1bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin/*
2bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * Based on Ocelot Linux port, which is
3bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * Copyright 2001 MontaVista Software Inc.
4bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * Author: jsun@mvista.com or jsun@junsun.net
5bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin *
6bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * Copyright 2003 ICT CAS
7bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * Author: Michael Guo <guoyi@ict.ac.cn>
8bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin *
9bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
10bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * Author: Fuxin Zhang, zhangfx@lemote.com
11bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin *
12f7a904dffe30a02636053d8022498ced7e44d31cWu Zhangjin * Copyright (C) 2009 Lemote Inc.
13f7a904dffe30a02636053d8022498ced7e44d31cWu Zhangjin * Author: Wu Zhangjin, wuzhangjin@gmail.com
14bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin *
157034228792cc561e79ff8600f02884bd4c80e287Ralf Baechle * This program is free software; you can redistribute	it and/or modify it
167034228792cc561e79ff8600f02884bd4c80e287Ralf Baechle * under  the terms of	the GNU General	 Public License as published by the
17bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * Free Software Foundation;  either version 2 of the  License, or (at your
18bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin * option) any later version.
19bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin */
20f8ede0f700f5478851f242f291d203cde54ca6cfWu Zhangjin#include <linux/module.h>
21bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin#include <asm/bootinfo.h>
225e983ff654ca3df3007b5b558b5271bb4622afa4Wu Zhangjin#include <loongson.h>
231a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen#include <boot_param.h>
245e983ff654ca3df3007b5b558b5271bb4622afa4Wu Zhangjin
251a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chenu32 cpu_clock_freq;
26f8ede0f700f5478851f242f291d203cde54ca6cfWu ZhangjinEXPORT_SYMBOL(cpu_clock_freq);
271a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chenstruct efi_memory_map_loongson *loongson_memmap;
281a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chenstruct loongson_system_configuration loongson_sysconf;
29bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin
30140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chenu64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
31e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenu64 loongson_freqctrl[MAX_PACKAGES];
32e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
33e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenunsigned long long smp_group[4];
34e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenint cpuhotplug_workaround = 0;
35140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen
36bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin#define parse_even_earlier(res, option, p)				\
37bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjindo {									\
38c87444af6fc853dd5571a830efff7e07c46a544eRalf Baechle	unsigned int tmp __maybe_unused;				\
39c87444af6fc853dd5571a830efff7e07c46a544eRalf Baechle									\
40bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin	if (strncmp(option, (char *)p, strlen(option)) == 0)		\
411a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		tmp = kstrtou32((char *)p + strlen(option"="), 10, &res); \
42bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin} while (0)
43bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin
44bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjinvoid __init prom_init_env(void)
45bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin{
46eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin	/* pmon passes arguments in 32bit pointers */
47eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin	unsigned int processor_id;
481a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen
491a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
501a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	int *_prom_envp;
51bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin	long l;
52bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin
53bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin	/* firmware arguments are initialized in head.S */
54bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin	_prom_envp = (int *)fw_arg2;
55bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin
56bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin	l = (long)*_prom_envp;
57bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin	while (l != 0) {
58bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin		parse_even_earlier(cpu_clock_freq, "cpuclock", l);
59bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin		parse_even_earlier(memsize, "memsize", l);
60bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin		parse_even_earlier(highmemsize, "highmemsize", l);
61bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin		_prom_envp++;
62bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin		l = (long)*_prom_envp;
63bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin	}
64bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin	if (memsize == 0)
65bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin		memsize = 256;
661a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize);
671a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen#else
681a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	struct boot_params *boot_p;
691a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	struct loongson_params *loongson_p;
701a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	struct efi_cpuinfo_loongson *ecpu;
711a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	struct irq_source_routing_table *eirq_source;
721a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen
731a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	/* firmware arguments are initialized in head.S */
741a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	boot_p = (struct boot_params *)fw_arg2;
751a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_p = &(boot_p->efi.smbios.lp);
761a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen
771a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	ecpu = (struct efi_cpuinfo_loongson *)
781a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		((u64)loongson_p + loongson_p->cpu_offset);
791a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	eirq_source = (struct irq_source_routing_table *)
801a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		((u64)loongson_p + loongson_p->irq_offset);
811a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_memmap = (struct efi_memory_map_loongson *)
821a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		((u64)loongson_p + loongson_p->memory_offset);
831a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen
841a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	cpu_clock_freq = ecpu->cpu_clock_freq;
851a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.cputype = ecpu->cputype;
86140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen	if (ecpu->cputype == Loongson_3A) {
87c46173183657bbdbe0d54a981c28807581648422Huacai Chen		loongson_sysconf.cores_per_node = 4;
88c46173183657bbdbe0d54a981c28807581648422Huacai Chen		loongson_sysconf.cores_per_package = 4;
89e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		smp_group[0] = 0x900000003ff01000;
90e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		smp_group[1] = 0x900010003ff01000;
91e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		smp_group[2] = 0x900020003ff01000;
92e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		smp_group[3] = 0x900030003ff01000;
93140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen		loongson_chipcfg[0] = 0x900000001fe00180;
94140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen		loongson_chipcfg[1] = 0x900010001fe00180;
95140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen		loongson_chipcfg[2] = 0x900020001fe00180;
96140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen		loongson_chipcfg[3] = 0x900030001fe00180;
97e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
98e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	} else if (ecpu->cputype == Loongson_3B) {
99e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */
100e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_sysconf.cores_per_package = 8;
101e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		smp_group[0] = 0x900000003ff01000;
102e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		smp_group[1] = 0x900010003ff05000;
103e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		smp_group[2] = 0x900020003ff09000;
104e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		smp_group[3] = 0x900030003ff0d000;
105e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_chipcfg[0] = 0x900000001fe00180;
106e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_chipcfg[1] = 0x900020001fe00180;
107e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_chipcfg[2] = 0x900040001fe00180;
108e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_chipcfg[3] = 0x900060001fe00180;
109e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_freqctrl[0] = 0x900000001fe001d0;
110e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_freqctrl[1] = 0x900020001fe001d0;
111e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_freqctrl[2] = 0x900040001fe001d0;
112e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_freqctrl[3] = 0x900060001fe001d0;
113e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson_sysconf.ht_control_base = 0x90001EFDFB000000;
114e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		cpuhotplug_workaround = 1;
115140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen	} else {
116c46173183657bbdbe0d54a981c28807581648422Huacai Chen		loongson_sysconf.cores_per_node = 1;
117c46173183657bbdbe0d54a981c28807581648422Huacai Chen		loongson_sysconf.cores_per_package = 1;
118140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen		loongson_chipcfg[0] = 0x900000001fe00180;
119140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen	}
120140e39c1e3d29f50e161f55cca60f60b80408c2aHuacai Chen
1211a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.nr_cpus = ecpu->nr_cpus;
1221a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
1231a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		loongson_sysconf.nr_cpus = NR_CPUS;
124c46173183657bbdbe0d54a981c28807581648422Huacai Chen	loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus +
125c46173183657bbdbe0d54a981c28807581648422Huacai Chen		loongson_sysconf.cores_per_node - 1) /
126c46173183657bbdbe0d54a981c28807581648422Huacai Chen		loongson_sysconf.cores_per_node;
1271a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen
1281a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr;
1291a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
1301a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr;
1311a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
1321a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	if (loongson_sysconf.dma_mask_bits < 32 ||
1331a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		loongson_sysconf.dma_mask_bits > 64)
1341a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		loongson_sysconf.dma_mask_bits = 32;
1351a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen
1361a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
1371a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
1381a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
1391a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen
1401a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
1411a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
1421a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
1431a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		loongson_sysconf.vgabios_addr);
1441a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen#endif
145eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin	if (cpu_clock_freq == 0) {
146eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin		processor_id = (&current_cpu_data)->processor_id;
147eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin		switch (processor_id & PRID_REV_MASK) {
148eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin		case PRID_REV_LOONGSON2E:
149eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin			cpu_clock_freq = 533080000;
150eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin			break;
151eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin		case PRID_REV_LOONGSON2F:
152eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin			cpu_clock_freq = 797000000;
153eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin			break;
1541a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen		case PRID_REV_LOONGSON3A:
1551a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen			cpu_clock_freq = 900000000;
1561a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen			break;
157e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		case PRID_REV_LOONGSON3B_R1:
158e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		case PRID_REV_LOONGSON3B_R2:
159e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen			cpu_clock_freq = 1000000000;
160e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen			break;
161eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin		default:
162eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin			cpu_clock_freq = 100000000;
163eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin			break;
164eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin		}
165eb11df472d8491fcb28534b59017e1b5465997faWu Zhangjin	}
1661a08f1524d2ee4d4239e56ee1b3f6da0df929563Huacai Chen	pr_info("CpuClock = %u\n", cpu_clock_freq);
167bd92aa013e8fcd17328ec8e060477761cf3380d9Wu Zhangjin}
168