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, ®data)) !=
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