2019-05-27 14:55:01 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2009-07-02 23:22:36 +08:00
|
|
|
/*
|
2009-11-06 18:35:34 +08:00
|
|
|
* Copyright (C) 2009 Lemote Inc.
|
2010-01-04 17:16:51 +08:00
|
|
|
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
2009-07-02 23:22:36 +08:00
|
|
|
*/
|
|
|
|
|
2020-03-25 11:55:00 +08:00
|
|
|
#include <linux/irqchip.h>
|
2020-05-27 21:17:21 +08:00
|
|
|
#include <linux/logic_pio.h>
|
2018-10-31 06:09:49 +08:00
|
|
|
#include <linux/memblock.h>
|
2020-07-28 23:36:56 +08:00
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_address.h>
|
2014-11-20 05:52:50 +08:00
|
|
|
#include <asm/bootinfo.h>
|
2017-06-22 23:06:50 +08:00
|
|
|
#include <asm/traps.h>
|
2014-03-21 18:44:08 +08:00
|
|
|
#include <asm/smp-ops.h>
|
2017-06-22 23:06:50 +08:00
|
|
|
#include <asm/cacheflush.h>
|
2019-11-07 12:01:15 +08:00
|
|
|
#include <asm/fw/fw.h>
|
2009-07-02 23:22:36 +08:00
|
|
|
|
2009-07-02 23:23:03 +08:00
|
|
|
#include <loongson.h>
|
MIPS: Loongson: Add DMA support for LS7A
In the current market, the most used bridge chip on the Loongson platform
are RS780E and LS7A, the RS780E bridge chip is already supported by the
mainline kernel.
If use the default implementation of __phys_to_dma() and __dma_to_phys()
in dma-direct.h when CONFIG_ARCH_HAS_PHYS_TO_DMA is not set, it works
well used with LS7A on the Loongson single-way and multi-way platform,
and also works well used with RS780E on the Loongson single-way platform,
but the DMA address will be wrong on the non-node0 used with RS780E on
the Loongson multi-way platform.
Just as the description in the code comment, the devices get node id from
40 bit of HyperTransport bus, so we extract 2 bit node id (bit 44~45) from
48 bit address space of Loongson CPU and embed it into HyperTransport bus
(bit 37-38), this operation can be done only at the software level used
with RS780E on the Loongson multi-way platform, because it has no hardware
function to translate address of node id, this is a hardware compatibility
problem.
Device
|
| DMA address
|
Host Bridge
|
| HT bus address (40 bit)
|
CPU
|
| physical address (48 bit)
|
RAM
The LS7A has dma_node_id_offset field in the DMA route config register,
the hardware can use the dma_node_id_offset to translate address of
node id automatically, so we can get correct address when just use the
dma_pfn_offset field in struct device.
For the above reasons, in order to maintain downward compatibility
to support the RS780E bridge chip, it is better to use the platform
dependent implementation of __phys_to_dma() and __dma_to_phys().
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-05-08 16:36:05 +08:00
|
|
|
#include <boot_param.h>
|
|
|
|
|
|
|
|
#define NODE_ID_OFFSET_ADDR ((void __iomem *)TO_UNCAC(0x1001041c))
|
|
|
|
|
|
|
|
u32 node_id_offset;
|
2009-07-02 23:22:36 +08:00
|
|
|
|
2017-06-22 23:06:50 +08:00
|
|
|
static void __init mips_nmi_setup(void)
|
|
|
|
{
|
|
|
|
void *base;
|
|
|
|
|
|
|
|
base = (void *)(CAC_BASE + 0x380);
|
2020-05-23 23:50:34 +08:00
|
|
|
memcpy(base, except_vec_nmi, 0x80);
|
2017-06-22 23:06:50 +08:00
|
|
|
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
|
|
|
|
}
|
|
|
|
|
MIPS: Loongson: Add DMA support for LS7A
In the current market, the most used bridge chip on the Loongson platform
are RS780E and LS7A, the RS780E bridge chip is already supported by the
mainline kernel.
If use the default implementation of __phys_to_dma() and __dma_to_phys()
in dma-direct.h when CONFIG_ARCH_HAS_PHYS_TO_DMA is not set, it works
well used with LS7A on the Loongson single-way and multi-way platform,
and also works well used with RS780E on the Loongson single-way platform,
but the DMA address will be wrong on the non-node0 used with RS780E on
the Loongson multi-way platform.
Just as the description in the code comment, the devices get node id from
40 bit of HyperTransport bus, so we extract 2 bit node id (bit 44~45) from
48 bit address space of Loongson CPU and embed it into HyperTransport bus
(bit 37-38), this operation can be done only at the software level used
with RS780E on the Loongson multi-way platform, because it has no hardware
function to translate address of node id, this is a hardware compatibility
problem.
Device
|
| DMA address
|
Host Bridge
|
| HT bus address (40 bit)
|
CPU
|
| physical address (48 bit)
|
RAM
The LS7A has dma_node_id_offset field in the DMA route config register,
the hardware can use the dma_node_id_offset to translate address of
node id automatically, so we can get correct address when just use the
dma_pfn_offset field in struct device.
For the above reasons, in order to maintain downward compatibility
to support the RS780E bridge chip, it is better to use the platform
dependent implementation of __phys_to_dma() and __dma_to_phys().
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-05-08 16:36:05 +08:00
|
|
|
void ls7a_early_config(void)
|
|
|
|
{
|
|
|
|
node_id_offset = ((readl(NODE_ID_OFFSET_ADDR) >> 8) & 0x1f) + 36;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rs780e_early_config(void)
|
|
|
|
{
|
|
|
|
node_id_offset = 37;
|
|
|
|
}
|
|
|
|
|
2020-07-29 14:58:37 +08:00
|
|
|
void virtual_early_config(void)
|
|
|
|
{
|
|
|
|
node_id_offset = 44;
|
|
|
|
}
|
|
|
|
|
2020-12-03 20:32:52 +08:00
|
|
|
void __init szmem(unsigned int node)
|
|
|
|
{
|
|
|
|
u32 i, mem_type;
|
|
|
|
static unsigned long num_physpages;
|
|
|
|
u64 node_id, node_psize, start_pfn, end_pfn, mem_start, mem_size;
|
|
|
|
|
2021-03-15 15:49:59 +08:00
|
|
|
/* Otherwise come from DTB */
|
|
|
|
if (loongson_sysconf.fw_interface != LOONGSON_LEFI)
|
|
|
|
return;
|
|
|
|
|
2020-12-03 20:32:52 +08:00
|
|
|
/* Parse memory information and activate */
|
|
|
|
for (i = 0; i < loongson_memmap->nr_map; i++) {
|
|
|
|
node_id = loongson_memmap->map[i].node_id;
|
|
|
|
if (node_id != node)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
mem_type = loongson_memmap->map[i].mem_type;
|
|
|
|
mem_size = loongson_memmap->map[i].mem_size;
|
|
|
|
mem_start = loongson_memmap->map[i].mem_start;
|
|
|
|
|
|
|
|
switch (mem_type) {
|
|
|
|
case SYSTEM_RAM_LOW:
|
|
|
|
case SYSTEM_RAM_HIGH:
|
|
|
|
start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT;
|
|
|
|
node_psize = (mem_size << 20) >> PAGE_SHIFT;
|
|
|
|
end_pfn = start_pfn + node_psize;
|
|
|
|
num_physpages += node_psize;
|
|
|
|
pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
|
|
|
|
(u32)node_id, mem_type, mem_start, mem_size);
|
|
|
|
pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
|
|
|
|
start_pfn, end_pfn, num_physpages);
|
2021-11-06 04:44:49 +08:00
|
|
|
memblock_add_node(PFN_PHYS(start_pfn),
|
|
|
|
PFN_PHYS(node_psize), node,
|
|
|
|
MEMBLOCK_NONE);
|
2020-12-03 20:32:52 +08:00
|
|
|
break;
|
|
|
|
case SYSTEM_RAM_RESERVED:
|
|
|
|
pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
|
|
|
|
(u32)node_id, mem_type, mem_start, mem_size);
|
|
|
|
memblock_reserve(((node_id << 44) + mem_start), mem_size << 20);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef CONFIG_NUMA
|
|
|
|
static void __init prom_init_memory(void)
|
|
|
|
{
|
|
|
|
szmem(0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-07-02 23:22:36 +08:00
|
|
|
void __init prom_init(void)
|
|
|
|
{
|
2019-11-07 12:01:15 +08:00
|
|
|
fw_init_cmdline();
|
2021-03-15 15:49:59 +08:00
|
|
|
|
|
|
|
if (fw_arg2 == 0 || (fdt_magic(fw_arg2) == FDT_MAGIC)) {
|
|
|
|
loongson_sysconf.fw_interface = LOONGSON_DTB;
|
|
|
|
prom_dtb_init_env();
|
|
|
|
} else {
|
|
|
|
loongson_sysconf.fw_interface = LOONGSON_LEFI;
|
|
|
|
prom_lefi_init_env();
|
|
|
|
}
|
2014-03-21 18:44:02 +08:00
|
|
|
|
|
|
|
/* init base address of io space */
|
2020-05-27 21:17:21 +08:00
|
|
|
set_io_port_base(PCI_IOBASE);
|
2014-03-21 18:44:02 +08:00
|
|
|
|
2021-03-15 15:49:59 +08:00
|
|
|
if (loongson_sysconf.early_config)
|
|
|
|
loongson_sysconf.early_config();
|
MIPS: Loongson: Add DMA support for LS7A
In the current market, the most used bridge chip on the Loongson platform
are RS780E and LS7A, the RS780E bridge chip is already supported by the
mainline kernel.
If use the default implementation of __phys_to_dma() and __dma_to_phys()
in dma-direct.h when CONFIG_ARCH_HAS_PHYS_TO_DMA is not set, it works
well used with LS7A on the Loongson single-way and multi-way platform,
and also works well used with RS780E on the Loongson single-way platform,
but the DMA address will be wrong on the non-node0 used with RS780E on
the Loongson multi-way platform.
Just as the description in the code comment, the devices get node id from
40 bit of HyperTransport bus, so we extract 2 bit node id (bit 44~45) from
48 bit address space of Loongson CPU and embed it into HyperTransport bus
(bit 37-38), this operation can be done only at the software level used
with RS780E on the Loongson multi-way platform, because it has no hardware
function to translate address of node id, this is a hardware compatibility
problem.
Device
|
| DMA address
|
Host Bridge
|
| HT bus address (40 bit)
|
CPU
|
| physical address (48 bit)
|
RAM
The LS7A has dma_node_id_offset field in the DMA route config register,
the hardware can use the dma_node_id_offset to translate address of
node id automatically, so we can get correct address when just use the
dma_pfn_offset field in struct device.
For the above reasons, in order to maintain downward compatibility
to support the RS780E bridge chip, it is better to use the platform
dependent implementation of __phys_to_dma() and __dma_to_phys().
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-05-08 16:36:05 +08:00
|
|
|
|
2020-12-03 20:32:52 +08:00
|
|
|
#ifdef CONFIG_NUMA
|
2014-06-26 11:41:28 +08:00
|
|
|
prom_init_numa_memory();
|
2020-12-03 20:32:52 +08:00
|
|
|
#else
|
|
|
|
prom_init_memory();
|
|
|
|
#endif
|
2009-11-06 18:35:34 +08:00
|
|
|
|
2019-10-20 23:01:35 +08:00
|
|
|
/* Hardcode to CPU UART 0 */
|
2021-03-15 15:50:01 +08:00
|
|
|
if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R)
|
|
|
|
setup_8250_early_printk_port(TO_UNCAC(LOONGSON_REG_BASE), 0, 1024);
|
|
|
|
else
|
|
|
|
setup_8250_early_printk_port(TO_UNCAC(LOONGSON_REG_BASE + 0x1e0), 0, 1024);
|
2019-10-20 23:01:35 +08:00
|
|
|
|
2014-03-21 18:44:08 +08:00
|
|
|
register_smp_ops(&loongson3_smp_ops);
|
2017-06-22 23:06:50 +08:00
|
|
|
board_nmi_handler_setup = mips_nmi_setup;
|
2009-07-02 23:22:36 +08:00
|
|
|
}
|
|
|
|
|
2020-07-28 23:36:56 +08:00
|
|
|
static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, resource_size_t hw_start,
|
|
|
|
resource_size_t size)
|
2020-05-27 21:17:21 +08:00
|
|
|
{
|
2020-07-28 23:36:56 +08:00
|
|
|
int ret = 0;
|
2020-05-27 21:17:21 +08:00
|
|
|
struct logic_pio_hwaddr *range;
|
2020-07-28 23:36:56 +08:00
|
|
|
unsigned long vaddr;
|
2020-05-27 21:17:21 +08:00
|
|
|
|
|
|
|
range = kzalloc(sizeof(*range), GFP_ATOMIC);
|
|
|
|
if (!range)
|
2020-07-28 23:36:56 +08:00
|
|
|
return -ENOMEM;
|
2020-05-27 21:17:21 +08:00
|
|
|
|
2020-07-28 23:36:56 +08:00
|
|
|
range->fwnode = fwnode;
|
2021-03-24 11:24:51 +08:00
|
|
|
range->size = size = round_up(size, PAGE_SIZE);
|
2020-07-28 23:36:56 +08:00
|
|
|
range->hw_start = hw_start;
|
2020-05-27 21:17:21 +08:00
|
|
|
range->flags = LOGIC_PIO_CPU_MMIO;
|
|
|
|
|
2020-07-28 23:36:56 +08:00
|
|
|
ret = logic_pio_register_range(range);
|
|
|
|
if (ret) {
|
|
|
|
kfree(range);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Legacy ISA must placed at the start of PCI_IOBASE */
|
|
|
|
if (range->io_start != 0) {
|
|
|
|
logic_pio_unregister_range(range);
|
|
|
|
kfree(range);
|
|
|
|
return -EINVAL;
|
2020-05-27 21:17:21 +08:00
|
|
|
}
|
|
|
|
|
2020-07-28 23:36:56 +08:00
|
|
|
vaddr = PCI_IOBASE + range->io_start;
|
|
|
|
|
|
|
|
ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __init void reserve_pio_range(void)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
|
|
|
|
for_each_node_by_name(np, "isa") {
|
|
|
|
struct of_range range;
|
|
|
|
struct of_range_parser parser;
|
|
|
|
|
|
|
|
pr_info("ISA Bridge: %pOF\n", np);
|
|
|
|
|
|
|
|
if (of_range_parser_init(&parser, np)) {
|
|
|
|
pr_info("Failed to parse resources.\n");
|
2021-10-15 15:01:22 +08:00
|
|
|
of_node_put(np);
|
2020-07-28 23:36:56 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for_each_of_range(&parser, &range) {
|
|
|
|
switch (range.flags & IORESOURCE_TYPE_BITS) {
|
|
|
|
case IORESOURCE_IO:
|
|
|
|
pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
|
|
|
|
range.cpu_addr,
|
|
|
|
range.cpu_addr + range.size - 1,
|
|
|
|
range.bus_addr);
|
|
|
|
if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size))
|
|
|
|
pr_warn("Failed to reserve legacy IO in Logic PIO\n");
|
|
|
|
break;
|
|
|
|
case IORESOURCE_MEM:
|
|
|
|
pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n",
|
|
|
|
range.cpu_addr,
|
|
|
|
range.cpu_addr + range.size - 1,
|
|
|
|
range.bus_addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-27 21:17:21 +08:00
|
|
|
}
|
|
|
|
|
2020-03-25 11:55:00 +08:00
|
|
|
void __init arch_init_irq(void)
|
|
|
|
{
|
2020-05-27 21:17:21 +08:00
|
|
|
reserve_pio_range();
|
2020-03-25 11:55:00 +08:00
|
|
|
irqchip_init();
|
|
|
|
}
|