Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/pci/ops-rc32434.c
10817 views
1
/*
2
* BRIEF MODULE DESCRIPTION
3
* pci_ops for IDT EB434 board
4
*
5
* Copyright 2004 IDT Inc. ([email protected])
6
* Copyright 2006 Felix Fietkau <[email protected]>
7
*
8
* This program is free software; you can redistribute it and/or modify it
9
* under the terms of the GNU General Public License as published by the
10
* Free Software Foundation; either version 2 of the License, or (at your
11
* option) any later version.
12
*
13
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
14
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
16
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
19
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
*
24
* You should have received a copy of the GNU General Public License along
25
* with this program; if not, write to the Free Software Foundation, Inc.,
26
* 675 Mass Ave, Cambridge, MA 02139, USA.
27
*/
28
#include <linux/delay.h>
29
#include <linux/init.h>
30
#include <linux/io.h>
31
#include <linux/pci.h>
32
#include <linux/types.h>
33
34
#include <asm/cpu.h>
35
#include <asm/mach-rc32434/rc32434.h>
36
#include <asm/mach-rc32434/pci.h>
37
38
#define PCI_ACCESS_READ 0
39
#define PCI_ACCESS_WRITE 1
40
41
42
#define PCI_CFG_SET(bus, slot, func, off) \
43
(rc32434_pci->pcicfga = (0x80000000 | \
44
((bus) << 16) | ((slot)<<11) | \
45
((func)<<8) | (off)))
46
47
static inline int config_access(unsigned char access_type,
48
struct pci_bus *bus, unsigned int devfn,
49
unsigned char where, u32 *data)
50
{
51
unsigned int slot = PCI_SLOT(devfn);
52
u8 func = PCI_FUNC(devfn);
53
54
/* Setup address */
55
PCI_CFG_SET(bus->number, slot, func, where);
56
rc32434_sync();
57
58
if (access_type == PCI_ACCESS_WRITE)
59
rc32434_pci->pcicfgd = *data;
60
else
61
*data = rc32434_pci->pcicfgd;
62
63
rc32434_sync();
64
65
return 0;
66
}
67
68
69
/*
70
* We can't address 8 and 16 bit words directly. Instead we have to
71
* read/write a 32bit word and mask/modify the data we actually want.
72
*/
73
static int read_config_byte(struct pci_bus *bus, unsigned int devfn,
74
int where, u8 *val)
75
{
76
u32 data;
77
int ret;
78
79
ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
80
*val = (data >> ((where & 3) << 3)) & 0xff;
81
return ret;
82
}
83
84
static int read_config_word(struct pci_bus *bus, unsigned int devfn,
85
int where, u16 *val)
86
{
87
u32 data;
88
int ret;
89
90
ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
91
*val = (data >> ((where & 3) << 3)) & 0xffff;
92
return ret;
93
}
94
95
static int read_config_dword(struct pci_bus *bus, unsigned int devfn,
96
int where, u32 *val)
97
{
98
int ret;
99
int delay = 1;
100
101
/*
102
* Don't scan too far, else there will be errors with plugged in
103
* daughterboard (rb564).
104
*/
105
if (bus->number == 0 && PCI_SLOT(devfn) > 21)
106
return 0;
107
108
retry:
109
ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val);
110
111
/*
112
* Certain devices react delayed at device scan time, this
113
* gives them time to settle
114
*/
115
if (where == PCI_VENDOR_ID) {
116
if (ret == 0xffffffff || ret == 0x00000000 ||
117
ret == 0x0000ffff || ret == 0xffff0000) {
118
if (delay > 4)
119
return 0;
120
delay *= 2;
121
msleep(delay);
122
goto retry;
123
}
124
}
125
126
return ret;
127
}
128
129
static int
130
write_config_byte(struct pci_bus *bus, unsigned int devfn, int where,
131
u8 val)
132
{
133
u32 data = 0;
134
135
if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
136
return -1;
137
138
data = (data & ~(0xff << ((where & 3) << 3))) |
139
(val << ((where & 3) << 3));
140
141
if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
142
return -1;
143
144
return PCIBIOS_SUCCESSFUL;
145
}
146
147
148
static int
149
write_config_word(struct pci_bus *bus, unsigned int devfn, int where,
150
u16 val)
151
{
152
u32 data = 0;
153
154
if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
155
return -1;
156
157
data = (data & ~(0xffff << ((where & 3) << 3))) |
158
(val << ((where & 3) << 3));
159
160
if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
161
return -1;
162
163
164
return PCIBIOS_SUCCESSFUL;
165
}
166
167
168
static int
169
write_config_dword(struct pci_bus *bus, unsigned int devfn, int where,
170
u32 val)
171
{
172
if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val))
173
return -1;
174
175
return PCIBIOS_SUCCESSFUL;
176
}
177
178
static int pci_config_read(struct pci_bus *bus, unsigned int devfn,
179
int where, int size, u32 *val)
180
{
181
switch (size) {
182
case 1:
183
return read_config_byte(bus, devfn, where, (u8 *) val);
184
case 2:
185
return read_config_word(bus, devfn, where, (u16 *) val);
186
default:
187
return read_config_dword(bus, devfn, where, val);
188
}
189
}
190
191
static int pci_config_write(struct pci_bus *bus, unsigned int devfn,
192
int where, int size, u32 val)
193
{
194
switch (size) {
195
case 1:
196
return write_config_byte(bus, devfn, where, (u8) val);
197
case 2:
198
return write_config_word(bus, devfn, where, (u16) val);
199
default:
200
return write_config_dword(bus, devfn, where, val);
201
}
202
}
203
204
struct pci_ops rc32434_pci_ops = {
205
.read = pci_config_read,
206
.write = pci_config_write,
207
};
208
209