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 void sprom_extract_r1(struct ssb_sprom_r1
*out
, const u16
*in
)
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
);
255 for (i
= 0; i
< 3; i
++) {
256 v
= in
[SPOFF(SSB_SPROM1_ET0MAC
) + i
];
257 *(((u16
*)out
->et0mac
) + i
) = cpu_to_be16(v
);
259 for (i
= 0; i
< 3; i
++) {
260 v
= in
[SPOFF(SSB_SPROM1_ET1MAC
) + i
];
261 *(((u16
*)out
->et1mac
) + i
) = cpu_to_be16(v
);
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
);
303 static void sprom_extract_r2(struct ssb_sprom_r2
*out
, const u16
*in
)
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
);
325 static void sprom_extract_r3(struct ssb_sprom_r3
*out
, const u16
*in
)
327 out
->ofdmapo
= (in
[SPOFF(SSB_SPROM3_OFDMAPO
) + 0] & 0xFF00) >> 8;
328 out
->ofdmapo
|= (in
[SPOFF(SSB_SPROM3_OFDMAPO
) + 0] & 0x00FF) << 8;
330 out
->ofdmapo
|= (in
[SPOFF(SSB_SPROM3_OFDMAPO
) + 1] & 0xFF00) >> 8;
331 out
->ofdmapo
|= (in
[SPOFF(SSB_SPROM3_OFDMAPO
) + 1] & 0x00FF) << 8;
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;
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;
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
);
357 out
->ofdmgpo
= (in
[SPOFF(SSB_SPROM3_OFDMGPO
) + 0] & 0xFF00) >> 8;
358 out
->ofdmgpo
|= (in
[SPOFF(SSB_SPROM3_OFDMGPO
) + 0] & 0x00FF) << 8;
360 out
->ofdmgpo
|= (in
[SPOFF(SSB_SPROM3_OFDMGPO
) + 1] & 0xFF00) >> 8;
361 out
->ofdmgpo
|= (in
[SPOFF(SSB_SPROM3_OFDMGPO
) + 1] & 0x00FF) << 8;
364 static int sprom_extract(struct ssb_sprom
*out
, const u16
*in
)
366 memset(out
, 0, sizeof(*out
));
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
);
372 if (out
->revision
== 0)
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)
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
);
391 int ssb_pci_sprom_get(struct ssb_bus
*bus
)
396 assert(bus
->bustype
== SSB_BUSTYPE_PCI
);
398 buf
= kcalloc(SSB_SPROMSIZE_WORDS
, sizeof(u16
), GFP_KERNEL
);
401 sprom_do_read(bus
, buf
);
402 err
= sprom_check_crc(buf
);
404 ssb_printk(KERN_WARNING PFX
405 "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
407 err
= sprom_extract(&bus
->sprom
, buf
);
414 void ssb_pci_get_boardtype(struct ssb_bus
*bus
)
416 pci_read_config_word(bus
->host_pci
, PCI_SUBSYSTEM_VENDOR_ID
,
418 pci_read_config_word(bus
->host_pci
, PCI_SUBSYSTEM_ID
,
420 pci_read_config_word(bus
->host_pci
, PCI_REVISION_ID
,
424 static u16
ssb_pci_read16(struct ssb_device
*dev
, u16 offset
)
426 struct ssb_bus
*bus
= dev
->bus
;
428 if (unlikely(bus
->mapped_device
!= dev
)) {
429 if (unlikely(ssb_pci_switch_core(bus
, dev
)))
432 return readw(bus
->mmio
+ offset
);
435 static u32
ssb_pci_read32(struct ssb_device
*dev
, u16 offset
)
437 struct ssb_bus
*bus
= dev
->bus
;
439 if (unlikely(bus
->mapped_device
!= dev
)) {
440 if (unlikely(ssb_pci_switch_core(bus
, dev
)))
443 return readl(bus
->mmio
+ offset
);
446 static void ssb_pci_write16(struct ssb_device
*dev
, u16 offset
, u16 value
)
448 struct ssb_bus
*bus
= dev
->bus
;
450 if (unlikely(bus
->mapped_device
!= dev
)) {
451 if (unlikely(ssb_pci_switch_core(bus
, dev
)))
454 writew(value
, bus
->mmio
+ offset
);
457 static void ssb_pci_write32(struct ssb_device
*dev
, u16 offset
, u32 value
)
459 struct ssb_bus
*bus
= dev
->bus
;
461 if (unlikely(bus
->mapped_device
!= dev
)) {
462 if (unlikely(ssb_pci_switch_core(bus
, dev
)))
465 writel(value
, bus
->mmio
+ offset
);
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
,
475 int ssb_pci_init(struct ssb_bus
*bus
)
477 if (bus
->bustype
!= SSB_BUSTYPE_PCI
)
479 return ssb_pci_sprom_get(bus
);