diff options
-rw-r--r-- | arch/mips/Kconfig | 2 | ||||
-rw-r--r-- | arch/mips/bcm47xx/prom.c | 113 | ||||
-rw-r--r-- | arch/mips/bcm47xx/setup.c | 51 |
3 files changed, 161 insertions, 5 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 4863494bac9f..371434dd744c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -55,6 +55,8 @@ config BCM47XX | |||
55 | select SSB | 55 | select SSB |
56 | select SSB_DRIVER_MIPS | 56 | select SSB_DRIVER_MIPS |
57 | select GENERIC_GPIO | 57 | select GENERIC_GPIO |
58 | select SYS_HAS_EARLY_PRINTK | ||
59 | select CFE | ||
58 | help | 60 | help |
59 | Support for BCM47XX based boards | 61 | Support for BCM47XX based boards |
60 | 62 | ||
diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c index 41ac9dd88bde..079e33d52783 100644 --- a/arch/mips/bcm47xx/prom.c +++ b/arch/mips/bcm47xx/prom.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> | 2 | * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> |
3 | * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net> | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License as published by the | 6 | * under the terms of the GNU General Public License as published by the |
@@ -23,18 +24,117 @@ | |||
23 | */ | 24 | */ |
24 | 25 | ||
25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/types.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/spinlock.h> | ||
26 | #include <asm/bootinfo.h> | 30 | #include <asm/bootinfo.h> |
31 | #include <asm/fw/cfe/cfe_api.h> | ||
32 | #include <asm/fw/cfe/cfe_error.h> | ||
33 | |||
34 | static int cfe_cons_handle; | ||
27 | 35 | ||
28 | const char *get_system_type(void) | 36 | const char *get_system_type(void) |
29 | { | 37 | { |
30 | return "Broadcom BCM47XX"; | 38 | return "Broadcom BCM47XX"; |
31 | } | 39 | } |
32 | 40 | ||
33 | void __init prom_init(void) | 41 | void prom_putchar(char c) |
42 | { | ||
43 | while (cfe_write(cfe_cons_handle, &c, 1) == 0) | ||
44 | ; | ||
45 | } | ||
46 | |||
47 | static __init void prom_init_cfe(void) | ||
48 | { | ||
49 | uint32_t cfe_ept; | ||
50 | uint32_t cfe_handle; | ||
51 | uint32_t cfe_eptseal; | ||
52 | int argc = fw_arg0; | ||
53 | char **envp = (char **) fw_arg2; | ||
54 | int *prom_vec = (int *) fw_arg3; | ||
55 | |||
56 | /* | ||
57 | * Check if a loader was used; if NOT, the 4 arguments are | ||
58 | * what CFE gives us (handle, 0, EPT and EPTSEAL) | ||
59 | */ | ||
60 | if (argc < 0) { | ||
61 | cfe_handle = (uint32_t)argc; | ||
62 | cfe_ept = (uint32_t)envp; | ||
63 | cfe_eptseal = (uint32_t)prom_vec; | ||
64 | } else { | ||
65 | if ((int)prom_vec < 0) { | ||
66 | /* | ||
67 | * Old loader; all it gives us is the handle, | ||
68 | * so use the "known" entrypoint and assume | ||
69 | * the seal. | ||
70 | */ | ||
71 | cfe_handle = (uint32_t)prom_vec; | ||
72 | cfe_ept = 0xBFC00500; | ||
73 | cfe_eptseal = CFE_EPTSEAL; | ||
74 | } else { | ||
75 | /* | ||
76 | * Newer loaders bundle the handle/ept/eptseal | ||
77 | * Note: prom_vec is in the loader's useg | ||
78 | * which is still alive in the TLB. | ||
79 | */ | ||
80 | cfe_handle = prom_vec[0]; | ||
81 | cfe_ept = prom_vec[2]; | ||
82 | cfe_eptseal = prom_vec[3]; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | if (cfe_eptseal != CFE_EPTSEAL) { | ||
87 | /* too early for panic to do any good */ | ||
88 | printk(KERN_ERR "CFE's entrypoint seal doesn't match."); | ||
89 | while (1) ; | ||
90 | } | ||
91 | |||
92 | cfe_init(cfe_handle, cfe_ept); | ||
93 | } | ||
94 | |||
95 | static __init void prom_init_console(void) | ||
96 | { | ||
97 | /* Initialize CFE console */ | ||
98 | cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); | ||
99 | } | ||
100 | |||
101 | static __init void prom_init_cmdline(void) | ||
102 | { | ||
103 | char buf[CL_SIZE]; | ||
104 | |||
105 | /* Get the kernel command line from CFE */ | ||
106 | if (cfe_getenv("LINUX_CMDLINE", buf, CL_SIZE) >= 0) { | ||
107 | buf[CL_SIZE-1] = 0; | ||
108 | strcpy(arcs_cmdline, buf); | ||
109 | } | ||
110 | |||
111 | /* Force a console handover by adding a console= argument if needed, | ||
112 | * as CFE is not available anymore later in the boot process. */ | ||
113 | if ((strstr(arcs_cmdline, "console=")) == NULL) { | ||
114 | /* Try to read the default serial port used by CFE */ | ||
115 | if ((cfe_getenv("BOOT_CONSOLE", buf, CL_SIZE) < 0) | ||
116 | || (strncmp("uart", buf, 4))) | ||
117 | /* Default to uart0 */ | ||
118 | strcpy(buf, "uart0"); | ||
119 | |||
120 | /* Compute the new command line */ | ||
121 | snprintf(arcs_cmdline, CL_SIZE, "%s console=ttyS%c,115200", | ||
122 | arcs_cmdline, buf[4]); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static __init void prom_init_mem(void) | ||
34 | { | 127 | { |
35 | unsigned long mem; | 128 | unsigned long mem; |
36 | 129 | ||
37 | /* Figure out memory size by finding aliases */ | 130 | /* Figure out memory size by finding aliases. |
131 | * | ||
132 | * We should theoretically use the mapping from CFE using cfe_enummem(). | ||
133 | * However as the BCM47XX is mostly used on low-memory systems, we | ||
134 | * want to reuse the memory used by CFE (around 4MB). That means cfe_* | ||
135 | * functions stop to work at some point during the boot, we should only | ||
136 | * call them at the beginning of the boot. | ||
137 | */ | ||
38 | for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { | 138 | for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { |
39 | if (*(unsigned long *)((unsigned long)(prom_init) + mem) == | 139 | if (*(unsigned long *)((unsigned long)(prom_init) + mem) == |
40 | *(unsigned long *)(prom_init)) | 140 | *(unsigned long *)(prom_init)) |
@@ -44,6 +144,15 @@ void __init prom_init(void) | |||
44 | add_memory_region(0, mem, BOOT_MEM_RAM); | 144 | add_memory_region(0, mem, BOOT_MEM_RAM); |
45 | } | 145 | } |
46 | 146 | ||
147 | void __init prom_init(void) | ||
148 | { | ||
149 | prom_init_cfe(); | ||
150 | prom_init_console(); | ||
151 | prom_init_cmdline(); | ||
152 | prom_init_mem(); | ||
153 | } | ||
154 | |||
47 | void __init prom_free_prom_memory(void) | 155 | void __init prom_free_prom_memory(void) |
48 | { | 156 | { |
49 | } | 157 | } |
158 | |||
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index dfc580aae958..f48aa5aa9bf0 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c | |||
@@ -27,9 +27,11 @@ | |||
27 | 27 | ||
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/ssb/ssb.h> | 29 | #include <linux/ssb/ssb.h> |
30 | #include <asm/bootinfo.h> | ||
30 | #include <asm/reboot.h> | 31 | #include <asm/reboot.h> |
31 | #include <asm/time.h> | 32 | #include <asm/time.h> |
32 | #include <bcm47xx.h> | 33 | #include <bcm47xx.h> |
34 | #include <asm/fw/cfe/cfe_api.h> | ||
33 | 35 | ||
34 | struct ssb_bus ssb_bcm47xx; | 36 | struct ssb_bus ssb_bcm47xx; |
35 | EXPORT_SYMBOL(ssb_bcm47xx); | 37 | EXPORT_SYMBOL(ssb_bcm47xx); |
@@ -53,12 +55,55 @@ static void bcm47xx_machine_halt(void) | |||
53 | cpu_relax(); | 55 | cpu_relax(); |
54 | } | 56 | } |
55 | 57 | ||
58 | static void str2eaddr(char *str, char *dest) | ||
59 | { | ||
60 | int i = 0; | ||
61 | |||
62 | if (str == NULL) { | ||
63 | memset(dest, 0, 6); | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | for (;;) { | ||
68 | dest[i++] = (char) simple_strtoul(str, NULL, 16); | ||
69 | str += 2; | ||
70 | if (!*str++ || i == 6) | ||
71 | break; | ||
72 | } | ||
73 | } | ||
74 | |||
56 | static int bcm47xx_get_invariants(struct ssb_bus *bus, | 75 | static int bcm47xx_get_invariants(struct ssb_bus *bus, |
57 | struct ssb_init_invariants *iv) | 76 | struct ssb_init_invariants *iv) |
58 | { | 77 | { |
59 | /* TODO: fill ssb_init_invariants using boardtype/boardrev | 78 | char buf[100]; |
60 | * CFE environment variables. | 79 | |
61 | */ | 80 | /* Fill boardinfo structure */ |
81 | memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); | ||
82 | |||
83 | if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0) | ||
84 | iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); | ||
85 | if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0) | ||
86 | iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); | ||
87 | if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0) | ||
88 | iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); | ||
89 | |||
90 | /* Fill sprom structure */ | ||
91 | memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); | ||
92 | iv->sprom.revision = 3; | ||
93 | |||
94 | if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) | ||
95 | str2eaddr(buf, iv->sprom.r1.et0mac); | ||
96 | if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) | ||
97 | str2eaddr(buf, iv->sprom.r1.et1mac); | ||
98 | if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) | ||
99 | iv->sprom.r1.et0phyaddr = simple_strtoul(buf, NULL, 10); | ||
100 | if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) | ||
101 | iv->sprom.r1.et1phyaddr = simple_strtoul(buf, NULL, 10); | ||
102 | if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) | ||
103 | iv->sprom.r1.et0mdcport = simple_strtoul(buf, NULL, 10); | ||
104 | if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) | ||
105 | iv->sprom.r1.et1mdcport = simple_strtoul(buf, NULL, 10); | ||
106 | |||
62 | return 0; | 107 | return 0; |
63 | } | 108 | } |
64 | 109 | ||