2 * arch/ppc/boot/spruce/misc.c
4 * Misc. bootloader code for IBM Spruce reference platform
6 * Authors: Johnnie Peters <jpeters@mvista.com>
7 * Matt Porter <mporter@mvista.com>
9 * Derived from arch/ppc/boot/prep/misc.c
11 * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under
12 * the terms of the GNU General Public License version 2. This program
13 * is licensed "as is" without any warranty of any kind, whether express
17 #include <linux/types.h>
18 #include <linux/config.h>
19 #include <linux/pci.h>
21 #include <asm/bootinfo.h>
23 extern unsigned long decompress_kernel(unsigned long load_addr
, int num_words
,
26 /* Define some important locations of the Spruce. */
27 #define SPRUCE_PCI_CONFIG_ADDR 0xfec00000
28 #define SPRUCE_PCI_CONFIG_DATA 0xfec00004
30 /* PCI configuration space access routines. */
31 unsigned int *pci_config_address
= (unsigned int *)SPRUCE_PCI_CONFIG_ADDR
;
32 unsigned char *pci_config_data
= (unsigned char *)SPRUCE_PCI_CONFIG_DATA
;
34 void cpc700_pcibios_read_config_byte(unsigned char bus
, unsigned char dev_fn
,
35 unsigned char offset
, unsigned char *val
)
37 out_le32(pci_config_address
,
38 (((bus
& 0xff)<<16) | (dev_fn
<<8) | (offset
&0xfc) | 0x80000000));
40 *val
= (in_le32((unsigned *)pci_config_data
) >> (8 * (offset
& 3))) & 0xff;
43 void cpc700_pcibios_write_config_byte(unsigned char bus
, unsigned char dev_fn
,
44 unsigned char offset
, unsigned char val
)
46 out_le32(pci_config_address
,
47 (((bus
& 0xff)<<16) | (dev_fn
<<8) | (offset
&0xfc) | 0x80000000));
49 out_8(pci_config_data
+ (offset
&3), val
);
52 void cpc700_pcibios_read_config_word(unsigned char bus
, unsigned char dev_fn
,
53 unsigned char offset
, unsigned short *val
)
55 out_le32(pci_config_address
,
56 (((bus
& 0xff)<<16) | (dev_fn
<<8) | (offset
&0xfc) | 0x80000000));
58 *val
= in_le16((unsigned short *)(pci_config_data
+ (offset
&3)));
61 void cpc700_pcibios_write_config_word(unsigned char bus
, unsigned char dev_fn
,
62 unsigned char offset
, unsigned short val
)
64 out_le32(pci_config_address
,
65 (((bus
& 0xff)<<16) | (dev_fn
<<8) | (offset
&0xfc) | 0x80000000));
67 out_le16((unsigned short *)(pci_config_data
+ (offset
&3)), val
);
70 void cpc700_pcibios_read_config_dword(unsigned char bus
, unsigned char dev_fn
,
71 unsigned char offset
, unsigned int *val
)
73 out_le32(pci_config_address
,
74 (((bus
& 0xff)<<16) | (dev_fn
<<8) | (offset
&0xfc) | 0x80000000));
76 *val
= in_le32((unsigned *)pci_config_data
);
79 void cpc700_pcibios_write_config_dword(unsigned char bus
, unsigned char dev_fn
,
80 unsigned char offset
, unsigned int val
)
82 out_le32(pci_config_address
,
83 (((bus
& 0xff)<<16) | (dev_fn
<<8) | (offset
&0xfc) | 0x80000000));
85 out_le32((unsigned *)pci_config_data
, val
);
88 #define PCNET32_WIO_RDP 0x10
89 #define PCNET32_WIO_RAP 0x12
90 #define PCNET32_WIO_RESET 0x14
92 #define PCNET32_DWIO_RDP 0x10
93 #define PCNET32_DWIO_RAP 0x14
94 #define PCNET32_DWIO_RESET 0x18
96 /* Processor interface config register access */
97 #define PIFCFGADDR 0xff500000
98 #define PIFCFGDATA 0xff500004
100 #define PLBMIFOPT 0x18 /* PLB Master Interface Options */
102 #define MEM_MBEN 0x24
103 #define MEM_TYPE 0x28
104 #define MEM_B1SA 0x3c
105 #define MEM_B1EA 0x5c
106 #define MEM_B2SA 0x40
107 #define MEM_B2EA 0x60
113 unsigned long mem_size
= 0;
114 unsigned long mem_mben
;
115 unsigned long mem_type
;
116 unsigned long mem_start
;
117 unsigned long mem_end
;
118 volatile int *mem_addr
= (int *)0xff500008;
119 volatile int *mem_data
= (int *)0xff50000c;
121 /* Get the size of memory from the memory controller. */
122 *mem_addr
= MEM_MBEN
;
124 mem_mben
= *mem_data
;
126 for(loop
= 0; loop
< 1000; loop
++);
128 *mem_addr
= MEM_TYPE
;
130 mem_type
= *mem_data
;
132 for(loop
= 0; loop
< 1000; loop
++);
134 *mem_addr
= MEM_TYPE
;
135 /* Confirm bank 1 has DRAM memory */
136 if ((mem_mben
& 0x40000000) &&
137 ((mem_type
& 0x30000000) == 0x10000000)) {
138 *mem_addr
= MEM_B1SA
;
140 mem_start
= *mem_data
;
142 for(loop
= 0; loop
< 1000; loop
++);
144 *mem_addr
= MEM_B1EA
;
148 for(loop
= 0; loop
< 1000; loop
++);
150 mem_size
= mem_end
- mem_start
+ 0x100000;
153 /* Confirm bank 2 has DRAM memory */
154 if ((mem_mben
& 0x20000000) &&
155 ((mem_type
& 0xc000000) == 0x4000000)) {
156 *mem_addr
= MEM_B2SA
;
158 mem_start
= *mem_data
;
160 for(loop
= 0; loop
< 1000; loop
++);
162 *mem_addr
= MEM_B2EA
;
166 for(loop
= 0; loop
< 1000; loop
++);
168 mem_size
+= mem_end
- mem_start
+ 0x100000;
174 load_kernel(unsigned long load_addr
, int num_words
, unsigned long cksum
,
175 void *ign1
, void *ign2
)
181 unsigned short vendor
;
182 unsigned short device
;
183 unsigned short command
;
184 unsigned char header_type
;
186 volatile int *pif_addr
= (int *)0xff500000;
187 volatile int *pif_data
= (int *)0xff500004;
190 * Gah, these firmware guys need to learn that hardware
191 * byte swapping is evil! Disable all hardware byte
192 * swapping so it doesn't hurt anyone.
194 *pif_addr
= PLBMIFOPT
;
196 *pif_data
= 0x00000000;
199 /* Search out and turn off the PcNet ethernet boot device. */
200 for (pci_devfn
= 1; pci_devfn
< 0xff; pci_devfn
++) {
201 if (PCI_FUNC(pci_devfn
) && !found_multi
)
204 cpc700_pcibios_read_config_byte(0, pci_devfn
,
205 PCI_HEADER_TYPE
, &header_type
);
207 if (!PCI_FUNC(pci_devfn
))
208 found_multi
= header_type
& 0x80;
210 cpc700_pcibios_read_config_word(0, pci_devfn
, PCI_VENDOR_ID
,
213 if (vendor
!= 0xffff) {
214 cpc700_pcibios_read_config_word(0, pci_devfn
,
215 PCI_DEVICE_ID
, &device
);
217 /* If this PCI device is the Lance PCNet board then turn it off */
218 if ((vendor
== PCI_VENDOR_ID_AMD
) &&
219 (device
== PCI_DEVICE_ID_AMD_LANCE
)) {
221 /* Turn on I/O Space on the board. */
222 cpc700_pcibios_read_config_word(0, pci_devfn
,
223 PCI_COMMAND
, &command
);
225 cpc700_pcibios_write_config_word(0, pci_devfn
,
226 PCI_COMMAND
, command
);
228 /* Get the I/O space address */
229 cpc700_pcibios_read_config_dword(0, pci_devfn
,
230 PCI_BASE_ADDRESS_0
, &bar0
);
233 /* Reset the PCNet Board */
234 inl (bar0
+PCNET32_DWIO_RESET
);
235 inw (bar0
+PCNET32_WIO_RESET
);
237 /* First do a work oriented read of csr0. If the value is
238 * 4 then this is the correct mode to access the board.
239 * If not try a double word ortiented read.
241 outw(0, bar0
+ PCNET32_WIO_RAP
);
242 csr0
= inw(bar0
+ PCNET32_WIO_RDP
);
245 /* Check the Chip id register */
246 outw(88, bar0
+ PCNET32_WIO_RAP
);
247 csr_id
= inw(bar0
+ PCNET32_WIO_RDP
);
250 /* This is the valid mode - set the stop bit */
251 outw(0, bar0
+ PCNET32_WIO_RAP
);
252 outw(csr0
, bar0
+ PCNET32_WIO_RDP
);
255 outl(0, bar0
+ PCNET32_DWIO_RAP
);
256 csr0
= inl(bar0
+ PCNET32_DWIO_RDP
);
258 /* Check the Chip id register */
259 outl(88, bar0
+ PCNET32_WIO_RAP
);
260 csr_id
= inl(bar0
+ PCNET32_WIO_RDP
);
263 /* This is the valid mode - set the stop bit*/
264 outl(0, bar0
+ PCNET32_WIO_RAP
);
265 outl(csr0
, bar0
+ PCNET32_WIO_RDP
);
273 return decompress_kernel(load_addr
, num_words
, cksum
);