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/libfdt.h> 20 #include <linux/pci_ids.h> 21 #include <linux/string_choices.h> 22 #include <asm/bootinfo.h> 23 #include <loongson.h> 24 #include <boot_param.h> 25 #include <builtin_dtbs.h> 26 #include <workarounds.h> 27 28 #define HOST_BRIDGE_CONFIG_ADDR ((void __iomem *)TO_UNCAC(0x1a000000)) 29 30 u32 cpu_clock_freq; 31 EXPORT_SYMBOL(cpu_clock_freq); 32 struct efi_memory_map_loongson *loongson_memmap; 33 struct loongson_system_configuration loongson_sysconf; 34 35 struct board_devices *eboard; 36 struct interface_info *einter; 37 struct loongson_special_attribute *especial; 38 39 u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; 40 u64 loongson_chiptemp[MAX_PACKAGES]; 41 u64 loongson_freqctrl[MAX_PACKAGES]; 42 43 unsigned long long smp_group[4]; 44 45 const char *get_system_type(void) 46 { 47 return "Generic Loongson64 System"; 48 } 49 50 51 void __init prom_dtb_init_env(void) 52 { 53 if ((fw_arg2 < CKSEG0 || fw_arg2 > CKSEG1) 54 && (fw_arg2 < XKPHYS || fw_arg2 > XKSEG)) 55 56 loongson_fdt_blob = __dtb_loongson64_2core_2k1000_begin; 57 else 58 loongson_fdt_blob = (void *)fw_arg2; 59 } 60 61 static int __init lefi_fixup_fdt_serial(void *fdt, u64 uart_addr, u32 uart_clk) 62 { 63 int node, len, depth = -1; 64 const fdt64_t *reg; 65 fdt32_t *clk; 66 67 for (node = fdt_next_node(fdt, -1, &depth); 68 node >= 0 && depth >= 0; 69 node = fdt_next_node(fdt, node, &depth)) { 70 reg = fdt_getprop(fdt, node, "reg", &len); 71 if (!reg || len <= 8 || fdt64_ld(reg) != uart_addr) 72 continue; 73 74 clk = fdt_getprop_w(fdt, node, "clock-frequency", &len); 75 if (!clk) { 76 pr_warn("UART 0x%llx misses clock-frequency property\n", 77 uart_addr); 78 return -ENOENT; 79 } else if (len != 4) { 80 pr_warn("UART 0x%llx has invalid clock-frequency property\n", 81 uart_addr); 82 return -EINVAL; 83 } 84 85 fdt32_st(clk, uart_clk); 86 87 return 0; 88 } 89 90 return -ENODEV; 91 } 92 93 static void __init lefi_fixup_fdt(struct system_loongson *system) 94 { 95 static unsigned char fdt_buf[16 << 10] __initdata; 96 struct uart_device *uartdev; 97 bool is_loongson64g; 98 u64 uart_base; 99 int ret, i; 100 101 ret = fdt_open_into(loongson_fdt_blob, fdt_buf, sizeof(fdt_buf)); 102 if (ret) { 103 pr_err("Failed to open FDT to fix up\n"); 104 return; 105 } 106 107 is_loongson64g = (read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G; 108 109 for (i = 0; i < system->nr_uarts; i++) { 110 uartdev = &system->uarts[i]; 111 112 ret = lefi_fixup_fdt_serial(fdt_buf, uartdev->uart_base, 113 uartdev->uartclk); 114 /* 115 * LOONGSON64G's CPU serials are mapped to two different 116 * addresses, one full-featured but differs from 117 * previous generations, one fully compatible with them. 118 * 119 * It's unspecified that which mapping should uart_base refer 120 * to, thus we should try fixing up with both. 121 */ 122 if (ret == -ENODEV && is_loongson64g) { 123 switch (uartdev->uart_base) { 124 case 0x1fe00100: 125 uart_base = 0x1fe001e0; 126 break; 127 case 0x1fe00110: 128 uart_base = 0x1fe001e8; 129 break; 130 case 0x1fe001e0: 131 uart_base = 0x1fe00100; 132 break; 133 case 0x1fe001e8: 134 uart_base = 0x1fe00110; 135 break; 136 default: 137 pr_err("Unexpected UART address 0x%llx passed by firmware\n", 138 uartdev->uart_base); 139 ret = -EINVAL; 140 goto err_fixup; 141 } 142 143 ret = lefi_fixup_fdt_serial(fdt_buf, uart_base, 144 uartdev->uartclk); 145 } 146 147 err_fixup: 148 if (ret) 149 pr_err("Couldn't fix up FDT node for UART 0x%llx\n", 150 uartdev->uart_base); 151 } 152 153 loongson_fdt_blob = fdt_buf; 154 } 155 156 void __init prom_lefi_init_env(void) 157 { 158 struct boot_params *boot_p; 159 struct loongson_params *loongson_p; 160 struct system_loongson *esys; 161 struct efi_cpuinfo_loongson *ecpu; 162 struct irq_source_routing_table *eirq_source; 163 u32 id; 164 u16 vendor; 165 166 /* firmware arguments are initialized in head.S */ 167 boot_p = (struct boot_params *)fw_arg2; 168 loongson_p = &(boot_p->efi.smbios.lp); 169 170 esys = (struct system_loongson *) 171 ((u64)loongson_p + loongson_p->system_offset); 172 ecpu = (struct efi_cpuinfo_loongson *) 173 ((u64)loongson_p + loongson_p->cpu_offset); 174 eboard = (struct board_devices *) 175 ((u64)loongson_p + loongson_p->boarddev_table_offset); 176 einter = (struct interface_info *) 177 ((u64)loongson_p + loongson_p->interface_offset); 178 especial = (struct loongson_special_attribute *) 179 ((u64)loongson_p + loongson_p->special_offset); 180 eirq_source = (struct irq_source_routing_table *) 181 ((u64)loongson_p + loongson_p->irq_offset); 182 loongson_memmap = (struct efi_memory_map_loongson *) 183 ((u64)loongson_p + loongson_p->memory_offset); 184 185 cpu_clock_freq = ecpu->cpu_clock_freq; 186 loongson_sysconf.cputype = ecpu->cputype; 187 switch (ecpu->cputype) { 188 case Legacy_2K: 189 case Loongson_2K: 190 smp_group[0] = 0x900000001fe11000; 191 loongson_sysconf.cores_per_node = 2; 192 loongson_sysconf.cores_per_package = 2; 193 break; 194 case Legacy_3A: 195 case Loongson_3A: 196 loongson_sysconf.cores_per_node = 4; 197 loongson_sysconf.cores_per_package = 4; 198 smp_group[0] = 0x900000003ff01000; 199 smp_group[1] = 0x900010003ff01000; 200 smp_group[2] = 0x900020003ff01000; 201 smp_group[3] = 0x900030003ff01000; 202 loongson_chipcfg[0] = 0x900000001fe00180; 203 loongson_chipcfg[1] = 0x900010001fe00180; 204 loongson_chipcfg[2] = 0x900020001fe00180; 205 loongson_chipcfg[3] = 0x900030001fe00180; 206 loongson_chiptemp[0] = 0x900000001fe0019c; 207 loongson_chiptemp[1] = 0x900010001fe0019c; 208 loongson_chiptemp[2] = 0x900020001fe0019c; 209 loongson_chiptemp[3] = 0x900030001fe0019c; 210 loongson_freqctrl[0] = 0x900000001fe001d0; 211 loongson_freqctrl[1] = 0x900010001fe001d0; 212 loongson_freqctrl[2] = 0x900020001fe001d0; 213 loongson_freqctrl[3] = 0x900030001fe001d0; 214 loongson_sysconf.workarounds = WORKAROUND_CPUFREQ; 215 break; 216 case Legacy_3B: 217 case Loongson_3B: 218 loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */ 219 loongson_sysconf.cores_per_package = 8; 220 smp_group[0] = 0x900000003ff01000; 221 smp_group[1] = 0x900010003ff05000; 222 smp_group[2] = 0x900020003ff09000; 223 smp_group[3] = 0x900030003ff0d000; 224 loongson_chipcfg[0] = 0x900000001fe00180; 225 loongson_chipcfg[1] = 0x900020001fe00180; 226 loongson_chipcfg[2] = 0x900040001fe00180; 227 loongson_chipcfg[3] = 0x900060001fe00180; 228 loongson_chiptemp[0] = 0x900000001fe0019c; 229 loongson_chiptemp[1] = 0x900020001fe0019c; 230 loongson_chiptemp[2] = 0x900040001fe0019c; 231 loongson_chiptemp[3] = 0x900060001fe0019c; 232 loongson_freqctrl[0] = 0x900000001fe001d0; 233 loongson_freqctrl[1] = 0x900020001fe001d0; 234 loongson_freqctrl[2] = 0x900040001fe001d0; 235 loongson_freqctrl[3] = 0x900060001fe001d0; 236 loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG; 237 break; 238 default: 239 loongson_sysconf.cores_per_node = 1; 240 loongson_sysconf.cores_per_package = 1; 241 loongson_chipcfg[0] = 0x900000001fe00180; 242 } 243 244 loongson_sysconf.nr_cpus = ecpu->nr_cpus; 245 loongson_sysconf.boot_cpu_id = ecpu->cpu_startup_core_id; 246 loongson_sysconf.reserved_cpus_mask = ecpu->reserved_cores_mask; 247 if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0) 248 loongson_sysconf.nr_cpus = NR_CPUS; 249 loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus + 250 loongson_sysconf.cores_per_node - 1) / 251 loongson_sysconf.cores_per_node; 252 253 loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits; 254 if (loongson_sysconf.dma_mask_bits < 32 || 255 loongson_sysconf.dma_mask_bits > 64) { 256 loongson_sysconf.dma_mask_bits = 32; 257 dma_default_coherent = true; 258 } else { 259 dma_default_coherent = !eirq_source->dma_noncoherent; 260 } 261 262 pr_info("Firmware: Coherent DMA: %s\n", str_on_off(dma_default_coherent)); 263 264 loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm; 265 loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown; 266 loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend; 267 268 loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios; 269 pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n", 270 loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr, 271 loongson_sysconf.vgabios_addr); 272 273 loongson_sysconf.workarounds |= esys->workarounds; 274 275 pr_info("CpuClock = %u\n", cpu_clock_freq); 276 277 /* Read the ID of PCI host bridge to detect bridge type */ 278 id = readl(HOST_BRIDGE_CONFIG_ADDR); 279 vendor = id & 0xffff; 280 281 switch (vendor) { 282 case PCI_VENDOR_ID_LOONGSON: 283 pr_info("The bridge chip is LS7A\n"); 284 loongson_sysconf.bridgetype = LS7A; 285 loongson_sysconf.early_config = ls7a_early_config; 286 break; 287 case PCI_VENDOR_ID_AMD: 288 case PCI_VENDOR_ID_ATI: 289 pr_info("The bridge chip is RS780E or SR5690\n"); 290 loongson_sysconf.bridgetype = RS780E; 291 loongson_sysconf.early_config = rs780e_early_config; 292 break; 293 default: 294 pr_info("The bridge chip is VIRTUAL\n"); 295 loongson_sysconf.bridgetype = VIRTUAL; 296 loongson_sysconf.early_config = virtual_early_config; 297 loongson_fdt_blob = __dtb_loongson64v_4core_virtio_begin; 298 break; 299 } 300 301 if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64C) { 302 switch (read_c0_prid() & PRID_REV_MASK) { 303 case PRID_REV_LOONGSON3A_R1: 304 case PRID_REV_LOONGSON3A_R2_0: 305 case PRID_REV_LOONGSON3A_R2_1: 306 case PRID_REV_LOONGSON3A_R3_0: 307 case PRID_REV_LOONGSON3A_R3_1: 308 switch (loongson_sysconf.bridgetype) { 309 case LS7A: 310 loongson_fdt_blob = __dtb_loongson64c_4core_ls7a_begin; 311 break; 312 case RS780E: 313 loongson_fdt_blob = __dtb_loongson64c_4core_rs780e_begin; 314 break; 315 default: 316 break; 317 } 318 break; 319 case PRID_REV_LOONGSON3B_R1: 320 case PRID_REV_LOONGSON3B_R2: 321 if (loongson_sysconf.bridgetype == RS780E) 322 loongson_fdt_blob = __dtb_loongson64c_8core_rs780e_begin; 323 break; 324 default: 325 break; 326 } 327 } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R) { 328 loongson_fdt_blob = __dtb_loongson64_2core_2k1000_begin; 329 } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G) { 330 if (loongson_sysconf.bridgetype == LS7A) 331 loongson_fdt_blob = __dtb_loongson64g_4core_ls7a_begin; 332 } 333 334 if (!loongson_fdt_blob) 335 pr_err("Failed to determine built-in Loongson64 dtb\n"); 336 else 337 lefi_fixup_fdt(esys); 338 } 339