1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Based on Ocelot Linux port, which is |
4 | * Copyright 2001 MontaVista Software Inc. |
5 | * Author: jsun@mvista.com or jsun@junsun.net |
6 | * |
7 | * Copyright 2003 ICT CAS |
8 | * Author: Michael Guo <guoyi@ict.ac.cn> |
9 | * |
10 | * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology |
11 | * Author: Fuxin Zhang, zhangfx@lemote.com |
12 | * |
13 | * Copyright (C) 2009 Lemote Inc. |
14 | * Author: Wu Zhangjin, wuzhangjin@gmail.com |
15 | */ |
16 | |
17 | #include <linux/dma-map-ops.h> |
18 | #include <linux/export.h> |
19 | #include <linux/pci_ids.h> |
20 | #include <asm/bootinfo.h> |
21 | #include <loongson.h> |
22 | #include <boot_param.h> |
23 | #include <builtin_dtbs.h> |
24 | #include <workarounds.h> |
25 | |
26 | #define HOST_BRIDGE_CONFIG_ADDR ((void __iomem *)TO_UNCAC(0x1a000000)) |
27 | |
28 | u32 cpu_clock_freq; |
29 | EXPORT_SYMBOL(cpu_clock_freq); |
30 | struct efi_memory_map_loongson *loongson_memmap; |
31 | struct loongson_system_configuration loongson_sysconf; |
32 | |
33 | struct board_devices *eboard; |
34 | struct interface_info *einter; |
35 | struct loongson_special_attribute *especial; |
36 | |
37 | u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; |
38 | u64 loongson_chiptemp[MAX_PACKAGES]; |
39 | u64 loongson_freqctrl[MAX_PACKAGES]; |
40 | |
41 | unsigned long long smp_group[4]; |
42 | |
43 | const char *get_system_type(void) |
44 | { |
45 | return "Generic Loongson64 System" ; |
46 | } |
47 | |
48 | |
49 | void __init prom_dtb_init_env(void) |
50 | { |
51 | if ((fw_arg2 < CKSEG0 || fw_arg2 > CKSEG1) |
52 | && (fw_arg2 < XKPHYS || fw_arg2 > XKSEG)) |
53 | |
54 | loongson_fdt_blob = __dtb_loongson64_2core_2k1000_begin; |
55 | else |
56 | loongson_fdt_blob = (void *)fw_arg2; |
57 | } |
58 | |
59 | void __init prom_lefi_init_env(void) |
60 | { |
61 | struct boot_params *boot_p; |
62 | struct loongson_params *loongson_p; |
63 | struct system_loongson *esys; |
64 | struct efi_cpuinfo_loongson *ecpu; |
65 | struct irq_source_routing_table *eirq_source; |
66 | u32 id; |
67 | u16 vendor; |
68 | |
69 | /* firmware arguments are initialized in head.S */ |
70 | boot_p = (struct boot_params *)fw_arg2; |
71 | loongson_p = &(boot_p->efi.smbios.lp); |
72 | |
73 | esys = (struct system_loongson *) |
74 | ((u64)loongson_p + loongson_p->system_offset); |
75 | ecpu = (struct efi_cpuinfo_loongson *) |
76 | ((u64)loongson_p + loongson_p->cpu_offset); |
77 | eboard = (struct board_devices *) |
78 | ((u64)loongson_p + loongson_p->boarddev_table_offset); |
79 | einter = (struct interface_info *) |
80 | ((u64)loongson_p + loongson_p->interface_offset); |
81 | especial = (struct loongson_special_attribute *) |
82 | ((u64)loongson_p + loongson_p->special_offset); |
83 | eirq_source = (struct irq_source_routing_table *) |
84 | ((u64)loongson_p + loongson_p->irq_offset); |
85 | loongson_memmap = (struct efi_memory_map_loongson *) |
86 | ((u64)loongson_p + loongson_p->memory_offset); |
87 | |
88 | cpu_clock_freq = ecpu->cpu_clock_freq; |
89 | loongson_sysconf.cputype = ecpu->cputype; |
90 | switch (ecpu->cputype) { |
91 | case Legacy_3A: |
92 | case Loongson_3A: |
93 | loongson_sysconf.cores_per_node = 4; |
94 | loongson_sysconf.cores_per_package = 4; |
95 | smp_group[0] = 0x900000003ff01000; |
96 | smp_group[1] = 0x900010003ff01000; |
97 | smp_group[2] = 0x900020003ff01000; |
98 | smp_group[3] = 0x900030003ff01000; |
99 | loongson_chipcfg[0] = 0x900000001fe00180; |
100 | loongson_chipcfg[1] = 0x900010001fe00180; |
101 | loongson_chipcfg[2] = 0x900020001fe00180; |
102 | loongson_chipcfg[3] = 0x900030001fe00180; |
103 | loongson_chiptemp[0] = 0x900000001fe0019c; |
104 | loongson_chiptemp[1] = 0x900010001fe0019c; |
105 | loongson_chiptemp[2] = 0x900020001fe0019c; |
106 | loongson_chiptemp[3] = 0x900030001fe0019c; |
107 | loongson_freqctrl[0] = 0x900000001fe001d0; |
108 | loongson_freqctrl[1] = 0x900010001fe001d0; |
109 | loongson_freqctrl[2] = 0x900020001fe001d0; |
110 | loongson_freqctrl[3] = 0x900030001fe001d0; |
111 | loongson_sysconf.workarounds = WORKAROUND_CPUFREQ; |
112 | break; |
113 | case Legacy_3B: |
114 | case Loongson_3B: |
115 | loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */ |
116 | loongson_sysconf.cores_per_package = 8; |
117 | smp_group[0] = 0x900000003ff01000; |
118 | smp_group[1] = 0x900010003ff05000; |
119 | smp_group[2] = 0x900020003ff09000; |
120 | smp_group[3] = 0x900030003ff0d000; |
121 | loongson_chipcfg[0] = 0x900000001fe00180; |
122 | loongson_chipcfg[1] = 0x900020001fe00180; |
123 | loongson_chipcfg[2] = 0x900040001fe00180; |
124 | loongson_chipcfg[3] = 0x900060001fe00180; |
125 | loongson_chiptemp[0] = 0x900000001fe0019c; |
126 | loongson_chiptemp[1] = 0x900020001fe0019c; |
127 | loongson_chiptemp[2] = 0x900040001fe0019c; |
128 | loongson_chiptemp[3] = 0x900060001fe0019c; |
129 | loongson_freqctrl[0] = 0x900000001fe001d0; |
130 | loongson_freqctrl[1] = 0x900020001fe001d0; |
131 | loongson_freqctrl[2] = 0x900040001fe001d0; |
132 | loongson_freqctrl[3] = 0x900060001fe001d0; |
133 | loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG; |
134 | break; |
135 | default: |
136 | loongson_sysconf.cores_per_node = 1; |
137 | loongson_sysconf.cores_per_package = 1; |
138 | loongson_chipcfg[0] = 0x900000001fe00180; |
139 | } |
140 | |
141 | loongson_sysconf.nr_cpus = ecpu->nr_cpus; |
142 | loongson_sysconf.boot_cpu_id = ecpu->cpu_startup_core_id; |
143 | loongson_sysconf.reserved_cpus_mask = ecpu->reserved_cores_mask; |
144 | if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0) |
145 | loongson_sysconf.nr_cpus = NR_CPUS; |
146 | loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus + |
147 | loongson_sysconf.cores_per_node - 1) / |
148 | loongson_sysconf.cores_per_node; |
149 | |
150 | loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits; |
151 | if (loongson_sysconf.dma_mask_bits < 32 || |
152 | loongson_sysconf.dma_mask_bits > 64) { |
153 | loongson_sysconf.dma_mask_bits = 32; |
154 | dma_default_coherent = true; |
155 | } else { |
156 | dma_default_coherent = !eirq_source->dma_noncoherent; |
157 | } |
158 | |
159 | pr_info("Firmware: Coherent DMA: %s\n" , dma_default_coherent ? "on" : "off" ); |
160 | |
161 | loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm; |
162 | loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown; |
163 | loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend; |
164 | |
165 | loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios; |
166 | pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n" , |
167 | loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr, |
168 | loongson_sysconf.vgabios_addr); |
169 | |
170 | loongson_sysconf.workarounds |= esys->workarounds; |
171 | |
172 | pr_info("CpuClock = %u\n" , cpu_clock_freq); |
173 | |
174 | /* Read the ID of PCI host bridge to detect bridge type */ |
175 | id = readl(HOST_BRIDGE_CONFIG_ADDR); |
176 | vendor = id & 0xffff; |
177 | |
178 | switch (vendor) { |
179 | case PCI_VENDOR_ID_LOONGSON: |
180 | pr_info("The bridge chip is LS7A\n" ); |
181 | loongson_sysconf.bridgetype = LS7A; |
182 | loongson_sysconf.early_config = ls7a_early_config; |
183 | break; |
184 | case PCI_VENDOR_ID_AMD: |
185 | case PCI_VENDOR_ID_ATI: |
186 | pr_info("The bridge chip is RS780E or SR5690\n" ); |
187 | loongson_sysconf.bridgetype = RS780E; |
188 | loongson_sysconf.early_config = rs780e_early_config; |
189 | break; |
190 | default: |
191 | pr_info("The bridge chip is VIRTUAL\n" ); |
192 | loongson_sysconf.bridgetype = VIRTUAL; |
193 | loongson_sysconf.early_config = virtual_early_config; |
194 | loongson_fdt_blob = __dtb_loongson64v_4core_virtio_begin; |
195 | break; |
196 | } |
197 | |
198 | if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64C) { |
199 | switch (read_c0_prid() & PRID_REV_MASK) { |
200 | case PRID_REV_LOONGSON3A_R1: |
201 | case PRID_REV_LOONGSON3A_R2_0: |
202 | case PRID_REV_LOONGSON3A_R2_1: |
203 | case PRID_REV_LOONGSON3A_R3_0: |
204 | case PRID_REV_LOONGSON3A_R3_1: |
205 | switch (loongson_sysconf.bridgetype) { |
206 | case LS7A: |
207 | loongson_fdt_blob = __dtb_loongson64c_4core_ls7a_begin; |
208 | break; |
209 | case RS780E: |
210 | loongson_fdt_blob = __dtb_loongson64c_4core_rs780e_begin; |
211 | break; |
212 | default: |
213 | break; |
214 | } |
215 | break; |
216 | case PRID_REV_LOONGSON3B_R1: |
217 | case PRID_REV_LOONGSON3B_R2: |
218 | if (loongson_sysconf.bridgetype == RS780E) |
219 | loongson_fdt_blob = __dtb_loongson64c_8core_rs780e_begin; |
220 | break; |
221 | default: |
222 | break; |
223 | } |
224 | } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G) { |
225 | if (loongson_sysconf.bridgetype == LS7A) |
226 | loongson_fdt_blob = __dtb_loongson64g_4core_ls7a_begin; |
227 | } |
228 | |
229 | if (!loongson_fdt_blob) |
230 | pr_err("Failed to determine built-in Loongson64 dtb\n" ); |
231 | } |
232 | |