xref: /openbmc/linux/arch/mips/loongson64/env.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
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