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