init.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2009,2010 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/kernel.h>
  19. #include <grub/misc.h>
  20. #include <grub/env.h>
  21. #include <grub/time.h>
  22. #include <grub/types.h>
  23. #include <grub/misc.h>
  24. #include <grub/mm.h>
  25. #include <grub/machine/time.h>
  26. #include <grub/machine/kernel.h>
  27. #include <grub/machine/memory.h>
  28. #include <grub/memory.h>
  29. #include <grub/mips/loongson.h>
  30. #include <grub/cs5536.h>
  31. #include <grub/term.h>
  32. #include <grub/cpu/memory.h>
  33. #include <grub/i18n.h>
  34. #include <grub/video.h>
  35. #include <grub/terminfo.h>
  36. #include <grub/keyboard_layouts.h>
  37. #include <grub/serial.h>
  38. #include <grub/loader.h>
  39. #include <grub/at_keyboard.h>
  40. grub_err_t
  41. grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
  42. {
  43. hook (GRUB_ARCH_LOWMEMPSTART, grub_arch_memsize << 20,
  44. GRUB_MEMORY_AVAILABLE, hook_data);
  45. hook (GRUB_ARCH_HIGHMEMPSTART, grub_arch_highmemsize << 20,
  46. GRUB_MEMORY_AVAILABLE, hook_data);
  47. return GRUB_ERR_NONE;
  48. }
  49. /* Helper for init_pci. */
  50. static int
  51. set_card (grub_pci_device_t dev, grub_pci_id_t pciid,
  52. void *data __attribute__ ((unused)))
  53. {
  54. grub_pci_address_t addr;
  55. /* We could use grub_pci_assign_addresses for this but we prefer to
  56. have exactly same memory map as on pmon. */
  57. switch (pciid)
  58. {
  59. case GRUB_LOONGSON_OHCI_PCIID:
  60. addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
  61. grub_pci_write (addr, 0x5025000);
  62. addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
  63. grub_pci_write_word (addr, GRUB_PCI_COMMAND_SERR_ENABLE
  64. | GRUB_PCI_COMMAND_PARITY_ERROR
  65. | GRUB_PCI_COMMAND_BUS_MASTER
  66. | GRUB_PCI_COMMAND_MEM_ENABLED);
  67. addr = grub_pci_make_address (dev, GRUB_PCI_REG_STATUS);
  68. grub_pci_write_word (addr, 0x0200 | GRUB_PCI_STATUS_CAPABILITIES);
  69. break;
  70. case GRUB_LOONGSON_EHCI_PCIID:
  71. addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
  72. grub_pci_write (addr, 0x5026000);
  73. addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
  74. grub_pci_write_word (addr, GRUB_PCI_COMMAND_SERR_ENABLE
  75. | GRUB_PCI_COMMAND_PARITY_ERROR
  76. | GRUB_PCI_COMMAND_BUS_MASTER
  77. | GRUB_PCI_COMMAND_MEM_ENABLED);
  78. addr = grub_pci_make_address (dev, GRUB_PCI_REG_STATUS);
  79. grub_pci_write_word (addr, (1 << GRUB_PCI_STATUS_DEVSEL_TIMING_SHIFT)
  80. | GRUB_PCI_STATUS_CAPABILITIES);
  81. break;
  82. }
  83. return 0;
  84. }
  85. static void
  86. init_pci (void)
  87. {
  88. *((volatile grub_uint32_t *) GRUB_CPU_LOONGSON_PCI_HIT1_SEL_LO) = 0x8000000c;
  89. *((volatile grub_uint32_t *) GRUB_CPU_LOONGSON_PCI_HIT1_SEL_HI) = 0xffffffff;
  90. /* Setup PCI controller. */
  91. *((volatile grub_uint16_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
  92. + GRUB_PCI_REG_COMMAND))
  93. = GRUB_PCI_COMMAND_PARITY_ERROR | GRUB_PCI_COMMAND_BUS_MASTER
  94. | GRUB_PCI_COMMAND_MEM_ENABLED;
  95. *((volatile grub_uint16_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
  96. + GRUB_PCI_REG_STATUS))
  97. = (1 << GRUB_PCI_STATUS_DEVSEL_TIMING_SHIFT)
  98. | GRUB_PCI_STATUS_FAST_B2B_CAPABLE | GRUB_PCI_STATUS_66MHZ_CAPABLE
  99. | GRUB_PCI_STATUS_CAPABILITIES;
  100. *((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
  101. + GRUB_PCI_REG_CACHELINE)) = 0xff;
  102. *((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
  103. + GRUB_PCI_REG_ADDRESS_REG0))
  104. = 0x80000000 | GRUB_PCI_ADDR_MEM_TYPE_64 | GRUB_PCI_ADDR_MEM_PREFETCH;
  105. *((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
  106. + GRUB_PCI_REG_ADDRESS_REG1)) = 0;
  107. grub_pci_iterate (set_card, NULL);
  108. }
  109. void
  110. grub_machine_init (void)
  111. {
  112. grub_addr_t modend;
  113. grub_uint32_t prid;
  114. asm volatile ("mfc0 %0, " GRUB_CPU_LOONGSON_COP0_PRID : "=r" (prid));
  115. switch (prid)
  116. {
  117. /* Loongson 2E. */
  118. case 0x6302:
  119. grub_arch_machine = GRUB_ARCH_MACHINE_FULOONG2E;
  120. grub_bonito_type = GRUB_BONITO_2F;
  121. break;
  122. /* Loongson 2F. */
  123. case 0x6303:
  124. if (grub_arch_machine != GRUB_ARCH_MACHINE_FULOONG2F
  125. && grub_arch_machine != GRUB_ARCH_MACHINE_YEELOONG)
  126. grub_arch_machine = GRUB_ARCH_MACHINE_YEELOONG;
  127. grub_bonito_type = GRUB_BONITO_2F;
  128. break;
  129. /* Loongson 3A. */
  130. case 0x6305:
  131. grub_arch_machine = GRUB_ARCH_MACHINE_YEELOONG_3A;
  132. grub_bonito_type = GRUB_BONITO_3A;
  133. break;
  134. }
  135. /* FIXME: measure this. */
  136. if (grub_arch_busclock == 0)
  137. {
  138. grub_arch_busclock = 66000000;
  139. grub_arch_cpuclock = 797000000;
  140. }
  141. grub_install_get_time_ms (grub_rtc_get_time_ms);
  142. if (grub_arch_memsize == 0)
  143. {
  144. grub_port_t smbbase;
  145. grub_err_t err;
  146. grub_pci_device_t dev;
  147. struct grub_smbus_spd spd;
  148. unsigned totalmem;
  149. int i;
  150. if (!grub_cs5536_find (&dev))
  151. grub_fatal ("No CS5536 found\n");
  152. err = grub_cs5536_init_smbus (dev, 0x7ff, &smbbase);
  153. if (err)
  154. grub_fatal ("Couldn't init SMBus: %s\n", grub_errmsg);
  155. /* Yeeloong and Fuloong have only one memory slot. */
  156. err = grub_cs5536_read_spd (smbbase, GRUB_SMB_RAM_START_ADDR, &spd);
  157. if (err)
  158. grub_fatal ("Couldn't read SPD: %s\n", grub_errmsg);
  159. for (i = 5; i < 13; i++)
  160. if (spd.ddr2.rank_capacity & (1 << (i & 7)))
  161. break;
  162. /* Something is wrong. */
  163. if (i == 13)
  164. totalmem = 256;
  165. else
  166. totalmem = ((spd.ddr2.num_of_ranks
  167. & GRUB_SMBUS_SPD_MEMORY_NUM_OF_RANKS_MASK) + 1) << (i + 2);
  168. if (totalmem >= 256)
  169. {
  170. grub_arch_memsize = 256;
  171. grub_arch_highmemsize = totalmem - 256;
  172. }
  173. else
  174. {
  175. grub_arch_memsize = totalmem;
  176. grub_arch_highmemsize = 0;
  177. }
  178. grub_cs5536_init_geode (dev);
  179. init_pci ();
  180. }
  181. modend = grub_modules_get_end ();
  182. grub_mm_init_region ((void *) modend, (grub_arch_memsize << 20)
  183. - (modend - GRUB_ARCH_LOWMEMVSTART));
  184. /* FIXME: use upper memory as well. */
  185. /* Initialize output terminal (can't be done earlier, as gfxterm
  186. relies on a working heap. */
  187. grub_video_sm712_init ();
  188. grub_video_sis315pro_init ();
  189. grub_video_radeon_fuloong2e_init ();
  190. grub_video_radeon_yeeloong3a_init ();
  191. grub_font_init ();
  192. grub_gfxterm_init ();
  193. grub_keylayouts_init ();
  194. if (grub_arch_machine == GRUB_ARCH_MACHINE_YEELOONG
  195. || grub_arch_machine == GRUB_ARCH_MACHINE_YEELOONG_3A)
  196. grub_at_keyboard_init ();
  197. grub_terminfo_init ();
  198. grub_serial_init ();
  199. grub_boot_init ();
  200. }
  201. void
  202. grub_machine_fini (int flags __attribute__ ((unused)))
  203. {
  204. }
  205. static int
  206. halt_via (grub_pci_device_t dev, grub_pci_id_t pciid,
  207. void *data __attribute__ ((unused)))
  208. {
  209. grub_uint16_t pm;
  210. grub_pci_address_t addr;
  211. if (pciid != 0x30571106)
  212. return 0;
  213. addr = grub_pci_make_address (dev, 0x40);
  214. pm = grub_pci_read (addr) & ~1;
  215. if (pm == 0)
  216. {
  217. grub_pci_write (addr, 0x1801);
  218. pm = 0x1800;
  219. }
  220. addr = grub_pci_make_address (dev, 0x80);
  221. grub_pci_write_byte (addr, 0xff);
  222. addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
  223. grub_pci_write_word (addr, grub_pci_read_word (addr) | GRUB_PCI_COMMAND_IO_ENABLED);
  224. /* FIXME: This one is derived from qemu. Check on real hardware. */
  225. grub_outw (0x2000, pm + 4 + GRUB_MACHINE_PCI_IO_BASE);
  226. grub_millisleep (5000);
  227. return 0;
  228. }
  229. void
  230. grub_halt (void)
  231. {
  232. switch (grub_arch_machine)
  233. {
  234. case GRUB_ARCH_MACHINE_FULOONG2E:
  235. grub_pci_iterate (halt_via, NULL);
  236. break;
  237. case GRUB_ARCH_MACHINE_FULOONG2F:
  238. {
  239. grub_pci_device_t dev;
  240. grub_port_t p;
  241. if (grub_cs5536_find (&dev))
  242. {
  243. p = (grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_GPIO_BAR)
  244. & GRUB_CS5536_LBAR_ADDR_MASK) + GRUB_MACHINE_PCI_IO_BASE;
  245. grub_outl ((1 << 13), p + 4);
  246. grub_outl ((1 << 29), p);
  247. grub_millisleep (5000);
  248. }
  249. }
  250. break;
  251. case GRUB_ARCH_MACHINE_YEELOONG:
  252. grub_outb (grub_inb (GRUB_CPU_LOONGSON_GPIOCFG)
  253. & ~GRUB_CPU_YEELOONG_SHUTDOWN_GPIO, GRUB_CPU_LOONGSON_GPIOCFG);
  254. grub_millisleep (1500);
  255. break;
  256. case GRUB_ARCH_MACHINE_YEELOONG_3A:
  257. grub_millisleep (1);
  258. grub_outb (0x4e, GRUB_MACHINE_PCI_IO_BASE_3A | 0x66);
  259. grub_millisleep (1);
  260. grub_outb (2, GRUB_MACHINE_PCI_IO_BASE_3A | 0x62);
  261. grub_millisleep (5000);
  262. break;
  263. }
  264. grub_puts_ (N_("Shutdown failed"));
  265. grub_refresh ();
  266. while (1);
  267. }
  268. void
  269. grub_exit (void)
  270. {
  271. grub_halt ();
  272. }
  273. void
  274. grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
  275. char **path __attribute__ ((unused)))
  276. {
  277. }
  278. extern char _end[];
  279. grub_addr_t grub_modbase = (grub_addr_t) _end;