| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 1 | /* | 
|  | 2 | *  Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 3 | *  Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net> | 
| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 4 | * | 
|  | 5 | *  This program is free software; you can redistribute  it and/or modify it | 
|  | 6 | *  under  the terms of  the GNU General  Public License as published by the | 
|  | 7 | *  Free Software Foundation;  either version 2 of the  License, or (at your | 
|  | 8 | *  option) any later version. | 
|  | 9 | * | 
|  | 10 | *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED | 
|  | 11 | *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF | 
|  | 12 | *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN | 
|  | 13 | *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, | 
|  | 14 | *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 
|  | 15 | *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF | 
|  | 16 | *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | 
|  | 17 | *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT | 
|  | 18 | *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 
|  | 19 | *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | 20 | * | 
|  | 21 | *  You should have received a copy of the  GNU General Public License along | 
|  | 22 | *  with this program; if not, write  to the Free Software Foundation, Inc., | 
|  | 23 | *  675 Mass Ave, Cambridge, MA 02139, USA. | 
|  | 24 | */ | 
|  | 25 |  | 
|  | 26 | #include <linux/init.h> | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 27 | #include <linux/types.h> | 
|  | 28 | #include <linux/kernel.h> | 
|  | 29 | #include <linux/spinlock.h> | 
| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 30 | #include <asm/bootinfo.h> | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 31 | #include <asm/fw/cfe/cfe_api.h> | 
|  | 32 | #include <asm/fw/cfe/cfe_error.h> | 
|  | 33 |  | 
|  | 34 | static int cfe_cons_handle; | 
| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 35 |  | 
|  | 36 | const char *get_system_type(void) | 
|  | 37 | { | 
|  | 38 | return "Broadcom BCM47XX"; | 
|  | 39 | } | 
|  | 40 |  | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 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 | { | 
| Dmitri Vorobiev | 7580c9c | 2009-10-13 23:43:24 +0300 | [diff] [blame] | 103 | static char buf[COMMAND_LINE_SIZE] __initdata; | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 104 |  | 
|  | 105 | /* Get the kernel command line from CFE */ | 
| Dmitri Vorobiev | 7580c9c | 2009-10-13 23:43:24 +0300 | [diff] [blame] | 106 | if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) { | 
|  | 107 | buf[COMMAND_LINE_SIZE - 1] = 0; | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 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 */ | 
| Dmitri Vorobiev | 7580c9c | 2009-10-13 23:43:24 +0300 | [diff] [blame] | 115 | if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0) | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 116 | || (strncmp("uart", buf, 4))) | 
|  | 117 | /* Default to uart0 */ | 
|  | 118 | strcpy(buf, "uart0"); | 
|  | 119 |  | 
|  | 120 | /* Compute the new command line */ | 
| Dmitri Vorobiev | 7580c9c | 2009-10-13 23:43:24 +0300 | [diff] [blame] | 121 | snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200", | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 122 | arcs_cmdline, buf[4]); | 
|  | 123 | } | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | static __init void prom_init_mem(void) | 
| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 127 | { | 
|  | 128 | unsigned long mem; | 
| Hauke Mehrtens | aec9222 | 2010-07-27 22:12:43 +0200 | [diff] [blame] | 129 | unsigned long max; | 
| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 130 |  | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 131 | /* Figure out memory size by finding aliases. | 
|  | 132 | * | 
|  | 133 | * We should theoretically use the mapping from CFE using cfe_enummem(). | 
|  | 134 | * However as the BCM47XX is mostly used on low-memory systems, we | 
|  | 135 | * want to reuse the memory used by CFE (around 4MB). That means cfe_* | 
|  | 136 | * functions stop to work at some point during the boot, we should only | 
|  | 137 | * call them at the beginning of the boot. | 
| Hauke Mehrtens | aec9222 | 2010-07-27 22:12:43 +0200 | [diff] [blame] | 138 | * | 
|  | 139 | * BCM47XX uses 128MB for addressing the ram, if the system contains | 
|  | 140 | * less that that amount of ram it remaps the ram more often into the | 
|  | 141 | * available space. | 
|  | 142 | * Accessing memory after 128MB will cause an exception. | 
|  | 143 | * max contains the biggest possible address supported by the platform. | 
|  | 144 | * If the method wants to try something above we assume 128MB ram. | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 145 | */ | 
| Hauke Mehrtens | aec9222 | 2010-07-27 22:12:43 +0200 | [diff] [blame] | 146 | max = ((unsigned long)(prom_init) | ((128 << 20) - 1)); | 
| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 147 | for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { | 
| Hauke Mehrtens | aec9222 | 2010-07-27 22:12:43 +0200 | [diff] [blame] | 148 | if (((unsigned long)(prom_init) + mem) > max) { | 
|  | 149 | mem = (128 << 20); | 
|  | 150 | printk(KERN_DEBUG "assume 128MB RAM\n"); | 
|  | 151 | break; | 
|  | 152 | } | 
| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 153 | if (*(unsigned long *)((unsigned long)(prom_init) + mem) == | 
|  | 154 | *(unsigned long *)(prom_init)) | 
|  | 155 | break; | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | add_memory_region(0, mem, BOOT_MEM_RAM); | 
|  | 159 | } | 
|  | 160 |  | 
| Aurelien Jarno | 25e5fb9 | 2007-09-25 15:41:24 +0200 | [diff] [blame] | 161 | void __init prom_init(void) | 
|  | 162 | { | 
|  | 163 | prom_init_cfe(); | 
|  | 164 | prom_init_console(); | 
|  | 165 | prom_init_cmdline(); | 
|  | 166 | prom_init_mem(); | 
|  | 167 | } | 
|  | 168 |  | 
| Aurelien Jarno | 1c0c13e | 2007-09-25 15:40:12 +0200 | [diff] [blame] | 169 | void __init prom_free_prom_memory(void) | 
|  | 170 | { | 
|  | 171 | } |