1 //==========================================================================
5 // HAL support code for IXP425 PCI
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.
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.
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
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.
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.
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.
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####
44 // Contributors: msalter
46 // Purpose: PCI support
47 // Description: Implementations of HAL PCI interfaces
49 //####DESCRIPTIONEND####
51 //========================================================================*/
53 #include <pkgconf/hal.h>
54 #include <pkgconf/system.h>
55 #include CYGBLD_HAL_PLATFORM_H
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
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>
74 ixp425_read_config_byte(int offset)
76 *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | PCI_CRP_AD_CBE_READ;
77 return *IXP425_PCI_CRP_RDATA >> (8*(offset & 3));
81 ixp425_read_config_word(int offset)
83 *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | PCI_CRP_AD_CBE_READ;
84 return *IXP425_PCI_CRP_RDATA >> (8*(offset & 3));
88 ixp425_read_config_dword(int offset)
90 *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | PCI_CRP_AD_CBE_READ;
91 return *IXP425_PCI_CRP_RDATA;
95 ixp425_write_config_byte(int offset, cyg_uint8 value)
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
103 int pos = offset & 3;
105 *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | _cbe[pos];
106 *IXP425_PCI_CRP_WDATA = value << (8 * pos);
110 ixp425_write_config_word(int offset, cyg_uint16 value)
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
118 int pos = offset & 3;
120 *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | _cbe[pos];
121 *IXP425_PCI_CRP_WDATA = value << (8 * pos);
125 ixp425_write_config_dword(int offset, cyg_uint32 value)
127 *IXP425_PCI_CRP_AD_CPE = (offset & ~3) | PCI_CRP_AD_CBE_WRITE;
128 *IXP425_PCI_CRP_WDATA = value;
131 // Setup address/cbe/cmd for read/write.
132 // Return CBE register value to use.
135 pci_config(cyg_uint32 bus, cyg_uint32 devfn, cyg_uint32 offset, cyg_uint32 cmd, int size)
137 static const cyg_uint8 byte_cbe[4] = { 0xe0, 0xd0, 0xb0, 0x70 };
138 static const cyg_uint8 word_cbe[4] = { 0xc0, 0x90, 0x30, 0x70 };
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.
147 *IXP425_PCI_NP_AD = offset;
151 // Take care with device number as we use device 0 to indicate
152 // the IXP425 itself. This code makes device 1-21 externally
155 *IXP425_PCI_NP_AD = (0x400 << CYG_PCI_DEV_GET_DEV(devfn)) |
156 (CYG_PCI_DEV_GET_FN(devfn)<< 8) | (offset & ~3);
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;
165 cmd |= byte_cbe[offset & 3];
167 cmd |= word_cbe[offset & 3];
172 // check for abort after config access
174 pci_check_abort(void)
176 if (*IXP425_PCI_ISR & PCI_ISR_PFE) {
177 *IXP425_PCI_ISR = PCI_ISR_PFE;
184 pci_np_read(cyg_uint32 cmd)
187 #ifdef CYGHWR_HAL_IXP425_PCI_NP_WORKAROUND
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.
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;
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;
208 if (pci_check_abort())
214 pci_np_write(cyg_uint32 cmd, cyg_uint32 data)
217 *IXP425_PCI_NP_CBE = cmd;
219 *IXP425_PCI_NP_WDATA = data;
221 (void)pci_check_abort();
225 bus_read_config_byte(cyg_uint32 bus, cyg_uint32 devfn, int offset)
227 cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGR, 1);
229 return pci_np_read(cmd) >> ((offset & 3) * 8);
233 bus_read_config_word(cyg_uint32 bus, cyg_uint32 devfn, int offset)
235 cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGR, 2);
237 return pci_np_read(cmd) >> ((offset & 3) * 8);
241 bus_read_config_dword(cyg_uint32 bus, cyg_uint32 devfn, int offset)
243 cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGR, 4);
245 return pci_np_read(cmd);
249 bus_write_config_byte(cyg_uint32 bus, cyg_uint32 devfn, int offset, cyg_uint8 value)
251 cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGW, 1);
253 pci_np_write(cmd, value << ((offset & 3) * 8));
257 bus_write_config_word(cyg_uint32 bus, cyg_uint32 devfn, int offset, cyg_uint16 value)
259 cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGW, 2);
261 pci_np_write(cmd, value << ((offset & 3) * 8));
265 bus_write_config_dword(cyg_uint32 bus, cyg_uint32 devfn, int offset, cyg_uint32 value)
267 cyg_uint32 cmd = pci_config(bus, devfn, offset, PCI_NP_CMD_CONFIGW, 4);
269 pci_np_write(cmd, value);
274 cyg_hal_plf_pci_cfg_read_dword (cyg_uint32 bus, cyg_uint32 devfn, cyg_uint32 offset)
276 if (bus || CYG_PCI_DEV_GET_DEV(devfn))
277 return bus_read_config_dword(bus, devfn, offset);
279 return ixp425_read_config_dword(offset);
284 cyg_hal_plf_pci_cfg_write_dword (cyg_uint32 bus,
289 if (bus || CYG_PCI_DEV_GET_DEV(devfn))
290 bus_write_config_dword(bus, devfn, offset, data);
292 ixp425_write_config_dword(offset, data);
297 cyg_hal_plf_pci_cfg_read_word (cyg_uint32 bus,
301 if (bus || CYG_PCI_DEV_GET_DEV(devfn))
302 return bus_read_config_word(bus, devfn, offset);
304 return ixp425_read_config_word(offset);
308 cyg_hal_plf_pci_cfg_write_word (cyg_uint32 bus,
313 if (bus || CYG_PCI_DEV_GET_DEV(devfn))
314 bus_write_config_word(bus, devfn, offset, data);
316 ixp425_write_config_word(offset, data);
320 cyg_hal_plf_pci_cfg_read_byte (cyg_uint32 bus,
324 if (bus || CYG_PCI_DEV_GET_DEV(devfn))
325 return bus_read_config_byte(bus, devfn, offset);
327 return ixp425_read_config_byte(offset);
332 cyg_hal_plf_pci_cfg_write_byte (cyg_uint32 bus,
337 if (bus || CYG_PCI_DEV_GET_DEV(devfn))
338 bus_write_config_byte(bus, devfn, offset, data);
340 ixp425_write_config_byte(offset, data);
345 cyg_hal_plf_pci_io_outb(cyg_uint32 offset, cyg_uint8 value)
347 cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOW, 1);
349 pci_np_write(cmd, value << ((offset & 3) * 8));
353 cyg_hal_plf_pci_io_outw(cyg_uint32 offset, cyg_uint16 value)
355 cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOW, 2);
357 pci_np_write(cmd, value << ((offset & 3) * 8));
361 cyg_hal_plf_pci_io_outl(cyg_uint32 offset, cyg_uint32 value)
363 cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOW, 4);
365 pci_np_write(cmd, value);
369 cyg_hal_plf_pci_io_inb(cyg_uint32 offset)
371 cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOR, 1);
373 return pci_np_read(cmd) >> ((offset & 3) * 8);
377 cyg_hal_plf_pci_io_inw(cyg_uint32 offset)
379 cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOR, 2);
381 return pci_np_read(cmd) >> ((offset & 3) * 8);
385 cyg_hal_plf_pci_io_inl(cyg_uint32 offset)
387 cyg_uint32 cmd = pci_config(0, 0, offset, PCI_NP_CMD_IOR, 4);
389 return pci_np_read(cmd);
392 #ifdef CYGHWR_HAL_ARM_BIGENDIAN
393 #define CSR_ENDIAN_BITS (PCI_CSR_PDS | PCI_CSR_ABE | PCI_CSR_ADS)
395 #define CSR_ENDIAN_BITS (PCI_CSR_ABE | PCI_CSR_ADS)
399 cyg_hal_plf_pci_init(void)
401 static int inited = 0;
402 int is_host = (*IXP425_PCI_CSR & PCI_CSR_HOST);
409 // If IC is set, assume warm start
410 if (*IXP425_PCI_CSR & PCI_CSR_IC)
413 // We use identity AHB->PCI address translation
414 // in the 0x48000000 address space
415 *IXP425_PCI_PCIMEMBASE = 0x48494A4B;
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;
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);
428 cyg_pci_set_memory_base(HAL_PCI_ALLOC_BASE_MEMORY);
429 cyg_pci_set_io_base(HAL_PCI_ALLOC_BASE_IO);
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
435 // XXX: Should we initialize the BAR5 to some very large value, so that
436 // it also will not be hit?
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);
441 *IXP425_PCI_ISR = PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE;
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;
450 HAL_PCI_CFG_WRITE_UINT16(0, 0, CYG_PCI_CFG_COMMAND,
451 CYG_PCI_CFG_COMMAND_MASTER | CYG_PCI_CFG_COMMAND_MEMORY);
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;
462 #endif // CYGPKG_IO_PCI