OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [mips/] [ddb5xxx/] [ddb5476/] [pci_ops.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Copyright 2001 MontaVista Software Inc.
3
 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
4
 *
5
 * arch/mips/ddb5xxx/ddb5476/pci_ops.c
6
 *     Define the pci_ops for DB5477.
7
 *
8
 * Much of the code is derived from the original DDB5074 port by
9
 * Geert Uytterhoeven <geert@sonycom.com>
10
 *
11
 * This program is free software; you can redistribute  it and/or modify it
12
 * under  the terms of  the GNU General  Public License as published by the
13
 * Free Software Foundation;  either version 2 of the  License, or (at your
14
 * option) any later version.
15
 *
16
 */
17
 
18
#include <linux/config.h>
19
#include <linux/pci.h>
20
#include <linux/kernel.h>
21
#include <linux/types.h>
22
 
23
#include <asm/addrspace.h>
24
#include <asm/debug.h>
25
 
26
#include <asm/ddb5xxx/ddb5xxx.h>
27
 
28
/*
29
 * config_swap structure records what set of pdar/pmr are used
30
 * to access pci config space.  It also provides a place hold the
31
 * original values for future restoring.
32
 */
33
struct pci_config_swap {
34
        u32     pdar;
35
        u32     pmr;
36
        u32     config_base;
37
        u32     config_size;
38
        u32     pdar_backup;
39
        u32     pmr_backup;
40
};
41
 
42
/*
43
 * On DDB5476, we have one set of swap registers
44
 */
45
struct pci_config_swap ext_pci_swap = {
46
        DDB_PCIW0,
47
        DDB_PCIINIT0,
48
        DDB_PCI_CONFIG_BASE,
49
        DDB_PCI_CONFIG_SIZE
50
};
51
 
52
/*
53
 * access config space
54
 */
55
static inline u32 ddb_access_config_base(struct pci_config_swap *swap,
56
                                         u32 bus,/* 0 means top level bus */
57
                                         u32 slot_num)
58
{
59
        u32 pci_addr = 0;
60
        u32 pciinit_offset = 0;
61
        u32 virt_addr = swap->config_base;
62
        u32 option;
63
 
64
        /*
65
         * BUG: skip host PCI controller.  Its BARS are bogus.
66
         */
67
        if (slot_num == 12)
68
                slot_num = 0;
69
 
70
        /* minimum pdar (window) size is 2MB */
71
        db_assert(swap->config_size >= (2 << 20));
72
 
73
        db_assert(slot_num < (1 << 5));
74
        db_assert(bus < (1 << 8));
75
 
76
        /* backup registers */
77
        swap->pdar_backup = ddb_in32(swap->pdar);
78
        swap->pmr_backup = ddb_in32(swap->pmr);
79
 
80
        /* set the pdar (pci window) register */
81
        ddb_set_pdar(swap->pdar,
82
                     swap->config_base,
83
                     swap->config_size,
84
                     32,        /* 32 bit wide */
85
                     0,          /* not on local memory bus */
86
                     0); /* not visible from PCI bus (N/A) */
87
 
88
        /*
89
         * calcuate the absolute pci config addr;
90
         * according to the spec, we start scanning from adr:11 (0x800)
91
         */
92
        if (bus == 0) {
93
                /* type 0 config */
94
                pci_addr = 0x800 << slot_num;
95
        } else {
96
                /* type 1 config */
97
                pci_addr = (bus << 16) | (slot_num << 11);
98
                /* panic("ddb_access_config_base: we don't support type 1 config Yet"); */
99
        }
100
 
101
        /*
102
         * if pci_addr is less than pci config window size,  we set
103
         * pciinit_offset to 0 and adjust the virt_address.
104
         * Otherwise we will try to adjust pciinit_offset.
105
         */
106
        if (pci_addr < swap->config_size) {
107
                virt_addr = KSEG1ADDR(swap->config_base + pci_addr);
108
                pciinit_offset = 0;
109
        } else {
110
                db_assert( (pci_addr & (swap->config_size - 1)) == 0);
111
                virt_addr = KSEG1ADDR(swap->config_base);
112
                pciinit_offset = pci_addr;
113
        }
114
 
115
        /* set the pmr register */
116
        option = DDB_PCI_ACCESS_32;
117
        if (bus != 0) option |= DDB_PCI_CFGTYPE1;
118
        ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option);
119
 
120
        return virt_addr;
121
}
122
 
123
static inline void ddb_close_config_base(struct pci_config_swap *swap)
124
{
125
        ddb_out32(swap->pdar, swap->pdar_backup);
126
        ddb_out32(swap->pmr, swap->pmr_backup);
127
}
128
 
