diff options
Diffstat (limited to 'arch/mips/loongson64/init.c')
-rw-r--r-- | arch/mips/loongson64/init.c | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/arch/mips/loongson64/init.c b/arch/mips/loongson64/init.c new file mode 100644 index 000000000..052cce6a8 --- /dev/null +++ b/arch/mips/loongson64/init.c | |||
@@ -0,0 +1,149 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2009 Lemote Inc. | ||
4 | * Author: Wu Zhangjin, wuzhangjin@gmail.com | ||
5 | */ | ||
6 | |||
7 | #include <linux/irqchip.h> | ||
8 | #include <linux/logic_pio.h> | ||
9 | #include <linux/memblock.h> | ||
10 | #include <linux/of.h> | ||
11 | #include <linux/of_address.h> | ||
12 | #include <asm/bootinfo.h> | ||
13 | #include <asm/traps.h> | ||
14 | #include <asm/smp-ops.h> | ||
15 | #include <asm/cacheflush.h> | ||
16 | #include <asm/fw/fw.h> | ||
17 | |||
18 | #include <loongson.h> | ||
19 | #include <boot_param.h> | ||
20 | |||
21 | #define NODE_ID_OFFSET_ADDR ((void __iomem *)TO_UNCAC(0x1001041c)) | ||
22 | |||
23 | u32 node_id_offset; | ||
24 | |||
25 | static void __init mips_nmi_setup(void) | ||
26 | { | ||
27 | void *base; | ||
28 | extern char except_vec_nmi[]; | ||
29 | |||
30 | base = (void *)(CAC_BASE + 0x380); | ||
31 | memcpy(base, except_vec_nmi, 0x80); | ||
32 | flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); | ||
33 | } | ||
34 | |||
35 | void ls7a_early_config(void) | ||
36 | { | ||
37 | node_id_offset = ((readl(NODE_ID_OFFSET_ADDR) >> 8) & 0x1f) + 36; | ||
38 | } | ||
39 | |||
40 | void rs780e_early_config(void) | ||
41 | { | ||
42 | node_id_offset = 37; | ||
43 | } | ||
44 | |||
45 | void virtual_early_config(void) | ||
46 | { | ||
47 | node_id_offset = 44; | ||
48 | } | ||
49 | |||
50 | void __init prom_init(void) | ||
51 | { | ||
52 | fw_init_cmdline(); | ||
53 | prom_init_env(); | ||
54 | |||
55 | /* init base address of io space */ | ||
56 | set_io_port_base(PCI_IOBASE); | ||
57 | |||
58 | loongson_sysconf.early_config(); | ||
59 | |||
60 | prom_init_numa_memory(); | ||
61 | |||
62 | /* Hardcode to CPU UART 0 */ | ||
63 | setup_8250_early_printk_port(TO_UNCAC(LOONGSON_REG_BASE + 0x1e0), 0, 1024); | ||
64 | |||
65 | register_smp_ops(&loongson3_smp_ops); | ||
66 | board_nmi_handler_setup = mips_nmi_setup; | ||
67 | } | ||
68 | |||
69 | void __init prom_free_prom_memory(void) | ||
70 | { | ||
71 | } | ||
72 | |||
73 | static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, resource_size_t hw_start, | ||
74 | resource_size_t size) | ||
75 | { | ||
76 | int ret = 0; | ||
77 | struct logic_pio_hwaddr *range; | ||
78 | unsigned long vaddr; | ||
79 | |||
80 | range = kzalloc(sizeof(*range), GFP_ATOMIC); | ||
81 | if (!range) | ||
82 | return -ENOMEM; | ||
83 | |||
84 | range->fwnode = fwnode; | ||
85 | range->size = size = round_up(size, PAGE_SIZE); | ||
86 | range->hw_start = hw_start; | ||
87 | range->flags = LOGIC_PIO_CPU_MMIO; | ||
88 | |||
89 | ret = logic_pio_register_range(range); | ||
90 | if (ret) { | ||
91 | kfree(range); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | /* Legacy ISA must placed at the start of PCI_IOBASE */ | ||
96 | if (range->io_start != 0) { | ||
97 | logic_pio_unregister_range(range); | ||
98 | kfree(range); | ||
99 | return -EINVAL; | ||
100 | } | ||
101 | |||
102 | vaddr = PCI_IOBASE + range->io_start; | ||
103 | |||
104 | ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL)); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static __init void reserve_pio_range(void) | ||
110 | { | ||
111 | struct device_node *np; | ||
112 | |||
113 | for_each_node_by_name(np, "isa") { | ||
114 | struct of_range range; | ||
115 | struct of_range_parser parser; | ||
116 | |||
117 | pr_info("ISA Bridge: %pOF\n", np); | ||
118 | |||
119 | if (of_range_parser_init(&parser, np)) { | ||
120 | pr_info("Failed to parse resources.\n"); | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | for_each_of_range(&parser, &range) { | ||
125 | switch (range.flags & IORESOURCE_TYPE_BITS) { | ||
126 | case IORESOURCE_IO: | ||
127 | pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n", | ||
128 | range.cpu_addr, | ||
129 | range.cpu_addr + range.size - 1, | ||
130 | range.bus_addr); | ||
131 | if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size)) | ||
132 | pr_warn("Failed to reserve legacy IO in Logic PIO\n"); | ||
133 | break; | ||
134 | case IORESOURCE_MEM: | ||
135 | pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n", | ||
136 | range.cpu_addr, | ||
137 | range.cpu_addr + range.size - 1, | ||
138 | range.bus_addr); | ||
139 | break; | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | void __init arch_init_irq(void) | ||
146 | { | ||
147 | reserve_pio_range(); | ||
148 | irqchip_init(); | ||
149 | } | ||