aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2007-09-25 09:41:24 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-10-11 18:46:06 -0400
commit25e5fb97419f73d39b37e9f73f9492c394de07b2 (patch)
tree42d3ced7426d396fef5a52bc69c20eb4092babf6 /arch
parent2f56cfdd812a17623483d3dfa3370a2e6282b245 (diff)
[MIPS] Add CFE support to BCM47XX
Add CFE support to the BCM47XX code. That includes querying CFE environment variables as well as using CFE to print messages before the serial port is initialized (early printk). Signed-off-by: Aurelien Jarno <aurel32@farad.aurel32.net> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/Kconfig2
-rw-r--r--arch/mips/bcm47xx/prom.c113
-rw-r--r--arch/mips/bcm47xx/setup.c51
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
34static int cfe_cons_handle;
27 35
28const char *get_system_type(void) 36const char *get_system_type(void)
29{ 37{
30 return "Broadcom BCM47XX"; 38 return "Broadcom BCM47XX";
31} 39}
32 40
33void __init prom_init(void) 41void prom_putchar(char c)
42{
43 while (cfe_write(cfe_cons_handle, &c, 1) == 0)
44 ;
45}
46
47static __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
95static __init void prom_init_console(void)
96{
97 /* Initialize CFE console */
98 cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
99}
100
101static __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
126static __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
147void __init prom_init(void)
148{
149 prom_init_cfe();
150 prom_init_console();
151 prom_init_cmdline();
152 prom_init_mem();
153}
154
47void __init prom_free_prom_memory(void) 155void __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
34struct ssb_bus ssb_bcm47xx; 36struct ssb_bus ssb_bcm47xx;
35EXPORT_SYMBOL(ssb_bcm47xx); 37EXPORT_SYMBOL(ssb_bcm47xx);
@@ -53,12 +55,55 @@ static void bcm47xx_machine_halt(void)
53 cpu_relax(); 55 cpu_relax();
54} 56}
55 57
58static 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
56static int bcm47xx_get_invariants(struct ssb_bus *bus, 75static 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