1/* 2 * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc. 3 * All rights reserved. 4 * Authors: Carsten Langgaard <carstenl@mips.com> 5 * Maciej W. Rozycki <macro@mips.com> 6 * 7 * This program is free software; you can distribute it and/or modify it 8 * under the terms of the GNU General Public License (Version 2) as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 19 * 20 * PROM library initialisation code. 21 */ 22#include <linux/init.h> 23#include <linux/string.h> 24#include <linux/kernel.h> 25 26#include <asm/bootinfo.h> 27#include <asm/io.h> 28#include <asm/system.h> 29#include <asm/cacheflush.h> 30#include <asm/traps.h> 31 32#include <asm/mips-boards/prom.h> 33#include <asm/mips-boards/generic.h> 34 35int prom_argc; 36int *_prom_argv, *_prom_envp; 37 38/* 39 * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer. 40 * This macro take care of sign extension, if running in 64-bit mode. 41 */ 42#define prom_envp(index) ((char *)(long)_prom_envp[(index)]) 43 44int init_debug; /* global var => auto initialized to 0 */ 45 46int mips_revision_corid; 47int mips_revision_sconid; 48 49char *prom_getenv(char *envname) 50{ 51 /* 52 * Return a pointer to the given environment variable. 53 * In 64-bit mode: we're using 64-bit pointers, but all pointers 54 * in the PROM structures are only 32-bit, so we need some 55 * workarounds, if we are running in 64-bit mode. 56 */ 57 int i, index = 0; 58 59 i = strlen(envname); 60 61 while (prom_envp(index)) { 62 if (strncmp(envname, prom_envp(index), i) == 0) 63 return prom_envp(index+1); 64 index += 2; 65 } 66 67 return NULL; 68} 69 70static inline unsigned char str2hexnum(unsigned char c) 71{ 72 if (c >= '0' && c <= '9') 73 return c - '0'; 74 if (c >= 'a' && c <= 'f') 75 return c - 'a' + 10; 76 return 0; /* foo */ 77} 78 79static inline void str2eaddr(unsigned char *ea, unsigned char *str) 80{ 81 int i; 82 83 for (i = 0; i < 6; i++) { 84 unsigned char num; 85 86 if ((*str == '.') || (*str == ':')) 87 str++; 88 num = str2hexnum(*str++) << 4; 89 num |= (str2hexnum(*str++)); 90 ea[i] = num; 91 } 92} 93 94int get_ethernet_addr(char *ethernet_addr) 95{ 96 char *ethaddr_str; 97 98 ethaddr_str = prom_getenv("ethaddr"); 99 if (!ethaddr_str) { 100 printk("ethaddr not set in boot prom\n"); 101 return -1; 102 } 103 str2eaddr(ethernet_addr, ethaddr_str); 104 105 if (init_debug > 1) { 106 int i; 107 printk("get_ethernet_addr: "); 108 for (i = 0; i < 5; i++) 109 printk("%02x:", (unsigned char)*(ethernet_addr+i)); 110 printk("%02x\n", *(ethernet_addr+i)); 111 } 112 113 return 0; 114} 115 116#ifdef CONFIG_SERIAL_8250_CONSOLE 117static void __init console_config(void) 118{ 119 char console_string[40]; 120 int baud = 0; 121 char parity = '\0', bits = '\0', flow = '\0'; 122 char *s; 123 124 if ((strstr(prom_getcmdline(), "console=")) == NULL) { 125 s = prom_getenv("modetty0"); 126 if (s) { 127 while (*s >= '0' && *s <= '9') 128 baud = baud*10 + *s++ - '0'; 129 if (*s == ',') 130 s++; 131 if (*s) 132 parity = *s++; 133 if (*s == ',') 134 s++; 135 if (*s) 136 bits = *s++; 137 if (*s == ',') 138 s++; 139 if (*s == 'h') 140 flow = 'r'; 141 } 142 if (baud == 0) 143 baud = 38400; 144 if (parity != 'n' && parity != 'o' && parity != 'e') 145 parity = 'n'; 146 if (bits != '7' && bits != '8') 147 bits = '8'; 148 if (flow == '\0') 149 flow = 'r'; 150 sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, parity, bits, flow); 151 strcat(prom_getcmdline(), console_string); 152 pr_info("Config serial console:%s\n", console_string); 153 } 154} 155#endif 156 157static void __init mips_nmi_setup(void) 158{ 159 void *base; 160 extern char except_vec_nmi; 161 162 base = cpu_has_veic ? 163 (void *)(CAC_BASE + 0xa80) : 164 (void *)(CAC_BASE + 0x380); 165#ifdef CONFIG_CPU_MICROMIPS 166 /* 167 * Decrement the exception vector address by one for MicroMIPS. 168 */ 169 memcpy(base, (&except_vec_nmi - 1), 0x80); 170 171 /* 172 * This is a hack. We do not know if the boot loader was built with 173 * MicroMIPS instructions or not. If it was not, the NMI exception 174 * code at 0x80000a80 will be taken in MIPS32 mode. The hand coded 175 * assembly below forces us into MicroMIPS mode if we are a pure 176 * MicroMIPS kernel. The assembly instructions are: 177 * 178 * 3C1A8000 lui k0,0x8000 179 * 375A0381 ori k0,k0,0x381 180 * 03400008 jr k0 181 * 00000000 nop 182 * 183 * The mode switch occurs by jumping to the unaligned exception 184 * vector address at 0x80000381 which would have been 0x80000380 185 * in MIPS32 mode. The jump to the unaligned address transitions 186 * us into MicroMIPS mode. 187 */ 188 if (!cpu_has_veic) { 189 void *base2 = (void *)(CAC_BASE + 0xa80); 190 *((unsigned int *)base2) = 0x3c1a8000; 191 *((unsigned int *)base2 + 1) = 0x375a0381; 192 *((unsigned int *)base2 + 2) = 0x03400008; 193 *((unsigned int *)base2 + 3) = 0x00000000; 194 flush_icache_range((unsigned long)base2, (unsigned long)base2 + 0x10); 195 } 196#else 197 memcpy(base, &except_vec_nmi, 0x80); 198#endif 199 flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); 200} 201 202static void __init mips_ejtag_setup(void) 203{ 204 void *base; 205 extern char except_vec_ejtag_debug; 206 207 base = cpu_has_veic ? 208 (void *)(CAC_BASE + 0xa00) : 209 (void *)(CAC_BASE + 0x300); 210#ifdef CONFIG_CPU_MICROMIPS 211 /* Deja vu... */ 212 memcpy(base, (&except_vec_ejtag_debug - 1), 0x80); 213 if (!cpu_has_veic) { 214 void *base2 = (void *)(CAC_BASE + 0xa00); 215 *((unsigned int *)base2) = 0x3c1a8000; 216 *((unsigned int *)base2 + 1) = 0x375a0301; 217 *((unsigned int *)base2 + 2) = 0x03400008; 218 *((unsigned int *)base2 + 3) = 0x00000000; 219 flush_icache_range((unsigned long)base2, (unsigned long)base2 + 0x10); 220 } 221#else 222 memcpy(base, &except_vec_ejtag_debug, 0x80); 223#endif 224 flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); 225} 226 227extern struct plat_smp_ops msmtc_smp_ops; 228 229void __init prom_init(void) 230{ 231 prom_argc = fw_arg0; 232 _prom_argv = (int *) fw_arg1; 233 _prom_envp = (int *) fw_arg2; 234 235 mips_display_message("LINUX"); 236 237 mips_revision_corid = MIPS_REVISION_CORID; 238 mips_revision_sconid = MIPS_REVISION_SCONID; 239 if (mips_revision_sconid == MIPS_REVISION_SCON_OTHER) { 240 switch (mips_revision_corid) { 241 case MIPS_REVISION_CORID_QED_RM5261: 242 case MIPS_REVISION_CORID_CORE_LV: 243 case MIPS_REVISION_CORID_CORE_FPGA: 244 case MIPS_REVISION_CORID_CORE_FPGAR2: 245 mips_revision_sconid = MIPS_REVISION_SCON_GT64120; 246 break; 247 case MIPS_REVISION_CORID_CORE_EMUL_BON: 248 case MIPS_REVISION_CORID_BONITO64: 249 case MIPS_REVISION_CORID_CORE_20K: 250 mips_revision_sconid = MIPS_REVISION_SCON_BONITO; 251 break; 252 case MIPS_REVISION_CORID_CORE_MSC: 253 case MIPS_REVISION_CORID_CORE_FPGA2: 254 case MIPS_REVISION_CORID_CORE_24K: 255 /* 256 * SOCit/ROCit support is essentially identical 257 * but make an attempt to distinguish them 258 */ 259 mips_revision_sconid = MIPS_REVISION_SCON_SOCIT; 260 break; 261 case MIPS_REVISION_CORID_CORE_FPGA3: 262 case MIPS_REVISION_CORID_CORE_FPGA4: 263 case MIPS_REVISION_CORID_CORE_FPGA5: 264 case MIPS_REVISION_CORID_CORE_EMUL_MSC: 265 default: 266 /* See above */ 267 mips_revision_sconid = MIPS_REVISION_SCON_ROCIT; 268 break; 269 } 270 } 271 272 board_nmi_handler_setup = mips_nmi_setup; 273 board_ejtag_handler_setup = mips_ejtag_setup; 274 275 pr_info("\nLINUX started...\n"); 276 prom_init_cmdline(); 277 prom_meminit(); 278#ifdef CONFIG_SERIAL_8250_CONSOLE 279 console_config(); 280#endif 281#ifdef CONFIG_MIPS_CMP 282 register_smp_ops(&cmp_smp_ops); 283#endif 284#ifdef CONFIG_MIPS_MT_SMP 285 register_smp_ops(&vsmp_smp_ops); 286#endif 287#ifdef CONFIG_MIPS_MT_SMTC 288 register_smp_ops(&msmtc_smp_ops); 289#endif 290} 291