1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "ssb_private.h"
16
17#include <linux/ssb/ssb.h>
18#include <linux/delay.h>
19#include <linux/io.h>
20#include <linux/etherdevice.h>
21#include <linux/mmc/sdio_func.h>
22
23
24#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 0
25
26
27
28#define SSB_SDIO_CIS 0x80
29#define SSB_SDIO_CIS_SROMREV 0x00
30#define SSB_SDIO_CIS_ID 0x01
31#define SSB_SDIO_CIS_BOARDREV 0x02
32#define SSB_SDIO_CIS_PA 0x03
33#define SSB_SDIO_CIS_PA_PA0B0_LO 0
34#define SSB_SDIO_CIS_PA_PA0B0_HI 1
35#define SSB_SDIO_CIS_PA_PA0B1_LO 2
36#define SSB_SDIO_CIS_PA_PA0B1_HI 3
37#define SSB_SDIO_CIS_PA_PA0B2_LO 4
38#define SSB_SDIO_CIS_PA_PA0B2_HI 5
39#define SSB_SDIO_CIS_PA_ITSSI 6
40#define SSB_SDIO_CIS_PA_MAXPOW 7
41#define SSB_SDIO_CIS_OEMNAME 0x04
42#define SSB_SDIO_CIS_CCODE 0x05
43#define SSB_SDIO_CIS_ANTENNA 0x06
44#define SSB_SDIO_CIS_ANTGAIN 0x07
45#define SSB_SDIO_CIS_BFLAGS 0x08
46#define SSB_SDIO_CIS_LEDS 0x09
47
48#define CISTPL_FUNCE_LAN_NODE_ID 0x04
49
50
51
52
53
54
55
56
57
58
59#define SBSDIO_FUNC1_SBADDRLOW 0x1000a
60#define SBSDIO_FUNC1_SBADDRMID 0x1000b
61#define SBSDIO_FUNC1_SBADDRHIGH 0x1000c
62
63
64#define SBSDIO_SBADDRLOW_MASK 0x80
65#define SBSDIO_SBADDRMID_MASK 0xff
66#define SBSDIO_SBADDRHIGH_MASK 0xff
67
68#define SBSDIO_SB_OFT_ADDR_MASK 0x7FFF
69
70
71#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x8000
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104static inline struct device *ssb_sdio_dev(struct ssb_bus *bus)
105{
106 return &bus->host_sdio->dev;
107}
108
109
110static int ssb_sdio_writeb(struct ssb_bus *bus, unsigned int addr, u8 val)
111{
112 int error = 0;
113
114 sdio_writeb(bus->host_sdio, val, addr, &error);
115 if (unlikely(error)) {
116 dev_dbg(ssb_sdio_dev(bus), "%08X <- %02x, error %d\n",
117 addr, val, error);
118 }
119
120 return error;
121}
122
123#if 0
124static u8 ssb_sdio_readb(struct ssb_bus *bus, unsigned int addr)
125{
126 u8 val;
127 int error = 0;
128
129 val = sdio_readb(bus->host_sdio, addr, &error);
130 if (unlikely(error)) {
131 dev_dbg(ssb_sdio_dev(bus), "%08X -> %02x, error %d\n",
132 addr, val, error);
133 }
134
135 return val;
136}
137#endif
138
139
140static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address)
141{
142 int error;
143
144 error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW,
145 (address >> 8) & SBSDIO_SBADDRLOW_MASK);
146 if (error)
147 goto out;
148 error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID,
149 (address >> 16) & SBSDIO_SBADDRMID_MASK);
150 if (error)
151 goto out;
152 error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH,
153 (address >> 24) & SBSDIO_SBADDRHIGH_MASK);
154 if (error)
155 goto out;
156 bus->sdio_sbaddr = address;
157out:
158 if (error) {
159 dev_dbg(ssb_sdio_dev(bus), "failed to set address window"
160 " to 0x%08x, error %d\n", address, error);
161 }
162
163 return error;
164}
165
166
167u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset)
168{
169 u32 val;
170 int error;
171
172 sdio_claim_host(bus->host_sdio);
173 val = sdio_readl(bus->host_sdio, offset, &error);
174 sdio_release_host(bus->host_sdio);
175 if (unlikely(error)) {
176 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n",
177 bus->sdio_sbaddr >> 16, offset, val, error);
178 }
179
180 return val;
181}
182
183
184int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
185{
186 u32 sbaddr;
187 int error;
188
189 sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
190 sdio_claim_host(bus->host_sdio);
191 error = ssb_sdio_set_sbaddr_window(bus, sbaddr);
192 sdio_release_host(bus->host_sdio);
193 if (error) {
194 dev_err(ssb_sdio_dev(bus), "failed to switch to core %u,"
195 " error %d\n", coreidx, error);
196 goto out;
197 }
198out:
199 return error;
200}
201
202
203static int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
204{
205 u8 coreidx = dev->core_index;
206 u32 sbaddr;
207 int error = 0;
208
209 sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
210 if (unlikely(bus->sdio_sbaddr != sbaddr)) {
211#if SSB_VERBOSE_SDIOCORESWITCH_DEBUG
212 dev_info(ssb_sdio_dev(bus),
213 "switching to %s core, index %d\n",
214 ssb_core_name(dev->id.coreid), coreidx);
215#endif
216 error = ssb_sdio_set_sbaddr_window(bus, sbaddr);
217 if (error) {
218 dev_dbg(ssb_sdio_dev(bus), "failed to switch to"
219 " core %u, error %d\n", coreidx, error);
220 goto out;
221 }
222 bus->mapped_device = dev;
223 }
224
225out:
226 return error;
227}
228
229static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset)
230{
231 struct ssb_bus *bus = dev->bus;
232 u8 val = 0xff;
233 int error = 0;
234
235 sdio_claim_host(bus->host_sdio);
236 if (unlikely(ssb_sdio_switch_core(bus, dev)))
237 goto out;
238 offset |= bus->sdio_sbaddr & 0xffff;
239 offset &= SBSDIO_SB_OFT_ADDR_MASK;
240 val = sdio_readb(bus->host_sdio, offset, &error);
241 if (error) {
242 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n",
243 bus->sdio_sbaddr >> 16, offset, val, error);
244 }
245out:
246 sdio_release_host(bus->host_sdio);
247
248 return val;
249}
250
251static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset)
252{
253 struct ssb_bus *bus = dev->bus;
254 u16 val = 0xffff;
255 int error = 0;
256
257 sdio_claim_host(bus->host_sdio);
258 if (unlikely(ssb_sdio_switch_core(bus, dev)))
259 goto out;
260 offset |= bus->sdio_sbaddr & 0xffff;
261 offset &= SBSDIO_SB_OFT_ADDR_MASK;
262 val = sdio_readw(bus->host_sdio, offset, &error);
263 if (error) {
264 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n",
265 bus->sdio_sbaddr >> 16, offset, val, error);
266 }
267out:
268 sdio_release_host(bus->host_sdio);
269
270 return val;
271}
272
273static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset)
274{
275 struct ssb_bus *bus = dev->bus;
276 u32 val = 0xffffffff;
277 int error = 0;
278
279 sdio_claim_host(bus->host_sdio);
280 if (unlikely(ssb_sdio_switch_core(bus, dev)))
281 goto out;
282 offset |= bus->sdio_sbaddr & 0xffff;
283 offset &= SBSDIO_SB_OFT_ADDR_MASK;
284 offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;
285 val = sdio_readl(bus->host_sdio, offset, &error);
286 if (error) {
287 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n",
288 bus->sdio_sbaddr >> 16, offset, val, error);
289 }
290out:
291 sdio_release_host(bus->host_sdio);
292
293 return val;
294}
295
296#ifdef CONFIG_SSB_BLOCKIO
297static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer,
298 size_t count, u16 offset, u8 reg_width)
299{
300 size_t saved_count = count;
301 struct ssb_bus *bus = dev->bus;
302 int error = 0;
303
304 sdio_claim_host(bus->host_sdio);
305 if (unlikely(ssb_sdio_switch_core(bus, dev))) {
306 error = -EIO;
307 memset(buffer, 0xff, count);
308 goto err_out;
309 }
310 offset |= bus->sdio_sbaddr & 0xffff;
311 offset &= SBSDIO_SB_OFT_ADDR_MASK;
312
313 switch (reg_width) {
314 case sizeof(u8): {
315 error = sdio_readsb(bus->host_sdio, buffer, offset, count);
316 break;
317 }
318 case sizeof(u16): {
319 WARN_ON(count & 1);
320 error = sdio_readsb(bus->host_sdio, buffer, offset, count);
321 break;
322 }
323 case sizeof(u32): {
324 WARN_ON(count & 3);
325 offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;
326 error = sdio_readsb(bus->host_sdio, buffer, offset, count);
327 break;
328 }
329 default:
330 WARN_ON(1);
331 }
332 if (!error)
333 goto out;
334
335err_out:
336 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n",
337 bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error);
338out:
339 sdio_release_host(bus->host_sdio);
340}
341#endif
342
343static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val)
344{
345 struct ssb_bus *bus = dev->bus;
346 int error = 0;
347
348 sdio_claim_host(bus->host_sdio);
349 if (unlikely(ssb_sdio_switch_core(bus, dev)))
350 goto out;
351 offset |= bus->sdio_sbaddr & 0xffff;
352 offset &= SBSDIO_SB_OFT_ADDR_MASK;
353 sdio_writeb(bus->host_sdio, val, offset, &error);
354 if (error) {
355 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n",
356 bus->sdio_sbaddr >> 16, offset, val, error);
357 }
358out:
359 sdio_release_host(bus->host_sdio);
360}
361
362static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val)
363{
364 struct ssb_bus *bus = dev->bus;
365 int error = 0;
366
367 sdio_claim_host(bus->host_sdio);
368 if (unlikely(ssb_sdio_switch_core(bus, dev)))
369 goto out;
370 offset |= bus->sdio_sbaddr & 0xffff;
371 offset &= SBSDIO_SB_OFT_ADDR_MASK;
372 sdio_writew(bus->host_sdio, val, offset, &error);
373 if (error) {
374 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n",
375 bus->sdio_sbaddr >> 16, offset, val, error);
376 }
377out:
378 sdio_release_host(bus->host_sdio);
379}
380
381static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val)
382{
383 struct ssb_bus *bus = dev->bus;
384 int error = 0;
385
386 sdio_claim_host(bus->host_sdio);
387 if (unlikely(ssb_sdio_switch_core(bus, dev)))
388 goto out;
389 offset |= bus->sdio_sbaddr & 0xffff;
390 offset &= SBSDIO_SB_OFT_ADDR_MASK;
391 offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;
392 sdio_writel(bus->host_sdio, val, offset, &error);
393 if (error) {
394 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n",
395 bus->sdio_sbaddr >> 16, offset, val, error);
396 }
397 if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32)
398 sdio_readl(bus->host_sdio, 0, &error);
399out:
400 sdio_release_host(bus->host_sdio);
401}
402
403#ifdef CONFIG_SSB_BLOCKIO
404static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer,
405 size_t count, u16 offset, u8 reg_width)
406{
407 size_t saved_count = count;
408 struct ssb_bus *bus = dev->bus;
409 int error = 0;
410
411 sdio_claim_host(bus->host_sdio);
412 if (unlikely(ssb_sdio_switch_core(bus, dev))) {
413 error = -EIO;
414 memset((void *)buffer, 0xff, count);
415 goto err_out;
416 }
417 offset |= bus->sdio_sbaddr & 0xffff;
418 offset &= SBSDIO_SB_OFT_ADDR_MASK;
419
420 switch (reg_width) {
421 case sizeof(u8):
422 error = sdio_writesb(bus->host_sdio, offset,
423 (void *)buffer, count);
424 break;
425 case sizeof(u16):
426 WARN_ON(count & 1);
427 error = sdio_writesb(bus->host_sdio, offset,
428 (void *)buffer, count);
429 break;
430 case sizeof(u32):
431 WARN_ON(count & 3);
432 offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;
433 error = sdio_writesb(bus->host_sdio, offset,
434 (void *)buffer, count);
435 break;
436 default:
437 WARN_ON(1);
438 }
439 if (!error)
440 goto out;
441
442err_out:
443 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n",
444 bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error);
445out:
446 sdio_release_host(bus->host_sdio);
447}
448
449#endif
450
451
452const struct ssb_bus_ops ssb_sdio_ops = {
453 .read8 = ssb_sdio_read8,
454 .read16 = ssb_sdio_read16,
455 .read32 = ssb_sdio_read32,
456 .write8 = ssb_sdio_write8,
457 .write16 = ssb_sdio_write16,
458 .write32 = ssb_sdio_write32,
459#ifdef CONFIG_SSB_BLOCKIO
460 .block_read = ssb_sdio_block_read,
461 .block_write = ssb_sdio_block_write,
462#endif
463};
464
465#define GOTO_ERROR_ON(condition, description) do { \
466 if (unlikely(condition)) { \
467 error_description = description; \
468 goto error; \
469 } \
470 } while (0)
471
472int ssb_sdio_get_invariants(struct ssb_bus *bus,
473 struct ssb_init_invariants *iv)
474{
475 struct ssb_sprom *sprom = &iv->sprom;
476 struct ssb_boardinfo *bi = &iv->boardinfo;
477 const char *error_description = "none";
478 struct sdio_func_tuple *tuple;
479 void *mac;
480
481 memset(sprom, 0xFF, sizeof(*sprom));
482 sprom->boardflags_lo = 0;
483 sprom->boardflags_hi = 0;
484
485 tuple = bus->host_sdio->tuples;
486 while (tuple) {
487 switch (tuple->code) {
488 case 0x22:
489 switch (tuple->data[0]) {
490 case CISTPL_FUNCE_LAN_NODE_ID:
491 GOTO_ERROR_ON((tuple->size != 7) &&
492 (tuple->data[1] != 6),
493 "mac tpl size");
494
495 mac = tuple->data + 2;
496 memcpy(sprom->il0mac, mac, ETH_ALEN);
497 memcpy(sprom->et1mac, mac, ETH_ALEN);
498 break;
499 default:
500 break;
501 }
502 break;
503 case 0x80:
504 switch (tuple->data[0]) {
505 case SSB_SDIO_CIS_SROMREV:
506 GOTO_ERROR_ON(tuple->size != 2,
507 "sromrev tpl size");
508 sprom->revision = tuple->data[1];
509 break;
510 case SSB_SDIO_CIS_ID:
511 GOTO_ERROR_ON((tuple->size != 5) &&
512 (tuple->size != 7),
513 "id tpl size");
514 bi->vendor = tuple->data[1] |
515 (tuple->data[2]<<8);
516 break;
517 case SSB_SDIO_CIS_BOARDREV:
518 GOTO_ERROR_ON(tuple->size != 2,
519 "boardrev tpl size");
520 sprom->board_rev = tuple->data[1];
521 break;
522 case SSB_SDIO_CIS_PA:
523 GOTO_ERROR_ON((tuple->size != 9) &&
524 (tuple->size != 10),
525 "pa tpl size");
526 sprom->pa0b0 = tuple->data[1] |
527 ((u16)tuple->data[2] << 8);
528 sprom->pa0b1 = tuple->data[3] |
529 ((u16)tuple->data[4] << 8);
530 sprom->pa0b2 = tuple->data[5] |
531 ((u16)tuple->data[6] << 8);
532 sprom->itssi_a = tuple->data[7];
533 sprom->itssi_bg = tuple->data[7];
534 sprom->maxpwr_a = tuple->data[8];
535 sprom->maxpwr_bg = tuple->data[8];
536 break;
537 case SSB_SDIO_CIS_OEMNAME:
538
539 break;
540 case SSB_SDIO_CIS_CCODE:
541 GOTO_ERROR_ON(tuple->size != 2,
542 "ccode tpl size");
543 sprom->country_code = tuple->data[1];
544 break;
545 case SSB_SDIO_CIS_ANTENNA:
546 GOTO_ERROR_ON(tuple->size != 2,
547 "ant tpl size");
548 sprom->ant_available_a = tuple->data[1];
549 sprom->ant_available_bg = tuple->data[1];
550 break;
551 case SSB_SDIO_CIS_ANTGAIN:
552 GOTO_ERROR_ON(tuple->size != 2,
553 "antg tpl size");
554 sprom->antenna_gain.a0 = tuple->data[1];
555 sprom->antenna_gain.a1 = tuple->data[1];
556 sprom->antenna_gain.a2 = tuple->data[1];
557 sprom->antenna_gain.a3 = tuple->data[1];
558 break;
559 case SSB_SDIO_CIS_BFLAGS:
560 GOTO_ERROR_ON((tuple->size != 3) &&
561 (tuple->size != 5),
562 "bfl tpl size");
563 sprom->boardflags_lo = tuple->data[1] |
564 ((u16)tuple->data[2] << 8);
565 break;
566 case SSB_SDIO_CIS_LEDS:
567 GOTO_ERROR_ON(tuple->size != 5,
568 "leds tpl size");
569 sprom->gpio0 = tuple->data[1];
570 sprom->gpio1 = tuple->data[2];
571 sprom->gpio2 = tuple->data[3];
572 sprom->gpio3 = tuple->data[4];
573 break;
574 default:
575 break;
576 }
577 break;
578 default:
579 break;
580 }
581 tuple = tuple->next;
582 }
583
584 return 0;
585error:
586 dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n",
587 error_description);
588 return -ENODEV;
589}
590
591void ssb_sdio_exit(struct ssb_bus *bus)
592{
593 if (bus->bustype != SSB_BUSTYPE_SDIO)
594 return;
595
596}
597
598int ssb_sdio_init(struct ssb_bus *bus)
599{
600 if (bus->bustype != SSB_BUSTYPE_SDIO)
601 return 0;
602
603 bus->sdio_sbaddr = ~0;
604
605 return 0;
606}
607