2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
4 * Copyright (C) 1999-2011, Broadcom Corporation
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:
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.
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.
24 * $Id: bcmsdh_sdmmc.c,v 1.14.64.3 2010-12-23 01:13:15 $
29 #include <bcmendian.h>
32 #include <sdio.h> /* SDIO Device and Protocol Specs */
33 #include <sdioh.h> /* SDIO Host Controller Specification */
34 #include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
35 #include <sdiovar.h> /* ioctl/iovars */
37 #include <linux/mmc/core.h>
38 #include <linux/mmc/card.h>
39 #include <linux/mmc/host.h>
40 #include <linux/mmc/sdio_func.h>
41 #include <linux/mmc/sdio_ids.h>
43 #include <dngl_stats.h>
46 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && !defined(BRCM_SUSPEND)
47 #include <linux/suspend.h>
48 extern volatile bool dhd_mmc_suspend;
49 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && !defined(BRCM_SUSPEND) */
50 #include "bcmsdh_sdmmc.h"
53 extern int sdio_function_init(void);
54 extern void sdio_function_cleanup(void);
55 #endif /* BCMSDH_MODULE */
57 #if !defined(OOB_INTR_ONLY)
58 static void IRQHandler(struct sdio_func *func);
59 static void IRQHandlerF2(struct sdio_func *func);
60 #endif /* !defined(OOB_INTR_ONLY) */
61 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
62 extern int sdio_reset_comm(struct mmc_card *card);
64 extern PBCMSDH_SDMMC_INSTANCE gInstance;
66 uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
67 uint sd_f2_blocksize = 512; /* Default blocksize */
69 uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
71 uint sd_power = 1; /* Default to SD Slot powered ON */
72 uint sd_clock = 1; /* Default to SD Clock turned ON */
73 uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */
74 uint sd_msglevel = 0x01;
75 uint sd_use_dma = TRUE;
76 DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
77 DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
78 DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
79 DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
81 #define DMA_ALIGN_MASK 0x03
83 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
86 sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
92 sd_trace(("%s\n", __FUNCTION__));
94 /* Get the Card's common CIS address */
95 sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
96 sd->func_cis_ptr[0] = sd->com_cis_ptr;
97 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
99 /* Get the Card's function CIS (for each function) */
100 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
101 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
102 sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
103 sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
104 __FUNCTION__, func, sd->func_cis_ptr[func]));
107 sd->func_cis_ptr[0] = sd->com_cis_ptr;
108 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
110 /* Enable Function 1 */
111 sdio_claim_host(gInstance->func[1]);
112 err_ret = sdio_enable_func(gInstance->func[1]);
113 sdio_release_host(gInstance->func[1]);
115 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret));
122 * Public entry points & extern's
124 extern sdioh_info_t *
125 sdioh_attach(osl_t *osh, void *bar0, uint irq)
130 sd_trace(("%s\n", __FUNCTION__));
132 if (gInstance == NULL) {
133 sd_err(("%s: SDIO Device not present\n", __FUNCTION__));
137 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
138 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
141 bzero((char *)sd, sizeof(sdioh_info_t));
143 if (sdioh_sdmmc_osinit(sd) != 0) {
144 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__));
145 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
150 sd->sd_blockmode = TRUE;
151 sd->use_client_ints = TRUE;
152 sd->client_block_size[0] = 64;
156 /* Claim host controller */
157 sdio_claim_host(gInstance->func[1]);
159 sd->client_block_size[1] = 64;
160 err_ret = sdio_set_block_size(gInstance->func[1], 64);
162 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
165 /* Release host controller F1 */
166 sdio_release_host(gInstance->func[1]);
168 if (gInstance->func[2]) {
169 /* Claim host controller F2 */
170 sdio_claim_host(gInstance->func[2]);
172 sd->client_block_size[2] = sd_f2_blocksize;
173 err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
175 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n",
179 /* Release host controller F2 */
180 sdio_release_host(gInstance->func[2]);
183 sdioh_sdmmc_card_enablefuncs(sd);
185 sd_trace(("%s: Done\n", __FUNCTION__));
191 sdioh_detach(osl_t *osh, sdioh_info_t *sd)
193 sd_trace(("%s\n", __FUNCTION__));
197 /* Disable Function 2 */
198 sdio_claim_host(gInstance->func[2]);
199 sdio_disable_func(gInstance->func[2]);
200 sdio_release_host(gInstance->func[2]);
202 /* Disable Function 1 */
203 sdio_claim_host(gInstance->func[1]);
204 sdio_disable_func(gInstance->func[1]);
205 sdio_release_host(gInstance->func[1]);
208 sdioh_sdmmc_osfree(sd);
210 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
212 return SDIOH_API_RC_SUCCESS;
215 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
218 sdioh_enable_func_intr(void)
223 if (gInstance->func[0]) {
224 sdio_claim_host(gInstance->func[0]);
226 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
228 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
229 sdio_release_host(gInstance->func[0]);
230 return SDIOH_API_RC_FAIL;
233 /* Enable F1 and F2 interrupts, set master enable */
234 reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN);
236 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
237 sdio_release_host(gInstance->func[0]);
240 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
241 return SDIOH_API_RC_FAIL;
245 return SDIOH_API_RC_SUCCESS;
249 sdioh_disable_func_intr(void)
254 if (gInstance->func[0]) {
255 sdio_claim_host(gInstance->func[0]);
256 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
258 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
259 sdio_release_host(gInstance->func[0]);
260 return SDIOH_API_RC_FAIL;
263 reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
264 /* Disable master interrupt with the last function interrupt */
267 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
269 sdio_release_host(gInstance->func[0]);
271 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
272 return SDIOH_API_RC_FAIL;
275 return SDIOH_API_RC_SUCCESS;
277 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
279 /* Configure callback to client when we recieve client interrupt */
281 sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
283 sd_trace(("%s: Entering\n", __FUNCTION__));
285 sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__));
286 return SDIOH_API_RC_FAIL;
288 #if !defined(OOB_INTR_ONLY)
289 sd->intr_handler = fn;
290 sd->intr_handler_arg = argh;
291 sd->intr_handler_valid = TRUE;
293 /* register and unmask irq */
294 if (gInstance->func[2]) {
295 sdio_claim_host(gInstance->func[2]);
296 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
297 sdio_release_host(gInstance->func[2]);
300 if (gInstance->func[1]) {
301 sdio_claim_host(gInstance->func[1]);
302 sdio_claim_irq(gInstance->func[1], IRQHandler);
303 sdio_release_host(gInstance->func[1]);
305 #elif defined(HW_OOB)
306 sdioh_enable_func_intr();
307 #endif /* !defined(OOB_INTR_ONLY) */
309 return SDIOH_API_RC_SUCCESS;
313 sdioh_interrupt_deregister(sdioh_info_t *sd)
315 sd_trace(("%s: Entering\n", __FUNCTION__));
317 #if !defined(OOB_INTR_ONLY)
318 if (gInstance->func[1]) {
319 /* register and unmask irq */
320 sdio_claim_host(gInstance->func[1]);
321 sdio_release_irq(gInstance->func[1]);
322 sdio_release_host(gInstance->func[1]);
325 if (gInstance->func[2]) {
326 /* Claim host controller F2 */
327 sdio_claim_host(gInstance->func[2]);
328 sdio_release_irq(gInstance->func[2]);
329 /* Release host controller F2 */
330 sdio_release_host(gInstance->func[2]);
333 sd->intr_handler_valid = FALSE;
334 sd->intr_handler = NULL;
335 sd->intr_handler_arg = NULL;
336 #elif defined(HW_OOB)
337 sdioh_disable_func_intr();
338 #endif /* !defined(OOB_INTR_ONLY) */
339 return SDIOH_API_RC_SUCCESS;
343 sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
345 sd_trace(("%s: Entering\n", __FUNCTION__));
346 *onoff = sd->client_intr_enabled;
347 return SDIOH_API_RC_SUCCESS;
350 #if defined(DHD_DEBUG)
352 sdioh_interrupt_pending(sdioh_info_t *sd)
359 sdioh_query_iofnum(sdioh_info_t *sd)
361 return sd->num_funcs;
384 const bcm_iovar_t sdioh_iovars[] = {
385 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
386 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 },
387 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
388 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 },
389 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
390 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
391 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
392 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
393 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
394 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
395 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
396 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
397 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
398 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 },
399 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 },
404 sdioh_iovar_op(sdioh_info_t *si, const char *name,
405 void *params, int plen, void *arg, int len, bool set)
407 const bcm_iovar_t *vi = NULL;
417 /* Get must have return space; Set does not take qualifiers */
418 ASSERT(set || (arg && len));
419 ASSERT(!set || (!params && !plen));
421 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
423 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
424 bcmerror = BCME_UNSUPPORTED;
428 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
431 /* Set up params so get and set can share the convenience variables */
432 if (params == NULL) {
437 if (vi->type == IOVT_VOID)
439 else if (vi->type == IOVT_BUFFER)
442 val_size = sizeof(int);
444 if (plen >= (int)sizeof(int_val))
445 bcopy(params, &int_val, sizeof(int_val));
447 bool_val = (int_val != 0) ? TRUE : FALSE;
449 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
451 case IOV_GVAL(IOV_MSGLEVEL):
452 int_val = (int32)sd_msglevel;
453 bcopy(&int_val, arg, val_size);
456 case IOV_SVAL(IOV_MSGLEVEL):
457 sd_msglevel = int_val;
460 case IOV_GVAL(IOV_BLOCKMODE):
461 int_val = (int32)si->sd_blockmode;
462 bcopy(&int_val, arg, val_size);
465 case IOV_SVAL(IOV_BLOCKMODE):
466 si->sd_blockmode = (bool)int_val;
467 /* Haven't figured out how to make non-block mode with DMA */
470 case IOV_GVAL(IOV_BLOCKSIZE):
471 if ((uint32)int_val > si->num_funcs) {
472 bcmerror = BCME_BADARG;
475 int_val = (int32)si->client_block_size[int_val];
476 bcopy(&int_val, arg, val_size);
479 case IOV_SVAL(IOV_BLOCKSIZE):
481 uint func = ((uint32)int_val >> 16);
482 uint blksize = (uint16)int_val;
485 if (func > si->num_funcs) {
486 bcmerror = BCME_BADARG;
491 case 0: maxsize = 32; break;
492 case 1: maxsize = BLOCK_SIZE_4318; break;
493 case 2: maxsize = BLOCK_SIZE_4328; break;
494 default: maxsize = 0;
496 if (blksize > maxsize) {
497 bcmerror = BCME_BADARG;
505 si->client_block_size[func] = blksize;
510 case IOV_GVAL(IOV_RXCHAIN):
512 bcopy(&int_val, arg, val_size);
515 case IOV_GVAL(IOV_DMA):
516 int_val = (int32)si->sd_use_dma;
517 bcopy(&int_val, arg, val_size);
520 case IOV_SVAL(IOV_DMA):
521 si->sd_use_dma = (bool)int_val;
524 case IOV_GVAL(IOV_USEINTS):
525 int_val = (int32)si->use_client_ints;
526 bcopy(&int_val, arg, val_size);
529 case IOV_SVAL(IOV_USEINTS):
530 si->use_client_ints = (bool)int_val;
531 if (si->use_client_ints)
532 si->intmask |= CLIENT_INTR;
534 si->intmask &= ~CLIENT_INTR;
538 case IOV_GVAL(IOV_DIVISOR):
539 int_val = (uint32)sd_divisor;
540 bcopy(&int_val, arg, val_size);
543 case IOV_SVAL(IOV_DIVISOR):
544 sd_divisor = int_val;
547 case IOV_GVAL(IOV_POWER):
548 int_val = (uint32)sd_power;
549 bcopy(&int_val, arg, val_size);
552 case IOV_SVAL(IOV_POWER):
556 case IOV_GVAL(IOV_CLOCK):
557 int_val = (uint32)sd_clock;
558 bcopy(&int_val, arg, val_size);
561 case IOV_SVAL(IOV_CLOCK):
565 case IOV_GVAL(IOV_SDMODE):
566 int_val = (uint32)sd_sdmode;
567 bcopy(&int_val, arg, val_size);
570 case IOV_SVAL(IOV_SDMODE):
574 case IOV_GVAL(IOV_HISPEED):
575 int_val = (uint32)sd_hiok;
576 bcopy(&int_val, arg, val_size);
579 case IOV_SVAL(IOV_HISPEED):
583 case IOV_GVAL(IOV_NUMINTS):
584 int_val = (int32)si->intrcount;
585 bcopy(&int_val, arg, val_size);
588 case IOV_GVAL(IOV_NUMLOCALINTS):
590 bcopy(&int_val, arg, val_size);
593 case IOV_GVAL(IOV_HOSTREG):
595 sdreg_t *sd_ptr = (sdreg_t *)params;
597 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
598 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
599 bcmerror = BCME_BADARG;
603 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
604 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
606 if (sd_ptr->offset & 1)
607 int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
608 else if (sd_ptr->offset & 2)
609 int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
611 int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
613 bcopy(&int_val, arg, sizeof(int_val));
617 case IOV_SVAL(IOV_HOSTREG):
619 sdreg_t *sd_ptr = (sdreg_t *)params;
621 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
622 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
623 bcmerror = BCME_BADARG;
627 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
628 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
633 case IOV_GVAL(IOV_DEVREG):
635 sdreg_t *sd_ptr = (sdreg_t *)params;
638 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
639 bcmerror = BCME_SDIO_ERROR;
644 bcopy(&int_val, arg, sizeof(int_val));
648 case IOV_SVAL(IOV_DEVREG):
650 sdreg_t *sd_ptr = (sdreg_t *)params;
651 uint8 data = (uint8)sd_ptr->value;
653 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
654 bcmerror = BCME_SDIO_ERROR;
661 bcmerror = BCME_UNSUPPORTED;
669 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
672 sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
678 data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; /* enable hw oob interrupt */
680 data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */
682 #if 0 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
683 /* Needed for Android Linux Kernel 2.6.35 */
684 data |= SDIO_SEPINT_ACT_HI; /* Active HIGH */
687 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data);
690 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
693 sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
696 /* No lock needed since sdioh_request_byte does locking */
697 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
702 sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
704 /* No lock needed since sdioh_request_byte does locking */
706 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
711 sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
713 /* read 24 bits and return valid 17 bit addr */
715 uint32 scratch, regdata;
716 uint8 *ptr = (uint8 *)&scratch;
717 for (i = 0; i < 3; i++) {
718 if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS)
719 sd_err(("%s: Can't read!\n", __FUNCTION__));
721 *ptr++ = (uint8) regdata;
725 /* Only the lower 17-bits are valid */
726 scratch = ltoh32(scratch);
727 scratch &= 0x0001FFFF;
732 sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
739 sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
741 if (!sd->func_cis_ptr[func]) {
743 sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
744 return SDIOH_API_RC_FAIL;
747 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]));
749 for (count = 0; count < length; count++) {
750 offset = sd->func_cis_ptr[func] + count;
751 if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) {
752 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
753 return SDIOH_API_RC_FAIL;
756 *cis = (uint8)(foo & 0xff);
760 return SDIOH_API_RC_SUCCESS;
764 sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
768 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
770 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
771 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
772 if(rw) { /* CMD52 Write */
774 /* Can only directly write to some F0 registers. Handle F2 enable
777 if (regaddr == SDIOD_CCCR_IOEN) {
778 if (gInstance->func[2]) {
779 sdio_claim_host(gInstance->func[2]);
780 if (*byte & SDIO_FUNC_ENABLE_2) {
781 /* Enable Function 2 */
782 err_ret = sdio_enable_func(gInstance->func[2]);
784 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
788 /* Disable Function 2 */
789 err_ret = sdio_disable_func(gInstance->func[2]);
791 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
795 sdio_release_host(gInstance->func[2]);
798 #if defined(MMC_SDIO_ABORT)
799 /* to allow abort command through F1 */
800 else if (regaddr == SDIOD_CCCR_IOABORT) {
801 sdio_claim_host(gInstance->func[func]);
803 * this sdio_f0_writeb() can be replaced with another api
804 * depending upon MMC driver change.
805 * As of this time, this is temporaray one
807 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
808 sdio_release_host(gInstance->func[func]);
810 #endif /* MMC_SDIO_ABORT */
811 else if (regaddr < 0xF0) {
812 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr));
814 /* Claim host controller, perform F0 write, and release */
815 sdio_claim_host(gInstance->func[func]);
816 sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
817 sdio_release_host(gInstance->func[func]);
820 /* Claim host controller, perform Fn write, and release */
821 sdio_claim_host(gInstance->func[func]);
822 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
823 sdio_release_host(gInstance->func[func]);
825 } else { /* CMD52 Read */
826 /* Claim host controller, perform Fn read, and release */
827 sdio_claim_host(gInstance->func[func]);
830 *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret);
832 *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret);
835 sdio_release_host(gInstance->func[func]);
839 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
840 rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
843 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
847 sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
848 uint32 *word, uint nbytes)
850 int err_ret = SDIOH_API_RC_FAIL;
853 sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
854 return SDIOH_API_RC_FAIL;
857 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
858 __FUNCTION__, cmd_type, rw, func, addr, nbytes));
860 DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
861 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
862 /* Claim host controller */
863 sdio_claim_host(gInstance->func[func]);
865 if(rw) { /* CMD52 Write */
867 sdio_writel(gInstance->func[func], *word, addr, &err_ret);
868 } else if (nbytes == 2) {
869 sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret);
871 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
873 } else { /* CMD52 Read */
875 *word = sdio_readl(gInstance->func[func], addr, &err_ret);
876 } else if (nbytes == 2) {
877 *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF;
879 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
883 /* Release host controller */
884 sdio_release_host(gInstance->func[func]);
887 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
888 rw ? "Write" : "Read", err_ret));
891 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
895 sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
896 uint addr, void *pkt)
898 bool fifo = (fix_inc == SDIOH_DATA_FIX);
904 sd_trace(("%s: Enter\n", __FUNCTION__));
907 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
908 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
910 /* Claim host controller */
911 sdio_claim_host(gInstance->func[func]);
912 for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
913 uint pkt_len = PKTLEN(sd->osh, pnext);
915 pkt_len &= 0xFFFFFFFC;
917 #ifdef CONFIG_MMC_MSM7X00A
918 if ((pkt_len % 64) == 32) {
919 sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
922 #endif /* CONFIG_MMC_MSM7X00A */
923 /* Make sure the packet is aligned properly. If it isn't, then this
924 * is the fault of sdioh_request_buffer() which is supposed to give
925 * us something we can work with.
927 ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
929 if ((write) && (!fifo)) {
930 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
931 ((uint8*)PKTDATA(sd->osh, pnext)),
934 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
935 ((uint8*)PKTDATA(sd->osh, pnext)),
938 err_ret = sdio_readsb(gInstance->func[func],
939 ((uint8*)PKTDATA(sd->osh, pnext)),
943 err_ret = sdio_memcpy_fromio(gInstance->func[func],
944 ((uint8*)PKTDATA(sd->osh, pnext)),
950 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
952 (write) ? "TX" : "RX",
953 pnext, SGCount, addr, pkt_len, err_ret));
955 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
957 (write) ? "TX" : "RX",
958 pnext, SGCount, addr, pkt_len));
968 /* Release host controller */
969 sdio_release_host(gInstance->func[func]);
971 sd_trace(("%s: Exit\n", __FUNCTION__));
972 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
977 * This function takes a buffer or packet, and fixes everything up so that in the
978 * end, a DMA-able packet is created.
980 * A buffer does not have an associated packet pointer, and may or may not be aligned.
981 * A packet may consist of a single packet, or a packet chain. If it is a packet chain,
982 * then all the packets in the chain must be properly aligned. If the packet data is not
983 * aligned, then there may only be one packet, and in this case, it is copied to a new
988 sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func,
989 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
994 sd_trace(("%s: Enter\n", __FUNCTION__));
996 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
997 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
998 /* Case 1: we don't have a packet. */
1000 sd_data(("%s: Creating new %s Packet, len=%d\n",
1001 __FUNCTION__, write ? "TX" : "RX", buflen_u));
1002 #ifdef DHD_USE_STATIC_BUF
1003 if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) {
1005 if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
1006 #endif /* DHD_USE_STATIC_BUF */
1007 sd_err(("%s: PKTGET failed: len %d\n",
1008 __FUNCTION__, buflen_u));
1009 return SDIOH_API_RC_FAIL;
1012 /* For a write, copy the buffer data into the packet. */
1014 bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u);
1017 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1019 /* For a read, copy the packet data back to the buffer. */
1021 bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
1023 #ifdef DHD_USE_STATIC_BUF
1024 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1026 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1027 #endif /* DHD_USE_STATIC_BUF */
1028 } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
1029 /* Case 2: We have a packet, but it is unaligned. */
1031 /* In this case, we cannot have a chain. */
1032 ASSERT(PKTNEXT(sd->osh, pkt) == NULL);
1034 sd_data(("%s: Creating aligned %s Packet, len=%d\n",
1035 __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
1036 #ifdef DHD_USE_STATIC_BUF
1037 if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1039 if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1040 #endif /* DHD_USE_STATIC_BUF */
1041 sd_err(("%s: PKTGET failed: len %d\n",
1042 __FUNCTION__, PKTLEN(sd->osh, pkt)));
1043 return SDIOH_API_RC_FAIL;
1046 /* For a write, copy the buffer data into the packet. */
1048 bcopy(PKTDATA(sd->osh, pkt),
1049 PKTDATA(sd->osh, mypkt),
1050 PKTLEN(sd->osh, pkt));
1053 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1055 /* For a read, copy the packet data back to the buffer. */
1057 bcopy(PKTDATA(sd->osh, mypkt),
1058 PKTDATA(sd->osh, pkt),
1059 PKTLEN(sd->osh, mypkt));
1061 #ifdef DHD_USE_STATIC_BUF
1062 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1064 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1065 #endif /* DHD_USE_STATIC_BUF */
1066 } else { /* case 3: We have a packet and it is aligned. */
1067 sd_data(("%s: Aligned %s Packet, direct DMA\n",
1068 __FUNCTION__, write ? "Tx" : "Rx"));
1069 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
1075 /* this function performs "abort" for both of host & device */
1077 sdioh_abort(sdioh_info_t *sd, uint func)
1079 #if defined(MMC_SDIO_ABORT)
1080 char t_func = (char) func;
1081 #endif /* defined(MMC_SDIO_ABORT) */
1082 sd_trace(("%s: Enter\n", __FUNCTION__));
1084 #if defined(MMC_SDIO_ABORT)
1085 /* issue abort cmd52 command through F1 */
1086 sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func);
1087 #endif /* defined(MMC_SDIO_ABORT) */
1089 sd_trace(("%s: Exit\n", __FUNCTION__));
1090 return SDIOH_API_RC_SUCCESS;
1093 /* Reset and re-initialize the device */
1094 int sdioh_sdio_reset(sdioh_info_t *si)
1096 sd_trace(("%s: Enter\n", __FUNCTION__));
1097 sd_trace(("%s: Exit\n", __FUNCTION__));
1098 return SDIOH_API_RC_SUCCESS;
1101 /* Disable device interrupt */
1103 sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1105 #ifndef OOB_INTR_ONLY
1106 struct mmc_card *card = gInstance->func[0]->card;
1107 struct mmc_host *host = card->host;
1108 host->ops->enable_sdio_irq(host, 0);
1110 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1111 sd->intmask &= ~CLIENT_INTR;
1114 /* Enable device interrupt */
1116 sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1118 #ifndef OOB_INTR_ONLY
1119 struct mmc_card *card = gInstance->func[0]->card;
1120 struct mmc_host *host = card->host;
1122 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1123 sd->intmask |= CLIENT_INTR;
1124 #ifndef OOB_INTR_ONLY
1125 host->ops->enable_sdio_irq(host, 1);
1129 /* Read client card reg */
1131 sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
1134 if ((func == 0) || (regsize == 1)) {
1137 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1140 sd_data(("%s: byte read data=0x%02x\n",
1141 __FUNCTION__, *data));
1143 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
1147 sd_data(("%s: word read data=0x%08x\n",
1148 __FUNCTION__, *data));
1154 #if !defined(OOB_INTR_ONLY)
1155 /* bcmsdh_sdmmc interrupt handler */
1156 static void IRQHandler(struct sdio_func *func)
1160 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1164 sdio_release_host(gInstance->func[0]);
1166 if (sd->use_client_ints) {
1168 ASSERT(sd->intr_handler);
1169 ASSERT(sd->intr_handler_arg);
1170 (sd->intr_handler)(sd->intr_handler_arg);
1172 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1174 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1175 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
1178 sdio_claim_host(gInstance->func[0]);
1181 /* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1182 static void IRQHandlerF2(struct sdio_func *func)
1186 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1192 #endif /* !defined(OOB_INTR_ONLY) */
1195 /* Write client card reg */
1197 sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
1200 if ((func == 0) || (regsize == 1)) {
1204 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1205 sd_data(("%s: byte write data=0x%02x\n",
1206 __FUNCTION__, data));
1211 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize);
1213 sd_data(("%s: word write data=0x%08x\n",
1214 __FUNCTION__, data));
1219 #endif /* NOTUSED */
1222 sdioh_start(sdioh_info_t *si, int stage)
1229 sdioh_stop(sdioh_info_t *si)
1235 sdioh_waitlockfree(sdioh_info_t *sd)