.. | .. |
---|
| 1 | +// SPDX-License-Identifier: ISC |
---|
1 | 2 | /* |
---|
2 | 3 | * 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 | 4 | */ |
---|
16 | 5 | |
---|
17 | 6 | #include <linux/types.h> |
---|
.. | .. |
---|
27 | 16 | #include <linux/mmc/sdio_ids.h> |
---|
28 | 17 | #include <linux/mmc/sdio_func.h> |
---|
29 | 18 | #include <linux/mmc/card.h> |
---|
| 19 | +#include <linux/mmc/core.h> |
---|
30 | 20 | #include <linux/semaphore.h> |
---|
31 | 21 | #include <linux/firmware.h> |
---|
32 | 22 | #include <linux/module.h> |
---|
.. | .. |
---|
52 | 42 | /* watermark expressed in number of words */ |
---|
53 | 43 | #define DEFAULT_F2_WATERMARK 0x8 |
---|
54 | 44 | #define CY_4373_F2_WATERMARK 0x40 |
---|
| 45 | +#define CY_4373_F1_MESBUSYCTRL (CY_4373_F2_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB) |
---|
| 46 | +#define CY_43012_F2_WATERMARK 0x60 |
---|
| 47 | +#define CY_43012_MES_WATERMARK 0x50 |
---|
| 48 | +#define CY_43012_MESBUSYCTRL (CY_43012_MES_WATERMARK | \ |
---|
| 49 | + SBSDIO_MESBUSYCTRL_ENAB) |
---|
| 50 | +#define CY_4339_F2_WATERMARK 48 |
---|
| 51 | +#define CY_4339_MES_WATERMARK 80 |
---|
| 52 | +#define CY_4339_MESBUSYCTRL (CY_4339_MES_WATERMARK | \ |
---|
| 53 | + SBSDIO_MESBUSYCTRL_ENAB) |
---|
| 54 | +#define CY_43455_F2_WATERMARK 0x60 |
---|
| 55 | +#define CY_43455_MES_WATERMARK 0x50 |
---|
| 56 | +#define CY_43455_MESBUSYCTRL (CY_43455_MES_WATERMARK | \ |
---|
| 57 | + SBSDIO_MESBUSYCTRL_ENAB) |
---|
| 58 | +#define CY_435X_F2_WATERMARK 0x40 |
---|
| 59 | +#define CY_435X_F1_MESBUSYCTRL (CY_435X_F2_WATERMARK | \ |
---|
| 60 | + SBSDIO_MESBUSYCTRL_ENAB) |
---|
55 | 61 | |
---|
56 | 62 | #ifdef DEBUG |
---|
57 | 63 | |
---|
.. | .. |
---|
323 | 329 | #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) |
---|
324 | 330 | #define BRCMF_SDIO_MAX_ACCESS_ERRORS 5 |
---|
325 | 331 | |
---|
326 | | -/* |
---|
327 | | - * Conversion of 802.1D priority to precedence level |
---|
328 | | - */ |
---|
329 | | -static uint prio2prec(u32 prio) |
---|
330 | | -{ |
---|
331 | | - return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ? |
---|
332 | | - (prio^2) : prio; |
---|
333 | | -} |
---|
334 | | - |
---|
335 | 332 | #ifdef DEBUG |
---|
336 | 333 | /* Device console log buffer state */ |
---|
337 | 334 | struct brcmf_console { |
---|
.. | .. |
---|
560 | 557 | BRCMF_SDIO_FT_SUB, |
---|
561 | 558 | }; |
---|
562 | 559 | |
---|
563 | | -#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) |
---|
| 560 | +#define SDIOD_DRVSTR_KEY(chip, pmu) (((unsigned int)(chip) << 16) | (pmu)) |
---|
564 | 561 | |
---|
565 | 562 | /* SDIO Pad drive strength to select value mappings */ |
---|
566 | 563 | struct sdiod_drive_str { |
---|
.. | .. |
---|
621 | 618 | /* Note the names are not postfixed with a1 for backward compatibility */ |
---|
622 | 619 | BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio"); |
---|
623 | 620 | BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"); |
---|
| 621 | +BRCMF_FW_DEF(43456, "brcmfmac43456-sdio"); |
---|
624 | 622 | BRCMF_FW_DEF(4354, "brcmfmac4354-sdio"); |
---|
625 | 623 | BRCMF_FW_DEF(4356, "brcmfmac4356-sdio"); |
---|
| 624 | +BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); |
---|
626 | 625 | BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); |
---|
| 626 | +BRCMF_FW_DEF(43012, "brcmfmac43012-sdio"); |
---|
627 | 627 | |
---|
628 | 628 | static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { |
---|
629 | 629 | BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), |
---|
.. | .. |
---|
640 | 640 | BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), |
---|
641 | 641 | BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), |
---|
642 | 642 | BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), |
---|
643 | | - BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455), |
---|
| 643 | + BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0x00000200, 43456), |
---|
| 644 | + BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455), |
---|
644 | 645 | BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), |
---|
645 | 646 | BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), |
---|
646 | | - BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373) |
---|
| 647 | + BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), |
---|
| 648 | + BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373), |
---|
| 649 | + BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) |
---|
647 | 650 | }; |
---|
| 651 | + |
---|
| 652 | +#define TXCTL_CREDITS 2 |
---|
648 | 653 | |
---|
649 | 654 | static void pkt_align(struct sk_buff *p, int len, int align) |
---|
650 | 655 | { |
---|
.. | .. |
---|
659 | 664 | /* To check if there's window offered */ |
---|
660 | 665 | static bool data_ok(struct brcmf_sdio *bus) |
---|
661 | 666 | { |
---|
662 | | - return (u8)(bus->tx_max - bus->tx_seq) != 0 && |
---|
663 | | - ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0; |
---|
| 667 | + u8 tx_rsv = 0; |
---|
| 668 | + |
---|
| 669 | + /* Reserve TXCTL_CREDITS credits for txctl when it is ready to send */ |
---|
| 670 | + if (bus->ctrl_frame_stat) |
---|
| 671 | + tx_rsv = TXCTL_CREDITS; |
---|
| 672 | + |
---|
| 673 | + return (bus->tx_max - bus->tx_seq - tx_rsv) != 0 && |
---|
| 674 | + ((bus->tx_max - bus->tx_seq - tx_rsv) & 0x80) == 0; |
---|
| 675 | + |
---|
| 676 | +} |
---|
| 677 | + |
---|
| 678 | +/* To check if there's window offered */ |
---|
| 679 | +static bool txctl_ok(struct brcmf_sdio *bus) |
---|
| 680 | +{ |
---|
| 681 | + return (bus->tx_max - bus->tx_seq) != 0 && |
---|
| 682 | + ((bus->tx_max - bus->tx_seq) & 0x80) == 0; |
---|
664 | 683 | } |
---|
665 | 684 | |
---|
666 | 685 | static int |
---|
.. | .. |
---|
682 | 701 | wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); |
---|
683 | 702 | /* 1st KSO write goes to AOS wake up core if device is asleep */ |
---|
684 | 703 | brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); |
---|
| 704 | + |
---|
| 705 | + /* In case of 43012 chip, the chip could go down immediately after |
---|
| 706 | + * KSO bit is cleared. So the further reads of KSO register could |
---|
| 707 | + * fail. Thereby just bailing out immediately after clearing KSO |
---|
| 708 | + * bit, to avoid polling of KSO bit. |
---|
| 709 | + */ |
---|
| 710 | + if (!on && bus->ci->chip == CY_CC_43012_CHIP_ID) |
---|
| 711 | + return err; |
---|
685 | 712 | |
---|
686 | 713 | if (on) { |
---|
687 | 714 | /* device WAKEUP through KSO: |
---|
.. | .. |
---|
1090 | 1117 | |
---|
1091 | 1118 | /* dongle indicates the firmware has halted/crashed */ |
---|
1092 | 1119 | if (hmb_data & HMB_DATA_FWHALT) { |
---|
1093 | | - brcmf_err("mailbox indicates firmware halted\n"); |
---|
1094 | | - brcmf_dev_coredump(&sdiod->func1->dev); |
---|
| 1120 | + brcmf_dbg(SDIO, "mailbox indicates firmware halted\n"); |
---|
| 1121 | + brcmf_fw_crashed(&sdiod->func1->dev); |
---|
1095 | 1122 | } |
---|
1096 | 1123 | |
---|
1097 | 1124 | /* Dongle recomposed rx frames, accept them again */ |
---|
.. | .. |
---|
1480 | 1507 | struct sk_buff *pfirst, *pnext; |
---|
1481 | 1508 | |
---|
1482 | 1509 | int errcode; |
---|
1483 | | - u8 doff, sfdoff; |
---|
| 1510 | + u8 doff; |
---|
1484 | 1511 | |
---|
1485 | 1512 | struct brcmf_sdio_hdrinfo rd_new; |
---|
1486 | 1513 | |
---|
.. | .. |
---|
1614 | 1641 | |
---|
1615 | 1642 | /* Remove superframe header, remember offset */ |
---|
1616 | 1643 | skb_pull(pfirst, rd_new.dat_offset); |
---|
1617 | | - sfdoff = rd_new.dat_offset; |
---|
1618 | 1644 | num = 0; |
---|
1619 | 1645 | |
---|
1620 | 1646 | /* Validate all the subframe headers */ |
---|
.. | .. |
---|
1678 | 1704 | brcmf_rx_event(bus->sdiodev->dev, pfirst); |
---|
1679 | 1705 | else |
---|
1680 | 1706 | brcmf_rx_frame(bus->sdiodev->dev, pfirst, |
---|
1681 | | - false); |
---|
| 1707 | + false, false); |
---|
1682 | 1708 | bus->sdcnt.rxglompkts++; |
---|
1683 | 1709 | } |
---|
1684 | 1710 | |
---|
.. | .. |
---|
2012 | 2038 | brcmf_rx_event(bus->sdiodev->dev, pkt); |
---|
2013 | 2039 | else |
---|
2014 | 2040 | brcmf_rx_frame(bus->sdiodev->dev, pkt, |
---|
2015 | | - false); |
---|
| 2041 | + false, false); |
---|
2016 | 2042 | |
---|
2017 | 2043 | /* prepare the descriptor for the next read */ |
---|
2018 | 2044 | rd->len = rd->len_nxtfrm << 4; |
---|
.. | .. |
---|
2209 | 2235 | * length of the chain (including padding) |
---|
2210 | 2236 | */ |
---|
2211 | 2237 | if (bus->txglom) |
---|
2212 | | - brcmf_sdio_update_hwhdr(pktq->next->data, total_len); |
---|
| 2238 | + brcmf_sdio_update_hwhdr(__skb_peek(pktq)->data, total_len); |
---|
2213 | 2239 | return 0; |
---|
2214 | 2240 | } |
---|
2215 | 2241 | |
---|
.. | .. |
---|
2417 | 2443 | return ret; |
---|
2418 | 2444 | } |
---|
2419 | 2445 | |
---|
| 2446 | +static bool brcmf_chip_is_ulp(struct brcmf_chip *ci) |
---|
| 2447 | +{ |
---|
| 2448 | + if (ci->chip == CY_CC_43012_CHIP_ID) |
---|
| 2449 | + return true; |
---|
| 2450 | + else |
---|
| 2451 | + return false; |
---|
| 2452 | +} |
---|
| 2453 | + |
---|
2420 | 2454 | static void brcmf_sdio_bus_stop(struct device *dev) |
---|
2421 | 2455 | { |
---|
2422 | 2456 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
---|
.. | .. |
---|
2424 | 2458 | struct brcmf_sdio *bus = sdiodev->bus; |
---|
2425 | 2459 | struct brcmf_core *core = bus->sdio_core; |
---|
2426 | 2460 | u32 local_hostintmask; |
---|
2427 | | - u8 saveclk; |
---|
| 2461 | + u8 saveclk, bpreq; |
---|
2428 | 2462 | int err; |
---|
2429 | 2463 | |
---|
2430 | 2464 | brcmf_dbg(TRACE, "Enter\n"); |
---|
.. | .. |
---|
2451 | 2485 | /* Force backplane clocks to assure F2 interrupt propagates */ |
---|
2452 | 2486 | saveclk = brcmf_sdiod_readb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, |
---|
2453 | 2487 | &err); |
---|
2454 | | - if (!err) |
---|
2455 | | - brcmf_sdiod_writeb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, |
---|
2456 | | - (saveclk | SBSDIO_FORCE_HT), &err); |
---|
| 2488 | + if (!err) { |
---|
| 2489 | + bpreq = saveclk; |
---|
| 2490 | + bpreq |= brcmf_chip_is_ulp(bus->ci) ? |
---|
| 2491 | + SBSDIO_HT_AVAIL_REQ : SBSDIO_FORCE_HT; |
---|
| 2492 | + brcmf_sdiod_writeb(sdiodev, |
---|
| 2493 | + SBSDIO_FUNC1_CHIPCLKCSR, |
---|
| 2494 | + bpreq, &err); |
---|
| 2495 | + } |
---|
2457 | 2496 | if (err) |
---|
2458 | 2497 | brcmf_err("Failed to force clock for F2: err %d\n", |
---|
2459 | 2498 | err); |
---|
.. | .. |
---|
2646 | 2685 | brcmf_sdio_clrintr(bus); |
---|
2647 | 2686 | |
---|
2648 | 2687 | if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && |
---|
2649 | | - data_ok(bus)) { |
---|
| 2688 | + txctl_ok(bus)) { |
---|
2650 | 2689 | sdio_claim_host(bus->sdiodev->func1); |
---|
2651 | 2690 | if (bus->ctrl_frame_stat) { |
---|
2652 | 2691 | err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, |
---|
.. | .. |
---|
2654 | 2693 | bus->ctrl_frame_err = err; |
---|
2655 | 2694 | wmb(); |
---|
2656 | 2695 | bus->ctrl_frame_stat = false; |
---|
| 2696 | + if (err) |
---|
| 2697 | + brcmf_err("sdio ctrlframe tx failed err=%d\n", |
---|
| 2698 | + err); |
---|
2657 | 2699 | } |
---|
2658 | 2700 | sdio_release_host(bus->sdiodev->func1); |
---|
2659 | 2701 | brcmf_sdio_wait_event_wakeup(bus); |
---|
.. | .. |
---|
2756 | 2798 | skb_push(pkt, bus->tx_hdrlen); |
---|
2757 | 2799 | /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ |
---|
2758 | 2800 | |
---|
2759 | | - prec = prio2prec((pkt->priority & PRIOMASK)); |
---|
| 2801 | + /* In WLAN, priority is always set by the AP using WMM parameters |
---|
| 2802 | + * and this need not always follow the standard 802.1d priority. |
---|
| 2803 | + * Based on AP WMM config, map from 802.1d priority to corresponding |
---|
| 2804 | + * precedence level. |
---|
| 2805 | + */ |
---|
| 2806 | + prec = brcmf_map_prio_to_prec(bus_if->drvr->config, |
---|
| 2807 | + (pkt->priority & PRIOMASK)); |
---|
2760 | 2808 | |
---|
2761 | 2809 | /* Check for existing queue, current flow-control, |
---|
2762 | 2810 | pending event, or pending clock */ |
---|
.. | .. |
---|
2990 | 3038 | if (error < 0) |
---|
2991 | 3039 | return error; |
---|
2992 | 3040 | |
---|
2993 | | - seq_printf(seq, |
---|
2994 | | - "dongle trap info: type 0x%x @ epc 0x%08x\n" |
---|
2995 | | - " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n" |
---|
2996 | | - " lr 0x%08x pc 0x%08x offset 0x%x\n" |
---|
2997 | | - " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n" |
---|
2998 | | - " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n", |
---|
2999 | | - le32_to_cpu(tr.type), le32_to_cpu(tr.epc), |
---|
3000 | | - le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr), |
---|
3001 | | - le32_to_cpu(tr.r13), le32_to_cpu(tr.r14), |
---|
3002 | | - le32_to_cpu(tr.pc), sh->trap_addr, |
---|
3003 | | - le32_to_cpu(tr.r0), le32_to_cpu(tr.r1), |
---|
3004 | | - le32_to_cpu(tr.r2), le32_to_cpu(tr.r3), |
---|
3005 | | - le32_to_cpu(tr.r4), le32_to_cpu(tr.r5), |
---|
3006 | | - le32_to_cpu(tr.r6), le32_to_cpu(tr.r7)); |
---|
3007 | | - |
---|
| 3041 | + if (seq) |
---|
| 3042 | + seq_printf(seq, |
---|
| 3043 | + "dongle trap info: type 0x%x @ epc 0x%08x\n" |
---|
| 3044 | + " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n" |
---|
| 3045 | + " lr 0x%08x pc 0x%08x offset 0x%x\n" |
---|
| 3046 | + " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n" |
---|
| 3047 | + " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n", |
---|
| 3048 | + le32_to_cpu(tr.type), le32_to_cpu(tr.epc), |
---|
| 3049 | + le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr), |
---|
| 3050 | + le32_to_cpu(tr.r13), le32_to_cpu(tr.r14), |
---|
| 3051 | + le32_to_cpu(tr.pc), sh->trap_addr, |
---|
| 3052 | + le32_to_cpu(tr.r0), le32_to_cpu(tr.r1), |
---|
| 3053 | + le32_to_cpu(tr.r2), le32_to_cpu(tr.r3), |
---|
| 3054 | + le32_to_cpu(tr.r4), le32_to_cpu(tr.r5), |
---|
| 3055 | + le32_to_cpu(tr.r6), le32_to_cpu(tr.r7)); |
---|
| 3056 | + else |
---|
| 3057 | + pr_debug("dongle trap info: type 0x%x @ epc 0x%08x\n" |
---|
| 3058 | + " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n" |
---|
| 3059 | + " lr 0x%08x pc 0x%08x offset 0x%x\n" |
---|
| 3060 | + " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n" |
---|
| 3061 | + " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n", |
---|
| 3062 | + le32_to_cpu(tr.type), le32_to_cpu(tr.epc), |
---|
| 3063 | + le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr), |
---|
| 3064 | + le32_to_cpu(tr.r13), le32_to_cpu(tr.r14), |
---|
| 3065 | + le32_to_cpu(tr.pc), sh->trap_addr, |
---|
| 3066 | + le32_to_cpu(tr.r0), le32_to_cpu(tr.r1), |
---|
| 3067 | + le32_to_cpu(tr.r2), le32_to_cpu(tr.r3), |
---|
| 3068 | + le32_to_cpu(tr.r4), le32_to_cpu(tr.r5), |
---|
| 3069 | + le32_to_cpu(tr.r6), le32_to_cpu(tr.r7)); |
---|
3008 | 3070 | return 0; |
---|
3009 | 3071 | } |
---|
3010 | 3072 | |
---|
.. | .. |
---|
3058 | 3120 | else if (sh.flags & SDPCM_SHARED_ASSERT) |
---|
3059 | 3121 | brcmf_err("assertion in dongle\n"); |
---|
3060 | 3122 | |
---|
3061 | | - if (sh.flags & SDPCM_SHARED_TRAP) |
---|
| 3123 | + if (sh.flags & SDPCM_SHARED_TRAP) { |
---|
3062 | 3124 | brcmf_err("firmware trap in dongle\n"); |
---|
| 3125 | + brcmf_sdio_trap_info(NULL, bus, &sh); |
---|
| 3126 | + } |
---|
3063 | 3127 | |
---|
3064 | 3128 | return 0; |
---|
3065 | 3129 | } |
---|
.. | .. |
---|
3337 | 3401 | /* Take arm out of reset */ |
---|
3338 | 3402 | if (!brcmf_chip_set_active(bus->ci, rstvec)) { |
---|
3339 | 3403 | brcmf_err("error getting out of ARM core reset\n"); |
---|
| 3404 | + bcmerror = -EIO; |
---|
3340 | 3405 | goto err; |
---|
3341 | 3406 | } |
---|
3342 | 3407 | |
---|
.. | .. |
---|
3346 | 3411 | return bcmerror; |
---|
3347 | 3412 | } |
---|
3348 | 3413 | |
---|
| 3414 | +static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus) |
---|
| 3415 | +{ |
---|
| 3416 | + if (bus->ci->chip == CY_CC_43012_CHIP_ID) |
---|
| 3417 | + return true; |
---|
| 3418 | + else |
---|
| 3419 | + return false; |
---|
| 3420 | +} |
---|
| 3421 | + |
---|
3349 | 3422 | static void brcmf_sdio_sr_init(struct brcmf_sdio *bus) |
---|
3350 | 3423 | { |
---|
3351 | 3424 | int err = 0; |
---|
3352 | 3425 | u8 val; |
---|
| 3426 | + u8 wakeupctrl; |
---|
| 3427 | + u8 cardcap; |
---|
| 3428 | + u8 chipclkcsr; |
---|
3353 | 3429 | |
---|
3354 | 3430 | brcmf_dbg(TRACE, "Enter\n"); |
---|
| 3431 | + |
---|
| 3432 | + if (brcmf_chip_is_ulp(bus->ci)) { |
---|
| 3433 | + wakeupctrl = SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT; |
---|
| 3434 | + chipclkcsr = SBSDIO_HT_AVAIL_REQ; |
---|
| 3435 | + } else { |
---|
| 3436 | + wakeupctrl = SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; |
---|
| 3437 | + chipclkcsr = SBSDIO_FORCE_HT; |
---|
| 3438 | + } |
---|
| 3439 | + |
---|
| 3440 | + if (brcmf_sdio_aos_no_decode(bus)) { |
---|
| 3441 | + cardcap = SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC; |
---|
| 3442 | + } else { |
---|
| 3443 | + cardcap = (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | |
---|
| 3444 | + SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT); |
---|
| 3445 | + } |
---|
3355 | 3446 | |
---|
3356 | 3447 | val = brcmf_sdiod_readb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, &err); |
---|
3357 | 3448 | if (err) { |
---|
3358 | 3449 | brcmf_err("error reading SBSDIO_FUNC1_WAKEUPCTRL\n"); |
---|
3359 | 3450 | return; |
---|
3360 | 3451 | } |
---|
3361 | | - |
---|
3362 | | - val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; |
---|
| 3452 | + val |= 1 << wakeupctrl; |
---|
3363 | 3453 | brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, val, &err); |
---|
3364 | 3454 | if (err) { |
---|
3365 | 3455 | brcmf_err("error writing SBSDIO_FUNC1_WAKEUPCTRL\n"); |
---|
.. | .. |
---|
3368 | 3458 | |
---|
3369 | 3459 | /* Add CMD14 Support */ |
---|
3370 | 3460 | brcmf_sdiod_func0_wb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP, |
---|
3371 | | - (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | |
---|
3372 | | - SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT), |
---|
| 3461 | + cardcap, |
---|
3373 | 3462 | &err); |
---|
3374 | 3463 | if (err) { |
---|
3375 | 3464 | brcmf_err("error writing SDIO_CCCR_BRCM_CARDCAP\n"); |
---|
.. | .. |
---|
3377 | 3466 | } |
---|
3378 | 3467 | |
---|
3379 | 3468 | brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, |
---|
3380 | | - SBSDIO_FORCE_HT, &err); |
---|
| 3469 | + chipclkcsr, &err); |
---|
3381 | 3470 | if (err) { |
---|
3382 | 3471 | brcmf_err("error writing SBSDIO_FUNC1_CHIPCLKCSR\n"); |
---|
3383 | 3472 | return; |
---|
.. | .. |
---|
3428 | 3517 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
---|
3429 | 3518 | struct brcmf_sdio *bus = sdiodev->bus; |
---|
3430 | 3519 | struct brcmf_core *core = bus->sdio_core; |
---|
3431 | | - uint pad_size; |
---|
3432 | 3520 | u32 value; |
---|
3433 | 3521 | int err; |
---|
3434 | 3522 | |
---|
.. | .. |
---|
3469 | 3557 | if (sdiodev->sg_support) { |
---|
3470 | 3558 | bus->txglom = false; |
---|
3471 | 3559 | value = 1; |
---|
3472 | | - pad_size = bus->sdiodev->func2->cur_blksize << 1; |
---|
3473 | 3560 | err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", |
---|
3474 | 3561 | &value, sizeof(u32)); |
---|
3475 | 3562 | if (err < 0) { |
---|
.. | .. |
---|
3539 | 3626 | } |
---|
3540 | 3627 | } |
---|
3541 | 3628 | |
---|
3542 | | -void brcmf_sdio_isr(struct brcmf_sdio *bus) |
---|
| 3629 | +void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr) |
---|
3543 | 3630 | { |
---|
3544 | 3631 | brcmf_dbg(TRACE, "Enter\n"); |
---|
3545 | 3632 | |
---|
.. | .. |
---|
3550 | 3637 | |
---|
3551 | 3638 | /* Count the interrupt call */ |
---|
3552 | 3639 | bus->sdcnt.intrcount++; |
---|
3553 | | - if (in_interrupt()) |
---|
| 3640 | + if (in_isr) |
---|
3554 | 3641 | atomic_set(&bus->ipend, 1); |
---|
3555 | 3642 | else |
---|
3556 | 3643 | if (brcmf_sdio_intr_rstatus(bus)) { |
---|
.. | .. |
---|
4047 | 4134 | return 0; |
---|
4048 | 4135 | } |
---|
4049 | 4136 | |
---|
| 4137 | +static int brcmf_sdio_bus_reset(struct device *dev) |
---|
| 4138 | +{ |
---|
| 4139 | + int ret = 0; |
---|
| 4140 | + struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
---|
| 4141 | + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
---|
| 4142 | + |
---|
| 4143 | + brcmf_dbg(SDIO, "Enter\n"); |
---|
| 4144 | + |
---|
| 4145 | + /* start by unregistering irqs */ |
---|
| 4146 | + brcmf_sdiod_intr_unregister(sdiodev); |
---|
| 4147 | + |
---|
| 4148 | + brcmf_sdiod_remove(sdiodev); |
---|
| 4149 | + |
---|
| 4150 | + /* reset the adapter */ |
---|
| 4151 | + sdio_claim_host(sdiodev->func1); |
---|
| 4152 | + mmc_hw_reset(sdiodev->func1->card->host); |
---|
| 4153 | + sdio_release_host(sdiodev->func1); |
---|
| 4154 | + |
---|
| 4155 | + brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN); |
---|
| 4156 | + |
---|
| 4157 | + ret = brcmf_sdiod_probe(sdiodev); |
---|
| 4158 | + if (ret) { |
---|
| 4159 | + brcmf_err("Failed to probe after sdio device reset: ret %d\n", |
---|
| 4160 | + ret); |
---|
| 4161 | + } |
---|
| 4162 | + |
---|
| 4163 | + return ret; |
---|
| 4164 | +} |
---|
| 4165 | + |
---|
4050 | 4166 | static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { |
---|
4051 | 4167 | .stop = brcmf_sdio_bus_stop, |
---|
4052 | 4168 | .preinit = brcmf_sdio_bus_preinit, |
---|
.. | .. |
---|
4058 | 4174 | .get_ramsize = brcmf_sdio_bus_get_ramsize, |
---|
4059 | 4175 | .get_memdump = brcmf_sdio_bus_get_memdump, |
---|
4060 | 4176 | .get_fwname = brcmf_sdio_get_fwname, |
---|
4061 | | - .debugfs_create = brcmf_sdio_debugfs_create |
---|
| 4177 | + .debugfs_create = brcmf_sdio_debugfs_create, |
---|
| 4178 | + .reset = brcmf_sdio_bus_reset |
---|
4062 | 4179 | }; |
---|
4063 | 4180 | |
---|
4064 | 4181 | #define BRCMF_SDIO_FW_CODE 0 |
---|
.. | .. |
---|
4074 | 4191 | const struct firmware *code; |
---|
4075 | 4192 | void *nvram; |
---|
4076 | 4193 | u32 nvram_len; |
---|
4077 | | - u8 saveclk; |
---|
| 4194 | + u8 saveclk, bpreq; |
---|
4078 | 4195 | u8 devctl; |
---|
4079 | 4196 | |
---|
4080 | 4197 | brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); |
---|
.. | .. |
---|
4108 | 4225 | /* Force clocks on backplane to be sure F2 interrupt propagates */ |
---|
4109 | 4226 | saveclk = brcmf_sdiod_readb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR, &err); |
---|
4110 | 4227 | if (!err) { |
---|
| 4228 | + bpreq = saveclk; |
---|
| 4229 | + bpreq |= brcmf_chip_is_ulp(bus->ci) ? |
---|
| 4230 | + SBSDIO_HT_AVAIL_REQ : SBSDIO_FORCE_HT; |
---|
4111 | 4231 | brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR, |
---|
4112 | | - (saveclk | SBSDIO_FORCE_HT), &err); |
---|
| 4232 | + bpreq, &err); |
---|
4113 | 4233 | } |
---|
4114 | 4234 | if (err) { |
---|
4115 | 4235 | brcmf_err("Failed to force clock for F2: err %d\n", err); |
---|
.. | .. |
---|
4132 | 4252 | bus->hostintmask, NULL); |
---|
4133 | 4253 | |
---|
4134 | 4254 | switch (sdiod->func1->device) { |
---|
4135 | | - case SDIO_DEVICE_ID_CYPRESS_4373: |
---|
| 4255 | + case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373: |
---|
4136 | 4256 | brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", |
---|
4137 | 4257 | CY_4373_F2_WATERMARK); |
---|
4138 | 4258 | brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, |
---|
.. | .. |
---|
4143 | 4263 | brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl, |
---|
4144 | 4264 | &err); |
---|
4145 | 4265 | brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, |
---|
4146 | | - CY_4373_F2_WATERMARK | |
---|
4147 | | - SBSDIO_MESBUSYCTRL_ENAB, &err); |
---|
| 4266 | + CY_4373_F1_MESBUSYCTRL, &err); |
---|
| 4267 | + break; |
---|
| 4268 | + case SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012: |
---|
| 4269 | + brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", |
---|
| 4270 | + CY_43012_F2_WATERMARK); |
---|
| 4271 | + brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, |
---|
| 4272 | + CY_43012_F2_WATERMARK, &err); |
---|
| 4273 | + devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL, |
---|
| 4274 | + &err); |
---|
| 4275 | + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; |
---|
| 4276 | + brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl, |
---|
| 4277 | + &err); |
---|
| 4278 | + brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, |
---|
| 4279 | + CY_43012_MESBUSYCTRL, &err); |
---|
| 4280 | + break; |
---|
| 4281 | + case SDIO_DEVICE_ID_BROADCOM_4329: |
---|
| 4282 | + case SDIO_DEVICE_ID_BROADCOM_4339: |
---|
| 4283 | + brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", |
---|
| 4284 | + CY_4339_F2_WATERMARK); |
---|
| 4285 | + brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, |
---|
| 4286 | + CY_4339_F2_WATERMARK, &err); |
---|
| 4287 | + devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL, |
---|
| 4288 | + &err); |
---|
| 4289 | + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; |
---|
| 4290 | + brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl, |
---|
| 4291 | + &err); |
---|
| 4292 | + brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, |
---|
| 4293 | + CY_4339_MESBUSYCTRL, &err); |
---|
| 4294 | + break; |
---|
| 4295 | + case SDIO_DEVICE_ID_BROADCOM_43455: |
---|
| 4296 | + brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", |
---|
| 4297 | + CY_43455_F2_WATERMARK); |
---|
| 4298 | + brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, |
---|
| 4299 | + CY_43455_F2_WATERMARK, &err); |
---|
| 4300 | + devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL, |
---|
| 4301 | + &err); |
---|
| 4302 | + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; |
---|
| 4303 | + brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl, |
---|
| 4304 | + &err); |
---|
| 4305 | + brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, |
---|
| 4306 | + CY_43455_MESBUSYCTRL, &err); |
---|
| 4307 | + break; |
---|
| 4308 | + case SDIO_DEVICE_ID_BROADCOM_4359: |
---|
| 4309 | + case SDIO_DEVICE_ID_BROADCOM_4354: |
---|
| 4310 | + case SDIO_DEVICE_ID_BROADCOM_4356: |
---|
| 4311 | + brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", |
---|
| 4312 | + CY_435X_F2_WATERMARK); |
---|
| 4313 | + brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, |
---|
| 4314 | + CY_435X_F2_WATERMARK, &err); |
---|
| 4315 | + devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL, |
---|
| 4316 | + &err); |
---|
| 4317 | + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; |
---|
| 4318 | + brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl, |
---|
| 4319 | + &err); |
---|
| 4320 | + brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, |
---|
| 4321 | + CY_435X_F1_MESBUSYCTRL, &err); |
---|
4148 | 4322 | break; |
---|
4149 | 4323 | default: |
---|
4150 | 4324 | brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, |
---|
.. | .. |
---|
4154 | 4328 | } else { |
---|
4155 | 4329 | /* Disable F2 again */ |
---|
4156 | 4330 | sdio_disable_func(sdiod->func2); |
---|
4157 | | - goto release; |
---|
| 4331 | + goto checkdied; |
---|
4158 | 4332 | } |
---|
4159 | 4333 | |
---|
4160 | 4334 | if (brcmf_chip_sr_capable(bus->ci)) { |
---|
.. | .. |
---|
4166 | 4340 | } |
---|
4167 | 4341 | |
---|
4168 | 4342 | if (err == 0) { |
---|
| 4343 | + /* Assign bus interface call back */ |
---|
| 4344 | + sdiod->bus_if->dev = sdiod->dev; |
---|
| 4345 | + sdiod->bus_if->ops = &brcmf_sdio_bus_ops; |
---|
| 4346 | + sdiod->bus_if->chip = bus->ci->chip; |
---|
| 4347 | + sdiod->bus_if->chiprev = bus->ci->chiprev; |
---|
| 4348 | + |
---|
4169 | 4349 | /* Allow full data communication using DPC from now on. */ |
---|
4170 | 4350 | brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA); |
---|
4171 | 4351 | |
---|
.. | .. |
---|
4175 | 4355 | } |
---|
4176 | 4356 | |
---|
4177 | 4357 | /* If we didn't come up, turn off backplane clock */ |
---|
4178 | | - if (err != 0) |
---|
| 4358 | + if (err != 0) { |
---|
4179 | 4359 | brcmf_sdio_clkctl(bus, CLK_NONE, false); |
---|
| 4360 | + goto checkdied; |
---|
| 4361 | + } |
---|
4180 | 4362 | |
---|
4181 | 4363 | sdio_release_host(sdiod->func1); |
---|
4182 | 4364 | |
---|
4183 | | - /* Assign bus interface call back */ |
---|
4184 | | - sdiod->bus_if->dev = sdiod->dev; |
---|
4185 | | - sdiod->bus_if->ops = &brcmf_sdio_bus_ops; |
---|
4186 | | - sdiod->bus_if->chip = bus->ci->chip; |
---|
4187 | | - sdiod->bus_if->chiprev = bus->ci->chiprev; |
---|
| 4365 | + err = brcmf_alloc(sdiod->dev, sdiod->settings); |
---|
| 4366 | + if (err) { |
---|
| 4367 | + brcmf_err("brcmf_alloc failed\n"); |
---|
| 4368 | + goto claim; |
---|
| 4369 | + } |
---|
4188 | 4370 | |
---|
4189 | 4371 | /* Attach to the common layer, reserve hdr space */ |
---|
4190 | | - err = brcmf_attach(sdiod->dev, sdiod->settings); |
---|
| 4372 | + err = brcmf_attach(sdiod->dev); |
---|
4191 | 4373 | if (err != 0) { |
---|
4192 | 4374 | brcmf_err("brcmf_attach failed\n"); |
---|
4193 | | - goto fail; |
---|
| 4375 | + goto free; |
---|
4194 | 4376 | } |
---|
4195 | 4377 | |
---|
4196 | 4378 | /* ready */ |
---|
4197 | 4379 | return; |
---|
4198 | 4380 | |
---|
| 4381 | +free: |
---|
| 4382 | + brcmf_free(sdiod->dev); |
---|
| 4383 | +claim: |
---|
| 4384 | + sdio_claim_host(sdiod->func1); |
---|
| 4385 | +checkdied: |
---|
| 4386 | + brcmf_sdio_checkdied(bus); |
---|
4199 | 4387 | release: |
---|
4200 | 4388 | sdio_release_host(sdiod->func1); |
---|
4201 | 4389 | fail: |
---|
.. | .. |
---|
4222 | 4410 | |
---|
4223 | 4411 | fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY; |
---|
4224 | 4412 | fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; |
---|
| 4413 | + fwreq->board_type = bus->sdiodev->settings->board_type; |
---|
4225 | 4414 | |
---|
4226 | 4415 | return fwreq; |
---|
4227 | 4416 | } |
---|
.. | .. |
---|
4352 | 4541 | brcmf_sdiod_intr_unregister(bus->sdiodev); |
---|
4353 | 4542 | |
---|
4354 | 4543 | brcmf_detach(bus->sdiodev->dev); |
---|
| 4544 | + brcmf_free(bus->sdiodev->dev); |
---|
4355 | 4545 | |
---|
4356 | 4546 | cancel_work_sync(&bus->datawork); |
---|
4357 | 4547 | if (bus->brcmf_wq) |
---|