1/* 2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel 3 * 4 * Copyright (C) 1999-2012, Broadcom Corporation 5 * 6 * Unless you and Broadcom execute a separate written software license 7 * agreement governing use of this software, this software is licensed to you 8 * under the terms of the GNU General Public License version 2 (the "GPL"), 9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the 10 * following added to such license: 11 * 12 * As a special exception, the copyright holders of this software give you 13 * permission to link this software with independent modules, and to copy and 14 * distribute the resulting executable under terms of your choice, provided that 15 * you also meet, for each linked independent module, the terms and conditions of 16 * the license of that module. An independent module is a module which is not 17 * derived from this software. The special exception does not apply to any 18 * modifications of the software. 19 * 20 * Notwithstanding the above, under no circumstances may you combine this 21 * software in any way with any other Broadcom software provided under a license 22 * other than the GPL, without Broadcom's express prior written consent. 23 * 24 * $Id: bcmsdh_sdmmc.c 347640 2012-07-27 11:53:21Z $ 25 */ 26#include <typedefs.h> 27 28#include <bcmdevs.h> 29#include <bcmendian.h> 30#include <bcmutils.h> 31#include <osl.h> 32#include <sdio.h> /* SDIO Device and Protocol Specs */ 33#include <sdioh.h> /* Standard SDIO Host Controller Specification */ 34#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ 35#include <sdiovar.h> /* ioctl/iovars */ 36 37#include <linux/mmc/core.h> 38#include <linux/mmc/card.h> 39#include <linux/mmc/sdio_func.h> 40#include <linux/mmc/sdio_ids.h> 41 42#include <dngl_stats.h> 43#include <dhd.h> 44 45#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) 46#include <linux/suspend.h> 47extern volatile bool dhd_mmc_suspend; 48#endif 49#include "bcmsdh_sdmmc.h" 50 51#ifndef BCMSDH_MODULE 52extern int sdio_function_init(void); 53extern void sdio_function_cleanup(void); 54#endif /* BCMSDH_MODULE */ 55 56#if !defined(OOB_INTR_ONLY) 57static void IRQHandler(struct sdio_func *func); 58static void IRQHandlerF2(struct sdio_func *func); 59#endif /* !defined(OOB_INTR_ONLY) */ 60static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); 61extern int sdio_reset_comm(struct mmc_card *card); 62 63extern PBCMSDH_SDMMC_INSTANCE gInstance; 64 65uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ 66#if defined(SDIO_F2_BLKSIZE) 67uint sd_f2_blocksize = SDIO_F2_BLKSIZE; 68#else 69uint sd_f2_blocksize = 512; /* Default blocksize */ 70#endif 71uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ 72 73uint sd_power = 1; /* Default to SD Slot powered ON */ 74uint sd_clock = 1; /* Default to SD Clock turned ON */ 75uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ 76uint sd_msglevel = 0x01; 77uint sd_use_dma = TRUE; 78DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); 79DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); 80DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); 81DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); 82 83#define DMA_ALIGN_MASK 0x03 84 85int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); 86 87static int 88sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) 89{ 90 int err_ret; 91 uint32 fbraddr; 92 uint8 func; 93 94 sd_trace(("%s\n", __FUNCTION__)); 95 96 /* Get the Card's common CIS address */ 97 sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); 98 sd->func_cis_ptr[0] = sd->com_cis_ptr; 99 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); 100 101 /* Get the Card's function CIS (for each function) */ 102 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; 103 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { 104 sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); 105 sd_info(("%s: Function %d CIS Ptr = 0x%x\n", 106 __FUNCTION__, func, sd->func_cis_ptr[func])); 107 } 108 109 sd->func_cis_ptr[0] = sd->com_cis_ptr; 110 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); 111 112 /* Enable Function 1 */ 113 sdio_claim_host(gInstance->func[1]); 114 err_ret = sdio_enable_func(gInstance->func[1]); 115 sdio_release_host(gInstance->func[1]); 116 if (err_ret) { 117 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret)); 118 } 119 120 return FALSE; 121} 122 123/* 124 * Public entry points & extern's 125 */ 126extern sdioh_info_t * 127sdioh_attach(osl_t *osh, void *bar0, uint irq) 128{ 129 sdioh_info_t *sd; 130 int err_ret; 131 132 sd_trace(("%s\n", __FUNCTION__)); 133 134 if (gInstance == NULL) { 135 sd_err(("%s: SDIO Device not present\n", __FUNCTION__)); 136 return NULL; 137 } 138 139 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { 140 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); 141 return NULL; 142 } 143 bzero((char *)sd, sizeof(sdioh_info_t)); 144 sd->osh = osh; 145 if (sdioh_sdmmc_osinit(sd) != 0) { 146 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__)); 147 MFREE(sd->osh, sd, sizeof(sdioh_info_t)); 148 return NULL; 149 } 150 151 sd->num_funcs = 2; 152 sd->sd_blockmode = TRUE; 153 sd->use_client_ints = TRUE; 154 sd->client_block_size[0] = 64; 155 sd->use_rxchain = FALSE; 156 157 gInstance->sd = sd; 158 159 /* Claim host controller */ 160 if (gInstance->func[1]) { 161 sdio_claim_host(gInstance->func[1]); 162 163 sd->client_block_size[1] = 64; 164 err_ret = sdio_set_block_size(gInstance->func[1], 64); 165 if (err_ret) { 166 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); 167 } 168 169 /* Release host controller F1 */ 170 sdio_release_host(gInstance->func[1]); 171 } else { 172 sd_err(("%s:gInstance->func[1] is null\n", __FUNCTION__)); 173 MFREE(sd->osh, sd, sizeof(sdioh_info_t)); 174 return NULL; 175 } 176 177 if (gInstance->func[2]) { 178 /* Claim host controller F2 */ 179 sdio_claim_host(gInstance->func[2]); 180 181 sd->client_block_size[2] = sd_f2_blocksize; 182 err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize); 183 if (err_ret) { 184 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n", 185 sd_f2_blocksize)); 186 } 187 188 /* Release host controller F2 */ 189 sdio_release_host(gInstance->func[2]); 190 } else { 191 sd_err(("%s:gInstance->func[2] is null\n", __FUNCTION__)); 192 MFREE(sd->osh, sd, sizeof(sdioh_info_t)); 193 return NULL; 194 } 195 196 sdioh_sdmmc_card_enablefuncs(sd); 197 198 sd_trace(("%s: Done\n", __FUNCTION__)); 199 return sd; 200} 201 202 203extern SDIOH_API_RC 204sdioh_detach(osl_t *osh, sdioh_info_t *sd) 205{ 206 sd_trace(("%s\n", __FUNCTION__)); 207 208 if (sd) { 209 210 /* Disable Function 2 */ 211 sdio_claim_host(gInstance->func[2]); 212 sdio_disable_func(gInstance->func[2]); 213 sdio_release_host(gInstance->func[2]); 214 215 /* Disable Function 1 */ 216 if (gInstance->func[1]) { 217 sdio_claim_host(gInstance->func[1]); 218 sdio_disable_func(gInstance->func[1]); 219 sdio_release_host(gInstance->func[1]); 220 } 221 222 gInstance->func[1] = NULL; 223 gInstance->func[2] = NULL; 224 225 /* deregister irq */ 226 sdioh_sdmmc_osfree(sd); 227 228 MFREE(sd->osh, sd, sizeof(sdioh_info_t)); 229 } 230 return SDIOH_API_RC_SUCCESS; 231} 232 233#if defined(OOB_INTR_ONLY) && defined(HW_OOB) 234 235extern SDIOH_API_RC 236sdioh_enable_func_intr(void) 237{ 238 uint8 reg; 239 int err; 240 241 if (gInstance->func[0]) { 242 sdio_claim_host(gInstance->func[0]); 243 244 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); 245 if (err) { 246 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); 247 sdio_release_host(gInstance->func[0]); 248 return SDIOH_API_RC_FAIL; 249 } 250 251 /* Enable F1 and F2 interrupts, set master enable */ 252 reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN); 253 254 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); 255 sdio_release_host(gInstance->func[0]); 256 257 if (err) { 258 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); 259 return SDIOH_API_RC_FAIL; 260 } 261 } 262 263 return SDIOH_API_RC_SUCCESS; 264} 265 266extern SDIOH_API_RC 267sdioh_disable_func_intr(void) 268{ 269 uint8 reg; 270 int err; 271 272 if (gInstance->func[0]) { 273 sdio_claim_host(gInstance->func[0]); 274 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); 275 if (err) { 276 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); 277 sdio_release_host(gInstance->func[0]); 278 return SDIOH_API_RC_FAIL; 279 } 280 281 reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); 282 /* Disable master interrupt with the last function interrupt */ 283 if (!(reg & 0xFE)) 284 reg = 0; 285 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); 286 287 sdio_release_host(gInstance->func[0]); 288 if (err) { 289 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); 290 return SDIOH_API_RC_FAIL; 291 } 292 } 293 return SDIOH_API_RC_SUCCESS; 294} 295#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ 296 297/* Configure callback to client when we recieve client interrupt */ 298extern SDIOH_API_RC 299sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) 300{ 301 sd_trace(("%s: Entering\n", __FUNCTION__)); 302 if (fn == NULL) { 303 sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__)); 304 return SDIOH_API_RC_FAIL; 305 } 306#if !defined(OOB_INTR_ONLY) 307 sd->intr_handler = fn; 308 sd->intr_handler_arg = argh; 309 sd->intr_handler_valid = TRUE; 310 311 /* register and unmask irq */ 312 if (gInstance->func[2]) { 313 sdio_claim_host(gInstance->func[2]); 314 sdio_claim_irq(gInstance->func[2], IRQHandlerF2); 315 sdio_release_host(gInstance->func[2]); 316 } 317 318 if (gInstance->func[1]) { 319 sdio_claim_host(gInstance->func[1]); 320 sdio_claim_irq(gInstance->func[1], IRQHandler); 321 sdio_release_host(gInstance->func[1]); 322 } 323#elif defined(HW_OOB) 324 sdioh_enable_func_intr(); 325#endif /* !defined(OOB_INTR_ONLY) */ 326 327 return SDIOH_API_RC_SUCCESS; 328} 329 330extern SDIOH_API_RC 331sdioh_interrupt_deregister(sdioh_info_t *sd) 332{ 333 sd_trace(("%s: Entering\n", __FUNCTION__)); 334 335#if !defined(OOB_INTR_ONLY) 336 if (gInstance->func[1]) { 337 /* register and unmask irq */ 338 sdio_claim_host(gInstance->func[1]); 339 sdio_release_irq(gInstance->func[1]); 340 sdio_release_host(gInstance->func[1]); 341 } 342 343 if (gInstance->func[2]) { 344 /* Claim host controller F2 */ 345 sdio_claim_host(gInstance->func[2]); 346 sdio_release_irq(gInstance->func[2]); 347 /* Release host controller F2 */ 348 sdio_release_host(gInstance->func[2]); 349 } 350 351 sd->intr_handler_valid = FALSE; 352 sd->intr_handler = NULL; 353 sd->intr_handler_arg = NULL; 354#elif defined(HW_OOB) 355 sdioh_disable_func_intr(); 356#endif /* !defined(OOB_INTR_ONLY) */ 357 return SDIOH_API_RC_SUCCESS; 358} 359 360extern SDIOH_API_RC 361sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) 362{ 363 sd_trace(("%s: Entering\n", __FUNCTION__)); 364 *onoff = sd->client_intr_enabled; 365 return SDIOH_API_RC_SUCCESS; 366} 367 368#if defined(DHD_DEBUG) 369extern bool 370sdioh_interrupt_pending(sdioh_info_t *sd) 371{ 372 return (0); 373} 374#endif 375 376uint 377sdioh_query_iofnum(sdioh_info_t *sd) 378{ 379 return sd->num_funcs; 380} 381 382/* IOVar table */ 383enum { 384 IOV_MSGLEVEL = 1, 385 IOV_BLOCKMODE, 386 IOV_BLOCKSIZE, 387 IOV_DMA, 388 IOV_USEINTS, 389 IOV_NUMINTS, 390 IOV_NUMLOCALINTS, 391 IOV_HOSTREG, 392 IOV_DEVREG, 393 IOV_DIVISOR, 394 IOV_SDMODE, 395 IOV_HISPEED, 396 IOV_HCIREGS, 397 IOV_POWER, 398 IOV_CLOCK, 399 IOV_RXCHAIN 400}; 401 402const bcm_iovar_t sdioh_iovars[] = { 403 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, 404 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, 405 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ 406 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, 407 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, 408 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, 409 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, 410 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, 411 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, 412 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, 413 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, 414 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, 415 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, 416 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 }, 417 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 }, 418 {NULL, 0, 0, 0, 0 } 419}; 420 421int 422sdioh_iovar_op(sdioh_info_t *si, const char *name, 423 void *params, int plen, void *arg, int len, bool set) 424{ 425 const bcm_iovar_t *vi = NULL; 426 int bcmerror = 0; 427 int val_size; 428 int32 int_val = 0; 429 bool bool_val; 430 uint32 actionid; 431 432 ASSERT(name); 433 ASSERT(len >= 0); 434 435 /* Get must have return space; Set does not take qualifiers */ 436 ASSERT(set || (arg && len)); 437 ASSERT(!set || (!params && !plen)); 438 439 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); 440 441 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { 442 bcmerror = BCME_UNSUPPORTED; 443 goto exit; 444 } 445 446 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) 447 goto exit; 448 449 /* Set up params so get and set can share the convenience variables */ 450 if (params == NULL) { 451 params = arg; 452 plen = len; 453 } 454 455 if (vi->type == IOVT_VOID) 456 val_size = 0; 457 else if (vi->type == IOVT_BUFFER) 458 val_size = len; 459 else 460 val_size = sizeof(int); 461 462 if (plen >= (int)sizeof(int_val)) 463 bcopy(params, &int_val, sizeof(int_val)); 464 465 bool_val = (int_val != 0) ? TRUE : FALSE; 466 BCM_REFERENCE(bool_val); 467 468 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); 469 switch (actionid) { 470 case IOV_GVAL(IOV_MSGLEVEL): 471 int_val = (int32)sd_msglevel; 472 bcopy(&int_val, arg, val_size); 473 break; 474 475 case IOV_SVAL(IOV_MSGLEVEL): 476 sd_msglevel = int_val; 477 break; 478 479 case IOV_GVAL(IOV_BLOCKMODE): 480 int_val = (int32)si->sd_blockmode; 481 bcopy(&int_val, arg, val_size); 482 break; 483 484 case IOV_SVAL(IOV_BLOCKMODE): 485 si->sd_blockmode = (bool)int_val; 486 /* Haven't figured out how to make non-block mode with DMA */ 487 break; 488 489 case IOV_GVAL(IOV_BLOCKSIZE): 490 if ((uint32)int_val > si->num_funcs) { 491 bcmerror = BCME_BADARG; 492 break; 493 } 494 int_val = (int32)si->client_block_size[int_val]; 495 bcopy(&int_val, arg, val_size); 496 break; 497 498 case IOV_SVAL(IOV_BLOCKSIZE): 499 { 500 uint func = ((uint32)int_val >> 16); 501 uint blksize = (uint16)int_val; 502 uint maxsize; 503 504 if (func > si->num_funcs) { 505 bcmerror = BCME_BADARG; 506 break; 507 } 508 509 switch (func) { 510 case 0: maxsize = 32; break; 511 case 1: maxsize = BLOCK_SIZE_4318; break; 512 case 2: maxsize = BLOCK_SIZE_4328; break; 513 default: maxsize = 0; 514 } 515 if (blksize > maxsize) { 516 bcmerror = BCME_BADARG; 517 break; 518 } 519 if (!blksize) { 520 blksize = maxsize; 521 } 522 523 /* Now set it */ 524 si->client_block_size[func] = blksize; 525 526 break; 527 } 528 529 case IOV_GVAL(IOV_RXCHAIN): 530 int_val = (int32)si->use_rxchain; 531 bcopy(&int_val, arg, val_size); 532 break; 533 534 case IOV_GVAL(IOV_DMA): 535 int_val = (int32)si->sd_use_dma; 536 bcopy(&int_val, arg, val_size); 537 break; 538 539 case IOV_SVAL(IOV_DMA): 540 si->sd_use_dma = (bool)int_val; 541 break; 542 543 case IOV_GVAL(IOV_USEINTS): 544 int_val = (int32)si->use_client_ints; 545 bcopy(&int_val, arg, val_size); 546 break; 547 548 case IOV_SVAL(IOV_USEINTS): 549 si->use_client_ints = (bool)int_val; 550 if (si->use_client_ints) 551 si->intmask |= CLIENT_INTR; 552 else 553 si->intmask &= ~CLIENT_INTR; 554 555 break; 556 557 case IOV_GVAL(IOV_DIVISOR): 558 int_val = (uint32)sd_divisor; 559 bcopy(&int_val, arg, val_size); 560 break; 561 562 case IOV_SVAL(IOV_DIVISOR): 563 sd_divisor = int_val; 564 break; 565 566 case IOV_GVAL(IOV_POWER): 567 int_val = (uint32)sd_power; 568 bcopy(&int_val, arg, val_size); 569 break; 570 571 case IOV_SVAL(IOV_POWER): 572 sd_power = int_val; 573 break; 574 575 case IOV_GVAL(IOV_CLOCK): 576 int_val = (uint32)sd_clock; 577 bcopy(&int_val, arg, val_size); 578 break; 579 580 case IOV_SVAL(IOV_CLOCK): 581 sd_clock = int_val; 582 break; 583 584 case IOV_GVAL(IOV_SDMODE): 585 int_val = (uint32)sd_sdmode; 586 bcopy(&int_val, arg, val_size); 587 break; 588 589 case IOV_SVAL(IOV_SDMODE): 590 sd_sdmode = int_val; 591 break; 592 593 case IOV_GVAL(IOV_HISPEED): 594 int_val = (uint32)sd_hiok; 595 bcopy(&int_val, arg, val_size); 596 break; 597 598 case IOV_SVAL(IOV_HISPEED): 599 sd_hiok = int_val; 600 break; 601 602 case IOV_GVAL(IOV_NUMINTS): 603 int_val = (int32)si->intrcount; 604 bcopy(&int_val, arg, val_size); 605 break; 606 607 case IOV_GVAL(IOV_NUMLOCALINTS): 608 int_val = (int32)0; 609 bcopy(&int_val, arg, val_size); 610 break; 611 612 case IOV_GVAL(IOV_HOSTREG): 613 { 614 sdreg_t *sd_ptr = (sdreg_t *)params; 615 616 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { 617 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); 618 bcmerror = BCME_BADARG; 619 break; 620 } 621 622 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__, 623 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), 624 sd_ptr->offset)); 625 if (sd_ptr->offset & 1) 626 int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ 627 else if (sd_ptr->offset & 2) 628 int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ 629 else 630 int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ 631 632 bcopy(&int_val, arg, sizeof(int_val)); 633 break; 634 } 635 636 case IOV_SVAL(IOV_HOSTREG): 637 { 638 sdreg_t *sd_ptr = (sdreg_t *)params; 639 640 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { 641 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); 642 bcmerror = BCME_BADARG; 643 break; 644 } 645 646 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, 647 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), 648 sd_ptr->offset)); 649 break; 650 } 651 652 case IOV_GVAL(IOV_DEVREG): 653 { 654 sdreg_t *sd_ptr = (sdreg_t *)params; 655 uint8 data = 0; 656 657 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { 658 bcmerror = BCME_SDIO_ERROR; 659 break; 660 } 661 662 int_val = (int)data; 663 bcopy(&int_val, arg, sizeof(int_val)); 664 break; 665 } 666 667 case IOV_SVAL(IOV_DEVREG): 668 { 669 sdreg_t *sd_ptr = (sdreg_t *)params; 670 uint8 data = (uint8)sd_ptr->value; 671 672 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { 673 bcmerror = BCME_SDIO_ERROR; 674 break; 675 } 676 break; 677 } 678 679 default: 680 bcmerror = BCME_UNSUPPORTED; 681 break; 682 } 683exit: 684 685 return bcmerror; 686} 687 688#if defined(OOB_INTR_ONLY) && defined(HW_OOB) 689 690SDIOH_API_RC 691sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) 692{ 693 SDIOH_API_RC status; 694 uint8 data; 695 696 if (enable) 697 data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; 698 else 699 data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ 700 701 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); 702 return status; 703} 704#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ 705 706extern SDIOH_API_RC 707sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) 708{ 709 SDIOH_API_RC status; 710 /* No lock needed since sdioh_request_byte does locking */ 711 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); 712 return status; 713} 714 715extern SDIOH_API_RC 716sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) 717{ 718 /* No lock needed since sdioh_request_byte does locking */ 719 SDIOH_API_RC status; 720 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); 721 return status; 722} 723 724static int 725sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) 726{ 727 /* read 24 bits and return valid 17 bit addr */ 728 int i; 729 uint32 scratch, regdata; 730 uint8 *ptr = (uint8 *)&scratch; 731 for (i = 0; i < 3; i++) { 732 if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) 733 sd_err(("%s: Can't read!\n", __FUNCTION__)); 734 735 *ptr++ = (uint8) regdata; 736 regaddr++; 737 } 738 739 /* Only the lower 17-bits are valid */ 740 scratch = ltoh32(scratch); 741 scratch &= 0x0001FFFF; 742 return (scratch); 743} 744 745extern SDIOH_API_RC 746sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) 747{ 748 uint32 count; 749 int offset; 750 uint32 foo; 751 uint8 *cis = cisd; 752 753 sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); 754 755 if (!sd->func_cis_ptr[func]) { 756 bzero(cis, length); 757 sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); 758 return SDIOH_API_RC_FAIL; 759 } 760 761 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); 762 763 for (count = 0; count < length; count++) { 764 offset = sd->func_cis_ptr[func] + count; 765 if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { 766 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); 767 return SDIOH_API_RC_FAIL; 768 } 769 770 *cis = (uint8)(foo & 0xff); 771 cis++; 772 } 773 774 return SDIOH_API_RC_SUCCESS; 775} 776 777extern SDIOH_API_RC 778sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) 779{ 780 int err_ret; 781 782 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); 783 784 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); 785 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); 786 if(rw) { /* CMD52 Write */ 787 if (func == 0) { 788 /* Can only directly write to some F0 registers. Handle F2 enable 789 * as a special case. 790 */ 791 if (regaddr == SDIOD_CCCR_IOEN) { 792 if (gInstance->func[2]) { 793 sdio_claim_host(gInstance->func[2]); 794 if (*byte & SDIO_FUNC_ENABLE_2) { 795 /* Enable Function 2 */ 796 err_ret = sdio_enable_func(gInstance->func[2]); 797 if (err_ret) { 798 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d", 799 err_ret)); 800 } 801 } else { 802 /* Disable Function 2 */ 803 err_ret = sdio_disable_func(gInstance->func[2]); 804 if (err_ret) { 805 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d", 806 err_ret)); 807 } 808 } 809 sdio_release_host(gInstance->func[2]); 810 } 811 } 812#if defined(MMC_SDIO_ABORT) 813 /* to allow abort command through F1 */ 814 else if (regaddr == SDIOD_CCCR_IOABORT) { 815 if (gInstance->func[func]) { 816 sdio_claim_host(gInstance->func[func]); 817 /* 818 * this sdio_f0_writeb() can be replaced with another api 819 * depending upon MMC driver change. 820 * As of this time, this is temporaray one 821 */ 822 sdio_writeb(gInstance->func[func], 823 *byte, regaddr, &err_ret); 824 sdio_release_host(gInstance->func[func]); 825 } 826 } 827#endif /* MMC_SDIO_ABORT */ 828 else if (regaddr < 0xF0) { 829 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); 830 } else { 831 /* Claim host controller, perform F0 write, and release */ 832 if (gInstance->func[func]) { 833 sdio_claim_host(gInstance->func[func]); 834 sdio_f0_writeb(gInstance->func[func], 835 *byte, regaddr, &err_ret); 836 sdio_release_host(gInstance->func[func]); 837 } 838 } 839 } else { 840 /* Claim host controller, perform Fn write, and release */ 841 if (gInstance->func[func]) { 842 sdio_claim_host(gInstance->func[func]); 843 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); 844 sdio_release_host(gInstance->func[func]); 845 } 846 } 847 } else { /* CMD52 Read */ 848 /* Claim host controller, perform Fn read, and release */ 849 if (gInstance->func[func]) { 850 sdio_claim_host(gInstance->func[func]); 851 if (func == 0) { 852 *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret); 853 } else { 854 *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret); 855 } 856 sdio_release_host(gInstance->func[func]); 857 } 858 } 859 860 if (err_ret) { 861 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", 862 rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); 863 } 864 865 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); 866} 867 868extern SDIOH_API_RC 869sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, 870 uint32 *word, uint nbytes) 871{ 872 int err_ret = SDIOH_API_RC_FAIL; 873 874 if (func == 0) { 875 sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); 876 return SDIOH_API_RC_FAIL; 877 } 878 879 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", 880 __FUNCTION__, cmd_type, rw, func, addr, nbytes)); 881 882 DHD_PM_RESUME_WAIT(sdioh_request_word_wait); 883 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); 884 /* Claim host controller */ 885 sdio_claim_host(gInstance->func[func]); 886 887 if(rw) { /* CMD52 Write */ 888 if (nbytes == 4) { 889 sdio_writel(gInstance->func[func], *word, addr, &err_ret); 890 } else if (nbytes == 2) { 891 sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret); 892 } else { 893 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); 894 } 895 } else { /* CMD52 Read */ 896 if (nbytes == 4) { 897 *word = sdio_readl(gInstance->func[func], addr, &err_ret); 898 } else if (nbytes == 2) { 899 *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF; 900 } else { 901 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); 902 } 903 } 904 905 /* Release host controller */ 906 sdio_release_host(gInstance->func[func]); 907 908 if (err_ret) { 909 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x", 910 rw ? "Write" : "Read", err_ret)); 911 } 912 913 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); 914} 915 916static SDIOH_API_RC 917sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, 918 uint addr, void *pkt) 919{ 920 bool fifo = (fix_inc == SDIOH_DATA_FIX); 921 uint32 SGCount = 0; 922 int err_ret = 0; 923 void *pnext, *pprev; 924 uint ttl_len, dma_len, lft_len, xfred_len, pkt_len; 925 uint blk_num; 926 struct mmc_request mmc_req; 927 struct mmc_command mmc_cmd; 928 struct mmc_data mmc_dat; 929 930 sd_trace(("%s: Enter\n", __FUNCTION__)); 931 932 ASSERT(pkt); 933 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); 934 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); 935 936 ttl_len = xfred_len = 0; 937 /* at least 4 bytes alignment of skb buff is guaranteed */ 938 for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) 939 ttl_len += PKTLEN(sd->osh, pnext); 940 941 if (!sd->use_rxchain || ttl_len <= sd->client_block_size[func]) { 942 blk_num = 0; 943 dma_len = 0; 944 } else { 945 blk_num = ttl_len / sd->client_block_size[func]; 946 dma_len = blk_num * sd->client_block_size[func]; 947 } 948 lft_len = ttl_len - dma_len; 949 950 sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n", 951 __FUNCTION__, write ? "W" : "R", 952 ttl_len, func, addr, blk_num, lft_len)); 953 954 if (0 != dma_len) { 955 memset(&mmc_req, 0, sizeof(struct mmc_request)); 956 memset(&mmc_cmd, 0, sizeof(struct mmc_command)); 957 memset(&mmc_dat, 0, sizeof(struct mmc_data)); 958 959 /* Set up DMA descriptors */ 960 pprev = pkt; 961 for (pnext = pkt; 962 pnext && dma_len; 963 pnext = PKTNEXT(sd->osh, pnext)) { 964 pkt_len = PKTLEN(sd->osh, pnext); 965 966 if (dma_len > pkt_len) 967 dma_len -= pkt_len; 968 else { 969 pkt_len = xfred_len = dma_len; 970 dma_len = 0; 971 pkt = pnext; 972 } 973 974 sg_set_buf(&sd->sg_list[SGCount++], 975 (uint8*)PKTDATA(sd->osh, pnext), 976 pkt_len); 977 978 if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) { 979 sd_err(("%s: sg list entries exceed limit\n", 980 __FUNCTION__)); 981 return (SDIOH_API_RC_FAIL); 982 } 983 } 984 985 mmc_dat.sg = sd->sg_list; 986 mmc_dat.sg_len = SGCount; 987 mmc_dat.blksz = sd->client_block_size[func]; 988 mmc_dat.blocks = blk_num; 989 mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; 990 991 mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ 992 mmc_cmd.arg = write ? 1<<31 : 0; 993 mmc_cmd.arg |= (func & 0x7) << 28; 994 mmc_cmd.arg |= 1<<27; 995 mmc_cmd.arg |= fifo ? 0 : 1<<26; 996 mmc_cmd.arg |= (addr & 0x1FFFF) << 9; 997 mmc_cmd.arg |= blk_num & 0x1FF; 998 mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; 999 1000 mmc_req.cmd = &mmc_cmd; 1001 mmc_req.data = &mmc_dat; 1002 1003 sdio_claim_host(gInstance->func[func]); 1004 mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card); 1005 mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req); 1006 sdio_release_host(gInstance->func[func]); 1007 1008 err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; 1009 if (0 != err_ret) { 1010 sd_err(("%s:CMD53 %s failed with code %d\n", 1011 __FUNCTION__, 1012 write ? "write" : "read", 1013 err_ret)); 1014 sd_err(("%s:Disabling rxchain and fire it with PIO\n", 1015 __FUNCTION__)); 1016 sd->use_rxchain = FALSE; 1017 pkt = pprev; 1018 lft_len = ttl_len; 1019 } else if (!fifo) { 1020 addr = addr + ttl_len - lft_len - dma_len; 1021 } 1022 } 1023 1024 /* PIO mode */ 1025 if (0 != lft_len) { 1026 /* Claim host controller */ 1027 sdio_claim_host(gInstance->func[func]); 1028 for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { 1029 uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) + 1030 xfred_len; 1031 pkt_len = PKTLEN(sd->osh, pnext); 1032 if (0 != xfred_len) { 1033 pkt_len -= xfred_len; 1034 xfred_len = 0; 1035 } 1036 1037 /* Align Patch 1038 * read or small packet(ex:BDC header) skip 32 byte align 1039 * otherwise, padding DHD_SDALIGN for performance 1040 */ 1041 if (write == 0 || pkt_len < 32) 1042 pkt_len = (pkt_len + 3) & 0xFFFFFFFC; 1043 else if (pkt_len % DHD_SDALIGN) 1044 pkt_len += DHD_SDALIGN - (pkt_len % DHD_SDALIGN); 1045 1046#ifdef CONFIG_MMC_MSM7X00A 1047 if ((pkt_len % 64) == 32) { 1048 sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); 1049 pkt_len += 32; 1050 } 1051#endif /* CONFIG_MMC_MSM7X00A */ 1052 1053 if ((write) && (!fifo)) 1054 err_ret = sdio_memcpy_toio( 1055 gInstance->func[func], 1056 addr, buf, pkt_len); 1057 else if (write) 1058 err_ret = sdio_memcpy_toio( 1059 gInstance->func[func], 1060 addr, buf, pkt_len); 1061 else if (fifo) 1062 err_ret = sdio_readsb( 1063 gInstance->func[func], 1064 buf, addr, pkt_len); 1065 else 1066 err_ret = sdio_memcpy_fromio( 1067 gInstance->func[func], 1068 buf, addr, pkt_len); 1069 1070 if (err_ret) 1071 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n", 1072 __FUNCTION__, 1073 (write) ? "TX" : "RX", 1074 pnext, SGCount, addr, pkt_len, err_ret)); 1075 else 1076 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", 1077 __FUNCTION__, 1078 (write) ? "TX" : "RX", 1079 pnext, SGCount, addr, pkt_len)); 1080 1081 if (!fifo) 1082 addr += pkt_len; 1083 SGCount ++; 1084 } 1085 sdio_release_host(gInstance->func[func]); 1086 } 1087 1088 sd_trace(("%s: Exit\n", __FUNCTION__)); 1089 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); 1090} 1091 1092 1093/* 1094 * This function takes a buffer or packet, and fixes everything up so that in the 1095 * end, a DMA-able packet is created. 1096 * 1097 * A buffer does not have an associated packet pointer, and may or may not be aligned. 1098 * A packet may consist of a single packet, or a packet chain. If it is a packet chain, 1099 * then all the packets in the chain must be properly aligned. If the packet data is not 1100 * aligned, then there may only be one packet, and in this case, it is copied to a new 1101 * aligned packet. 1102 * 1103 */ 1104extern SDIOH_API_RC 1105sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, 1106 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) 1107{ 1108 SDIOH_API_RC Status; 1109 void *mypkt = NULL; 1110 1111 sd_trace(("%s: Enter\n", __FUNCTION__)); 1112 1113 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); 1114 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); 1115 /* Case 1: we don't have a packet. */ 1116 if (pkt == NULL) { 1117 sd_data(("%s: Creating new %s Packet, len=%d\n", 1118 __FUNCTION__, write ? "TX" : "RX", buflen_u)); 1119#ifdef CONFIG_DHD_USE_STATIC_BUF 1120 if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) { 1121#else 1122 if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) { 1123#endif /* CONFIG_DHD_USE_STATIC_BUF */ 1124 sd_err(("%s: PKTGET failed: len %d\n", 1125 __FUNCTION__, buflen_u)); 1126 return SDIOH_API_RC_FAIL; 1127 } 1128 1129 /* For a write, copy the buffer data into the packet. */ 1130 if (write) { 1131 bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u); 1132 } 1133 1134 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); 1135 1136 /* For a read, copy the packet data back to the buffer. */ 1137 if (!write) { 1138 bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u); 1139 } 1140#ifdef CONFIG_DHD_USE_STATIC_BUF 1141 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); 1142#else 1143 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); 1144#endif /* CONFIG_DHD_USE_STATIC_BUF */ 1145 } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { 1146 /* Case 2: We have a packet, but it is unaligned. */ 1147 1148 /* In this case, we cannot have a chain. */ 1149 ASSERT(PKTNEXT(sd->osh, pkt) == NULL); 1150 1151 sd_data(("%s: Creating aligned %s Packet, len=%d\n", 1152 __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt))); 1153#ifdef CONFIG_DHD_USE_STATIC_BUF 1154 if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { 1155#else 1156 if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { 1157#endif /* CONFIG_DHD_USE_STATIC_BUF */ 1158 sd_err(("%s: PKTGET failed: len %d\n", 1159 __FUNCTION__, PKTLEN(sd->osh, pkt))); 1160 return SDIOH_API_RC_FAIL; 1161 } 1162 1163 /* For a write, copy the buffer data into the packet. */ 1164 if (write) { 1165 bcopy(PKTDATA(sd->osh, pkt), 1166 PKTDATA(sd->osh, mypkt), 1167 PKTLEN(sd->osh, pkt)); 1168 } 1169 1170 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); 1171 1172 /* For a read, copy the packet data back to the buffer. */ 1173 if (!write) { 1174 bcopy(PKTDATA(sd->osh, mypkt), 1175 PKTDATA(sd->osh, pkt), 1176 PKTLEN(sd->osh, mypkt)); 1177 } 1178#ifdef CONFIG_DHD_USE_STATIC_BUF 1179 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); 1180#else 1181 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); 1182#endif /* CONFIG_DHD_USE_STATIC_BUF */ 1183 } else { /* case 3: We have a packet and it is aligned. */ 1184 sd_data(("%s: Aligned %s Packet, direct DMA\n", 1185 __FUNCTION__, write ? "Tx" : "Rx")); 1186 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt); 1187 } 1188 1189 return (Status); 1190} 1191 1192/* this function performs "abort" for both of host & device */ 1193extern int 1194sdioh_abort(sdioh_info_t *sd, uint func) 1195{ 1196#if defined(MMC_SDIO_ABORT) 1197 char t_func = (char) func; 1198#endif /* defined(MMC_SDIO_ABORT) */ 1199 sd_trace(("%s: Enter\n", __FUNCTION__)); 1200 1201#if defined(MMC_SDIO_ABORT) 1202 /* issue abort cmd52 command through F1 */ 1203 sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); 1204#endif /* defined(MMC_SDIO_ABORT) */ 1205 1206 sd_trace(("%s: Exit\n", __FUNCTION__)); 1207 return SDIOH_API_RC_SUCCESS; 1208} 1209 1210/* Reset and re-initialize the device */ 1211int sdioh_sdio_reset(sdioh_info_t *si) 1212{ 1213 sd_trace(("%s: Enter\n", __FUNCTION__)); 1214 sd_trace(("%s: Exit\n", __FUNCTION__)); 1215 return SDIOH_API_RC_SUCCESS; 1216} 1217 1218/* Disable device interrupt */ 1219void 1220sdioh_sdmmc_devintr_off(sdioh_info_t *sd) 1221{ 1222 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); 1223 sd->intmask &= ~CLIENT_INTR; 1224} 1225 1226/* Enable device interrupt */ 1227void 1228sdioh_sdmmc_devintr_on(sdioh_info_t *sd) 1229{ 1230 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); 1231 sd->intmask |= CLIENT_INTR; 1232} 1233 1234/* Read client card reg */ 1235int 1236sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) 1237{ 1238 1239 if ((func == 0) || (regsize == 1)) { 1240 uint8 temp = 0; 1241 1242 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); 1243 *data = temp; 1244 *data &= 0xff; 1245 sd_data(("%s: byte read data=0x%02x\n", 1246 __FUNCTION__, *data)); 1247 } else { 1248 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize); 1249 if (regsize == 2) 1250 *data &= 0xffff; 1251 1252 sd_data(("%s: word read data=0x%08x\n", 1253 __FUNCTION__, *data)); 1254 } 1255 1256 return SUCCESS; 1257} 1258 1259#if !defined(OOB_INTR_ONLY) 1260/* bcmsdh_sdmmc interrupt handler */ 1261static void IRQHandler(struct sdio_func *func) 1262{ 1263 sdioh_info_t *sd; 1264 1265 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n")); 1266 sd = gInstance->sd; 1267 1268 ASSERT(sd != NULL); 1269 sdio_release_host(gInstance->func[0]); 1270 1271 if (sd->use_client_ints) { 1272 sd->intrcount++; 1273 ASSERT(sd->intr_handler); 1274 ASSERT(sd->intr_handler_arg); 1275 (sd->intr_handler)(sd->intr_handler_arg); 1276 } else { 1277 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n")); 1278 1279 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", 1280 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); 1281 } 1282 1283 sdio_claim_host(gInstance->func[0]); 1284} 1285 1286/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ 1287static void IRQHandlerF2(struct sdio_func *func) 1288{ 1289 sdioh_info_t *sd; 1290 1291 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n")); 1292 1293 sd = gInstance->sd; 1294 1295 ASSERT(sd != NULL); 1296 BCM_REFERENCE(sd); 1297} 1298#endif /* !defined(OOB_INTR_ONLY) */ 1299 1300#ifdef NOTUSED 1301/* Write client card reg */ 1302static int 1303sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) 1304{ 1305 1306 if ((func == 0) || (regsize == 1)) { 1307 uint8 temp; 1308 1309 temp = data & 0xff; 1310 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); 1311 sd_data(("%s: byte write data=0x%02x\n", 1312 __FUNCTION__, data)); 1313 } else { 1314 if (regsize == 2) 1315 data &= 0xffff; 1316 1317 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); 1318 1319 sd_data(("%s: word write data=0x%08x\n", 1320 __FUNCTION__, data)); 1321 } 1322 1323 return SUCCESS; 1324} 1325#endif /* NOTUSED */ 1326 1327int 1328sdioh_start(sdioh_info_t *si, int stage) 1329{ 1330 int ret; 1331 sdioh_info_t *sd = gInstance->sd; 1332 1333 if (!sd) return (0); 1334 1335 /* Need to do this stages as we can't enable the interrupt till 1336 downloading of the firmware is complete, other wise polling 1337 sdio access will come in way 1338 */ 1339 if (gInstance->func[0]) { 1340 if (stage == 0) { 1341 /* Since the power to the chip is killed, we will have 1342 re enumerate the device again. Set the block size 1343 and enable the fucntion 1 for in preparation for 1344 downloading the code 1345 */ 1346 /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux 1347 2.6.27. The implementation prior to that is buggy, and needs broadcom's 1348 patch for it 1349 */ 1350 if ((ret = sdio_reset_comm(gInstance->func[0]->card))) { 1351 sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); 1352 return ret; 1353 } 1354 else { 1355 sd->num_funcs = 2; 1356 sd->sd_blockmode = TRUE; 1357 sd->use_client_ints = TRUE; 1358 sd->client_block_size[0] = 64; 1359 1360 if (gInstance->func[1]) { 1361 /* Claim host controller */ 1362 sdio_claim_host(gInstance->func[1]); 1363 1364 sd->client_block_size[1] = 64; 1365 if (sdio_set_block_size(gInstance->func[1], 64)) { 1366 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); 1367 } 1368 1369 /* Release host controller F1 */ 1370 sdio_release_host(gInstance->func[1]); 1371 } 1372 1373 if (gInstance->func[2]) { 1374 /* Claim host controller F2 */ 1375 sdio_claim_host(gInstance->func[2]); 1376 1377 sd->client_block_size[2] = sd_f2_blocksize; 1378 if (sdio_set_block_size(gInstance->func[2], 1379 sd_f2_blocksize)) { 1380 sd_err(("bcmsdh_sdmmc: Failed to set F2 " 1381 "blocksize to %d\n", sd_f2_blocksize)); 1382 } 1383 1384 /* Release host controller F2 */ 1385 sdio_release_host(gInstance->func[2]); 1386 } 1387 1388 sdioh_sdmmc_card_enablefuncs(sd); 1389 } 1390 } else { 1391#if !defined(OOB_INTR_ONLY) 1392 sdio_claim_host(gInstance->func[0]); 1393 if (gInstance->func[2]) 1394 sdio_claim_irq(gInstance->func[2], IRQHandlerF2); 1395 if (gInstance->func[1]) 1396 sdio_claim_irq(gInstance->func[1], IRQHandler); 1397 sdio_release_host(gInstance->func[0]); 1398#else /* defined(OOB_INTR_ONLY) */ 1399#if defined(HW_OOB) 1400 sdioh_enable_func_intr(); 1401#endif 1402 bcmsdh_oob_intr_set(TRUE); 1403#endif /* !defined(OOB_INTR_ONLY) */ 1404 } 1405 } 1406 else 1407 sd_err(("%s Failed\n", __FUNCTION__)); 1408 1409 return (0); 1410} 1411 1412int 1413sdioh_stop(sdioh_info_t *si) 1414{ 1415 /* MSM7201A Android sdio stack has bug with interrupt 1416 So internaly within SDIO stack they are polling 1417 which cause issue when device is turned off. So 1418 unregister interrupt with SDIO stack to stop the 1419 polling 1420 */ 1421 if (gInstance->func[0]) { 1422#if !defined(OOB_INTR_ONLY) 1423 sdio_claim_host(gInstance->func[0]); 1424 if (gInstance->func[1]) 1425 sdio_release_irq(gInstance->func[1]); 1426 if (gInstance->func[2]) 1427 sdio_release_irq(gInstance->func[2]); 1428 sdio_release_host(gInstance->func[0]); 1429#else /* defined(OOB_INTR_ONLY) */ 1430#if defined(HW_OOB) 1431 sdioh_disable_func_intr(); 1432#endif 1433 bcmsdh_oob_intr_set(FALSE); 1434#endif /* !defined(OOB_INTR_ONLY) */ 1435 } 1436 else 1437 sd_err(("%s Failed\n", __FUNCTION__)); 1438 return (0); 1439} 1440 1441int 1442sdioh_waitlockfree(sdioh_info_t *sd) 1443{ 1444 return (1); 1445} 1446 1447 1448SDIOH_API_RC 1449sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) 1450{ 1451 return SDIOH_API_RC_FAIL; 1452} 1453 1454SDIOH_API_RC 1455sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) 1456{ 1457 return SDIOH_API_RC_FAIL; 1458} 1459 1460bool 1461sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) 1462{ 1463 return FALSE; 1464} 1465 1466SDIOH_API_RC 1467sdioh_gpio_init(sdioh_info_t *sd) 1468{ 1469 return SDIOH_API_RC_FAIL; 1470} 1471