msp_prom.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  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. #include <linux/module.h>
  37. #include <linux/kernel.h>
  38. #include <linux/init.h>
  39. #include <linux/string.h>
  40. #include <linux/interrupt.h>
  41. #include <linux/mm.h>
  42. #ifdef CONFIG_CRAMFS
  43. #include <linux/cramfs_fs.h>
  44. #endif
  45. #ifdef CONFIG_SQUASHFS
  46. #include <linux/squashfs_fs.h>
  47. #endif
  48. #include <asm/addrspace.h>
  49. #include <asm/bootinfo.h>
  50. #include <asm-generic/sections.h>
  51. #include <asm/page.h>
  52. #include <msp_prom.h>
  53. #include <msp_regs.h>
  54. /* global PROM environment variables and pointers */
  55. int prom_argc;
  56. char **prom_argv, **prom_envp;
  57. int *prom_vec;
  58. /* debug flag */
  59. int init_debug = 1;
  60. /* memory blocks */
  61. struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
  62. /* default feature sets */
  63. static char msp_default_features[] =
  64. #if defined(CONFIG_PMC_MSP4200_EVAL) \
  65. || defined(CONFIG_PMC_MSP4200_GW)
  66. "ERER";
  67. #elif defined(CONFIG_PMC_MSP7120_EVAL) \
  68. || defined(CONFIG_PMC_MSP7120_GW)
  69. "EMEMSP";
  70. #elif defined(CONFIG_PMC_MSP7120_FPGA)
  71. "EMEM";
  72. #endif
  73. /* conversion functions */
  74. static inline unsigned char str2hexnum(unsigned char c)
  75. {
  76. if (c >= '0' && c <= '9')
  77. return c - '0';
  78. if (c >= 'a' && c <= 'f')
  79. return c - 'a' + 10;
  80. return 0; /* foo */
  81. }
  82. static inline int str2eaddr(unsigned char *ea, unsigned char *str)
  83. {
  84. int index = 0;
  85. unsigned char num = 0;
  86. while (*str != '\0') {
  87. if ((*str == '.') || (*str == ':')) {
  88. ea[index++] = num;
  89. num = 0;
  90. str++;
  91. } else {
  92. num = num << 4;
  93. num |= str2hexnum(*str++);
  94. }
  95. }
  96. if (index == 5) {
  97. ea[index++] = num;
  98. return 0;
  99. } else
  100. return -1;
  101. }
  102. EXPORT_SYMBOL(str2eaddr);
  103. static inline unsigned long str2hex(unsigned char *str)
  104. {
  105. int value = 0;
  106. while (*str) {
  107. value = value << 4;
  108. value |= str2hexnum(*str++);
  109. }
  110. return value;
  111. }
  112. /* function to query the system information */
  113. const char *get_system_type(void)
  114. {
  115. #if defined(CONFIG_PMC_MSP4200_EVAL)
  116. return "PMC-Sierra MSP4200 Eval Board";
  117. #elif defined(CONFIG_PMC_MSP4200_GW)
  118. return "PMC-Sierra MSP4200 VoIP Gateway";
  119. #elif defined(CONFIG_PMC_MSP7120_EVAL)
  120. return "PMC-Sierra MSP7120 Eval Board";
  121. #elif defined(CONFIG_PMC_MSP7120_GW)
  122. return "PMC-Sierra MSP7120 Residential Gateway";
  123. #elif defined(CONFIG_PMC_MSP7120_FPGA)
  124. return "PMC-Sierra MSP7120 FPGA";
  125. #else
  126. #error "What is the type of *your* MSP?"
  127. #endif
  128. }
  129. int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr)
  130. {
  131. char *ethaddr_str;
  132. ethaddr_str = prom_getenv(ethaddr_name);
  133. if (!ethaddr_str) {
  134. printk(KERN_WARNING "%s not set in boot prom\n", ethaddr_name);
  135. return -1;
  136. }
  137. if (str2eaddr(ethernet_addr, ethaddr_str) == -1) {
  138. printk(KERN_WARNING "%s badly formatted-<%s>\n",
  139. ethaddr_name, ethaddr_str);
  140. return -1;
  141. }
  142. if (init_debug > 1) {
  143. int i;
  144. printk(KERN_DEBUG "get_ethernet_addr: for %s ", ethaddr_name);
  145. for (i = 0; i < 5; i++)
  146. printk(KERN_DEBUG "%02x:",
  147. (unsigned char)*(ethernet_addr+i));
  148. printk(KERN_DEBUG "%02x\n", *(ethernet_addr+i));
  149. }
  150. return 0;
  151. }
  152. EXPORT_SYMBOL(get_ethernet_addr);
  153. static char *get_features(void)
  154. {
  155. char *feature = prom_getenv(FEATURES);
  156. if (feature == NULL) {
  157. /* default features based on MACHINE_TYPE */
  158. feature = msp_default_features;
  159. }
  160. return feature;
  161. }
  162. static char test_feature(char c)
  163. {
  164. char *feature = get_features();
  165. while (*feature) {
  166. if (*feature++ == c)
  167. return *feature;
  168. feature++;
  169. }
  170. return FEATURE_NOEXIST;
  171. }
  172. unsigned long get_deviceid(void)
  173. {
  174. char *deviceid = prom_getenv(DEVICEID);
  175. if (deviceid == NULL)
  176. return *DEV_ID_REG;
  177. else
  178. return str2hex(deviceid);
  179. }
  180. char identify_pci(void)
  181. {
  182. return test_feature(PCI_KEY);
  183. }
  184. EXPORT_SYMBOL(identify_pci);
  185. char identify_pcimux(void)
  186. {
  187. return test_feature(PCIMUX_KEY);
  188. }
  189. char identify_sec(void)
  190. {
  191. return test_feature(SEC_KEY);
  192. }
  193. EXPORT_SYMBOL(identify_sec);
  194. char identify_spad(void)
  195. {
  196. return test_feature(SPAD_KEY);
  197. }
  198. EXPORT_SYMBOL(identify_spad);
  199. char identify_tdm(void)
  200. {
  201. return test_feature(TDM_KEY);
  202. }
  203. EXPORT_SYMBOL(identify_tdm);
  204. char identify_zsp(void)
  205. {
  206. return test_feature(ZSP_KEY);
  207. }
  208. EXPORT_SYMBOL(identify_zsp);
  209. static char identify_enetfeature(char key, unsigned long interface_num)
  210. {
  211. char *feature = get_features();
  212. while (*feature) {
  213. if (*feature++ == key && interface_num-- == 0)
  214. return *feature;
  215. feature++;
  216. }
  217. return FEATURE_NOEXIST;
  218. }
  219. char identify_enet(unsigned long interface_num)
  220. {
  221. return identify_enetfeature(ENET_KEY, interface_num);
  222. }
  223. EXPORT_SYMBOL(identify_enet);
  224. char identify_enetTxD(unsigned long interface_num)
  225. {
  226. return identify_enetfeature(ENETTXD_KEY, interface_num);
  227. }
  228. EXPORT_SYMBOL(identify_enetTxD);
  229. unsigned long identify_family(void)
  230. {
  231. unsigned long deviceid;
  232. deviceid = get_deviceid();
  233. return deviceid & CPU_DEVID_FAMILY;
  234. }
  235. EXPORT_SYMBOL(identify_family);
  236. unsigned long identify_revision(void)
  237. {
  238. unsigned long deviceid;
  239. deviceid = get_deviceid();
  240. return deviceid & CPU_DEVID_REVISION;
  241. }
  242. EXPORT_SYMBOL(identify_revision);
  243. /* PROM environment functions */
  244. char *prom_getenv(char *env_name)
  245. {
  246. /*
  247. * Return a pointer to the given environment variable. prom_envp
  248. * points to a null terminated array of pointers to variables.
  249. * Environment variables are stored in the form of "memsize=64"
  250. */
  251. char **var = prom_envp;
  252. int i = strlen(env_name);
  253. while (*var) {
  254. if (strncmp(env_name, *var, i) == 0) {
  255. return (*var + strlen(env_name) + 1);
  256. }
  257. var++;
  258. }
  259. return NULL;
  260. }
  261. /* PROM commandline functions */
  262. char *prom_getcmdline(void)
  263. {
  264. return &(arcs_cmdline[0]);
  265. }
  266. EXPORT_SYMBOL(prom_getcmdline);
  267. void __init prom_init_cmdline(void)
  268. {
  269. char *cp;
  270. int actr;
  271. actr = 1; /* Always ignore argv[0] */
  272. cp = &(arcs_cmdline[0]);
  273. while (actr < prom_argc) {
  274. strcpy(cp, prom_argv[actr]);
  275. cp += strlen(prom_argv[actr]);
  276. *cp++ = ' ';
  277. actr++;
  278. }
  279. if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
  280. --cp;
  281. *cp = '\0';
  282. }
  283. /* memory allocation functions */
  284. static int __init prom_memtype_classify(unsigned int type)
  285. {
  286. switch (type) {
  287. case yamon_free:
  288. return BOOT_MEM_RAM;
  289. case yamon_prom:
  290. return BOOT_MEM_ROM_DATA;
  291. default:
  292. return BOOT_MEM_RESERVED;
  293. }
  294. }
  295. void __init prom_meminit(void)
  296. {
  297. struct prom_pmemblock *p;
  298. p = prom_getmdesc();
  299. while (p->size) {
  300. long type;
  301. unsigned long base, size;
  302. type = prom_memtype_classify(p->type);
  303. base = p->base;
  304. size = p->size;
  305. add_memory_region(base, size, type);
  306. p++;
  307. }
  308. }
  309. void __init prom_free_prom_memory(void)
  310. {
  311. int argc;
  312. char **argv;
  313. char **envp;
  314. char *ptr;
  315. int len = 0;
  316. int i;
  317. unsigned long addr;
  318. /*
  319. * preserve environment variables and command line from pmon/bbload
  320. * first preserve the command line
  321. */
  322. for (argc = 0; argc < prom_argc; argc++) {
  323. len += sizeof(char *); /* length of pointer */
  324. len += strlen(prom_argv[argc]) + 1; /* length of string */
  325. }
  326. len += sizeof(char *); /* plus length of null pointer */
  327. argv = kmalloc(len, GFP_KERNEL);
  328. ptr = (char *) &argv[prom_argc + 1]; /* strings follow array */
  329. for (argc = 0; argc < prom_argc; argc++) {
  330. argv[argc] = ptr;
  331. strcpy(ptr, prom_argv[argc]);
  332. ptr += strlen(prom_argv[argc]) + 1;
  333. }
  334. argv[prom_argc] = NULL; /* end array with null pointer */
  335. prom_argv = argv;
  336. /* next preserve the environment variables */
  337. len = 0;
  338. i = 0;
  339. for (envp = prom_envp; *envp != NULL; envp++) {
  340. i++; /* count number of environment variables */
  341. len += sizeof(char *); /* length of pointer */
  342. len += strlen(*envp) + 1; /* length of string */
  343. }
  344. len += sizeof(char *); /* plus length of null pointer */
  345. envp = kmalloc(len, GFP_KERNEL);
  346. ptr = (char *) &envp[i+1];
  347. for (argc = 0; argc < i; argc++) {
  348. envp[argc] = ptr;
  349. strcpy(ptr, prom_envp[argc]);
  350. ptr += strlen(prom_envp[argc]) + 1;
  351. }
  352. envp[i] = NULL; /* end array with null pointer */
  353. prom_envp = envp;
  354. for (i = 0; i < boot_mem_map.nr_map; i++) {
  355. if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
  356. continue;
  357. addr = boot_mem_map.map[i].addr;
  358. free_init_pages("prom memory",
  359. addr, addr + boot_mem_map.map[i].size);
  360. }
  361. }
  362. struct prom_pmemblock *__init prom_getmdesc(void)
  363. {
  364. static char memsz_env[] __initdata = "memsize";
  365. static char heaptop_env[] __initdata = "heaptop";
  366. char *str;
  367. unsigned int memsize;
  368. unsigned int heaptop;
  369. #ifdef CONFIG_MTD_PMC_MSP_RAMROOT
  370. void *ramroot_start;
  371. unsigned long ramroot_size;
  372. #endif
  373. int i;
  374. str = prom_getenv(memsz_env);
  375. if (!str) {
  376. ppfinit("memsize not set in boot prom, "
  377. "set to default (32Mb)\n");
  378. memsize = 0x02000000;
  379. } else {
  380. memsize = simple_strtol(str, NULL, 0);
  381. if (memsize == 0) {
  382. /* if memsize is a bad size, use reasonable default */
  383. memsize = 0x02000000;
  384. }
  385. /* convert to physical address (removing caching bits, etc) */
  386. memsize = CPHYSADDR(memsize);
  387. }
  388. str = prom_getenv(heaptop_env);
  389. if (!str) {
  390. heaptop = CPHYSADDR((u32)&_text);
  391. ppfinit("heaptop not set in boot prom, "
  392. "set to default 0x%08x\n", heaptop);
  393. } else {
  394. heaptop = simple_strtol(str, NULL, 16);
  395. if (heaptop == 0) {
  396. /* heaptop conversion bad, might have 0xValue */
  397. heaptop = simple_strtol(str, NULL, 0);
  398. if (heaptop == 0) {
  399. /* heaptop still bad, use reasonable default */
  400. heaptop = CPHYSADDR((u32)&_text);
  401. }
  402. }
  403. /* convert to physical address (removing caching bits, etc) */
  404. heaptop = CPHYSADDR((u32)heaptop);
  405. }
  406. /* the base region */
  407. i = 0;
  408. mdesc[i].type = BOOT_MEM_RESERVED;
  409. mdesc[i].base = 0x00000000;
  410. mdesc[i].size = PAGE_ALIGN(0x300 + 0x80);
  411. /* jtag interrupt vector + sizeof vector */
  412. /* PMON data */
  413. if (heaptop > mdesc[i].base + mdesc[i].size) {
  414. i++; /* 1 */
  415. mdesc[i].type = BOOT_MEM_ROM_DATA;
  416. mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
  417. mdesc[i].size = heaptop - mdesc[i].base;
  418. }
  419. /* end of PMON data to start of kernel -- probably zero .. */
  420. if (heaptop != CPHYSADDR((u32)_text)) {
  421. i++; /* 2 */
  422. mdesc[i].type = BOOT_MEM_RAM;
  423. mdesc[i].base = heaptop;
  424. mdesc[i].size = CPHYSADDR((u32)_text) - mdesc[i].base;
  425. }
  426. /* kernel proper */
  427. i++; /* 3 */
  428. mdesc[i].type = BOOT_MEM_RESERVED;
  429. mdesc[i].base = CPHYSADDR((u32)_text);
  430. #ifdef CONFIG_MTD_PMC_MSP_RAMROOT
  431. if (get_ramroot(&ramroot_start, &ramroot_size)) {
  432. /*
  433. * Rootfs in RAM -- follows kernel
  434. * Combine rootfs image with kernel block so a
  435. * page (4k) isn't wasted between memory blocks
  436. */
  437. mdesc[i].size = CPHYSADDR(PAGE_ALIGN(
  438. (u32)ramroot_start + ramroot_size)) - mdesc[i].base;
  439. } else
  440. #endif
  441. mdesc[i].size = CPHYSADDR(PAGE_ALIGN(
  442. (u32)_end)) - mdesc[i].base;
  443. /* Remainder of RAM -- under memsize */
  444. i++; /* 5 */
  445. mdesc[i].type = yamon_free;
  446. mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
  447. mdesc[i].size = memsize - mdesc[i].base;
  448. return &mdesc[0];
  449. }
  450. /* rootfs functions */
  451. #ifdef CONFIG_MTD_PMC_MSP_RAMROOT
  452. bool get_ramroot(void **start, unsigned long *size)
  453. {
  454. extern char _end[];
  455. /* Check for start following the end of the kernel */
  456. void *check_start = (void *)_end;
  457. /* Check for supported rootfs types */
  458. #ifdef CONFIG_CRAMFS
  459. if (*(__u32 *)check_start == CRAMFS_MAGIC) {
  460. /* Get CRAMFS size */
  461. *start = check_start;
  462. *size = PAGE_ALIGN(((struct cramfs_super *)
  463. check_start)->size);
  464. return true;
  465. }
  466. #endif
  467. #ifdef CONFIG_SQUASHFS
  468. if (*((unsigned int *)check_start) == SQUASHFS_MAGIC) {
  469. /* Get SQUASHFS size */
  470. *start = check_start;
  471. *size = PAGE_ALIGN(((struct squashfs_super_block *)
  472. check_start)->bytes_used);
  473. return true;
  474. }
  475. #endif
  476. return false;
  477. }
  478. EXPORT_SYMBOL(get_ramroot);
  479. #endif