update work in progress rewritten bcm947xx code. wifi and usb seem to be working...
[openwrt/staging/chunkeey.git] / target / linux / brcm47xx-2.6 / files / drivers / ssb / pci.c
1 /*
2 * Sonics Silicon Backplane PCI-Hostbus related functions.
3 *
4 * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
5 * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
6 * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
7 * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
8 * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
9 *
10 * Derived from the Broadcom 4400 device driver.
11 * Copyright (C) 2002 David S. Miller (davem@redhat.com)
12 * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
13 * Copyright (C) 2006 Broadcom Corporation.
14 *
15 * Licensed under the GNU/GPL. See COPYING for details.
16 */
17
18 #include <linux/ssb/ssb.h>
19 #include <linux/ssb/ssb_regs.h>
20 #include <linux/pci.h>
21 #include <linux/delay.h>
22
23 #include "ssb_private.h"
24
25
26 int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
27 {
28 int err;
29 int attempts = 0;
30 u32 cur_core;
31
32 while (1) {
33 err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
34 (coreidx * SSB_CORE_SIZE)
35 + SSB_ENUM_BASE);
36 if (err)
37 goto error;
38 err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
39 &cur_core);
40 if (err)
41 goto error;
42 cur_core = (cur_core - SSB_ENUM_BASE)
43 / SSB_CORE_SIZE;
44 if (cur_core == coreidx)
45 break;
46
47 if (attempts++ > SSB_BAR0_MAX_RETRIES)
48 goto error;
49 udelay(10);
50 }
51 return 0;
52 error:
53 ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
54 return -ENODEV;
55 }
56
57 int ssb_pci_switch_core(struct ssb_bus *bus,
58 struct ssb_device *dev)
59 {
60 int err;
61 unsigned long flags;
62
63 ssb_dprintk(KERN_INFO PFX
64 "Switching to %s core, index %d\n",
65 ssb_core_name(dev->id.coreid),
66 dev->core_index);
67
68 spin_lock_irqsave(&bus->bar_lock, flags);
69 err = ssb_pci_switch_coreidx(bus, dev->core_index);
70 if (!err)
71 bus->mapped_device = dev;
72 spin_unlock_irqrestore(&bus->bar_lock, flags);
73
74 return err;
75 }
76
77 int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
78 {
79 int err;
80 u32 in, out, outenable;
81 u16 pci_status;
82
83 if (bus->bustype != SSB_BUSTYPE_PCI)
84 return 0;
85
86 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
87 if (err)
88 goto err_pci;
89 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
90 if (err)
91 goto err_pci;
92 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
93 if (err)
94 goto err_pci;
95
96 outenable |= what;
97
98 if (turn_on) {
99 /* Avoid glitching the clock if GPRS is already using it.
100 * We can't actually read the state of the PLLPD so we infer it
101 * by the value of XTAL_PU which *is* readable via gpioin.
102 */
103 if (!(in & SSB_GPIO_XTAL)) {
104 if (what & SSB_GPIO_XTAL) {
105 /* Turn the crystal on */
106 out |= SSB_GPIO_XTAL;
107 if (what & SSB_GPIO_PLL)
108 out |= SSB_GPIO_PLL;
109 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
110 if (err)
111 goto err_pci;
112 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
113 outenable);
114 if (err)
115 goto err_pci;
116 msleep(1);
117 }
118 if (what & SSB_GPIO_PLL) {
119 /* Turn the PLL on */
120 out &= ~SSB_GPIO_PLL;
121 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
122 if (err)
123 goto err_pci;
124 msleep(2);
125 }
126 }
127
128 err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
129 if (err)
130 goto err_pci;
131 pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
132 err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
133 if (err)
134 goto err_pci;
135 } else {
136 if (what & SSB_GPIO_XTAL) {
137 /* Turn the crystal off */
138 out &= ~SSB_GPIO_XTAL;
139 }
140 if (what & SSB_GPIO_PLL) {
141 /* Turn the PLL off */
142 out |= SSB_GPIO_PLL;
143 }
144 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
145 if (err)
146 goto err_pci;
147 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
148 if (err)
149 goto err_pci;
150 }
151
152 out:
153 return err;
154
155 err_pci:
156 printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
157 err = -EBUSY;
158 goto out;
159 }
160
161 #define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16))
162 #define SPEX(_outvar, _offset, _mask, _shift) \
163 out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
164
165 static inline u8 ssb_crc8(u8 crc, u8 data)
166 {
167 /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
168 static const u8 t[] = {
169 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
170 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
171 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
172 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
173 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
174 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
175 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
176 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
177 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
178 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
179 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
180 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
181 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
182 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
183 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
184 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
185 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
186 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
187 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
188 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
189 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
190 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
191 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
192 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
193 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
194 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
195 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
196 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
197 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
198 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
199 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
200 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
201 };
202 return t[crc ^ data];
203 }
204
205 static u8 ssb_sprom_crc(const u16 *sprom)
206 {
207 int word;
208 u8 crc = 0xFF;
209
210 for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
211 crc = ssb_crc8(crc, sprom[word] & 0x00FF);
212 crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
213 }
214 crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
215 crc ^= 0xFF;
216
217 return crc;
218 }
219
220 static int sprom_check_crc(const u16 *sprom)
221 {
222 u8 crc;
223 u8 expected_crc;
224 u16 tmp;
225
226 crc = ssb_sprom_crc(sprom);
227 tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
228 expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
229 if (crc != expected_crc)
230 return -EPROTO;
231
232 return 0;
233 }
234
235 static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
236 {
237 int i;
238
239 for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
240 sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
241 }
242
243 static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
244 {
245 int i;
246 u16 v;
247
248 SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
249 SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
250 SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
251 for (i = 0; i < 3; i++) {
252 v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
253 *(((u16 *)out->il0mac) + i) = cpu_to_be16(v);
254 }
255 for (i = 0; i < 3; i++) {
256 v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
257 *(((u16 *)out->et0mac) + i) = cpu_to_be16(v);
258 }
259 for (i = 0; i < 3; i++) {
260 v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
261 *(((u16 *)out->et1mac) + i) = cpu_to_be16(v);
262 }
263 SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
264 SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
265 SSB_SPROM1_ETHPHY_ET1A_SHIFT);
266 SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
267 SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
268 SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
269 SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
270 SSB_SPROM1_BINF_CCODE_SHIFT);
271 SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
272 SSB_SPROM1_BINF_ANTA_SHIFT);
273 SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
274 SSB_SPROM1_BINF_ANTBG_SHIFT);
275 SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
276 SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
277 SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
278 SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
279 SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
280 SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
281 SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
282 SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
283 SSB_SPROM1_GPIOA_P1_SHIFT);
284 SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
285 SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
286 SSB_SPROM1_GPIOB_P3_SHIFT);
287 SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, 0);
288 SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG,
289 SSB_SPROM1_MAXPWR_BG_SHIFT);
290 SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, 0);
291 SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG,
292 SSB_SPROM1_ITSSI_BG_SHIFT);
293 SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
294 SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
295 SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
296 SSB_SPROM1_AGAIN_BG_SHIFT);
297 for (i = 0; i < 4; i++) {
298 v = in[SPOFF(SSB_SPROM1_OEM) + i];
299 *(((u16 *)out->oem) + i) = cpu_to_le16(v);
300 }
301 }
302
303 static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
304 {
305 int i;
306 u16 v;
307
308 SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
309 SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
310 SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
311 SSB_SPROM2_MAXP_A_LO_SHIFT);
312 SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
313 SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
314 SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
315 SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
316 SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
317 SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
318 SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
319 for (i = 0; i < 4; i++) {
320 v = in[SPOFF(SSB_SPROM2_CCODE) + i];
321 *(((u16 *)out->country_str) + i) = cpu_to_le16(v);
322 }
323 }
324
325 static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
326 {
327 out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
328 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
329 out->ofdmapo <<= 16;
330 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
331 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
332
333 out->ofdmalpo = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
334 out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
335 out->ofdmalpo <<= 16;
336 out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
337 out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
338
339 out->ofdmahpo = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
340 out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
341 out->ofdmahpo <<= 16;
342 out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
343 out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
344
345 SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
346 SSB_SPROM3_GPIOLDC_ON_SHIFT);
347 SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
348 SSB_SPROM3_GPIOLDC_OFF_SHIFT);
349 SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
350 SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
351 SSB_SPROM3_CCKPO_2M_SHIFT);
352 SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
353 SSB_SPROM3_CCKPO_55M_SHIFT);
354 SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
355 SSB_SPROM3_CCKPO_11M_SHIFT);
356
357 out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
358 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
359 out->ofdmgpo <<= 16;
360 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
361 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
362 }
363
364 static int sprom_extract(struct ssb_sprom *out, const u16 *in)
365 {
366 memset(out, 0, sizeof(*out));
367
368 SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
369 SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
370 SSB_SPROM_REVISION_CRC_SHIFT);
371
372 if (out->revision == 0)
373 goto unsupported;
374 if (out->revision >= 1 && out->revision <= 3)
375 sprom_extract_r1(&out->r1, in);
376 if (out->revision >= 2 && out->revision <= 3)
377 sprom_extract_r2(&out->r2, in);
378 if (out->revision == 3)
379 sprom_extract_r3(&out->r3, in);
380 if (out->revision >= 4)
381 goto unsupported;
382
383 return 0;
384 unsupported:
385 ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
386 "detected. Will extract v1\n", out->revision);
387 sprom_extract_r1(&out->r1, in);
388 return 0;
389 }
390
391 int ssb_pci_sprom_get(struct ssb_bus *bus)
392 {
393 int err = -ENOMEM;
394 u16 *buf;
395
396 assert(bus->bustype == SSB_BUSTYPE_PCI);
397
398 buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
399 if (!buf)
400 goto out;
401 sprom_do_read(bus, buf);
402 err = sprom_check_crc(buf);
403 if (err) {
404 ssb_printk(KERN_WARNING PFX
405 "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
406 }
407 err = sprom_extract(&bus->sprom, buf);
408
409 kfree(buf);
410 out:
411 return err;
412 }
413
414 void ssb_pci_get_boardtype(struct ssb_bus *bus)
415 {
416 pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
417 &bus->board_vendor);
418 pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
419 &bus->board_type);
420 pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
421 &bus->board_rev);
422 }
423
424 static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
425 {
426 struct ssb_bus *bus = dev->bus;
427
428 if (unlikely(bus->mapped_device != dev)) {
429 if (unlikely(ssb_pci_switch_core(bus, dev)))
430 return 0xFFFF;
431 }
432 return readw(bus->mmio + offset);
433 }
434
435 static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
436 {
437 struct ssb_bus *bus = dev->bus;
438
439 if (unlikely(bus->mapped_device != dev)) {
440 if (unlikely(ssb_pci_switch_core(bus, dev)))
441 return 0xFFFFFFFF;
442 }
443 return readl(bus->mmio + offset);
444 }
445
446 static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
447 {
448 struct ssb_bus *bus = dev->bus;
449
450 if (unlikely(bus->mapped_device != dev)) {
451 if (unlikely(ssb_pci_switch_core(bus, dev)))
452 return;
453 }
454 writew(value, bus->mmio + offset);
455 }
456
457 static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
458 {
459 struct ssb_bus *bus = dev->bus;
460
461 if (unlikely(bus->mapped_device != dev)) {
462 if (unlikely(ssb_pci_switch_core(bus, dev)))
463 return;
464 }
465 writel(value, bus->mmio + offset);
466 }
467
468 const struct ssb_bus_ops ssb_pci_ops = {
469 .read16 = ssb_pci_read16,
470 .read32 = ssb_pci_read32,
471 .write16 = ssb_pci_write16,
472 .write32 = ssb_pci_write32,
473 };
474
475 int ssb_pci_init(struct ssb_bus *bus)
476 {
477 if (bus->bustype != SSB_BUSTYPE_PCI)
478 return 0;
479 return ssb_pci_sprom_get(bus);
480 }