misc-spruce.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Misc. bootloader code for IBM Spruce reference platform
  3. *
  4. * Authors: Johnnie Peters <jpeters@mvista.com>
  5. * Matt Porter <mporter@mvista.com>
  6. *
  7. * Derived from arch/ppc/boot/prep/misc.c
  8. *
  9. * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under
  10. * the terms of the GNU General Public License version 2. This program
  11. * is licensed "as is" without any warranty of any kind, whether express
  12. * or implied.
  13. */
  14. #include <linux/types.h>
  15. #include <linux/config.h>
  16. #include <linux/pci.h>
  17. #include <asm/bootinfo.h>
  18. extern unsigned long decompress_kernel(unsigned long load_addr, int num_words,
  19. unsigned long cksum);
  20. /* Define some important locations of the Spruce. */
  21. #define SPRUCE_PCI_CONFIG_ADDR 0xfec00000
  22. #define SPRUCE_PCI_CONFIG_DATA 0xfec00004
  23. /* PCI configuration space access routines. */
  24. unsigned int *pci_config_address = (unsigned int *)SPRUCE_PCI_CONFIG_ADDR;
  25. unsigned char *pci_config_data = (unsigned char *)SPRUCE_PCI_CONFIG_DATA;
  26. void cpc700_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
  27. unsigned char offset, unsigned char *val)
  28. {
  29. out_le32(pci_config_address,
  30. (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
  31. *val= (in_le32((unsigned *)pci_config_data) >> (8 * (offset & 3))) & 0xff;
  32. }
  33. void cpc700_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
  34. unsigned char offset, unsigned char val)
  35. {
  36. out_le32(pci_config_address,
  37. (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
  38. out_8(pci_config_data + (offset&3), val);
  39. }
  40. void cpc700_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
  41. unsigned char offset, unsigned short *val)
  42. {
  43. out_le32(pci_config_address,
  44. (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
  45. *val= in_le16((unsigned short *)(pci_config_data + (offset&3)));
  46. }
  47. void cpc700_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
  48. unsigned char offset, unsigned short val)
  49. {
  50. out_le32(pci_config_address,
  51. (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
  52. out_le16((unsigned short *)(pci_config_data + (offset&3)), val);
  53. }
  54. void cpc700_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
  55. unsigned char offset, unsigned int *val)
  56. {
  57. out_le32(pci_config_address,
  58. (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
  59. *val= in_le32((unsigned *)pci_config_data);
  60. }
  61. void cpc700_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
  62. unsigned char offset, unsigned int val)
  63. {
  64. out_le32(pci_config_address,
  65. (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
  66. out_le32((unsigned *)pci_config_data, val);
  67. }
  68. #define PCNET32_WIO_RDP 0x10
  69. #define PCNET32_WIO_RAP 0x12
  70. #define PCNET32_WIO_RESET 0x14
  71. #define PCNET32_DWIO_RDP 0x10
  72. #define PCNET32_DWIO_RAP 0x14
  73. #define PCNET32_DWIO_RESET 0x18
  74. /* Processor interface config register access */
  75. #define PIFCFGADDR 0xff500000
  76. #define PIFCFGDATA 0xff500004
  77. #define PLBMIFOPT 0x18 /* PLB Master Interface Options */
  78. #define MEM_MBEN 0x24
  79. #define MEM_TYPE 0x28
  80. #define MEM_B1SA 0x3c
  81. #define MEM_B1EA 0x5c
  82. #define MEM_B2SA 0x40
  83. #define MEM_B2EA 0x60
  84. unsigned long
  85. get_mem_size(void)
  86. {
  87. int loop;
  88. unsigned long mem_size = 0;
  89. unsigned long mem_mben;
  90. unsigned long mem_type;
  91. unsigned long mem_start;
  92. unsigned long mem_end;
  93. volatile int *mem_addr = (int *)0xff500008;
  94. volatile int *mem_data = (int *)0xff50000c;
  95. /* Get the size of memory from the memory controller. */
  96. *mem_addr = MEM_MBEN;
  97. asm("sync");
  98. mem_mben = *mem_data;
  99. asm("sync");
  100. for(loop = 0; loop < 1000; loop++);
  101. *mem_addr = MEM_TYPE;
  102. asm("sync");
  103. mem_type = *mem_data;
  104. asm("sync");
  105. for(loop = 0; loop < 1000; loop++);
  106. *mem_addr = MEM_TYPE;
  107. /* Confirm bank 1 has DRAM memory */
  108. if ((mem_mben & 0x40000000) &&
  109. ((mem_type & 0x30000000) == 0x10000000)) {
  110. *mem_addr = MEM_B1SA;
  111. asm("sync");
  112. mem_start = *mem_data;
  113. asm("sync");
  114. for(loop = 0; loop < 1000; loop++);
  115. *mem_addr = MEM_B1EA;
  116. asm("sync");
  117. mem_end = *mem_data;
  118. asm("sync");
  119. for(loop = 0; loop < 1000; loop++);
  120. mem_size = mem_end - mem_start + 0x100000;
  121. }
  122. /* Confirm bank 2 has DRAM memory */
  123. if ((mem_mben & 0x20000000) &&
  124. ((mem_type & 0xc000000) == 0x4000000)) {
  125. *mem_addr = MEM_B2SA;
  126. asm("sync");
  127. mem_start = *mem_data;
  128. asm("sync");
  129. for(loop = 0; loop < 1000; loop++);
  130. *mem_addr = MEM_B2EA;
  131. asm("sync");
  132. mem_end = *mem_data;
  133. asm("sync");
  134. for(loop = 0; loop < 1000; loop++);
  135. mem_size += mem_end - mem_start + 0x100000;
  136. }
  137. return mem_size;
  138. }
  139. unsigned long
  140. load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
  141. void *ign1, void *ign2)
  142. {
  143. int csr0;
  144. int csr_id;
  145. int pci_devfn;
  146. int found_multi = 0;
  147. unsigned short vendor;
  148. unsigned short device;
  149. unsigned short command;
  150. unsigned char header_type;
  151. unsigned int bar0;
  152. volatile int *pif_addr = (int *)0xff500000;
  153. volatile int *pif_data = (int *)0xff500004;
  154. /*
  155. * Gah, these firmware guys need to learn that hardware
  156. * byte swapping is evil! Disable all hardware byte
  157. * swapping so it doesn't hurt anyone.
  158. */
  159. *pif_addr = PLBMIFOPT;
  160. asm("sync");
  161. *pif_data = 0x00000000;
  162. asm("sync");
  163. /* Search out and turn off the PcNet ethernet boot device. */
  164. for (pci_devfn = 1; pci_devfn < 0xff; pci_devfn++) {
  165. if (PCI_FUNC(pci_devfn) && !found_multi)
  166. continue;
  167. cpc700_pcibios_read_config_byte(0, pci_devfn,
  168. PCI_HEADER_TYPE, &header_type);
  169. if (!PCI_FUNC(pci_devfn))
  170. found_multi = header_type & 0x80;
  171. cpc700_pcibios_read_config_word(0, pci_devfn, PCI_VENDOR_ID,
  172. &vendor);
  173. if (vendor != 0xffff) {
  174. cpc700_pcibios_read_config_word(0, pci_devfn,
  175. PCI_DEVICE_ID, &device);
  176. /* If this PCI device is the Lance PCNet board then turn it off */
  177. if ((vendor == PCI_VENDOR_ID_AMD) &&
  178. (device == PCI_DEVICE_ID_AMD_LANCE)) {
  179. /* Turn on I/O Space on the board. */
  180. cpc700_pcibios_read_config_word(0, pci_devfn,
  181. PCI_COMMAND, &command);
  182. command |= 0x1;
  183. cpc700_pcibios_write_config_word(0, pci_devfn,
  184. PCI_COMMAND, command);
  185. /* Get the I/O space address */
  186. cpc700_pcibios_read_config_dword(0, pci_devfn,
  187. PCI_BASE_ADDRESS_0, &bar0);
  188. bar0 &= 0xfffffffe;
  189. /* Reset the PCNet Board */
  190. inl (bar0+PCNET32_DWIO_RESET);
  191. inw (bar0+PCNET32_WIO_RESET);
  192. /* First do a work oriented read of csr0. If the value is
  193. * 4 then this is the correct mode to access the board.
  194. * If not try a double word ortiented read.
  195. */
  196. outw(0, bar0 + PCNET32_WIO_RAP);
  197. csr0 = inw(bar0 + PCNET32_WIO_RDP);
  198. if (csr0 == 4) {
  199. /* Check the Chip id register */
  200. outw(88, bar0 + PCNET32_WIO_RAP);
  201. csr_id = inw(bar0 + PCNET32_WIO_RDP);
  202. if (csr_id) {
  203. /* This is the valid mode - set the stop bit */
  204. outw(0, bar0 + PCNET32_WIO_RAP);
  205. outw(csr0, bar0 + PCNET32_WIO_RDP);
  206. }
  207. } else {
  208. outl(0, bar0 + PCNET32_DWIO_RAP);
  209. csr0 = inl(bar0 + PCNET32_DWIO_RDP);
  210. if (csr0 == 4) {
  211. /* Check the Chip id register */
  212. outl(88, bar0 + PCNET32_WIO_RAP);
  213. csr_id = inl(bar0 + PCNET32_WIO_RDP);
  214. if (csr_id) {
  215. /* This is the valid mode - set the stop bit*/
  216. outl(0, bar0 + PCNET32_WIO_RAP);
  217. outl(csr0, bar0 + PCNET32_WIO_RDP);
  218. }
  219. }
  220. }
  221. }
  222. }
  223. }
  224. return decompress_kernel(load_addr, num_words, cksum);
  225. }