2 * Sonics Silicon Backplane PCI-Hostbus related functions.
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>
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.
15 * Licensed under the GNU/GPL. See COPYING for details.
18 #include <linux/ssb/ssb.h>
19 #include <linux/ssb/ssb_regs.h>
20 #include <linux/pci.h>
21 #include <linux/delay.h>
23 #include "ssb_private.h"
26 int ssb_pci_switch_coreidx(struct ssb_bus
*bus
, u8 coreidx
)
33 err
= pci_write_config_dword(bus
->host_pci
, SSB_BAR0_WIN
,
34 (coreidx
* SSB_CORE_SIZE
)
38 err
= pci_read_config_dword(bus
->host_pci
, SSB_BAR0_WIN
,
42 cur_core
= (cur_core
- SSB_ENUM_BASE
)
44 if (cur_core
== coreidx
)
47 if (attempts
++ > SSB_BAR0_MAX_RETRIES
)
53 ssb_printk(KERN_ERR PFX
"Failed to switch to core %u\n", coreidx
);
57 int ssb_pci_switch_core(struct ssb_bus
*bus
,
58 struct ssb_device
*dev
)
63 ssb_dprintk(KERN_INFO PFX
64 "Switching to %s core, index %d\n",
65 ssb_core_name(dev
->id
.coreid
),
68 spin_lock_irqsave(&bus
->bar_lock
, flags
);
69 err
= ssb_pci_switch_coreidx(bus
, dev
->core_index
);
71 bus
->mapped_device
= dev
;
72 spin_unlock_irqrestore(&bus
->bar_lock
, flags
);
77 int ssb_pci_xtal(struct ssb_bus
*bus
, u32 what
, int turn_on
)
80 u32 in
, out
, outenable
;
83 if (bus
->bustype
!= SSB_BUSTYPE_PCI
)
86 err
= pci_read_config_dword(bus
->host_pci
, SSB_GPIO_IN
, &in
);
89 err
= pci_read_config_dword(bus
->host_pci
, SSB_GPIO_OUT
, &out
);
92 err
= pci_read_config_dword(bus
->host_pci
, SSB_GPIO_OUT_ENABLE
, &outenable
);
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.
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
)
109 err
= pci_write_config_dword(bus
->host_pci
, SSB_GPIO_OUT
, out
);
112 err
= pci_write_config_dword(bus
->host_pci
, SSB_GPIO_OUT_ENABLE
,
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
);
128 err
= pci_read_config_word(bus
->host_pci
, PCI_STATUS
, &pci_status
);
131 pci_status
&= ~PCI_STATUS_SIG_TARGET_ABORT
;
132 err
= pci_write_config_word(bus
->host_pci
, PCI_STATUS
, pci_status
);
136 if (what
& SSB_GPIO_XTAL
) {
137 /* Turn the crystal off */
138 out
&= ~SSB_GPIO_XTAL
;
140 if (what
& SSB_GPIO_PLL
) {
141 /* Turn the PLL off */
144 err
= pci_write_config_dword(bus
->host_pci
, SSB_GPIO_OUT
, out
);
147 err
= pci_write_config_dword(bus
->host_pci
, SSB_GPIO_OUT_ENABLE
, outenable
);
156 printk(KERN_ERR PFX
"Error: ssb_pci_xtal() could not access PCI config space!\n");
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))
165 static inline u8
ssb_crc8(u8 crc
, u8 data
)
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,
202 return t
[crc
^ data
];
205 static u8
ssb_sprom_crc(const u16
*sprom
)
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);
214 crc
= ssb_crc8(crc
, sprom
[SPOFF(SSB_SPROM_REVISION
)] & 0x00FF);
220 static int sprom_check_crc(const u16
*sprom
)
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
)
235 static void sprom_do_read(struct ssb_bus
*bus
, u16
*sprom
)
239 for (i
= 0; i
< SSB_SPROMSIZE_WORDS
; i
++)
240 sprom
[i
] = readw(bus
->mmio
+ SSB_SPROM_BASE
+ (i
* 2));
243 static int sprom_do_write(struct ssb_bus
*bus
, const u16
*sprom
)
245 struct pci_dev
*pdev
= bus
->host_pci
;
249 ssb_printk(KERN_NOTICE PFX
"Writing SPROM. Do NOT turn off the power! Please stand by...\n");
250 err
= pci_read_config_dword(pdev
, SSB_SPROMCTL
, &spromctl
);
253 spromctl
|= SSB_SPROMCTL_WE
;
254 err
= pci_write_config_dword(pdev
, SSB_SPROMCTL
, spromctl
);
257 ssb_printk(KERN_NOTICE PFX
"[ 0%%");
259 for (i
= 0; i
< SSB_SPROMSIZE_WORDS
; i
++) {
260 if (i
== SSB_SPROMSIZE_WORDS
/ 4)
262 else if (i
== SSB_SPROMSIZE_WORDS
/ 2)
264 else if (i
== (SSB_SPROMSIZE_WORDS
/ 4) * 3)
268 writew(sprom
[i
], bus
->mmio
+ SSB_SPROM_BASE
+ (i
* 2));
272 err
= pci_read_config_dword(pdev
, SSB_SPROMCTL
, &spromctl
);
275 spromctl
&= ~SSB_SPROMCTL_WE
;
276 err
= pci_write_config_dword(pdev
, SSB_SPROMCTL
, spromctl
);
280 ssb_printk("100%% ]\n");
281 ssb_printk(KERN_NOTICE PFX
"SPROM written.\n");
285 ssb_printk(KERN_ERR PFX
"Could not access SPROM control register.\n");
289 static void sprom_extract_r1(struct ssb_sprom_r1
*out
, const u16
*in
)
294 SPEX(pci_spid
, SSB_SPROM1_SPID
, 0xFFFF, 0);
295 SPEX(pci_svid
, SSB_SPROM1_SVID
, 0xFFFF, 0);
296 SPEX(pci_pid
, SSB_SPROM1_PID
, 0xFFFF, 0);
297 for (i
= 0; i
< 3; i
++) {
298 v
= in
[SPOFF(SSB_SPROM1_IL0MAC
) + i
];
299 *(((u16
*)out
->il0mac
) + i
) = cpu_to_be16(v
);
301 for (i
= 0; i
< 3; i
++) {
302 v
= in
[SPOFF(SSB_SPROM1_ET0MAC
) + i
];
303 *(((u16
*)out
->et0mac
) + i
) = cpu_to_be16(v
);
305 for (i
= 0; i
< 3; i
++) {
306 v
= in
[SPOFF(SSB_SPROM1_ET1MAC
) + i
];
307 *(((u16
*)out
->et1mac
) + i
) = cpu_to_be16(v
);
309 SPEX(et0phyaddr
, SSB_SPROM1_ETHPHY
, SSB_SPROM1_ETHPHY_ET0A
, 0);
310 SPEX(et1phyaddr
, SSB_SPROM1_ETHPHY
, SSB_SPROM1_ETHPHY_ET1A
,
311 SSB_SPROM1_ETHPHY_ET1A_SHIFT
);
312 SPEX(et0mdcport
, SSB_SPROM1_ETHPHY
, SSB_SPROM1_ETHPHY_ET0M
, 14);
313 SPEX(et1mdcport
, SSB_SPROM1_ETHPHY
, SSB_SPROM1_ETHPHY_ET1M
, 15);
314 SPEX(board_rev
, SSB_SPROM1_BINF
, SSB_SPROM1_BINF_BREV
, 0);
315 SPEX(country_code
, SSB_SPROM1_BINF
, SSB_SPROM1_BINF_CCODE
,
316 SSB_SPROM1_BINF_CCODE_SHIFT
);
317 SPEX(antenna_a
, SSB_SPROM1_BINF
, SSB_SPROM1_BINF_ANTA
,
318 SSB_SPROM1_BINF_ANTA_SHIFT
);
319 SPEX(antenna_bg
, SSB_SPROM1_BINF
, SSB_SPROM1_BINF_ANTBG
,
320 SSB_SPROM1_BINF_ANTBG_SHIFT
);
321 SPEX(pa0b0
, SSB_SPROM1_PA0B0
, 0xFFFF, 0);
322 SPEX(pa0b1
, SSB_SPROM1_PA0B1
, 0xFFFF, 0);
323 SPEX(pa0b2
, SSB_SPROM1_PA0B2
, 0xFFFF, 0);
324 SPEX(pa1b0
, SSB_SPROM1_PA1B0
, 0xFFFF, 0);
325 SPEX(pa1b1
, SSB_SPROM1_PA1B1
, 0xFFFF, 0);
326 SPEX(pa1b2
, SSB_SPROM1_PA1B2
, 0xFFFF, 0);
327 SPEX(gpio0
, SSB_SPROM1_GPIOA
, SSB_SPROM1_GPIOA_P0
, 0);
328 SPEX(gpio1
, SSB_SPROM1_GPIOA
, SSB_SPROM1_GPIOA_P1
,
329 SSB_SPROM1_GPIOA_P1_SHIFT
);
330 SPEX(gpio2
, SSB_SPROM1_GPIOB
, SSB_SPROM1_GPIOB_P2
, 0);
331 SPEX(gpio3
, SSB_SPROM1_GPIOB
, SSB_SPROM1_GPIOB_P3
,
332 SSB_SPROM1_GPIOB_P3_SHIFT
);
333 SPEX(maxpwr_a
, SSB_SPROM1_MAXPWR
, SSB_SPROM1_MAXPWR_A
,
334 SSB_SPROM1_MAXPWR_A_SHIFT
);
335 SPEX(maxpwr_bg
, SSB_SPROM1_MAXPWR
, SSB_SPROM1_MAXPWR_BG
, 0);
336 SPEX(itssi_a
, SSB_SPROM1_ITSSI
, SSB_SPROM1_ITSSI_A
,
337 SSB_SPROM1_ITSSI_A_SHIFT
);
338 SPEX(itssi_bg
, SSB_SPROM1_ITSSI
, SSB_SPROM1_ITSSI_BG
, 0);
339 SPEX(boardflags_lo
, SSB_SPROM1_BFLLO
, 0xFFFF, 0);
340 SPEX(antenna_gain_a
, SSB_SPROM1_AGAIN
, SSB_SPROM1_AGAIN_A
, 0);
341 SPEX(antenna_gain_bg
, SSB_SPROM1_AGAIN
, SSB_SPROM1_AGAIN_BG
,
342 SSB_SPROM1_AGAIN_BG_SHIFT
);
343 for (i
= 0; i
< 4; i
++) {
344 v
= in
[SPOFF(SSB_SPROM1_OEM
) + i
];
345 *(((u16
*)out
->oem
) + i
) = cpu_to_le16(v
);
349 static void sprom_extract_r2(struct ssb_sprom_r2
*out
, const u16
*in
)
354 SPEX(boardflags_hi
, SSB_SPROM2_BFLHI
, 0xFFFF, 0);
355 SPEX(maxpwr_a_hi
, SSB_SPROM2_MAXP_A
, SSB_SPROM2_MAXP_A_HI
, 0);
356 SPEX(maxpwr_a_lo
, SSB_SPROM2_MAXP_A
, SSB_SPROM2_MAXP_A_LO
,
357 SSB_SPROM2_MAXP_A_LO_SHIFT
);
358 SPEX(pa1lob0
, SSB_SPROM2_PA1LOB0
, 0xFFFF, 0);
359 SPEX(pa1lob1
, SSB_SPROM2_PA1LOB1
, 0xFFFF, 0);
360 SPEX(pa1lob2
, SSB_SPROM2_PA1LOB2
, 0xFFFF, 0);
361 SPEX(pa1hib0
, SSB_SPROM2_PA1HIB0
, 0xFFFF, 0);
362 SPEX(pa1hib1
, SSB_SPROM2_PA1HIB1
, 0xFFFF, 0);
363 SPEX(pa1hib2
, SSB_SPROM2_PA1HIB2
, 0xFFFF, 0);
364 SPEX(ofdm_pwr_off
, SSB_SPROM2_OPO
, SSB_SPROM2_OPO_VALUE
, 0);
365 for (i
= 0; i
< 4; i
++) {
366 v
= in
[SPOFF(SSB_SPROM2_CCODE
) + i
];
367 *(((u16
*)out
->country_str
) + i
) = cpu_to_le16(v
);
371 static void sprom_extract_r3(struct ssb_sprom_r3
*out
, const u16
*in
)
373 out
->ofdmapo
= (in
[SPOFF(SSB_SPROM3_OFDMAPO
) + 0] & 0xFF00) >> 8;
374 out
->ofdmapo
|= (in
[SPOFF(SSB_SPROM3_OFDMAPO
) + 0] & 0x00FF) << 8;
376 out
->ofdmapo
|= (in
[SPOFF(SSB_SPROM3_OFDMAPO
) + 1] & 0xFF00) >> 8;
377 out
->ofdmapo
|= (in
[SPOFF(SSB_SPROM3_OFDMAPO
) + 1] & 0x00FF) << 8;
379 out
->ofdmalpo
= (in
[SPOFF(SSB_SPROM3_OFDMALPO
) + 0] & 0xFF00) >> 8;
380 out
->ofdmalpo
|= (in
[SPOFF(SSB_SPROM3_OFDMALPO
) + 0] & 0x00FF) << 8;
381 out
->ofdmalpo
<<= 16;
382 out
->ofdmalpo
|= (in
[SPOFF(SSB_SPROM3_OFDMALPO
) + 1] & 0xFF00) >> 8;
383 out
->ofdmalpo
|= (in
[SPOFF(SSB_SPROM3_OFDMALPO
) + 1] & 0x00FF) << 8;
385 out
->ofdmahpo
= (in
[SPOFF(SSB_SPROM3_OFDMAHPO
) + 0] & 0xFF00) >> 8;
386 out
->ofdmahpo
|= (in
[SPOFF(SSB_SPROM3_OFDMAHPO
) + 0] & 0x00FF) << 8;
387 out
->ofdmahpo
<<= 16;
388 out
->ofdmahpo
|= (in
[SPOFF(SSB_SPROM3_OFDMAHPO
) + 1] & 0xFF00) >> 8;
389 out
->ofdmahpo
|= (in
[SPOFF(SSB_SPROM3_OFDMAHPO
) + 1] & 0x00FF) << 8;
391 SPEX(gpioldc_on_cnt
, SSB_SPROM3_GPIOLDC
, SSB_SPROM3_GPIOLDC_ON
,
392 SSB_SPROM3_GPIOLDC_ON_SHIFT
);
393 SPEX(gpioldc_off_cnt
, SSB_SPROM3_GPIOLDC
, SSB_SPROM3_GPIOLDC_OFF
,
394 SSB_SPROM3_GPIOLDC_OFF_SHIFT
);
395 SPEX(cckpo_1M
, SSB_SPROM3_CCKPO
, SSB_SPROM3_CCKPO_1M
, 0);
396 SPEX(cckpo_2M
, SSB_SPROM3_CCKPO
, SSB_SPROM3_CCKPO_2M
,
397 SSB_SPROM3_CCKPO_2M_SHIFT
);
398 SPEX(cckpo_55M
, SSB_SPROM3_CCKPO
, SSB_SPROM3_CCKPO_55M
,
399 SSB_SPROM3_CCKPO_55M_SHIFT
);
400 SPEX(cckpo_11M
, SSB_SPROM3_CCKPO
, SSB_SPROM3_CCKPO_11M
,
401 SSB_SPROM3_CCKPO_11M_SHIFT
);
403 out
->ofdmgpo
= (in
[SPOFF(SSB_SPROM3_OFDMGPO
) + 0] & 0xFF00) >> 8;
404 out
->ofdmgpo
|= (in
[SPOFF(SSB_SPROM3_OFDMGPO
) + 0] & 0x00FF) << 8;
406 out
->ofdmgpo
|= (in
[SPOFF(SSB_SPROM3_OFDMGPO
) + 1] & 0xFF00) >> 8;
407 out
->ofdmgpo
|= (in
[SPOFF(SSB_SPROM3_OFDMGPO
) + 1] & 0x00FF) << 8;
410 static int sprom_extract(struct ssb_bus
*bus
,
411 struct ssb_sprom
*out
, const u16
*in
)
413 memset(out
, 0, sizeof(*out
));
415 SPEX(revision
, SSB_SPROM_REVISION
, SSB_SPROM_REVISION_REV
, 0);
416 SPEX(crc
, SSB_SPROM_REVISION
, SSB_SPROM_REVISION_CRC
,
417 SSB_SPROM_REVISION_CRC_SHIFT
);
419 if ((bus
->chip_id
& 0xFF00) == 0x4400) {
420 /* Workaround: The BCM44XX chip has a stupid revision
421 * number stored in the SPROM.
422 * Always extract r1. */
423 sprom_extract_r1(&out
->r1
, in
);
425 if (out
->revision
== 0)
427 if (out
->revision
>= 1 && out
->revision
<= 3)
428 sprom_extract_r1(&out
->r1
, in
);
429 if (out
->revision
>= 2 && out
->revision
<= 3)
430 sprom_extract_r2(&out
->r2
, in
);
431 if (out
->revision
== 3)
432 sprom_extract_r3(&out
->r3
, in
);
433 if (out
->revision
>= 4)
439 ssb_printk(KERN_WARNING PFX
"Unsupported SPROM revision %d "
440 "detected. Will extract v1\n", out
->revision
);
441 sprom_extract_r1(&out
->r1
, in
);
445 static int ssb_pci_sprom_get(struct ssb_bus
*bus
,
446 struct ssb_sprom
*sprom
)
451 buf
= kcalloc(SSB_SPROMSIZE_WORDS
, sizeof(u16
), GFP_KERNEL
);
454 sprom_do_read(bus
, buf
);
455 err
= sprom_check_crc(buf
);
457 ssb_printk(KERN_WARNING PFX
458 "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
460 err
= sprom_extract(bus
, sprom
, buf
);
467 static void ssb_pci_get_boardinfo(struct ssb_bus
*bus
,
468 struct ssb_boardinfo
*bi
)
470 pci_read_config_word(bus
->host_pci
, PCI_SUBSYSTEM_VENDOR_ID
,
472 pci_read_config_word(bus
->host_pci
, PCI_SUBSYSTEM_ID
,
474 pci_read_config_word(bus
->host_pci
, PCI_REVISION_ID
,
478 int ssb_pci_get_invariants(struct ssb_bus
*bus
,
479 struct ssb_init_invariants
*iv
)
483 err
= ssb_pci_sprom_get(bus
, &iv
->sprom
);
486 ssb_pci_get_boardinfo(bus
, &iv
->boardinfo
);
492 static u16
ssb_pci_read16(struct ssb_device
*dev
, u16 offset
)
494 struct ssb_bus
*bus
= dev
->bus
;
496 if (unlikely(bus
->mapped_device
!= dev
)) {
497 if (unlikely(ssb_pci_switch_core(bus
, dev
)))
500 return readw(bus
->mmio
+ offset
);
503 static u32
ssb_pci_read32(struct ssb_device
*dev
, u16 offset
)
505 struct ssb_bus
*bus
= dev
->bus
;
507 if (unlikely(bus
->mapped_device
!= dev
)) {
508 if (unlikely(ssb_pci_switch_core(bus
, dev
)))
511 return readl(bus
->mmio
+ offset
);
514 static void ssb_pci_write16(struct ssb_device
*dev
, u16 offset
, u16 value
)
516 struct ssb_bus
*bus
= dev
->bus
;
518 if (unlikely(bus
->mapped_device
!= dev
)) {
519 if (unlikely(ssb_pci_switch_core(bus
, dev
)))
522 writew(value
, bus
->mmio
+ offset
);
525 static void ssb_pci_write32(struct ssb_device
*dev
, u16 offset
, u32 value
)
527 struct ssb_bus
*bus
= dev
->bus
;
529 if (unlikely(bus
->mapped_device
!= dev
)) {
530 if (unlikely(ssb_pci_switch_core(bus
, dev
)))
533 writel(value
, bus
->mmio
+ offset
);
536 const struct ssb_bus_ops ssb_pci_ops
= {
537 .read16
= ssb_pci_read16
,
538 .read32
= ssb_pci_read32
,
539 .write16
= ssb_pci_write16
,
540 .write32
= ssb_pci_write32
,
543 static int sprom2hex(const u16
*sprom
, char *buf
, size_t buf_len
)
547 for (i
= 0; i
< SSB_SPROMSIZE_WORDS
; i
++) {
548 pos
+= snprintf(buf
+ pos
, buf_len
- pos
- 1,
549 "%04X", swab16(sprom
[i
]) & 0xFFFF);
551 pos
+= snprintf(buf
+ pos
, buf_len
- pos
- 1, "\n");
556 static int hex2sprom(u16
*sprom
, const char *dump
, size_t len
)
560 unsigned long parsed
;
562 if (len
< SSB_SPROMSIZE_BYTES
* 2)
565 while (cnt
< SSB_SPROMSIZE_WORDS
) {
566 memcpy(tmp
, dump
, 4);
568 parsed
= simple_strtoul(tmp
, NULL
, 16);
569 sprom
[cnt
++] = swab16((u16
)parsed
);
575 static ssize_t
ssb_pci_attr_sprom_show(struct device
*pcidev
,
576 struct device_attribute
*attr
,
579 struct pci_dev
*pdev
= container_of(pcidev
, struct pci_dev
, dev
);
585 bus
= ssb_pci_dev_to_bus(pdev
);
589 sprom
= kcalloc(SSB_SPROMSIZE_WORDS
, sizeof(u16
), GFP_KERNEL
);
594 if (mutex_lock_interruptible(&bus
->pci_sprom_mutex
))
596 sprom_do_read(bus
, sprom
);
597 mutex_unlock(&bus
->pci_sprom_mutex
);
599 count
= sprom2hex(sprom
, buf
, PAGE_SIZE
);
605 return err
? err
: count
;
608 static ssize_t
ssb_pci_attr_sprom_store(struct device
*pcidev
,
609 struct device_attribute
*attr
,
610 const char *buf
, size_t count
)
612 struct pci_dev
*pdev
= container_of(pcidev
, struct pci_dev
, dev
);
615 int res
= 0, err
= -ENODEV
;
617 bus
= ssb_pci_dev_to_bus(pdev
);
621 sprom
= kcalloc(SSB_SPROMSIZE_WORDS
, sizeof(u16
), GFP_KERNEL
);
624 err
= hex2sprom(sprom
, buf
, count
);
629 err
= sprom_check_crc(sprom
);
636 if (mutex_lock_interruptible(&bus
->pci_sprom_mutex
))
638 err
= ssb_devices_freeze(bus
);
640 ssb_printk(KERN_ERR PFX
"SPROM write: Could not freeze all devices\n");
643 res
= sprom_do_write(bus
, sprom
);
644 err
= ssb_devices_thaw(bus
);
646 ssb_printk(KERN_ERR PFX
"SPROM write: Could not thaw all devices\n");
648 mutex_unlock(&bus
->pci_sprom_mutex
);
654 return err
? err
: count
;
657 static DEVICE_ATTR(ssb_sprom
, 0600,
658 ssb_pci_attr_sprom_show
,
659 ssb_pci_attr_sprom_store
);
661 void ssb_pci_exit(struct ssb_bus
*bus
)
663 struct pci_dev
*pdev
;
665 if (bus
->bustype
!= SSB_BUSTYPE_PCI
)
668 pdev
= bus
->host_pci
;
669 device_remove_file(&pdev
->dev
, &dev_attr_ssb_sprom
);
672 int ssb_pci_init(struct ssb_bus
*bus
)
674 struct pci_dev
*pdev
;
677 if (bus
->bustype
!= SSB_BUSTYPE_PCI
)
680 pdev
= bus
->host_pci
;
681 mutex_init(&bus
->pci_sprom_mutex
);
682 err
= device_create_file(&pdev
->dev
, &dev_attr_ssb_sprom
);