fix a dependency bug
[openwrt.git] / target / linux / generic-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(5);
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 int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
244 {
245 struct pci_dev *pdev = bus->host_pci;
246 int i, err;
247 u32 spromctl;
248
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);
251 if (err)
252 goto err_ctlreg;
253 spromctl |= SSB_SPROMCTL_WE;
254 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
255 if (err)
256 goto err_ctlreg;
257 ssb_printk(KERN_NOTICE PFX "[ 0%%");
258 msleep(500);
259 for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
260 if (i == SSB_SPROMSIZE_WORDS / 4)
261 ssb_printk("25%%");
262 else if (i == SSB_SPROMSIZE_WORDS / 2)
263 ssb_printk("50%%");
264 else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
265 ssb_printk("75%%");
266 else if (i % 2)
267 ssb_printk(".");
268 writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
269 mmiowb();
270 msleep(20);
271 }
272 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
273 if (err)
274 goto err_ctlreg;
275 spromctl &= ~SSB_SPROMCTL_WE;
276 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
277 if (err)
278 goto err_ctlreg;
279 msleep(500);
280 ssb_printk("100%% ]\n");
281 ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
282
283 return 0;
284 err_ctlreg:
285 ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
286 return err;
287 }
288
289 static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
290 {
291 int i;
292 u16 v;
293
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);
300 }
301 for (i = 0; i < 3; i++) {
302 v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
303 *(((u16 *)out->et0mac) + i) = cpu_to_be16(v);
304 }
305 for (i = 0; i < 3; i++) {
306 v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
307 *(((u16 *)out->et1mac) + i) = cpu_to_be16(v);
308 }
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);
346 }
347 }
348
349 static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
350 {
351 int i;
352 u16 v;
353
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);
368 }
369 }
370
371 static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
372 {
373 out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
374 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
375 out->ofdmapo <<= 16;
376 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
377 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
378
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;
384
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;
390
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);
402
403 out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
404 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
405 out->ofdmgpo <<= 16;
406 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
407 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
408 }
409
410 static int sprom_extract(struct ssb_bus *bus,
411 struct ssb_sprom *out, const u16 *in)
412 {
413 memset(out, 0, sizeof(*out));
414
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);
418
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);
424 } else {
425 if (out->revision == 0)
426 goto unsupported;
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)
434 goto unsupported;
435 }
436
437 return 0;
438 unsupported:
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);
442 return 0;
443 }
444
445 static int ssb_pci_sprom_get(struct ssb_bus *bus,
446 struct ssb_sprom *sprom)
447 {
448 int err = -ENOMEM;
449 u16 *buf;
450
451 buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
452 if (!buf)
453 goto out;
454 sprom_do_read(bus, buf);
455 err = sprom_check_crc(buf);
456 if (err) {
457 ssb_printk(KERN_WARNING PFX
458 "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
459 }
460 err = sprom_extract(bus, sprom, buf);
461
462 kfree(buf);
463 out:
464 return err;
465 }
466
467 static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
468 struct ssb_boardinfo *bi)
469 {
470 pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
471 &bi->vendor);
472 pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
473 &bi->type);
474 pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
475 &bi->rev);
476 }
477
478 int ssb_pci_get_invariants(struct ssb_bus *bus,
479 struct ssb_init_invariants *iv)
480 {
481 int err;
482
483 err = ssb_pci_sprom_get(bus, &iv->sprom);
484 if (err)
485 goto out;
486 ssb_pci_get_boardinfo(bus, &iv->boardinfo);
487
488 out:
489 return err;
490 }
491
492 static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
493 {
494 struct ssb_bus *bus = dev->bus;
495
496 if (unlikely(bus->mapped_device != dev)) {
497 if (unlikely(ssb_pci_switch_core(bus, dev)))
498 return 0xFFFF;
499 }
500 return readw(bus->mmio + offset);
501 }
502
503 static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
504 {
505 struct ssb_bus *bus = dev->bus;
506
507 if (unlikely(bus->mapped_device != dev)) {
508 if (unlikely(ssb_pci_switch_core(bus, dev)))
509 return 0xFFFFFFFF;
510 }
511 return readl(bus->mmio + offset);
512 }
513
514 static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
515 {
516 struct ssb_bus *bus = dev->bus;
517
518 if (unlikely(bus->mapped_device != dev)) {
519 if (unlikely(ssb_pci_switch_core(bus, dev)))
520 return;
521 }
522 writew(value, bus->mmio + offset);
523 }
524
525 static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
526 {
527 struct ssb_bus *bus = dev->bus;
528
529 if (unlikely(bus->mapped_device != dev)) {
530 if (unlikely(ssb_pci_switch_core(bus, dev)))
531 return;
532 }
533 writel(value, bus->mmio + offset);
534 }
535
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,
541 };
542
543 static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
544 {
545 int i, pos = 0;
546
547 for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
548 pos += snprintf(buf + pos, buf_len - pos - 1,
549 "%04X", swab16(sprom[i]) & 0xFFFF);
550 }
551 pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
552
553 return pos + 1;
554 }
555
556 static int hex2sprom(u16 *sprom, const char *dump, size_t len)
557 {
558 char tmp[5] = { 0 };
559 int cnt = 0;
560 unsigned long parsed;
561
562 if (len < SSB_SPROMSIZE_BYTES * 2)
563 return -EINVAL;
564
565 while (cnt < SSB_SPROMSIZE_WORDS) {
566 memcpy(tmp, dump, 4);
567 dump += 4;
568 parsed = simple_strtoul(tmp, NULL, 16);
569 sprom[cnt++] = swab16((u16)parsed);
570 }
571
572 return 0;
573 }
574
575 static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
576 struct device_attribute *attr,
577 char *buf)
578 {
579 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
580 struct ssb_bus *bus;
581 u16 *sprom;
582 int err = -ENODEV;
583 ssize_t count = 0;
584
585 bus = ssb_pci_dev_to_bus(pdev);
586 if (!bus)
587 goto out;
588 err = -ENOMEM;
589 sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
590 if (!sprom)
591 goto out;
592
593 err = -ERESTARTSYS;
594 if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
595 goto out_kfree;
596 sprom_do_read(bus, sprom);
597 mutex_unlock(&bus->pci_sprom_mutex);
598
599 count = sprom2hex(sprom, buf, PAGE_SIZE);
600 err = 0;
601
602 out_kfree:
603 kfree(sprom);
604 out:
605 return err ? err : count;
606 }
607
608 static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
609 struct device_attribute *attr,
610 const char *buf, size_t count)
611 {
612 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
613 struct ssb_bus *bus;
614 u16 *sprom;
615 int res = 0, err = -ENODEV;
616
617 bus = ssb_pci_dev_to_bus(pdev);
618 if (!bus)
619 goto out;
620 err = -ENOMEM;
621 sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
622 if (!sprom)
623 goto out;
624 err = hex2sprom(sprom, buf, count);
625 if (err) {
626 err = -EINVAL;
627 goto out_kfree;
628 }
629 err = sprom_check_crc(sprom);
630 if (err) {
631 err = -EINVAL;
632 goto out_kfree;
633 }
634
635 err = -ERESTARTSYS;
636 if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
637 goto out_kfree;
638 err = ssb_devices_freeze(bus);
639 if (err) {
640 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
641 goto out_unlock;
642 }
643 res = sprom_do_write(bus, sprom);
644 err = ssb_devices_thaw(bus);
645 if (err)
646 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
647 out_unlock:
648 mutex_unlock(&bus->pci_sprom_mutex);
649 out_kfree:
650 kfree(sprom);
651 out:
652 if (res)
653 return res;
654 return err ? err : count;
655 }
656
657 static DEVICE_ATTR(ssb_sprom, 0600,
658 ssb_pci_attr_sprom_show,
659 ssb_pci_attr_sprom_store);
660
661 void ssb_pci_exit(struct ssb_bus *bus)
662 {
663 struct pci_dev *pdev;
664
665 if (bus->bustype != SSB_BUSTYPE_PCI)
666 return;
667
668 pdev = bus->host_pci;
669 device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
670 }
671
672 int ssb_pci_init(struct ssb_bus *bus)
673 {
674 struct pci_dev *pdev;
675 int err;
676
677 if (bus->bustype != SSB_BUSTYPE_PCI)
678 return 0;
679
680 pdev = bus->host_pci;
681 mutex_init(&bus->pci_sprom_mutex);
682 err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
683 if (err)
684 goto out;
685
686 out:
687 return err;
688 }
This page took 0.100597 seconds and 5 git commands to generate.