129
static int read_config_dword(struct pci_config_swap *swap,
130
                             struct pci_dev *dev,
131
                             u32 where,
132
                             u32 *val)
133
{
134
        u32 bus, slot_num, func_num;
135
        u32 base;
136
 
137
        db_assert((where & 3) == 0);
138
        db_assert(where < (1 << 8));
139
 
140
        /* check if the bus is top-level */
141
        if (dev->bus->parent != NULL) {
142
                bus = dev->bus->number;
143
                db_assert(bus != 0);
144
        } else {
145
                bus = 0;
146
        }
147
 
148
        slot_num = PCI_SLOT(dev->devfn);
149
        func_num = PCI_FUNC(dev->devfn);
150
        base = ddb_access_config_base(swap, bus, slot_num);
151
        *val = *(volatile u32*) (base + (func_num << 8) + where);
152
        ddb_close_config_base(swap);
153
        return PCIBIOS_SUCCESSFUL;
154
}
155
 
156
static int read_config_word(struct pci_config_swap *swap,
157
                            struct pci_dev *dev,
158
                            u32 where,
159
                            u16 *val)
160
{
161
        int status;
162
        u32 result;
163
 
164
        db_assert((where & 1) == 0);
165
 
166
        status = read_config_dword(swap, dev, where & ~3, &result);
167
        if (where & 2) result >>= 16;
168
        *val = result & 0xffff;
169
        return status;
170
}
171
 
172
static int read_config_byte(struct pci_config_swap *swap,
173
                            struct pci_dev *dev,
174
                            u32 where,
175
                            u8 *val)
176
{
177
        int status;
178
        u32 result;
179
 
180
        status = read_config_dword(swap, dev, where & ~3, &result);
181
        if (where & 1) result >>= 8;
182
        if (where & 2) result >>= 16;
183
        *val = result & 0xff;
184
        return status;
185
}
186
 
187
static int write_config_dword(struct pci_config_swap *swap,
188
                              struct pci_dev *dev,
189
                              u32 where,
190
                              u32 val)
191
{
192
        u32 bus, slot_num, func_num;
193
        u32 base;
194
 
195
        db_assert((where & 3) == 0);
196
        db_assert(where < (1 << 8));
197
 
198
        /* check if the bus is top-level */
199
        if (dev->bus->parent != NULL) {
200
                bus = dev->bus->number;
201
                db_assert(bus != 0);
202
        } else {
203
                bus = 0;
204
        }
205
 
206
        slot_num = PCI_SLOT(dev->devfn);
207
        func_num = PCI_FUNC(dev->devfn);
208
        base = ddb_access_config_base(swap, bus, slot_num);
209
        *(volatile u32*) (base + (func_num << 8) + where) = val;
210
        ddb_close_config_base(swap);
211
        return PCIBIOS_SUCCESSFUL;
212
}
213
 
214
static int write_config_word(struct pci_config_swap *swap,
215
                             struct pci_dev *dev,
216
                             u32 where,
217
                             u16 val)
218
{
219
        int status, shift=0;
220
        u32 result;
221
 
222
        db_assert((where & 1) == 0);
223
 
224
        status = read_config_dword(swap, dev, where & ~3, &result);
225
        if (status != PCIBIOS_SUCCESSFUL) return status;
226
 
227
        if (where & 2)
228
                shift += 16;
229
        result &= ~(0xffff << shift);
230
        result |= val << shift;
231
        return write_config_dword(swap, dev, where & ~3, result);
232
}
233
 
234
static int write_config_byte(struct pci_config_swap *swap,
235
                             struct pci_dev *dev,
236
                             u32 where,
237
                             u8 val)
238
{
239
        int status, shift=0;
240
        u32 result;
241
 
242
        status = read_config_dword(swap, dev, where & ~3, &result);
243
        if (status != PCIBIOS_SUCCESSFUL) return status;
244
 
245
        if (where & 2)
246
                shift += 16;
247
        if (where & 1)
248
                shift += 8;
249
        result &= ~(0xff << shift);
250
        result |= val << shift;
251
        return write_config_dword(swap, dev, where & ~3, result);
252
}
253
 
254
#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \
255
static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \
256
{ \
257
     return rw##_config_##unitname(pciswap, \
258
                                   dev, \
259
                                   where, \
260
                                   val); \
261
}
262
 
263
MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap)
264
MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap)
265
MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap)
266
 
267
MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap)
268
MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap)
269
MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap)
270
 
271
struct pci_ops ddb5476_ext_pci_ops ={
272
        extpci_read_config_byte,
273
        extpci_read_config_word,
274
        extpci_read_config_dword,
275
        extpci_write_config_byte,
276
        extpci_write_config_word,
277
        extpci_write_config_dword
278
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.