16fbde6b4SJiaxun Yang // SPDX-License-Identifier: GPL-2.0-or-later
26fbde6b4SJiaxun Yang /*
36fbde6b4SJiaxun Yang * Based on Ocelot Linux port, which is
46fbde6b4SJiaxun Yang * Copyright 2001 MontaVista Software Inc.
56fbde6b4SJiaxun Yang * Author: jsun@mvista.com or jsun@junsun.net
66fbde6b4SJiaxun Yang *
76fbde6b4SJiaxun Yang * Copyright 2003 ICT CAS
86fbde6b4SJiaxun Yang * Author: Michael Guo <guoyi@ict.ac.cn>
96fbde6b4SJiaxun Yang *
106fbde6b4SJiaxun Yang * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
116fbde6b4SJiaxun Yang * Author: Fuxin Zhang, zhangfx@lemote.com
126fbde6b4SJiaxun Yang *
136fbde6b4SJiaxun Yang * Copyright (C) 2009 Lemote Inc.
146fbde6b4SJiaxun Yang * Author: Wu Zhangjin, wuzhangjin@gmail.com
156fbde6b4SJiaxun Yang */
161eed445dSJiaxun Yang
171eed445dSJiaxun Yang #include <linux/dma-map-ops.h>
186fbde6b4SJiaxun Yang #include <linux/export.h>
198c88cc53STiezhu Yang #include <linux/pci_ids.h>
206fbde6b4SJiaxun Yang #include <asm/bootinfo.h>
216fbde6b4SJiaxun Yang #include <loongson.h>
226fbde6b4SJiaxun Yang #include <boot_param.h>
23fcecdcd3SJiaxun Yang #include <builtin_dtbs.h>
246fbde6b4SJiaxun Yang #include <workarounds.h>
256fbde6b4SJiaxun Yang
268c88cc53STiezhu Yang #define HOST_BRIDGE_CONFIG_ADDR ((void __iomem *)TO_UNCAC(0x1a000000))
278c88cc53STiezhu Yang
286fbde6b4SJiaxun Yang u32 cpu_clock_freq;
296fbde6b4SJiaxun Yang EXPORT_SYMBOL(cpu_clock_freq);
306fbde6b4SJiaxun Yang struct efi_memory_map_loongson *loongson_memmap;
316fbde6b4SJiaxun Yang struct loongson_system_configuration loongson_sysconf;
326fbde6b4SJiaxun Yang
336c1bfbd9STiezhu Yang struct board_devices *eboard;
346c1bfbd9STiezhu Yang struct interface_info *einter;
356c1bfbd9STiezhu Yang struct loongson_special_attribute *especial;
366c1bfbd9STiezhu Yang
376fbde6b4SJiaxun Yang u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
386fbde6b4SJiaxun Yang u64 loongson_chiptemp[MAX_PACKAGES];
396fbde6b4SJiaxun Yang u64 loongson_freqctrl[MAX_PACKAGES];
406fbde6b4SJiaxun Yang
416fbde6b4SJiaxun Yang unsigned long long smp_group[4];
426fbde6b4SJiaxun Yang
get_system_type(void)436fbde6b4SJiaxun Yang const char *get_system_type(void)
446fbde6b4SJiaxun Yang {
456fbde6b4SJiaxun Yang return "Generic Loongson64 System";
466fbde6b4SJiaxun Yang }
476fbde6b4SJiaxun Yang
488e2fe0ecSQing Zhang
prom_dtb_init_env(void)498e2fe0ecSQing Zhang void __init prom_dtb_init_env(void)
508e2fe0ecSQing Zhang {
518e2fe0ecSQing Zhang if ((fw_arg2 < CKSEG0 || fw_arg2 > CKSEG1)
528e2fe0ecSQing Zhang && (fw_arg2 < XKPHYS || fw_arg2 > XKSEG))
538e2fe0ecSQing Zhang
548e2fe0ecSQing Zhang loongson_fdt_blob = __dtb_loongson64_2core_2k1000_begin;
558e2fe0ecSQing Zhang else
568e2fe0ecSQing Zhang loongson_fdt_blob = (void *)fw_arg2;
578e2fe0ecSQing Zhang }
588e2fe0ecSQing Zhang
prom_lefi_init_env(void)598e2fe0ecSQing Zhang void __init prom_lefi_init_env(void)
606fbde6b4SJiaxun Yang {
616fbde6b4SJiaxun Yang struct boot_params *boot_p;
626fbde6b4SJiaxun Yang struct loongson_params *loongson_p;
636fbde6b4SJiaxun Yang struct system_loongson *esys;
646fbde6b4SJiaxun Yang struct efi_cpuinfo_loongson *ecpu;
656fbde6b4SJiaxun Yang struct irq_source_routing_table *eirq_source;
668c88cc53STiezhu Yang u32 id;
674f5d31ceSHuacai Chen u16 vendor;
686fbde6b4SJiaxun Yang
696fbde6b4SJiaxun Yang /* firmware arguments are initialized in head.S */
706fbde6b4SJiaxun Yang boot_p = (struct boot_params *)fw_arg2;
716fbde6b4SJiaxun Yang loongson_p = &(boot_p->efi.smbios.lp);
726fbde6b4SJiaxun Yang
736fbde6b4SJiaxun Yang esys = (struct system_loongson *)
746fbde6b4SJiaxun Yang ((u64)loongson_p + loongson_p->system_offset);
756fbde6b4SJiaxun Yang ecpu = (struct efi_cpuinfo_loongson *)
766fbde6b4SJiaxun Yang ((u64)loongson_p + loongson_p->cpu_offset);
776c1bfbd9STiezhu Yang eboard = (struct board_devices *)
786c1bfbd9STiezhu Yang ((u64)loongson_p + loongson_p->boarddev_table_offset);
796c1bfbd9STiezhu Yang einter = (struct interface_info *)
806c1bfbd9STiezhu Yang ((u64)loongson_p + loongson_p->interface_offset);
816c1bfbd9STiezhu Yang especial = (struct loongson_special_attribute *)
826c1bfbd9STiezhu Yang ((u64)loongson_p + loongson_p->special_offset);
836fbde6b4SJiaxun Yang eirq_source = (struct irq_source_routing_table *)
846fbde6b4SJiaxun Yang ((u64)loongson_p + loongson_p->irq_offset);
856fbde6b4SJiaxun Yang loongson_memmap = (struct efi_memory_map_loongson *)
866fbde6b4SJiaxun Yang ((u64)loongson_p + loongson_p->memory_offset);
876fbde6b4SJiaxun Yang
886fbde6b4SJiaxun Yang cpu_clock_freq = ecpu->cpu_clock_freq;
896fbde6b4SJiaxun Yang loongson_sysconf.cputype = ecpu->cputype;
906fbde6b4SJiaxun Yang switch (ecpu->cputype) {
91*f7097b5fSJiaxun Yang case Legacy_2K:
92*f7097b5fSJiaxun Yang case Loongson_2K:
93*f7097b5fSJiaxun Yang smp_group[0] = 0x900000001fe11000;
94*f7097b5fSJiaxun Yang loongson_sysconf.cores_per_node = 2;
95*f7097b5fSJiaxun Yang loongson_sysconf.cores_per_package = 2;
96*f7097b5fSJiaxun Yang break;
976fbde6b4SJiaxun Yang case Legacy_3A:
986fbde6b4SJiaxun Yang case Loongson_3A:
996fbde6b4SJiaxun Yang loongson_sysconf.cores_per_node = 4;
1006fbde6b4SJiaxun Yang loongson_sysconf.cores_per_package = 4;
1016fbde6b4SJiaxun Yang smp_group[0] = 0x900000003ff01000;
1026fbde6b4SJiaxun Yang smp_group[1] = 0x900010003ff01000;
1036fbde6b4SJiaxun Yang smp_group[2] = 0x900020003ff01000;
1046fbde6b4SJiaxun Yang smp_group[3] = 0x900030003ff01000;
1056fbde6b4SJiaxun Yang loongson_chipcfg[0] = 0x900000001fe00180;
1066fbde6b4SJiaxun Yang loongson_chipcfg[1] = 0x900010001fe00180;
1076fbde6b4SJiaxun Yang loongson_chipcfg[2] = 0x900020001fe00180;
1086fbde6b4SJiaxun Yang loongson_chipcfg[3] = 0x900030001fe00180;
1096fbde6b4SJiaxun Yang loongson_chiptemp[0] = 0x900000001fe0019c;
1106fbde6b4SJiaxun Yang loongson_chiptemp[1] = 0x900010001fe0019c;
1116fbde6b4SJiaxun Yang loongson_chiptemp[2] = 0x900020001fe0019c;
1126fbde6b4SJiaxun Yang loongson_chiptemp[3] = 0x900030001fe0019c;
1136fbde6b4SJiaxun Yang loongson_freqctrl[0] = 0x900000001fe001d0;
1146fbde6b4SJiaxun Yang loongson_freqctrl[1] = 0x900010001fe001d0;
1156fbde6b4SJiaxun Yang loongson_freqctrl[2] = 0x900020001fe001d0;
1166fbde6b4SJiaxun Yang loongson_freqctrl[3] = 0x900030001fe001d0;
1176fbde6b4SJiaxun Yang loongson_sysconf.workarounds = WORKAROUND_CPUFREQ;
1186fbde6b4SJiaxun Yang break;
1196fbde6b4SJiaxun Yang case Legacy_3B:
1206fbde6b4SJiaxun Yang case Loongson_3B:
1216fbde6b4SJiaxun Yang loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */
1226fbde6b4SJiaxun Yang loongson_sysconf.cores_per_package = 8;
1236fbde6b4SJiaxun Yang smp_group[0] = 0x900000003ff01000;
1246fbde6b4SJiaxun Yang smp_group[1] = 0x900010003ff05000;
1256fbde6b4SJiaxun Yang smp_group[2] = 0x900020003ff09000;
1266fbde6b4SJiaxun Yang smp_group[3] = 0x900030003ff0d000;
1276fbde6b4SJiaxun Yang loongson_chipcfg[0] = 0x900000001fe00180;
1286fbde6b4SJiaxun Yang loongson_chipcfg[1] = 0x900020001fe00180;
1296fbde6b4SJiaxun Yang loongson_chipcfg[2] = 0x900040001fe00180;
1306fbde6b4SJiaxun Yang loongson_chipcfg[3] = 0x900060001fe00180;
1316fbde6b4SJiaxun Yang loongson_chiptemp[0] = 0x900000001fe0019c;
1326fbde6b4SJiaxun Yang loongson_chiptemp[1] = 0x900020001fe0019c;
1336fbde6b4SJiaxun Yang loongson_chiptemp[2] = 0x900040001fe0019c;
1346fbde6b4SJiaxun Yang loongson_chiptemp[3] = 0x900060001fe0019c;
1356fbde6b4SJiaxun Yang loongson_freqctrl[0] = 0x900000001fe001d0;
1366fbde6b4SJiaxun Yang loongson_freqctrl[1] = 0x900020001fe001d0;
1376fbde6b4SJiaxun Yang loongson_freqctrl[2] = 0x900040001fe001d0;
1386fbde6b4SJiaxun Yang loongson_freqctrl[3] = 0x900060001fe001d0;
1396fbde6b4SJiaxun Yang loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG;
1406fbde6b4SJiaxun Yang break;
1416fbde6b4SJiaxun Yang default:
1426fbde6b4SJiaxun Yang loongson_sysconf.cores_per_node = 1;
1436fbde6b4SJiaxun Yang loongson_sysconf.cores_per_package = 1;
1446fbde6b4SJiaxun Yang loongson_chipcfg[0] = 0x900000001fe00180;
1456fbde6b4SJiaxun Yang }
1466fbde6b4SJiaxun Yang
1476fbde6b4SJiaxun Yang loongson_sysconf.nr_cpus = ecpu->nr_cpus;
1486fbde6b4SJiaxun Yang loongson_sysconf.boot_cpu_id = ecpu->cpu_startup_core_id;
1496fbde6b4SJiaxun Yang loongson_sysconf.reserved_cpus_mask = ecpu->reserved_cores_mask;
1506fbde6b4SJiaxun Yang if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
1516fbde6b4SJiaxun Yang loongson_sysconf.nr_cpus = NR_CPUS;
1526fbde6b4SJiaxun Yang loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus +
1536fbde6b4SJiaxun Yang loongson_sysconf.cores_per_node - 1) /
1546fbde6b4SJiaxun Yang loongson_sysconf.cores_per_node;
1556fbde6b4SJiaxun Yang
1566fbde6b4SJiaxun Yang loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
1576fbde6b4SJiaxun Yang if (loongson_sysconf.dma_mask_bits < 32 ||
1581eed445dSJiaxun Yang loongson_sysconf.dma_mask_bits > 64) {
1596fbde6b4SJiaxun Yang loongson_sysconf.dma_mask_bits = 32;
1601eed445dSJiaxun Yang dma_default_coherent = true;
1611eed445dSJiaxun Yang } else {
1621eed445dSJiaxun Yang dma_default_coherent = !eirq_source->dma_noncoherent;
1631eed445dSJiaxun Yang }
1641eed445dSJiaxun Yang
1651eed445dSJiaxun Yang pr_info("Firmware: Coherent DMA: %s\n", dma_default_coherent ? "on" : "off");
1666fbde6b4SJiaxun Yang
1676fbde6b4SJiaxun Yang loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
1686fbde6b4SJiaxun Yang loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
1696fbde6b4SJiaxun Yang loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
1706fbde6b4SJiaxun Yang
1716fbde6b4SJiaxun Yang loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
1726fbde6b4SJiaxun Yang pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
1736fbde6b4SJiaxun Yang loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
1746fbde6b4SJiaxun Yang loongson_sysconf.vgabios_addr);
1756fbde6b4SJiaxun Yang
1766fbde6b4SJiaxun Yang loongson_sysconf.workarounds |= esys->workarounds;
1776fbde6b4SJiaxun Yang
1786fbde6b4SJiaxun Yang pr_info("CpuClock = %u\n", cpu_clock_freq);
1798c88cc53STiezhu Yang
1808c88cc53STiezhu Yang /* Read the ID of PCI host bridge to detect bridge type */
1818c88cc53STiezhu Yang id = readl(HOST_BRIDGE_CONFIG_ADDR);
1828c88cc53STiezhu Yang vendor = id & 0xffff;
1838c88cc53STiezhu Yang
18439c1485cSHuacai Chen switch (vendor) {
18539c1485cSHuacai Chen case PCI_VENDOR_ID_LOONGSON:
1868c88cc53STiezhu Yang pr_info("The bridge chip is LS7A\n");
1878c88cc53STiezhu Yang loongson_sysconf.bridgetype = LS7A;
18868fbb972STiezhu Yang loongson_sysconf.early_config = ls7a_early_config;
18939c1485cSHuacai Chen break;
19039c1485cSHuacai Chen case PCI_VENDOR_ID_AMD:
19139c1485cSHuacai Chen case PCI_VENDOR_ID_ATI:
1928c88cc53STiezhu Yang pr_info("The bridge chip is RS780E or SR5690\n");
1938c88cc53STiezhu Yang loongson_sysconf.bridgetype = RS780E;
19468fbb972STiezhu Yang loongson_sysconf.early_config = rs780e_early_config;
19539c1485cSHuacai Chen break;
19639c1485cSHuacai Chen default:
19739c1485cSHuacai Chen pr_info("The bridge chip is VIRTUAL\n");
19839c1485cSHuacai Chen loongson_sysconf.bridgetype = VIRTUAL;
19939c1485cSHuacai Chen loongson_sysconf.early_config = virtual_early_config;
20039c1485cSHuacai Chen loongson_fdt_blob = __dtb_loongson64v_4core_virtio_begin;
20139c1485cSHuacai Chen break;
2028c88cc53STiezhu Yang }
203770a697cSJiaxun Yang
204770a697cSJiaxun Yang if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64C) {
205770a697cSJiaxun Yang switch (read_c0_prid() & PRID_REV_MASK) {
206770a697cSJiaxun Yang case PRID_REV_LOONGSON3A_R1:
207770a697cSJiaxun Yang case PRID_REV_LOONGSON3A_R2_0:
208770a697cSJiaxun Yang case PRID_REV_LOONGSON3A_R2_1:
209770a697cSJiaxun Yang case PRID_REV_LOONGSON3A_R3_0:
210770a697cSJiaxun Yang case PRID_REV_LOONGSON3A_R3_1:
211770a697cSJiaxun Yang switch (loongson_sysconf.bridgetype) {
212770a697cSJiaxun Yang case LS7A:
213770a697cSJiaxun Yang loongson_fdt_blob = __dtb_loongson64c_4core_ls7a_begin;
214770a697cSJiaxun Yang break;
215770a697cSJiaxun Yang case RS780E:
216770a697cSJiaxun Yang loongson_fdt_blob = __dtb_loongson64c_4core_rs780e_begin;
217770a697cSJiaxun Yang break;
218770a697cSJiaxun Yang default:
219770a697cSJiaxun Yang break;
220770a697cSJiaxun Yang }
221770a697cSJiaxun Yang break;
222770a697cSJiaxun Yang case PRID_REV_LOONGSON3B_R1:
223770a697cSJiaxun Yang case PRID_REV_LOONGSON3B_R2:
224770a697cSJiaxun Yang if (loongson_sysconf.bridgetype == RS780E)
225770a697cSJiaxun Yang loongson_fdt_blob = __dtb_loongson64c_8core_rs780e_begin;
226770a697cSJiaxun Yang break;
227770a697cSJiaxun Yang default:
228770a697cSJiaxun Yang break;
229770a697cSJiaxun Yang }
230*f7097b5fSJiaxun Yang } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R) {
231*f7097b5fSJiaxun Yang loongson_fdt_blob = __dtb_loongson64_2core_2k1000_begin;
232770a697cSJiaxun Yang } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G) {
233770a697cSJiaxun Yang if (loongson_sysconf.bridgetype == LS7A)
234770a697cSJiaxun Yang loongson_fdt_blob = __dtb_loongson64g_4core_ls7a_begin;
235770a697cSJiaxun Yang }
236770a697cSJiaxun Yang
237770a697cSJiaxun Yang if (!loongson_fdt_blob)
238770a697cSJiaxun Yang pr_err("Failed to determine built-in Loongson64 dtb\n");
2396fbde6b4SJiaxun Yang }
240