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