| 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 | } |