Commit | Line | Data |
---|---|---|
4b3d6953 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
91d8037f | 2 | /* |
91d8037f DB |
3 | * Copyright(c) 2010 Intel Corporation. All rights reserved. |
4 | * | |
91d8037f DB |
5 | * Contact Information: |
6 | * Intel Corporation | |
7 | * 2200 Mission College Blvd. | |
8 | * Santa Clara, CA 97052 | |
9 | * | |
10 | * This provides access methods for PCI registers that mis-behave on | |
11 | * the CE4100. Each register can be assigned a private init, read and | |
12 | * write routine. The exception to this is the bridge device. The | |
13 | * bridge device is the only device on bus zero (0) that requires any | |
14 | * fixup so it is a special case ATM | |
15 | */ | |
16 | ||
17 | #include <linux/kernel.h> | |
18 | #include <linux/pci.h> | |
19 | #include <linux/init.h> | |
20 | ||
03150171 | 21 | #include <asm/ce4100.h> |
91d8037f DB |
22 | #include <asm/pci_x86.h> |
23 | ||
24 | struct sim_reg { | |
25 | u32 value; | |
26 | u32 mask; | |
27 | }; | |
28 | ||
29 | struct sim_dev_reg { | |
30 | int dev_func; | |
31 | int reg; | |
32 | void (*init)(struct sim_dev_reg *reg); | |
33 | void (*read)(struct sim_dev_reg *reg, u32 *value); | |
34 | void (*write)(struct sim_dev_reg *reg, u32 value); | |
35 | struct sim_reg sim_reg; | |
36 | }; | |
37 | ||
91d8037f DB |
38 | #define MB (1024 * 1024) |
39 | #define KB (1024) | |
40 | #define SIZE_TO_MASK(size) (~(size - 1)) | |
41 | ||
42 | #define DEFINE_REG(device, func, offset, size, init_op, read_op, write_op)\ | |
43 | { PCI_DEVFN(device, func), offset, init_op, read_op, write_op,\ | |
44 | {0, SIZE_TO_MASK(size)} }, | |
45 | ||
bb290fda TG |
46 | /* |
47 | * All read/write functions are called with pci_config_lock held. | |
48 | */ | |
91d8037f DB |
49 | static void reg_init(struct sim_dev_reg *reg) |
50 | { | |
51 | pci_direct_conf1.read(0, 1, reg->dev_func, reg->reg, 4, | |
52 | ®->sim_reg.value); | |
53 | } | |
54 | ||
55 | static void reg_read(struct sim_dev_reg *reg, u32 *value) | |
56 | { | |
91d8037f | 57 | *value = reg->sim_reg.value; |
91d8037f DB |
58 | } |
59 | ||
60 | static void reg_write(struct sim_dev_reg *reg, u32 value) | |
61 | { | |
91d8037f DB |
62 | reg->sim_reg.value = (value & reg->sim_reg.mask) | |
63 | (reg->sim_reg.value & ~reg->sim_reg.mask); | |
91d8037f DB |
64 | } |
65 | ||
66 | static void sata_reg_init(struct sim_dev_reg *reg) | |
67 | { | |
68 | pci_direct_conf1.read(0, 1, PCI_DEVFN(14, 0), 0x10, 4, | |
69 | ®->sim_reg.value); | |
70 | reg->sim_reg.value += 0x400; | |
71 | } | |
72 | ||
73 | static void ehci_reg_read(struct sim_dev_reg *reg, u32 *value) | |
74 | { | |
75 | reg_read(reg, value); | |
76 | if (*value != reg->sim_reg.mask) | |
77 | *value |= 0x100; | |
78 | } | |
79 | ||
0253b04d | 80 | static void sata_revid_init(struct sim_dev_reg *reg) |
91d8037f DB |
81 | { |
82 | reg->sim_reg.value = 0x01060100; | |
83 | reg->sim_reg.mask = 0; | |
84 | } | |
85 | ||
86 | static void sata_revid_read(struct sim_dev_reg *reg, u32 *value) | |
87 | { | |
88 | reg_read(reg, value); | |
89 | } | |
90 | ||
37aeec36 MB |
91 | static void reg_noirq_read(struct sim_dev_reg *reg, u32 *value) |
92 | { | |
37aeec36 MB |
93 | /* force interrupt pin value to 0 */ |
94 | *value = reg->sim_reg.value & 0xfff00ff; | |
37aeec36 MB |
95 | } |
96 | ||
91d8037f DB |
97 | static struct sim_dev_reg bus1_fixups[] = { |
98 | DEFINE_REG(2, 0, 0x10, (16*MB), reg_init, reg_read, reg_write) | |
99 | DEFINE_REG(2, 0, 0x14, (256), reg_init, reg_read, reg_write) | |
100 | DEFINE_REG(2, 1, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
101 | DEFINE_REG(3, 0, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
102 | DEFINE_REG(4, 0, 0x10, (128*KB), reg_init, reg_read, reg_write) | |
103 | DEFINE_REG(4, 1, 0x10, (128*KB), reg_init, reg_read, reg_write) | |
104 | DEFINE_REG(6, 0, 0x10, (512*KB), reg_init, reg_read, reg_write) | |
105 | DEFINE_REG(6, 1, 0x10, (512*KB), reg_init, reg_read, reg_write) | |
106 | DEFINE_REG(6, 2, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
107 | DEFINE_REG(8, 0, 0x10, (1*MB), reg_init, reg_read, reg_write) | |
108 | DEFINE_REG(8, 1, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
109 | DEFINE_REG(8, 2, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
110 | DEFINE_REG(9, 0, 0x10 , (1*MB), reg_init, reg_read, reg_write) | |
111 | DEFINE_REG(9, 0, 0x14, (64*KB), reg_init, reg_read, reg_write) | |
112 | DEFINE_REG(10, 0, 0x10, (256), reg_init, reg_read, reg_write) | |
113 | DEFINE_REG(10, 0, 0x14, (256*MB), reg_init, reg_read, reg_write) | |
114 | DEFINE_REG(11, 0, 0x10, (256), reg_init, reg_read, reg_write) | |
115 | DEFINE_REG(11, 0, 0x14, (256), reg_init, reg_read, reg_write) | |
116 | DEFINE_REG(11, 1, 0x10, (256), reg_init, reg_read, reg_write) | |
117 | DEFINE_REG(11, 2, 0x10, (256), reg_init, reg_read, reg_write) | |
118 | DEFINE_REG(11, 2, 0x14, (256), reg_init, reg_read, reg_write) | |
119 | DEFINE_REG(11, 2, 0x18, (256), reg_init, reg_read, reg_write) | |
120 | DEFINE_REG(11, 3, 0x10, (256), reg_init, reg_read, reg_write) | |
121 | DEFINE_REG(11, 3, 0x14, (256), reg_init, reg_read, reg_write) | |
122 | DEFINE_REG(11, 4, 0x10, (256), reg_init, reg_read, reg_write) | |
123 | DEFINE_REG(11, 5, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
124 | DEFINE_REG(11, 6, 0x10, (256), reg_init, reg_read, reg_write) | |
125 | DEFINE_REG(11, 7, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
37aeec36 | 126 | DEFINE_REG(11, 7, 0x3c, 256, reg_init, reg_noirq_read, reg_write) |
91d8037f DB |
127 | DEFINE_REG(12, 0, 0x10, (128*KB), reg_init, reg_read, reg_write) |
128 | DEFINE_REG(12, 0, 0x14, (256), reg_init, reg_read, reg_write) | |
129 | DEFINE_REG(12, 1, 0x10, (1024), reg_init, reg_read, reg_write) | |
130 | DEFINE_REG(13, 0, 0x10, (32*KB), reg_init, ehci_reg_read, reg_write) | |
131 | DEFINE_REG(13, 1, 0x10, (32*KB), reg_init, ehci_reg_read, reg_write) | |
132 | DEFINE_REG(14, 0, 0x8, 0, sata_revid_init, sata_revid_read, 0) | |
133 | DEFINE_REG(14, 0, 0x10, 0, reg_init, reg_read, reg_write) | |
134 | DEFINE_REG(14, 0, 0x14, 0, reg_init, reg_read, reg_write) | |
135 | DEFINE_REG(14, 0, 0x18, 0, reg_init, reg_read, reg_write) | |
136 | DEFINE_REG(14, 0, 0x1C, 0, reg_init, reg_read, reg_write) | |
137 | DEFINE_REG(14, 0, 0x20, 0, reg_init, reg_read, reg_write) | |
138 | DEFINE_REG(14, 0, 0x24, (0x200), sata_reg_init, reg_read, reg_write) | |
139 | DEFINE_REG(15, 0, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
140 | DEFINE_REG(15, 0, 0x14, (64*KB), reg_init, reg_read, reg_write) | |
141 | DEFINE_REG(16, 0, 0x10, (64*KB), reg_init, reg_read, reg_write) | |
142 | DEFINE_REG(16, 0, 0x14, (64*MB), reg_init, reg_read, reg_write) | |
143 | DEFINE_REG(16, 0, 0x18, (64*MB), reg_init, reg_read, reg_write) | |
37aeec36 | 144 | DEFINE_REG(16, 0, 0x3c, 256, reg_init, reg_noirq_read, reg_write) |
91d8037f DB |
145 | DEFINE_REG(17, 0, 0x10, (128*KB), reg_init, reg_read, reg_write) |
146 | DEFINE_REG(18, 0, 0x10, (1*KB), reg_init, reg_read, reg_write) | |
37aeec36 | 147 | DEFINE_REG(18, 0, 0x3c, 256, reg_init, reg_noirq_read, reg_write) |
91d8037f DB |
148 | }; |
149 | ||
150 | static void __init init_sim_regs(void) | |
151 | { | |
152 | int i; | |
153 | ||
154 | for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { | |
155 | if (bus1_fixups[i].init) | |
156 | bus1_fixups[i].init(&bus1_fixups[i]); | |
157 | } | |
158 | } | |
159 | ||
160 | static inline void extract_bytes(u32 *value, int reg, int len) | |
161 | { | |
162 | uint32_t mask; | |
163 | ||
164 | *value >>= ((reg & 3) * 8); | |
165 | mask = 0xFFFFFFFF >> ((4 - len) * 8); | |
166 | *value &= mask; | |
167 | } | |
168 | ||
0253b04d | 169 | static int bridge_read(unsigned int devfn, int reg, int len, u32 *value) |
91d8037f DB |
170 | { |
171 | u32 av_bridge_base, av_bridge_limit; | |
172 | int retval = 0; | |
173 | ||
174 | switch (reg) { | |
175 | /* Make BARs appear to not request any memory. */ | |
176 | case PCI_BASE_ADDRESS_0: | |
177 | case PCI_BASE_ADDRESS_0 + 1: | |
178 | case PCI_BASE_ADDRESS_0 + 2: | |
179 | case PCI_BASE_ADDRESS_0 + 3: | |
180 | *value = 0; | |
181 | break; | |
182 | ||
183 | /* Since subordinate bus number register is hardwired | |
184 | * to zero and read only, so do the simulation. | |
185 | */ | |
186 | case PCI_PRIMARY_BUS: | |
187 | if (len == 4) | |
188 | *value = 0x00010100; | |
189 | break; | |
190 | ||
191 | case PCI_SUBORDINATE_BUS: | |
192 | *value = 1; | |
193 | break; | |
194 | ||
195 | case PCI_MEMORY_BASE: | |
196 | case PCI_MEMORY_LIMIT: | |
197 | /* Get the A/V bridge base address. */ | |
198 | pci_direct_conf1.read(0, 0, devfn, | |
199 | PCI_BASE_ADDRESS_0, 4, &av_bridge_base); | |
200 | ||
201 | av_bridge_limit = av_bridge_base + (512*MB - 1); | |
202 | av_bridge_limit >>= 16; | |
203 | av_bridge_limit &= 0xFFF0; | |
204 | ||
205 | av_bridge_base >>= 16; | |
206 | av_bridge_base &= 0xFFF0; | |
207 | ||
208 | if (reg == PCI_MEMORY_LIMIT) | |
209 | *value = av_bridge_limit; | |
210 | else if (len == 2) | |
211 | *value = av_bridge_base; | |
212 | else | |
213 | *value = (av_bridge_limit << 16) | av_bridge_base; | |
214 | break; | |
215 | /* Make prefetchable memory limit smaller than prefetchable | |
216 | * memory base, so not claim prefetchable memory space. | |
217 | */ | |
218 | case PCI_PREF_MEMORY_BASE: | |
219 | *value = 0xFFF0; | |
220 | break; | |
221 | case PCI_PREF_MEMORY_LIMIT: | |
222 | *value = 0x0; | |
223 | break; | |
224 | /* Make IO limit smaller than IO base, so not claim IO space. */ | |
225 | case PCI_IO_BASE: | |
226 | *value = 0xF0; | |
227 | break; | |
228 | case PCI_IO_LIMIT: | |
229 | *value = 0; | |
230 | break; | |
231 | default: | |
232 | retval = 1; | |
233 | } | |
234 | return retval; | |
235 | } | |
236 | ||
bb290fda | 237 | static int ce4100_bus1_read(unsigned int devfn, int reg, int len, u32 *value) |
91d8037f | 238 | { |
bb290fda | 239 | unsigned long flags; |
13884c66 | 240 | int i; |
91d8037f | 241 | |
bb290fda TG |
242 | for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { |
243 | if (bus1_fixups[i].dev_func == devfn && | |
244 | bus1_fixups[i].reg == (reg & ~3) && | |
245 | bus1_fixups[i].read) { | |
246 | ||
247 | raw_spin_lock_irqsave(&pci_config_lock, flags); | |
248 | bus1_fixups[i].read(&(bus1_fixups[i]), value); | |
249 | raw_spin_unlock_irqrestore(&pci_config_lock, flags); | |
250 | extract_bytes(value, reg, len); | |
251 | return 0; | |
91d8037f DB |
252 | } |
253 | } | |
bb290fda TG |
254 | return -1; |
255 | } | |
256 | ||
257 | static int ce4100_conf_read(unsigned int seg, unsigned int bus, | |
258 | unsigned int devfn, int reg, int len, u32 *value) | |
259 | { | |
260 | WARN_ON(seg); | |
261 | ||
262 | if (bus == 1 && !ce4100_bus1_read(devfn, reg, len, value)) | |
263 | return 0; | |
91d8037f DB |
264 | |
265 | if (bus == 0 && (PCI_DEVFN(1, 0) == devfn) && | |
266 | !bridge_read(devfn, reg, len, value)) | |
267 | return 0; | |
268 | ||
269 | return pci_direct_conf1.read(seg, bus, devfn, reg, len, value); | |
270 | } | |
271 | ||
bb290fda | 272 | static int ce4100_bus1_write(unsigned int devfn, int reg, int len, u32 value) |
91d8037f | 273 | { |
bb290fda | 274 | unsigned long flags; |
91d8037f DB |
275 | int i; |
276 | ||
bb290fda TG |
277 | for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { |
278 | if (bus1_fixups[i].dev_func == devfn && | |
279 | bus1_fixups[i].reg == (reg & ~3) && | |
280 | bus1_fixups[i].write) { | |
281 | ||
282 | raw_spin_lock_irqsave(&pci_config_lock, flags); | |
283 | bus1_fixups[i].write(&(bus1_fixups[i]), value); | |
284 | raw_spin_unlock_irqrestore(&pci_config_lock, flags); | |
285 | return 0; | |
91d8037f DB |
286 | } |
287 | } | |
bb290fda TG |
288 | return -1; |
289 | } | |
290 | ||
291 | static int ce4100_conf_write(unsigned int seg, unsigned int bus, | |
292 | unsigned int devfn, int reg, int len, u32 value) | |
293 | { | |
294 | WARN_ON(seg); | |
295 | ||
296 | if (bus == 1 && !ce4100_bus1_write(devfn, reg, len, value)) | |
297 | return 0; | |
91d8037f DB |
298 | |
299 | /* Discard writes to A/V bridge BAR. */ | |
300 | if (bus == 0 && PCI_DEVFN(1, 0) == devfn && | |
301 | ((reg & ~3) == PCI_BASE_ADDRESS_0)) | |
302 | return 0; | |
303 | ||
304 | return pci_direct_conf1.write(seg, bus, devfn, reg, len, value); | |
305 | } | |
306 | ||
72da0b07 | 307 | static const struct pci_raw_ops ce4100_pci_conf = { |
bb290fda TG |
308 | .read = ce4100_conf_read, |
309 | .write = ce4100_conf_write, | |
91d8037f DB |
310 | }; |
311 | ||
03150171 | 312 | int __init ce4100_pci_init(void) |
91d8037f DB |
313 | { |
314 | init_sim_regs(); | |
315 | raw_pci_ops = &ce4100_pci_conf; | |
03150171 SAS |
316 | /* Indicate caller that it should invoke pci_legacy_init() */ |
317 | return 1; | |
91d8037f | 318 | } |