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