]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/staging/brcm80211/brcmfmac/bcmsdh.c
e5cf138100f1289208de60798823f3173ad73490
[mv-sheeva.git] / drivers / staging / brcm80211 / brcmfmac / bcmsdh.c
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 /* ****************** SDIO CARD Interface Functions **************************/
17
18 #include <linux/types.h>
19 #include <linux/netdevice.h>
20 #include <linux/pci.h>
21 #include <linux/pci_ids.h>
22 #include <linux/sched.h>
23 #include <linux/completion.h>
24 #include <linux/mmc/sdio_func.h>
25 #include <linux/mmc/card.h>
26
27 #include <defs.h>
28 #include <brcm_hw_ids.h>
29 #include <brcmu_utils.h>
30 #include <brcmu_wifi.h>
31 #include <soc.h>
32 #include "dhd.h"
33 #include "dhd_bus.h"
34 #include "dhd_dbg.h"
35 #include "sdio_host.h"
36
37 #define SDIOH_API_ACCESS_RETRY_LIMIT    2
38
39 #define SDIOH_CMD_TYPE_NORMAL   0       /* Normal command */
40 #define SDIOH_CMD_TYPE_APPEND   1       /* Append command */
41 #define SDIOH_CMD_TYPE_CUTTHRU  2       /* Cut-through command */
42
43 #define SDIOH_DATA_PIO          0       /* PIO mode */
44 #define SDIOH_DATA_DMA          1       /* DMA mode */
45
46 /* Module parameters specific to each host-controller driver */
47
48 module_param(sd_f2_blocksize, int, 0);
49
50 /* IOVar table */
51 enum {
52         IOV_MSGLEVEL = 1,
53         IOV_DEVREG,
54         IOV_HCIREGS,
55         IOV_RXCHAIN
56 };
57
58 const struct brcmu_iovar sdioh_iovars[] = {
59         {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)}
60         ,
61         {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0}
62         ,
63         {NULL, 0, 0, 0, 0}
64 };
65
66 int
67 brcmf_sdcard_iovar_op(struct brcmf_sdio_dev *sdiodev, const char *name,
68                 void *params, int plen, void *arg, int len, bool set)
69 {
70         const struct brcmu_iovar *vi = NULL;
71         int bcmerror = 0;
72         int val_size;
73         s32 int_val = 0;
74         bool bool_val;
75         u32 actionid;
76
77         if (name == NULL || len < 0)
78                 return -EINVAL;
79
80         /* Set does not take qualifiers */
81         if (set && (params || plen))
82                 return -EINVAL;
83
84         /* Get must have return space;*/
85         if (!set && !(arg && len))
86                 return -EINVAL;
87
88         BRCMF_TRACE(("%s: Enter (%s %s)\n", __func__, (set ? "set" : "get"),
89                   name));
90
91         vi = brcmu_iovar_lookup(sdioh_iovars, name);
92         if (vi == NULL) {
93                 bcmerror = -ENOTSUPP;
94                 goto exit;
95         }
96
97         bcmerror = brcmu_iovar_lencheck(vi, arg, len, set);
98         if (bcmerror != 0)
99                 goto exit;
100
101         /* Set up params so get and set can share the convenience variables */
102         if (params == NULL) {
103                 params = arg;
104                 plen = len;
105         }
106
107         if (vi->type == IOVT_VOID)
108                 val_size = 0;
109         else if (vi->type == IOVT_BUFFER)
110                 val_size = len;
111         else
112                 val_size = sizeof(int);
113
114         if (plen >= (int)sizeof(int_val))
115                 memcpy(&int_val, params, sizeof(int_val));
116
117         bool_val = (int_val != 0) ? true : false;
118
119         actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
120         switch (actionid) {
121         case IOV_GVAL(IOV_RXCHAIN):
122                 int_val = false;
123                 memcpy(arg, &int_val, val_size);
124                 break;
125
126         case IOV_GVAL(IOV_DEVREG):
127                 {
128                         struct brcmf_sdreg *sd_ptr =
129                                         (struct brcmf_sdreg *) params;
130                         u8 data = 0;
131
132                         if (brcmf_sdioh_cfg_read
133                             (sdiodev, sd_ptr->func, sd_ptr->offset, &data)) {
134                                 bcmerror = -EIO;
135                                 break;
136                         }
137
138                         int_val = (int)data;
139                         memcpy(arg, &int_val, sizeof(int_val));
140                         break;
141                 }
142
143         case IOV_SVAL(IOV_DEVREG):
144                 {
145                         struct brcmf_sdreg *sd_ptr =
146                                         (struct brcmf_sdreg *) params;
147                         u8 data = (u8) sd_ptr->value;
148
149                         if (brcmf_sdioh_cfg_write
150                             (sdiodev, sd_ptr->func, sd_ptr->offset, &data)) {
151                                 bcmerror = -EIO;
152                                 break;
153                         }
154                         break;
155                 }
156
157         default:
158                 bcmerror = -ENOTSUPP;
159                 break;
160         }
161 exit:
162
163         return bcmerror;
164 }
165
166 static void brcmf_sdioh_irqhandler(struct sdio_func *func)
167 {
168         struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
169
170         BRCMF_TRACE(("brcmf: ***IRQHandler\n"));
171
172         sdio_release_host(func);
173
174         brcmf_sdbrcm_isr(sdiodev->bus);
175
176         sdio_claim_host(func);
177 }
178
179 int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev)
180 {
181         BRCMF_TRACE(("%s: Entering\n", __func__));
182
183         sdio_claim_host(sdiodev->func[1]);
184         sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler);
185         sdio_release_host(sdiodev->func[1]);
186
187         return 0;
188 }
189
190 int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev)
191 {
192         return brcmf_sdioh_interrupt_deregister(sdiodev);
193 }
194
195 u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
196                          int *err)
197 {
198         int status;
199         s32 retry = 0;
200         u8 data = 0;
201
202         do {
203                 if (retry)      /* wait for 1 ms till bus get settled down */
204                         udelay(1000);
205                 status =
206                     brcmf_sdioh_cfg_read(sdiodev, fnc_num, addr,
207                                    (u8 *) &data);
208         } while (status != 0
209                  && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
210         if (err)
211                 *err = status;
212
213         BRCMF_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n",
214                      __func__, fnc_num, addr, data));
215
216         return data;
217 }
218
219 void
220 brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
221                        u8 data, int *err)
222 {
223         int status;
224         s32 retry = 0;
225
226         do {
227                 if (retry)      /* wait for 1 ms till bus get settled down */
228                         udelay(1000);
229                 status =
230                     brcmf_sdioh_cfg_write(sdiodev, fnc_num, addr,
231                                     (u8 *) &data);
232         } while (status != 0
233                  && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
234         if (err)
235                 *err = status;
236
237         BRCMF_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n",
238                      __func__, fnc_num, addr, data));
239 }
240
241 int brcmf_sdcard_cis_read(struct brcmf_sdio_dev *sdiodev, uint func, u8 * cis,
242                           uint length)
243 {
244         int status;
245
246         u8 *tmp_buf, *tmp_ptr;
247         u8 *ptr;
248         bool ascii = func & ~0xf;
249         func &= 0x7;
250
251         status = brcmf_sdioh_cis_read(sdiodev, func, cis, length);
252
253         if (ascii) {
254                 /* Move binary bits to tmp and format them
255                          into the provided buffer. */
256                 tmp_buf = kmalloc(length, GFP_ATOMIC);
257                 if (tmp_buf == NULL) {
258                         BRCMF_ERROR(("%s: out of memory\n", __func__));
259                         return -ENOMEM;
260                 }
261                 memcpy(tmp_buf, cis, length);
262                 for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4);
263                      tmp_ptr++) {
264                         ptr += sprintf((char *)ptr, "%.2x ", *tmp_ptr & 0xff);
265                         if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0)
266                                 ptr += sprintf((char *)ptr, "\n");
267                 }
268                 kfree(tmp_buf);
269         }
270
271         return status;
272 }
273
274 static int
275 brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
276 {
277         int err = 0;
278         brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
279                          (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
280         if (!err)
281                 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
282                                        SBSDIO_FUNC1_SBADDRMID,
283                                        (address >> 16) & SBSDIO_SBADDRMID_MASK,
284                                        &err);
285         if (!err)
286                 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
287                                        SBSDIO_FUNC1_SBADDRHIGH,
288                                        (address >> 24) & SBSDIO_SBADDRHIGH_MASK,
289                                        &err);
290
291         return err;
292 }
293
294 u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size)
295 {
296         int status;
297         u32 word = 0;
298         uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
299
300         BRCMF_INFO(("%s:fun = 1, addr = 0x%x, ", __func__, addr));
301
302         if (bar0 != sdiodev->sbwad) {
303                 if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0))
304                         return 0xFFFFFFFF;
305
306                 sdiodev->sbwad = bar0;
307         }
308
309         addr &= SBSDIO_SB_OFT_ADDR_MASK;
310         if (size == 4)
311                 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
312
313         status = brcmf_sdioh_request_word(sdiodev, SDIOH_CMD_TYPE_NORMAL,
314                                     SDIOH_READ, SDIO_FUNC_1, addr, &word, size);
315
316         sdiodev->regfail = (status != 0);
317
318         BRCMF_INFO(("u32data = 0x%x\n", word));
319
320         /* if ok, return appropriately masked word */
321         if (status == 0) {
322                 switch (size) {
323                 case sizeof(u8):
324                         return word & 0xff;
325                 case sizeof(u16):
326                         return word & 0xffff;
327                 case sizeof(u32):
328                         return word;
329                 default:
330                         sdiodev->regfail = true;
331
332                 }
333         }
334
335         /* otherwise, bad sdio access or invalid size */
336         BRCMF_ERROR(("%s: error reading addr 0x%04x size %d\n", __func__,
337                       addr, size));
338         return 0xFFFFFFFF;
339 }
340
341 u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
342                            u32 data)
343 {
344         int status;
345         uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
346         int err = 0;
347
348         BRCMF_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
349                      __func__, addr, size * 8, data));
350
351         if (bar0 != sdiodev->sbwad) {
352                 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
353                 if (err)
354                         return err;
355
356                 sdiodev->sbwad = bar0;
357         }
358
359         addr &= SBSDIO_SB_OFT_ADDR_MASK;
360         if (size == 4)
361                 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
362         status =
363             brcmf_sdioh_request_word(sdiodev, SDIOH_CMD_TYPE_NORMAL,
364                                SDIOH_WRITE, SDIO_FUNC_1, addr, &data, size);
365         sdiodev->regfail = (status != 0);
366
367         if (status == 0)
368                 return 0;
369
370         BRCMF_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
371                       __func__, data, addr, size));
372         return 0xFFFFFFFF;
373 }
374
375 bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
376 {
377         return sdiodev->regfail;
378 }
379
380 int
381 brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
382                       uint flags,
383                       u8 *buf, uint nbytes, struct sk_buff *pkt,
384                       void (*complete)(void *handle, int status,
385                                        bool sync_waiting),
386                       void *handle)
387 {
388         int status;
389         uint incr_fix;
390         uint width;
391         uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
392         int err = 0;
393
394         BRCMF_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
395                      __func__, fn, addr, nbytes));
396
397         /* Async not implemented yet */
398         if (flags & SDIO_REQ_ASYNC)
399                 return -ENOTSUPP;
400
401         if (bar0 != sdiodev->sbwad) {
402                 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
403                 if (err)
404                         return err;
405
406                 sdiodev->sbwad = bar0;
407         }
408
409         addr &= SBSDIO_SB_OFT_ADDR_MASK;
410
411         incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
412         width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
413         if (width == 4)
414                 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
415
416         status = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_PIO,
417                 incr_fix, SDIOH_READ, fn, addr, width, nbytes, buf, pkt);
418
419         return status;
420 }
421
422 int
423 brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
424                       uint flags, u8 *buf, uint nbytes, void *pkt,
425                       void (*complete)(void *handle, int status,
426                                        bool sync_waiting),
427                       void *handle)
428 {
429         uint incr_fix;
430         uint width;
431         uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
432         int err = 0;
433
434         BRCMF_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
435                      __func__, fn, addr, nbytes));
436
437         /* Async not implemented yet */
438         if (flags & SDIO_REQ_ASYNC)
439                 return -ENOTSUPP;
440
441         if (bar0 != sdiodev->sbwad) {
442                 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
443                 if (err)
444                         return err;
445
446                 sdiodev->sbwad = bar0;
447         }
448
449         addr &= SBSDIO_SB_OFT_ADDR_MASK;
450
451         incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
452         width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
453         if (width == 4)
454                 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
455
456         return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_PIO,
457                 incr_fix, SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
458 }
459
460 int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
461                         u8 *buf, uint nbytes)
462 {
463         addr &= SBSDIO_SB_OFT_ADDR_MASK;
464         addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
465
466         return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_PIO,
467                 SDIOH_DATA_INC, (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
468                 addr, 4, nbytes, buf, NULL);
469 }
470
471 int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
472 {
473         return brcmf_sdioh_abort(sdiodev, fn);
474 }
475
476 u32 brcmf_sdcard_cur_sbwad(struct brcmf_sdio_dev *sdiodev)
477 {
478         return sdiodev->sbwad;
479 }
480
481 int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
482 {
483         u32 regs = 0;
484         int ret = 0;
485
486         ret = brcmf_sdioh_attach(sdiodev);
487         if (ret)
488                 goto out;
489
490         regs = SI_ENUM_BASE;
491
492         /* Report the BAR, to fix if needed */
493         sdiodev->sbwad = SI_ENUM_BASE;
494
495         /* try to attach to the target device */
496         sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev);
497         if (!sdiodev->bus) {
498                 BRCMF_ERROR(("%s: device attach failed\n", __func__));
499                 ret = -ENODEV;
500                 goto out;
501         }
502
503 out:
504         if (ret)
505                 brcmf_sdio_remove(sdiodev);
506
507         return ret;
508 }
509 EXPORT_SYMBOL(brcmf_sdio_probe);
510
511 int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
512 {
513         if (sdiodev->bus) {
514                 brcmf_sdbrcm_disconnect(sdiodev->bus);
515                 sdiodev->bus = NULL;
516         }
517
518         brcmf_sdioh_detach(sdiodev);
519
520         sdiodev->sbwad = 0;
521
522         return 0;
523 }
524 EXPORT_SYMBOL(brcmf_sdio_remove);
525
526 int brcmf_sdio_register(void)
527 {
528         return brcmf_sdio_function_init();
529 }
530
531 void brcmf_sdio_unregister(void)
532 {
533         brcmf_sdio_function_cleanup();
534 }
535
536 void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
537 {
538         if (enable)
539                 brcmf_sdbrcm_wd_timer(sdiodev->bus, brcmf_watchdog_ms);
540         else
541                 brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
542 }