aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuacai Chen <chenhc@lemote.com>2014-03-21 06:44:02 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-03-31 12:17:12 -0400
commit1a08f1524d2ee4d4239e56ee1b3f6da0df929563 (patch)
tree35e14776ea58a8a99c491479dcd12e0a07cbe256
parent5f6d693ebb4993c49a0d150da1c5fff15867fec0 (diff)
MIPS: Loongson: Add UEFI-like firmware interface (LEFI) support
The new UEFI-like firmware interface (LEFI, i.e. Loongson Unified Firmware Interface) has 3 advantages: 1, Firmware export a physical memory map which is similar to X86's E820 map, so prom_init_memory() will be more elegant that #ifdef clauses can be removed. 2, Firmware export a pci irq routing table, we no longer need pci irq routing fixup in kernel's code. 3, Firmware has a built-in vga bios, and its address is exported, the linux kernel no longer need an embedded blob. With the LEFI interface, Loongson-3A/2G and all their successors can use a unified kernel. All Loongson-based machines support this new interface except 2E/2F series. Signed-off-by: Huacai Chen <chenhc@lemote.com> Signed-off-by: Hongliang Tao <taohl@lemote.com> Signed-off-by: Hua Yan <yanh@lemote.com> Tested-by: Alex Smith <alex.smith@imgtec.com> Reviewed-by: Alex Smith <alex.smith@imgtec.com> Cc: John Crispin <john@phrozen.org> Cc: Steven J. Hill <Steven.Hill@imgtec.com> Cc: Aurelien Jarno <aurelien@aurel32.net> Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang <zhangfx@lemote.com> Cc: Zhangjin Wu <wuzhangjin@gmail.com> Patchwork: https://patchwork.linux-mips.org/patch/6632 Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/include/asm/mach-loongson/boot_param.h163
-rw-r--r--arch/mips/include/asm/mach-loongson/loongson.h4
-rw-r--r--arch/mips/loongson/common/env.c67
-rw-r--r--arch/mips/loongson/common/init.c9
-rw-r--r--arch/mips/loongson/common/mem.c42
-rw-r--r--arch/mips/loongson/common/pci.c6
-rw-r--r--arch/mips/loongson/common/reset.c21
7 files changed, 292 insertions, 20 deletions
diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h b/arch/mips/include/asm/mach-loongson/boot_param.h
new file mode 100644
index 000000000000..829a7ec185fb
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/boot_param.h
@@ -0,0 +1,163 @@
1#ifndef __ASM_MACH_LOONGSON_BOOT_PARAM_H_
2#define __ASM_MACH_LOONGSON_BOOT_PARAM_H_
3
4#define SYSTEM_RAM_LOW 1
5#define SYSTEM_RAM_HIGH 2
6#define MEM_RESERVED 3
7#define PCI_IO 4
8#define PCI_MEM 5
9#define LOONGSON_CFG_REG 6
10#define VIDEO_ROM 7
11#define ADAPTER_ROM 8
12#define ACPI_TABLE 9
13#define MAX_MEMORY_TYPE 10
14
15#define LOONGSON3_BOOT_MEM_MAP_MAX 128
16struct efi_memory_map_loongson {
17 u16 vers; /* version of efi_memory_map */
18 u32 nr_map; /* number of memory_maps */
19 u32 mem_freq; /* memory frequence */
20 struct mem_map {
21 u32 node_id; /* node_id which memory attached to */
22 u32 mem_type; /* system memory, pci memory, pci io, etc. */
23 u64 mem_start; /* memory map start address */
24 u32 mem_size; /* each memory_map size, not the total size */
25 } map[LOONGSON3_BOOT_MEM_MAP_MAX];
26} __packed;
27
28enum loongson_cpu_type {
29 Loongson_2E = 0,
30 Loongson_2F = 1,
31 Loongson_3A = 2,
32 Loongson_3B = 3,
33 Loongson_1A = 4,
34 Loongson_1B = 5
35};
36
37/*
38 * Capability and feature descriptor structure for MIPS CPU
39 */
40struct efi_cpuinfo_loongson {
41 u16 vers; /* version of efi_cpuinfo_loongson */
42 u32 processor_id; /* PRID, e.g. 6305, 6306 */
43 u32 cputype; /* Loongson_3A/3B, etc. */
44 u32 total_node; /* num of total numa nodes */
45 u32 cpu_startup_core_id; /* Core id */
46 u32 cpu_clock_freq; /* cpu_clock */
47 u32 nr_cpus;
48} __packed;
49
50struct system_loongson {
51 u16 vers; /* version of system_loongson */
52 u32 ccnuma_smp; /* 0: no numa; 1: has numa */
53 u32 sing_double_channel; /* 1:single; 2:double */
54} __packed;
55
56struct irq_source_routing_table {
57 u16 vers;
58 u16 size;
59 u16 rtr_bus;
60 u16 rtr_devfn;
61 u32 vendor;
62 u32 device;
63 u32 PIC_type; /* conform use HT or PCI to route to CPU-PIC */
64 u64 ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */
65 u64 ht_enable; /* irqs used in this PIC */
66 u32 node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */
67 u64 pci_mem_start_addr;
68 u64 pci_mem_end_addr;
69 u64 pci_io_start_addr;
70 u64 pci_io_end_addr;
71 u64 pci_config_addr;
72 u32 dma_mask_bits;
73} __packed;
74
75struct interface_info {
76 u16 vers; /* version of the specificition */
77 u16 size;
78 u8 flag;
79 char description[64];
80} __packed;
81
82#define MAX_RESOURCE_NUMBER 128
83struct resource_loongson {
84 u64 start; /* resource start address */
85 u64 end; /* resource end address */
86 char name[64];
87 u32 flags;
88};
89
90struct archdev_data {}; /* arch specific additions */
91
92struct board_devices {
93 char name[64]; /* hold the device name */
94 u32 num_resources; /* number of device_resource */
95 /* for each device's resource */
96 struct resource_loongson resource[MAX_RESOURCE_NUMBER];
97 /* arch specific additions */
98 struct archdev_data archdata;
99};
100
101struct loongson_special_attribute {
102 u16 vers; /* version of this special */
103 char special_name[64]; /* special_atribute_name */
104 u32 loongson_special_type; /* type of special device */
105 /* for each device's resource */
106 struct resource_loongson resource[MAX_RESOURCE_NUMBER];
107};
108
109struct loongson_params {
110 u64 memory_offset; /* efi_memory_map_loongson struct offset */
111 u64 cpu_offset; /* efi_cpuinfo_loongson struct offset */
112 u64 system_offset; /* system_loongson struct offset */
113 u64 irq_offset; /* irq_source_routing_table struct offset */
114 u64 interface_offset; /* interface_info struct offset */
115 u64 special_offset; /* loongson_special_attribute struct offset */
116 u64 boarddev_table_offset; /* board_devices offset */
117};
118
119struct smbios_tables {
120 u16 vers; /* version of smbios */
121 u64 vga_bios; /* vga_bios address */
122 struct loongson_params lp;
123};
124
125struct efi_reset_system_t {
126 u64 ResetCold;
127 u64 ResetWarm;
128 u64 ResetType;
129 u64 Shutdown;
130 u64 DoSuspend; /* NULL if not support */
131};
132
133struct efi_loongson {
134 u64 mps; /* MPS table */
135 u64 acpi; /* ACPI table (IA64 ext 0.71) */
136 u64 acpi20; /* ACPI table (ACPI 2.0) */
137 struct smbios_tables smbios; /* SM BIOS table */
138 u64 sal_systab; /* SAL system table */
139 u64 boot_info; /* boot info table */
140};
141
142struct boot_params {
143 struct efi_loongson efi;
144 struct efi_reset_system_t reset_system;
145};
146
147struct loongson_system_configuration {
148 u32 nr_cpus;
149 enum loongson_cpu_type cputype;
150 u64 ht_control_base;
151 u64 pci_mem_start_addr;
152 u64 pci_mem_end_addr;
153 u64 pci_io_base;
154 u64 restart_addr;
155 u64 poweroff_addr;
156 u64 suspend_addr;
157 u64 vgabios_addr;
158 u32 dma_mask_bits;
159};
160
161extern struct efi_memory_map_loongson *loongson_memmap;
162extern struct loongson_system_configuration loongson_sysconf;
163#endif
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index b286534fef08..5913ea064ebe 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -24,8 +24,8 @@ extern void mach_prepare_reboot(void);
24extern void mach_prepare_shutdown(void); 24extern void mach_prepare_shutdown(void);
25 25
26/* environment arguments from bootloader */ 26/* environment arguments from bootloader */
27extern unsigned long cpu_clock_freq; 27extern u32 cpu_clock_freq;
28extern unsigned long memsize, highmemsize; 28extern u32 memsize, highmemsize;
29 29
30/* loongson-specific command line, env and memory initialization */ 30/* loongson-specific command line, env and memory initialization */
31extern void __init prom_init_memory(void); 31extern void __init prom_init_memory(void);
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c
index 0a18fcf2d372..0c543eae49bf 100644
--- a/arch/mips/loongson/common/env.c
+++ b/arch/mips/loongson/common/env.c
@@ -18,29 +18,30 @@
18 * option) any later version. 18 * option) any later version.
19 */ 19 */
20#include <linux/module.h> 20#include <linux/module.h>
21
22#include <asm/bootinfo.h> 21#include <asm/bootinfo.h>
23
24#include <loongson.h> 22#include <loongson.h>
23#include <boot_param.h>
25 24
26unsigned long cpu_clock_freq; 25u32 cpu_clock_freq;
27EXPORT_SYMBOL(cpu_clock_freq); 26EXPORT_SYMBOL(cpu_clock_freq);
28unsigned long memsize, highmemsize; 27struct efi_memory_map_loongson *loongson_memmap;
28struct loongson_system_configuration loongson_sysconf;
29 29
30#define parse_even_earlier(res, option, p) \ 30#define parse_even_earlier(res, option, p) \
31do { \ 31do { \
32 unsigned int tmp __maybe_unused; \ 32 unsigned int tmp __maybe_unused; \
33 \ 33 \
34 if (strncmp(option, (char *)p, strlen(option)) == 0) \ 34 if (strncmp(option, (char *)p, strlen(option)) == 0) \
35 tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \ 35 tmp = kstrtou32((char *)p + strlen(option"="), 10, &res); \
36} while (0) 36} while (0)
37 37
38void __init prom_init_env(void) 38void __init prom_init_env(void)
39{ 39{
40 /* pmon passes arguments in 32bit pointers */ 40 /* pmon passes arguments in 32bit pointers */
41 int *_prom_envp;
42 unsigned long bus_clock;
43 unsigned int processor_id; 41 unsigned int processor_id;
42
43#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
44 int *_prom_envp;
44 long l; 45 long l;
45 46
46 /* firmware arguments are initialized in head.S */ 47 /* firmware arguments are initialized in head.S */
@@ -48,7 +49,6 @@ void __init prom_init_env(void)
48 49
49 l = (long)*_prom_envp; 50 l = (long)*_prom_envp;
50 while (l != 0) { 51 while (l != 0) {
51 parse_even_earlier(bus_clock, "busclock", l);
52 parse_even_earlier(cpu_clock_freq, "cpuclock", l); 52 parse_even_earlier(cpu_clock_freq, "cpuclock", l);
53 parse_even_earlier(memsize, "memsize", l); 53 parse_even_earlier(memsize, "memsize", l);
54 parse_even_earlier(highmemsize, "highmemsize", l); 54 parse_even_earlier(highmemsize, "highmemsize", l);
@@ -57,8 +57,48 @@ void __init prom_init_env(void)
57 } 57 }
58 if (memsize == 0) 58 if (memsize == 0)
59 memsize = 256; 59 memsize = 256;
60 if (bus_clock == 0) 60 pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize);
61 bus_clock = 66000000; 61#else
62 struct boot_params *boot_p;
63 struct loongson_params *loongson_p;
64 struct efi_cpuinfo_loongson *ecpu;
65 struct irq_source_routing_table *eirq_source;
66
67 /* firmware arguments are initialized in head.S */
68 boot_p = (struct boot_params *)fw_arg2;
69 loongson_p = &(boot_p->efi.smbios.lp);
70
71 ecpu = (struct efi_cpuinfo_loongson *)
72 ((u64)loongson_p + loongson_p->cpu_offset);
73 eirq_source = (struct irq_source_routing_table *)
74 ((u64)loongson_p + loongson_p->irq_offset);
75 loongson_memmap = (struct efi_memory_map_loongson *)
76 ((u64)loongson_p + loongson_p->memory_offset);
77
78 cpu_clock_freq = ecpu->cpu_clock_freq;
79 loongson_sysconf.cputype = ecpu->cputype;
80 loongson_sysconf.nr_cpus = ecpu->nr_cpus;
81 if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
82 loongson_sysconf.nr_cpus = NR_CPUS;
83
84 loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr;
85 loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
86 loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr;
87 loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
88 if (loongson_sysconf.dma_mask_bits < 32 ||
89 loongson_sysconf.dma_mask_bits > 64)
90 loongson_sysconf.dma_mask_bits = 32;
91
92 loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
93 loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
94 loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
95
96 loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
97 loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
98 pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
99 loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
100 loongson_sysconf.vgabios_addr);
101#endif
62 if (cpu_clock_freq == 0) { 102 if (cpu_clock_freq == 0) {
63 processor_id = (&current_cpu_data)->processor_id; 103 processor_id = (&current_cpu_data)->processor_id;
64 switch (processor_id & PRID_REV_MASK) { 104 switch (processor_id & PRID_REV_MASK) {
@@ -68,12 +108,13 @@ void __init prom_init_env(void)
68 case PRID_REV_LOONGSON2F: 108 case PRID_REV_LOONGSON2F:
69 cpu_clock_freq = 797000000; 109 cpu_clock_freq = 797000000;
70 break; 110 break;
111 case PRID_REV_LOONGSON3A:
112 cpu_clock_freq = 900000000;
113 break;
71 default: 114 default:
72 cpu_clock_freq = 100000000; 115 cpu_clock_freq = 100000000;
73 break; 116 break;
74 } 117 }
75 } 118 }
76 119 pr_info("CpuClock = %u\n", cpu_clock_freq);
77 pr_info("busclock=%ld, cpuclock=%ld, memsize=%ld, highmemsize=%ld\n",
78 bus_clock, cpu_clock_freq, memsize, highmemsize);
79} 120}
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c
index ae7af1fd5d59..81ba3b4a8f30 100644
--- a/arch/mips/loongson/common/init.c
+++ b/arch/mips/loongson/common/init.c
@@ -17,10 +17,6 @@ unsigned long __maybe_unused _loongson_addrwincfg_base;
17 17
18void __init prom_init(void) 18void __init prom_init(void)
19{ 19{
20 /* init base address of io space */
21 set_io_port_base((unsigned long)
22 ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
23
24#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG 20#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
25 _loongson_addrwincfg_base = (unsigned long) 21 _loongson_addrwincfg_base = (unsigned long)
26 ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE); 22 ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE);
@@ -28,6 +24,11 @@ void __init prom_init(void)
28 24
29 prom_init_cmdline(); 25 prom_init_cmdline();
30 prom_init_env(); 26 prom_init_env();
27
28 /* init base address of io space */
29 set_io_port_base((unsigned long)
30 ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
31
31 prom_init_memory(); 32 prom_init_memory();
32 33
33 /*init the uart base address */ 34 /*init the uart base address */
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c
index 8626a42f5b94..b01d52473da8 100644
--- a/arch/mips/loongson/common/mem.c
+++ b/arch/mips/loongson/common/mem.c
@@ -11,9 +11,14 @@
11#include <asm/bootinfo.h> 11#include <asm/bootinfo.h>
12 12
13#include <loongson.h> 13#include <loongson.h>
14#include <boot_param.h>
14#include <mem.h> 15#include <mem.h>
15#include <pci.h> 16#include <pci.h>
16 17
18#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
19
20u32 memsize, highmemsize;
21
17void __init prom_init_memory(void) 22void __init prom_init_memory(void)
18{ 23{
19 add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); 24 add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
@@ -49,6 +54,43 @@ void __init prom_init_memory(void)
49#endif /* !CONFIG_64BIT */ 54#endif /* !CONFIG_64BIT */
50} 55}
51 56
57#else /* CONFIG_LEFI_FIRMWARE_INTERFACE */
58
59void __init prom_init_memory(void)
60{
61 int i;
62 u32 node_id;
63 u32 mem_type;
64
65 /* parse memory information */
66 for (i = 0; i < loongson_memmap->nr_map; i++) {
67 node_id = loongson_memmap->map[i].node_id;
68 mem_type = loongson_memmap->map[i].mem_type;
69
70 if (node_id == 0) {
71 switch (mem_type) {
72 case SYSTEM_RAM_LOW:
73 add_memory_region(loongson_memmap->map[i].mem_start,
74 (u64)loongson_memmap->map[i].mem_size << 20,
75 BOOT_MEM_RAM);
76 break;
77 case SYSTEM_RAM_HIGH:
78 add_memory_region(loongson_memmap->map[i].mem_start,
79 (u64)loongson_memmap->map[i].mem_size << 20,
80 BOOT_MEM_RAM);
81 break;
82 case MEM_RESERVED:
83 add_memory_region(loongson_memmap->map[i].mem_start,
84 (u64)loongson_memmap->map[i].mem_size << 20,
85 BOOT_MEM_RESERVED);
86 break;
87 }
88 }
89 }
90}
91
92#endif /* CONFIG_LEFI_FIRMWARE_INTERFACE */
93
52/* override of arch/mips/mm/cache.c: __uncached_access */ 94/* override of arch/mips/mm/cache.c: __uncached_access */
53int __uncached_access(struct file *file, unsigned long addr) 95int __uncached_access(struct file *file, unsigned long addr)
54{ 96{
diff --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c
index fa7784459721..003ab4e618b3 100644
--- a/arch/mips/loongson/common/pci.c
+++ b/arch/mips/loongson/common/pci.c
@@ -11,6 +11,7 @@
11 11
12#include <pci.h> 12#include <pci.h>
13#include <loongson.h> 13#include <loongson.h>
14#include <boot_param.h>
14 15
15static struct resource loongson_pci_mem_resource = { 16static struct resource loongson_pci_mem_resource = {
16 .name = "pci memory space", 17 .name = "pci memory space",
@@ -82,7 +83,10 @@ static int __init pcibios_init(void)
82 setup_pcimap(); 83 setup_pcimap();
83 84
84 loongson_pci_controller.io_map_base = mips_io_port_base; 85 loongson_pci_controller.io_map_base = mips_io_port_base;
85 86#ifdef CONFIG_LEFI_FIRMWARE_INTERFACE
87 loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr;
88 loongson_pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr;
89#endif
86 register_pci_controller(&loongson_pci_controller); 90 register_pci_controller(&loongson_pci_controller);
87 91
88 return 0; 92 return 0;
diff --git a/arch/mips/loongson/common/reset.c b/arch/mips/loongson/common/reset.c
index 65bfbb5d06f4..a60715e11306 100644
--- a/arch/mips/loongson/common/reset.c
+++ b/arch/mips/loongson/common/reset.c
@@ -16,6 +16,7 @@
16#include <asm/reboot.h> 16#include <asm/reboot.h>
17 17
18#include <loongson.h> 18#include <loongson.h>
19#include <boot_param.h>
19 20
20static inline void loongson_reboot(void) 21static inline void loongson_reboot(void)
21{ 22{
@@ -37,17 +38,37 @@ static inline void loongson_reboot(void)
37 38
38static void loongson_restart(char *command) 39static void loongson_restart(char *command)
39{ 40{
41#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
40 /* do preparation for reboot */ 42 /* do preparation for reboot */
41 mach_prepare_reboot(); 43 mach_prepare_reboot();
42 44
43 /* reboot via jumping to boot base address */ 45 /* reboot via jumping to boot base address */
44 loongson_reboot(); 46 loongson_reboot();
47#else
48 void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
49
50 fw_restart();
51 while (1) {
52 if (cpu_wait)
53 cpu_wait();
54 }
55#endif
45} 56}
46 57
47static void loongson_poweroff(void) 58static void loongson_poweroff(void)
48{ 59{
60#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
49 mach_prepare_shutdown(); 61 mach_prepare_shutdown();
50 unreachable(); 62 unreachable();
63#else
64 void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
65
66 fw_poweroff();
67 while (1) {
68 if (cpu_wait)
69 cpu_wait();
70 }
71#endif
51} 72}
52 73
53static void loongson_halt(void) 74static void loongson_halt(void)