source: rtems/bsps/powerpc/beatnik/pci/gt_pci_init.c @ d7205f0

Last change on this file since d7205f0 was 5a4e3dc0, checked in by Sebastian Huber <sebastian.huber@…>, on 04/23/18 at 10:50:58

bsps: Move PCI drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 8.2 KB
RevLine 
[b7a6d23a]1/* PCI configuration space access */
2
3/*
4 * Acknowledgements:
5 * Valuable information was obtained from the following drivers
6 *   netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
7 *   linux:  (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
8 *   rtems:  (C) Brookhaven National Laboratory; K. Feng
9 */
10
11/*
12 * Original file header of libbsp/shared/pci.c where this file is based upon.
13 *
14 *  Copyright (C) 1999 valette@crf.canon.fr
15 *
16 *  This code is heavily inspired by the public specification of STREAM V2
17 *  that can be found at :
18 *
19 *      <http://www.chorus.com/Documentation/index.html> by following
20 *  the STREAM API Specification Document link.
21 *
22 *  The license and distribution terms for this file may be
[0c875c6a]23 *  found in the file LICENSE in this distribution or at
[c499856]24 *  http://www.rtems.org/license/LICENSE.
[b7a6d23a]25 *
26 *  Till Straumann, <strauman@slac.stanford.edu>, 1/2002
27 *   - separated bridge detection code out of this file
28 */
29
30#include <rtems.h>
31#include <bsp.h>
32#include <libcpu/io.h>
33#include <bsp/pci.h>
34#include <rtems/bspIo.h>
35#include <stdint.h>
36
37/* set to max so we get early access to hose 0 */
38unsigned        BSP_pci_hose1_bus_base = (unsigned)-1;
39
40#define MV64x60_PCI0_CONFIG_ADDR        (BSP_MV64x60_BASE + 0xcf8)
41#define MV64x60_PCI0_CONFIG_DATA        (BSP_MV64x60_BASE + 0xcfc)
42#define MV64x60_PCI1_CONFIG_ADDR        (BSP_MV64x60_BASE + 0xc78)
43#define MV64x60_PCI1_CONFIG_DATA        (BSP_MV64x60_BASE + 0xc7c)
44
45#define PCI_BUS2HOSE(bus) (bus<BSP_pci_hose1_bus_base?0:1)
46
47void detect_host_bridge(void)
48{
49
50}
51
52typedef struct {
53        volatile unsigned char *pci_config_addr;
54        volatile unsigned char *pci_config_data;
55} PciHoseCfg;
56
57static PciHoseCfg hoses[2] = {
58        {
59                pci_config_addr:        (volatile unsigned char *)(MV64x60_PCI0_CONFIG_ADDR),
60                pci_config_data:        (volatile unsigned char *)(MV64x60_PCI0_CONFIG_DATA),
61        },
62        {
63                pci_config_addr:        (volatile unsigned char *)(MV64x60_PCI1_CONFIG_ADDR),
64                pci_config_data:        (volatile unsigned char *)(MV64x60_PCI1_CONFIG_DATA),
65        }
66};
67
68#define pci hoses[hose]
69
70#define HOSE_PREAMBLE \
71        uint8_t hose; \
72                if (bus < BSP_pci_hose1_bus_base) { \
73                        hose = 0; \
74                } else { \
75                        hose = 1; \
76                        bus -= BSP_pci_hose1_bus_base; \
77                }
78
79
80/* Sigh; we have to copy those out from the shared area... */
81static int
82indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
83                              unsigned char function,
84                              unsigned char offset, uint8_t *val) {
85HOSE_PREAMBLE;
[2d5c486]86        out_be32((volatile uint32_t *) pci.pci_config_addr,
[b7a6d23a]87                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
88        *val = in_8(pci.pci_config_data + (offset&3));
89        return PCIBIOS_SUCCESSFUL;
90}
91
92static int
93indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
94                              unsigned char function,
95                              unsigned char offset, uint16_t *val) {
96HOSE_PREAMBLE;
97        *val = 0xffff;
98        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
[2d5c486]99        out_be32((uint32_t*) pci.pci_config_addr,
[b7a6d23a]100                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
[2d5c486]101        *val = in_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)));
[b7a6d23a]102        return PCIBIOS_SUCCESSFUL;
103}
104
105static int
106indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
107                              unsigned char function,
108                              unsigned char offset, uint32_t *val) {
109HOSE_PREAMBLE;
110        *val = 0xffffffff;
111        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
[2d5c486]112        out_be32((uint32_t*) pci.pci_config_addr,
[b7a6d23a]113                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
[2d5c486]114        *val = in_le32((volatile uint32_t *)pci.pci_config_data);
[b7a6d23a]115        return PCIBIOS_SUCCESSFUL;
116}
117
118static int
119indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
120                               unsigned char function,
121                               unsigned char offset, uint8_t val) {
122HOSE_PREAMBLE;
[2d5c486]123        out_be32((uint32_t*) pci.pci_config_addr,
[b7a6d23a]124                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
125        out_8(pci.pci_config_data + (offset&3), val);
126        return PCIBIOS_SUCCESSFUL;
127}
128
129static int
130indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
131                               unsigned char function,
132                               unsigned char offset, uint16_t val) {
133HOSE_PREAMBLE;
134        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
[2d5c486]135        out_be32((uint32_t*) pci.pci_config_addr,
[b7a6d23a]136                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
[2d5c486]137        out_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)), val);
[b7a6d23a]138        return PCIBIOS_SUCCESSFUL;
139}
140
141static int
142indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
143                                unsigned char function,
144                                unsigned char offset, uint32_t val) {
145HOSE_PREAMBLE;
146        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
[2d5c486]147        out_be32((uint32_t*) pci.pci_config_addr,
[b7a6d23a]148                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
[2d5c486]149        out_le32((volatile uint32_t *)pci.pci_config_data, val);
[b7a6d23a]150        return PCIBIOS_SUCCESSFUL;
151}
152
153const pci_config_access_functions pci_hosed_indirect_functions = {
154        indirect_pci_read_config_byte,
155        indirect_pci_read_config_word,
156        indirect_pci_read_config_dword,
157        indirect_pci_write_config_byte,
158        indirect_pci_write_config_word,
159        indirect_pci_write_config_dword
160};
161
162
163extern unsigned char ucMaxPCIBus; /* importing this is ugly */
164
165/* This is a very ugly hack. I don't want to change the shared
166 * code to support multiple hoses so we hide everything under
167 * the hood with horrible kludges for now. Sorry.
168 */
169void
170BSP_pci_initialize(void)
171{
172
173#if 0   /* These values are already set up for the shared/pci.c code      */
174{
175extern pci_config_access_functions pci_indirect_functions;
176        /* by means of the PCI_CONFIG_ADDR/PCI_CONFIG_DATA macros (bsp.h) */
177        BSP_pci_configuration.pci_config_addr = hoses[0].pci_config_addr;
178        BSP_pci_configuration.pci_config_data = hoses[0].pci_config_data;
179        BSP_pci_configuration.pci_functions   = &pci_indirect_functions;
180}
181#endif
182        /* initialize the first hose */
183        /* scan hose 0 and sets the maximum bus number */
184        pci_initialize();
185        /* remember the boundary */
186        BSP_pci_hose1_bus_base = pci_bus_count();
187        /* so far, so good -- now comes the cludgy part: */
188        /* hack/reset the bus count */
189        ucMaxPCIBus = 0;
190        /* scan hose 1 */
191        BSP_pci_configuration.pci_config_addr = hoses[1].pci_config_addr;
192        BSP_pci_configuration.pci_config_data = hoses[1].pci_config_data;
193        pci_initialize();
194        /* check for overflow of an unsigned char */
195        if ( BSP_pci_hose1_bus_base + pci_bus_count() > 255 ) {
[1c193a2]196                rtems_panic("Too many PCI busses in the system");
[b7a6d23a]197        }
198        /* readjust total number */
199        ucMaxPCIBus+=BSP_pci_hose1_bus_base;
200
201        /* install new access functions that can hide the hoses */
202        BSP_pci_configuration.pci_config_addr = (volatile unsigned char *)0xdeadbeef;
203        BSP_pci_configuration.pci_config_data = (volatile unsigned char *)0xdeadbeef;
204        BSP_pci_configuration.pci_functions   = &pci_hosed_indirect_functions;
205}
206
207#define PCI_ERR_BITS            0xf900
208#define PCI_STATUS_OK(x)        (!((x)&PCI_ERR_BITS))
209
210/* For now, just clear errors in the PCI status reg.
211 *
212 * Returns: (for diagnostic purposes)
213 *          original settings (i.e. before applying the clearing
214 *          sequence)
215 *          (pci_status(hose_1)&0xff00) | ((pci_status(hose_2)>>8)&0xff)
216 */
217
218static unsigned long clear_hose_errors(int bus, int quiet)
219{
220unsigned long   rval;
221uint16_t        pcistat;
222int                             count;
223int                             hose = PCI_BUS2HOSE(bus);
224
225        /* read error status for info return */
226        pci_read_config_word(bus,0,0,PCI_STATUS,&pcistat);
227        rval = pcistat;
228
229        count=10;
230        do {
231                /* clear error reporting registers */
232
233                /* clear PCI status register */
234                pci_write_config_word(bus,0,0,PCI_STATUS, PCI_ERR_BITS);
235
236                /* read  new status */
237                pci_read_config_word(bus,0,0,PCI_STATUS, &pcistat);
238
239        } while ( ! PCI_STATUS_OK(pcistat) && count-- );
240
241        if ( !PCI_STATUS_OK(rval) && !quiet) {
[1b24a9b]242                printk("Cleared PCI errors at discovery (hose %i): pci_stat was 0x%04lx\n", hose, rval);
[b7a6d23a]243        }
244        if ( !PCI_STATUS_OK(pcistat) ) {
245                printk("Unable to clear PCI errors at discovery (hose %i) still 0x%04x after 10 attempts\n",hose, pcistat);
246        }
247        return rval;
248}
249
250unsigned short
251(*_BSP_clear_vmebridge_errors)(int) = 0;
252
253unsigned long
254_BSP_clear_hostbridge_errors(int enableMCP, int quiet)
255{
256unsigned long   rval;
257
258        /* MCP is not connected */
259        if ( enableMCP )
260                return -1;
261
262        rval  = (clear_hose_errors(0, quiet) & PCI_ERR_BITS)>>8;
263        rval |= clear_hose_errors(BSP_pci_hose1_bus_base, quiet) & PCI_ERR_BITS;
264
265        /* Tsi148 doesn't propagate VME bus errors to PCI status reg. */
266        if ( _BSP_clear_vmebridge_errors )
267                rval |= _BSP_clear_vmebridge_errors(quiet)<<16;
268
269        return rval;
270}
Note: See TracBrowser for help on using the repository browser.