1/* 2 * BRIEF MODULE DESCRIPTION 3 * PROM library initialisation code, assuming a version of 4 * pmon is the boot code. 5 * 6 * Copyright 2000,2001 MontaVista Software Inc. 7 * Author: MontaVista Software, Inc. 8 * ppopov@mvista.com or source@mvista.com 9 * 10 * This file was derived from Carsten Langgaard's 11 * arch/mips/mips-boards/xx files. 12 * 13 * Carsten Langgaard, carstenl@mips.com 14 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. 15 * 16 * This program is free software; you can redistribute it and/or modify it 17 * under the terms of the GNU General Public License as published by the 18 * Free Software Foundation; either version 2 of the License, or (at your 19 * option) any later version. 20 * 21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 24 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 27 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * You should have received a copy of the GNU General Public License along 33 * with this program; if not, write to the Free Software Foundation, Inc., 34 * 675 Mass Ave, Cambridge, MA 02139, USA. 35 */ 36 37#include <linux/module.h> 38#include <linux/kernel.h> 39#include <linux/init.h> 40#include <linux/string.h> 41#include <linux/interrupt.h> 42#include <linux/mm.h> 43#include <linux/slab.h> 44 45#include <asm/addrspace.h> 46#include <asm/bootinfo.h> 47#include <asm-generic/sections.h> 48#include <asm/page.h> 49 50#include <msp_prom.h> 51#include <msp_regs.h> 52 53/* global PROM environment variables and pointers */ 54int prom_argc; 55char **prom_argv, **prom_envp; 56int *prom_vec; 57 58/* debug flag */ 59int init_debug = 1; 60 61/* memory blocks */ 62struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; 63 64/* default feature sets */ 65static char msp_default_features[] = 66#if defined(CONFIG_PMC_MSP4200_EVAL) \ 67 || defined(CONFIG_PMC_MSP4200_GW) 68 "ERER"; 69#elif defined(CONFIG_PMC_MSP7120_EVAL) \ 70 || defined(CONFIG_PMC_MSP7120_GW) 71 "EMEMSP"; 72#elif defined(CONFIG_PMC_MSP7120_FPGA) 73 "EMEM"; 74#endif 75 76/* conversion functions */ 77static inline unsigned char str2hexnum(unsigned char c) 78{ 79 if (c >= '0' && c <= '9') 80 return c - '0'; 81 if (c >= 'a' && c <= 'f') 82 return c - 'a' + 10; 83 return 0; /* foo */ 84} 85 86int str2eaddr(unsigned char *ea, unsigned char *str) 87{ 88 int index = 0; 89 unsigned char num = 0; 90 91 while (*str != '\0') { 92 if ((*str == '.') || (*str == ':')) { 93 ea[index++] = num; 94 num = 0; 95 str++; 96 } else { 97 num = num << 4; 98 num |= str2hexnum(*str++); 99 } 100 } 101 102 if (index == 5) { 103 ea[index++] = num; 104 return 0; 105 } else 106 return -1; 107} 108EXPORT_SYMBOL(str2eaddr); 109 110static inline unsigned long str2hex(unsigned char *str) 111{ 112 int value = 0; 113 114 while (*str) { 115 value = value << 4; 116 value |= str2hexnum(*str++); 117 } 118 119 return value; 120} 121 122/* function to query the system information */ 123const char *get_system_type(void) 124{ 125#if defined(CONFIG_PMC_MSP4200_EVAL) 126 return "PMC-Sierra MSP4200 Eval Board"; 127#elif defined(CONFIG_PMC_MSP4200_GW) 128 return "PMC-Sierra MSP4200 VoIP Gateway"; 129#elif defined(CONFIG_PMC_MSP7120_EVAL) 130 return "PMC-Sierra MSP7120 Eval Board"; 131#elif defined(CONFIG_PMC_MSP7120_GW) 132 return "PMC-Sierra MSP7120 Residential Gateway"; 133#elif defined(CONFIG_PMC_MSP7120_FPGA) 134 return "PMC-Sierra MSP7120 FPGA"; 135#else 136 #error "What is the type of *your* MSP?" 137#endif 138} 139 140int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr) 141{ 142 char *ethaddr_str; 143 144 ethaddr_str = prom_getenv(ethaddr_name); 145 if (!ethaddr_str) { 146 printk(KERN_WARNING "%s not set in boot prom\n", ethaddr_name); 147 return -1; 148 } 149 150 if (str2eaddr(ethernet_addr, ethaddr_str) == -1) { 151 printk(KERN_WARNING "%s badly formatted-<%s>\n", 152 ethaddr_name, ethaddr_str); 153 return -1; 154 } 155 156 if (init_debug > 1) { 157 int i; 158 printk(KERN_DEBUG "get_ethernet_addr: for %s ", ethaddr_name); 159 for (i = 0; i < 5; i++) 160 printk(KERN_DEBUG "%02x:", 161 (unsigned char)*(ethernet_addr+i)); 162 printk(KERN_DEBUG "%02x\n", *(ethernet_addr+i)); 163 } 164 165 return 0; 166} 167EXPORT_SYMBOL(get_ethernet_addr); 168 169static char *get_features(void) 170{ 171 char *feature = prom_getenv(FEATURES); 172 173 if (feature == NULL) { 174 /* default features based on MACHINE_TYPE */ 175 feature = msp_default_features; 176 } 177 178 return feature; 179} 180 181static char test_feature(char c) 182{ 183 char *feature = get_features(); 184 185 while (*feature) { 186 if (*feature++ == c) 187 return *feature; 188 feature++; 189 } 190 191 return FEATURE_NOEXIST; 192} 193 194unsigned long get_deviceid(void) 195{ 196 char *deviceid = prom_getenv(DEVICEID); 197 198 if (deviceid == NULL) 199 return *DEV_ID_REG; 200 else 201 return str2hex(deviceid); 202} 203 204char identify_pci(void) 205{ 206 return test_feature(PCI_KEY); 207} 208EXPORT_SYMBOL(identify_pci); 209 210char identify_pcimux(void) 211{ 212 return test_feature(PCIMUX_KEY); 213} 214 215char identify_sec(void) 216{ 217 return test_feature(SEC_KEY); 218} 219EXPORT_SYMBOL(identify_sec); 220 221char identify_spad(void) 222{ 223 return test_feature(SPAD_KEY); 224} 225EXPORT_SYMBOL(identify_spad); 226 227char identify_tdm(void) 228{ 229 return test_feature(TDM_KEY); 230} 231EXPORT_SYMBOL(identify_tdm); 232 233char identify_zsp(void) 234{ 235 return test_feature(ZSP_KEY); 236} 237EXPORT_SYMBOL(identify_zsp); 238 239static char identify_enetfeature(char key, unsigned long interface_num) 240{ 241 char *feature = get_features(); 242 243 while (*feature) { 244 if (*feature++ == key && interface_num-- == 0) 245 return *feature; 246 feature++; 247 } 248 249 return FEATURE_NOEXIST; 250} 251 252char identify_enet(unsigned long interface_num) 253{ 254 return identify_enetfeature(ENET_KEY, interface_num); 255} 256EXPORT_SYMBOL(identify_enet); 257 258char identify_enetTxD(unsigned long interface_num) 259{ 260 return identify_enetfeature(ENETTXD_KEY, interface_num); 261} 262EXPORT_SYMBOL(identify_enetTxD); 263 264unsigned long identify_family(void) 265{ 266 unsigned long deviceid; 267 268 deviceid = get_deviceid(); 269 270 return deviceid & CPU_DEVID_FAMILY; 271} 272EXPORT_SYMBOL(identify_family); 273 274unsigned long identify_revision(void) 275{ 276 unsigned long deviceid; 277 278 deviceid = get_deviceid(); 279 280 return deviceid & CPU_DEVID_REVISION; 281} 282EXPORT_SYMBOL(identify_revision); 283 284/* PROM environment functions */ 285char *prom_getenv(char *env_name) 286{ 287 /* 288 * Return a pointer to the given environment variable. prom_envp 289 * points to a null terminated array of pointers to variables. 290 * Environment variables are stored in the form of "memsize=64" 291 */ 292 293 char **var = prom_envp; 294 int i = strlen(env_name); 295 296 while (*var) { 297 if (strncmp(env_name, *var, i) == 0) { 298 return *var + strlen(env_name) + 1; 299 } 300 var++; 301 } 302 303 return NULL; 304} 305 306/* PROM commandline functions */ 307void __init prom_init_cmdline(void) 308{ 309 char *cp; 310 int actr; 311 312 actr = 1; /* Always ignore argv[0] */ 313 314 cp = &(arcs_cmdline[0]); 315 while (actr < prom_argc) { 316 strcpy(cp, prom_argv[actr]); 317 cp += strlen(prom_argv[actr]); 318 *cp++ = ' '; 319 actr++; 320 } 321 if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ 322 --cp; 323 *cp = '\0'; 324} 325 326/* memory allocation functions */ 327static int __init prom_memtype_classify(unsigned int type) 328{ 329 switch (type) { 330 case yamon_free: 331 return BOOT_MEM_RAM; 332 case yamon_prom: 333 return BOOT_MEM_ROM_DATA; 334 default: 335 return BOOT_MEM_RESERVED; 336 } 337} 338 339void __init prom_meminit(void) 340{ 341 struct prom_pmemblock *p; 342 343 p = prom_getmdesc(); 344 345 while (p->size) { 346 long type; 347 unsigned long base, size; 348 349 type = prom_memtype_classify(p->type); 350 base = p->base; 351 size = p->size; 352 353 add_memory_region(base, size, type); 354 p++; 355 } 356} 357 358void __init prom_free_prom_memory(void) 359{ 360 int argc; 361 char **argv; 362 char **envp; 363 char *ptr; 364 int len = 0; 365 int i; 366 unsigned long addr; 367 368 /* 369 * preserve environment variables and command line from pmon/bbload 370 * first preserve the command line 371 */ 372 for (argc = 0; argc < prom_argc; argc++) { 373 len += sizeof(char *); /* length of pointer */ 374 len += strlen(prom_argv[argc]) + 1; /* length of string */ 375 } 376 len += sizeof(char *); /* plus length of null pointer */ 377 378 argv = kmalloc(len, GFP_KERNEL); 379 ptr = (char *) &argv[prom_argc + 1]; /* strings follow array */ 380 381 for (argc = 0; argc < prom_argc; argc++) { 382 argv[argc] = ptr; 383 strcpy(ptr, prom_argv[argc]); 384 ptr += strlen(prom_argv[argc]) + 1; 385 } 386 argv[prom_argc] = NULL; /* end array with null pointer */ 387 prom_argv = argv; 388 389 /* next preserve the environment variables */ 390 len = 0; 391 i = 0; 392 for (envp = prom_envp; *envp != NULL; envp++) { 393 i++; /* count number of environment variables */ 394 len += sizeof(char *); /* length of pointer */ 395 len += strlen(*envp) + 1; /* length of string */ 396 } 397 len += sizeof(char *); /* plus length of null pointer */ 398 399 envp = kmalloc(len, GFP_KERNEL); 400 ptr = (char *) &envp[i+1]; 401 402 for (argc = 0; argc < i; argc++) { 403 envp[argc] = ptr; 404 strcpy(ptr, prom_envp[argc]); 405 ptr += strlen(prom_envp[argc]) + 1; 406 } 407 envp[i] = NULL; /* end array with null pointer */ 408 prom_envp = envp; 409 410 for (i = 0; i < boot_mem_map.nr_map; i++) { 411 if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) 412 continue; 413 414 addr = boot_mem_map.map[i].addr; 415 free_init_pages("prom memory", 416 addr, addr + boot_mem_map.map[i].size); 417 } 418} 419 420struct prom_pmemblock *__init prom_getmdesc(void) 421{ 422 static char memsz_env[] __initdata = "memsize"; 423 static char heaptop_env[] __initdata = "heaptop"; 424 char *str; 425 unsigned int memsize; 426 unsigned int heaptop; 427 int i; 428 429 str = prom_getenv(memsz_env); 430 if (!str) { 431 ppfinit("memsize not set in boot prom, " 432 "set to default (32Mb)\n"); 433 memsize = 0x02000000; 434 } else { 435 memsize = simple_strtol(str, NULL, 0); 436 437 if (memsize == 0) { 438 /* if memsize is a bad size, use reasonable default */ 439 memsize = 0x02000000; 440 } 441 442 /* convert to physical address (removing caching bits, etc) */ 443 memsize = CPHYSADDR(memsize); 444 } 445 446 str = prom_getenv(heaptop_env); 447 if (!str) { 448 heaptop = CPHYSADDR((u32)&_text); 449 ppfinit("heaptop not set in boot prom, " 450 "set to default 0x%08x\n", heaptop); 451 } else { 452 heaptop = simple_strtol(str, NULL, 16); 453 if (heaptop == 0) { 454 /* heaptop conversion bad, might have 0xValue */ 455 heaptop = simple_strtol(str, NULL, 0); 456 457 if (heaptop == 0) { 458 /* heaptop still bad, use reasonable default */ 459 heaptop = CPHYSADDR((u32)&_text); 460 } 461 } 462 463 /* convert to physical address (removing caching bits, etc) */ 464 heaptop = CPHYSADDR((u32)heaptop); 465 } 466 467 /* the base region */ 468 i = 0; 469 mdesc[i].type = BOOT_MEM_RESERVED; 470 mdesc[i].base = 0x00000000; 471 mdesc[i].size = PAGE_ALIGN(0x300 + 0x80); 472 /* jtag interrupt vector + sizeof vector */ 473 474 /* PMON data */ 475 if (heaptop > mdesc[i].base + mdesc[i].size) { 476 i++; /* 1 */ 477 mdesc[i].type = BOOT_MEM_ROM_DATA; 478 mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size; 479 mdesc[i].size = heaptop - mdesc[i].base; 480 } 481 482 /* end of PMON data to start of kernel -- probably zero .. */ 483 if (heaptop != CPHYSADDR((u32)_text)) { 484 i++; /* 2 */ 485 mdesc[i].type = BOOT_MEM_RAM; 486 mdesc[i].base = heaptop; 487 mdesc[i].size = CPHYSADDR((u32)_text) - mdesc[i].base; 488 } 489 490 /* kernel proper */ 491 i++; /* 3 */ 492 mdesc[i].type = BOOT_MEM_RESERVED; 493 mdesc[i].base = CPHYSADDR((u32)_text); 494 mdesc[i].size = CPHYSADDR(PAGE_ALIGN((u32)_end)) - mdesc[i].base; 495 496 /* Remainder of RAM -- under memsize */ 497 i++; /* 5 */ 498 mdesc[i].type = yamon_free; 499 mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size; 500 mdesc[i].size = memsize - mdesc[i].base; 501 502 return &mdesc[0]; 503} 504