setup.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <linux/config.h>
  19. #include <linux/init.h>
  20. #include <linux/kernel.h>
  21. #include <linux/linkage.h>
  22. #include <linux/mm.h>
  23. #include <linux/blkdev.h>
  24. #include <linux/bootmem.h>
  25. #include <linux/pm.h>
  26. #include <linux/smp.h>
  27. #include <asm/bootinfo.h>
  28. #include <asm/reboot.h>
  29. #include <asm/sibyte/board.h>
  30. #include "cfe_api.h"
  31. #include "cfe_error.h"
  32. /* Max ram addressable in 32-bit segments */
  33. #ifdef CONFIG_64BIT
  34. #define MAX_RAM_SIZE (~0ULL)
  35. #else
  36. #ifdef CONFIG_HIGHMEM
  37. #ifdef CONFIG_64BIT_PHYS_ADDR
  38. #define MAX_RAM_SIZE (~0ULL)
  39. #else
  40. #define MAX_RAM_SIZE (0xffffffffULL)
  41. #endif
  42. #else
  43. #define MAX_RAM_SIZE (0x1fffffffULL)
  44. #endif
  45. #endif
  46. #define SIBYTE_MAX_MEM_REGIONS 8
  47. phys_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS];
  48. phys_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS];
  49. unsigned int board_mem_region_count;
  50. int cfe_cons_handle;
  51. #ifdef CONFIG_BLK_DEV_INITRD
  52. extern unsigned long initrd_start, initrd_end;
  53. #endif
  54. #ifdef CONFIG_KGDB
  55. extern int kgdb_port;
  56. #endif
  57. static void ATTRIB_NORET cfe_linux_exit(void *arg)
  58. {
  59. int warm = *(int *)arg;
  60. if (smp_processor_id()) {
  61. static int reboot_smp;
  62. /* Don't repeat the process from another CPU */
  63. if (!reboot_smp) {
  64. /* Get CPU 0 to do the cfe_exit */
  65. reboot_smp = 1;
  66. smp_call_function(cfe_linux_exit, arg, 1, 0);
  67. }
  68. } else {
  69. printk("Passing control back to CFE...\n");
  70. cfe_exit(warm, 0);
  71. printk("cfe_exit returned??\n");
  72. }
  73. while (1);
  74. }
  75. static void ATTRIB_NORET cfe_linux_restart(char *command)
  76. {
  77. static const int zero;
  78. cfe_linux_exit((void *)&zero);
  79. }
  80. static void ATTRIB_NORET cfe_linux_halt(void)
  81. {
  82. static const int one = 1;
  83. cfe_linux_exit((void *)&one);
  84. }
  85. static __init void prom_meminit(void)
  86. {
  87. u64 addr, size, type; /* regardless of 64BIT_PHYS_ADDR */
  88. int mem_flags = 0;
  89. unsigned int idx;
  90. int rd_flag;
  91. #ifdef CONFIG_BLK_DEV_INITRD
  92. unsigned long initrd_pstart;
  93. unsigned long initrd_pend;
  94. initrd_pstart = CPHYSADDR(initrd_start);
  95. initrd_pend = CPHYSADDR(initrd_end);
  96. if (initrd_start &&
  97. ((initrd_pstart > MAX_RAM_SIZE)
  98. || (initrd_pend > MAX_RAM_SIZE))) {
  99. panic("initrd out of addressable memory");
  100. }
  101. #endif /* INITRD */
  102. for (idx = 0; cfe_enummem(idx, mem_flags, &addr, &size, &type) != CFE_ERR_NOMORE;
  103. idx++) {
  104. rd_flag = 0;
  105. if (type == CFE_MI_AVAILABLE) {
  106. /*
  107. * See if this block contains (any portion of) the
  108. * ramdisk
  109. */
  110. #ifdef CONFIG_BLK_DEV_INITRD
  111. if (initrd_start) {
  112. if ((initrd_pstart > addr) &&
  113. (initrd_pstart < (addr + size))) {
  114. add_memory_region(addr,
  115. initrd_pstart - addr,
  116. BOOT_MEM_RAM);
  117. rd_flag = 1;
  118. }
  119. if ((initrd_pend > addr) &&
  120. (initrd_pend < (addr + size))) {
  121. add_memory_region(initrd_pend,
  122. (addr + size) - initrd_pend,
  123. BOOT_MEM_RAM);
  124. rd_flag = 1;
  125. }
  126. }
  127. #endif
  128. if (!rd_flag) {
  129. if (addr > MAX_RAM_SIZE)
  130. continue;
  131. if (addr+size > MAX_RAM_SIZE)
  132. size = MAX_RAM_SIZE - (addr+size) + 1;
  133. /*
  134. * memcpy/__copy_user prefetch, which
  135. * will cause a bus error for
  136. * KSEG/KUSEG addrs not backed by RAM.
  137. * Hence, reserve some padding for the
  138. * prefetch distance.
  139. */
  140. if (size > 512)
  141. size -= 512;
  142. add_memory_region(addr, size, BOOT_MEM_RAM);
  143. }
  144. board_mem_region_addrs[board_mem_region_count] = addr;
  145. board_mem_region_sizes[board_mem_region_count] = size;
  146. board_mem_region_count++;
  147. if (board_mem_region_count ==
  148. SIBYTE_MAX_MEM_REGIONS) {
  149. /*
  150. * Too many regions. Need to configure more
  151. */
  152. while(1);
  153. }
  154. }
  155. }
  156. #ifdef CONFIG_BLK_DEV_INITRD
  157. if (initrd_start) {
  158. add_memory_region(initrd_pstart, initrd_pend - initrd_pstart,
  159. BOOT_MEM_RESERVED);
  160. }
  161. #endif
  162. }
  163. #ifdef CONFIG_BLK_DEV_INITRD
  164. static int __init initrd_setup(char *str)
  165. {
  166. char rdarg[64];
  167. int idx;
  168. char *tmp, *endptr;
  169. unsigned long initrd_size;
  170. /* Make a copy of the initrd argument so we can smash it up here */
  171. for (idx = 0; idx < sizeof(rdarg)-1; idx++) {
  172. if (!str[idx] || (str[idx] == ' ')) break;
  173. rdarg[idx] = str[idx];
  174. }
  175. rdarg[idx] = 0;
  176. str = rdarg;
  177. /*
  178. *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>"
  179. * e.g. initrd=3abfd@80010000. This is set up by the loader.
  180. */
  181. for (tmp = str; *tmp != '@'; tmp++) {
  182. if (!*tmp) {
  183. goto fail;
  184. }
  185. }
  186. *tmp = 0;
  187. tmp++;
  188. if (!*tmp) {
  189. goto fail;
  190. }
  191. initrd_size = simple_strtoul(str, &endptr, 16);
  192. if (*endptr) {
  193. *(tmp-1) = '@';
  194. goto fail;
  195. }
  196. *(tmp-1) = '@';
  197. initrd_start = simple_strtoul(tmp, &endptr, 16);
  198. if (*endptr) {
  199. goto fail;
  200. }
  201. initrd_end = initrd_start + initrd_size;
  202. prom_printf("Found initrd of %lx@%lx\n", initrd_size, initrd_start);
  203. return 1;
  204. fail:
  205. prom_printf("Bad initrd argument. Disabling initrd\n");
  206. initrd_start = 0;
  207. initrd_end = 0;
  208. return 1;
  209. }
  210. #endif
  211. /*
  212. * prom_init is called just after the cpu type is determined, from setup_arch()
  213. */
  214. void __init prom_init(void)
  215. {
  216. uint64_t cfe_ept, cfe_handle;
  217. unsigned int cfe_eptseal;
  218. int argc = fw_arg0;
  219. char **envp = (char **) fw_arg2;
  220. int *prom_vec = (int *) fw_arg3;
  221. #ifdef CONFIG_KGDB
  222. char *arg;
  223. #endif
  224. _machine_restart = cfe_linux_restart;
  225. _machine_halt = cfe_linux_halt;
  226. pm_power_off = cfe_linux_halt;
  227. /*
  228. * Check if a loader was used; if NOT, the 4 arguments are
  229. * what CFE gives us (handle, 0, EPT and EPTSEAL)
  230. */
  231. if (argc < 0) {
  232. cfe_handle = (uint64_t)(long)argc;
  233. cfe_ept = (long)envp;
  234. cfe_eptseal = (uint32_t)(unsigned long)prom_vec;
  235. } else {
  236. if ((int32_t)(long)prom_vec < 0) {
  237. /*
  238. * Old loader; all it gives us is the handle,
  239. * so use the "known" entrypoint and assume
  240. * the seal.
  241. */
  242. cfe_handle = (uint64_t)(long)prom_vec;
  243. cfe_ept = (uint64_t)((int32_t)0x9fc00500);
  244. cfe_eptseal = CFE_EPTSEAL;
  245. } else {
  246. /*
  247. * Newer loaders bundle the handle/ept/eptseal
  248. * Note: prom_vec is in the loader's useg
  249. * which is still alive in the TLB.
  250. */
  251. cfe_handle = (uint64_t)((int32_t *)prom_vec)[0];
  252. cfe_ept = (uint64_t)((int32_t *)prom_vec)[2];
  253. cfe_eptseal = (unsigned int)((uint32_t *)prom_vec)[3];
  254. }
  255. }
  256. if (cfe_eptseal != CFE_EPTSEAL) {
  257. /* too early for panic to do any good */
  258. prom_printf("CFE's entrypoint seal doesn't match. Spinning.");
  259. while (1) ;
  260. }
  261. cfe_init(cfe_handle, cfe_ept);
  262. /*
  263. * Get the handle for (at least) prom_putchar, possibly for
  264. * boot console
  265. */
  266. cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
  267. if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, CL_SIZE) < 0) {
  268. if (argc < 0) {
  269. /*
  270. * It's OK for direct boot to not provide a
  271. * command line
  272. */
  273. strcpy(arcs_cmdline, "root=/dev/ram0 ");
  274. #ifdef CONFIG_SIBYTE_PTSWARM
  275. strcat(arcs_cmdline, "console=ttyS0,115200 ");
  276. #endif
  277. } else {
  278. /* The loader should have set the command line */
  279. /* too early for panic to do any good */
  280. prom_printf("LINUX_CMDLINE not defined in cfe.");
  281. while (1) ;
  282. }
  283. }
  284. #ifdef CONFIG_KGDB
  285. if ((arg = strstr(arcs_cmdline,"kgdb=duart")) != NULL)
  286. kgdb_port = (arg[10] == '0') ? 0 : 1;
  287. else
  288. kgdb_port = 1;
  289. #endif
  290. #ifdef CONFIG_BLK_DEV_INITRD
  291. {
  292. char *ptr;
  293. /* Need to find out early whether we've got an initrd. So scan
  294. the list looking now */
  295. for (ptr = arcs_cmdline; *ptr; ptr++) {
  296. while (*ptr == ' ') {
  297. ptr++;
  298. }
  299. if (!strncmp(ptr, "initrd=", 7)) {
  300. initrd_setup(ptr+7);
  301. break;
  302. } else {
  303. while (*ptr && (*ptr != ' ')) {
  304. ptr++;
  305. }
  306. }
  307. }
  308. }
  309. #endif /* CONFIG_BLK_DEV_INITRD */
  310. /* Not sure this is needed, but it's the safe way. */
  311. arcs_cmdline[CL_SIZE-1] = 0;
  312. mips_machgroup = MACH_GROUP_SIBYTE;
  313. prom_meminit();
  314. }
  315. unsigned long __init prom_free_prom_memory(void)
  316. {
  317. /* Not sure what I'm supposed to do here. Nothing, I think */
  318. return 0;
  319. }
  320. void prom_putchar(char c)
  321. {
  322. int ret;
  323. while ((ret = cfe_write(cfe_cons_handle, &c, 1)) == 0)
  324. ;
  325. }