• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &regdata)) != 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