1/* 2 * Sonics Silicon Backplane 3 * SDIO-Hostbus related functions 4 * 5 * Copyright 2009 Albert Herranz <albert_herranz@yahoo.es> 6 * 7 * Based on drivers/ssb/pcmcia.c 8 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 9 * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de> 10 * 11 * Licensed under the GNU/GPL. See COPYING for details. 12 * 13 */ 14 15#include <linux/ssb/ssb.h> 16#include <linux/delay.h> 17#include <linux/io.h> 18#include <linux/etherdevice.h> 19#include <linux/mmc/sdio_func.h> 20 21#include "ssb_private.h" 22 23/* Define the following to 1 to enable a printk on each coreswitch. */ 24#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 0 25 26 27/* Hardware invariants CIS tuples */ 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 /* same as in PCMCIA */ 49 50 51/* 52 * Function 1 miscellaneous registers. 53 * 54 * Definitions match src/include/sbsdio.h from the 55 * Android Open Source Project 56 * http://android.git.kernel.org/?p=platform/system/wlan/broadcom.git 57 * 58 */ 59#define SBSDIO_FUNC1_SBADDRLOW 0x1000a /* SB Address window Low (b15) */ 60#define SBSDIO_FUNC1_SBADDRMID 0x1000b /* SB Address window Mid (b23-b16) */ 61#define SBSDIO_FUNC1_SBADDRHIGH 0x1000c /* SB Address window High (b24-b31) */ 62 63/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ 64#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid address bits in SBADDRLOW */ 65#define SBSDIO_SBADDRMID_MASK 0xff /* Valid address bits in SBADDRMID */ 66#define SBSDIO_SBADDRHIGH_MASK 0xff /* Valid address bits in SBADDRHIGH */ 67 68#define SBSDIO_SB_OFT_ADDR_MASK 0x7FFF /* sb offset addr is <= 15 bits, 32k */ 69 70/* REVISIT: this flag doesn't seem to matter */ 71#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x8000 /* forces 32-bit SB access */ 72 73 74/* 75 * Address map within the SDIO function address space (128K). 76 * 77 * Start End Description 78 * ------- ------- ------------------------------------------ 79 * 0x00000 0x0ffff selected backplane address window (64K) 80 * 0x10000 0x1ffff backplane control registers (max 64K) 81 * 82 * The current address window is configured by writing to registers 83 * SBADDRLOW, SBADDRMID and SBADDRHIGH. 84 * 85 * In order to access the contents of a 32-bit Silicon Backplane address 86 * the backplane address window must be first loaded with the highest 87 * 16 bits of the target address. Then, an access must be done to the 88 * SDIO function address space using the lower 15 bits of the address. 89 * Bit 15 of the address must be set when doing 32 bit accesses. 90 * 91 * 10987654321098765432109876543210 92 * WWWWWWWWWWWWWWWWW SB Address Window 93 * OOOOOOOOOOOOOOOO Offset within SB Address Window 94 * a 32-bit access flag 95 */ 96 97 98/* 99 * SSB I/O via SDIO. 100 * 101 * NOTE: SDIO address @addr is 17 bits long (SDIO address space is 128K). 102 */ 103 104static inline struct device *ssb_sdio_dev(struct ssb_bus *bus) 105{ 106 return &bus->host_sdio->dev; 107} 108 109/* host claimed */ 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 124/* host claimed */ 125static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address) 126{ 127 int error; 128 129 error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW, 130 (address >> 8) & SBSDIO_SBADDRLOW_MASK); 131 if (error) 132 goto out; 133 error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID, 134 (address >> 16) & SBSDIO_SBADDRMID_MASK); 135 if (error) 136 goto out; 137 error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH, 138 (address >> 24) & SBSDIO_SBADDRHIGH_MASK); 139 if (error) 140 goto out; 141 bus->sdio_sbaddr = address; 142out: 143 if (error) { 144 dev_dbg(ssb_sdio_dev(bus), "failed to set address window" 145 " to 0x%08x, error %d\n", address, error); 146 } 147 148 return error; 149} 150 151/* for enumeration use only */ 152u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) 153{ 154 u32 val; 155 int error; 156 157 sdio_claim_host(bus->host_sdio); 158 val = sdio_readl(bus->host_sdio, offset, &error); 159 sdio_release_host(bus->host_sdio); 160 if (unlikely(error)) { 161 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", 162 bus->sdio_sbaddr >> 16, offset, val, error); 163 } 164 165 return val; 166} 167 168/* for enumeration use only */ 169int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) 170{ 171 u32 sbaddr; 172 int error; 173 174 sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; 175 sdio_claim_host(bus->host_sdio); 176 error = ssb_sdio_set_sbaddr_window(bus, sbaddr); 177 sdio_release_host(bus->host_sdio); 178 if (error) { 179 dev_err(ssb_sdio_dev(bus), "failed to switch to core %u," 180 " error %d\n", coreidx, error); 181 goto out; 182 } 183out: 184 return error; 185} 186 187/* host must be already claimed */ 188int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) 189{ 190 u8 coreidx = dev->core_index; 191 u32 sbaddr; 192 int error = 0; 193 194 sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; 195 if (unlikely(bus->sdio_sbaddr != sbaddr)) { 196#if SSB_VERBOSE_SDIOCORESWITCH_DEBUG 197 dev_info(ssb_sdio_dev(bus), 198 "switching to %s core, index %d\n", 199 ssb_core_name(dev->id.coreid), coreidx); 200#endif 201 error = ssb_sdio_set_sbaddr_window(bus, sbaddr); 202 if (error) { 203 dev_dbg(ssb_sdio_dev(bus), "failed to switch to" 204 " core %u, error %d\n", coreidx, error); 205 goto out; 206 } 207 bus->mapped_device = dev; 208 } 209 210out: 211 return error; 212} 213 214static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset) 215{ 216 struct ssb_bus *bus = dev->bus; 217 u8 val = 0xff; 218 int error = 0; 219 220 sdio_claim_host(bus->host_sdio); 221 if (unlikely(ssb_sdio_switch_core(bus, dev))) 222 goto out; 223 offset |= bus->sdio_sbaddr & 0xffff; 224 offset &= SBSDIO_SB_OFT_ADDR_MASK; 225 val = sdio_readb(bus->host_sdio, offset, &error); 226 if (error) { 227 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n", 228 bus->sdio_sbaddr >> 16, offset, val, error); 229 } 230out: 231 sdio_release_host(bus->host_sdio); 232 233 return val; 234} 235 236static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset) 237{ 238 struct ssb_bus *bus = dev->bus; 239 u16 val = 0xffff; 240 int error = 0; 241 242 sdio_claim_host(bus->host_sdio); 243 if (unlikely(ssb_sdio_switch_core(bus, dev))) 244 goto out; 245 offset |= bus->sdio_sbaddr & 0xffff; 246 offset &= SBSDIO_SB_OFT_ADDR_MASK; 247 val = sdio_readw(bus->host_sdio, offset, &error); 248 if (error) { 249 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n", 250 bus->sdio_sbaddr >> 16, offset, val, error); 251 } 252out: 253 sdio_release_host(bus->host_sdio); 254 255 return val; 256} 257 258static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset) 259{ 260 struct ssb_bus *bus = dev->bus; 261 u32 val = 0xffffffff; 262 int error = 0; 263 264 sdio_claim_host(bus->host_sdio); 265 if (unlikely(ssb_sdio_switch_core(bus, dev))) 266 goto out; 267 offset |= bus->sdio_sbaddr & 0xffff; 268 offset &= SBSDIO_SB_OFT_ADDR_MASK; 269 offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ 270 val = sdio_readl(bus->host_sdio, offset, &error); 271 if (error) { 272 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", 273 bus->sdio_sbaddr >> 16, offset, val, error); 274 } 275out: 276 sdio_release_host(bus->host_sdio); 277 278 return val; 279} 280 281#ifdef CONFIG_SSB_BLOCKIO 282static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer, 283 size_t count, u16 offset, u8 reg_width) 284{ 285 size_t saved_count = count; 286 struct ssb_bus *bus = dev->bus; 287 int error = 0; 288 289 sdio_claim_host(bus->host_sdio); 290 if (unlikely(ssb_sdio_switch_core(bus, dev))) { 291 error = -EIO; 292 memset(buffer, 0xff, count); 293 goto err_out; 294 } 295 offset |= bus->sdio_sbaddr & 0xffff; 296 offset &= SBSDIO_SB_OFT_ADDR_MASK; 297 298 switch (reg_width) { 299 case sizeof(u8): { 300 error = sdio_readsb(bus->host_sdio, buffer, offset, count); 301 break; 302 } 303 case sizeof(u16): { 304 SSB_WARN_ON(count & 1); 305 error = sdio_readsb(bus->host_sdio, buffer, offset, count); 306 break; 307 } 308 case sizeof(u32): { 309 SSB_WARN_ON(count & 3); 310 offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ 311 error = sdio_readsb(bus->host_sdio, buffer, offset, count); 312 break; 313 } 314 default: 315 SSB_WARN_ON(1); 316 } 317 if (!error) 318 goto out; 319 320err_out: 321 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n", 322 bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); 323out: 324 sdio_release_host(bus->host_sdio); 325} 326#endif /* CONFIG_SSB_BLOCKIO */ 327 328static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val) 329{ 330 struct ssb_bus *bus = dev->bus; 331 int error = 0; 332 333 sdio_claim_host(bus->host_sdio); 334 if (unlikely(ssb_sdio_switch_core(bus, dev))) 335 goto out; 336 offset |= bus->sdio_sbaddr & 0xffff; 337 offset &= SBSDIO_SB_OFT_ADDR_MASK; 338 sdio_writeb(bus->host_sdio, val, offset, &error); 339 if (error) { 340 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n", 341 bus->sdio_sbaddr >> 16, offset, val, error); 342 } 343out: 344 sdio_release_host(bus->host_sdio); 345} 346 347static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val) 348{ 349 struct ssb_bus *bus = dev->bus; 350 int error = 0; 351 352 sdio_claim_host(bus->host_sdio); 353 if (unlikely(ssb_sdio_switch_core(bus, dev))) 354 goto out; 355 offset |= bus->sdio_sbaddr & 0xffff; 356 offset &= SBSDIO_SB_OFT_ADDR_MASK; 357 sdio_writew(bus->host_sdio, val, offset, &error); 358 if (error) { 359 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n", 360 bus->sdio_sbaddr >> 16, offset, val, error); 361 } 362out: 363 sdio_release_host(bus->host_sdio); 364} 365 366static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val) 367{ 368 struct ssb_bus *bus = dev->bus; 369 int error = 0; 370 371 sdio_claim_host(bus->host_sdio); 372 if (unlikely(ssb_sdio_switch_core(bus, dev))) 373 goto out; 374 offset |= bus->sdio_sbaddr & 0xffff; 375 offset &= SBSDIO_SB_OFT_ADDR_MASK; 376 offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ 377 sdio_writel(bus->host_sdio, val, offset, &error); 378 if (error) { 379 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n", 380 bus->sdio_sbaddr >> 16, offset, val, error); 381 } 382 if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32) 383 sdio_readl(bus->host_sdio, 0, &error); 384out: 385 sdio_release_host(bus->host_sdio); 386} 387 388#ifdef CONFIG_SSB_BLOCKIO 389static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer, 390 size_t count, u16 offset, u8 reg_width) 391{ 392 size_t saved_count = count; 393 struct ssb_bus *bus = dev->bus; 394 int error = 0; 395 396 sdio_claim_host(bus->host_sdio); 397 if (unlikely(ssb_sdio_switch_core(bus, dev))) { 398 error = -EIO; 399 memset((void *)buffer, 0xff, count); 400 goto err_out; 401 } 402 offset |= bus->sdio_sbaddr & 0xffff; 403 offset &= SBSDIO_SB_OFT_ADDR_MASK; 404 405 switch (reg_width) { 406 case sizeof(u8): 407 error = sdio_writesb(bus->host_sdio, offset, 408 (void *)buffer, count); 409 break; 410 case sizeof(u16): 411 SSB_WARN_ON(count & 1); 412 error = sdio_writesb(bus->host_sdio, offset, 413 (void *)buffer, count); 414 break; 415 case sizeof(u32): 416 SSB_WARN_ON(count & 3); 417 offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ 418 error = sdio_writesb(bus->host_sdio, offset, 419 (void *)buffer, count); 420 break; 421 default: 422 SSB_WARN_ON(1); 423 } 424 if (!error) 425 goto out; 426 427err_out: 428 dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n", 429 bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); 430out: 431 sdio_release_host(bus->host_sdio); 432} 433 434#endif /* CONFIG_SSB_BLOCKIO */ 435 436/* Not "static", as it's used in main.c */ 437const struct ssb_bus_ops ssb_sdio_ops = { 438 .read8 = ssb_sdio_read8, 439 .read16 = ssb_sdio_read16, 440 .read32 = ssb_sdio_read32, 441 .write8 = ssb_sdio_write8, 442 .write16 = ssb_sdio_write16, 443 .write32 = ssb_sdio_write32, 444#ifdef CONFIG_SSB_BLOCKIO 445 .block_read = ssb_sdio_block_read, 446 .block_write = ssb_sdio_block_write, 447#endif 448}; 449 450#define GOTO_ERROR_ON(condition, description) do { \ 451 if (unlikely(condition)) { \ 452 error_description = description; \ 453 goto error; \ 454 } \ 455 } while (0) 456 457int ssb_sdio_get_invariants(struct ssb_bus *bus, 458 struct ssb_init_invariants *iv) 459{ 460 struct ssb_sprom *sprom = &iv->sprom; 461 struct ssb_boardinfo *bi = &iv->boardinfo; 462 const char *error_description = "none"; 463 struct sdio_func_tuple *tuple; 464 void *mac; 465 466 memset(sprom, 0xFF, sizeof(*sprom)); 467 sprom->boardflags_lo = 0; 468 sprom->boardflags_hi = 0; 469 470 tuple = bus->host_sdio->tuples; 471 while (tuple) { 472 switch (tuple->code) { 473 case 0x22: /* extended function */ 474 switch (tuple->data[0]) { 475 case CISTPL_FUNCE_LAN_NODE_ID: 476 GOTO_ERROR_ON((tuple->size != 7) && 477 (tuple->data[1] != 6), 478 "mac tpl size"); 479 /* fetch the MAC address. */ 480 mac = tuple->data + 2; 481 memcpy(sprom->il0mac, mac, ETH_ALEN); 482 memcpy(sprom->et1mac, mac, ETH_ALEN); 483 break; 484 default: 485 break; 486 } 487 break; 488 case 0x80: /* vendor specific tuple */ 489 switch (tuple->data[0]) { 490 case SSB_SDIO_CIS_SROMREV: 491 GOTO_ERROR_ON(tuple->size != 2, 492 "sromrev tpl size"); 493 sprom->revision = tuple->data[1]; 494 break; 495 case SSB_SDIO_CIS_ID: 496 GOTO_ERROR_ON((tuple->size != 5) && 497 (tuple->size != 7), 498 "id tpl size"); 499 bi->vendor = tuple->data[1] | 500 (tuple->data[2]<<8); 501 break; 502 case SSB_SDIO_CIS_BOARDREV: 503 GOTO_ERROR_ON(tuple->size != 2, 504 "boardrev tpl size"); 505 sprom->board_rev = tuple->data[1]; 506 break; 507 case SSB_SDIO_CIS_PA: 508 GOTO_ERROR_ON((tuple->size != 9) && 509 (tuple->size != 10), 510 "pa tpl size"); 511 sprom->pa0b0 = tuple->data[1] | 512 ((u16)tuple->data[2] << 8); 513 sprom->pa0b1 = tuple->data[3] | 514 ((u16)tuple->data[4] << 8); 515 sprom->pa0b2 = tuple->data[5] | 516 ((u16)tuple->data[6] << 8); 517 sprom->itssi_a = tuple->data[7]; 518 sprom->itssi_bg = tuple->data[7]; 519 sprom->maxpwr_a = tuple->data[8]; 520 sprom->maxpwr_bg = tuple->data[8]; 521 break; 522 case SSB_SDIO_CIS_OEMNAME: 523 /* Not present */ 524 break; 525 case SSB_SDIO_CIS_CCODE: 526 GOTO_ERROR_ON(tuple->size != 2, 527 "ccode tpl size"); 528 sprom->country_code = tuple->data[1]; 529 break; 530 case SSB_SDIO_CIS_ANTENNA: 531 GOTO_ERROR_ON(tuple->size != 2, 532 "ant tpl size"); 533 sprom->ant_available_a = tuple->data[1]; 534 sprom->ant_available_bg = tuple->data[1]; 535 break; 536 case SSB_SDIO_CIS_ANTGAIN: 537 GOTO_ERROR_ON(tuple->size != 2, 538 "antg tpl size"); 539 sprom->antenna_gain.ghz24.a0 = tuple->data[1]; 540 sprom->antenna_gain.ghz24.a1 = tuple->data[1]; 541 sprom->antenna_gain.ghz24.a2 = tuple->data[1]; 542 sprom->antenna_gain.ghz24.a3 = tuple->data[1]; 543 sprom->antenna_gain.ghz5.a0 = tuple->data[1]; 544 sprom->antenna_gain.ghz5.a1 = tuple->data[1]; 545 sprom->antenna_gain.ghz5.a2 = tuple->data[1]; 546 sprom->antenna_gain.ghz5.a3 = tuple->data[1]; 547 break; 548 case SSB_SDIO_CIS_BFLAGS: 549 GOTO_ERROR_ON((tuple->size != 3) && 550 (tuple->size != 5), 551 "bfl tpl size"); 552 sprom->boardflags_lo = tuple->data[1] | 553 ((u16)tuple->data[2] << 8); 554 break; 555 case SSB_SDIO_CIS_LEDS: 556 GOTO_ERROR_ON(tuple->size != 5, 557 "leds tpl size"); 558 sprom->gpio0 = tuple->data[1]; 559 sprom->gpio1 = tuple->data[2]; 560 sprom->gpio2 = tuple->data[3]; 561 sprom->gpio3 = tuple->data[4]; 562 break; 563 default: 564 break; 565 } 566 break; 567 default: 568 break; 569 } 570 tuple = tuple->next; 571 } 572 573 return 0; 574error: 575 dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n", 576 error_description); 577 return -ENODEV; 578} 579 580void ssb_sdio_exit(struct ssb_bus *bus) 581{ 582 if (bus->bustype != SSB_BUSTYPE_SDIO) 583 return; 584 /* Nothing to do here. */ 585} 586 587int ssb_sdio_init(struct ssb_bus *bus) 588{ 589 if (bus->bustype != SSB_BUSTYPE_SDIO) 590 return 0; 591 592 bus->sdio_sbaddr = ~0; 593 594 return 0; 595} 596