blob: 8f600fcd24308b38f1c029bac53211df632d00a0 [file] [log] [blame]
Michael Buesch61e115a2007-09-18 15:12:50 -04001/*
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/* Define the following to 1 to enable a printk on each coreswitch. */
27#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
28
29
30/* Lowlevel coreswitching */
31int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
32{
33 int err;
34 int attempts = 0;
35 u32 cur_core;
36
37 while (1) {
38 err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
39 (coreidx * SSB_CORE_SIZE)
40 + SSB_ENUM_BASE);
41 if (err)
42 goto error;
43 err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
44 &cur_core);
45 if (err)
46 goto error;
47 cur_core = (cur_core - SSB_ENUM_BASE)
48 / SSB_CORE_SIZE;
49 if (cur_core == coreidx)
50 break;
51
52 if (attempts++ > SSB_BAR0_MAX_RETRIES)
53 goto error;
54 udelay(10);
55 }
56 return 0;
57error:
58 ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
59 return -ENODEV;
60}
61
62int ssb_pci_switch_core(struct ssb_bus *bus,
63 struct ssb_device *dev)
64{
65 int err;
66 unsigned long flags;
67
68#if SSB_VERBOSE_PCICORESWITCH_DEBUG
69 ssb_printk(KERN_INFO PFX
70 "Switching to %s core, index %d\n",
71 ssb_core_name(dev->id.coreid),
72 dev->core_index);
73#endif
74
75 spin_lock_irqsave(&bus->bar_lock, flags);
76 err = ssb_pci_switch_coreidx(bus, dev->core_index);
77 if (!err)
78 bus->mapped_device = dev;
79 spin_unlock_irqrestore(&bus->bar_lock, flags);
80
81 return err;
82}
83
84/* Enable/disable the on board crystal oscillator and/or PLL. */
85int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
86{
87 int err;
88 u32 in, out, outenable;
89 u16 pci_status;
90
91 if (bus->bustype != SSB_BUSTYPE_PCI)
92 return 0;
93
94 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
95 if (err)
96 goto err_pci;
97 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
98 if (err)
99 goto err_pci;
100 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
101 if (err)
102 goto err_pci;
103
104 outenable |= what;
105
106 if (turn_on) {
107 /* Avoid glitching the clock if GPRS is already using it.
108 * We can't actually read the state of the PLLPD so we infer it
109 * by the value of XTAL_PU which *is* readable via gpioin.
110 */
111 if (!(in & SSB_GPIO_XTAL)) {
112 if (what & SSB_GPIO_XTAL) {
113 /* Turn the crystal on */
114 out |= SSB_GPIO_XTAL;
115 if (what & SSB_GPIO_PLL)
116 out |= SSB_GPIO_PLL;
117 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
118 if (err)
119 goto err_pci;
120 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
121 outenable);
122 if (err)
123 goto err_pci;
124 msleep(1);
125 }
126 if (what & SSB_GPIO_PLL) {
127 /* Turn the PLL on */
128 out &= ~SSB_GPIO_PLL;
129 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
130 if (err)
131 goto err_pci;
132 msleep(5);
133 }
134 }
135
136 err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
137 if (err)
138 goto err_pci;
139 pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
140 err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
141 if (err)
142 goto err_pci;
143 } else {
144 if (what & SSB_GPIO_XTAL) {
145 /* Turn the crystal off */
146 out &= ~SSB_GPIO_XTAL;
147 }
148 if (what & SSB_GPIO_PLL) {
149 /* Turn the PLL off */
150 out |= SSB_GPIO_PLL;
151 }
152 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
153 if (err)
154 goto err_pci;
155 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
156 if (err)
157 goto err_pci;
158 }
159
160out:
161 return err;
162
163err_pci:
164 printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
165 err = -EBUSY;
166 goto out;
167}
168
169/* Get the word-offset for a SSB_SPROM_XXX define. */
170#define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16))
171/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
172#define SPEX(_outvar, _offset, _mask, _shift) \
173 out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
174
175static inline u8 ssb_crc8(u8 crc, u8 data)
176{
177 /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
178 static const u8 t[] = {
179 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
180 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
181 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
182 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
183 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
184 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
185 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
186 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
187 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
188 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
189 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
190 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
191 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
192 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
193 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
194 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
195 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
196 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
197 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
198 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
199 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
200 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
201 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
202 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
203 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
204 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
205 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
206 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
207 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
208 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
209 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
210 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
211 };
212 return t[crc ^ data];
213}
214
Larry Fingerc272ef42007-11-09 16:56:25 -0600215static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
Michael Buesch61e115a2007-09-18 15:12:50 -0400216{
217 int word;
218 u8 crc = 0xFF;
219
Larry Fingerc272ef42007-11-09 16:56:25 -0600220 for (word = 0; word < size - 1; word++) {
Michael Buesch61e115a2007-09-18 15:12:50 -0400221 crc = ssb_crc8(crc, sprom[word] & 0x00FF);
222 crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
223 }
Larry Fingerc272ef42007-11-09 16:56:25 -0600224 crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
Michael Buesch61e115a2007-09-18 15:12:50 -0400225 crc ^= 0xFF;
226
227 return crc;
228}
229
Larry Fingerc272ef42007-11-09 16:56:25 -0600230static int sprom_check_crc(const u16 *sprom, u16 size)
Michael Buesch61e115a2007-09-18 15:12:50 -0400231{
232 u8 crc;
233 u8 expected_crc;
234 u16 tmp;
235
Larry Fingerc272ef42007-11-09 16:56:25 -0600236 crc = ssb_sprom_crc(sprom, size);
237 tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
Michael Buesch61e115a2007-09-18 15:12:50 -0400238 expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
239 if (crc != expected_crc)
240 return -EPROTO;
241
242 return 0;
243}
244
245static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
246{
247 int i;
248
Larry Fingerc272ef42007-11-09 16:56:25 -0600249 for (i = 0; i < bus->sprom_size; i++)
Michael Buesch61e115a2007-09-18 15:12:50 -0400250 sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
251}
252
253static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
254{
255 struct pci_dev *pdev = bus->host_pci;
256 int i, err;
257 u32 spromctl;
Larry Fingerc272ef42007-11-09 16:56:25 -0600258 u16 size = bus->sprom_size;
Michael Buesch61e115a2007-09-18 15:12:50 -0400259
260 ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
261 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
262 if (err)
263 goto err_ctlreg;
264 spromctl |= SSB_SPROMCTL_WE;
265 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
266 if (err)
267 goto err_ctlreg;
268 ssb_printk(KERN_NOTICE PFX "[ 0%%");
269 msleep(500);
Larry Fingerc272ef42007-11-09 16:56:25 -0600270 for (i = 0; i < size; i++) {
271 if (i == size / 4)
Michael Buesch61e115a2007-09-18 15:12:50 -0400272 ssb_printk("25%%");
Larry Fingerc272ef42007-11-09 16:56:25 -0600273 else if (i == size / 2)
Michael Buesch61e115a2007-09-18 15:12:50 -0400274 ssb_printk("50%%");
Larry Fingerc272ef42007-11-09 16:56:25 -0600275 else if (i == (size * 3) / 4)
Michael Buesch61e115a2007-09-18 15:12:50 -0400276 ssb_printk("75%%");
277 else if (i % 2)
278 ssb_printk(".");
279 writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
280 mmiowb();
281 msleep(20);
282 }
283 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
284 if (err)
285 goto err_ctlreg;
286 spromctl &= ~SSB_SPROMCTL_WE;
287 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
288 if (err)
289 goto err_ctlreg;
290 msleep(500);
291 ssb_printk("100%% ]\n");
292 ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
293
294 return 0;
295err_ctlreg:
296 ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
297 return err;
298}
299
300static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
301{
302 int i;
303 u16 v;
304
305 SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
306 SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
307 SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
308 for (i = 0; i < 3; i++) {
309 v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
Michael Buesch6b9bafe2007-09-19 18:55:12 +0200310 *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
Michael Buesch61e115a2007-09-18 15:12:50 -0400311 }
312 for (i = 0; i < 3; i++) {
313 v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
Michael Buesch6b9bafe2007-09-19 18:55:12 +0200314 *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
Michael Buesch61e115a2007-09-18 15:12:50 -0400315 }
316 for (i = 0; i < 3; i++) {
317 v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
Michael Buesch6b9bafe2007-09-19 18:55:12 +0200318 *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
Michael Buesch61e115a2007-09-18 15:12:50 -0400319 }
320 SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
321 SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
322 SSB_SPROM1_ETHPHY_ET1A_SHIFT);
323 SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
324 SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
325 SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
326 SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
327 SSB_SPROM1_BINF_CCODE_SHIFT);
328 SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
329 SSB_SPROM1_BINF_ANTA_SHIFT);
330 SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
331 SSB_SPROM1_BINF_ANTBG_SHIFT);
332 SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
333 SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
334 SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
335 SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
336 SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
337 SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
338 SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
339 SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
340 SSB_SPROM1_GPIOA_P1_SHIFT);
341 SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
342 SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
343 SSB_SPROM1_GPIOB_P3_SHIFT);
344 SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
345 SSB_SPROM1_MAXPWR_A_SHIFT);
346 SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
347 SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
348 SSB_SPROM1_ITSSI_A_SHIFT);
349 SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
350 SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
351 SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
352 SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
353 SSB_SPROM1_AGAIN_BG_SHIFT);
Michael Buesch61e115a2007-09-18 15:12:50 -0400354}
355
Larry Fingerc272ef42007-11-09 16:56:25 -0600356static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
357{
358 int i;
359 u16 v;
360 u16 loc[3];
361
362 if (out->revision == 3) { /* rev 3 moved MAC */
363 loc[0] = SSB_SPROM3_IL0MAC;
364 loc[1] = SSB_SPROM3_ET0MAC;
365 loc[2] = SSB_SPROM3_ET1MAC;
366 } else {
367 loc[0] = SSB_SPROM1_IL0MAC;
368 loc[1] = SSB_SPROM1_ET0MAC;
369 loc[2] = SSB_SPROM1_ET1MAC;
370 }
371 for (i = 0; i < 3; i++) {
372 v = in[SPOFF(loc[0]) + i];
373 *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
374 }
375 for (i = 0; i < 3; i++) {
376 v = in[SPOFF(loc[1]) + i];
377 *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
378 }
379 for (i = 0; i < 3; i++) {
380 v = in[SPOFF(loc[2]) + i];
381 *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
382 }
383 SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
384 SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
385 SSB_SPROM1_ETHPHY_ET1A_SHIFT);
386 SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
387 SSB_SPROM1_BINF_CCODE_SHIFT);
388 SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
389 SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
390 SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
391 SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
392 SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
393 SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
394 SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
395 SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
396 SSB_SPROM1_GPIOA_P1_SHIFT);
397 SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
398 SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
399 SSB_SPROM1_GPIOB_P3_SHIFT);
400 SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
401 SSB_SPROM1_MAXPWR_A_SHIFT);
402 SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
403 SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
404 SSB_SPROM1_ITSSI_A_SHIFT);
405 SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
406 SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
407 SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
408 SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
409 SSB_SPROM1_AGAIN_BG_SHIFT);
410}
411
412static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
Michael Buesch61e115a2007-09-18 15:12:50 -0400413{
414 int i;
415 u16 v;
416
Larry Fingerc272ef42007-11-09 16:56:25 -0600417 /* extract the r1 variables */
418 for (i = 0; i < 3; i++) {
419 v = in[SPOFF(SSB_SPROM4_IL0MAC) + i];
420 *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
Michael Buesch61e115a2007-09-18 15:12:50 -0400421 }
Larry Fingerc272ef42007-11-09 16:56:25 -0600422 for (i = 0; i < 3; i++) {
423 v = in[SPOFF(SSB_SPROM4_ET0MAC) + i];
424 *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
425 }
426 for (i = 0; i < 3; i++) {
427 v = in[SPOFF(SSB_SPROM4_ET1MAC) + i];
428 *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
429 }
430 SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
431 SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
432 SSB_SPROM4_ETHPHY_ET1A_SHIFT);
433 SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
434 SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
435 SPEX(antenna_gain_a, SSB_SPROM4_AGAIN, SSB_SPROM4_AGAIN_0, 0);
436 SPEX(antenna_gain_bg, SSB_SPROM4_AGAIN, SSB_SPROM4_AGAIN_1,
437 SSB_SPROM4_AGAIN_1_SHIFT);
438 /* TODO - get remaining rev 4 stuff needed */
Michael Buesch61e115a2007-09-18 15:12:50 -0400439}
440
Larry Fingerc272ef42007-11-09 16:56:25 -0600441static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
442 const u16 *in, u16 size)
Michael Buesch61e115a2007-09-18 15:12:50 -0400443{
444 memset(out, 0, sizeof(*out));
445
Larry Fingerc272ef42007-11-09 16:56:25 -0600446 out->revision = in[size - 1] & 0x00FF;
Michael Buesch61e115a2007-09-18 15:12:50 -0400447 if ((bus->chip_id & 0xFF00) == 0x4400) {
448 /* Workaround: The BCM44XX chip has a stupid revision
449 * number stored in the SPROM.
450 * Always extract r1. */
Larry Fingerc272ef42007-11-09 16:56:25 -0600451 out->revision = 1;
452 sprom_extract_r123(out, in);
Michael Buesch61e115a2007-09-18 15:12:50 -0400453 sprom_extract_r1(&out->r1, in);
Larry Fingerc272ef42007-11-09 16:56:25 -0600454 } else if (bus->chip_id == 0x4321) {
455 /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
456 out->revision = 4;
457 sprom_extract_r4(out, in);
Michael Buesch61e115a2007-09-18 15:12:50 -0400458 } else {
459 if (out->revision == 0)
460 goto unsupported;
Larry Fingerc272ef42007-11-09 16:56:25 -0600461 if (out->revision >= 1 && out->revision <= 3) {
462 sprom_extract_r123(out, in);
Michael Buesch61e115a2007-09-18 15:12:50 -0400463 sprom_extract_r1(&out->r1, in);
Larry Fingerc272ef42007-11-09 16:56:25 -0600464 }
465 if (out->revision == 4)
466 sprom_extract_r4(out, in);
467 if (out->revision >= 5)
Michael Buesch61e115a2007-09-18 15:12:50 -0400468 goto unsupported;
469 }
470
471 return 0;
472unsupported:
473 ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
474 "detected. Will extract v1\n", out->revision);
475 sprom_extract_r1(&out->r1, in);
476 return 0;
477}
478
479static int ssb_pci_sprom_get(struct ssb_bus *bus,
480 struct ssb_sprom *sprom)
481{
482 int err = -ENOMEM;
483 u16 *buf;
484
Larry Fingerc272ef42007-11-09 16:56:25 -0600485 buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
Michael Buesch61e115a2007-09-18 15:12:50 -0400486 if (!buf)
487 goto out;
Larry Fingerc272ef42007-11-09 16:56:25 -0600488 bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
Michael Buesch61e115a2007-09-18 15:12:50 -0400489 sprom_do_read(bus, buf);
Larry Fingerc272ef42007-11-09 16:56:25 -0600490 err = sprom_check_crc(buf, bus->sprom_size);
Michael Buesch61e115a2007-09-18 15:12:50 -0400491 if (err) {
Larry Fingerc272ef42007-11-09 16:56:25 -0600492 /* check for rev 4 sprom - has special signature */
493 if (buf [32] == 0x5372) {
494 ssb_printk(KERN_WARNING PFX "Extracting a rev 4"
495 " SPROM\n");
496 kfree(buf);
497 buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
498 GFP_KERNEL);
499 if (!buf)
500 goto out;
501 bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
502 sprom_do_read(bus, buf);
503 err = sprom_check_crc(buf, bus->sprom_size);
504 }
505 if (err)
506 ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
507 " SPROM CRC (corrupt SPROM)\n");
Michael Buesch61e115a2007-09-18 15:12:50 -0400508 }
Larry Fingerc272ef42007-11-09 16:56:25 -0600509 err = sprom_extract(bus, sprom, buf, bus->sprom_size);
Michael Buesch61e115a2007-09-18 15:12:50 -0400510
511 kfree(buf);
512out:
513 return err;
514}
515
516static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
517 struct ssb_boardinfo *bi)
518{
519 pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
520 &bi->vendor);
521 pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
522 &bi->type);
523 pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
524 &bi->rev);
525}
526
527int ssb_pci_get_invariants(struct ssb_bus *bus,
528 struct ssb_init_invariants *iv)
529{
530 int err;
531
532 err = ssb_pci_sprom_get(bus, &iv->sprom);
533 if (err)
534 goto out;
535 ssb_pci_get_boardinfo(bus, &iv->boardinfo);
536
537out:
538 return err;
539}
540
541#ifdef CONFIG_SSB_DEBUG
542static int ssb_pci_assert_buspower(struct ssb_bus *bus)
543{
544 if (likely(bus->powered_up))
545 return 0;
546
547 printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
548 "while accessing PCI MMIO space\n");
549 if (bus->power_warn_count <= 10) {
550 bus->power_warn_count++;
551 dump_stack();
552 }
553
554 return -ENODEV;
555}
556#else /* DEBUG */
557static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
558{
559 return 0;
560}
561#endif /* DEBUG */
562
563static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
564{
565 struct ssb_bus *bus = dev->bus;
566
567 if (unlikely(ssb_pci_assert_buspower(bus)))
568 return 0xFFFF;
569 if (unlikely(bus->mapped_device != dev)) {
570 if (unlikely(ssb_pci_switch_core(bus, dev)))
571 return 0xFFFF;
572 }
Michael Buesch4b402c62007-09-19 18:53:44 +0200573 return ioread16(bus->mmio + offset);
Michael Buesch61e115a2007-09-18 15:12:50 -0400574}
575
576static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
577{
578 struct ssb_bus *bus = dev->bus;
579
580 if (unlikely(ssb_pci_assert_buspower(bus)))
581 return 0xFFFFFFFF;
582 if (unlikely(bus->mapped_device != dev)) {
583 if (unlikely(ssb_pci_switch_core(bus, dev)))
584 return 0xFFFFFFFF;
585 }
Michael Buesch4b402c62007-09-19 18:53:44 +0200586 return ioread32(bus->mmio + offset);
Michael Buesch61e115a2007-09-18 15:12:50 -0400587}
588
589static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
590{
591 struct ssb_bus *bus = dev->bus;
592
593 if (unlikely(ssb_pci_assert_buspower(bus)))
594 return;
595 if (unlikely(bus->mapped_device != dev)) {
596 if (unlikely(ssb_pci_switch_core(bus, dev)))
597 return;
598 }
Michael Buesch4b402c62007-09-19 18:53:44 +0200599 iowrite16(value, bus->mmio + offset);
Michael Buesch61e115a2007-09-18 15:12:50 -0400600}
601
602static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
603{
604 struct ssb_bus *bus = dev->bus;
605
606 if (unlikely(ssb_pci_assert_buspower(bus)))
607 return;
608 if (unlikely(bus->mapped_device != dev)) {
609 if (unlikely(ssb_pci_switch_core(bus, dev)))
610 return;
611 }
Michael Buesch4b402c62007-09-19 18:53:44 +0200612 iowrite32(value, bus->mmio + offset);
Michael Buesch61e115a2007-09-18 15:12:50 -0400613}
614
615/* Not "static", as it's used in main.c */
616const struct ssb_bus_ops ssb_pci_ops = {
617 .read16 = ssb_pci_read16,
618 .read32 = ssb_pci_read32,
619 .write16 = ssb_pci_write16,
620 .write32 = ssb_pci_write32,
621};
622
Larry Fingerc272ef42007-11-09 16:56:25 -0600623static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size)
Michael Buesch61e115a2007-09-18 15:12:50 -0400624{
625 int i, pos = 0;
626
Larry Fingerc272ef42007-11-09 16:56:25 -0600627 for (i = 0; i < size; i++)
Michael Buesch61e115a2007-09-18 15:12:50 -0400628 pos += snprintf(buf + pos, buf_len - pos - 1,
629 "%04X", swab16(sprom[i]) & 0xFFFF);
Michael Buesch61e115a2007-09-18 15:12:50 -0400630 pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
631
632 return pos + 1;
633}
634
Larry Fingerc272ef42007-11-09 16:56:25 -0600635static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size)
Michael Buesch61e115a2007-09-18 15:12:50 -0400636{
637 char tmp[5] = { 0 };
638 int cnt = 0;
639 unsigned long parsed;
640
Larry Fingerc272ef42007-11-09 16:56:25 -0600641 if (len < size * 2)
Michael Buesch61e115a2007-09-18 15:12:50 -0400642 return -EINVAL;
643
Larry Fingerc272ef42007-11-09 16:56:25 -0600644 while (cnt < size) {
Michael Buesch61e115a2007-09-18 15:12:50 -0400645 memcpy(tmp, dump, 4);
646 dump += 4;
647 parsed = simple_strtoul(tmp, NULL, 16);
648 sprom[cnt++] = swab16((u16)parsed);
649 }
650
651 return 0;
652}
653
654static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
655 struct device_attribute *attr,
656 char *buf)
657{
658 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
659 struct ssb_bus *bus;
660 u16 *sprom;
661 int err = -ENODEV;
662 ssize_t count = 0;
663
664 bus = ssb_pci_dev_to_bus(pdev);
665 if (!bus)
666 goto out;
667 err = -ENOMEM;
Larry Fingerc272ef42007-11-09 16:56:25 -0600668 sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
Michael Buesch61e115a2007-09-18 15:12:50 -0400669 if (!sprom)
670 goto out;
671
672 /* Use interruptible locking, as the SPROM write might
673 * be holding the lock for several seconds. So allow userspace
674 * to cancel operation. */
675 err = -ERESTARTSYS;
676 if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
677 goto out_kfree;
678 sprom_do_read(bus, sprom);
679 mutex_unlock(&bus->pci_sprom_mutex);
680
Larry Fingerc272ef42007-11-09 16:56:25 -0600681 count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size);
Michael Buesch61e115a2007-09-18 15:12:50 -0400682 err = 0;
683
684out_kfree:
685 kfree(sprom);
686out:
687 return err ? err : count;
688}
689
690static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
691 struct device_attribute *attr,
692 const char *buf, size_t count)
693{
694 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
695 struct ssb_bus *bus;
696 u16 *sprom;
697 int res = 0, err = -ENODEV;
698
699 bus = ssb_pci_dev_to_bus(pdev);
700 if (!bus)
701 goto out;
702 err = -ENOMEM;
Larry Fingerc272ef42007-11-09 16:56:25 -0600703 sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
Michael Buesch61e115a2007-09-18 15:12:50 -0400704 if (!sprom)
705 goto out;
Larry Fingerc272ef42007-11-09 16:56:25 -0600706 err = hex2sprom(sprom, buf, count, bus->sprom_size);
Michael Buesch61e115a2007-09-18 15:12:50 -0400707 if (err) {
708 err = -EINVAL;
709 goto out_kfree;
710 }
Larry Fingerc272ef42007-11-09 16:56:25 -0600711 err = sprom_check_crc(sprom, bus->sprom_size);
Michael Buesch61e115a2007-09-18 15:12:50 -0400712 if (err) {
713 err = -EINVAL;
714 goto out_kfree;
715 }
716
717 /* Use interruptible locking, as the SPROM write might
718 * be holding the lock for several seconds. So allow userspace
719 * to cancel operation. */
720 err = -ERESTARTSYS;
721 if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
722 goto out_kfree;
723 err = ssb_devices_freeze(bus);
724 if (err == -EOPNOTSUPP) {
725 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
726 "No suspend support. Is CONFIG_PM enabled?\n");
727 goto out_unlock;
728 }
729 if (err) {
730 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
731 goto out_unlock;
732 }
733 res = sprom_do_write(bus, sprom);
734 err = ssb_devices_thaw(bus);
735 if (err)
736 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
737out_unlock:
738 mutex_unlock(&bus->pci_sprom_mutex);
739out_kfree:
740 kfree(sprom);
741out:
742 if (res)
743 return res;
744 return err ? err : count;
745}
746
747static DEVICE_ATTR(ssb_sprom, 0600,
748 ssb_pci_attr_sprom_show,
749 ssb_pci_attr_sprom_store);
750
751void ssb_pci_exit(struct ssb_bus *bus)
752{
753 struct pci_dev *pdev;
754
755 if (bus->bustype != SSB_BUSTYPE_PCI)
756 return;
757
758 pdev = bus->host_pci;
759 device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
760}
761
762int ssb_pci_init(struct ssb_bus *bus)
763{
764 struct pci_dev *pdev;
765 int err;
766
767 if (bus->bustype != SSB_BUSTYPE_PCI)
768 return 0;
769
770 pdev = bus->host_pci;
771 mutex_init(&bus->pci_sprom_mutex);
772 err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
773 if (err)
774 goto out;
775
776out:
777 return err;
778}