• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
3  *
4  * Copyright (C) 1999-2019, Broadcom.
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions
16  * of the license of that module.  An independent module is a module which is
17  * not derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  *
25  * <<Broadcom-WL-IPTag/Proprietary,Open:>>
26  *
27  * $Id: bcmsdh_sdmmc.c 782528 2018-09-28 12:15:40Z $
28  */
29 #include <typedefs.h>
30 
31 #include <bcmdevs.h>
32 #include <bcmendian.h>
33 #include <bcmutils.h>
34 #include <osl.h>
35 #include <sdio.h>     /* SDIO Device and Protocol Specs */
36 #include <sdioh.h>    /* Standard SDIO Host Controller Specification */
37 #include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
38 #include <sdiovar.h>  /* ioctl/iovars */
39 
40 #include <linux/mmc/core.h>
41 #include <linux/mmc/host.h>
42 #include <linux/mmc/card.h>
43 #include <linux/mmc/sdio_func.h>
44 #include <linux/mmc/sdio_ids.h>
45 
46 #include <dngl_stats.h>
47 #include <dhd.h>
48 #include <dhd_dbg.h>
49 
50 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
51 #include <linux/suspend.h>
52 extern volatile bool dhd_mmc_suspend;
53 #endif // endif
54 #include "bcmsdh_sdmmc.h"
55 
56 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)) ||                          \
57     (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
mmc_host_clk_hold(struct mmc_host * host)58 static inline void mmc_host_clk_hold(struct mmc_host *host)
59 {
60     BCM_REFERENCE(host);
61     return;
62 }
63 
mmc_host_clk_release(struct mmc_host * host)64 static inline void mmc_host_clk_release(struct mmc_host *host)
65 {
66     BCM_REFERENCE(host);
67     return;
68 }
69 
mmc_host_clk_rate(struct mmc_host * host)70 static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
71 {
72     return host->ios.clock;
73 }
74 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) */
75 
76 #ifndef BCMSDH_MODULE
77 extern int sdio_function_init(void);
78 extern void sdio_function_cleanup(void);
79 #endif /* BCMSDH_MODULE */
80 
81 #if !defined(OOB_INTR_ONLY)
82 static void IRQHandler(struct sdio_func *func);
83 static void IRQHandlerF2(struct sdio_func *func);
84 #endif /* !defined(OOB_INTR_ONLY) */
85 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
86 #if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE)
87 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) && defined(MMC_SW_RESET)
88 extern int mmc_sw_reset(struct mmc_host *host);
89 #else
90 extern int sdio_reset_comm(struct mmc_card *card);
91 #endif
92 #endif
93 #ifdef GLOBAL_SDMMC_INSTANCE
94 extern PBCMSDH_SDMMC_INSTANCE gInstance;
95 #endif
96 #ifdef CUSTOMER_HW_ALLWINNER
97 extern int sunxi_mmc_check_r1_ready(struct mmc_host *mmc, unsigned ms);
98 #endif
99 
100 #define DEFAULT_SDIO_F2_BLKSIZE 512
101 #ifndef CUSTOM_SDIO_F2_BLKSIZE
102 #define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE
103 #endif // endif
104 
105 #define DEFAULT_SDIO_F1_BLKSIZE 64
106 #ifndef CUSTOM_SDIO_F1_BLKSIZE
107 #define CUSTOM_SDIO_F1_BLKSIZE DEFAULT_SDIO_F1_BLKSIZE
108 #endif // endif
109 
110 #define MAX_IO_RW_EXTENDED_BLK 511
111 
112 uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
113 uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE;
114 uint sd_f1_blocksize = CUSTOM_SDIO_F1_BLKSIZE;
115 
116 #if defined(BT_OVER_SDIO)
117 uint sd_f3_blocksize = 64;
118 #endif /* defined (BT_OVER_SDIO) */
119 
120 uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
121 
122 uint sd_power = 1;    /* Default to SD Slot powered ON */
123 uint sd_clock = 1;    /* Default to SD Clock turned ON */
124 uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */
125 uint sd_msglevel = SDH_ERROR_VAL;
126 uint sd_use_dma = TRUE;
127 
128 #ifndef CUSTOM_RXCHAIN
129 #define CUSTOM_RXCHAIN 0
130 #endif // endif
131 
132 DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
133 DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
134 DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
135 DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
136 
137 #define DMA_ALIGN_MASK 0x03
138 #define MMC_SDIO_ABORT_RETRY_LIMIT 5
139 
140 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
141                              int regsize, uint32 *data);
142 
143 #if defined(BT_OVER_SDIO)
sdioh_sdmmc_card_enable_func_f3(sdioh_info_t * sd,struct sdio_func * func)144 extern void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd,
145                                             struct sdio_func *func)
146 {
147     sd->func[0x3] = func;
148     sd_info(("%s sd->func[0x3] %p\n", __FUNCTION__, sd->func[0x3]));
149 }
150 #endif /* defined (BT_OVER_SDIO) */
151 
152 void sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz);
153 uint sdmmc_get_clock_rate(sdioh_info_t *sd);
154 void sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div);
155 
sdioh_sdmmc_card_enablefuncs(sdioh_info_t * sd)156 static int sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
157 {
158     int err_ret;
159     uint32 fbraddr;
160     uint8 func;
161 
162     sd_trace(("%s\n", __FUNCTION__));
163 
164     /* Get the Card's common CIS address */
165     sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
166     sd->func_cis_ptr[0] = sd->com_cis_ptr;
167     sd_info(
168         ("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
169 
170     /* Get the Card's function CIS (for each function) */
171     for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; func <= sd->num_funcs;
172          func++, fbraddr += SDIOD_FBR_SIZE) {
173         sd->func_cis_ptr[func] =
174             sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
175         sd_info(("%s: Function %d CIS Ptr = 0x%x\n", __FUNCTION__, func,
176                  sd->func_cis_ptr[func]));
177     }
178 
179     sd->func_cis_ptr[0] = sd->com_cis_ptr;
180     sd_info(
181         ("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
182 
183     /* Enable Function 1 */
184     sdio_claim_host(sd->func[1]);
185     err_ret = sdio_enable_func(sd->func[1]);
186     sdio_release_host(sd->func[1]);
187     if (err_ret) {
188         sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x\n", err_ret));
189     }
190 
191     return FALSE;
192 }
193 
194 /*
195  *	Public entry points & extern's
196  */
sdioh_attach(osl_t * osh,struct sdio_func * func)197 extern sdioh_info_t *sdioh_attach(osl_t *osh, struct sdio_func *func)
198 {
199     sdioh_info_t *sd = NULL;
200     int err_ret;
201 
202     sd_trace(("%s\n", __FUNCTION__));
203 
204     if (func == NULL) {
205         sd_err(("%s: sdio function device is NULL\n", __FUNCTION__));
206         return NULL;
207     }
208 
209     if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
210         sd_err(("sdioh_attach: out of memory, malloced %d bytes\n",
211                 MALLOCED(osh)));
212         return NULL;
213     }
214     bzero((char *)sd, sizeof(sdioh_info_t));
215     sd->osh = osh;
216     sd->fake_func0.num = 0;
217     sd->fake_func0.card = func->card;
218     sd->func[0] = &sd->fake_func0;
219 #ifdef GLOBAL_SDMMC_INSTANCE
220     if (func->num == 0x2) {
221         sd->func[1] = gInstance->func[1];
222     }
223 #else
224     sd->func[1] = func->card->sdio_func[0];
225 #endif
226     sd->func[0x2] = func->card->sdio_func[1];
227 #ifdef GLOBAL_SDMMC_INSTANCE
228     sd->func[func->num] = func;
229 #endif
230 
231 #if defined(BT_OVER_SDIO)
232     sd->func[0x3] = NULL;
233 #endif /* defined (BT_OVER_SDIO) */
234 
235     sd->num_funcs = 0x2;
236     sd->sd_blockmode = TRUE;
237     sd->use_client_ints = TRUE;
238     sd->client_block_size[0] = 0x40;
239     sd->use_rxchain = CUSTOM_RXCHAIN;
240     if (sd->func[1] == NULL || sd->func[0x2] == NULL) {
241         sd_err(("%s: func 1 or 2 is null \n", __FUNCTION__));
242         goto fail;
243     }
244     sdio_set_drvdata(sd->func[1], sd);
245 
246     sdio_claim_host(sd->func[1]);
247     sd->client_block_size[1] = sd_f1_blocksize;
248     err_ret = sdio_set_block_size(sd->func[1], sd_f1_blocksize);
249     sdio_release_host(sd->func[1]);
250     if (err_ret) {
251         sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize(%d)\n", err_ret));
252         goto fail;
253     }
254 
255     sdio_claim_host(sd->func[0x2]);
256     if ((func->device == BCM43362_CHIP_ID || func->device == BCM4330_CHIP_ID) &&
257         sd_f2_blocksize > 0x80) {
258         sd_f2_blocksize = 0x80;
259     }
260     sd->client_block_size[0x2] = sd_f2_blocksize;
261     printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize);
262     err_ret = sdio_set_block_size(sd->func[0x2], sd_f2_blocksize);
263     sdio_release_host(sd->func[0x2]);
264     if (err_ret) {
265         sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d(%d)\n",
266                 sd_f2_blocksize, err_ret));
267         goto fail;
268     }
269 
270     sd->sd_clk_rate = sdmmc_get_clock_rate(sd);
271     printf("%s: sd clock rate = %u\n", __FUNCTION__, sd->sd_clk_rate);
272     sdioh_sdmmc_card_enablefuncs(sd);
273 #if !defined(OOB_INTR_ONLY)
274     mutex_init(
275         &sd->claim_host_mutex); // terence 20140926: fix for claim host issue
276 #endif
277 
278     sd_trace(("%s: Done\n", __FUNCTION__));
279     return sd;
280 
281 fail:
282     MFREE(sd->osh, sd, sizeof(sdioh_info_t));
283     return NULL;
284 }
285 
sdioh_detach(osl_t * osh,sdioh_info_t * sd)286 extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd)
287 {
288     sd_trace(("%s\n", __FUNCTION__));
289 
290     if (sd) {
291         /* Disable Function 2 */
292         if (sd->func[0x2]) {
293             sdio_claim_host(sd->func[0x2]);
294             sdio_disable_func(sd->func[0x2]);
295             sdio_release_host(sd->func[0x2]);
296         }
297 
298         /* Disable Function 1 */
299         if (sd->func[1]) {
300             sdio_claim_host(sd->func[1]);
301             sdio_disable_func(sd->func[1]);
302             sdio_release_host(sd->func[1]);
303         }
304 
305         sd->func[1] = NULL;
306         sd->func[0x2] = NULL;
307 
308         MFREE(sd->osh, sd, sizeof(sdioh_info_t));
309     }
310     return SDIOH_API_RC_SUCCESS;
311 }
312 
313 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
314 
sdioh_enable_func_intr(sdioh_info_t * sd)315 extern SDIOH_API_RC sdioh_enable_func_intr(sdioh_info_t *sd)
316 {
317     uint8 reg;
318     int err;
319 
320     if (sd->func[0] == NULL) {
321         sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__));
322         return SDIOH_API_RC_FAIL;
323     }
324 
325     sdio_claim_host(sd->func[0]);
326     reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err);
327     if (err) {
328         sd_err(
329             ("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
330         sdio_release_host(sd->func[0]);
331         return SDIOH_API_RC_FAIL;
332     }
333     /* Enable F1 and F2 interrupts, clear master enable */
334     reg &= ~INTR_CTL_MASTER_EN;
335     reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
336 #if defined(BT_OVER_SDIO)
337     reg |= (INTR_CTL_FUNC3_EN);
338 #endif /* defined (BT_OVER_SDIO) */
339     sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err);
340     sdio_release_host(sd->func[0]);
341 
342     if (err) {
343         sd_err(
344             ("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
345         return SDIOH_API_RC_FAIL;
346     }
347 
348     return SDIOH_API_RC_SUCCESS;
349 }
350 
sdioh_disable_func_intr(sdioh_info_t * sd)351 extern SDIOH_API_RC sdioh_disable_func_intr(sdioh_info_t *sd)
352 {
353     uint8 reg;
354     int err;
355 
356     if (sd->func[0] == NULL) {
357         sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__));
358         return SDIOH_API_RC_FAIL;
359     }
360 
361     sdio_claim_host(sd->func[0]);
362     reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err);
363     if (err) {
364         sd_err(
365             ("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
366         sdio_release_host(sd->func[0]);
367         return SDIOH_API_RC_FAIL;
368     }
369     reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
370 #if defined(BT_OVER_SDIO)
371     reg &= ~INTR_CTL_FUNC3_EN;
372 #endif // endif
373     /* Disable master interrupt with the last function interrupt */
374     if (!(reg & 0xFE)) {
375         reg = 0;
376     }
377     sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err);
378     sdio_release_host(sd->func[0]);
379 
380     if (err) {
381         sd_err(
382             ("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
383         return SDIOH_API_RC_FAIL;
384     }
385 
386     return SDIOH_API_RC_SUCCESS;
387 }
388 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
389 
390 /* Configure callback to client when we recieve client interrupt */
sdioh_interrupt_register(sdioh_info_t * sd,sdioh_cb_fn_t fn,void * argh)391 extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn,
392                                              void *argh)
393 {
394     sd_trace(("%s: Entering\n", __FUNCTION__));
395     if (fn == NULL) {
396         sd_err(
397             ("%s: interrupt handler is NULL, not registering\n", __FUNCTION__));
398         return SDIOH_API_RC_FAIL;
399     }
400 #if !defined(OOB_INTR_ONLY)
401     sd->intr_handler = fn;
402     sd->intr_handler_arg = argh;
403     sd->intr_handler_valid = TRUE;
404 
405     /* register and unmask irq */
406     if (sd->func[0x2]) {
407         sdio_claim_host(sd->func[0x2]);
408         sdio_claim_irq(sd->func[0x2], IRQHandlerF2);
409         sdio_release_host(sd->func[0x2]);
410     }
411 
412     if (sd->func[1]) {
413         sdio_claim_host(sd->func[1]);
414         sdio_claim_irq(sd->func[1], IRQHandler);
415         sdio_release_host(sd->func[1]);
416     }
417 #elif defined(HW_OOB)
418     sdioh_enable_func_intr(sd);
419 #endif /* !defined(OOB_INTR_ONLY) */
420 
421     return SDIOH_API_RC_SUCCESS;
422 }
423 
sdioh_interrupt_deregister(sdioh_info_t * sd)424 extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *sd)
425 {
426     sd_trace(("%s: Entering\n", __FUNCTION__));
427 
428 #if !defined(OOB_INTR_ONLY)
429     if (sd->func[1]) {
430         /* register and unmask irq */
431         sdio_claim_host(sd->func[1]);
432         sdio_release_irq(sd->func[1]);
433         sdio_release_host(sd->func[1]);
434     }
435 
436     if (sd->func[0x2]) {
437         /* Claim host controller F2 */
438         sdio_claim_host(sd->func[0x2]);
439         sdio_release_irq(sd->func[0x2]);
440         /* Release host controller F2 */
441         sdio_release_host(sd->func[0x2]);
442     }
443 
444     sd->intr_handler_valid = FALSE;
445     sd->intr_handler = NULL;
446     sd->intr_handler_arg = NULL;
447 #elif defined(HW_OOB)
448     if (dhd_download_fw_on_driverload) {
449         sdioh_disable_func_intr(sd);
450     }
451 #endif /* !defined(OOB_INTR_ONLY) */
452     return SDIOH_API_RC_SUCCESS;
453 }
454 
sdioh_interrupt_query(sdioh_info_t * sd,bool * onoff)455 extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
456 {
457     sd_trace(("%s: Entering\n", __FUNCTION__));
458     *onoff = sd->client_intr_enabled;
459     return SDIOH_API_RC_SUCCESS;
460 }
461 
462 #if defined(DHD_DEBUG)
sdioh_interrupt_pending(sdioh_info_t * sd)463 extern bool sdioh_interrupt_pending(sdioh_info_t *sd)
464 {
465     return (0);
466 }
467 #endif // endif
468 
sdioh_query_iofnum(sdioh_info_t * sd)469 uint sdioh_query_iofnum(sdioh_info_t *sd)
470 {
471     return sd->num_funcs;
472 }
473 
474 /* IOVar table */
475 enum {
476     IOV_MSGLEVEL = 1,
477     IOV_BLOCKMODE,
478     IOV_BLOCKSIZE,
479     IOV_DMA,
480     IOV_USEINTS,
481     IOV_NUMINTS,
482     IOV_NUMLOCALINTS,
483     IOV_HOSTREG,
484     IOV_DEVREG,
485     IOV_DIVISOR,
486     IOV_SDMODE,
487     IOV_HISPEED,
488     IOV_HCIREGS,
489     IOV_POWER,
490     IOV_CLOCK,
491     IOV_RXCHAIN
492 };
493 
494 const bcm_iovar_t sdioh_iovars[] = {
495     {"sd_msglevel", IOV_MSGLEVEL, 0, 0, IOVT_UINT32, 0},
496     {"sd_blockmode", IOV_BLOCKMODE, 0, 0, IOVT_BOOL, 0},
497     {"sd_blocksize", IOV_BLOCKSIZE, 0, 0, IOVT_UINT32,
498      0}, /* ((fn << 16) | size) */
499     {"sd_dma", IOV_DMA, 0, 0, IOVT_BOOL, 0},
500     {"sd_ints", IOV_USEINTS, 0, 0, IOVT_BOOL, 0},
501     {"sd_numints", IOV_NUMINTS, 0, 0, IOVT_UINT32, 0},
502     {"sd_numlocalints", IOV_NUMLOCALINTS, 0, 0, IOVT_UINT32, 0},
503     {"sd_divisor", IOV_DIVISOR, 0, 0, IOVT_UINT32, 0},
504     {"sd_power", IOV_POWER, 0, 0, IOVT_UINT32, 0},
505     {"sd_clock", IOV_CLOCK, 0, 0, IOVT_UINT32, 0},
506     {"sd_mode", IOV_SDMODE, 0, 0, IOVT_UINT32, 100},
507     {"sd_highspeed", IOV_HISPEED, 0, 0, IOVT_UINT32, 0},
508     {"sd_rxchain", IOV_RXCHAIN, 0, 0, IOVT_BOOL, 0},
509     {NULL, 0, 0, 0, 0, 0}};
510 
sdioh_iovar_op(sdioh_info_t * si,const char * name,void * params,int plen,void * arg,int len,bool set)511 int sdioh_iovar_op(sdioh_info_t *si, const char *name, void *params, int plen,
512                    void *arg, int len, bool set)
513 {
514     const bcm_iovar_t *vi = NULL;
515     int bcmerror = 0;
516     int val_size;
517     int32 int_val = 0;
518     bool bool_val;
519     uint32 actionid;
520 
521     ASSERT(name);
522     ASSERT(len >= 0);
523 
524     /* Get must have return space; Set does not take qualifiers */
525     ASSERT(set || (arg && len));
526     ASSERT(!set || (!params && !plen));
527 
528     sd_trace(
529         ("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
530 
531     if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
532         bcmerror = BCME_UNSUPPORTED;
533         goto exit;
534     }
535 
536     if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) {
537         goto exit;
538     }
539 
540     /* Set up params so get and set can share the convenience variables */
541     if (params == NULL) {
542         params = arg;
543         plen = len;
544     }
545 
546     if (vi->type == IOVT_VOID) {
547         val_size = 0;
548     } else if (vi->type == IOVT_BUFFER) {
549         val_size = len;
550     } else {
551         val_size = sizeof(int);
552     }
553 
554     if (plen >= (int)sizeof(int_val)) {
555         bcopy(params, &int_val, sizeof(int_val));
556     }
557 
558     bool_val = (int_val != 0) ? TRUE : FALSE;
559     BCM_REFERENCE(bool_val);
560 
561     actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
562     switch (actionid) {
563         case IOV_GVAL(IOV_MSGLEVEL):
564             int_val = (int32)sd_msglevel;
565             bcopy(&int_val, arg, val_size);
566             break;
567 
568         case IOV_SVAL(IOV_MSGLEVEL):
569             sd_msglevel = int_val;
570             break;
571 
572         case IOV_GVAL(IOV_BLOCKMODE):
573             int_val = (int32)si->sd_blockmode;
574             bcopy(&int_val, arg, val_size);
575             break;
576 
577         case IOV_SVAL(IOV_BLOCKMODE):
578             si->sd_blockmode = (bool)int_val;
579             /* Haven't figured out how to make non-block mode with DMA */
580             break;
581 
582         case IOV_GVAL(IOV_BLOCKSIZE):
583             if ((uint32)int_val > si->num_funcs) {
584                 bcmerror = BCME_BADARG;
585                 break;
586             }
587             int_val = (int32)si->client_block_size[int_val];
588             bcopy(&int_val, arg, val_size);
589             break;
590 
591         case IOV_SVAL(IOV_BLOCKSIZE): {
592             uint func = ((uint32)int_val >> 16);
593             uint blksize = (uint16)int_val;
594             uint maxsize;
595 
596             if (func > si->num_funcs) {
597                 bcmerror = BCME_BADARG;
598                 break;
599             }
600 
601             switch (func) {
602                 case 0:
603                     maxsize = 0x20;
604                     break;
605                 case 1:
606                     maxsize = BLOCK_SIZE_4318;
607                     break;
608                 case 0x2:
609                     maxsize = BLOCK_SIZE_4328;
610                     break;
611                 default:
612                     maxsize = 0;
613             }
614             if (blksize > maxsize) {
615                 bcmerror = BCME_BADARG;
616                 break;
617             }
618             if (!blksize) {
619                 blksize = maxsize;
620             }
621 
622             /* Now set it */
623             si->client_block_size[func] = blksize;
624 
625 #ifdef USE_DYNAMIC_F2_BLKSIZE
626             if (si->func[func] == NULL) {
627                 sd_err(("%s: SDIO Device not present\n", __FUNCTION__));
628                 bcmerror = BCME_NORESOURCE;
629                 break;
630             }
631             sdio_claim_host(si->func[func]);
632             bcmerror = sdio_set_block_size(si->func[func], blksize);
633             if (bcmerror) {
634                 sd_err(("%s: Failed to set F%d blocksize to %d(%d)\n",
635                         __FUNCTION__, func, blksize, bcmerror));
636             }
637             sdio_release_host(si->func[func]);
638 #endif /* USE_DYNAMIC_F2_BLKSIZE */
639             break;
640         }
641 
642         case IOV_GVAL(IOV_RXCHAIN):
643             int_val = (int32)si->use_rxchain;
644             bcopy(&int_val, arg, val_size);
645             break;
646 
647         case IOV_GVAL(IOV_DMA):
648             int_val = (int32)si->sd_use_dma;
649             bcopy(&int_val, arg, val_size);
650             break;
651 
652         case IOV_SVAL(IOV_DMA):
653             si->sd_use_dma = (bool)int_val;
654             break;
655 
656         case IOV_GVAL(IOV_USEINTS):
657             int_val = (int32)si->use_client_ints;
658             bcopy(&int_val, arg, val_size);
659             break;
660 
661         case IOV_SVAL(IOV_USEINTS):
662             si->use_client_ints = (bool)int_val;
663             if (si->use_client_ints) {
664                 si->intmask |= CLIENT_INTR;
665             } else {
666                 si->intmask &= ~CLIENT_INTR;
667             }
668 
669             break;
670 
671         case IOV_GVAL(IOV_DIVISOR):
672             int_val = (uint32)sd_divisor;
673             bcopy(&int_val, arg, val_size);
674             break;
675 
676         case IOV_SVAL(IOV_DIVISOR):
677             /* set the clock to divisor, if value is non-zero & power of 2 */
678             if (int_val && !(int_val & (int_val - 1))) {
679                 sd_divisor = int_val;
680                 sdmmc_set_clock_divisor(si, sd_divisor);
681             } else {
682                 DHD_ERROR(
683                     ("%s: Invalid sd_divisor value, should be power of 2!\n",
684                      __FUNCTION__));
685             }
686             break;
687 
688         case IOV_GVAL(IOV_POWER):
689             int_val = (uint32)sd_power;
690             bcopy(&int_val, arg, val_size);
691             break;
692 
693         case IOV_SVAL(IOV_POWER):
694             sd_power = int_val;
695             break;
696 
697         case IOV_GVAL(IOV_CLOCK):
698             int_val = (uint32)sd_clock;
699             bcopy(&int_val, arg, val_size);
700             break;
701 
702         case IOV_SVAL(IOV_CLOCK):
703             sd_clock = int_val;
704             break;
705 
706         case IOV_GVAL(IOV_SDMODE):
707             int_val = (uint32)sd_sdmode;
708             bcopy(&int_val, arg, val_size);
709             break;
710 
711         case IOV_SVAL(IOV_SDMODE):
712             sd_sdmode = int_val;
713             break;
714 
715         case IOV_GVAL(IOV_HISPEED):
716             int_val = (uint32)sd_hiok;
717             bcopy(&int_val, arg, val_size);
718             break;
719 
720         case IOV_SVAL(IOV_HISPEED):
721             sd_hiok = int_val;
722             break;
723 
724         case IOV_GVAL(IOV_NUMINTS):
725             int_val = (int32)si->intrcount;
726             bcopy(&int_val, arg, val_size);
727             break;
728 
729         case IOV_GVAL(IOV_NUMLOCALINTS):
730             int_val = (int32)0;
731             bcopy(&int_val, arg, val_size);
732             break;
733         default:
734             bcmerror = BCME_UNSUPPORTED;
735             break;
736     }
737 exit:
738 
739     return bcmerror;
740 }
741 
742 #if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN)
743 
744 SDIOH_API_RC
sdioh_enable_hw_oob_intr(sdioh_info_t * sd,bool enable)745 sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
746 {
747     SDIOH_API_RC status;
748     uint8 data;
749 
750     if (enable)
751 #ifdef HW_OOB_LOW_LEVEL
752         data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
753 #else
754         data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI;
755 #endif
756     else {
757         data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */
758     }
759 
760     status =
761         sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data);
762     return status;
763 }
764 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
765 
sdioh_cfg_read(sdioh_info_t * sd,uint fnc_num,uint32 addr,uint8 * data)766 extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr,
767                                    uint8 *data)
768 {
769     SDIOH_API_RC status;
770     /* No lock needed since sdioh_request_byte does locking */
771     status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
772     return status;
773 }
774 
sdioh_cfg_write(sdioh_info_t * sd,uint fnc_num,uint32 addr,uint8 * data)775 extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr,
776                                     uint8 *data)
777 {
778     /* No lock needed since sdioh_request_byte does locking */
779     SDIOH_API_RC status;
780     status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
781     return status;
782 }
783 
sdioh_sdmmc_get_cisaddr(sdioh_info_t * sd,uint32 regaddr)784 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
785 {
786     /* read 24 bits and return valid 17 bit addr */
787     int i;
788     uint32 scratch, regdata;
789     uint8 *ptr = (uint8 *)&scratch;
790     for (i = 0; i < 0x3; i++) {
791         if ((sdioh_sdmmc_card_regread(sd, 0, regaddr, 1, &regdata)) !=
792             SUCCESS) {
793             sd_err(("%s: Can't read!\n", __FUNCTION__));
794         }
795 
796         *ptr++ = (uint8)regdata;
797         regaddr++;
798     }
799 
800     /* Only the lower 17-bits are valid */
801     scratch = ltoh32(scratch);
802     scratch &= 0x0001FFFF;
803     return (scratch);
804 }
805 
sdioh_cis_read(sdioh_info_t * sd,uint func,uint8 * cisd,uint32 length)806 extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd,
807                                    uint32 length)
808 {
809     uint32 count;
810     int offset;
811     uint32 foo;
812     uint8 *cis = cisd;
813 
814     sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
815 
816     if (!sd->func_cis_ptr[func]) {
817         bzero(cis, length);
818         sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
819         return SDIOH_API_RC_FAIL;
820     }
821 
822     sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func,
823             sd->func_cis_ptr[func]));
824 
825     for (count = 0; count < length; count++) {
826         offset = sd->func_cis_ptr[func] + count;
827         if (sdioh_sdmmc_card_regread(sd, 0, offset, 1, &foo) < 0) {
828             sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
829             return SDIOH_API_RC_FAIL;
830         }
831 
832         *cis = (uint8)(foo & 0xff);
833         cis++;
834     }
835 
836     return SDIOH_API_RC_SUCCESS;
837 }
838 
sdioh_cisaddr_read(sdioh_info_t * sd,uint func,uint8 * cisd,uint32 offset)839 extern SDIOH_API_RC sdioh_cisaddr_read(sdioh_info_t *sd, uint func, uint8 *cisd,
840                                        uint32 offset)
841 {
842     uint32 foo;
843 
844     sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
845 
846     if (!sd->func_cis_ptr[func]) {
847         sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
848         return SDIOH_API_RC_FAIL;
849     }
850 
851     sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func,
852             sd->func_cis_ptr[func]));
853 
854     if (sdioh_sdmmc_card_regread(sd, 0, sd->func_cis_ptr[func] + offset, 1,
855                                  &foo) < 0) {
856         sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
857         return SDIOH_API_RC_FAIL;
858     }
859 
860     *cisd = (uint8)(foo & 0xff);
861 
862     return SDIOH_API_RC_SUCCESS;
863 }
864 
sdioh_request_byte(sdioh_info_t * sd,uint rw,uint func,uint regaddr,uint8 * byte)865 extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func,
866                                        uint regaddr, uint8 *byte)
867 {
868     int err_ret = 0;
869 #if defined(MMC_SDIO_ABORT)
870     int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT;
871 #endif // endif
872     struct osl_timespec now, before;
873 
874     if (sd_msglevel & SDH_COST_VAL) {
875         osl_do_gettimeofday(&before);
876     }
877 
878     sd_info(
879         ("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
880 
881     DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
882     DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
883     if (rw) { /* CMD52 Write */
884         if (func == 0) {
885             /* Can only directly write to some F0 registers.  Handle F2 enable
886              * as a special case.
887              */
888             if (regaddr == SDIOD_CCCR_IOEN) {
889 #if defined(BT_OVER_SDIO)
890                 do {
891                     if (sd->func[0x3]) {
892                         sd_info(("bcmsdh_sdmmc F3: *byte 0x%x\n", *byte));
893 
894                         if (*byte & SDIO_FUNC_ENABLE_3) {
895                             sdio_claim_host(sd->func[0x3]);
896 
897                             /* Set Function 3 Block Size */
898                             err_ret = sdio_set_block_size(sd->func[3],
899                                                           sd_f3_blocksize);
900                             if (err_ret) {
901                                 sd_err(("F3 blocksize set err%d\n", err_ret));
902                             }
903 
904                             /* Enable Function 3 */
905                             sd_info(("bcmsdh_sdmmc F3: enable F3 fn %p\n",
906                                      sd->func[0x3]));
907                             err_ret = sdio_enable_func(sd->func[0x3]);
908                             if (err_ret) {
909                                 sd_err(("bcmsdh_sdmmc: enable F3 err:%d\n",
910                                         err_ret));
911                             }
912 
913                             sdio_release_host(sd->func[0x3]);
914 
915                             break;
916                         } else if (*byte & SDIO_FUNC_DISABLE_3) {
917                             sdio_claim_host(sd->func[0x3]);
918 
919                             /* Disable Function 3 */
920                             sd_info(("bcmsdh_sdmmc F3: disable F3 fn %p\n",
921                                      sd->func[0x3]));
922                             err_ret = sdio_disable_func(sd->func[0x3]);
923                             if (err_ret) {
924                                 sd_err(("bcmsdh_sdmmc: Disable F3 err:%d\n",
925                                         err_ret));
926                             }
927                             sdio_release_host(sd->func[0x3]);
928                             sd->func[0x3] = NULL;
929 
930                             break;
931                         }
932                     }
933 #endif /* defined (BT_OVER_SDIO) */
934                     if (sd->func[0x2]) {
935                         sdio_claim_host(sd->func[0x2]);
936                         if (*byte & SDIO_FUNC_ENABLE_2) {
937                             /* Enable Function 2 */
938                             err_ret = sdio_enable_func(sd->func[2]);
939                             if (err_ret) {
940                                 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d\n",
941                                         err_ret));
942                             }
943                         } else {
944                             /* Disable Function 2 */
945                             err_ret = sdio_disable_func(sd->func[2]);
946                             if (err_ret) {
947                                 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d\n",
948                                         err_ret));
949                             }
950                         }
951                         sdio_release_host(sd->func[0x2]);
952                     }
953 #if defined(BT_OVER_SDIO)
954                 } while (0);
955 #endif /* defined (BT_OVER_SDIO) */
956             }
957 #if defined(MMC_SDIO_ABORT)
958             /* to allow abort command through F1 */
959             else if (regaddr == SDIOD_CCCR_IOABORT) {
960                 while (sdio_abort_retry--) {
961                     if (sd->func[func]) {
962                         sdio_claim_host(sd->func[func]);
963                         /*
964                          * this sdio_f0_writeb() can be replaced with
965                          * another api depending upon MMC driver change.
966                          * As of this time, this is temporaray one
967                          */
968                         sdio_writeb(sd->func[func], *byte, regaddr, &err_ret);
969                         sdio_release_host(sd->func[func]);
970                     }
971                     if (!err_ret) {
972                         break;
973                     }
974                 }
975             }
976 #endif      /* MMC_SDIO_ABORT */
977             /* to allow abort command through F1 */
978 #if defined(SDIO_ISR_THREAD)
979             else if (regaddr == SDIOD_CCCR_INTR_EXTN) {
980                 while (sdio_abort_retry--) {
981                     if (sd->func[func]) {
982                         sdio_claim_host(sd->func[func]);
983                         /*
984                          * this sdio_f0_writeb() can be replaced with
985                          * another api depending upon MMC driver change.
986                          * As of this time, this is temporaray one
987                          */
988                         sdio_writeb(sd->func[func], *byte, regaddr, &err_ret);
989                         sdio_release_host(sd->func[func]);
990                     }
991                     if (!err_ret) {
992                         break;
993                     }
994                 }
995             }
996 #endif
997             else if (regaddr < 0xF0) {
998                 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n",
999                         regaddr));
1000             } else {
1001                 /* Claim host controller, perform F0 write, and release */
1002                 if (sd->func[func]) {
1003                     sdio_claim_host(sd->func[func]);
1004                     sdio_f0_writeb(sd->func[func], *byte, regaddr, &err_ret);
1005                     sdio_release_host(sd->func[func]);
1006                 }
1007             }
1008         } else {
1009             /* Claim host controller, perform Fn write, and release */
1010             if (sd->func[func]) {
1011                 sdio_claim_host(sd->func[func]);
1012                 sdio_writeb(sd->func[func], *byte, regaddr, &err_ret);
1013                 sdio_release_host(sd->func[func]);
1014             }
1015         }
1016     } else { /* CMD52 Read */
1017         /* Claim host controller, perform Fn read, and release */
1018         if (sd->func[func]) {
1019             sdio_claim_host(sd->func[func]);
1020             if (func == 0) {
1021                 *byte = sdio_f0_readb(sd->func[func], regaddr, &err_ret);
1022             } else {
1023                 *byte = sdio_readb(sd->func[func], regaddr, &err_ret);
1024             }
1025             sdio_release_host(sd->func[func]);
1026         }
1027     }
1028 
1029 #ifdef CUSTOMER_HW_ALLWINNER
1030     // AW judge sdio read write timeout, 1s
1031     if (sunxi_mmc_check_r1_ready(sd->func[func]->card->host, 0x3E8) != 0) {
1032         printf("%s data timeout.\n", __FUNCTION__);
1033     }
1034 #endif
1035 
1036     if (err_ret) {
1037         if ((regaddr == 0x1001F) &&
1038             ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ) ||
1039              (err_ret == -EIO))) {
1040         } else {
1041             sd_err(
1042                 ("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
1043                  rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
1044         }
1045     }
1046 
1047     if (sd_msglevel & SDH_COST_VAL) {
1048         uint32 diff_us;
1049         osl_do_gettimeofday(&now);
1050         diff_us = osl_do_gettimediff(&now, &before);
1051         sd_cost(("%s: rw=%d len=1 cost = %3dms %3dus\n", __FUNCTION__, rw,
1052                  diff_us / 0x3E8, diff_us % 0x3E8));
1053     }
1054 
1055     return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
1056 }
1057 
sdioh_set_mode(sdioh_info_t * sd,uint mode)1058 uint sdioh_set_mode(sdioh_info_t *sd, uint mode)
1059 {
1060     if (mode == SDPCM_TXGLOM_CPY) {
1061         sd->txglom_mode = mode;
1062     } else if (mode == SDPCM_TXGLOM_MDESC) {
1063         sd->txglom_mode = mode;
1064     }
1065 
1066     return (sd->txglom_mode);
1067 }
1068 
1069 #ifdef PKT_STATICS
sdioh_get_spend_time(sdioh_info_t * sd)1070 uint32 sdioh_get_spend_time(sdioh_info_t *sd)
1071 {
1072     return (sd->sdio_spent_time_us);
1073 }
1074 #endif
1075 
sdioh_request_word(sdioh_info_t * sd,uint cmd_type,uint rw,uint func,uint addr,uint32 * word,uint nbytes)1076 extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw,
1077                                        uint func, uint addr, uint32 *word,
1078                                        uint nbytes)
1079 {
1080     int err_ret = SDIOH_API_RC_FAIL;
1081     int err_ret2 =
1082         SDIOH_API_RC_SUCCESS; // terence 20130621: prevent dhd_dpc in dead lock
1083 #if defined(MMC_SDIO_ABORT)
1084     int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT;
1085 #endif // endif
1086     struct osl_timespec now, before;
1087 
1088     if (sd_msglevel & SDH_COST_VAL) {
1089         osl_do_gettimeofday(&before);
1090     }
1091 
1092     if (func == 0) {
1093         sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
1094         return SDIOH_API_RC_FAIL;
1095     }
1096 
1097     sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
1098              __FUNCTION__, cmd_type, rw, func, addr, nbytes));
1099 
1100     DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
1101     DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
1102     /* Claim host controller */
1103     sdio_claim_host(sd->func[func]);
1104 
1105     if (rw) { /* CMD52 Write */
1106         if (nbytes == 0x4) {
1107             sdio_writel(sd->func[func], *word, addr, &err_ret);
1108         } else if (nbytes == 0x2) {
1109             sdio_writew(sd->func[func], (*word & 0xFFFF), addr, &err_ret);
1110         } else {
1111             sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
1112         }
1113     } else { /* CMD52 Read */
1114         if (nbytes == 0x4) {
1115             *word = sdio_readl(sd->func[func], addr, &err_ret);
1116         } else if (nbytes == 0x2) {
1117             *word = sdio_readw(sd->func[func], addr, &err_ret) & 0xFFFF;
1118         } else {
1119             sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
1120         }
1121     }
1122 
1123 #ifdef CUSTOMER_HW_ALLWINNER
1124     // AW judge sdio read write timeout, 1s
1125     if (sunxi_mmc_check_r1_ready(sd->func[func]->card->host, 0x3E8) != 0) {
1126         printf("%s data timeout.\n", __FUNCTION__);
1127     }
1128 #endif
1129 
1130     /* Release host controller */
1131     sdio_release_host(sd->func[func]);
1132 
1133     if (err_ret) {
1134 #if defined(MMC_SDIO_ABORT)
1135         /* Any error on CMD53 transaction should abort that function using
1136          * function 0. */
1137         while (sdio_abort_retry--) {
1138             if (sd->func[0]) {
1139                 sdio_claim_host(sd->func[0]);
1140                 /*
1141                  * this sdio_f0_writeb() can be replaced with another api
1142                  * depending upon MMC driver change.
1143                  * As of this time, this is temporaray one
1144                  */
1145                 sdio_writeb(sd->func[0], func, SDIOD_CCCR_IOABORT, &err_ret2);
1146 
1147 #ifdef CUSTOMER_HW_ALLWINNER
1148                 // AW judge sdio read write timeout, 1s
1149                 if (sunxi_mmc_check_r1_ready(sd->func[func]->card->host,
1150                                              0x3E8) != 0) {
1151                     printf("%s data timeout, SDIO_CCCR_IOABORT.\n",
1152                            __FUNCTION__);
1153                 }
1154 #endif
1155                 sdio_release_host(sd->func[0]);
1156             }
1157             if (!err_ret2) {
1158                 break;
1159             }
1160         }
1161         if (err_ret)
1162 #endif /* MMC_SDIO_ABORT */
1163         {
1164             sd_err(("bcmsdh_sdmmc: Failed to %s word F%d:@0x%05x=%02x, Err: "
1165                     "0x%08x\n",
1166                     rw ? "Write" : "Read", func, addr, *word, err_ret));
1167         }
1168     }
1169 
1170     if (sd_msglevel & SDH_COST_VAL) {
1171         uint32 diff_us;
1172         osl_do_gettimeofday(&now);
1173         diff_us = osl_do_gettimediff(&now, &before);
1174         sd_cost(("%s: rw=%d, len=%d cost = %3dms %3dus\n", __FUNCTION__, rw,
1175                  nbytes, diff_us / 0x3E8, diff_us % 0x3E8));
1176     }
1177 
1178     return (((err_ret == 0) && (err_ret2 == 0)) ? SDIOH_API_RC_SUCCESS
1179                                                 : SDIOH_API_RC_FAIL);
1180 }
1181 
1182 #ifdef BCMSDIOH_TXGLOM
sdioh_request_packet_chain(sdioh_info_t * sd,uint fix_inc,uint write,uint func,uint addr,void * pkt)1183 static SDIOH_API_RC sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc,
1184                                                uint write, uint func, uint addr,
1185                                                void *pkt)
1186 {
1187     bool fifo = (fix_inc == SDIOH_DATA_FIX);
1188     int err_ret = 0;
1189     void *pnext;
1190     uint ttl_len, pkt_offset;
1191     uint blk_num;
1192     uint blk_size;
1193     uint max_blk_count;
1194     uint max_req_size;
1195     struct mmc_request mmc_req;
1196     struct mmc_command mmc_cmd;
1197     struct mmc_data mmc_dat;
1198     uint32 sg_count;
1199     struct sdio_func *sdio_func = sd->func[func];
1200     struct mmc_host *host = sdio_func->card->host;
1201     uint8 *localbuf = NULL;
1202     uint local_plen = 0;
1203     uint pkt_len = 0;
1204     struct osl_timespec now, before;
1205 
1206     sd_trace(("%s: Enter\n", __FUNCTION__));
1207     ASSERT(pkt);
1208     DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
1209     DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
1210 
1211 #ifndef PKT_STATICS
1212     if (sd_msglevel & SDH_COST_VAL)
1213 #endif
1214         osl_do_gettimeofday(&before);
1215 
1216     blk_size = sd->client_block_size[func];
1217     max_blk_count = min(host->max_blk_count, (uint)MAX_IO_RW_EXTENDED_BLK);
1218     max_req_size = min(max_blk_count * blk_size, host->max_req_size);
1219 
1220     pkt_offset = 0;
1221     pnext = pkt;
1222 
1223     ttl_len = 0;
1224     sg_count = 0;
1225     if (sd->txglom_mode == SDPCM_TXGLOM_MDESC) {
1226         while (pnext != NULL) {
1227             ttl_len = 0;
1228             sg_count = 0;
1229             memset(&mmc_req, 0, sizeof(struct mmc_request));
1230             memset(&mmc_cmd, 0, sizeof(struct mmc_command));
1231             memset(&mmc_dat, 0, sizeof(struct mmc_data));
1232             sg_init_table(sd->sg_list, ARRAYSIZE(sd->sg_list));
1233 
1234             /* Set up scatter-gather DMA descriptors. this loop is to find out
1235              * the max data we can transfer with one command 53. blocks per
1236              * command is limited by host max_req_size and 9-bit max block
1237              * number. when the total length of this packet chain is bigger than
1238              * max_req_size, use multiple SD_IO_RW_EXTENDED commands (each
1239              * transfer is still block aligned)
1240              */
1241             while (pnext != NULL && ttl_len < max_req_size) {
1242                 int pkt_len;
1243                 int sg_data_size;
1244                 uint8 *pdata = (uint8 *)PKTDATA(sd->osh, pnext);
1245 
1246                 ASSERT(pdata != NULL);
1247                 pkt_len = PKTLEN(sd->osh, pnext);
1248                 sd_trace(("%s[%d] data=%p, len=%d\n", __FUNCTION__, write,
1249                           pdata, pkt_len));
1250                 /* sg_count is unlikely larger than the array size, and this is
1251                  * NOT something we can handle here, but in case it happens,
1252                  * PLEASE put a restriction on max tx/glom count (based on
1253                  * host->max_segs).
1254                  */
1255                 if (sg_count >= ARRAYSIZE(sd->sg_list)) {
1256                     sd_err(("%s: sg list entries(%u) exceed limit(%zu),"
1257                             " sd blk_size=%u\n",
1258                             __FUNCTION__, sg_count,
1259                             (size_t)ARRAYSIZE(sd->sg_list), blk_size));
1260                     return (SDIOH_API_RC_FAIL);
1261                 }
1262                 pdata += pkt_offset;
1263 
1264                 sg_data_size = pkt_len - pkt_offset;
1265                 if (sg_data_size > max_req_size - ttl_len) {
1266                     sg_data_size = max_req_size - ttl_len;
1267                 }
1268                 /* some platforms put a restriction on the data size of each
1269                  * scatter-gather DMA descriptor, use multiple sg buffers when
1270                  * xfer_size is bigger than max_seg_size
1271                  */
1272                 if (sg_data_size > host->max_seg_size) {
1273                     sg_data_size = host->max_seg_size;
1274                 }
1275                 sg_set_buf(&sd->sg_list[sg_count++], pdata, sg_data_size);
1276 
1277                 ttl_len += sg_data_size;
1278                 pkt_offset += sg_data_size;
1279                 if (pkt_offset == pkt_len) {
1280                     pnext = PKTNEXT(sd->osh, pnext);
1281                     pkt_offset = 0;
1282                 }
1283             }
1284 
1285             if (ttl_len % blk_size != 0) {
1286                 sd_err(("%s, data length %d not aligned to block size %d\n",
1287                         __FUNCTION__, ttl_len, blk_size));
1288                 return SDIOH_API_RC_FAIL;
1289             }
1290             blk_num = ttl_len / blk_size;
1291             mmc_dat.sg = sd->sg_list;
1292             mmc_dat.sg_len = sg_count;
1293             mmc_dat.blksz = blk_size;
1294             mmc_dat.blocks = blk_num;
1295             mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
1296             mmc_cmd.opcode = 0x35; /* SD_IO_RW_EXTENDED */
1297             mmc_cmd.arg = write ? 1 << 0x1F : 0;
1298             mmc_cmd.arg |= (func & 0x7) << 0x1C;
1299             mmc_cmd.arg |= 1 << 0x1B;
1300             mmc_cmd.arg |= fifo ? 0 : 1 << 0x1A;
1301             mmc_cmd.arg |= (addr & 0x1FFFF) << 0x9;
1302             mmc_cmd.arg |= blk_num & 0x1FF;
1303             mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
1304             mmc_req.cmd = &mmc_cmd;
1305             mmc_req.data = &mmc_dat;
1306             if (!fifo) {
1307                 addr += ttl_len;
1308             }
1309 
1310             sdio_claim_host(sdio_func);
1311             mmc_set_data_timeout(&mmc_dat, sdio_func->card);
1312             mmc_wait_for_req(host, &mmc_req);
1313             sdio_release_host(sdio_func);
1314 
1315             err_ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
1316             if (err_ret != 0) {
1317                 sd_err(("%s:CMD53 %s failed with code %d\n", __FUNCTION__,
1318                         write ? "write" : "read", err_ret));
1319                 return SDIOH_API_RC_FAIL;
1320             }
1321         }
1322     } else if (sd->txglom_mode == SDPCM_TXGLOM_CPY) {
1323         for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
1324             ttl_len += PKTLEN(sd->osh, pnext);
1325         }
1326         /* Claim host controller */
1327         sdio_claim_host(sd->func[func]);
1328         for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
1329             uint8 *buf = (uint8 *)PKTDATA(sd->osh, pnext);
1330             pkt_len = PKTLEN(sd->osh, pnext);
1331 
1332             if (!localbuf) {
1333                 localbuf = (uint8 *)MALLOC(sd->osh, ttl_len);
1334                 if (localbuf == NULL) {
1335                     sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n",
1336                             __FUNCTION__, (write) ? "TX" : "RX"));
1337                     goto txglomfail;
1338                 }
1339             }
1340 
1341             bcopy(buf, (localbuf + local_plen), pkt_len);
1342             local_plen += pkt_len;
1343             if (PKTNEXT(sd->osh, pnext)) {
1344                 continue;
1345             }
1346 
1347             buf = localbuf;
1348             pkt_len = local_plen;
1349         txglomfail:
1350             /* Align Patch */
1351             if (!write || pkt_len < 0x20) {
1352                 pkt_len = (pkt_len + 0x3) & 0xFFFFFFFC;
1353             } else if (pkt_len % blk_size) {
1354                 pkt_len += blk_size - (pkt_len % blk_size);
1355             }
1356 
1357             if ((write) && (!fifo)) {
1358                 err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, pkt_len);
1359             } else if (write) {
1360                 err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, pkt_len);
1361             } else if (fifo) {
1362                 err_ret = sdio_readsb(sd->func[func], buf, addr, pkt_len);
1363             } else {
1364                 err_ret =
1365                     sdio_memcpy_fromio(sd->func[func], buf, addr, pkt_len);
1366             }
1367 
1368             if (err_ret) {
1369                 sd_err(
1370                     ("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n",
1371                      __FUNCTION__, (write) ? "TX" : "RX", pnext, sg_count, addr,
1372                      pkt_len, err_ret));
1373             } else {
1374                 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
1375                           __FUNCTION__, (write) ? "TX" : "RX", pnext, sg_count,
1376                           addr, pkt_len));
1377             }
1378 
1379             if (!fifo) {
1380                 addr += pkt_len;
1381             }
1382             sg_count++;
1383         }
1384         sdio_release_host(sd->func[func]);
1385     } else {
1386         sd_err(
1387             ("%s: set to wrong glom mode %d\n", __FUNCTION__, sd->txglom_mode));
1388         return SDIOH_API_RC_FAIL;
1389     }
1390 
1391     if (localbuf) {
1392         MFREE(sd->osh, localbuf, ttl_len);
1393     }
1394 
1395 #ifndef PKT_STATICS
1396     if (sd_msglevel & SDH_COST_VAL)
1397 #endif
1398     {
1399         uint32 diff_us;
1400         osl_do_gettimeofday(&now);
1401         diff_us = osl_do_gettimediff(&now, &before);
1402         sd_cost(("%s: rw=%d, ttl_len=%4d cost = %3dms %3dus\n", __FUNCTION__,
1403                  write, ttl_len, diff_us / 0x3E8, diff_us % 0x3E8));
1404 #ifdef PKT_STATICS
1405         if (write && (func == 0x2)) {
1406             sd->sdio_spent_time_us = diff_us;
1407         }
1408 #endif
1409     }
1410 
1411     sd_trace(("%s: Exit\n", __FUNCTION__));
1412     return SDIOH_API_RC_SUCCESS;
1413 }
1414 #endif /* BCMSDIOH_TXGLOM */
1415 
sdioh_buffer_tofrom_bus(sdioh_info_t * sd,uint fix_inc,uint write,uint func,uint addr,uint8 * buf,uint len)1416 static SDIOH_API_RC sdioh_buffer_tofrom_bus(sdioh_info_t *sd, uint fix_inc,
1417                                             uint write, uint func, uint addr,
1418                                             uint8 *buf, uint len)
1419 {
1420     bool fifo = (fix_inc == SDIOH_DATA_FIX);
1421     int err_ret = 0;
1422     struct osl_timespec now, before;
1423 
1424     sd_trace(("%s: Enter\n", __FUNCTION__));
1425     ASSERT(buf);
1426 
1427     if (sd_msglevel & SDH_COST_VAL) {
1428         osl_do_gettimeofday(&before);
1429     }
1430 
1431     /* NOTE:
1432      * For all writes, each packet length is aligned to 32 (or 4)
1433      * bytes in dhdsdio_txpkt_preprocess, and for glom the last packet length
1434      * is aligned to block boundary. If you want to align each packet to
1435      * a custom size, please do it in dhdsdio_txpkt_preprocess, NOT here
1436      *
1437      * For reads, the alignment is doen in sdioh_request_buffer.
1438      *
1439      */
1440     sdio_claim_host(sd->func[func]);
1441 
1442     if ((write) && (!fifo)) {
1443         err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len);
1444     } else if (write) {
1445         err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len);
1446     } else if (fifo) {
1447         err_ret = sdio_readsb(sd->func[func], buf, addr, len);
1448     } else {
1449         err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, len);
1450     }
1451 
1452 #ifdef CUSTOMER_HW_ALLWINNER
1453     // AW judge sdio read write timeout, 1s
1454     if (sunxi_mmc_check_r1_ready(sd->func[func]->card->host, 0x3E8) != 0) {
1455         printf("%s data timeout.\n", __FUNCTION__);
1456     }
1457 #endif
1458 
1459     sdio_release_host(sd->func[func]);
1460 
1461     if (err_ret) {
1462         sd_err(("%s: %s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=%d\n",
1463                 __FUNCTION__, (write) ? "TX" : "RX", buf, addr, len, err_ret));
1464     } else {
1465         sd_trace(("%s: %s xfr'd %p, addr=0x%05x, len=%d\n", __FUNCTION__,
1466                   (write) ? "TX" : "RX", buf, addr, len));
1467     }
1468 
1469     sd_trace(("%s: Exit\n", __FUNCTION__));
1470 
1471     if (sd_msglevel & SDH_COST_VAL) {
1472         uint32 diff_us;
1473         osl_do_gettimeofday(&now);
1474         diff_us = osl_do_gettimediff(&now, &before);
1475         sd_cost(("%s: rw=%d, len=%4d cost = %3dms %3dus\n", __FUNCTION__, write,
1476                  len, diff_us / 0x3E8, diff_us % 0x3E8));
1477     }
1478 
1479     return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
1480 }
1481 
1482 /*
1483  * This function takes a buffer or packet, and fixes everything up so that in
1484  * the end, a DMA-able packet is created.
1485  *
1486  * A buffer does not have an associated packet pointer, and may or may not be
1487  * aligned. A packet may consist of a single packet, or a packet chain.  If it
1488  * is a packet chain, then all the packets in the chain must be properly
1489  * aligned.  If the packet data is not aligned, then there may only be one
1490  * packet, and in this case, it is copied to a new aligned packet.
1491  *
1492  */
sdioh_request_buffer(sdioh_info_t * sd,uint pio_dma,uint fix_inc,uint write,uint func,uint addr,uint reg_width,uint buf_len,uint8 * buffer,void * pkt)1493 extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma,
1494                                          uint fix_inc, uint write, uint func,
1495                                          uint addr, uint reg_width,
1496                                          uint buf_len, uint8 *buffer, void *pkt)
1497 {
1498     SDIOH_API_RC status;
1499     void *tmppkt;
1500     struct osl_timespec now, before;
1501 
1502     sd_trace(("%s: Enter\n", __FUNCTION__));
1503     DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
1504     DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
1505 
1506     if (sd_msglevel & SDH_COST_VAL) {
1507         osl_do_gettimeofday(&before);
1508     }
1509 
1510     if (pkt) {
1511 #ifdef BCMSDIOH_TXGLOM
1512         /* packet chain, only used for tx/rx glom, all packets length
1513          * are aligned, total length is a block multiple
1514          */
1515         if (PKTNEXT(sd->osh, pkt)) {
1516             return sdioh_request_packet_chain(sd, fix_inc, write, func, addr,
1517                                               pkt);
1518         }
1519 #endif /* BCMSDIOH_TXGLOM */
1520         /* non-glom mode, ignore the buffer parameter and use the packet pointer
1521          * (this shouldn't happen)
1522          */
1523         buffer = PKTDATA(sd->osh, pkt);
1524         buf_len = PKTLEN(sd->osh, pkt);
1525     }
1526 
1527     ASSERT(buffer);
1528 
1529     /* buffer and length are aligned, use it directly so we can avoid memory
1530      * copy */
1531     if (((ulong)buffer & DMA_ALIGN_MASK) == 0 &&
1532         (buf_len & DMA_ALIGN_MASK) == 0) {
1533         return sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, buffer,
1534                                        buf_len);
1535     }
1536 
1537     sd_trace(("%s: [%d] doing memory copy buf=%p, len=%d\n", __FUNCTION__,
1538               write, buffer, buf_len));
1539 
1540     /* otherwise, a memory copy is needed as the input buffer is not aligned */
1541     tmppkt = PKTGET_STATIC(sd->osh, buf_len + DEFAULT_SDIO_F2_BLKSIZE,
1542                            write ? TRUE : FALSE);
1543     if (tmppkt == NULL) {
1544         sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buf_len));
1545         return SDIOH_API_RC_FAIL;
1546     }
1547 
1548     if (write) {
1549         bcopy(buffer, PKTDATA(sd->osh, tmppkt), buf_len);
1550     }
1551 
1552     status = sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr,
1553                                      PKTDATA(sd->osh, tmppkt),
1554                                      ROUNDUP(buf_len, (DMA_ALIGN_MASK + 1)));
1555 
1556     if (!write) {
1557         bcopy(PKTDATA(sd->osh, tmppkt), buffer, buf_len);
1558     }
1559 
1560     PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE);
1561 
1562     if (sd_msglevel & SDH_COST_VAL) {
1563         uint32 diff_us;
1564         osl_do_gettimeofday(&now);
1565         diff_us = osl_do_gettimediff(&now, &before);
1566         sd_cost(("%s: rw=%d, len=%d cost = %3dms %3dus\n", __FUNCTION__, write,
1567                  buf_len, diff_us / 0x3E8, diff_us % 0x3E8));
1568     }
1569 
1570     return status;
1571 }
1572 
1573 /* this function performs "abort" for both of host & device */
sdioh_abort(sdioh_info_t * sd,uint func)1574 extern int sdioh_abort(sdioh_info_t *sd, uint func)
1575 {
1576 #if defined(MMC_SDIO_ABORT)
1577     char t_func = (char)func;
1578 #endif /* defined(MMC_SDIO_ABORT) */
1579     sd_trace(("%s: Enter\n", __FUNCTION__));
1580 
1581 #if defined(MMC_SDIO_ABORT)
1582     /* issue abort cmd52 command through F1 */
1583     sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT,
1584                        &t_func);
1585 #endif /* defined(MMC_SDIO_ABORT) */
1586 
1587     sd_trace(("%s: Exit\n", __FUNCTION__));
1588     return SDIOH_API_RC_SUCCESS;
1589 }
1590 
1591 /* Reset and re-initialize the device */
sdioh_sdio_reset(sdioh_info_t * si)1592 int sdioh_sdio_reset(sdioh_info_t *si)
1593 {
1594     sd_trace(("%s: Enter\n", __FUNCTION__));
1595     sd_trace(("%s: Exit\n", __FUNCTION__));
1596     return SDIOH_API_RC_SUCCESS;
1597 }
1598 
1599 /* Disable device interrupt */
sdioh_sdmmc_devintr_off(sdioh_info_t * sd)1600 void sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1601 {
1602     sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1603     sd->intmask &= ~CLIENT_INTR;
1604 }
1605 
1606 /* Enable device interrupt */
sdioh_sdmmc_devintr_on(sdioh_info_t * sd)1607 void sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1608 {
1609     sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1610     sd->intmask |= CLIENT_INTR;
1611 }
1612 
1613 /* Read client card reg */
sdioh_sdmmc_card_regread(sdioh_info_t * sd,int func,uint32 regaddr,int regsize,uint32 * data)1614 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
1615                              int regsize, uint32 *data)
1616 {
1617     if ((func == 0) || (regsize == 1)) {
1618         uint8 temp = 0;
1619 
1620         sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1621         *data = temp;
1622         *data &= 0xff;
1623         sd_data(("%s: byte read data=0x%02x\n", __FUNCTION__, *data));
1624     } else {
1625         if (sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data,
1626                                regsize)) {
1627             return BCME_SDIO_ERROR;
1628         }
1629         if (regsize == 0x2) {
1630             *data &= 0xffff;
1631         }
1632 
1633         sd_data(("%s: word read data=0x%08x\n", __FUNCTION__, *data));
1634     }
1635 
1636     return SUCCESS;
1637 }
1638 
1639 #if !defined(OOB_INTR_ONLY)
sdio_claim_host_lock_local(sdioh_info_t * sd)1640 void sdio_claim_host_lock_local(
1641     sdioh_info_t *sd) // terence 20140926: fix for claim host issue
1642 {
1643 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
1644     if (sd) {
1645         mutex_lock(&sd->claim_host_mutex);
1646     }
1647 #endif
1648 }
1649 
sdio_claim_host_unlock_local(sdioh_info_t * sd)1650 void sdio_claim_host_unlock_local(
1651     sdioh_info_t *sd) // terence 20140926: fix for claim host issue
1652 {
1653 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
1654     if (sd) {
1655         mutex_unlock(&sd->claim_host_mutex);
1656     }
1657 #endif
1658 }
1659 
1660 /* bcmsdh_sdmmc interrupt handler */
IRQHandler(struct sdio_func * func)1661 static void IRQHandler(struct sdio_func *func)
1662 {
1663     sdioh_info_t *sd;
1664 
1665     sd = sdio_get_drvdata(func);
1666 
1667     ASSERT(sd != NULL);
1668 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
1669     if (mutex_is_locked(&sd->claim_host_mutex)) {
1670         printf("%s: muxtex is locked and return\n", __FUNCTION__);
1671         return;
1672     }
1673 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
1674 
1675     sdio_claim_host_lock_local(sd);
1676     sdio_release_host(sd->func[0]);
1677 
1678     if (sd->use_client_ints) {
1679         sd->intrcount++;
1680         ASSERT(sd->intr_handler);
1681         ASSERT(sd->intr_handler_arg);
1682         (sd->intr_handler)(sd->intr_handler_arg);
1683     } else {
1684         sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1685 
1686         sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1687                 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
1688     }
1689 
1690     sdio_claim_host(sd->func[0]);
1691     sdio_claim_host_unlock_local(sd);
1692 }
1693 
1694 /* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
IRQHandlerF2(struct sdio_func * func)1695 static void IRQHandlerF2(struct sdio_func *func)
1696 {
1697     sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1698 }
1699 #endif /* !defined(OOB_INTR_ONLY) */
1700 
1701 #ifdef NOTUSED
1702 /* Write client card reg */
sdioh_sdmmc_card_regwrite(sdioh_info_t * sd,int func,uint32 regaddr,int regsize,uint32 data)1703 static int sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
1704                                      int regsize, uint32 data)
1705 {
1706     if ((func == 0) || (regsize == 1)) {
1707         uint8 temp;
1708 
1709         temp = data & 0xff;
1710         sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1711         sd_data(("%s: byte write data=0x%02x\n", __FUNCTION__, data));
1712     } else {
1713         if (regsize == 0x2) {
1714             data &= 0xffff;
1715         }
1716 
1717         sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize);
1718 
1719         sd_data(("%s: word write data=0x%08x\n", __FUNCTION__, data));
1720     }
1721 
1722     return SUCCESS;
1723 }
1724 #endif /* NOTUSED */
1725 
1726 #if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE)
sdio_sw_reset(sdioh_info_t * sd)1727 static int sdio_sw_reset(sdioh_info_t *sd)
1728 {
1729 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) && defined(MMC_SW_RESET)
1730     struct mmc_host *host = sd->func[0]->card->host;
1731 #endif
1732     int err = 0;
1733 
1734 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) && defined(MMC_SW_RESET)
1735     printf("%s: Enter\n", __FUNCTION__);
1736     sdio_claim_host(sd->func[0]);
1737     err = mmc_sw_reset(host);
1738     sdio_release_host(sd->func[0]);
1739 #else
1740     err = sdio_reset_comm(sd->func[0]->card);
1741 #endif
1742     if (err) {
1743         sd_err(("%s Failed, error = %d\n", __FUNCTION__, err));
1744     }
1745     return err;
1746 }
1747 #endif
1748 
sdioh_start(sdioh_info_t * sd,int stage)1749 int sdioh_start(sdioh_info_t *sd, int stage)
1750 {
1751     int ret;
1752 
1753     if (!sd) {
1754         sd_err(("%s Failed, sd is NULL\n", __FUNCTION__));
1755         return (0);
1756     }
1757 
1758     /* Need to do this stages as we can't enable the interrupt till
1759         downloading of the firmware is complete, other wise polling
1760         sdio access will come in way
1761     */
1762     if (sd->func[0]) {
1763         if (stage == 0) {
1764             /* Since the power to the chip is killed, we will have
1765                 re enumerate the device again. Set the block size
1766                 and enable the fucntion 1 for in preparation for
1767                 downloading the code
1768             */
1769             /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for
1770                Linux 2.6.27. The implementation prior to that is buggy, and
1771                needs broadcom's patch for it
1772             */
1773 #if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE)
1774             if ((ret = sdio_sw_reset(sd))) {
1775                 sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
1776                 return ret;
1777             } else
1778 #endif
1779             {
1780                 sd->num_funcs = 0x2;
1781                 sd->sd_blockmode = TRUE;
1782                 sd->use_client_ints = TRUE;
1783                 sd->client_block_size[0] = 0x40;
1784 
1785                 if (sd->func[1]) {
1786                     /* Claim host controller */
1787                     sdio_claim_host(sd->func[1]);
1788 
1789                     sd->client_block_size[1] = 0x40;
1790                     ret = sdio_set_block_size(sd->func[1], 0x40);
1791                     if (ret) {
1792                         sd_err(("bcmsdh_sdmmc: Failed to set F1 "
1793                                 "blocksize(%d)\n",
1794                                 ret));
1795                     }
1796 
1797                     /* Release host controller F1 */
1798                     sdio_release_host(sd->func[1]);
1799                 }
1800 
1801                 if (sd->func[0x2]) {
1802                     /* Claim host controller F2 */
1803                     sdio_claim_host(sd->func[0x2]);
1804 
1805                     sd->client_block_size[0x2] = sd_f2_blocksize;
1806                     printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__,
1807                            sd_f2_blocksize);
1808                     ret = sdio_set_block_size(sd->func[0x2], sd_f2_blocksize);
1809                     if (ret) {
1810                         sd_err(("bcmsdh_sdmmc: Failed to set F2 "
1811                                 "blocksize to %d(%d)\n",
1812                                 sd_f2_blocksize, ret));
1813                     }
1814 
1815                     /* Release host controller F2 */
1816                     sdio_release_host(sd->func[2]);
1817                 }
1818 
1819                 sdioh_sdmmc_card_enablefuncs(sd);
1820             }
1821         } else {
1822 #if !defined(OOB_INTR_ONLY)
1823             sdio_claim_host(sd->func[0]);
1824             if (sd->func[0x2]) {
1825                 sdio_claim_irq(sd->func[0x2], IRQHandlerF2);
1826             }
1827             if (sd->func[1]) {
1828                 sdio_claim_irq(sd->func[1], IRQHandler);
1829             }
1830             sdio_release_host(sd->func[0]);
1831 #else /* defined(OOB_INTR_ONLY) */
1832 #if defined(HW_OOB)
1833             sdioh_enable_func_intr(sd);
1834 #endif // endif
1835             bcmsdh_oob_intr_set(sd->bcmsdh, TRUE);
1836 #endif /* !defined(OOB_INTR_ONLY) */
1837         }
1838     } else {
1839         sd_err(("%s Failed\n", __FUNCTION__));
1840     }
1841 
1842     return (0);
1843 }
1844 
sdioh_stop(sdioh_info_t * sd)1845 int sdioh_stop(sdioh_info_t *sd)
1846 {
1847     /* MSM7201A Android sdio stack has bug with interrupt
1848         So internaly within SDIO stack they are polling
1849         which cause issue when device is turned off. So
1850         unregister interrupt with SDIO stack to stop the
1851         polling
1852     */
1853 #if !defined(OOB_INTR_ONLY)
1854     sdio_claim_host_lock_local(sd);
1855 #endif
1856     if (sd->func[0]) {
1857 #if !defined(OOB_INTR_ONLY)
1858         sdio_claim_host(sd->func[0]);
1859         if (sd->func[1]) {
1860             sdio_release_irq(sd->func[1]);
1861         }
1862         if (sd->func[0x2]) {
1863             sdio_release_irq(sd->func[0x2]);
1864         }
1865         sdio_release_host(sd->func[0]);
1866 #else /* defined(OOB_INTR_ONLY) */
1867 #if defined(HW_OOB)
1868         sdioh_disable_func_intr(sd);
1869 #endif // endif
1870         bcmsdh_oob_intr_set(sd->bcmsdh, FALSE);
1871 #endif /* !defined(OOB_INTR_ONLY) */
1872     } else {
1873         sd_err(("%s Failed\n", __FUNCTION__));
1874     }
1875 #if !defined(OOB_INTR_ONLY)
1876     sdio_claim_host_unlock_local(sd);
1877 #endif
1878     return (0);
1879 }
1880 
sdioh_waitlockfree(sdioh_info_t * sd)1881 int sdioh_waitlockfree(sdioh_info_t *sd)
1882 {
1883     return (1);
1884 }
1885 
1886 SDIOH_API_RC
sdioh_gpioouten(sdioh_info_t * sd,uint32 gpio)1887 sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio)
1888 {
1889     return SDIOH_API_RC_FAIL;
1890 }
1891 
1892 SDIOH_API_RC
sdioh_gpioout(sdioh_info_t * sd,uint32 gpio,bool enab)1893 sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab)
1894 {
1895     return SDIOH_API_RC_FAIL;
1896 }
1897 
sdioh_gpioin(sdioh_info_t * sd,uint32 gpio)1898 bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio)
1899 {
1900     return FALSE;
1901 }
1902 
1903 SDIOH_API_RC
sdioh_gpio_init(sdioh_info_t * sd)1904 sdioh_gpio_init(sdioh_info_t *sd)
1905 {
1906     return SDIOH_API_RC_FAIL;
1907 }
1908 
sdmmc_get_clock_rate(sdioh_info_t * sd)1909 uint sdmmc_get_clock_rate(sdioh_info_t *sd)
1910 {
1911 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)) ||                          \
1912     (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
1913     struct sdio_func *sdio_func = sd->func[0];
1914     struct mmc_host *host = sdio_func->card->host;
1915     return mmc_host_clk_rate(host);
1916 #else
1917     return 0;
1918 #endif
1919 }
1920 
sdmmc_set_clock_rate(sdioh_info_t * sd,uint hz)1921 void sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz)
1922 {
1923 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)) ||                          \
1924     (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
1925     struct sdio_func *sdio_func = sd->func[0];
1926     struct mmc_host *host = sdio_func->card->host;
1927     struct mmc_ios *ios = &host->ios;
1928 
1929     mmc_host_clk_hold(host);
1930     DHD_INFO(
1931         ("%s: Before change: sd clock rate is %u\n", __FUNCTION__, ios->clock));
1932     if (hz < host->f_min) {
1933         DHD_ERROR(("%s: Intended rate is below min rate, setting to min\n",
1934                    __FUNCTION__));
1935         hz = host->f_min;
1936     }
1937 
1938     if (hz > host->f_max) {
1939         DHD_ERROR(("%s: Intended rate exceeds max rate, setting to max\n",
1940                    __FUNCTION__));
1941         hz = host->f_max;
1942     }
1943     ios->clock = hz;
1944     host->ops->set_ios(host, ios);
1945     DHD_ERROR(
1946         ("%s: After change: sd clock rate is %u\n", __FUNCTION__, ios->clock));
1947     mmc_host_clk_release(host);
1948 #else
1949     return;
1950 #endif
1951 }
1952 
sdmmc_set_clock_divisor(sdioh_info_t * sd,uint sd_div)1953 void sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div)
1954 {
1955     uint hz;
1956     uint old_div = sdmmc_get_clock_rate(sd);
1957     if (old_div == sd_div) {
1958         return;
1959     }
1960 
1961     hz = sd->sd_clk_rate / sd_div;
1962     sdmmc_set_clock_rate(sd, hz);
1963 }
1964