update work in progress rewritten bcm947xx code. wifi and usb seem to be working...
[librecmc/librecmc.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 }