2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
4 * Copyright (C) 1999-2010, 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.1.2.5.6.30.4.1 2010/09/02 23:12:21 Exp $
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/sdio_func.h>
39 #include <linux/mmc/sdio_ids.h>
41 #include <dngl_stats.h>
44 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
45 #include <linux/suspend.h>
46 extern volatile bool dhd_mmc_suspend;
48 #include "bcmsdh_sdmmc.h"
51 extern int sdio_function_init(void);
52 extern void sdio_function_cleanup(void);
53 #endif /* BCMSDH_MODULE */
55 #if !defined(OOB_INTR_ONLY)
56 static void IRQHandler(struct sdio_func *func);
57 static void IRQHandlerF2(struct sdio_func *func);
58 #endif /* !defined(OOB_INTR_ONLY) */
59 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
60 extern int sdio_reset_comm(struct mmc_card *card);
62 extern PBCMSDH_SDMMC_INSTANCE gInstance;
64 uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
65 uint sd_f2_blocksize = 512; /* Default blocksize */
67 uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
69 uint sd_power = 1; /* Default to SD Slot powered ON */
70 uint sd_clock = 1; /* Default to SD Clock turned ON */
71 uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */
72 uint sd_msglevel = 0x01;
73 uint sd_use_dma = TRUE;
74 DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
75 DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
76 DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
77 DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
79 #define DMA_ALIGN_MASK 0x03
81 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
84 sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
90 sd_trace(("%s\n", __FUNCTION__));
92 /* Get the Card's common CIS address */
93 sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
94 sd->func_cis_ptr[0] = sd->com_cis_ptr;
95 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
97 /* Get the Card's function CIS (for each function) */
98 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
99 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
100 sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
101 sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
102 __FUNCTION__, func, sd->func_cis_ptr[func]));
105 sd->func_cis_ptr[0] = sd->com_cis_ptr;
106 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
108 /* Enable Function 1 */
109 sdio_claim_host(gInstance->func[1]);
110 err_ret = sdio_enable_func(gInstance->func[1]);
111 sdio_release_host(gInstance->func[1]);
113 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret));
120 * Public entry points & extern's
122 extern sdioh_info_t *
123 sdioh_attach(osl_t *osh, void *bar0, uint irq)
128 sd_trace(("%s\n", __FUNCTION__));
130 if (gInstance == NULL) {
131 sd_err(("%s: SDIO Device not present\n", __FUNCTION__));
135 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
136 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
139 bzero((char *)sd, sizeof(sdioh_info_t));
141 if (sdioh_sdmmc_osinit(sd) != 0) {
142 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__));
143 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
148 sd->sd_blockmode = TRUE;
149 sd->use_client_ints = TRUE;
150 sd->client_block_size[0] = 64;
154 /* Claim host controller */
155 sdio_claim_host(gInstance->func[1]);
157 sd->client_block_size[1] = 64;
158 err_ret = sdio_set_block_size(gInstance->func[1], 64);
160 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
163 /* Release host controller F1 */
164 sdio_release_host(gInstance->func[1]);
166 if (gInstance->func[2]) {
167 /* Claim host controller F2 */
168 sdio_claim_host(gInstance->func[2]);
170 sd->client_block_size[2] = sd_f2_blocksize;
171 err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
173 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n",
177 /* Release host controller F2 */
178 sdio_release_host(gInstance->func[2]);
181 sdioh_sdmmc_card_enablefuncs(sd);
183 sd_trace(("%s: Done\n", __FUNCTION__));
189 sdioh_detach(osl_t *osh, sdioh_info_t *sd)
191 sd_trace(("%s\n", __FUNCTION__));
195 /* Disable Function 2 */
196 sdio_claim_host(gInstance->func[2]);
197 sdio_disable_func(gInstance->func[2]);
198 sdio_release_host(gInstance->func[2]);
200 /* Disable Function 1 */
201 sdio_claim_host(gInstance->func[1]);
202 sdio_disable_func(gInstance->func[1]);
203 sdio_release_host(gInstance->func[1]);
206 sdioh_sdmmc_osfree(sd);
208 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
210 return SDIOH_API_RC_SUCCESS;
213 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
216 sdioh_enable_func_intr(void)
221 if (gInstance->func[0]) {
222 sdio_claim_host(gInstance->func[0]);
224 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
226 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
227 sdio_release_host(gInstance->func[0]);
228 return SDIOH_API_RC_FAIL;
231 /* Enable F1 and F2 interrupts, set master enable */
232 reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN);
234 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
235 sdio_release_host(gInstance->func[0]);
238 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
239 return SDIOH_API_RC_FAIL;
243 return SDIOH_API_RC_SUCCESS;
247 sdioh_disable_func_intr(void)
252 if (gInstance->func[0]) {
253 sdio_claim_host(gInstance->func[0]);
254 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
256 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
257 sdio_release_host(gInstance->func[0]);
258 return SDIOH_API_RC_FAIL;
261 reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
262 /* Disable master interrupt with the last function interrupt */
265 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
267 sdio_release_host(gInstance->func[0]);
269 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
270 return SDIOH_API_RC_FAIL;
273 return SDIOH_API_RC_SUCCESS;
275 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
277 /* Configure callback to client when we recieve client interrupt */
279 sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
281 sd_trace(("%s: Entering\n", __FUNCTION__));
283 sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__));
284 return SDIOH_API_RC_FAIL;
286 #if !defined(OOB_INTR_ONLY)
287 sd->intr_handler = fn;
288 sd->intr_handler_arg = argh;
289 sd->intr_handler_valid = TRUE;
291 /* register and unmask irq */
292 if (gInstance->func[2]) {
293 sdio_claim_host(gInstance->func[2]);
294 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
295 sdio_release_host(gInstance->func[2]);
298 if (gInstance->func[1]) {
299 sdio_claim_host(gInstance->func[1]);
300 sdio_claim_irq(gInstance->func[1], IRQHandler);
301 sdio_release_host(gInstance->func[1]);
303 #elif defined(HW_OOB)
304 sdioh_enable_func_intr();
305 #endif /* defined(OOB_INTR_ONLY) */
306 return SDIOH_API_RC_SUCCESS;
310 sdioh_interrupt_deregister(sdioh_info_t *sd)
312 sd_trace(("%s: Entering\n", __FUNCTION__));
314 #if !defined(OOB_INTR_ONLY)
315 if (gInstance->func[1]) {
316 /* register and unmask irq */
317 sdio_claim_host(gInstance->func[1]);
318 sdio_release_irq(gInstance->func[1]);
319 sdio_release_host(gInstance->func[1]);
322 if (gInstance->func[2]) {
323 /* Claim host controller F2 */
324 sdio_claim_host(gInstance->func[2]);
325 sdio_release_irq(gInstance->func[2]);
326 /* Release host controller F2 */
327 sdio_release_host(gInstance->func[2]);
330 sd->intr_handler_valid = FALSE;
331 sd->intr_handler = NULL;
332 sd->intr_handler_arg = NULL;
333 #elif defined(HW_OOB)
334 sdioh_disable_func_intr();
335 #endif /* !defined(OOB_INTR_ONLY) */
336 return SDIOH_API_RC_SUCCESS;
340 sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
342 sd_trace(("%s: Entering\n", __FUNCTION__));
343 *onoff = sd->client_intr_enabled;
344 return SDIOH_API_RC_SUCCESS;
347 #if defined(DHD_DEBUG)
349 sdioh_interrupt_pending(sdioh_info_t *sd)
356 sdioh_query_iofnum(sdioh_info_t *sd)
358 return sd->num_funcs;
381 const bcm_iovar_t sdioh_iovars[] = {
382 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
383 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 },
384 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
385 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 },
386 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
387 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
388 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
389 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
390 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
391 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
392 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
393 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
394 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
395 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 },
396 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 },
401 sdioh_iovar_op(sdioh_info_t *si, const char *name,
402 void *params, int plen, void *arg, int len, bool set)
404 const bcm_iovar_t *vi = NULL;
414 /* Get must have return space; Set does not take qualifiers */
415 ASSERT(set || (arg && len));
416 ASSERT(!set || (!params && !plen));
418 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
420 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
421 bcmerror = BCME_UNSUPPORTED;
425 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
428 /* Set up params so get and set can share the convenience variables */
429 if (params == NULL) {
434 if (vi->type == IOVT_VOID)
436 else if (vi->type == IOVT_BUFFER)
439 val_size = sizeof(int);
441 if (plen >= (int)sizeof(int_val))
442 bcopy(params, &int_val, sizeof(int_val));
444 bool_val = (int_val != 0) ? TRUE : FALSE;
446 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
448 case IOV_GVAL(IOV_MSGLEVEL):
449 int_val = (int32)sd_msglevel;
450 bcopy(&int_val, arg, val_size);
453 case IOV_SVAL(IOV_MSGLEVEL):
454 sd_msglevel = int_val;
457 case IOV_GVAL(IOV_BLOCKMODE):
458 int_val = (int32)si->sd_blockmode;
459 bcopy(&int_val, arg, val_size);
462 case IOV_SVAL(IOV_BLOCKMODE):
463 si->sd_blockmode = (bool)int_val;
464 /* Haven't figured out how to make non-block mode with DMA */
467 case IOV_GVAL(IOV_BLOCKSIZE):
468 if ((uint32)int_val > si->num_funcs) {
469 bcmerror = BCME_BADARG;
472 int_val = (int32)si->client_block_size[int_val];
473 bcopy(&int_val, arg, val_size);
476 case IOV_SVAL(IOV_BLOCKSIZE):
478 uint func = ((uint32)int_val >> 16);
479 uint blksize = (uint16)int_val;
482 if (func > si->num_funcs) {
483 bcmerror = BCME_BADARG;
488 case 0: maxsize = 32; break;
489 case 1: maxsize = BLOCK_SIZE_4318; break;
490 case 2: maxsize = BLOCK_SIZE_4328; break;
491 default: maxsize = 0;
493 if (blksize > maxsize) {
494 bcmerror = BCME_BADARG;
502 si->client_block_size[func] = blksize;
507 case IOV_GVAL(IOV_RXCHAIN):
509 bcopy(&int_val, arg, val_size);
512 case IOV_GVAL(IOV_DMA):
513 int_val = (int32)si->sd_use_dma;
514 bcopy(&int_val, arg, val_size);
517 case IOV_SVAL(IOV_DMA):
518 si->sd_use_dma = (bool)int_val;
521 case IOV_GVAL(IOV_USEINTS):
522 int_val = (int32)si->use_client_ints;
523 bcopy(&int_val, arg, val_size);
526 case IOV_SVAL(IOV_USEINTS):
527 si->use_client_ints = (bool)int_val;
528 if (si->use_client_ints)
529 si->intmask |= CLIENT_INTR;
531 si->intmask &= ~CLIENT_INTR;
535 case IOV_GVAL(IOV_DIVISOR):
536 int_val = (uint32)sd_divisor;
537 bcopy(&int_val, arg, val_size);
540 case IOV_SVAL(IOV_DIVISOR):
541 sd_divisor = int_val;
544 case IOV_GVAL(IOV_POWER):
545 int_val = (uint32)sd_power;
546 bcopy(&int_val, arg, val_size);
549 case IOV_SVAL(IOV_POWER):
553 case IOV_GVAL(IOV_CLOCK):
554 int_val = (uint32)sd_clock;
555 bcopy(&int_val, arg, val_size);
558 case IOV_SVAL(IOV_CLOCK):
562 case IOV_GVAL(IOV_SDMODE):
563 int_val = (uint32)sd_sdmode;
564 bcopy(&int_val, arg, val_size);
567 case IOV_SVAL(IOV_SDMODE):
571 case IOV_GVAL(IOV_HISPEED):
572 int_val = (uint32)sd_hiok;
573 bcopy(&int_val, arg, val_size);
576 case IOV_SVAL(IOV_HISPEED):
580 case IOV_GVAL(IOV_NUMINTS):
581 int_val = (int32)si->intrcount;
582 bcopy(&int_val, arg, val_size);
585 case IOV_GVAL(IOV_NUMLOCALINTS):
587 bcopy(&int_val, arg, val_size);
590 case IOV_GVAL(IOV_HOSTREG):
592 sdreg_t *sd_ptr = (sdreg_t *)params;
594 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
595 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
596 bcmerror = BCME_BADARG;
600 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
601 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
603 if (sd_ptr->offset & 1)
604 int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
605 else if (sd_ptr->offset & 2)
606 int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
608 int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
610 bcopy(&int_val, arg, sizeof(int_val));
614 case IOV_SVAL(IOV_HOSTREG):
616 sdreg_t *sd_ptr = (sdreg_t *)params;
618 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
619 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
620 bcmerror = BCME_BADARG;
624 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
625 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
630 case IOV_GVAL(IOV_DEVREG):
632 sdreg_t *sd_ptr = (sdreg_t *)params;
635 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
636 bcmerror = BCME_SDIO_ERROR;
641 bcopy(&int_val, arg, sizeof(int_val));
645 case IOV_SVAL(IOV_DEVREG):
647 sdreg_t *sd_ptr = (sdreg_t *)params;
648 uint8 data = (uint8)sd_ptr->value;
650 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
651 bcmerror = BCME_SDIO_ERROR;
658 bcmerror = BCME_UNSUPPORTED;
666 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
669 sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
675 data = 3; /* enable hw oob interrupt */
677 data = 4; /* disable hw oob interrupt */
678 data |= 4; /* Active HIGH */
680 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data);
683 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
686 sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
689 /* No lock needed since sdioh_request_byte does locking */
690 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
695 sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
697 /* No lock needed since sdioh_request_byte does locking */
699 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
704 sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
706 /* read 24 bits and return valid 17 bit addr */
708 uint32 scratch, regdata;
709 uint8 *ptr = (uint8 *)&scratch;
710 for (i = 0; i < 3; i++) {
711 if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS)
712 sd_err(("%s: Can't read!\n", __FUNCTION__));
714 *ptr++ = (uint8) regdata;
718 /* Only the lower 17-bits are valid */
719 scratch = ltoh32(scratch);
720 scratch &= 0x0001FFFF;
725 sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
732 sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
734 if (!sd->func_cis_ptr[func]) {
736 sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
737 return SDIOH_API_RC_FAIL;
740 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]));
742 for (count = 0; count < length; count++) {
743 offset = sd->func_cis_ptr[func] + count;
744 if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) {
745 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
746 return SDIOH_API_RC_FAIL;
749 *cis = (uint8)(foo & 0xff);
753 return SDIOH_API_RC_SUCCESS;
757 sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
761 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
763 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
764 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
765 if(rw) { /* CMD52 Write */
767 /* Can only directly write to some F0 registers. Handle F2 enable
770 if (regaddr == SDIOD_CCCR_IOEN) {
771 if (gInstance->func[2]) {
772 sdio_claim_host(gInstance->func[2]);
773 if (*byte & SDIO_FUNC_ENABLE_2) {
774 /* Enable Function 2 */
775 err_ret = sdio_enable_func(gInstance->func[2]);
777 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
781 /* Disable Function 2 */
782 err_ret = sdio_disable_func(gInstance->func[2]);
784 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
788 sdio_release_host(gInstance->func[2]);
791 #if defined(MMC_SDIO_ABORT)
792 /* to allow abort command through F1 */
793 else if (regaddr == SDIOD_CCCR_IOABORT) {
794 sdio_claim_host(gInstance->func[func]);
796 * this sdio_f0_writeb() can be replaced with another api
797 * depending upon MMC driver change.
798 * As of this time, this is temporaray one
800 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
801 sdio_release_host(gInstance->func[func]);
803 #endif /* MMC_SDIO_ABORT */
804 else if (regaddr < 0xF0) {
805 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr));
807 /* Claim host controller, perform F0 write, and release */
808 sdio_claim_host(gInstance->func[func]);
809 sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
810 sdio_release_host(gInstance->func[func]);
813 /* Claim host controller, perform Fn write, and release */
814 sdio_claim_host(gInstance->func[func]);
815 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
816 sdio_release_host(gInstance->func[func]);
818 } else { /* CMD52 Read */
819 /* Claim host controller, perform Fn read, and release */
820 sdio_claim_host(gInstance->func[func]);
823 *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret);
825 *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret);
828 sdio_release_host(gInstance->func[func]);
832 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
833 rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
836 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
840 sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
841 uint32 *word, uint nbytes)
843 int err_ret = SDIOH_API_RC_FAIL;
846 sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
847 return SDIOH_API_RC_FAIL;
850 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
851 __FUNCTION__, cmd_type, rw, func, addr, nbytes));
853 DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
854 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
855 /* Claim host controller */
856 sdio_claim_host(gInstance->func[func]);
858 if(rw) { /* CMD52 Write */
860 sdio_writel(gInstance->func[func], *word, addr, &err_ret);
861 } else if (nbytes == 2) {
862 sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret);
864 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
866 } else { /* CMD52 Read */
868 *word = sdio_readl(gInstance->func[func], addr, &err_ret);
869 } else if (nbytes == 2) {
870 *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF;
872 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
876 /* Release host controller */
877 sdio_release_host(gInstance->func[func]);
880 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
881 rw ? "Write" : "Read", err_ret));
884 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
888 sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
889 uint addr, void *pkt)
891 bool fifo = (fix_inc == SDIOH_DATA_FIX);
897 sd_trace(("%s: Enter\n", __FUNCTION__));
900 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
901 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
903 /* Claim host controller */
904 sdio_claim_host(gInstance->func[func]);
905 for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
906 uint pkt_len = PKTLEN(sd->osh, pnext);
908 pkt_len &= 0xFFFFFFFC;
910 #ifdef CONFIG_MMC_MSM7X00A
911 if ((pkt_len % 64) == 32) {
912 sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
915 #endif /* CONFIG_MMC_MSM7X00A */
916 /* Make sure the packet is aligned properly. If it isn't, then this
917 * is the fault of sdioh_request_buffer() which is supposed to give
918 * us something we can work with.
920 ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
922 if ((write) && (!fifo)) {
923 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
924 ((uint8*)PKTDATA(sd->osh, pnext)),
927 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
928 ((uint8*)PKTDATA(sd->osh, pnext)),
931 err_ret = sdio_readsb(gInstance->func[func],
932 ((uint8*)PKTDATA(sd->osh, pnext)),
936 err_ret = sdio_memcpy_fromio(gInstance->func[func],
937 ((uint8*)PKTDATA(sd->osh, pnext)),
943 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
945 (write) ? "TX" : "RX",
946 pnext, SGCount, addr, pkt_len, err_ret));
948 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
950 (write) ? "TX" : "RX",
951 pnext, SGCount, addr, pkt_len));
961 /* Release host controller */
962 sdio_release_host(gInstance->func[func]);
964 sd_trace(("%s: Exit\n", __FUNCTION__));
965 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
970 * This function takes a buffer or packet, and fixes everything up so that in the
971 * end, a DMA-able packet is created.
973 * A buffer does not have an associated packet pointer, and may or may not be aligned.
974 * A packet may consist of a single packet, or a packet chain. If it is a packet chain,
975 * then all the packets in the chain must be properly aligned. If the packet data is not
976 * aligned, then there may only be one packet, and in this case, it is copied to a new
981 sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func,
982 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
987 sd_trace(("%s: Enter\n", __FUNCTION__));
989 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
990 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
991 /* Case 1: we don't have a packet. */
993 sd_data(("%s: Creating new %s Packet, len=%d\n",
994 __FUNCTION__, write ? "TX" : "RX", buflen_u));
995 #ifdef DHD_USE_STATIC_BUF
996 if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) {
998 if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
999 #endif /* DHD_USE_STATIC_BUF */
1000 sd_err(("%s: PKTGET failed: len %d\n",
1001 __FUNCTION__, buflen_u));
1002 return SDIOH_API_RC_FAIL;
1005 /* For a write, copy the buffer data into the packet. */
1007 bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u);
1010 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1012 /* For a read, copy the packet data back to the buffer. */
1014 bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
1016 #ifdef DHD_USE_STATIC_BUF
1017 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1019 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1020 #endif /* DHD_USE_STATIC_BUF */
1021 } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
1022 /* Case 2: We have a packet, but it is unaligned. */
1024 /* In this case, we cannot have a chain. */
1025 ASSERT(PKTNEXT(sd->osh, pkt) == NULL);
1027 sd_data(("%s: Creating aligned %s Packet, len=%d\n",
1028 __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
1029 #ifdef DHD_USE_STATIC_BUF
1030 if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1032 if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1033 #endif /* DHD_USE_STATIC_BUF */
1034 sd_err(("%s: PKTGET failed: len %d\n",
1035 __FUNCTION__, PKTLEN(sd->osh, pkt)));
1036 return SDIOH_API_RC_FAIL;
1039 /* For a write, copy the buffer data into the packet. */
1041 bcopy(PKTDATA(sd->osh, pkt),
1042 PKTDATA(sd->osh, mypkt),
1043 PKTLEN(sd->osh, pkt));
1046 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1048 /* For a read, copy the packet data back to the buffer. */
1050 bcopy(PKTDATA(sd->osh, mypkt),
1051 PKTDATA(sd->osh, pkt),
1052 PKTLEN(sd->osh, mypkt));
1054 #ifdef DHD_USE_STATIC_BUF
1055 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1057 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1058 #endif /* DHD_USE_STATIC_BUF */
1059 } else { /* case 3: We have a packet and it is aligned. */
1060 sd_data(("%s: Aligned %s Packet, direct DMA\n",
1061 __FUNCTION__, write ? "Tx" : "Rx"));
1062 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
1068 /* this function performs "abort" for both of host & device */
1070 sdioh_abort(sdioh_info_t *sd, uint func)
1072 #if defined(MMC_SDIO_ABORT)
1073 char t_func = (char) func;
1074 #endif /* defined(MMC_SDIO_ABORT) */
1075 sd_trace(("%s: Enter\n", __FUNCTION__));
1077 #if defined(MMC_SDIO_ABORT)
1078 /* issue abort cmd52 command through F1 */
1079 sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func);
1080 #endif /* defined(MMC_SDIO_ABORT) */
1082 sd_trace(("%s: Exit\n", __FUNCTION__));
1083 return SDIOH_API_RC_SUCCESS;
1086 /* Reset and re-initialize the device */
1087 int sdioh_sdio_reset(sdioh_info_t *si)
1089 sd_trace(("%s: Enter\n", __FUNCTION__));
1090 sd_trace(("%s: Exit\n", __FUNCTION__));
1091 return SDIOH_API_RC_SUCCESS;
1094 /* Disable device interrupt */
1096 sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1098 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1099 sd->intmask &= ~CLIENT_INTR;
1102 /* Enable device interrupt */
1104 sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1106 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1107 sd->intmask |= CLIENT_INTR;
1110 /* Read client card reg */
1112 sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
1115 if ((func == 0) || (regsize == 1)) {
1118 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1121 sd_data(("%s: byte read data=0x%02x\n",
1122 __FUNCTION__, *data));
1124 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
1128 sd_data(("%s: word read data=0x%08x\n",
1129 __FUNCTION__, *data));
1135 #if !defined(OOB_INTR_ONLY)
1136 /* bcmsdh_sdmmc interrupt handler */
1137 static void IRQHandler(struct sdio_func *func)
1141 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1145 sdio_release_host(gInstance->func[0]);
1147 if (sd->use_client_ints) {
1149 ASSERT(sd->intr_handler);
1150 ASSERT(sd->intr_handler_arg);
1151 (sd->intr_handler)(sd->intr_handler_arg);
1153 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1155 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1156 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
1159 sdio_claim_host(gInstance->func[0]);
1162 /* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1163 static void IRQHandlerF2(struct sdio_func *func)
1167 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1173 #endif /* !defined(OOB_INTR_ONLY) */
1176 /* Write client card reg */
1178 sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
1181 if ((func == 0) || (regsize == 1)) {
1185 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1186 sd_data(("%s: byte write data=0x%02x\n",
1187 __FUNCTION__, data));
1192 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize);
1194 sd_data(("%s: word write data=0x%08x\n",
1195 __FUNCTION__, data));
1200 #endif /* NOTUSED */
1203 sdioh_start(sdioh_info_t *si, int stage)
1206 sdioh_info_t *sd = gInstance->sd;
1208 /* Need to do this stages as we can't enable the interrupt till
1209 downloading of the firmware is complete, other wise polling
1210 sdio access will come in way
1212 if (gInstance->func[0]) {
1214 /* Since the power to the chip is killed, we will have
1215 re enumerate the device again. Set the block size
1216 and enable the fucntion 1 for in preparation for
1217 downloading the code
1219 /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
1220 2.6.27. The implementation prior to that is buggy, and needs broadcom's
1223 if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
1224 sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
1227 sd->sd_blockmode = TRUE;
1228 sd->use_client_ints = TRUE;
1229 sd->client_block_size[0] = 64;
1231 /* Claim host controller */
1232 sdio_claim_host(gInstance->func[1]);
1234 sd->client_block_size[1] = 64;
1235 if (sdio_set_block_size(gInstance->func[1], 64)) {
1236 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
1239 /* Release host controller F1 */
1240 sdio_release_host(gInstance->func[1]);
1242 if (gInstance->func[2]) {
1243 /* Claim host controller F2 */
1244 sdio_claim_host(gInstance->func[2]);
1246 sd->client_block_size[2] = sd_f2_blocksize;
1247 if (sdio_set_block_size(gInstance->func[2],
1249 sd_err(("bcmsdh_sdmmc: Failed to set F2 "
1250 "blocksize to %d\n", sd_f2_blocksize));
1253 /* Release host controller F2 */
1254 sdio_release_host(gInstance->func[2]);
1257 sdioh_sdmmc_card_enablefuncs(sd);
1260 #if !defined(OOB_INTR_ONLY)
1261 sdio_claim_host(gInstance->func[0]);
1262 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
1263 sdio_claim_irq(gInstance->func[1], IRQHandler);
1264 sdio_release_host(gInstance->func[0]);
1265 #else /* defined(OOB_INTR_ONLY) */
1267 sdioh_enable_func_intr();
1269 bcmsdh_oob_intr_set(TRUE);
1270 #endif /* !defined(OOB_INTR_ONLY) */
1274 sd_err(("%s Failed\n", __FUNCTION__));
1280 sdioh_stop(sdioh_info_t *si)
1282 /* MSM7201A Android sdio stack has bug with interrupt
1283 So internaly within SDIO stack they are polling
1284 which cause issue when device is turned off. So
1285 unregister interrupt with SDIO stack to stop the
1288 if (gInstance->func[0]) {
1289 #if !defined(OOB_INTR_ONLY)
1290 sdio_claim_host(gInstance->func[0]);
1291 sdio_release_irq(gInstance->func[1]);
1292 sdio_release_irq(gInstance->func[2]);
1293 sdio_release_host(gInstance->func[0]);
1294 #else /* defined(OOB_INTR_ONLY) */
1296 sdioh_disable_func_intr();
1298 bcmsdh_oob_intr_set(FALSE);
1299 #endif /* !defined(OOB_INTR_ONLY) */
1302 sd_err(("%s Failed\n", __FUNCTION__));