Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[sfrench/cifs-2.6.git] / arch / ppc / boot / simple / misc-spruce.c
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
15 #include <linux/types.h>
16 #include <linux/config.h>
17 #include <linux/pci.h>
18
19 #include <asm/bootinfo.h>
20
21 extern unsigned long decompress_kernel(unsigned long load_addr, int num_words,
22                                        unsigned long cksum);
23
24 /* Define some important locations of the Spruce. */
25 #define SPRUCE_PCI_CONFIG_ADDR  0xfec00000
26 #define SPRUCE_PCI_CONFIG_DATA  0xfec00004
27
28 /* PCI configuration space access routines. */
29 unsigned int *pci_config_address = (unsigned int *)SPRUCE_PCI_CONFIG_ADDR;
30 unsigned char *pci_config_data   = (unsigned char *)SPRUCE_PCI_CONFIG_DATA;
31
32 void cpc700_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
33                              unsigned char offset, unsigned char *val)
34 {
35         out_le32(pci_config_address,
36                  (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
37
38         *val= (in_le32((unsigned *)pci_config_data) >> (8 * (offset & 3))) & 0xff;
39 }
40
41 void cpc700_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
42                              unsigned char offset, unsigned char val)
43 {
44         out_le32(pci_config_address,
45                  (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
46
47         out_8(pci_config_data + (offset&3), val);
48 }
49
50 void cpc700_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
51                              unsigned char offset, unsigned short *val)
52 {
53         out_le32(pci_config_address,
54                  (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
55
56         *val= in_le16((unsigned short *)(pci_config_data + (offset&3)));
57 }
58
59 void cpc700_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
60                              unsigned char offset, unsigned short val)
61 {
62         out_le32(pci_config_address,
63                  (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
64
65         out_le16((unsigned short *)(pci_config_data + (offset&3)), val);
66 }
67
68 void cpc700_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
69                              unsigned char offset, unsigned int *val)
70 {
71         out_le32(pci_config_address,
72                  (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
73
74         *val= in_le32((unsigned *)pci_config_data);
75 }
76
77 void cpc700_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
78                              unsigned char offset, unsigned int val)
79 {
80         out_le32(pci_config_address,
81                  (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
82
83         out_le32((unsigned *)pci_config_data, val);
84 }
85
86 #define PCNET32_WIO_RDP         0x10
87 #define PCNET32_WIO_RAP         0x12
88 #define PCNET32_WIO_RESET       0x14
89
90 #define PCNET32_DWIO_RDP        0x10
91 #define PCNET32_DWIO_RAP        0x14
92 #define PCNET32_DWIO_RESET      0x18
93
94 /* Processor interface config register access */
95 #define PIFCFGADDR 0xff500000
96 #define PIFCFGDATA 0xff500004
97
98 #define PLBMIFOPT 0x18 /* PLB Master Interface Options */
99
100 #define MEM_MBEN        0x24
101 #define MEM_TYPE        0x28
102 #define MEM_B1SA        0x3c
103 #define MEM_B1EA        0x5c
104 #define MEM_B2SA        0x40
105 #define MEM_B2EA        0x60
106
107 unsigned long
108 get_mem_size(void)
109 {
110         int loop;
111         unsigned long mem_size = 0;
112         unsigned long mem_mben;
113         unsigned long mem_type;
114         unsigned long mem_start;
115         unsigned long mem_end;
116         volatile int *mem_addr = (int *)0xff500008;
117         volatile int *mem_data = (int *)0xff50000c;
118
119         /* Get the size of memory from the memory controller. */
120         *mem_addr = MEM_MBEN;
121         asm("sync");
122         mem_mben = *mem_data;
123         asm("sync");
124         for(loop = 0; loop < 1000; loop++);
125
126         *mem_addr = MEM_TYPE;
127         asm("sync");
128         mem_type = *mem_data;
129         asm("sync");
130         for(loop = 0; loop < 1000; loop++);
131
132         *mem_addr = MEM_TYPE;
133         /* Confirm bank 1 has DRAM memory */
134         if ((mem_mben & 0x40000000) &&
135                                 ((mem_type & 0x30000000) == 0x10000000)) {
136                 *mem_addr = MEM_B1SA;
137                 asm("sync");
138                 mem_start = *mem_data;
139                 asm("sync");
140                 for(loop = 0; loop < 1000; loop++);
141
142                 *mem_addr = MEM_B1EA;
143                 asm("sync");
144                 mem_end = *mem_data;
145                 asm("sync");
146                 for(loop = 0; loop < 1000; loop++);
147
148                 mem_size = mem_end - mem_start + 0x100000;
149         }
150
151         /* Confirm bank 2 has DRAM memory */
152         if ((mem_mben & 0x20000000) &&
153                                 ((mem_type & 0xc000000) == 0x4000000)) {
154                 *mem_addr = MEM_B2SA;
155                 asm("sync");
156                 mem_start = *mem_data;
157                 asm("sync");
158                 for(loop = 0; loop < 1000; loop++);
159
160                 *mem_addr = MEM_B2EA;
161                 asm("sync");
162                 mem_end = *mem_data;
163                 asm("sync");
164                 for(loop = 0; loop < 1000; loop++);
165
166                 mem_size += mem_end - mem_start + 0x100000;
167         }
168         return mem_size;
169 }
170
171 unsigned long
172 load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
173                 void *ign1, void *ign2)
174 {
175         int csr0;
176         int csr_id;
177         int pci_devfn;
178         int found_multi = 0;
179         unsigned short vendor;
180         unsigned short device;
181         unsigned short command;
182         unsigned char header_type;
183         unsigned int bar0;
184         volatile int *pif_addr = (int *)0xff500000;
185         volatile int *pif_data = (int *)0xff500004;
186
187         /*
188          * Gah, these firmware guys need to learn that hardware
189          * byte swapping is evil! Disable all hardware byte
190          * swapping so it doesn't hurt anyone.
191          */
192         *pif_addr = PLBMIFOPT;
193         asm("sync");
194         *pif_data = 0x00000000;
195         asm("sync");
196
197         /* Search out and turn off the PcNet ethernet boot device. */
198         for (pci_devfn = 1; pci_devfn < 0xff; pci_devfn++) {
199                 if (PCI_FUNC(pci_devfn) && !found_multi)
200                         continue;
201
202                 cpc700_pcibios_read_config_byte(0, pci_devfn,
203                                 PCI_HEADER_TYPE, &header_type);
204
205                 if (!PCI_FUNC(pci_devfn))
206                         found_multi = header_type & 0x80;
207
208                 cpc700_pcibios_read_config_word(0, pci_devfn, PCI_VENDOR_ID,
209                                 &vendor);
210
211                 if (vendor != 0xffff) {
212                         cpc700_pcibios_read_config_word(0, pci_devfn,
213                                                 PCI_DEVICE_ID, &device);
214
215                         /* If this PCI device is the Lance PCNet board then turn it off */
216                         if ((vendor == PCI_VENDOR_ID_AMD) &&
217                                         (device == PCI_DEVICE_ID_AMD_LANCE)) {
218
219                                 /* Turn on I/O Space on the board. */
220                                 cpc700_pcibios_read_config_word(0, pci_devfn,
221                                                 PCI_COMMAND, &command);
222                                 command |= 0x1;
223                                 cpc700_pcibios_write_config_word(0, pci_devfn,
224                                                 PCI_COMMAND, command);
225
226                                 /* Get the I/O space address */
227                                 cpc700_pcibios_read_config_dword(0, pci_devfn,
228                                                 PCI_BASE_ADDRESS_0, &bar0);
229                                 bar0 &= 0xfffffffe;
230
231                                 /* Reset the PCNet Board */
232                                 inl (bar0+PCNET32_DWIO_RESET);
233                                 inw (bar0+PCNET32_WIO_RESET);
234
235                                 /* First do a work oriented read of csr0.  If the value is
236                                  * 4 then this is the correct mode to access the board.
237                                  * If not try a double word ortiented read.
238                                  */
239                                 outw(0, bar0 + PCNET32_WIO_RAP);
240                                 csr0 = inw(bar0 + PCNET32_WIO_RDP);
241
242                                 if (csr0 == 4) {
243                                         /* Check the Chip id register */
244                                         outw(88, bar0 + PCNET32_WIO_RAP);
245                                         csr_id = inw(bar0 + PCNET32_WIO_RDP);
246
247                                         if (csr_id) {
248                                                 /* This is the valid mode - set the stop bit */
249                                                 outw(0, bar0 + PCNET32_WIO_RAP);
250                                                 outw(csr0, bar0 + PCNET32_WIO_RDP);
251                                         }
252                                 } else {
253                                         outl(0, bar0 + PCNET32_DWIO_RAP);
254                                         csr0 = inl(bar0 + PCNET32_DWIO_RDP);
255                                         if (csr0 == 4) {
256                                                 /* Check the Chip id register */
257                                                 outl(88, bar0 + PCNET32_WIO_RAP);
258                                                 csr_id = inl(bar0 + PCNET32_WIO_RDP);
259
260                                                 if (csr_id) {
261                                                         /* This is the valid mode  - set the stop bit*/
262                                                         outl(0, bar0 + PCNET32_WIO_RAP);
263                                                         outl(csr0, bar0 + PCNET32_WIO_RDP);
264                                                 }
265                                         }
266                                 }
267                         }
268                 }
269         }
270
271         return decompress_kernel(load_addr, num_words, cksum);
272 }