diff options
author | Huacai Chen <chenhc@lemote.com> | 2014-03-21 06:44:02 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-03-31 12:17:12 -0400 |
commit | 1a08f1524d2ee4d4239e56ee1b3f6da0df929563 (patch) | |
tree | 35e14776ea58a8a99c491479dcd12e0a07cbe256 /arch/mips/loongson | |
parent | 5f6d693ebb4993c49a0d150da1c5fff15867fec0 (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>
Diffstat (limited to 'arch/mips/loongson')
-rw-r--r-- | arch/mips/loongson/common/env.c | 67 | ||||
-rw-r--r-- | arch/mips/loongson/common/init.c | 9 | ||||
-rw-r--r-- | arch/mips/loongson/common/mem.c | 42 | ||||
-rw-r--r-- | arch/mips/loongson/common/pci.c | 6 | ||||
-rw-r--r-- | arch/mips/loongson/common/reset.c | 21 |
5 files changed, 127 insertions, 18 deletions
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 | ||
26 | unsigned long cpu_clock_freq; | 25 | u32 cpu_clock_freq; |
27 | EXPORT_SYMBOL(cpu_clock_freq); | 26 | EXPORT_SYMBOL(cpu_clock_freq); |
28 | unsigned long memsize, highmemsize; | 27 | struct efi_memory_map_loongson *loongson_memmap; |
28 | struct loongson_system_configuration loongson_sysconf; | ||
29 | 29 | ||
30 | #define parse_even_earlier(res, option, p) \ | 30 | #define parse_even_earlier(res, option, p) \ |
31 | do { \ | 31 | do { \ |
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 | ||
38 | void __init prom_init_env(void) | 38 | void __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 = (¤t_cpu_data)->processor_id; | 103 | processor_id = (¤t_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 | ||
18 | void __init prom_init(void) | 18 | void __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 | |||
20 | u32 memsize, highmemsize; | ||
21 | |||
17 | void __init prom_init_memory(void) | 22 | void __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 | |||
59 | void __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 */ |
53 | int __uncached_access(struct file *file, unsigned long addr) | 95 | int __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 | ||
15 | static struct resource loongson_pci_mem_resource = { | 16 | static 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 | ||
20 | static inline void loongson_reboot(void) | 21 | static inline void loongson_reboot(void) |
21 | { | 22 | { |
@@ -37,17 +38,37 @@ static inline void loongson_reboot(void) | |||
37 | 38 | ||
38 | static void loongson_restart(char *command) | 39 | static 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 | ||
47 | static void loongson_poweroff(void) | 58 | static 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 | ||
53 | static void loongson_halt(void) | 74 | static void loongson_halt(void) |