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