]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/xscale/ixp425/v2_0/src/ixp425_pci.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / xscale / ixp425 / v2_0 / src / ixp425_pci.c
1 //==========================================================================
2 //
3 //      ixp425_pci.c
4 //
5 //      HAL support code for IXP425 PCI
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    msalter
44 // Contributors: msalter
45 // Date:         2002-12-08
46 // Purpose:      PCI support
47 // Description:  Implementations of HAL PCI interfaces
48 //
49 //####DESCRIPTIONEND####
50 //
51 //========================================================================*/
52
53 #include <pkgconf/hal.h>
54 #include <pkgconf/system.h>
55 #include CYGBLD_HAL_PLATFORM_H
56
57 #ifdef CYGPKG_IO_PCI
58
59 #include <cyg/infra/cyg_type.h>         // base types
60 #include <cyg/infra/cyg_trac.h>         // tracing macros
61 #include <cyg/infra/cyg_ass.h>          // assertion macros
62
63 #include <cyg/hal/hal_io.h>             // IO macros
64 #include <cyg/hal/hal_if.h>             // calling interface API
65 #include <cyg/hal/hal_arch.h>           // Register state info
66 #include <cyg/hal/hal_diag.h>
67 #include <cyg/hal/hal_intr.h>           // Interrupt names
68 #include <cyg/hal/hal_cache.h>
69 #include <cyg/io/pci_hw.h>
70 #include <cyg/io/pci.h>
71
72
73 static cyg_uint8
74 ixp425_read_config_byte(int offset)
75
76     *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | PCI_CRP_AD_CBE_READ;
77     return *IXP425_PCI_CRP_RDATA >> (8*(offset & 3));
78 }
79
80 static cyg_uint16
81 ixp425_read_config_word(int offset)
82
83     *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | PCI_CRP_AD_CBE_READ;
84     return *IXP425_PCI_CRP_RDATA >> (8*(offset & 3));
85 }
86
87 static cyg_uint32
88 ixp425_read_config_dword(int offset)
89
90     *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | PCI_CRP_AD_CBE_READ;
91     return *IXP425_PCI_CRP_RDATA;
92 }
93
94 void
95 ixp425_write_config_byte(int offset, cyg_uint8 value)
96 {
97     static const cyg_uint32 _cbe[4] = {
98         (0xe << PCI_CRP_AD_CBE_BE_SHIFT) | PCI_CRP_AD_CBE_WRITE,
99         (0xd << PCI_CRP_AD_CBE_BE_SHIFT) | PCI_CRP_AD_CBE_WRITE,
100         (0xb << PCI_CRP_AD_CBE_BE_SHIFT) | PCI_CRP_AD_CBE_WRITE,
101         (0x7 << PCI_CRP_AD_CBE_BE_SHIFT) | PCI_CRP_AD_CBE_WRITE
102     };
103     int pos = offset & 3;
104
105     *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | _cbe[pos];
106     *IXP425_PCI_CRP_WDATA = value << (8 * pos);
107 }
108
109 void
110 ixp425_write_config_word(int offset, cyg_uint16 value)
111 {
112     static const cyg_uint32 _cbe[4] = {
113         (0xc << PCI_CRP_AD_CBE_BE_SHIFT) | PCI_CRP_AD_CBE_WRITE,
114         (0x9 << PCI_CRP_AD_CBE_BE_SHIFT) | PCI_CRP_AD_CBE_WRITE,
115         (0x3 << PCI_CRP_AD_CBE_BE_SHIFT) | PCI_CRP_AD_CBE_WRITE,
116         (0x7 << PCI_CRP_AD_CBE_BE_SHIFT) | PCI_CRP_AD_CBE_WRITE
117     };
118     int pos = offset & 3;
119
120     *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | _cbe[pos];
121     *IXP425_PCI_CRP_WDATA = value << (8 * pos);
122 }
123
124 void
125 ixp425_write_config_dword(int offset, cyg_uint32 value)
126 {
127     *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | PCI_CRP_AD_CBE_WRITE;
128     *IXP425_PCI_CRP_WDATA = value;
129 }
130
131 // Setup address/cbe/cmd for read/write.
132 // Return CBE register value to use.
133 //
134 static cyg_uint32
135 pci_config(cyg_uint32 bus, cyg_uint32 devfn, cyg_uint32 offset, cyg_uint32 cmd, int size)
136 {
137     static const cyg_uint8 byte_cbe[4] = { 0xe0, 0xd0, 0xb0, 0x70 };
138     static const cyg_uint8 word_cbe[4] = { 0xc0, 0x90, 0x30, 0x70 };
139
140     if (bus == 0) {
141         // bus == 0 && devfn == 0 is a special case. Higher level config cycle
142         // code will not call this routine for bus 0, devfn 0 as that is the
143         // device address used by the IXP425 PCI device. When commands other
144         // than config read/write are desired, bus 0, devfn 0 is used to
145         // indicate that the offset should be used as the address.
146         if (devfn == 0) {
147             *IXP425_PCI_NP_AD = offset;
148         } else {
149             // type 0
150             //
151             // Take care with device number as we use device 0 to indicate
152             // the IXP425 itself. This code makes device 1-21 externally
153             // addressable.
154             //
155             *IXP425_PCI_NP_AD = (0x400 << CYG_PCI_DEV_GET_DEV(devfn)) |
156             (CYG_PCI_DEV_GET_FN(devfn)<< 8) | (offset & ~3);
157         }
158     } else {
159         // type 1
160         *IXP425_PCI_NP_AD = (bus << 16) | (CYG_PCI_DEV_GET_DEV(devfn) << 11) | 
161             (CYG_PCI_DEV_GET_FN(devfn) << 8) | (offset & ~3) | 1;
162     }
163
164     if (size == 1)
165         cmd |= byte_cbe[offset & 3];
166     else if (size == 2)
167         cmd |= word_cbe[offset & 3];
168
169     return cmd;
170 }
171
172 // check for abort after config access
173 static int
174 pci_check_abort(void)
175 {
176     if (*IXP425_PCI_ISR & PCI_ISR_PFE) {
177         *IXP425_PCI_ISR = PCI_ISR_PFE;
178         return 1;
179     }
180     return 0;
181 }
182
183 static cyg_uint32
184 pci_np_read(cyg_uint32 cmd)
185 {
186     cyg_uint32 data;
187 #ifdef CYGHWR_HAL_IXP425_PCI_NP_WORKAROUND
188     // 
189     // PCI NP Bug workaround  - only works if NP PCI space reads have
190     // no side effects! Read 8 times. Last one will be good.
191     //
192     int i;
193
194     for (i = 0; i < 8; i++) {
195         // set up and execute the read
196         *IXP425_PCI_NP_CBE = cmd;
197         // the result of the read is now in NP_RDATA (maybe)
198         data = *IXP425_PCI_NP_RDATA;
199         // the result of the read is now in NP_RDATA (for sure)
200         data = *IXP425_PCI_NP_RDATA;
201     }
202 #else
203     // set up and execute the read
204     *IXP425_PCI_NP_CBE = cmd;
205     // the result of the read is now in NP_RDATA
206     data = *IXP425_PCI_NP_RDATA;
207 #endif
208     if (pci_check_abort())
209         return 0xffffffff;
210     return data;
211 }
212
213 static void
214 pci_np_write(cyg_uint32 cmd, cyg_uint32 data)
215 {
216     // set up the write
217     *IXP425_PCI_NP_CBE = cmd;
218     // write the date
219     *IXP425_PCI_NP_WDATA = data;
220
221     (void)pci_check_abort();
222 }
223
224 static cyg_uint8
225 bus_read_config_byte(cyg_uint32 bus, cyg_uint32 devfn, int offset)
226 {
227     cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGR, 1);
228
229     return pci_np_read(cmd) >> ((offset & 3) * 8);
230 }
231
232 static cyg_uint16
233 bus_read_config_word(cyg_uint32 bus, cyg_uint32 devfn, int offset)
234 {
235     cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGR, 2);
236
237     return pci_np_read(cmd) >> ((offset & 3) * 8);
238 }
239
240 static cyg_uint32
241 bus_read_config_dword(cyg_uint32 bus, cyg_uint32 devfn, int offset)
242 {
243     cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGR, 4);
244
245     return pci_np_read(cmd);
246 }
247
248 static void
249 bus_write_config_byte(cyg_uint32 bus, cyg_uint32 devfn, int offset, cyg_uint8 value)
250 {
251     cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGW, 1);
252
253     pci_np_write(cmd, value << ((offset & 3) * 8));
254 }
255
256 static void
257 bus_write_config_word(cyg_uint32 bus, cyg_uint32 devfn, int offset, cyg_uint16 value)
258 {
259     cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGW, 2);
260
261     pci_np_write(cmd, value << ((offset & 3) * 8));
262 }
263
264 static void
265 bus_write_config_dword(cyg_uint32 bus, cyg_uint32 devfn, int offset, cyg_uint32 value)
266 {
267     cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGW, 4);
268
269     pci_np_write(cmd, value);
270 }
271
272
273 cyg_uint32
274 cyg_hal_plf_pci_cfg_read_dword (cyg_uint32 bus, cyg_uint32 devfn, cyg_uint32 offset)
275 {
276     if (bus || CYG_PCI_DEV_GET_DEV(devfn))
277         return bus_read_config_dword(bus, devfn, offset);
278
279     return ixp425_read_config_dword(offset);
280 }
281
282
283 void
284 cyg_hal_plf_pci_cfg_write_dword (cyg_uint32 bus,
285                                  cyg_uint32 devfn,
286                                  cyg_uint32 offset,
287                                  cyg_uint32 data)
288 {
289     if (bus || CYG_PCI_DEV_GET_DEV(devfn))
290         bus_write_config_dword(bus, devfn, offset, data);
291     else
292         ixp425_write_config_dword(offset, data);
293 }
294
295
296 cyg_uint16
297 cyg_hal_plf_pci_cfg_read_word (cyg_uint32 bus,
298                                cyg_uint32 devfn,
299                                cyg_uint32 offset)
300 {
301     if (bus || CYG_PCI_DEV_GET_DEV(devfn))
302         return bus_read_config_word(bus, devfn, offset);
303
304     return ixp425_read_config_word(offset);
305 }
306
307 void
308 cyg_hal_plf_pci_cfg_write_word (cyg_uint32 bus,
309                                 cyg_uint32 devfn,
310                                 cyg_uint32 offset,
311                                 cyg_uint16 data)
312 {
313     if (bus || CYG_PCI_DEV_GET_DEV(devfn))
314         bus_write_config_word(bus, devfn, offset, data);
315     else
316         ixp425_write_config_word(offset, data);
317 }
318
319 cyg_uint8
320 cyg_hal_plf_pci_cfg_read_byte (cyg_uint32 bus,
321                                cyg_uint32 devfn,
322                                cyg_uint32 offset)
323 {
324     if (bus || CYG_PCI_DEV_GET_DEV(devfn))
325         return bus_read_config_byte(bus, devfn, offset);
326
327     return ixp425_read_config_byte(offset);
328 }
329
330
331 void
332 cyg_hal_plf_pci_cfg_write_byte (cyg_uint32 bus,
333                                 cyg_uint32 devfn,
334                                 cyg_uint32 offset,
335                                 cyg_uint8 data)
336 {
337     if (bus || CYG_PCI_DEV_GET_DEV(devfn))
338         bus_write_config_byte(bus, devfn, offset, data);
339     else
340         ixp425_write_config_byte(offset, data);
341 }
342
343
344 void
345 cyg_hal_plf_pci_io_outb(cyg_uint32 offset, cyg_uint8 value)
346 {
347     cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOW, 1);
348
349     pci_np_write(cmd, value << ((offset & 3) * 8));
350 }
351
352 void
353 cyg_hal_plf_pci_io_outw(cyg_uint32 offset, cyg_uint16 value)
354 {
355     cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOW, 2);
356
357     pci_np_write(cmd, value << ((offset & 3) * 8));
358 }
359
360 void
361 cyg_hal_plf_pci_io_outl(cyg_uint32 offset, cyg_uint32 value)
362 {
363     cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOW, 4);
364
365     pci_np_write(cmd, value);
366 }
367
368 cyg_uint8
369 cyg_hal_plf_pci_io_inb(cyg_uint32 offset)
370 {
371     cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOR, 1);
372
373     return pci_np_read(cmd) >> ((offset & 3) * 8);
374 }
375
376 cyg_uint16
377 cyg_hal_plf_pci_io_inw(cyg_uint32 offset)
378 {
379     cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOR, 2);
380
381     return pci_np_read(cmd) >> ((offset & 3) * 8);
382 }
383
384 cyg_uint32
385 cyg_hal_plf_pci_io_inl(cyg_uint32 offset)
386 {
387     cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOR, 4);
388
389     return pci_np_read(cmd);
390 }
391
392 #ifdef CYGHWR_HAL_ARM_BIGENDIAN
393 #define CSR_ENDIAN_BITS  (PCI_CSR_PDS | PCI_CSR_ABE | PCI_CSR_ADS)
394 #else
395 #define CSR_ENDIAN_BITS  (PCI_CSR_ABE | PCI_CSR_ADS)
396 #endif
397
398 void
399 cyg_hal_plf_pci_init(void)
400 {  
401     static int inited = 0;
402     int  is_host = (*IXP425_PCI_CSR & PCI_CSR_HOST);
403
404     if (inited)
405         return;
406     else
407         inited = 1;
408             
409     // If IC is set, assume warm start
410     if (*IXP425_PCI_CSR  & PCI_CSR_IC)
411         return;
412
413     // We use identity AHB->PCI address translation
414     // in the 0x48000000 address space
415     *IXP425_PCI_PCIMEMBASE = 0x48494A4B;
416
417     // We also use identity PCI->AHB address translation
418     // in 4 16MB BARs that begin at the physical memory start
419     *IXP425_PCI_AHBMEMBASE = 0x00010203;
420
421     if (is_host) {
422
423         HAL_PCI_CFG_WRITE_UINT32(0, 0, CYG_PCI_CFG_BAR_0, 0x00000000);
424         HAL_PCI_CFG_WRITE_UINT32(0, 0, CYG_PCI_CFG_BAR_1, 0x01000000);
425         HAL_PCI_CFG_WRITE_UINT32(0, 0, CYG_PCI_CFG_BAR_2, 0x02000000);
426         HAL_PCI_CFG_WRITE_UINT32(0, 0, CYG_PCI_CFG_BAR_3, 0x03000000);
427
428         cyg_pci_set_memory_base(HAL_PCI_ALLOC_BASE_MEMORY);
429         cyg_pci_set_io_base(HAL_PCI_ALLOC_BASE_IO);
430
431         // This one should never get used, as we request the memory for
432         // work with PCI with GFP_DMA, which will return mem in the first 64 MB.
433         // But we still must initialize it so that it wont intersect with first 4
434         // BARs
435         // XXX: Should we initialize the BAR5 to some very large value, so that
436         // it also will not be hit?
437         //
438         HAL_PCI_CFG_WRITE_UINT32(0, 0, CYG_PCI_CFG_BAR_4, 0x80000000);
439         HAL_PCI_CFG_WRITE_UINT32(0, 0, CYG_PCI_CFG_BAR_5, 0x90000000);
440
441         *IXP425_PCI_ISR = PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE;
442
443         //
444         // Set Initialize Complete in PCI Control Register: allow IXP425 to
445         // respond to PCI configuration cycles. Specify that the AHB bus is
446         // operating in big endian mode. Set up byte lane swapping between 
447         // little-endian PCI and the big-endian AHB bus 
448         *IXP425_PCI_CSR = PCI_CSR_IC | CSR_ENDIAN_BITS;
449     
450         HAL_PCI_CFG_WRITE_UINT16(0, 0, CYG_PCI_CFG_COMMAND,
451                  CYG_PCI_CFG_COMMAND_MASTER | CYG_PCI_CFG_COMMAND_MEMORY);
452     } else {
453         //
454         // Set Initialize Complete in PCI Control Register: allow IXP425 to
455         // respond to PCI configuration cycles. Specify that the AHB bus is
456         // operating in big endian mode. Set up byte lane swapping between 
457         // little-endian PCI and the big-endian AHB bus 
458         *IXP425_PCI_CSR = PCI_CSR_IC | PCI_CSR_ABE | PCI_CSR_PDS | PCI_CSR_ADS;
459     }
460 }
461
462 #endif // CYGPKG_IO_PCI