1 /*
2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
3 *
4 * Copyright (C) 1999-2009, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdh_sdmmc.c,v 1.1.2.5.6.27 2009/10/28 19:42:29 Exp $
25 */
26 #include <typedefs.h>
27
28 #include <bcmdevs.h>
29 #include <bcmendian.h>
30 #include <bcmutils.h>
31 #include <osl.h>
32 #include <sdio.h> /* SDIO Device and Protocol Specs */
33 #include <sdioh.h> /* SDIO Host Controller Specification */
34 #include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
35 #include <sdiovar.h> /* ioctl/iovars */
36
37 #include <linux/mmc/core.h>
38 #include <linux/mmc/sdio_func.h>
39 #include <linux/mmc/sdio_ids.h>
40
41 #include <dngl_stats.h>
42 #include <dhd.h>
43
44 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
45 #include <linux/suspend.h>
46 extern volatile bool dhd_mmc_suspend;
47 #endif
48 #include "bcmsdh_sdmmc.h"
49
50 #ifndef BCMSDH_MODULE
51 extern int sdio_function_init(void);
52 extern void sdio_function_cleanup(void);
53 #endif /* BCMSDH_MODULE */
54
55 #if !defined(OOB_INTR_ONLY)
56 static void IRQHandler(struct sdio_func *func);
57 static void IRQHandlerF2(struct sdio_func *func);
58 #endif
59 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
60 extern int sdio_reset_comm(struct mmc_card *card);
61
62 extern PBCMSDH_SDMMC_INSTANCE gInstance;
63
64 uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
65 uint sd_f2_blocksize = 512; /* Default blocksize */
66
67 uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
68
69 uint sd_power = 1; /* Default to SD Slot powered ON */
70 uint sd_clock = 1; /* Default to SD Clock turned ON */
71 uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */
72 uint sd_msglevel = 0x01;
73 uint sd_use_dma = TRUE;
74 DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
75 DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
76 DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
77 DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
78
79 #define DMA_ALIGN_MASK 0x03
80
81 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
82
83 static int
sdioh_sdmmc_card_enablefuncs(sdioh_info_t * sd)84 sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
85 {
86 int err_ret;
87 uint32 fbraddr;
88 uint8 func;
89
90 sd_trace(("%s\n", __FUNCTION__));
91
92 /* Get the Card's common CIS address */
93 sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
94 sd->func_cis_ptr[0] = sd->com_cis_ptr;
95 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
96
97 /* Get the Card's function CIS (for each function) */
98 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
99 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
100 sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
101 sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
102 __FUNCTION__, func, sd->func_cis_ptr[func]));
103 }
104
105 sd->func_cis_ptr[0] = sd->com_cis_ptr;
106 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
107
108 /* Enable Function 1 */
109 sdio_claim_host(gInstance->func[1]);
110 err_ret = sdio_enable_func(gInstance->func[1]);
111 sdio_release_host(gInstance->func[1]);
112 if (err_ret) {
113 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret));
114 }
115
116 return FALSE;
117 }
118
119 /*
120 * Public entry points & extern's
121 */
122 extern sdioh_info_t *
sdioh_attach(osl_t * osh,void * bar0,uint irq)123 sdioh_attach(osl_t *osh, void *bar0, uint irq)
124 {
125 sdioh_info_t *sd;
126 int err_ret;
127
128 sd_trace(("%s\n", __FUNCTION__));
129
130 if (gInstance == NULL) {
131 sd_err(("%s: SDIO Device not present\n", __FUNCTION__));
132 return NULL;
133 }
134
135 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
136 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
137 return NULL;
138 }
139 bzero((char *)sd, sizeof(sdioh_info_t));
140 sd->osh = osh;
141 if (sdioh_sdmmc_osinit(sd) != 0) {
142 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__));
143 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
144 return NULL;
145 }
146
147 sd->num_funcs = 2;
148 sd->sd_blockmode = TRUE;
149 sd->use_client_ints = TRUE;
150 sd->client_block_size[0] = 64;
151
152 gInstance->sd = sd;
153
154 /* Claim host controller */
155 sdio_claim_host(gInstance->func[1]);
156
157 sd->client_block_size[1] = 64;
158 err_ret = sdio_set_block_size(gInstance->func[1], 64);
159 if (err_ret) {
160 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
161 }
162
163 /* Release host controller F1 */
164 sdio_release_host(gInstance->func[1]);
165
166 if (gInstance->func[2]) {
167 /* Claim host controller F2 */
168 sdio_claim_host(gInstance->func[2]);
169
170 sd->client_block_size[2] = sd_f2_blocksize;
171 err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
172 if (err_ret) {
173 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n",
174 sd_f2_blocksize));
175 }
176
177 /* Release host controller F2 */
178 sdio_release_host(gInstance->func[2]);
179 }
180
181 sdioh_sdmmc_card_enablefuncs(sd);
182
183 sd_trace(("%s: Done\n", __FUNCTION__));
184 return sd;
185 }
186
187
188 extern SDIOH_API_RC
sdioh_detach(osl_t * osh,sdioh_info_t * sd)189 sdioh_detach(osl_t *osh, sdioh_info_t *sd)
190 {
191 sd_trace(("%s\n", __FUNCTION__));
192
193 if (sd) {
194
195 /* Disable Function 2 */
196 sdio_claim_host(gInstance->func[2]);
197 sdio_disable_func(gInstance->func[2]);
198 sdio_release_host(gInstance->func[2]);
199
200 /* Disable Function 1 */
201 sdio_claim_host(gInstance->func[1]);
202 sdio_disable_func(gInstance->func[1]);
203 sdio_release_host(gInstance->func[1]);
204
205 /* deregister irq */
206 sdioh_sdmmc_osfree(sd);
207
208 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
209 }
210 return SDIOH_API_RC_SUCCESS;
211 }
212
213 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
214 #define _SDIO_CCCR_IENx 0x04 /* Function/Master Interrupt Enable */
215
216 extern SDIOH_API_RC
sdioh_enable_func_intr(uint32 func)217 sdioh_enable_func_intr(uint32 func)
218 {
219 uint8 reg;
220 int err;
221
222 if (gInstance->func[0]) {
223 sdio_claim_host(gInstance->func[0]);
224 reg = sdio_readb(gInstance->func[0], _SDIO_CCCR_IENx, &err);
225 if (err) {
226 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
227 sdio_release_host(gInstance->func[0]);
228 return SDIOH_API_RC_FAIL;
229 }
230 reg |= 1 << func; /* enable function-x interrupt */
231 reg |= 1; /* Master interrupt enable */
232 sdio_writeb(gInstance->func[0], reg, _SDIO_CCCR_IENx, &err);
233 sdio_release_host(gInstance->func[0]);
234 if (err) {
235 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
236 return SDIOH_API_RC_FAIL;
237 }
238 }
239
240 return SDIOH_API_RC_SUCCESS;
241
242 }
243
244 extern SDIOH_API_RC
sdioh_disable_func_intr(uint32 func)245 sdioh_disable_func_intr(uint32 func)
246 {
247 uint8 reg;
248 int err;
249
250 if (gInstance->func[0]) {
251 sdio_claim_host(gInstance->func[0]);
252 reg = sdio_readb(gInstance->func[0], _SDIO_CCCR_IENx, &err);
253 if (err) {
254 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
255 sdio_release_host(gInstance->func[0]);
256 return SDIOH_API_RC_FAIL;
257 }
258 reg &= ~(1 << func);
259 /* Disable master interrupt with the last function interrupt */
260 if (!(reg & 0xFE))
261 reg = 0;
262 sdio_writeb(gInstance->func[0], reg, _SDIO_CCCR_IENx, &err);
263 sdio_release_host(gInstance->func[0]);
264 if (err) {
265 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
266 return SDIOH_API_RC_FAIL;
267 }
268 }
269 return SDIOH_API_RC_SUCCESS;
270
271 }
272 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
273
274 /* Configure callback to client when we recieve client interrupt */
275 extern SDIOH_API_RC
sdioh_interrupt_register(sdioh_info_t * sd,sdioh_cb_fn_t fn,void * argh)276 sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
277 {
278 sd_trace(("%s: Entering\n", __FUNCTION__));
279 if (fn == NULL) {
280 sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__));
281 return SDIOH_API_RC_FAIL;
282 }
283 #if !defined(OOB_INTR_ONLY)
284 sd->intr_handler = fn;
285 sd->intr_handler_arg = argh;
286 sd->intr_handler_valid = TRUE;
287
288 /* register and unmask irq */
289 if (gInstance->func[2]) {
290 sdio_claim_host(gInstance->func[2]);
291 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
292 sdio_release_host(gInstance->func[2]);
293 }
294
295 if (gInstance->func[1]) {
296 sdio_claim_host(gInstance->func[1]);
297 sdio_claim_irq(gInstance->func[1], IRQHandler);
298 sdio_release_host(gInstance->func[1]);
299 }
300 #elif defined(HW_OOB)
301 sdioh_enable_func_intr(2);
302 #endif /* defined(OOB_INTR_ONLY) */
303 return SDIOH_API_RC_SUCCESS;
304 }
305
306 extern SDIOH_API_RC
sdioh_interrupt_deregister(sdioh_info_t * sd)307 sdioh_interrupt_deregister(sdioh_info_t *sd)
308 {
309 sd_trace(("%s: Entering\n", __FUNCTION__));
310
311 #if !defined(OOB_INTR_ONLY)
312 if (gInstance->func[1]) {
313 /* register and unmask irq */
314 sdio_claim_host(gInstance->func[1]);
315 sdio_release_irq(gInstance->func[1]);
316 sdio_release_host(gInstance->func[1]);
317 }
318
319 if (gInstance->func[2]) {
320 /* Claim host controller F2 */
321 sdio_claim_host(gInstance->func[2]);
322 sdio_release_irq(gInstance->func[2]);
323 /* Release host controller F2 */
324 sdio_release_host(gInstance->func[2]);
325 }
326
327 sd->intr_handler_valid = FALSE;
328 sd->intr_handler = NULL;
329 sd->intr_handler_arg = NULL;
330 #elif defined(HW_OOB)
331 sdioh_disable_func_intr(2);
332 #endif /* !defined(OOB_INTR_ONLY) */
333 return SDIOH_API_RC_SUCCESS;
334 }
335
336 extern SDIOH_API_RC
sdioh_interrupt_query(sdioh_info_t * sd,bool * onoff)337 sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
338 {
339 sd_trace(("%s: Entering\n", __FUNCTION__));
340 *onoff = sd->client_intr_enabled;
341 return SDIOH_API_RC_SUCCESS;
342 }
343
344 #if defined(DHD_DEBUG)
345 extern bool
sdioh_interrupt_pending(sdioh_info_t * sd)346 sdioh_interrupt_pending(sdioh_info_t *sd)
347 {
348 return (0);
349 }
350 #endif
351
352 uint
sdioh_query_iofnum(sdioh_info_t * sd)353 sdioh_query_iofnum(sdioh_info_t *sd)
354 {
355 return sd->num_funcs;
356 }
357
358 /* IOVar table */
359 enum {
360 IOV_MSGLEVEL = 1,
361 IOV_BLOCKMODE,
362 IOV_BLOCKSIZE,
363 IOV_DMA,
364 IOV_USEINTS,
365 IOV_NUMINTS,
366 IOV_NUMLOCALINTS,
367 IOV_HOSTREG,
368 IOV_DEVREG,
369 IOV_DIVISOR,
370 IOV_SDMODE,
371 IOV_HISPEED,
372 IOV_HCIREGS,
373 IOV_POWER,
374 IOV_CLOCK,
375 IOV_RXCHAIN
376 };
377
378 const bcm_iovar_t sdioh_iovars[] = {
379 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
380 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 },
381 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
382 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 },
383 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
384 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
385 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
386 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
387 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
388 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
389 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
390 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
391 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
392 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 },
393 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 },
394 {NULL, 0, 0, 0, 0 }
395 };
396
397 int
sdioh_iovar_op(sdioh_info_t * si,const char * name,void * params,int plen,void * arg,int len,bool set)398 sdioh_iovar_op(sdioh_info_t *si, const char *name,
399 void *params, int plen, void *arg, int len, bool set)
400 {
401 const bcm_iovar_t *vi = NULL;
402 int bcmerror = 0;
403 int val_size;
404 int32 int_val = 0;
405 bool bool_val;
406 uint32 actionid;
407
408 ASSERT(name);
409 ASSERT(len >= 0);
410
411 /* Get must have return space; Set does not take qualifiers */
412 ASSERT(set || (arg && len));
413 ASSERT(!set || (!params && !plen));
414
415 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
416
417 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
418 bcmerror = BCME_UNSUPPORTED;
419 goto exit;
420 }
421
422 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
423 goto exit;
424
425 /* Set up params so get and set can share the convenience variables */
426 if (params == NULL) {
427 params = arg;
428 plen = len;
429 }
430
431 if (vi->type == IOVT_VOID)
432 val_size = 0;
433 else if (vi->type == IOVT_BUFFER)
434 val_size = len;
435 else
436 val_size = sizeof(int);
437
438 if (plen >= (int)sizeof(int_val))
439 bcopy(params, &int_val, sizeof(int_val));
440
441 bool_val = (int_val != 0) ? TRUE : FALSE;
442
443 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
444 switch (actionid) {
445 case IOV_GVAL(IOV_MSGLEVEL):
446 int_val = (int32)sd_msglevel;
447 bcopy(&int_val, arg, val_size);
448 break;
449
450 case IOV_SVAL(IOV_MSGLEVEL):
451 sd_msglevel = int_val;
452 break;
453
454 case IOV_GVAL(IOV_BLOCKMODE):
455 int_val = (int32)si->sd_blockmode;
456 bcopy(&int_val, arg, val_size);
457 break;
458
459 case IOV_SVAL(IOV_BLOCKMODE):
460 si->sd_blockmode = (bool)int_val;
461 /* Haven't figured out how to make non-block mode with DMA */
462 break;
463
464 case IOV_GVAL(IOV_BLOCKSIZE):
465 if ((uint32)int_val > si->num_funcs) {
466 bcmerror = BCME_BADARG;
467 break;
468 }
469 int_val = (int32)si->client_block_size[int_val];
470 bcopy(&int_val, arg, val_size);
471 break;
472
473 case IOV_SVAL(IOV_BLOCKSIZE):
474 {
475 uint func = ((uint32)int_val >> 16);
476 uint blksize = (uint16)int_val;
477 uint maxsize;
478
479 if (func > si->num_funcs) {
480 bcmerror = BCME_BADARG;
481 break;
482 }
483
484 switch (func) {
485 case 0: maxsize = 32; break;
486 case 1: maxsize = BLOCK_SIZE_4318; break;
487 case 2: maxsize = BLOCK_SIZE_4328; break;
488 default: maxsize = 0;
489 }
490 if (blksize > maxsize) {
491 bcmerror = BCME_BADARG;
492 break;
493 }
494 if (!blksize) {
495 blksize = maxsize;
496 }
497
498 /* Now set it */
499 si->client_block_size[func] = blksize;
500
501 break;
502 }
503
504 case IOV_GVAL(IOV_RXCHAIN):
505 int_val = FALSE;
506 bcopy(&int_val, arg, val_size);
507 break;
508
509 case IOV_GVAL(IOV_DMA):
510 int_val = (int32)si->sd_use_dma;
511 bcopy(&int_val, arg, val_size);
512 break;
513
514 case IOV_SVAL(IOV_DMA):
515 si->sd_use_dma = (bool)int_val;
516 break;
517
518 case IOV_GVAL(IOV_USEINTS):
519 int_val = (int32)si->use_client_ints;
520 bcopy(&int_val, arg, val_size);
521 break;
522
523 case IOV_SVAL(IOV_USEINTS):
524 si->use_client_ints = (bool)int_val;
525 if (si->use_client_ints)
526 si->intmask |= CLIENT_INTR;
527 else
528 si->intmask &= ~CLIENT_INTR;
529
530 break;
531
532 case IOV_GVAL(IOV_DIVISOR):
533 int_val = (uint32)sd_divisor;
534 bcopy(&int_val, arg, val_size);
535 break;
536
537 case IOV_SVAL(IOV_DIVISOR):
538 sd_divisor = int_val;
539 break;
540
541 case IOV_GVAL(IOV_POWER):
542 int_val = (uint32)sd_power;
543 bcopy(&int_val, arg, val_size);
544 break;
545
546 case IOV_SVAL(IOV_POWER):
547 sd_power = int_val;
548 break;
549
550 case IOV_GVAL(IOV_CLOCK):
551 int_val = (uint32)sd_clock;
552 bcopy(&int_val, arg, val_size);
553 break;
554
555 case IOV_SVAL(IOV_CLOCK):
556 sd_clock = int_val;
557 break;
558
559 case IOV_GVAL(IOV_SDMODE):
560 int_val = (uint32)sd_sdmode;
561 bcopy(&int_val, arg, val_size);
562 break;
563
564 case IOV_SVAL(IOV_SDMODE):
565 sd_sdmode = int_val;
566 break;
567
568 case IOV_GVAL(IOV_HISPEED):
569 int_val = (uint32)sd_hiok;
570 bcopy(&int_val, arg, val_size);
571 break;
572
573 case IOV_SVAL(IOV_HISPEED):
574 sd_hiok = int_val;
575 break;
576
577 case IOV_GVAL(IOV_NUMINTS):
578 int_val = (int32)si->intrcount;
579 bcopy(&int_val, arg, val_size);
580 break;
581
582 case IOV_GVAL(IOV_NUMLOCALINTS):
583 int_val = (int32)0;
584 bcopy(&int_val, arg, val_size);
585 break;
586
587 case IOV_GVAL(IOV_HOSTREG):
588 {
589 sdreg_t *sd_ptr = (sdreg_t *)params;
590
591 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
592 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
593 bcmerror = BCME_BADARG;
594 break;
595 }
596
597 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
598 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
599 sd_ptr->offset));
600 if (sd_ptr->offset & 1)
601 int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
602 else if (sd_ptr->offset & 2)
603 int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
604 else
605 int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
606
607 bcopy(&int_val, arg, sizeof(int_val));
608 break;
609 }
610
611 case IOV_SVAL(IOV_HOSTREG):
612 {
613 sdreg_t *sd_ptr = (sdreg_t *)params;
614
615 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
616 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
617 bcmerror = BCME_BADARG;
618 break;
619 }
620
621 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
622 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
623 sd_ptr->offset));
624 break;
625 }
626
627 case IOV_GVAL(IOV_DEVREG):
628 {
629 sdreg_t *sd_ptr = (sdreg_t *)params;
630 uint8 data = 0;
631
632 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
633 bcmerror = BCME_SDIO_ERROR;
634 break;
635 }
636
637 int_val = (int)data;
638 bcopy(&int_val, arg, sizeof(int_val));
639 break;
640 }
641
642 case IOV_SVAL(IOV_DEVREG):
643 {
644 sdreg_t *sd_ptr = (sdreg_t *)params;
645 uint8 data = (uint8)sd_ptr->value;
646
647 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
648 bcmerror = BCME_SDIO_ERROR;
649 break;
650 }
651 break;
652 }
653
654 default:
655 bcmerror = BCME_UNSUPPORTED;
656 break;
657 }
658 exit:
659
660 return bcmerror;
661 }
662
663 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
664
665 SDIOH_API_RC
sdioh_enable_hw_oob_intr(sdioh_info_t * sd,bool enable)666 sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
667 {
668 SDIOH_API_RC status;
669 uint8 data;
670
671 if (enable)
672 data = 3; /* enable hw oob interrupt */
673 else
674 data = 4; /* disable hw oob interrupt */
675
676 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data);
677 return status;
678 }
679 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
680
681
682 extern SDIOH_API_RC
sdioh_cfg_read(sdioh_info_t * sd,uint fnc_num,uint32 addr,uint8 * data)683 sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
684 {
685 SDIOH_API_RC status;
686 /* No lock needed since sdioh_request_byte does locking */
687 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
688 return status;
689 }
690
691 extern SDIOH_API_RC
sdioh_cfg_write(sdioh_info_t * sd,uint fnc_num,uint32 addr,uint8 * data)692 sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
693 {
694 /* No lock needed since sdioh_request_byte does locking */
695 SDIOH_API_RC status;
696 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
697 return status;
698 }
699
700 static int
sdioh_sdmmc_get_cisaddr(sdioh_info_t * sd,uint32 regaddr)701 sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
702 {
703 /* read 24 bits and return valid 17 bit addr */
704 int i;
705 uint32 scratch, regdata;
706 uint8 *ptr = (uint8 *)&scratch;
707 for (i = 0; i < 3; i++) {
708 if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS)
709 sd_err(("%s: Can't read!\n", __FUNCTION__));
710
711 *ptr++ = (uint8) regdata;
712 regaddr++;
713 }
714
715 /* Only the lower 17-bits are valid */
716 scratch = ltoh32(scratch);
717 scratch &= 0x0001FFFF;
718 return (scratch);
719 }
720
721 extern SDIOH_API_RC
sdioh_cis_read(sdioh_info_t * sd,uint func,uint8 * cisd,uint32 length)722 sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
723 {
724 uint32 count;
725 int offset;
726 uint32 foo;
727 uint8 *cis = cisd;
728
729 sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
730
731 if (!sd->func_cis_ptr[func]) {
732 bzero(cis, length);
733 sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
734 return SDIOH_API_RC_FAIL;
735 }
736
737 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]));
738
739 for (count = 0; count < length; count++) {
740 offset = sd->func_cis_ptr[func] + count;
741 if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) {
742 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
743 return SDIOH_API_RC_FAIL;
744 }
745
746 *cis = (uint8)(foo & 0xff);
747 cis++;
748 }
749
750 return SDIOH_API_RC_SUCCESS;
751 }
752
753 extern SDIOH_API_RC
sdioh_request_byte(sdioh_info_t * sd,uint rw,uint func,uint regaddr,uint8 * byte)754 sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
755 {
756 int err_ret;
757
758 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
759
760 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
761 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
762 if(rw) { /* CMD52 Write */
763 if (func == 0) {
764 /* Can only directly write to some F0 registers. Handle F2 enable
765 * as a special case.
766 */
767 if (regaddr == SDIOD_CCCR_IOEN) {
768 if (gInstance->func[2]) {
769 sdio_claim_host(gInstance->func[2]);
770 if (*byte & SDIO_FUNC_ENABLE_2) {
771 /* Enable Function 2 */
772 err_ret = sdio_enable_func(gInstance->func[2]);
773 if (err_ret) {
774 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
775 err_ret));
776 }
777 } else {
778 /* Disable Function 2 */
779 err_ret = sdio_disable_func(gInstance->func[2]);
780 if (err_ret) {
781 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
782 err_ret));
783 }
784 }
785 sdio_release_host(gInstance->func[2]);
786 }
787 }
788 #if defined(MMC_SDIO_ABORT)
789 /* to allow abort command through F1 */
790 else if (regaddr == SDIOD_CCCR_IOABORT) {
791 sdio_claim_host(gInstance->func[func]);
792 /*
793 * this sdio_f0_writeb() can be replaced with another api
794 * depending upon MMC driver change.
795 * As of this time, this is temporaray one
796 */
797 sdio_f0_writeb(gInstance->func[func], *byte,
798 regaddr, &err_ret);
799 sdio_release_host(gInstance->func[func]);
800 }
801 #endif /* MMC_SDIO_ABORT */
802 else if (regaddr < 0xF0) {
803 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr));
804 } else {
805 /* Claim host controller, perform F0 write, and release */
806 sdio_claim_host(gInstance->func[func]);
807 sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
808 sdio_release_host(gInstance->func[func]);
809 }
810 } else {
811 /* Claim host controller, perform Fn write, and release */
812 sdio_claim_host(gInstance->func[func]);
813 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
814 sdio_release_host(gInstance->func[func]);
815 }
816 } else { /* CMD52 Read */
817 /* Claim host controller, perform Fn read, and release */
818 sdio_claim_host(gInstance->func[func]);
819
820 if (func == 0) {
821 *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret);
822 } else {
823 *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret);
824 }
825
826 sdio_release_host(gInstance->func[func]);
827 }
828
829 if (err_ret) {
830 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
831 rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
832 }
833
834 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
835 }
836
837 extern SDIOH_API_RC
sdioh_request_word(sdioh_info_t * sd,uint cmd_type,uint rw,uint func,uint addr,uint32 * word,uint nbytes)838 sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
839 uint32 *word, uint nbytes)
840 {
841 int err_ret = SDIOH_API_RC_FAIL;
842
843 if (func == 0) {
844 sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
845 return SDIOH_API_RC_FAIL;
846 }
847
848 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
849 __FUNCTION__, cmd_type, rw, func, addr, nbytes));
850
851 DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
852 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
853 /* Claim host controller */
854 sdio_claim_host(gInstance->func[func]);
855
856 if(rw) { /* CMD52 Write */
857 if (nbytes == 4) {
858 sdio_writel(gInstance->func[func], *word, addr, &err_ret);
859 } else if (nbytes == 2) {
860 sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret);
861 } else {
862 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
863 }
864 } else { /* CMD52 Read */
865 if (nbytes == 4) {
866 *word = sdio_readl(gInstance->func[func], addr, &err_ret);
867 } else if (nbytes == 2) {
868 *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF;
869 } else {
870 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
871 }
872 }
873
874 /* Release host controller */
875 sdio_release_host(gInstance->func[func]);
876
877 if (err_ret) {
878 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
879 rw ? "Write" : "Read", err_ret));
880 }
881
882 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
883 }
884
885 static SDIOH_API_RC
sdioh_request_packet(sdioh_info_t * sd,uint fix_inc,uint write,uint func,uint addr,void * pkt)886 sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
887 uint addr, void *pkt)
888 {
889 bool fifo = (fix_inc == SDIOH_DATA_FIX);
890 uint32 SGCount = 0;
891 int err_ret = 0;
892
893 void *pnext;
894
895 sd_trace(("%s: Enter\n", __FUNCTION__));
896
897 ASSERT(pkt);
898 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
899 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
900
901 /* Claim host controller */
902 sdio_claim_host(gInstance->func[func]);
903 for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
904 uint pkt_len = PKTLEN(sd->osh, pnext);
905 pkt_len += 3;
906 pkt_len &= 0xFFFFFFFC;
907
908 #ifdef CONFIG_MMC_MSM7X00A
909 if ((pkt_len % 64) == 32) {
910 sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
911 pkt_len += 32;
912 }
913 #endif /* CONFIG_MMC_MSM7X00A */
914 /* Make sure the packet is aligned properly. If it isn't, then this
915 * is the fault of sdioh_request_buffer() which is supposed to give
916 * us something we can work with.
917 */
918 ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
919
920 if ((write) && (!fifo)) {
921 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
922 ((uint8*)PKTDATA(sd->osh, pnext)),
923 pkt_len);
924 } else if (write) {
925 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
926 ((uint8*)PKTDATA(sd->osh, pnext)),
927 pkt_len);
928 } else if (fifo) {
929 err_ret = sdio_readsb(gInstance->func[func],
930 ((uint8*)PKTDATA(sd->osh, pnext)),
931 addr,
932 pkt_len);
933 } else {
934 err_ret = sdio_memcpy_fromio(gInstance->func[func],
935 ((uint8*)PKTDATA(sd->osh, pnext)),
936 addr,
937 pkt_len);
938 }
939
940 if (err_ret) {
941 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
942 __FUNCTION__,
943 (write) ? "TX" : "RX",
944 pnext, SGCount, addr, pkt_len, err_ret));
945 } else {
946 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
947 __FUNCTION__,
948 (write) ? "TX" : "RX",
949 pnext, SGCount, addr, pkt_len));
950 }
951
952 if (!fifo) {
953 addr += pkt_len;
954 }
955 SGCount ++;
956
957 }
958
959 /* Release host controller */
960 sdio_release_host(gInstance->func[func]);
961
962 sd_trace(("%s: Exit\n", __FUNCTION__));
963 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
964 }
965
966
967 /*
968 * This function takes a buffer or packet, and fixes everything up so that in the
969 * end, a DMA-able packet is created.
970 *
971 * A buffer does not have an associated packet pointer, and may or may not be aligned.
972 * A packet may consist of a single packet, or a packet chain. If it is a packet chain,
973 * then all the packets in the chain must be properly aligned. If the packet data is not
974 * aligned, then there may only be one packet, and in this case, it is copied to a new
975 * aligned packet.
976 *
977 */
978 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 buflen_u,uint8 * buffer,void * pkt)979 sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func,
980 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
981 {
982 SDIOH_API_RC Status;
983 void *mypkt = NULL;
984
985 sd_trace(("%s: Enter\n", __FUNCTION__));
986
987 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
988 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
989 /* Case 1: we don't have a packet. */
990 if (pkt == NULL) {
991 sd_data(("%s: Creating new %s Packet, len=%d\n",
992 __FUNCTION__, write ? "TX" : "RX", buflen_u));
993 #ifdef DHD_USE_STATIC_BUF
994 if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) {
995 #else
996 if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
997 #endif /* DHD_USE_STATIC_BUF */
998 sd_err(("%s: PKTGET failed: len %d\n",
999 __FUNCTION__, buflen_u));
1000 return SDIOH_API_RC_FAIL;
1001 }
1002
1003 /* For a write, copy the buffer data into the packet. */
1004 if (write) {
1005 bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u);
1006 }
1007
1008 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1009
1010 /* For a read, copy the packet data back to the buffer. */
1011 if (!write) {
1012 bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
1013 }
1014 #ifdef DHD_USE_STATIC_BUF
1015 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1016 #else
1017 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1018 #endif /* DHD_USE_STATIC_BUF */
1019 } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
1020 /* Case 2: We have a packet, but it is unaligned. */
1021
1022 /* In this case, we cannot have a chain. */
1023 ASSERT(PKTNEXT(sd->osh, pkt) == NULL);
1024
1025 sd_data(("%s: Creating aligned %s Packet, len=%d\n",
1026 __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
1027 #ifdef DHD_USE_STATIC_BUF
1028 if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1029 #else
1030 if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1031 #endif /* DHD_USE_STATIC_BUF */
1032 sd_err(("%s: PKTGET failed: len %d\n",
1033 __FUNCTION__, PKTLEN(sd->osh, pkt)));
1034 return SDIOH_API_RC_FAIL;
1035 }
1036
1037 /* For a write, copy the buffer data into the packet. */
1038 if (write) {
1039 bcopy(PKTDATA(sd->osh, pkt),
1040 PKTDATA(sd->osh, mypkt),
1041 PKTLEN(sd->osh, pkt));
1042 }
1043
1044 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1045
1046 /* For a read, copy the packet data back to the buffer. */
1047 if (!write) {
1048 bcopy(PKTDATA(sd->osh, mypkt),
1049 PKTDATA(sd->osh, pkt),
1050 PKTLEN(sd->osh, mypkt));
1051 }
1052 #ifdef DHD_USE_STATIC_BUF
1053 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1054 #else
1055 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1056 #endif /* DHD_USE_STATIC_BUF */
1057 } else { /* case 3: We have a packet and it is aligned. */
1058 sd_data(("%s: Aligned %s Packet, direct DMA\n",
1059 __FUNCTION__, write ? "Tx" : "Rx"));
1060 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
1061 }
1062
1063 return (Status);
1064 }
1065
1066 extern int
1067 sdioh_abort(sdioh_info_t *sd, uint func)
1068 {
1069 char t_func = (char) func;
1070
1071 sd_trace(("%s: Enter\n", __FUNCTION__));
1072
1073 #if defined(MMC_SDIO_ABORT)
1074 /* issue abort cmd52 command through F1 */
1075 sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func);
1076 #endif /* defined(MMC_SDIO_ABORT) */
1077
1078 sd_trace(("%s: Exit\n", __FUNCTION__));
1079 return SDIOH_API_RC_SUCCESS;
1080 }
1081
1082 /* Reset and re-initialize the device */
1083 int sdioh_sdio_reset(sdioh_info_t *si)
1084 {
1085 sd_trace(("%s: Enter\n", __FUNCTION__));
1086 sd_trace(("%s: Exit\n", __FUNCTION__));
1087 return SDIOH_API_RC_SUCCESS;
1088 }
1089
1090 /* Disable device interrupt */
1091 void
1092 sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1093 {
1094 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1095 sd->intmask &= ~CLIENT_INTR;
1096 }
1097
1098 /* Enable device interrupt */
1099 void
1100 sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1101 {
1102 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1103 sd->intmask |= CLIENT_INTR;
1104 }
1105
1106 /* Read client card reg */
1107 int
1108 sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
1109 {
1110
1111 if ((func == 0) || (regsize == 1)) {
1112 uint8 temp = 0;
1113
1114 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1115 *data = temp;
1116 *data &= 0xff;
1117 sd_data(("%s: byte read data=0x%02x\n",
1118 __FUNCTION__, *data));
1119 } else {
1120 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
1121 if (regsize == 2)
1122 *data &= 0xffff;
1123
1124 sd_data(("%s: word read data=0x%08x\n",
1125 __FUNCTION__, *data));
1126 }
1127
1128 return SUCCESS;
1129 }
1130
1131 #if !defined(OOB_INTR_ONLY)
1132 /* bcmsdh_sdmmc interrupt handler */
1133 static void IRQHandler(struct sdio_func *func)
1134 {
1135 sdioh_info_t *sd;
1136
1137 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1138 sd = gInstance->sd;
1139
1140 ASSERT(sd != NULL);
1141 sdio_release_host(gInstance->func[0]);
1142
1143 if (sd->use_client_ints) {
1144 sd->intrcount++;
1145 ASSERT(sd->intr_handler);
1146 ASSERT(sd->intr_handler_arg);
1147 (sd->intr_handler)(sd->intr_handler_arg);
1148 } else {
1149 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1150
1151 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1152 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
1153 }
1154
1155 sdio_claim_host(gInstance->func[0]);
1156 }
1157
1158 /* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1159 static void IRQHandlerF2(struct sdio_func *func)
1160 {
1161 sdioh_info_t *sd;
1162
1163 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1164
1165 sd = gInstance->sd;
1166
1167 ASSERT(sd != NULL);
1168 }
1169 #endif /* !defined(OOB_INTR_ONLY) */
1170
1171 #ifdef NOTUSED
1172 /* Write client card reg */
1173 static int
1174 sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
1175 {
1176
1177 if ((func == 0) || (regsize == 1)) {
1178 uint8 temp;
1179
1180 temp = data & 0xff;
1181 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1182 sd_data(("%s: byte write data=0x%02x\n",
1183 __FUNCTION__, data));
1184 } else {
1185 if (regsize == 2)
1186 data &= 0xffff;
1187
1188 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize);
1189
1190 sd_data(("%s: word write data=0x%08x\n",
1191 __FUNCTION__, data));
1192 }
1193
1194 return SUCCESS;
1195 }
1196 #endif /* NOTUSED */
1197
1198 int
1199 sdioh_start(sdioh_info_t *si, int stage)
1200 {
1201 int ret;
1202 sdioh_info_t *sd = gInstance->sd;
1203
1204 /* Need to do this stages as we can't enable the interrupt till
1205 downloading of the firmware is complete, other wise polling
1206 sdio access will come in way
1207 */
1208 if (gInstance->func[0]) {
1209 if (stage == 0) {
1210 /* Since the power to the chip is killed, we will have
1211 re enumerate the device again. Set the block size
1212 and enable the fucntion 1 for in preparation for
1213 downloading the code
1214 */
1215 /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
1216 2.6.27. The implementation prior to that is buggy, and needs broadcom's
1217 patch for it
1218 */
1219 if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
1220 sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
1221 else {
1222 sd->num_funcs = 2;
1223 sd->sd_blockmode = TRUE;
1224 sd->use_client_ints = TRUE;
1225 sd->client_block_size[0] = 64;
1226
1227 /* Claim host controller */
1228 sdio_claim_host(gInstance->func[1]);
1229
1230 sd->client_block_size[1] = 64;
1231 if (sdio_set_block_size(gInstance->func[1], 64)) {
1232 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
1233 }
1234
1235 /* Release host controller F1 */
1236 sdio_release_host(gInstance->func[1]);
1237
1238 if (gInstance->func[2]) {
1239 /* Claim host controller F2 */
1240 sdio_claim_host(gInstance->func[2]);
1241
1242 sd->client_block_size[2] = sd_f2_blocksize;
1243 if (sdio_set_block_size(gInstance->func[2],
1244 sd_f2_blocksize)) {
1245 sd_err(("bcmsdh_sdmmc: Failed to set F2 "
1246 "blocksize to %d\n", sd_f2_blocksize));
1247 }
1248
1249 /* Release host controller F2 */
1250 sdio_release_host(gInstance->func[2]);
1251 }
1252
1253 sdioh_sdmmc_card_enablefuncs(sd);
1254 }
1255 } else {
1256 #if !defined(OOB_INTR_ONLY)
1257 sdio_claim_host(gInstance->func[0]);
1258 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
1259 sdio_claim_irq(gInstance->func[1], IRQHandler);
1260 sdio_release_host(gInstance->func[0]);
1261 #else /* defined(OOB_INTR_ONLY) */
1262 #if defined(HW_OOB)
1263 sdioh_enable_func_intr(2);
1264 #endif
1265 bcmsdh_oob_intr_set(TRUE);
1266 #endif /* !defined(OOB_INTR_ONLY) */
1267 }
1268 }
1269 else
1270 sd_err(("%s Failed\n", __FUNCTION__));
1271
1272 return (0);
1273 }
1274
1275 int
1276 sdioh_stop(sdioh_info_t *si)
1277 {
1278 /* MSM7201A Android sdio stack has bug with interrupt
1279 So internaly within SDIO stack they are polling
1280 which cause issue when device is turned off. So
1281 unregister interrupt with SDIO stack to stop the
1282 polling
1283 */
1284 if (gInstance->func[0]) {
1285 #if !defined(OOB_INTR_ONLY)
1286 sdio_claim_host(gInstance->func[0]);
1287 sdio_release_irq(gInstance->func[1]);
1288 sdio_release_irq(gInstance->func[2]);
1289 sdio_release_host(gInstance->func[0]);
1290 #else /* defined(OOB_INTR_ONLY) */
1291 #if defined(HW_OOB)
1292 sdioh_disable_func_intr(2);
1293 #endif
1294 bcmsdh_oob_intr_set(FALSE);
1295 #endif /* !defined(OOB_INTR_ONLY) */
1296 }
1297 else
1298 sd_err(("%s Failed\n", __FUNCTION__));
1299 return (0);
1300 }
1301