2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
4 * Copyright (C) 1999-2013, 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 418714 2013-08-16 13:21:09Z $
29 #include <bcmendian.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 */
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>
42 #include <dngl_stats.h>
45 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
46 #include <linux/suspend.h>
47 extern volatile bool dhd_mmc_suspend
;
49 #include "bcmsdh_sdmmc.h"
52 extern int sdio_function_init(void);
53 extern void sdio_function_cleanup(void);
54 #endif /* BCMSDH_MODULE */
56 #if !defined(OOB_INTR_ONLY)
57 static void IRQHandler(struct sdio_func
*func
);
58 static void IRQHandlerF2(struct sdio_func
*func
);
59 #endif /* !defined(OOB_INTR_ONLY) */
60 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t
*sd
, uint32 regaddr
);
61 extern int sdio_reset_comm(struct mmc_card
*card
);
63 extern PBCMSDH_SDMMC_INSTANCE gInstance
;
65 #define DEFAULT_SDIO_F2_BLKSIZE 512
66 #ifndef CUSTOM_SDIO_F2_BLKSIZE
67 #define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE
70 uint sd_sdmode
= SDIOH_MODE_SD4
; /* Use SD4 mode by default */
71 uint sd_f2_blocksize
= CUSTOM_SDIO_F2_BLKSIZE
;
72 uint sd_divisor
= 2; /* Default 48MHz/2 = 24MHz */
74 uint sd_power
= 1; /* Default to SD Slot powered ON */
75 uint sd_clock
= 1; /* Default to SD Clock turned ON */
76 uint sd_hiok
= FALSE
; /* Don't use hi-speed mode by default */
77 uint sd_msglevel
= 0x01;
78 uint sd_use_dma
= TRUE
;
80 #ifdef BCMSDIOH_TXGLOM
82 #define CUSTOM_TXGLOM 0
84 uint sd_txglom
= CUSTOM_TXGLOM
;
85 #endif /* BCMSDIOH_TXGLOM */
87 #ifndef CUSTOM_RXCHAIN
88 #define CUSTOM_RXCHAIN 0
91 DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait
);
92 DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait
);
93 DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait
);
94 DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait
);
96 #define DMA_ALIGN_MASK 0x03
97 #define MMC_SDIO_ABORT_RETRY_LIMIT 5
99 int sdioh_sdmmc_card_regread(sdioh_info_t
*sd
, int func
, uint32 regaddr
, int regsize
, uint32
*data
);
102 sdioh_sdmmc_card_enablefuncs(sdioh_info_t
*sd
)
108 sd_trace(("%s\n", __FUNCTION__
));
110 /* Get the Card's common CIS address */
111 sd
->com_cis_ptr
= sdioh_sdmmc_get_cisaddr(sd
, SDIOD_CCCR_CISPTR_0
);
112 sd
->func_cis_ptr
[0] = sd
->com_cis_ptr
;
113 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__
, sd
->com_cis_ptr
));
115 /* Get the Card's function CIS (for each function) */
116 for (fbraddr
= SDIOD_FBR_STARTADDR
, func
= 1;
117 func
<= sd
->num_funcs
; func
++, fbraddr
+= SDIOD_FBR_SIZE
) {
118 sd
->func_cis_ptr
[func
] = sdioh_sdmmc_get_cisaddr(sd
, SDIOD_FBR_CISPTR_0
+ fbraddr
);
119 sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
120 __FUNCTION__
, func
, sd
->func_cis_ptr
[func
]));
123 sd
->func_cis_ptr
[0] = sd
->com_cis_ptr
;
124 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__
, sd
->com_cis_ptr
));
126 /* Enable Function 1 */
127 sdio_claim_host(gInstance
->func
[1]);
128 err_ret
= sdio_enable_func(gInstance
->func
[1]);
129 sdio_release_host(gInstance
->func
[1]);
131 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret
));
138 * Public entry points & extern's
140 extern sdioh_info_t
*
141 sdioh_attach(osl_t
*osh
, void *bar0
, uint irq
)
146 sd_trace(("%s\n", __FUNCTION__
));
148 if (gInstance
== NULL
) {
149 sd_err(("%s: SDIO Device not present\n", __FUNCTION__
));
153 if ((sd
= (sdioh_info_t
*)MALLOC(osh
, sizeof(sdioh_info_t
))) == NULL
) {
154 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh
)));
157 bzero((char *)sd
, sizeof(sdioh_info_t
));
159 if (sdioh_sdmmc_osinit(sd
) != 0) {
160 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__
));
161 MFREE(sd
->osh
, sd
, sizeof(sdioh_info_t
));
166 sd
->sd_blockmode
= TRUE
;
167 sd
->use_client_ints
= TRUE
;
168 sd
->client_block_size
[0] = 64;
169 sd
->use_rxchain
= CUSTOM_RXCHAIN
;
173 /* Claim host controller */
174 if (gInstance
->func
[1]) {
175 sdio_claim_host(gInstance
->func
[1]);
177 sd
->client_block_size
[1] = 64;
178 err_ret
= sdio_set_block_size(gInstance
->func
[1], 64);
179 /* Release host controller F1 */
180 sdio_release_host(gInstance
->func
[1]);
182 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
183 MFREE(sd
->osh
, sd
, sizeof(sdioh_info_t
));
188 sd_err(("%s:gInstance->func[1] is null\n", __FUNCTION__
));
189 MFREE(sd
->osh
, sd
, sizeof(sdioh_info_t
));
193 if (gInstance
->func
[2]) {
194 /* Claim host controller F2 */
195 sdio_claim_host(gInstance
->func
[2]);
197 sd
->client_block_size
[2] = sd_f2_blocksize
;
198 err_ret
= sdio_set_block_size(gInstance
->func
[2], sd_f2_blocksize
);
199 /* Release host controller F2 */
200 sdio_release_host(gInstance
->func
[2]);
202 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n",
204 MFREE(sd
->osh
, sd
, sizeof(sdioh_info_t
));
209 sd_err(("%s:gInstance->func[2] is null\n", __FUNCTION__
));
210 MFREE(sd
->osh
, sd
, sizeof(sdioh_info_t
));
214 sdioh_sdmmc_card_enablefuncs(sd
);
216 sd_trace(("%s: Done\n", __FUNCTION__
));
222 sdioh_detach(osl_t
*osh
, sdioh_info_t
*sd
)
224 sd_trace(("%s\n", __FUNCTION__
));
228 /* Disable Function 2 */
229 sdio_claim_host(gInstance
->func
[2]);
230 sdio_disable_func(gInstance
->func
[2]);
231 sdio_release_host(gInstance
->func
[2]);
233 /* Disable Function 1 */
234 if (gInstance
->func
[1]) {
235 sdio_claim_host(gInstance
->func
[1]);
236 sdio_disable_func(gInstance
->func
[1]);
237 sdio_release_host(gInstance
->func
[1]);
240 gInstance
->func
[1] = NULL
;
241 gInstance
->func
[2] = NULL
;
244 sdioh_sdmmc_osfree(sd
);
246 MFREE(sd
->osh
, sd
, sizeof(sdioh_info_t
));
248 return SDIOH_API_RC_SUCCESS
;
251 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
254 sdioh_enable_func_intr(void)
259 if (gInstance
->func
[0]) {
260 sdio_claim_host(gInstance
->func
[0]);
262 reg
= sdio_readb(gInstance
->func
[0], SDIOD_CCCR_INTEN
, &err
);
264 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__
, err
));
265 sdio_release_host(gInstance
->func
[0]);
266 return SDIOH_API_RC_FAIL
;
269 /* Enable F1 and F2 interrupts, clear master enable */
270 reg
&= ~INTR_CTL_MASTER_EN
;
271 reg
|= (INTR_CTL_FUNC1_EN
| INTR_CTL_FUNC2_EN
);
272 sdio_writeb(gInstance
->func
[0], reg
, SDIOD_CCCR_INTEN
, &err
);
273 sdio_release_host(gInstance
->func
[0]);
276 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__
, err
));
277 return SDIOH_API_RC_FAIL
;
281 return SDIOH_API_RC_SUCCESS
;
285 sdioh_disable_func_intr(void)
290 if (gInstance
->func
[0]) {
291 sdio_claim_host(gInstance
->func
[0]);
292 reg
= sdio_readb(gInstance
->func
[0], SDIOD_CCCR_INTEN
, &err
);
294 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__
, err
));
295 sdio_release_host(gInstance
->func
[0]);
296 return SDIOH_API_RC_FAIL
;
299 reg
&= ~(INTR_CTL_FUNC1_EN
| INTR_CTL_FUNC2_EN
);
300 /* Disable master interrupt with the last function interrupt */
303 sdio_writeb(gInstance
->func
[0], reg
, SDIOD_CCCR_INTEN
, &err
);
305 sdio_release_host(gInstance
->func
[0]);
307 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__
, err
));
308 return SDIOH_API_RC_FAIL
;
311 return SDIOH_API_RC_SUCCESS
;
313 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
315 /* Configure callback to client when we recieve client interrupt */
317 sdioh_interrupt_register(sdioh_info_t
*sd
, sdioh_cb_fn_t fn
, void *argh
)
319 sd_trace(("%s: Entering\n", __FUNCTION__
));
321 sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__
));
322 return SDIOH_API_RC_FAIL
;
324 #if !defined(OOB_INTR_ONLY)
325 sd
->intr_handler
= fn
;
326 sd
->intr_handler_arg
= argh
;
327 sd
->intr_handler_valid
= TRUE
;
329 /* register and unmask irq */
330 if (gInstance
->func
[2]) {
331 sdio_claim_host(gInstance
->func
[2]);
332 sdio_claim_irq(gInstance
->func
[2], IRQHandlerF2
);
333 sdio_release_host(gInstance
->func
[2]);
336 if (gInstance
->func
[1]) {
337 sdio_claim_host(gInstance
->func
[1]);
338 sdio_claim_irq(gInstance
->func
[1], IRQHandler
);
339 sdio_release_host(gInstance
->func
[1]);
341 #elif defined(HW_OOB)
342 sdioh_enable_func_intr();
343 #endif /* !defined(OOB_INTR_ONLY) */
345 return SDIOH_API_RC_SUCCESS
;
349 sdioh_interrupt_deregister(sdioh_info_t
*sd
)
351 sd_trace(("%s: Entering\n", __FUNCTION__
));
353 #if !defined(OOB_INTR_ONLY)
354 if (gInstance
->func
[1]) {
355 /* register and unmask irq */
356 sdio_claim_host(gInstance
->func
[1]);
357 sdio_release_irq(gInstance
->func
[1]);
358 sdio_release_host(gInstance
->func
[1]);
361 if (gInstance
->func
[2]) {
362 /* Claim host controller F2 */
363 sdio_claim_host(gInstance
->func
[2]);
364 sdio_release_irq(gInstance
->func
[2]);
365 /* Release host controller F2 */
366 sdio_release_host(gInstance
->func
[2]);
369 sd
->intr_handler_valid
= FALSE
;
370 sd
->intr_handler
= NULL
;
371 sd
->intr_handler_arg
= NULL
;
372 #elif defined(HW_OOB)
373 if (dhd_download_fw_on_driverload
)
374 sdioh_disable_func_intr();
375 #endif /* !defined(OOB_INTR_ONLY) */
376 return SDIOH_API_RC_SUCCESS
;
380 sdioh_interrupt_query(sdioh_info_t
*sd
, bool *onoff
)
382 sd_trace(("%s: Entering\n", __FUNCTION__
));
383 *onoff
= sd
->client_intr_enabled
;
384 return SDIOH_API_RC_SUCCESS
;
387 #if defined(DHD_DEBUG)
389 sdioh_interrupt_pending(sdioh_info_t
*sd
)
396 sdioh_query_iofnum(sdioh_info_t
*sd
)
398 return sd
->num_funcs
;
421 const bcm_iovar_t sdioh_iovars
[] = {
422 {"sd_msglevel", IOV_MSGLEVEL
, 0, IOVT_UINT32
, 0 },
423 {"sd_blockmode", IOV_BLOCKMODE
, 0, IOVT_BOOL
, 0 },
424 {"sd_blocksize", IOV_BLOCKSIZE
, 0, IOVT_UINT32
, 0 }, /* ((fn << 16) | size) */
425 {"sd_dma", IOV_DMA
, 0, IOVT_BOOL
, 0 },
426 {"sd_ints", IOV_USEINTS
, 0, IOVT_BOOL
, 0 },
427 {"sd_numints", IOV_NUMINTS
, 0, IOVT_UINT32
, 0 },
428 {"sd_numlocalints", IOV_NUMLOCALINTS
, 0, IOVT_UINT32
, 0 },
429 {"sd_hostreg", IOV_HOSTREG
, 0, IOVT_BUFFER
, sizeof(sdreg_t
) },
430 {"sd_devreg", IOV_DEVREG
, 0, IOVT_BUFFER
, sizeof(sdreg_t
) },
431 {"sd_divisor", IOV_DIVISOR
, 0, IOVT_UINT32
, 0 },
432 {"sd_power", IOV_POWER
, 0, IOVT_UINT32
, 0 },
433 {"sd_clock", IOV_CLOCK
, 0, IOVT_UINT32
, 0 },
434 {"sd_mode", IOV_SDMODE
, 0, IOVT_UINT32
, 100},
435 {"sd_highspeed", IOV_HISPEED
, 0, IOVT_UINT32
, 0 },
436 {"sd_rxchain", IOV_RXCHAIN
, 0, IOVT_BOOL
, 0 },
441 sdioh_iovar_op(sdioh_info_t
*si
, const char *name
,
442 void *params
, int plen
, void *arg
, int len
, bool set
)
444 const bcm_iovar_t
*vi
= NULL
;
454 /* Get must have return space; Set does not take qualifiers */
455 ASSERT(set
|| (arg
&& len
));
456 ASSERT(!set
|| (!params
&& !plen
));
458 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__
, (set
? "set" : "get"), name
));
460 if ((vi
= bcm_iovar_lookup(sdioh_iovars
, name
)) == NULL
) {
461 bcmerror
= BCME_UNSUPPORTED
;
465 if ((bcmerror
= bcm_iovar_lencheck(vi
, arg
, len
, set
)) != 0)
468 /* Set up params so get and set can share the convenience variables */
469 if (params
== NULL
) {
474 if (vi
->type
== IOVT_VOID
)
476 else if (vi
->type
== IOVT_BUFFER
)
479 val_size
= sizeof(int);
481 if (plen
>= (int)sizeof(int_val
))
482 bcopy(params
, &int_val
, sizeof(int_val
));
484 bool_val
= (int_val
!= 0) ? TRUE
: FALSE
;
485 BCM_REFERENCE(bool_val
);
487 actionid
= set
? IOV_SVAL(vi
->varid
) : IOV_GVAL(vi
->varid
);
489 case IOV_GVAL(IOV_MSGLEVEL
):
490 int_val
= (int32
)sd_msglevel
;
491 bcopy(&int_val
, arg
, val_size
);
494 case IOV_SVAL(IOV_MSGLEVEL
):
495 sd_msglevel
= int_val
;
498 case IOV_GVAL(IOV_BLOCKMODE
):
499 int_val
= (int32
)si
->sd_blockmode
;
500 bcopy(&int_val
, arg
, val_size
);
503 case IOV_SVAL(IOV_BLOCKMODE
):
504 si
->sd_blockmode
= (bool)int_val
;
505 /* Haven't figured out how to make non-block mode with DMA */
508 case IOV_GVAL(IOV_BLOCKSIZE
):
509 if ((uint32
)int_val
> si
->num_funcs
) {
510 bcmerror
= BCME_BADARG
;
513 int_val
= (int32
)si
->client_block_size
[int_val
];
514 bcopy(&int_val
, arg
, val_size
);
517 case IOV_SVAL(IOV_BLOCKSIZE
):
519 uint func
= ((uint32
)int_val
>> 16);
520 uint blksize
= (uint16
)int_val
;
523 if (func
> si
->num_funcs
) {
524 bcmerror
= BCME_BADARG
;
529 case 0: maxsize
= 32; break;
530 case 1: maxsize
= BLOCK_SIZE_4318
; break;
531 case 2: maxsize
= BLOCK_SIZE_4328
; break;
532 default: maxsize
= 0;
534 if (blksize
> maxsize
) {
535 bcmerror
= BCME_BADARG
;
543 si
->client_block_size
[func
] = blksize
;
548 case IOV_GVAL(IOV_RXCHAIN
):
549 int_val
= (int32
)si
->use_rxchain
;
550 bcopy(&int_val
, arg
, val_size
);
553 case IOV_GVAL(IOV_DMA
):
554 int_val
= (int32
)si
->sd_use_dma
;
555 bcopy(&int_val
, arg
, val_size
);
558 case IOV_SVAL(IOV_DMA
):
559 si
->sd_use_dma
= (bool)int_val
;
562 case IOV_GVAL(IOV_USEINTS
):
563 int_val
= (int32
)si
->use_client_ints
;
564 bcopy(&int_val
, arg
, val_size
);
567 case IOV_SVAL(IOV_USEINTS
):
568 si
->use_client_ints
= (bool)int_val
;
569 if (si
->use_client_ints
)
570 si
->intmask
|= CLIENT_INTR
;
572 si
->intmask
&= ~CLIENT_INTR
;
576 case IOV_GVAL(IOV_DIVISOR
):
577 int_val
= (uint32
)sd_divisor
;
578 bcopy(&int_val
, arg
, val_size
);
581 case IOV_SVAL(IOV_DIVISOR
):
582 sd_divisor
= int_val
;
585 case IOV_GVAL(IOV_POWER
):
586 int_val
= (uint32
)sd_power
;
587 bcopy(&int_val
, arg
, val_size
);
590 case IOV_SVAL(IOV_POWER
):
594 case IOV_GVAL(IOV_CLOCK
):
595 int_val
= (uint32
)sd_clock
;
596 bcopy(&int_val
, arg
, val_size
);
599 case IOV_SVAL(IOV_CLOCK
):
603 case IOV_GVAL(IOV_SDMODE
):
604 int_val
= (uint32
)sd_sdmode
;
605 bcopy(&int_val
, arg
, val_size
);
608 case IOV_SVAL(IOV_SDMODE
):
612 case IOV_GVAL(IOV_HISPEED
):
613 int_val
= (uint32
)sd_hiok
;
614 bcopy(&int_val
, arg
, val_size
);
617 case IOV_SVAL(IOV_HISPEED
):
621 case IOV_GVAL(IOV_NUMINTS
):
622 int_val
= (int32
)si
->intrcount
;
623 bcopy(&int_val
, arg
, val_size
);
626 case IOV_GVAL(IOV_NUMLOCALINTS
):
628 bcopy(&int_val
, arg
, val_size
);
631 case IOV_GVAL(IOV_HOSTREG
):
633 sdreg_t
*sd_ptr
= (sdreg_t
*)params
;
635 if (sd_ptr
->offset
< SD_SysAddr
|| sd_ptr
->offset
> SD_MaxCurCap
) {
636 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__
, sd_ptr
->offset
));
637 bcmerror
= BCME_BADARG
;
641 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__
,
642 (sd_ptr
->offset
& 1) ? 8 : ((sd_ptr
->offset
& 2) ? 16 : 32),
644 if (sd_ptr
->offset
& 1)
645 int_val
= 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
646 else if (sd_ptr
->offset
& 2)
647 int_val
= 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
649 int_val
= 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
651 bcopy(&int_val
, arg
, sizeof(int_val
));
655 case IOV_SVAL(IOV_HOSTREG
):
657 sdreg_t
*sd_ptr
= (sdreg_t
*)params
;
659 if (sd_ptr
->offset
< SD_SysAddr
|| sd_ptr
->offset
> SD_MaxCurCap
) {
660 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__
, sd_ptr
->offset
));
661 bcmerror
= BCME_BADARG
;
665 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__
, sd_ptr
->value
,
666 (sd_ptr
->offset
& 1) ? 8 : ((sd_ptr
->offset
& 2) ? 16 : 32),
671 case IOV_GVAL(IOV_DEVREG
):
673 sdreg_t
*sd_ptr
= (sdreg_t
*)params
;
676 if (sdioh_cfg_read(si
, sd_ptr
->func
, sd_ptr
->offset
, &data
)) {
677 bcmerror
= BCME_SDIO_ERROR
;
682 bcopy(&int_val
, arg
, sizeof(int_val
));
686 case IOV_SVAL(IOV_DEVREG
):
688 sdreg_t
*sd_ptr
= (sdreg_t
*)params
;
689 uint8 data
= (uint8
)sd_ptr
->value
;
691 if (sdioh_cfg_write(si
, sd_ptr
->func
, sd_ptr
->offset
, &data
)) {
692 bcmerror
= BCME_SDIO_ERROR
;
699 bcmerror
= BCME_UNSUPPORTED
;
707 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
710 sdioh_enable_hw_oob_intr(sdioh_info_t
*sd
, bool enable
)
716 data
= SDIO_SEPINT_MASK
| SDIO_SEPINT_OE
| SDIO_SEPINT_ACT_HI
;
718 data
= SDIO_SEPINT_ACT_HI
; /* disable hw oob interrupt */
720 status
= sdioh_request_byte(sd
, SDIOH_WRITE
, 0, SDIOD_CCCR_BRCM_SEPINT
, &data
);
723 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
726 sdioh_cfg_read(sdioh_info_t
*sd
, uint fnc_num
, uint32 addr
, uint8
*data
)
729 /* No lock needed since sdioh_request_byte does locking */
730 status
= sdioh_request_byte(sd
, SDIOH_READ
, fnc_num
, addr
, data
);
735 sdioh_cfg_write(sdioh_info_t
*sd
, uint fnc_num
, uint32 addr
, uint8
*data
)
737 /* No lock needed since sdioh_request_byte does locking */
739 status
= sdioh_request_byte(sd
, SDIOH_WRITE
, fnc_num
, addr
, data
);
744 sdioh_sdmmc_get_cisaddr(sdioh_info_t
*sd
, uint32 regaddr
)
746 /* read 24 bits and return valid 17 bit addr */
748 uint32 scratch
, regdata
;
749 uint8
*ptr
= (uint8
*)&scratch
;
750 for (i
= 0; i
< 3; i
++) {
751 if ((sdioh_sdmmc_card_regread (sd
, 0, regaddr
, 1, ®data
)) != SUCCESS
)
752 sd_err(("%s: Can't read!\n", __FUNCTION__
));
754 *ptr
++ = (uint8
) regdata
;
758 /* Only the lower 17-bits are valid */
759 scratch
= ltoh32(scratch
);
760 scratch
&= 0x0001FFFF;
765 sdioh_cis_read(sdioh_info_t
*sd
, uint func
, uint8
*cisd
, uint32 length
)
772 sd_trace(("%s: Func = %d\n", __FUNCTION__
, func
));
774 if (!sd
->func_cis_ptr
[func
]) {
776 sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__
, func
));
777 return SDIOH_API_RC_FAIL
;
780 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__
, func
, sd
->func_cis_ptr
[func
]));
782 for (count
= 0; count
< length
; count
++) {
783 offset
= sd
->func_cis_ptr
[func
] + count
;
784 if (sdioh_sdmmc_card_regread (sd
, 0, offset
, 1, &foo
) < 0) {
785 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__
));
786 return SDIOH_API_RC_FAIL
;
789 *cis
= (uint8
)(foo
& 0xff);
793 return SDIOH_API_RC_SUCCESS
;
797 sdioh_request_byte(sdioh_info_t
*sd
, uint rw
, uint func
, uint regaddr
, uint8
*byte
)
800 #if defined(MMC_SDIO_ABORT)
801 int sdio_abort_retry
= MMC_SDIO_ABORT_RETRY_LIMIT
;
804 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__
, rw
, func
, regaddr
));
806 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait
);
807 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL
);
808 if(rw
) { /* CMD52 Write */
810 /* Can only directly write to some F0 registers. Handle F2 enable
813 if (regaddr
== SDIOD_CCCR_IOEN
) {
814 if (gInstance
->func
[2]) {
815 sdio_claim_host(gInstance
->func
[2]);
816 if (*byte
& SDIO_FUNC_ENABLE_2
) {
817 /* Enable Function 2 */
818 err_ret
= sdio_enable_func(gInstance
->func
[2]);
820 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
824 /* Disable Function 2 */
825 err_ret
= sdio_disable_func(gInstance
->func
[2]);
827 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
831 sdio_release_host(gInstance
->func
[2]);
834 #if defined(MMC_SDIO_ABORT)
835 /* to allow abort command through F1 */
836 else if (regaddr
== SDIOD_CCCR_IOABORT
) {
837 while (sdio_abort_retry
--) {
838 if (gInstance
->func
[func
]) {
839 sdio_claim_host(gInstance
->func
[func
]);
841 * this sdio_f0_writeb() can be replaced with
842 * another api depending upon MMC driver change.
843 * As of this time, this is temporaray one
845 sdio_writeb(gInstance
->func
[func
],
846 *byte
, regaddr
, &err_ret
);
847 sdio_release_host(gInstance
->func
[func
]);
853 #endif /* MMC_SDIO_ABORT */
854 else if (regaddr
< 0xF0) {
855 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr
));
857 /* Claim host controller, perform F0 write, and release */
858 if (gInstance
->func
[func
]) {
859 sdio_claim_host(gInstance
->func
[func
]);
860 sdio_f0_writeb(gInstance
->func
[func
],
861 *byte
, regaddr
, &err_ret
);
862 sdio_release_host(gInstance
->func
[func
]);
866 /* Claim host controller, perform Fn write, and release */
867 if (gInstance
->func
[func
]) {
868 sdio_claim_host(gInstance
->func
[func
]);
869 sdio_writeb(gInstance
->func
[func
], *byte
, regaddr
, &err_ret
);
870 sdio_release_host(gInstance
->func
[func
]);
873 } else { /* CMD52 Read */
874 /* Claim host controller, perform Fn read, and release */
875 if (gInstance
->func
[func
]) {
876 sdio_claim_host(gInstance
->func
[func
]);
878 *byte
= sdio_f0_readb(gInstance
->func
[func
], regaddr
, &err_ret
);
880 *byte
= sdio_readb(gInstance
->func
[func
], regaddr
, &err_ret
);
882 sdio_release_host(gInstance
->func
[func
]);
887 if ((regaddr
== 0x1001F) && (err_ret
== -110)) {
889 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
890 rw
? "Write" : "Read", func
, regaddr
, *byte
, err_ret
));
894 return ((err_ret
== 0) ? SDIOH_API_RC_SUCCESS
: SDIOH_API_RC_FAIL
);
898 sdioh_request_word(sdioh_info_t
*sd
, uint cmd_type
, uint rw
, uint func
, uint addr
,
899 uint32
*word
, uint nbytes
)
901 int err_ret
= SDIOH_API_RC_FAIL
;
902 int err_ret2
= SDIOH_API_RC_SUCCESS
; // terence 20130621: prevent dhd_dpc in dead lock
903 #if defined(MMC_SDIO_ABORT)
904 int sdio_abort_retry
= MMC_SDIO_ABORT_RETRY_LIMIT
;
908 sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__
));
909 return SDIOH_API_RC_FAIL
;
912 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
913 __FUNCTION__
, cmd_type
, rw
, func
, addr
, nbytes
));
915 DHD_PM_RESUME_WAIT(sdioh_request_word_wait
);
916 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL
);
917 /* Claim host controller */
918 sdio_claim_host(gInstance
->func
[func
]);
920 if(rw
) { /* CMD52 Write */
922 sdio_writel(gInstance
->func
[func
], *word
, addr
, &err_ret
);
923 } else if (nbytes
== 2) {
924 sdio_writew(gInstance
->func
[func
], (*word
& 0xFFFF), addr
, &err_ret
);
926 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__
, nbytes
));
928 } else { /* CMD52 Read */
930 *word
= sdio_readl(gInstance
->func
[func
], addr
, &err_ret
);
931 } else if (nbytes
== 2) {
932 *word
= sdio_readw(gInstance
->func
[func
], addr
, &err_ret
) & 0xFFFF;
934 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__
, nbytes
));
938 /* Release host controller */
939 sdio_release_host(gInstance
->func
[func
]);
942 #if defined(MMC_SDIO_ABORT)
943 /* Any error on CMD53 transaction should abort that function using function 0. */
944 while (sdio_abort_retry
--) {
945 if (gInstance
->func
[0]) {
946 sdio_claim_host(gInstance
->func
[0]);
948 * this sdio_f0_writeb() can be replaced with another api
949 * depending upon MMC driver change.
950 * As of this time, this is temporaray one
952 sdio_writeb(gInstance
->func
[0],
953 func
, SDIOD_CCCR_IOABORT
, &err_ret2
);
954 sdio_release_host(gInstance
->func
[0]);
960 #endif /* MMC_SDIO_ABORT */
962 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n",
963 rw
? "Write" : "Read", err_ret
));
967 return (((err_ret
== 0)&&(err_ret2
== 0)) ? SDIOH_API_RC_SUCCESS
: SDIOH_API_RC_FAIL
);
970 #ifdef BCMSDIOH_TXGLOM
972 sdioh_glom_post(sdioh_info_t
*sd
, uint8
*frame
, void *pkt
, uint len
)
974 void *phead
= sd
->glom_info
.glom_pkt_head
;
975 void *ptail
= sd
->glom_info
.glom_pkt_tail
;
977 BCM_REFERENCE(frame
);
979 ASSERT(!PKTLINK(pkt
));
982 sd
->glom_info
.glom_pkt_head
= sd
->glom_info
.glom_pkt_tail
= pkt
;
986 PKTSETNEXT(sd
->osh
, ptail
, pkt
);
987 sd
->glom_info
.glom_pkt_tail
= pkt
;
989 sd
->glom_info
.count
++;
993 sdioh_glom_clear(sdioh_info_t
*sd
)
997 pnext
= sd
->glom_info
.glom_pkt_head
;
1000 sd_err(("sdioh_glom_clear: no first packet to clear!\n"));
1006 pnext
= PKTNEXT(sd
->osh
, pnow
);
1007 PKTSETNEXT(sd
->osh
, pnow
, NULL
);
1008 sd
->glom_info
.count
--;
1011 sd
->glom_info
.glom_pkt_head
= NULL
;
1012 sd
->glom_info
.glom_pkt_tail
= NULL
;
1013 if (sd
->glom_info
.count
!= 0) {
1014 sd_err(("sdioh_glom_clear: glom count mismatch!\n"));
1015 sd
->glom_info
.count
= 0;
1020 sdioh_set_mode(sdioh_info_t
*sd
, uint mode
)
1022 if (mode
== SDPCM_TXGLOM_CPY
)
1023 sd
->txglom_mode
= mode
;
1024 else if (mode
== SDPCM_TXGLOM_MDESC
)
1025 sd
->txglom_mode
= mode
;
1027 return (sd
->txglom_mode
);
1031 sdioh_glom_enabled(void)
1035 #endif /* BCMSDIOH_TXGLOM */
1037 static INLINE
int sdioh_request_packet_align(uint pkt_len
, uint write
, uint func
, int blk_size
)
1040 if (!write
|| pkt_len
< 32)
1041 pkt_len
= (pkt_len
+ 3) & 0xFFFFFFFC;
1042 else if ((pkt_len
> blk_size
) && (pkt_len
% blk_size
)) {
1043 if (func
== SDIO_FUNC_2
) {
1044 sd_err(("%s: [%s] dhd_sdio must align %d bytes"
1045 " packet larger than a %d bytes blk size by a blk size\n",
1046 __FUNCTION__
, write
? "W" : "R", pkt_len
, blk_size
));
1048 pkt_len
+= blk_size
- (pkt_len
% blk_size
);
1050 #ifdef CONFIG_MMC_MSM7X00A
1051 if ((pkt_len
% 64) == 32) {
1052 sd_err(("%s: Rounding up TX packet +=32\n", __FUNCTION__
));
1055 #endif /* CONFIG_MMC_MSM7X00A */
1060 sdioh_request_packet(sdioh_info_t
*sd
, uint fix_inc
, uint write
, uint func
,
1061 uint addr
, void *pkt
)
1063 bool fifo
= (fix_inc
== SDIOH_DATA_FIX
);
1067 uint ttl_len
, dma_len
, lft_len
, xfred_len
, pkt_len
;
1070 struct mmc_request mmc_req
;
1071 struct mmc_command mmc_cmd
;
1072 struct mmc_data mmc_dat
;
1073 #ifdef BCMSDIOH_TXGLOM
1074 uint8
*localbuf
= NULL
;
1075 uint local_plen
= 0;
1076 bool need_txglom
= write
&& sdioh_glom_enabled() &&
1077 (pkt
== sd
->glom_info
.glom_pkt_tail
) &&
1078 (sd
->glom_info
.glom_pkt_head
!= sd
->glom_info
.glom_pkt_tail
);
1079 #endif /* BCMSDIOH_TXGLOM */
1081 sd_trace(("%s: Enter\n", __FUNCTION__
));
1084 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait
);
1085 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL
);
1087 ttl_len
= xfred_len
= 0;
1088 #ifdef BCMSDIOH_TXGLOM
1090 pkt
= sd
->glom_info
.glom_pkt_head
;
1092 #endif /* BCMSDIOH_TXGLOM */
1094 /* at least 4 bytes alignment of skb buff is guaranteed */
1095 for (pnext
= pkt
; pnext
; pnext
= PKTNEXT(sd
->osh
, pnext
))
1096 ttl_len
+= PKTLEN(sd
->osh
, pnext
);
1098 blk_size
= sd
->client_block_size
[func
];
1099 if (((!write
&& sd
->use_rxchain
) ||
1100 #ifdef BCMSDIOH_TXGLOM
1101 (need_txglom
&& sd
->txglom_mode
== SDPCM_TXGLOM_MDESC
) ||
1103 0) && (ttl_len
>= blk_size
)) {
1104 blk_num
= ttl_len
/ blk_size
;
1105 dma_len
= blk_num
* blk_size
;
1111 lft_len
= ttl_len
- dma_len
;
1113 sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n",
1114 __FUNCTION__
, write
? "W" : "R",
1115 ttl_len
, func
, addr
, blk_num
, lft_len
));
1118 memset(&mmc_req
, 0, sizeof(struct mmc_request
));
1119 memset(&mmc_cmd
, 0, sizeof(struct mmc_command
));
1120 memset(&mmc_dat
, 0, sizeof(struct mmc_data
));
1122 /* Set up DMA descriptors */
1125 pnext
= PKTNEXT(sd
->osh
, pnext
)) {
1126 pkt_len
= PKTLEN(sd
->osh
, pnext
);
1128 if (dma_len
> pkt_len
)
1131 pkt_len
= xfred_len
= dma_len
;
1136 sg_set_buf(&sd
->sg_list
[SGCount
++],
1137 (uint8
*)PKTDATA(sd
->osh
, pnext
),
1140 if (SGCount
>= SDIOH_SDMMC_MAX_SG_ENTRIES
) {
1141 sd_err(("%s: sg list entries exceed limit\n",
1143 return (SDIOH_API_RC_FAIL
);
1147 mmc_dat
.sg
= sd
->sg_list
;
1148 mmc_dat
.sg_len
= SGCount
;
1149 mmc_dat
.blksz
= blk_size
;
1150 mmc_dat
.blocks
= blk_num
;
1151 mmc_dat
.flags
= write
? MMC_DATA_WRITE
: MMC_DATA_READ
;
1153 mmc_cmd
.opcode
= 53; /* SD_IO_RW_EXTENDED */
1154 mmc_cmd
.arg
= write
? 1<<31 : 0;
1155 mmc_cmd
.arg
|= (func
& 0x7) << 28;
1156 mmc_cmd
.arg
|= 1<<27;
1157 mmc_cmd
.arg
|= fifo
? 0 : 1<<26;
1158 mmc_cmd
.arg
|= (addr
& 0x1FFFF) << 9;
1159 mmc_cmd
.arg
|= blk_num
& 0x1FF;
1160 mmc_cmd
.flags
= MMC_RSP_SPI_R5
| MMC_RSP_R5
| MMC_CMD_ADTC
;
1162 mmc_req
.cmd
= &mmc_cmd
;
1163 mmc_req
.data
= &mmc_dat
;
1165 sdio_claim_host(gInstance
->func
[func
]);
1166 ////mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card);
1167 ////mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req);
1168 sdio_release_host(gInstance
->func
[func
]);
1170 err_ret
= mmc_cmd
.error
? mmc_cmd
.error
: mmc_dat
.error
;
1172 sd_err(("%s:CMD53 %s failed with code %d\n",
1174 write
? "write" : "read",
1178 addr
= addr
+ ttl_len
- lft_len
- dma_len
;
1184 /* Claim host controller */
1185 sdio_claim_host(gInstance
->func
[func
]);
1186 for (pnext
= pkt
; pnext
; pnext
= PKTNEXT(sd
->osh
, pnext
)) {
1187 uint8
*buf
= (uint8
*)PKTDATA(sd
->osh
, pnext
) +
1190 pkt_len
= PKTLEN(sd
->osh
, pnext
);
1191 if (0 != xfred_len
) {
1192 pkt_len
-= xfred_len
;
1195 #ifdef BCMSDIOH_TXGLOM
1198 uint prev_lft_len
= lft_len
;
1199 lft_len
= sdioh_request_packet_align(lft_len
, write
,
1202 if (lft_len
> prev_lft_len
) {
1203 sd_err(("%s: padding is unexpected! lft_len %d,"
1204 " prev_lft_len %d %s\n",
1205 __FUNCTION__
, lft_len
, prev_lft_len
,
1206 write
? "Write" : "Read"));
1209 localbuf
= (uint8
*)MALLOC(sd
->osh
, lft_len
);
1210 if (localbuf
== NULL
) {
1211 sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n",
1212 __FUNCTION__
, (write
) ? "TX" : "RX"));
1213 need_txglom
= FALSE
;
1217 bcopy(buf
, (localbuf
+ local_plen
), pkt_len
);
1218 local_plen
+= pkt_len
;
1220 if (PKTNEXT(sd
->osh
, pnext
)) {
1225 pkt_len
= local_plen
;
1229 #endif /* BCMSDIOH_TXGLOM */
1232 #ifdef BCMSDIOH_TXGLOM
1236 pkt_len
= sdioh_request_packet_align(pkt_len
, write
,
1239 pad
= pkt_len
- PKTLEN(sd
->osh
, pnext
);
1242 if (func
== SDIO_FUNC_2
) {
1243 sd_err(("%s: padding is unexpected! pkt_len %d,"
1244 " PKTLEN %d lft_len %d %s\n",
1245 __FUNCTION__
, pkt_len
, PKTLEN(sd
->osh
, pnext
),
1246 lft_len
, write
? "Write" : "Read"));
1248 if (PKTTAILROOM(sd
->osh
, pkt
) < pad
) {
1249 sd_info(("%s: insufficient tailroom %d, pad %d,"
1250 " lft_len %d pktlen %d, func %d %s\n",
1251 __FUNCTION__
, (int)PKTTAILROOM(sd
->osh
, pkt
),
1252 pad
, lft_len
, PKTLEN(sd
->osh
, pnext
), func
,
1253 write
? "W" : "R"));
1254 if (PKTPADTAILROOM(sd
->osh
, pkt
, pad
)) {
1255 sd_err(("%s: padding error size %d.\n",
1256 __FUNCTION__
, pad
));
1257 return SDIOH_API_RC_FAIL
;
1263 if ((write
) && (!fifo
))
1264 err_ret
= sdio_memcpy_toio(
1265 gInstance
->func
[func
],
1266 addr
, buf
, pkt_len
);
1268 err_ret
= sdio_memcpy_toio(
1269 gInstance
->func
[func
],
1270 addr
, buf
, pkt_len
);
1272 err_ret
= sdio_readsb(
1273 gInstance
->func
[func
],
1274 buf
, addr
, pkt_len
);
1276 err_ret
= sdio_memcpy_fromio(
1277 gInstance
->func
[func
],
1278 buf
, addr
, pkt_len
);
1281 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n",
1283 (write
) ? "TX" : "RX",
1284 pnext
, SGCount
, addr
, pkt_len
, err_ret
));
1286 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
1288 (write
) ? "TX" : "RX",
1289 pnext
, SGCount
, addr
, pkt_len
));
1295 sdio_release_host(gInstance
->func
[func
]);
1297 #ifdef BCMSDIOH_TXGLOM
1299 MFREE(sd
->osh
, localbuf
, lft_len
);
1300 #endif /* BCMSDIOH_TXGLOM */
1302 sd_trace(("%s: Exit\n", __FUNCTION__
));
1303 return ((err_ret
== 0) ? SDIOH_API_RC_SUCCESS
: SDIOH_API_RC_FAIL
);
1308 * This function takes a buffer or packet, and fixes everything up so that in the
1309 * end, a DMA-able packet is created.
1311 * A buffer does not have an associated packet pointer, and may or may not be aligned.
1312 * A packet may consist of a single packet, or a packet chain. If it is a packet chain,
1313 * then all the packets in the chain must be properly aligned. If the packet data is not
1314 * aligned, then there may only be one packet, and in this case, it is copied to a new
1319 sdioh_request_buffer(sdioh_info_t
*sd
, uint pio_dma
, uint fix_inc
, uint write
, uint func
,
1320 uint addr
, uint reg_width
, uint buflen_u
, uint8
*buffer
, void *pkt
)
1322 SDIOH_API_RC Status
;
1324 void *orig_buf
= NULL
;
1327 sd_trace(("%s: Enter\n", __FUNCTION__
));
1329 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait
);
1330 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL
);
1333 /* Case 1: we don't have a packet. */
1336 } else if ((ulong
)PKTDATA(sd
->osh
, pkt
) & DMA_ALIGN_MASK
) {
1337 /* Case 2: We have a packet, but it is unaligned.
1338 * in this case, we cannot have a chain.
1340 ASSERT(PKTNEXT(sd
->osh
, pkt
) == NULL
);
1342 orig_buf
= PKTDATA(sd
->osh
, pkt
);
1343 copylen
= PKTLEN(sd
->osh
, pkt
);
1348 tmppkt
= PKTGET_STATIC(sd
->osh
, copylen
, write
? TRUE
: FALSE
);
1349 if (tmppkt
== NULL
) {
1350 sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__
, copylen
));
1351 return SDIOH_API_RC_FAIL
;
1353 /* For a write, copy the buffer data into the packet. */
1355 bcopy(orig_buf
, PKTDATA(sd
->osh
, tmppkt
), copylen
);
1358 Status
= sdioh_request_packet(sd
, fix_inc
, write
, func
, addr
, tmppkt
);
1361 /* For a read, copy the packet data back to the buffer. */
1363 bcopy(PKTDATA(sd
->osh
, tmppkt
), orig_buf
, PKTLEN(sd
->osh
, tmppkt
));
1364 PKTFREE_STATIC(sd
->osh
, tmppkt
, write
? TRUE
: FALSE
);
1370 /* this function performs "abort" for both of host & device */
1372 sdioh_abort(sdioh_info_t
*sd
, uint func
)
1374 #if defined(MMC_SDIO_ABORT)
1375 char t_func
= (char) func
;
1376 #endif /* defined(MMC_SDIO_ABORT) */
1377 sd_trace(("%s: Enter\n", __FUNCTION__
));
1379 #if defined(MMC_SDIO_ABORT)
1380 /* issue abort cmd52 command through F1 */
1381 sdioh_request_byte(sd
, SD_IO_OP_WRITE
, SDIO_FUNC_0
, SDIOD_CCCR_IOABORT
, &t_func
);
1382 #endif /* defined(MMC_SDIO_ABORT) */
1384 sd_trace(("%s: Exit\n", __FUNCTION__
));
1385 return SDIOH_API_RC_SUCCESS
;
1388 /* Reset and re-initialize the device */
1389 int sdioh_sdio_reset(sdioh_info_t
*si
)
1391 sd_trace(("%s: Enter\n", __FUNCTION__
));
1392 sd_trace(("%s: Exit\n", __FUNCTION__
));
1393 return SDIOH_API_RC_SUCCESS
;
1396 /* Disable device interrupt */
1398 sdioh_sdmmc_devintr_off(sdioh_info_t
*sd
)
1400 sd_trace(("%s: %d\n", __FUNCTION__
, sd
->use_client_ints
));
1401 sd
->intmask
&= ~CLIENT_INTR
;
1404 /* Enable device interrupt */
1406 sdioh_sdmmc_devintr_on(sdioh_info_t
*sd
)
1408 sd_trace(("%s: %d\n", __FUNCTION__
, sd
->use_client_ints
));
1409 sd
->intmask
|= CLIENT_INTR
;
1412 /* Read client card reg */
1414 sdioh_sdmmc_card_regread(sdioh_info_t
*sd
, int func
, uint32 regaddr
, int regsize
, uint32
*data
)
1417 if ((func
== 0) || (regsize
== 1)) {
1420 sdioh_request_byte(sd
, SDIOH_READ
, func
, regaddr
, &temp
);
1423 sd_data(("%s: byte read data=0x%02x\n",
1424 __FUNCTION__
, *data
));
1426 sdioh_request_word(sd
, 0, SDIOH_READ
, func
, regaddr
, data
, regsize
);
1430 sd_data(("%s: word read data=0x%08x\n",
1431 __FUNCTION__
, *data
));
1437 #if !defined(OOB_INTR_ONLY)
1438 /* bcmsdh_sdmmc interrupt handler */
1439 static void IRQHandler(struct sdio_func
*func
)
1443 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1447 sdio_release_host(gInstance
->func
[0]);
1449 if (sd
->use_client_ints
) {
1451 ASSERT(sd
->intr_handler
);
1452 ASSERT(sd
->intr_handler_arg
);
1453 (sd
->intr_handler
)(sd
->intr_handler_arg
);
1455 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1457 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1458 __FUNCTION__
, sd
->client_intr_enabled
, sd
->intr_handler
));
1461 sdio_claim_host(gInstance
->func
[0]);
1464 /* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1465 static void IRQHandlerF2(struct sdio_func
*func
)
1469 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1476 #endif /* !defined(OOB_INTR_ONLY) */
1479 /* Write client card reg */
1481 sdioh_sdmmc_card_regwrite(sdioh_info_t
*sd
, int func
, uint32 regaddr
, int regsize
, uint32 data
)
1484 if ((func
== 0) || (regsize
== 1)) {
1488 sdioh_request_byte(sd
, SDIOH_READ
, func
, regaddr
, &temp
);
1489 sd_data(("%s: byte write data=0x%02x\n",
1490 __FUNCTION__
, data
));
1495 sdioh_request_word(sd
, 0, SDIOH_READ
, func
, regaddr
, &data
, regsize
);
1497 sd_data(("%s: word write data=0x%08x\n",
1498 __FUNCTION__
, data
));
1503 #endif /* NOTUSED */
1506 sdioh_start(sdioh_info_t
*si
, int stage
)
1508 sdioh_info_t
*sd
= gInstance
->sd
;
1511 sd_err(("%s Failed, sd is NULL\n", __FUNCTION__
));
1515 /* Need to do this stages as we can't enable the interrupt till
1516 downloading of the firmware is complete, other wise polling
1517 sdio access will come in way
1519 if (gInstance
->func
[0]) {
1521 /* Since the power to the chip is killed, we will have
1522 re enumerate the device again. Set the block size
1523 and enable the fucntion 1 for in preparation for
1524 downloading the code
1526 /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
1527 2.6.27. The implementation prior to that is buggy, and needs broadcom's
1531 if ((ret = sdio_reset_comm(gInstance->func[0]->card))) {
1532 sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
1538 sd
->sd_blockmode
= TRUE
;
1539 sd
->use_client_ints
= TRUE
;
1540 sd
->client_block_size
[0] = 64;
1542 if (gInstance
->func
[1]) {
1543 /* Claim host controller */
1544 sdio_claim_host(gInstance
->func
[1]);
1546 sd
->client_block_size
[1] = 64;
1547 if (sdio_set_block_size(gInstance
->func
[1], 64)) {
1548 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
1551 /* Release host controller F1 */
1552 sdio_release_host(gInstance
->func
[1]);
1555 if (gInstance
->func
[2]) {
1556 /* Claim host controller F2 */
1557 sdio_claim_host(gInstance
->func
[2]);
1559 sd
->client_block_size
[2] = sd_f2_blocksize
;
1560 if (sdio_set_block_size(gInstance
->func
[2],
1562 sd_err(("bcmsdh_sdmmc: Failed to set F2 "
1563 "blocksize to %d\n", sd_f2_blocksize
));
1566 /* Release host controller F2 */
1567 sdio_release_host(gInstance
->func
[2]);
1570 sdioh_sdmmc_card_enablefuncs(sd
);
1573 #if !defined(OOB_INTR_ONLY)
1574 sdio_claim_host(gInstance
->func
[0]);
1575 if (gInstance
->func
[2])
1576 sdio_claim_irq(gInstance
->func
[2], IRQHandlerF2
);
1577 if (gInstance
->func
[1])
1578 sdio_claim_irq(gInstance
->func
[1], IRQHandler
);
1579 sdio_release_host(gInstance
->func
[0]);
1580 #else /* defined(OOB_INTR_ONLY) */
1582 sdioh_enable_func_intr();
1584 bcmsdh_oob_intr_set(TRUE
);
1585 #endif /* !defined(OOB_INTR_ONLY) */
1589 sd_err(("%s Failed\n", __FUNCTION__
));
1595 sdioh_stop(sdioh_info_t
*si
)
1597 /* MSM7201A Android sdio stack has bug with interrupt
1598 So internaly within SDIO stack they are polling
1599 which cause issue when device is turned off. So
1600 unregister interrupt with SDIO stack to stop the
1603 if (gInstance
->func
[0]) {
1604 #if !defined(OOB_INTR_ONLY)
1605 sdio_claim_host(gInstance
->func
[0]);
1606 if (gInstance
->func
[1])
1607 sdio_release_irq(gInstance
->func
[1]);
1608 if (gInstance
->func
[2])
1609 sdio_release_irq(gInstance
->func
[2]);
1610 sdio_release_host(gInstance
->func
[0]);
1611 #else /* defined(OOB_INTR_ONLY) */
1613 sdioh_disable_func_intr();
1615 bcmsdh_oob_intr_set(FALSE
);
1616 #endif /* !defined(OOB_INTR_ONLY) */
1619 sd_err(("%s Failed\n", __FUNCTION__
));
1624 sdioh_waitlockfree(sdioh_info_t
*sd
)
1631 sdioh_gpioouten(sdioh_info_t
*sd
, uint32 gpio
)
1633 return SDIOH_API_RC_FAIL
;
1637 sdioh_gpioout(sdioh_info_t
*sd
, uint32 gpio
, bool enab
)
1639 return SDIOH_API_RC_FAIL
;
1643 sdioh_gpioin(sdioh_info_t
*sd
, uint32 gpio
)
1649 sdioh_gpio_init(sdioh_info_t
*sd
)
1651 return SDIOH_API_RC_FAIL
;