| @@ -1,1509 +1,1508 @@ | | | @@ -1,1509 +1,1508 @@ |
1 | /* $NetBSD: if_bwfm_sdio.c,v 1.19 2020/06/23 10:09:33 martin Exp $ */ | | 1 | /* $NetBSD: if_bwfm_sdio.c,v 1.20 2020/07/20 06:44:55 mrg Exp $ */ |
2 | /* $OpenBSD: if_bwfm_sdio.c,v 1.1 2017/10/11 17:19:50 patrick Exp $ */ | | 2 | /* $OpenBSD: if_bwfm_sdio.c,v 1.1 2017/10/11 17:19:50 patrick Exp $ */ |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2010-2016 Broadcom Corporation | | 4 | * Copyright (c) 2010-2016 Broadcom Corporation |
5 | * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> | | 5 | * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and/or distribute this software for any | | 7 | * Permission to use, copy, modify, and/or distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ | | 18 | */ |
19 | | | 19 | |
20 | #include <sys/param.h> | | 20 | #include <sys/param.h> |
21 | #include <sys/systm.h> | | 21 | #include <sys/systm.h> |
22 | #include <sys/buf.h> | | 22 | #include <sys/buf.h> |
23 | #include <sys/endian.h> | | 23 | #include <sys/endian.h> |
24 | #include <sys/kernel.h> | | 24 | #include <sys/kernel.h> |
25 | #include <sys/malloc.h> | | 25 | #include <sys/malloc.h> |
26 | #include <sys/device.h> | | 26 | #include <sys/device.h> |
27 | #include <sys/queue.h> | | 27 | #include <sys/queue.h> |
28 | #include <sys/socket.h> | | 28 | #include <sys/socket.h> |
29 | #include <sys/mutex.h> | | 29 | #include <sys/mutex.h> |
30 | | | 30 | |
31 | #include <net/bpf.h> | | 31 | #include <net/bpf.h> |
32 | #include <net/if.h> | | 32 | #include <net/if.h> |
33 | #include <net/if_dl.h> | | 33 | #include <net/if_dl.h> |
34 | #include <net/if_media.h> | | 34 | #include <net/if_media.h> |
35 | #include <net/if_ether.h> | | 35 | #include <net/if_ether.h> |
36 | | | 36 | |
37 | #include <netinet/in.h> | | 37 | #include <netinet/in.h> |
38 | | | 38 | |
39 | #include <dev/ofw/openfirm.h> | | 39 | #include <dev/ofw/openfirm.h> |
40 | #include <dev/fdt/fdtvar.h> | | 40 | #include <dev/fdt/fdtvar.h> |
41 | | | 41 | |
42 | #include <net80211/ieee80211_var.h> | | 42 | #include <net80211/ieee80211_var.h> |
43 | | | 43 | |
44 | #include <dev/sdmmc/sdmmcdevs.h> | | 44 | #include <dev/sdmmc/sdmmcdevs.h> |
45 | #include <dev/sdmmc/sdmmcvar.h> | | 45 | #include <dev/sdmmc/sdmmcvar.h> |
46 | | | 46 | |
47 | #include <dev/ic/bwfmreg.h> | | 47 | #include <dev/ic/bwfmreg.h> |
48 | #include <dev/ic/bwfmvar.h> | | 48 | #include <dev/ic/bwfmvar.h> |
49 | #include <dev/sdmmc/if_bwfm_sdio.h> | | 49 | #include <dev/sdmmc/if_bwfm_sdio.h> |
50 | | | 50 | |
51 | #ifdef BWFM_DEBUG | | 51 | #ifdef BWFM_DEBUG |
52 | #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) | | 52 | #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) |
53 | #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) | | 53 | #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) |
54 | static int bwfm_debug = 2; | | 54 | static int bwfm_debug = 2; |
55 | #else | | 55 | #else |
56 | #define DPRINTF(x) do { ; } while (0) | | 56 | #define DPRINTF(x) do { ; } while (0) |
57 | #define DPRINTFN(n, x) do { ; } while (0) | | 57 | #define DPRINTFN(n, x) do { ; } while (0) |
58 | #endif | | 58 | #endif |
59 | | | 59 | |
60 | #define DEVNAME(sc) device_xname((sc)->sc_sc.sc_dev) | | 60 | #define DEVNAME(sc) device_xname((sc)->sc_sc.sc_dev) |
61 | | | 61 | |
62 | enum bwfm_sdio_clkstate { | | 62 | enum bwfm_sdio_clkstate { |
63 | CLK_NONE, | | 63 | CLK_NONE, |
64 | CLK_SDONLY, | | 64 | CLK_SDONLY, |
65 | CLK_PENDING, | | 65 | CLK_PENDING, |
66 | CLK_AVAIL | | 66 | CLK_AVAIL |
67 | }; | | 67 | }; |
68 | | | 68 | |
69 | struct bwfm_sdio_softc { | | 69 | struct bwfm_sdio_softc { |
70 | struct bwfm_softc sc_sc; | | 70 | struct bwfm_softc sc_sc; |
71 | kmutex_t sc_lock; | | 71 | kmutex_t sc_lock; |
72 | | | 72 | |
73 | bool sc_bwfm_attached; | | 73 | bool sc_bwfm_attached; |
74 | | | 74 | |
75 | struct sdmmc_function **sc_sf; | | 75 | struct sdmmc_function **sc_sf; |
76 | size_t sc_sf_size; | | 76 | size_t sc_sf_size; |
77 | | | 77 | |
78 | uint32_t sc_bar0; | | 78 | uint32_t sc_bar0; |
79 | enum bwfm_sdio_clkstate sc_clkstate; | | 79 | enum bwfm_sdio_clkstate sc_clkstate; |
80 | bool sc_sr_enabled; | | 80 | bool sc_sr_enabled; |
81 | bool sc_alp_only; | | 81 | bool sc_alp_only; |
82 | bool sc_sleeping; | | 82 | bool sc_sleeping; |
83 | bool sc_rxskip; | | 83 | bool sc_rxskip; |
84 | | | 84 | |
85 | struct sdmmc_task sc_task; | | 85 | struct sdmmc_task sc_task; |
86 | bool sc_task_queued; | | 86 | bool sc_task_queued; |
87 | | | 87 | |
88 | uint8_t sc_tx_seq; | | 88 | uint8_t sc_tx_seq; |
89 | uint8_t sc_tx_max_seq; | | 89 | uint8_t sc_tx_max_seq; |
90 | int sc_tx_count; | | 90 | int sc_tx_count; |
91 | MBUFQ_HEAD() sc_tx_queue; | | 91 | MBUFQ_HEAD() sc_tx_queue; |
92 | | | 92 | |
93 | struct mbuf *sc_rxctl_queue; | | 93 | struct mbuf *sc_rxctl_queue; |
94 | kcondvar_t sc_rxctl_cv; | | 94 | kcondvar_t sc_rxctl_cv; |
95 | | | 95 | |
96 | void *sc_ih; | | 96 | void *sc_ih; |
97 | struct bwfm_core *sc_cc; | | 97 | struct bwfm_core *sc_cc; |
98 | | | 98 | |
99 | char *sc_bounce_buf; | | 99 | char *sc_bounce_buf; |
100 | size_t sc_bounce_size; | | 100 | size_t sc_bounce_size; |
101 | | | 101 | |
102 | uint32_t sc_console_addr; | | 102 | uint32_t sc_console_addr; |
103 | char *sc_console_buf; | | 103 | char *sc_console_buf; |
104 | size_t sc_console_buf_size; | | 104 | size_t sc_console_buf_size; |
105 | uint32_t sc_console_readidx; | | 105 | uint32_t sc_console_readidx; |
106 | | | 106 | |
107 | int sc_phandle; | | 107 | int sc_phandle; |
108 | void *sc_fdtih; | | 108 | void *sc_fdtih; |
109 | }; | | 109 | }; |
110 | | | 110 | |
111 | static int bwfm_sdio_match(device_t, cfdata_t, void *); | | 111 | static int bwfm_sdio_match(device_t, cfdata_t, void *); |
112 | static void bwfm_sdio_attach(device_t, device_t, void *); | | 112 | static void bwfm_sdio_attach(device_t, device_t, void *); |
113 | static int bwfm_sdio_detach(device_t, int); | | 113 | static int bwfm_sdio_detach(device_t, int); |
114 | static void bwfm_sdio_attachhook(device_t); | | 114 | static void bwfm_sdio_attachhook(device_t); |
115 | static int bwfm_fdt_find_phandle(device_t, device_t); | | 115 | static int bwfm_fdt_find_phandle(device_t, device_t); |
116 | static const char *bwfm_fdt_get_model(void); | | 116 | static const char *bwfm_fdt_get_model(void); |
117 | | | 117 | |
118 | static void bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t); | | 118 | static void bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t); |
119 | static uint8_t bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t); | | 119 | static uint8_t bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t); |
120 | static uint32_t bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t); | | 120 | static uint32_t bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t); |
121 | static void bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t, | | 121 | static void bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t, |
122 | uint8_t); | | 122 | uint8_t); |
123 | static void bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t, | | 123 | static void bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t, |
124 | uint32_t); | | 124 | uint32_t); |
125 | | | 125 | |
126 | static uint32_t bwfm_sdio_dev_read(struct bwfm_sdio_softc *, uint32_t); | | 126 | static uint32_t bwfm_sdio_dev_read(struct bwfm_sdio_softc *, uint32_t); |
127 | static void bwfm_sdio_dev_write(struct bwfm_sdio_softc *, uint32_t, | | 127 | static void bwfm_sdio_dev_write(struct bwfm_sdio_softc *, uint32_t, |
128 | uint32_t); | | 128 | uint32_t); |
129 | | | 129 | |
130 | static uint32_t bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t); | | 130 | static uint32_t bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t); |
131 | static void bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t, | | 131 | static void bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t, |
132 | uint32_t); | | 132 | uint32_t); |
133 | static int bwfm_sdio_buscore_prepare(struct bwfm_softc *); | | 133 | static int bwfm_sdio_buscore_prepare(struct bwfm_softc *); |
134 | static void bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t); | | 134 | static void bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t); |
135 | | | 135 | |
136 | static int bwfm_sdio_buf_read(struct bwfm_sdio_softc *, | | 136 | static int bwfm_sdio_buf_read(struct bwfm_sdio_softc *, |
137 | struct sdmmc_function *, uint32_t, char *, size_t); | | 137 | struct sdmmc_function *, uint32_t, char *, size_t); |
138 | static int bwfm_sdio_buf_write(struct bwfm_sdio_softc *, | | 138 | static int bwfm_sdio_buf_write(struct bwfm_sdio_softc *, |
139 | struct sdmmc_function *, uint32_t, char *, size_t); | | 139 | struct sdmmc_function *, uint32_t, char *, size_t); |
140 | | | 140 | |
141 | static struct mbuf *bwfm_sdio_newbuf(void); | | 141 | static struct mbuf *bwfm_sdio_newbuf(void); |
142 | static void bwfm_qput(struct mbuf **, struct mbuf *); | | 142 | static void bwfm_qput(struct mbuf **, struct mbuf *); |
143 | static struct mbuf *bwfm_qget(struct mbuf **); | | 143 | static struct mbuf *bwfm_qget(struct mbuf **); |
144 | | | 144 | |
145 | static uint32_t bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *, | | 145 | static uint32_t bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *, |
146 | uint32_t, char *, size_t, int); | | 146 | uint32_t, char *, size_t, int); |
147 | static uint32_t bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *, | | 147 | static uint32_t bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *, |
148 | char *, size_t, int); | | 148 | char *, size_t, int); |
149 | | | 149 | |
150 | static int bwfm_sdio_intr1(void *, const char *); | | 150 | static int bwfm_sdio_intr1(void *, const char *); |
151 | static int bwfm_sdio_intr(void *); | | 151 | static int bwfm_sdio_intr(void *); |
152 | static void bwfm_sdio_task(void *); | | 152 | static void bwfm_sdio_task(void *); |
153 | static void bwfm_sdio_task1(struct bwfm_sdio_softc *); | | 153 | static void bwfm_sdio_task1(struct bwfm_sdio_softc *); |
154 | | | 154 | |
155 | static int bwfm_nvram_convert(u_char *, size_t, size_t *); | | 155 | static int bwfm_nvram_convert(u_char *, size_t, size_t *); |
156 | static int bwfm_sdio_load_microcode(struct bwfm_sdio_softc *, | | 156 | static int bwfm_sdio_load_microcode(struct bwfm_sdio_softc *, |
157 | u_char *, size_t, u_char *, size_t); | | 157 | u_char *, size_t, u_char *, size_t); |
158 | static void bwfm_sdio_clkctl(struct bwfm_sdio_softc *, | | 158 | static void bwfm_sdio_clkctl(struct bwfm_sdio_softc *, |
159 | enum bwfm_sdio_clkstate, bool); | | 159 | enum bwfm_sdio_clkstate, bool); |
160 | static void bwfm_sdio_htclk(struct bwfm_sdio_softc *, bool, bool); | | 160 | static void bwfm_sdio_htclk(struct bwfm_sdio_softc *, bool, bool); |
161 | | | 161 | |
162 | #ifdef notyet | | 162 | #ifdef notyet |
163 | static int bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *, bool, bool); | | 163 | static int bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *, bool, bool); |
164 | #endif | | 164 | #endif |
165 | static void bwfm_sdio_drivestrength(struct bwfm_sdio_softc *, unsigned); | | 165 | static void bwfm_sdio_drivestrength(struct bwfm_sdio_softc *, unsigned); |
166 | static void bwfm_sdio_readshared(struct bwfm_sdio_softc *); | | 166 | static void bwfm_sdio_readshared(struct bwfm_sdio_softc *); |
167 | | | 167 | |
168 | static int bwfm_sdio_txcheck(struct bwfm_softc *); | | 168 | static int bwfm_sdio_txcheck(struct bwfm_softc *); |
169 | static int bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf **); | | 169 | static int bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf **); |
170 | static int bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t); | | 170 | static int bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t); |
171 | static int bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *); | | 171 | static int bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *); |
172 | | | 172 | |
173 | static int bwfm_sdio_tx_ok(struct bwfm_sdio_softc *); | | 173 | static int bwfm_sdio_tx_ok(struct bwfm_sdio_softc *); |
174 | static void bwfm_sdio_tx_frames(struct bwfm_sdio_softc *); | | 174 | static void bwfm_sdio_tx_frames(struct bwfm_sdio_softc *); |
175 | static void bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *, | | 175 | static void bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *, |
176 | struct mbuf *); | | 176 | struct mbuf *); |
177 | static void bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *, | | 177 | static void bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *, |
178 | struct mbuf *); | | 178 | struct mbuf *); |
179 | | | 179 | |
180 | static void bwfm_sdio_rx_frames(struct bwfm_sdio_softc *); | | 180 | static void bwfm_sdio_rx_frames(struct bwfm_sdio_softc *); |
181 | static void bwfm_sdio_rx_glom(struct bwfm_sdio_softc *, | | 181 | static void bwfm_sdio_rx_glom(struct bwfm_sdio_softc *, |
182 | uint16_t *, int, uint16_t *); | | 182 | uint16_t *, int, uint16_t *); |
183 | | | 183 | |
184 | #ifdef BWFM_DEBUG | | 184 | #ifdef BWFM_DEBUG |
185 | static void bwfm_sdio_debug_console(struct bwfm_sdio_softc *); | | 185 | static void bwfm_sdio_debug_console(struct bwfm_sdio_softc *); |
186 | #endif | | 186 | #endif |
187 | | | 187 | |
188 | static const struct bwfm_firmware_selector bwfm_sdio_fwtab[] = { | | 188 | static const struct bwfm_firmware_selector bwfm_sdio_fwtab[] = { |
189 | BWFM_FW_ENTRY(BRCM_CC_43143_CHIP_ID, | | 189 | BWFM_FW_ENTRY(BRCM_CC_43143_CHIP_ID, |
190 | BWFM_FWSEL_ALLREVS, "brcmfmac43143-sdio"), | | 190 | BWFM_FWSEL_ALLREVS, "brcmfmac43143-sdio"), |
191 | | | 191 | |
192 | BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID, | | 192 | BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID, |
193 | BWFM_FWSEL_REV_LE(4), "brcmfmac43241b0-sdio"), | | 193 | BWFM_FWSEL_REV_LE(4), "brcmfmac43241b0-sdio"), |
194 | BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID, | | 194 | BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID, |
195 | BWFM_FWSEL_REV_EQ(5), "brcmfmac43241b4-sdio"), | | 195 | BWFM_FWSEL_REV_EQ(5), "brcmfmac43241b4-sdio"), |
196 | BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID, | | 196 | BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID, |
197 | BWFM_FWSEL_REV_GE(6), "brcmfmac43241b5-sdio"), | | 197 | BWFM_FWSEL_REV_GE(6), "brcmfmac43241b5-sdio"), |
198 | | | 198 | |
199 | BWFM_FW_ENTRY(BRCM_CC_4329_CHIP_ID, | | 199 | BWFM_FW_ENTRY(BRCM_CC_4329_CHIP_ID, |
200 | BWFM_FWSEL_ALLREVS, "brcmfmac4329-sdio"), | | 200 | BWFM_FWSEL_ALLREVS, "brcmfmac4329-sdio"), |
201 | | | 201 | |
202 | BWFM_FW_ENTRY(BRCM_CC_4330_CHIP_ID, | | 202 | BWFM_FW_ENTRY(BRCM_CC_4330_CHIP_ID, |
203 | BWFM_FWSEL_ALLREVS, "brcmfmac4330-sdio"), | | 203 | BWFM_FWSEL_ALLREVS, "brcmfmac4330-sdio"), |
204 | | | 204 | |
205 | BWFM_FW_ENTRY(BRCM_CC_4334_CHIP_ID, | | 205 | BWFM_FW_ENTRY(BRCM_CC_4334_CHIP_ID, |
206 | BWFM_FWSEL_ALLREVS, "brcmfmac4334-sdio"), | | 206 | BWFM_FWSEL_ALLREVS, "brcmfmac4334-sdio"), |
207 | | | 207 | |
208 | BWFM_FW_ENTRY(BRCM_CC_43340_CHIP_ID, | | 208 | BWFM_FW_ENTRY(BRCM_CC_43340_CHIP_ID, |
209 | BWFM_FWSEL_ALLREVS, "brcmfmac43340-sdio"), | | 209 | BWFM_FWSEL_ALLREVS, "brcmfmac43340-sdio"), |
210 | BWFM_FW_ENTRY(BRCM_CC_43341_CHIP_ID, | | 210 | BWFM_FW_ENTRY(BRCM_CC_43341_CHIP_ID, |
211 | BWFM_FWSEL_ALLREVS, "brcmfmac43340-sdio"), | | 211 | BWFM_FWSEL_ALLREVS, "brcmfmac43340-sdio"), |
212 | | | 212 | |
213 | BWFM_FW_ENTRY(BRCM_CC_4335_CHIP_ID, | | 213 | BWFM_FW_ENTRY(BRCM_CC_4335_CHIP_ID, |
214 | BWFM_FWSEL_ALLREVS, "brcmfmac4335-sdio"), | | 214 | BWFM_FWSEL_ALLREVS, "brcmfmac4335-sdio"), |
215 | | | 215 | |
216 | BWFM_FW_ENTRY(BRCM_CC_43362_CHIP_ID, | | 216 | BWFM_FW_ENTRY(BRCM_CC_43362_CHIP_ID, |
217 | BWFM_FWSEL_REV_GE(1), "brcmfmac43362-sdio"), | | 217 | BWFM_FWSEL_REV_GE(1), "brcmfmac43362-sdio"), |
218 | | | 218 | |
219 | BWFM_FW_ENTRY(BRCM_CC_4339_CHIP_ID, | | 219 | BWFM_FW_ENTRY(BRCM_CC_4339_CHIP_ID, |
220 | BWFM_FWSEL_ALLREVS, "brcmfmac4339-sdio"), | | 220 | BWFM_FWSEL_ALLREVS, "brcmfmac4339-sdio"), |
221 | | | 221 | |
222 | BWFM_FW_ENTRY(BRCM_CC_43430_CHIP_ID, | | 222 | BWFM_FW_ENTRY(BRCM_CC_43430_CHIP_ID, |
223 | BWFM_FWSEL_REV_EQ(0), "brcmfmac43430a0-sdio"), | | 223 | BWFM_FWSEL_REV_EQ(0), "brcmfmac43430a0-sdio"), |
224 | BWFM_FW_ENTRY(BRCM_CC_43430_CHIP_ID, | | 224 | BWFM_FW_ENTRY(BRCM_CC_43430_CHIP_ID, |
225 | BWFM_FWSEL_REV_GE(1), "brcmfmac43430-sdio"), | | 225 | BWFM_FWSEL_REV_GE(1), "brcmfmac43430-sdio"), |
226 | | | 226 | |
227 | BWFM_FW_ENTRY(BRCM_CC_4345_CHIP_ID, | | 227 | BWFM_FW_ENTRY(BRCM_CC_4345_CHIP_ID, |
228 | BWFM_FWSEL_REV_EQ(9), "brcmfmac43456-sdio"), | | 228 | BWFM_FWSEL_REV_EQ(9), "brcmfmac43456-sdio"), |
229 | BWFM_FW_ENTRY(BRCM_CC_4345_CHIP_ID, | | 229 | BWFM_FW_ENTRY(BRCM_CC_4345_CHIP_ID, |
230 | BWFM_FWSEL_REV_LE(8) + BWFM_FWSEL_REV_GE(10), | | 230 | BWFM_FWSEL_REV_LE(8) + BWFM_FWSEL_REV_GE(10), |
231 | "brcmfmac43455-sdio"), | | 231 | "brcmfmac43455-sdio"), |
232 | | | 232 | |
233 | BWFM_FW_ENTRY(BRCM_CC_4354_CHIP_ID, | | 233 | BWFM_FW_ENTRY(BRCM_CC_4354_CHIP_ID, |
234 | BWFM_FWSEL_ALLREVS, "brcmfmac4354-sdio"), | | 234 | BWFM_FWSEL_ALLREVS, "brcmfmac4354-sdio"), |
235 | | | 235 | |
236 | BWFM_FW_ENTRY(BRCM_CC_4356_CHIP_ID, | | 236 | BWFM_FW_ENTRY(BRCM_CC_4356_CHIP_ID, |
237 | BWFM_FWSEL_ALLREVS, "brcmfmac4356-sdio"), | | 237 | BWFM_FWSEL_ALLREVS, "brcmfmac4356-sdio"), |
238 | | | 238 | |
239 | BWFM_FW_ENTRY(CY_CC_4373_CHIP_ID, | | 239 | BWFM_FW_ENTRY(CY_CC_4373_CHIP_ID, |
240 | BWFM_FWSEL_ALLREVS, "brcmfmac4373-sdio"), | | 240 | BWFM_FWSEL_ALLREVS, "brcmfmac4373-sdio"), |
241 | | | 241 | |
242 | BWFM_FW_ENTRY(CY_CC_43012_CHIP_ID, | | 242 | BWFM_FW_ENTRY(CY_CC_43012_CHIP_ID, |
243 | BWFM_FWSEL_ALLREVS, "brcmfmac43012-sdio"), | | 243 | BWFM_FWSEL_ALLREVS, "brcmfmac43012-sdio"), |
244 | | | 244 | |
245 | BWFM_FW_ENTRY_END | | 245 | BWFM_FW_ENTRY_END |
246 | }; | | 246 | }; |
247 | | | 247 | |
248 | static const struct bwfm_bus_ops bwfm_sdio_bus_ops = { | | 248 | static const struct bwfm_bus_ops bwfm_sdio_bus_ops = { |
249 | .bs_init = NULL, | | 249 | .bs_init = NULL, |
250 | .bs_stop = NULL, | | 250 | .bs_stop = NULL, |
251 | .bs_txcheck = bwfm_sdio_txcheck, | | 251 | .bs_txcheck = bwfm_sdio_txcheck, |
252 | .bs_txdata = bwfm_sdio_txdata, | | 252 | .bs_txdata = bwfm_sdio_txdata, |
253 | .bs_txctl = bwfm_sdio_txctl, | | 253 | .bs_txctl = bwfm_sdio_txctl, |
254 | .bs_rxctl = bwfm_sdio_rxctl, | | 254 | .bs_rxctl = bwfm_sdio_rxctl, |
255 | }; | | 255 | }; |
256 | | | 256 | |
257 | static const struct bwfm_buscore_ops bwfm_sdio_buscore_ops = { | | 257 | static const struct bwfm_buscore_ops bwfm_sdio_buscore_ops = { |
258 | .bc_read = bwfm_sdio_buscore_read, | | 258 | .bc_read = bwfm_sdio_buscore_read, |
259 | .bc_write = bwfm_sdio_buscore_write, | | 259 | .bc_write = bwfm_sdio_buscore_write, |
260 | .bc_prepare = bwfm_sdio_buscore_prepare, | | 260 | .bc_prepare = bwfm_sdio_buscore_prepare, |
261 | .bc_reset = NULL, | | 261 | .bc_reset = NULL, |
262 | .bc_setup = NULL, | | 262 | .bc_setup = NULL, |
263 | .bc_activate = bwfm_sdio_buscore_activate, | | 263 | .bc_activate = bwfm_sdio_buscore_activate, |
264 | }; | | 264 | }; |
265 | | | 265 | |
266 | CFATTACH_DECL_NEW(bwfm_sdio, sizeof(struct bwfm_sdio_softc), | | 266 | CFATTACH_DECL_NEW(bwfm_sdio, sizeof(struct bwfm_sdio_softc), |
267 | bwfm_sdio_match, bwfm_sdio_attach, bwfm_sdio_detach, NULL); | | 267 | bwfm_sdio_match, bwfm_sdio_attach, bwfm_sdio_detach, NULL); |
268 | | | 268 | |
269 | static const struct bwfm_sdio_product { | | 269 | static const struct bwfm_sdio_product { |
270 | uint32_t manufacturer; | | 270 | uint32_t manufacturer; |
271 | uint32_t product; | | 271 | uint32_t product; |
272 | const char *cisinfo[4]; | | 272 | const char *cisinfo[4]; |
273 | } bwfm_sdio_products[] = { | | 273 | } bwfm_sdio_products[] = { |
274 | { | | 274 | { |
275 | SDMMC_VENDOR_BROADCOM, | | 275 | SDMMC_VENDOR_BROADCOM, |
276 | SDMMC_PRODUCT_BROADCOM_BCM4330, | | 276 | SDMMC_PRODUCT_BROADCOM_BCM4330, |
277 | SDMMC_CIS_BROADCOM_BCM4330 | | 277 | SDMMC_CIS_BROADCOM_BCM4330 |
278 | }, | | 278 | }, |
279 | { | | 279 | { |
280 | SDMMC_VENDOR_BROADCOM, | | 280 | SDMMC_VENDOR_BROADCOM, |
281 | SDMMC_PRODUCT_BROADCOM_BCM4334, | | 281 | SDMMC_PRODUCT_BROADCOM_BCM4334, |
282 | SDMMC_CIS_BROADCOM_BCM4334 | | 282 | SDMMC_CIS_BROADCOM_BCM4334 |
283 | }, | | 283 | }, |
284 | { | | 284 | { |
285 | SDMMC_VENDOR_BROADCOM, | | 285 | SDMMC_VENDOR_BROADCOM, |
286 | SDMMC_PRODUCT_BROADCOM_BCM43143, | | 286 | SDMMC_PRODUCT_BROADCOM_BCM43143, |
287 | SDMMC_CIS_BROADCOM_BCM43143 | | 287 | SDMMC_CIS_BROADCOM_BCM43143 |
288 | }, | | 288 | }, |
289 | { | | 289 | { |
290 | SDMMC_VENDOR_BROADCOM, | | 290 | SDMMC_VENDOR_BROADCOM, |
291 | SDMMC_PRODUCT_BROADCOM_BCM43430, | | 291 | SDMMC_PRODUCT_BROADCOM_BCM43430, |
292 | SDMMC_CIS_BROADCOM_BCM43430 | | 292 | SDMMC_CIS_BROADCOM_BCM43430 |
293 | }, | | 293 | }, |
294 | { | | 294 | { |
295 | SDMMC_VENDOR_BROADCOM, | | 295 | SDMMC_VENDOR_BROADCOM, |
296 | SDMMC_PRODUCT_BROADCOM_BCM43455, | | 296 | SDMMC_PRODUCT_BROADCOM_BCM43455, |
297 | SDMMC_CIS_BROADCOM_BCM43455 | | 297 | SDMMC_CIS_BROADCOM_BCM43455 |
298 | }, | | 298 | }, |
299 | { | | 299 | { |
300 | SDMMC_VENDOR_BROADCOM, | | 300 | SDMMC_VENDOR_BROADCOM, |
301 | SDMMC_PRODUCT_BROADCOM_BCM43362, | | 301 | SDMMC_PRODUCT_BROADCOM_BCM43362, |
302 | SDMMC_CIS_BROADCOM_BCM43362 | | 302 | SDMMC_CIS_BROADCOM_BCM43362 |
303 | }, | | 303 | }, |
304 | }; | | 304 | }; |
305 | | | 305 | |
306 | static const char * const compatible[] = { | | 306 | static const char * const compatible[] = { |
307 | "brcm,bcm4329-fmac", | | 307 | "brcm,bcm4329-fmac", |
308 | NULL | | 308 | NULL |
309 | }; | | 309 | }; |
310 | | | 310 | |
311 | static int | | 311 | static int |
312 | bwfm_sdio_match(device_t parent, cfdata_t match, void *aux) | | 312 | bwfm_sdio_match(device_t parent, cfdata_t match, void *aux) |
313 | { | | 313 | { |
314 | struct sdmmc_attach_args *saa = aux; | | 314 | struct sdmmc_attach_args *saa = aux; |
315 | struct sdmmc_function *sf = saa->sf; | | 315 | struct sdmmc_function *sf = saa->sf; |
316 | struct sdmmc_cis *cis; | | 316 | struct sdmmc_cis *cis; |
317 | const struct bwfm_sdio_product *bsp; | | 317 | const struct bwfm_sdio_product *bsp; |
318 | int i; | | 318 | int i; |
319 | | | 319 | |
320 | /* Not SDIO. */ | | 320 | /* Not SDIO. */ |
321 | if (sf == NULL) | | 321 | if (sf == NULL) |
322 | return 0; | | 322 | return 0; |
323 | | | 323 | |
324 | cis = &sf->sc->sc_fn0->cis; | | 324 | cis = &sf->sc->sc_fn0->cis; |
325 | for (i = 0; i < __arraycount(bwfm_sdio_products); ++i) { | | 325 | for (i = 0; i < __arraycount(bwfm_sdio_products); ++i) { |
326 | bsp = &bwfm_sdio_products[i]; | | 326 | bsp = &bwfm_sdio_products[i]; |
327 | if (cis->manufacturer == bsp->manufacturer && | | 327 | if (cis->manufacturer == bsp->manufacturer && |
328 | cis->product == bsp->product) | | 328 | cis->product == bsp->product) |
329 | break; | | 329 | break; |
330 | } | | 330 | } |
331 | if (i >= __arraycount(bwfm_sdio_products)) | | 331 | if (i >= __arraycount(bwfm_sdio_products)) |
332 | return 0; | | 332 | return 0; |
333 | | | 333 | |
334 | /* We need both functions, but ... */ | | 334 | /* We need both functions, but ... */ |
335 | if (sf->sc->sc_function_count <= 1) | | 335 | if (sf->sc->sc_function_count <= 1) |
336 | return 0; | | 336 | return 0; |
337 | | | 337 | |
338 | /* ... only attach for one. */ | | 338 | /* ... only attach for one. */ |
339 | if (sf->number != 1) | | 339 | if (sf->number != 1) |
340 | return 0; | | 340 | return 0; |
341 | | | 341 | |
342 | return 1; | | 342 | return 1; |
343 | } | | 343 | } |
344 | | | 344 | |
345 | static void | | 345 | static void |
346 | bwfm_sdio_attach(device_t parent, device_t self, void *aux) | | 346 | bwfm_sdio_attach(device_t parent, device_t self, void *aux) |
347 | { | | 347 | { |
348 | struct bwfm_sdio_softc *sc = device_private(self); | | 348 | struct bwfm_sdio_softc *sc = device_private(self); |
349 | struct sdmmc_attach_args *saa = aux; | | 349 | struct sdmmc_attach_args *saa = aux; |
350 | struct sdmmc_function *sf = saa->sf; | | 350 | struct sdmmc_function *sf = saa->sf; |
351 | struct bwfm_core *core; | | 351 | struct bwfm_core *core; |
352 | uint32_t reg; | | 352 | uint32_t reg; |
353 | | | 353 | |
354 | sc->sc_sc.sc_dev = self; | | 354 | sc->sc_sc.sc_dev = self; |
355 | | | 355 | |
356 | aprint_naive("\n"); | | 356 | aprint_naive("\n"); |
357 | aprint_normal("\n"); | | 357 | aprint_normal("\n"); |
358 | | | 358 | |
359 | sc->sc_phandle = bwfm_fdt_find_phandle(self, parent); | | 359 | sc->sc_phandle = bwfm_fdt_find_phandle(self, parent); |
360 | | | 360 | |
361 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); | | 361 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); |
362 | cv_init(&sc->sc_rxctl_cv, "bwfmctl"); | | 362 | cv_init(&sc->sc_rxctl_cv, "bwfmctl"); |
363 | | | 363 | |
364 | sdmmc_init_task(&sc->sc_task, bwfm_sdio_task, sc); | | 364 | sdmmc_init_task(&sc->sc_task, bwfm_sdio_task, sc); |
365 | | | 365 | |
366 | sc->sc_bounce_size = 64 * 1024; | | 366 | sc->sc_bounce_size = 64 * 1024; |
367 | sc->sc_bounce_buf = kmem_alloc(sc->sc_bounce_size, KM_SLEEP); | | 367 | sc->sc_bounce_buf = kmem_alloc(sc->sc_bounce_size, KM_SLEEP); |
368 | sc->sc_tx_seq = 0xff; | | 368 | sc->sc_tx_seq = 0xff; |
369 | MBUFQ_INIT(&sc->sc_tx_queue); | | 369 | MBUFQ_INIT(&sc->sc_tx_queue); |
370 | sc->sc_rxctl_queue = NULL; | | 370 | sc->sc_rxctl_queue = NULL; |
371 | | | 371 | |
372 | sc->sc_sf_size = (sf->sc->sc_function_count + 1) | | 372 | sc->sc_sf_size = (sf->sc->sc_function_count + 1) |
373 | * sizeof(struct sdmmc_function *); | | 373 | * sizeof(struct sdmmc_function *); |
374 | sc->sc_sf = kmem_zalloc(sc->sc_sf_size, KM_SLEEP); | | 374 | sc->sc_sf = kmem_zalloc(sc->sc_sf_size, KM_SLEEP); |
375 | | | 375 | |
376 | /* Copy all function pointers. */ | | 376 | /* Copy all function pointers. */ |
377 | SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) { | | 377 | SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) { |
378 | sc->sc_sf[sf->number] = sf; | | 378 | sc->sc_sf[sf->number] = sf; |
379 | } | | 379 | } |
380 | | | 380 | |
381 | sdmmc_io_set_blocklen(sc->sc_sf[1], 64); | | 381 | sdmmc_io_set_blocklen(sc->sc_sf[1], 64); |
382 | sdmmc_io_set_blocklen(sc->sc_sf[2], 512); | | 382 | sdmmc_io_set_blocklen(sc->sc_sf[2], 512); |
383 | | | 383 | |
384 | /* Enable Function 1. */ | | 384 | /* Enable Function 1. */ |
385 | if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) { | | 385 | if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) { |
386 | printf("%s: cannot enable function 1\n", DEVNAME(sc)); | | 386 | printf("%s: cannot enable function 1\n", DEVNAME(sc)); |
387 | return; | | 387 | return; |
388 | } | | 388 | } |
389 | | | 389 | |
390 | DPRINTF(("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc), | | 390 | DPRINTF(("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc), |
391 | bwfm_sdio_read_4(sc, 0x18000000))); | | 391 | bwfm_sdio_read_4(sc, 0x18000000))); |
392 | | | 392 | |
393 | /* Force PLL off */ | | 393 | /* Force PLL off */ |
394 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, | | 394 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, |
395 | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | | | 395 | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | |
396 | BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ); | | 396 | BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ); |
397 | | | 397 | |
398 | sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops; | | 398 | sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops; |
399 | if (bwfm_chip_attach(&sc->sc_sc) != 0) { | | 399 | if (bwfm_chip_attach(&sc->sc_sc) != 0) { |
400 | aprint_error_dev(self, "cannot attach chip\n"); | | 400 | aprint_error_dev(self, "cannot attach chip\n"); |
401 | return; | | 401 | return; |
402 | } | | 402 | } |
403 | | | 403 | |
404 | sc->sc_cc = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_CHIPCOMMON); | | 404 | sc->sc_cc = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_CHIPCOMMON); |
405 | if (sc->sc_cc == NULL) { | | 405 | if (sc->sc_cc == NULL) { |
406 | aprint_error_dev(self, "cannot find chipcommon core\n"); | | 406 | aprint_error_dev(self, "cannot find chipcommon core\n"); |
407 | return; | | 407 | return; |
408 | } | | 408 | } |
409 | | | 409 | |
410 | core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); | | 410 | core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); |
411 | if (core->co_rev >= 12) { | | 411 | if (core->co_rev >= 12) { |
412 | reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR); | | 412 | reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR); |
413 | if ((reg & BWFM_SDIO_FUNC1_SLEEPCSR_KSO) == 0) { | | 413 | if ((reg & BWFM_SDIO_FUNC1_SLEEPCSR_KSO) == 0) { |
414 | reg |= BWFM_SDIO_FUNC1_SLEEPCSR_KSO; | | 414 | reg |= BWFM_SDIO_FUNC1_SLEEPCSR_KSO; |
415 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR, reg); | | 415 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR, reg); |
416 | } | | 416 | } |
417 | } | | 417 | } |
418 | | | 418 | |
419 | /* Default, override from "brcm,drive-strength" */ | | 419 | /* Default, override from "brcm,drive-strength" */ |
420 | bwfm_sdio_drivestrength(sc, 6); | | 420 | bwfm_sdio_drivestrength(sc, 6); |
421 | | | 421 | |
422 | bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCTRL, | | 422 | bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCTRL, |
423 | bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_CARDCTRL) | | | 423 | bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_CARDCTRL) | |
424 | BWFM_SDIO_CCCR_CARDCTRL_WLANRESET); | | 424 | BWFM_SDIO_CCCR_CARDCTRL_WLANRESET); |
425 | | | 425 | |
426 | core = bwfm_chip_get_pmu(&sc->sc_sc); | | 426 | core = bwfm_chip_get_pmu(&sc->sc_sc); |
427 | bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL, | | 427 | bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL, |
428 | bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL) | | | 428 | bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL) | |
429 | (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD << | | 429 | (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD << |
430 | BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT)); | | 430 | BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT)); |
431 | | | 431 | |
432 | sdmmc_io_function_disable(sc->sc_sf[2]); | | 432 | sdmmc_io_function_disable(sc->sc_sf[2]); |
433 | | | 433 | |
434 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0); | | 434 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0); |
435 | sc->sc_clkstate = CLK_SDONLY; | | 435 | sc->sc_clkstate = CLK_SDONLY; |
436 | | | 436 | |
437 | config_mountroot(self, bwfm_sdio_attachhook); | | 437 | config_mountroot(self, bwfm_sdio_attachhook); |
438 | } | | 438 | } |
439 | | | 439 | |
440 | static void | | 440 | static void |
441 | bwfm_sdio_attachhook(device_t self) | | 441 | bwfm_sdio_attachhook(device_t self) |
442 | { | | 442 | { |
443 | struct bwfm_sdio_softc *sc = device_private(self); | | 443 | struct bwfm_sdio_softc *sc = device_private(self); |
444 | struct bwfm_softc *bwfm = &sc->sc_sc; | | 444 | struct bwfm_softc *bwfm = &sc->sc_sc; |
445 | struct bwfm_firmware_context fwctx; | | 445 | struct bwfm_firmware_context fwctx; |
446 | size_t ucsize = 0, nvlen = 0, nvsize = 0; | | 446 | size_t ucsize = 0, nvlen = 0, nvsize = 0; |
447 | uint8_t *ucode, *nvram; | | 447 | uint8_t *ucode, *nvram; |
448 | uint32_t reg, clk; | | 448 | uint32_t reg, clk; |
449 | | | 449 | |
450 | DPRINTF(("%s: chip 0x%08x rev %u\n", DEVNAME(sc), | | 450 | DPRINTF(("%s: chip 0x%08x rev %u\n", DEVNAME(sc), |
451 | bwfm->sc_chip.ch_chip, bwfm->sc_chip.ch_chiprev)); | | 451 | bwfm->sc_chip.ch_chip, bwfm->sc_chip.ch_chiprev)); |
452 | | | 452 | |
453 | /* | | 453 | /* |
454 | * 4335s >= rev 2 are considered 4339s. | | 454 | * 4335s >= rev 2 are considered 4339s. |
455 | */ | | 455 | */ |
456 | if (bwfm->sc_chip.ch_chip == BRCM_CC_4335_CHIP_ID && | | 456 | if (bwfm->sc_chip.ch_chip == BRCM_CC_4335_CHIP_ID && |
457 | bwfm->sc_chip.ch_chiprev >= 2) | | 457 | bwfm->sc_chip.ch_chiprev >= 2) |
458 | bwfm->sc_chip.ch_chip = BRCM_CC_4339_CHIP_ID; | | 458 | bwfm->sc_chip.ch_chip = BRCM_CC_4339_CHIP_ID; |
459 | | | 459 | |
460 | bwfm_firmware_context_init(&fwctx, | | 460 | bwfm_firmware_context_init(&fwctx, |
461 | bwfm->sc_chip.ch_chip, bwfm->sc_chip.ch_chiprev, | | 461 | bwfm->sc_chip.ch_chip, bwfm->sc_chip.ch_chiprev, |
462 | bwfm_fdt_get_model(), | | 462 | bwfm_fdt_get_model(), |
463 | BWFM_FWREQ(BWFM_FILETYPE_UCODE) | BWFM_FWREQ(BWFM_FILETYPE_NVRAM)); | | 463 | BWFM_FWREQ(BWFM_FILETYPE_UCODE) | BWFM_FWREQ(BWFM_FILETYPE_NVRAM)); |
464 | | | 464 | |
465 | if (!bwfm_firmware_open(bwfm, bwfm_sdio_fwtab, &fwctx)) { | | 465 | if (!bwfm_firmware_open(bwfm, bwfm_sdio_fwtab, &fwctx)) { |
466 | /* Error message already displayed. */ | | 466 | /* Error message already displayed. */ |
467 | goto err; | | 467 | goto err; |
468 | } | | 468 | } |
469 | | | 469 | |
470 | ucode = bwfm_firmware_data(&fwctx, BWFM_FILETYPE_UCODE, &ucsize); | | 470 | ucode = bwfm_firmware_data(&fwctx, BWFM_FILETYPE_UCODE, &ucsize); |
471 | KASSERT(ucode != NULL); | | 471 | KASSERT(ucode != NULL); |
472 | nvram = bwfm_firmware_data(&fwctx, BWFM_FILETYPE_NVRAM, &nvlen); | | 472 | nvram = bwfm_firmware_data(&fwctx, BWFM_FILETYPE_NVRAM, &nvlen); |
473 | KASSERT(nvram != NULL); | | 473 | KASSERT(nvram != NULL); |
474 | | | 474 | |
475 | if (bwfm_nvram_convert(nvram, nvlen, &nvsize)) { | | 475 | if (bwfm_nvram_convert(nvram, nvlen, &nvsize)) { |
476 | aprint_error_dev(bwfm->sc_dev, | | 476 | aprint_error_dev(bwfm->sc_dev, |
477 | "unable to convert %s file\n", | | 477 | "unable to convert %s file\n", |
478 | bwfm_firmware_description(BWFM_FILETYPE_NVRAM)); | | 478 | bwfm_firmware_description(BWFM_FILETYPE_NVRAM)); |
479 | goto err; | | 479 | goto err; |
480 | } | | 480 | } |
481 | | | 481 | |
482 | sc->sc_alp_only = true; | | 482 | sc->sc_alp_only = true; |
483 | if (bwfm_sdio_load_microcode(sc, ucode, ucsize, nvram, nvsize) != 0) { | | 483 | if (bwfm_sdio_load_microcode(sc, ucode, ucsize, nvram, nvsize) != 0) { |
484 | aprint_error_dev(bwfm->sc_dev, "could not load microcode\n"); | | 484 | aprint_error_dev(bwfm->sc_dev, "could not load microcode\n"); |
485 | goto err; | | 485 | goto err; |
486 | } | | 486 | } |
487 | sc->sc_alp_only = false; | | 487 | sc->sc_alp_only = false; |
488 | | | 488 | |
489 | sdmmc_pause(hztoms(1)*1000, NULL); | | 489 | sdmmc_pause(hztoms(1)*1000, NULL); |
490 | | | 490 | |
491 | bwfm_sdio_clkctl(sc, CLK_AVAIL, false); | | 491 | bwfm_sdio_clkctl(sc, CLK_AVAIL, false); |
492 | if (sc->sc_clkstate != CLK_AVAIL) { | | 492 | if (sc->sc_clkstate != CLK_AVAIL) { |
493 | aprint_error_dev(bwfm->sc_dev, "could not access clock\n"); | | 493 | aprint_error_dev(bwfm->sc_dev, "could not access clock\n"); |
494 | goto err; | | 494 | goto err; |
495 | } | | 495 | } |
496 | | | 496 | |
497 | clk = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); | | 497 | clk = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); |
498 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, | | 498 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, |
499 | clk | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT); | | 499 | clk | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT); |
500 | | | 500 | |
501 | bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOXDATA, | | 501 | bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOXDATA, |
502 | SDPCM_PROT_VERSION << SDPCM_PROT_VERSION_SHIFT); | | 502 | SDPCM_PROT_VERSION << SDPCM_PROT_VERSION_SHIFT); |
503 | if (sdmmc_io_function_enable(sc->sc_sf[2])) { | | 503 | if (sdmmc_io_function_enable(sc->sc_sf[2])) { |
504 | aprint_error_dev(bwfm->sc_dev, "cannot enable function 2\n"); | | 504 | aprint_error_dev(bwfm->sc_dev, "cannot enable function 2\n"); |
505 | goto err; | | 505 | goto err; |
506 | } | | 506 | } |
507 | | | 507 | |
508 | // bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK, | | 508 | bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK, |
509 | // SDPCMD_INTSTATUS_HMB_SW_MASK | SDPCMD_INTSTATUS_CHIPACTIVE); | | 509 | SDPCMD_INTSTATUS_HMB_SW_MASK | SDPCMD_INTSTATUS_CHIPACTIVE); |
510 | bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK, 0xffffffff); | | | |
511 | bwfm_sdio_write_1(sc, BWFM_SDIO_WATERMARK, 8); | | 510 | bwfm_sdio_write_1(sc, BWFM_SDIO_WATERMARK, 8); |
512 | | | 511 | |
513 | if (bwfm_chip_sr_capable(bwfm)) { | | 512 | if (bwfm_chip_sr_capable(bwfm)) { |
514 | reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL); | | 513 | reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL); |
515 | reg |= BWFM_SDIO_FUNC1_WAKEUPCTRL_HTWAIT; | | 514 | reg |= BWFM_SDIO_FUNC1_WAKEUPCTRL_HTWAIT; |
516 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL, reg); | | 515 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL, reg); |
517 | bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCAP, | | 516 | bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCAP, |
518 | BWFM_SDIO_CCCR_CARDCAP_CMD14_SUPPORT | | | 517 | BWFM_SDIO_CCCR_CARDCAP_CMD14_SUPPORT | |
519 | BWFM_SDIO_CCCR_CARDCAP_CMD14_EXT); | | 518 | BWFM_SDIO_CCCR_CARDCAP_CMD14_EXT); |
520 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, | | 519 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, |
521 | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT); | | 520 | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT); |
522 | sc->sc_sr_enabled = 1; | | 521 | sc->sc_sr_enabled = 1; |
523 | } else { | | 522 | } else { |
524 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clk); | | 523 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clk); |
525 | } | | 524 | } |
526 | | | 525 | |
527 | #ifdef notyet | | 526 | #ifdef notyet |
528 | if (sc->sc_phandle >= 0) { | | 527 | if (sc->sc_phandle >= 0) { |
529 | sc->sc_fdtih = fdtbus_intr_establish(sc->sc_phandle, | | 528 | sc->sc_fdtih = fdtbus_intr_establish(sc->sc_phandle, |
530 | 0, IPL_SDMMC, IST_LEVEL, bwfm_sdio_intr, sc); | | 529 | 0, IPL_SDMMC, IST_LEVEL, bwfm_sdio_intr, sc); |
531 | } | | 530 | } |
532 | #endif | | 531 | #endif |
533 | if (sc->sc_fdtih != NULL) { | | 532 | if (sc->sc_fdtih != NULL) { |
534 | aprint_normal_dev(self, "enabling GPIO interrupt\n"); | | 533 | aprint_normal_dev(self, "enabling GPIO interrupt\n"); |
535 | } else { | | 534 | } else { |
536 | sc->sc_ih = sdmmc_intr_establish(device_parent(self), | | 535 | sc->sc_ih = sdmmc_intr_establish(device_parent(self), |
537 | bwfm_sdio_intr, sc, DEVNAME(sc)); | | 536 | bwfm_sdio_intr, sc, DEVNAME(sc)); |
538 | } | | 537 | } |
539 | | | 538 | |
540 | if (sc->sc_ih == NULL && sc->sc_fdtih == NULL) { | | 539 | if (sc->sc_ih == NULL && sc->sc_fdtih == NULL) { |
541 | aprint_error_dev(self, "could not establish interrupt\n"); | | 540 | aprint_error_dev(self, "could not establish interrupt\n"); |
542 | bwfm_sdio_clkctl(sc, CLK_NONE, false); | | 541 | bwfm_sdio_clkctl(sc, CLK_NONE, false); |
543 | return; | | 542 | return; |
544 | } | | 543 | } |
545 | sdmmc_intr_enable(sc->sc_sf[1]); | | 544 | sdmmc_intr_enable(sc->sc_sf[1]); |
546 | | | 545 | |
547 | sdmmc_pause(100000, NULL); | | 546 | sdmmc_pause(100000, NULL); |
548 | | | 547 | |
549 | sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops; | | 548 | sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops; |
550 | sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops; | | 549 | sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops; |
551 | bwfm_attach(&sc->sc_sc); | | 550 | bwfm_attach(&sc->sc_sc); |
552 | sc->sc_bwfm_attached = true; | | 551 | sc->sc_bwfm_attached = true; |
553 | | | 552 | |
554 | err: | | 553 | err: |
555 | bwfm_firmware_close(&fwctx); | | 554 | bwfm_firmware_close(&fwctx); |
556 | } | | 555 | } |
557 | | | 556 | |
558 | static int | | 557 | static int |
559 | bwfm_fdt_find_phandle(device_t self, device_t parent) | | 558 | bwfm_fdt_find_phandle(device_t self, device_t parent) |
560 | { | | 559 | { |
561 | prop_dictionary_t dict; | | 560 | prop_dictionary_t dict; |
562 | device_t dev; | | 561 | device_t dev; |
563 | const char *str; | | 562 | const char *str; |
564 | int phandle; | | 563 | int phandle; |
565 | | | 564 | |
566 | /* locate in FDT */ | | 565 | /* locate in FDT */ |
567 | dict = device_properties(self); | | 566 | dict = device_properties(self); |
568 | if (prop_dictionary_get_cstring_nocopy(dict, "fdt-path", &str)) { | | 567 | if (prop_dictionary_get_cstring_nocopy(dict, "fdt-path", &str)) { |
569 | /* search in FDT */ | | 568 | /* search in FDT */ |
570 | phandle = OF_finddevice(str); | | 569 | phandle = OF_finddevice(str); |
571 | } else { | | 570 | } else { |
572 | | | 571 | |
573 | /* parent parent is sdhc controller */ | | 572 | /* parent parent is sdhc controller */ |
574 | dev = device_parent(parent); | | 573 | dev = device_parent(parent); |
575 | if (dev == NULL) | | 574 | if (dev == NULL) |
576 | return -1; | | 575 | return -1; |
577 | /* locate in FDT */ | | 576 | /* locate in FDT */ |
578 | dict = device_properties(dev); | | 577 | dict = device_properties(dev); |
579 | if (!prop_dictionary_get_cstring_nocopy(dict, "fdt-path", &str)) | | 578 | if (!prop_dictionary_get_cstring_nocopy(dict, "fdt-path", &str)) |
580 | return -1; | | 579 | return -1; |
581 | | | 580 | |
582 | /* are we the only FDT child ? */ | | 581 | /* are we the only FDT child ? */ |
583 | phandle = OF_child(OF_finddevice(str)); | | 582 | phandle = OF_child(OF_finddevice(str)); |
584 | } | | 583 | } |
585 | | | 584 | |
586 | if (!of_match_compatible(phandle, compatible)) | | 585 | if (!of_match_compatible(phandle, compatible)) |
587 | return -1; | | 586 | return -1; |
588 | | | 587 | |
589 | return phandle; | | 588 | return phandle; |
590 | } | | 589 | } |
591 | | | 590 | |
592 | static const char * | | 591 | static const char * |
593 | bwfm_fdt_get_model(void) | | 592 | bwfm_fdt_get_model(void) |
594 | { | | 593 | { |
595 | int phandle; | | 594 | int phandle; |
596 | | | 595 | |
597 | phandle = OF_finddevice("/"); | | 596 | phandle = OF_finddevice("/"); |
598 | return fdtbus_get_string_index(phandle, "compatible", 0); | | 597 | return fdtbus_get_string_index(phandle, "compatible", 0); |
599 | } | | 598 | } |
600 | | | 599 | |
601 | static int | | 600 | static int |
602 | bwfm_sdio_detach(device_t self, int flags) | | 601 | bwfm_sdio_detach(device_t self, int flags) |
603 | { | | 602 | { |
604 | struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self; | | 603 | struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self; |
605 | | | 604 | |
606 | #ifdef BWFM_DEBUG | | 605 | #ifdef BWFM_DEBUG |
607 | bwfm_sdio_debug_console(sc); | | 606 | bwfm_sdio_debug_console(sc); |
608 | #endif | | 607 | #endif |
609 | | | 608 | |
610 | if (sc->sc_ih || sc->sc_fdtih) { | | 609 | if (sc->sc_ih || sc->sc_fdtih) { |
611 | sdmmc_intr_disable(sc->sc_sf[1]); | | 610 | sdmmc_intr_disable(sc->sc_sf[1]); |
612 | if (sc->sc_ih) | | 611 | if (sc->sc_ih) |
613 | sdmmc_intr_disestablish(sc->sc_ih); | | 612 | sdmmc_intr_disestablish(sc->sc_ih); |
614 | if (sc->sc_fdtih) | | 613 | if (sc->sc_fdtih) |
615 | fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_fdtih); | | 614 | fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_fdtih); |
616 | } | | 615 | } |
617 | if (sc->sc_bwfm_attached) | | 616 | if (sc->sc_bwfm_attached) |
618 | bwfm_detach(&sc->sc_sc, flags); | | 617 | bwfm_detach(&sc->sc_sc, flags); |
619 | | | 618 | |
620 | sdmmc_del_task(sc->sc_sf[1]->sc, &sc->sc_task, NULL); | | 619 | sdmmc_del_task(sc->sc_sf[1]->sc, &sc->sc_task, NULL); |
621 | | | 620 | |
622 | kmem_free(sc->sc_sf, sc->sc_sf_size); | | 621 | kmem_free(sc->sc_sf, sc->sc_sf_size); |
623 | kmem_free(sc->sc_bounce_buf, sc->sc_bounce_size); | | 622 | kmem_free(sc->sc_bounce_buf, sc->sc_bounce_size); |
624 | | | 623 | |
625 | cv_destroy(&sc->sc_rxctl_cv); | | 624 | cv_destroy(&sc->sc_rxctl_cv); |
626 | mutex_destroy(&sc->sc_lock); | | 625 | mutex_destroy(&sc->sc_lock); |
627 | | | 626 | |
628 | return 0; | | 627 | return 0; |
629 | } | | 628 | } |
630 | | | 629 | |
631 | static void | | 630 | static void |
632 | bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t addr) | | 631 | bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t addr) |
633 | { | | 632 | { |
634 | uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK; | | 633 | uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK; |
635 | | | 634 | |
636 | if (sc->sc_bar0 == bar0) | | 635 | if (sc->sc_bar0 == bar0) |
637 | return; | | 636 | return; |
638 | | | 637 | |
639 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW, | | 638 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW, |
640 | (bar0 >> 8) & 0xff); | | 639 | (bar0 >> 8) & 0xff); |
641 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID, | | 640 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID, |
642 | (bar0 >> 16) & 0xff); | | 641 | (bar0 >> 16) & 0xff); |
643 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH, | | 642 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH, |
644 | (bar0 >> 24) & 0xff); | | 643 | (bar0 >> 24) & 0xff); |
645 | sc->sc_bar0 = bar0; | | 644 | sc->sc_bar0 = bar0; |
646 | } | | 645 | } |
647 | | | 646 | |
648 | static uint8_t | | 647 | static uint8_t |
649 | bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr) | | 648 | bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr) |
650 | { | | 649 | { |
651 | struct sdmmc_function *sf; | | 650 | struct sdmmc_function *sf; |
652 | uint8_t rv; | | 651 | uint8_t rv; |
653 | | | 652 | |
654 | /* | | 653 | /* |
655 | * figure out how to read the register based on address range | | 654 | * figure out how to read the register based on address range |
656 | * 0x00 ~ 0x7FF: function 0 CCCR and FBR | | 655 | * 0x00 ~ 0x7FF: function 0 CCCR and FBR |
657 | * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers | | 656 | * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers |
658 | * The rest: function 1 silicon backplane core registers | | 657 | * The rest: function 1 silicon backplane core registers |
659 | */ | | 658 | */ |
660 | if ((addr & ~0x7ff) == 0) | | 659 | if ((addr & ~0x7ff) == 0) |
661 | sf = sc->sc_sf[0]; | | 660 | sf = sc->sc_sf[0]; |
662 | else | | 661 | else |
663 | sf = sc->sc_sf[1]; | | 662 | sf = sc->sc_sf[1]; |
664 | | | 663 | |
665 | rv = sdmmc_io_read_1(sf, addr); | | 664 | rv = sdmmc_io_read_1(sf, addr); |
666 | return rv; | | 665 | return rv; |
667 | } | | 666 | } |
668 | | | 667 | |
669 | static uint32_t | | 668 | static uint32_t |
670 | bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr) | | 669 | bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr) |
671 | { | | 670 | { |
672 | struct sdmmc_function *sf; | | 671 | struct sdmmc_function *sf; |
673 | uint32_t rv; | | 672 | uint32_t rv; |
674 | | | 673 | |
675 | bwfm_sdio_backplane(sc, addr); | | 674 | bwfm_sdio_backplane(sc, addr); |
676 | | | 675 | |
677 | addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; | | 676 | addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; |
678 | addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; | | 677 | addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; |
679 | | | 678 | |
680 | /* | | 679 | /* |
681 | * figure out how to read the register based on address range | | 680 | * figure out how to read the register based on address range |
682 | * 0x00 ~ 0x7FF: function 0 CCCR and FBR | | 681 | * 0x00 ~ 0x7FF: function 0 CCCR and FBR |
683 | * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers | | 682 | * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers |
684 | * The rest: function 1 silicon backplane core registers | | 683 | * The rest: function 1 silicon backplane core registers |
685 | */ | | 684 | */ |
686 | if ((addr & ~0x7ff) == 0) | | 685 | if ((addr & ~0x7ff) == 0) |
687 | sf = sc->sc_sf[0]; | | 686 | sf = sc->sc_sf[0]; |
688 | else | | 687 | else |
689 | sf = sc->sc_sf[1]; | | 688 | sf = sc->sc_sf[1]; |
690 | | | 689 | |
691 | rv = sdmmc_io_read_4(sf, addr); | | 690 | rv = sdmmc_io_read_4(sf, addr); |
692 | return htole32(rv); | | 691 | return htole32(rv); |
693 | } | | 692 | } |
694 | | | 693 | |
695 | static void | | 694 | static void |
696 | bwfm_sdio_write_1(struct bwfm_sdio_softc *sc, uint32_t addr, uint8_t data) | | 695 | bwfm_sdio_write_1(struct bwfm_sdio_softc *sc, uint32_t addr, uint8_t data) |
697 | { | | 696 | { |
698 | struct sdmmc_function *sf; | | 697 | struct sdmmc_function *sf; |
699 | | | 698 | |
700 | /* | | 699 | /* |
701 | * figure out how to read the register based on address range | | 700 | * figure out how to read the register based on address range |
702 | * 0x00 ~ 0x7FF: function 0 CCCR and FBR | | 701 | * 0x00 ~ 0x7FF: function 0 CCCR and FBR |
703 | * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers | | 702 | * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers |
704 | * The rest: function 1 silicon backplane core registers | | 703 | * The rest: function 1 silicon backplane core registers |
705 | */ | | 704 | */ |
706 | if ((addr & ~0x7ff) == 0) | | 705 | if ((addr & ~0x7ff) == 0) |
707 | sf = sc->sc_sf[0]; | | 706 | sf = sc->sc_sf[0]; |
708 | else | | 707 | else |
709 | sf = sc->sc_sf[1]; | | 708 | sf = sc->sc_sf[1]; |
710 | | | 709 | |
711 | sdmmc_io_write_1(sf, addr, data); | | 710 | sdmmc_io_write_1(sf, addr, data); |
712 | } | | 711 | } |
713 | | | 712 | |
714 | static void | | 713 | static void |
715 | bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data) | | 714 | bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data) |
716 | { | | 715 | { |
717 | struct sdmmc_function *sf; | | 716 | struct sdmmc_function *sf; |
718 | | | 717 | |
719 | bwfm_sdio_backplane(sc, addr); | | 718 | bwfm_sdio_backplane(sc, addr); |
720 | | | 719 | |
721 | addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; | | 720 | addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; |
722 | addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; | | 721 | addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; |
723 | | | 722 | |
724 | /* | | 723 | /* |
725 | * figure out how to read the register based on address range | | 724 | * figure out how to read the register based on address range |
726 | * 0x00 ~ 0x7FF: function 0 CCCR and FBR | | 725 | * 0x00 ~ 0x7FF: function 0 CCCR and FBR |
727 | * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers | | 726 | * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers |
728 | * The rest: function 1 silicon backplane core registers | | 727 | * The rest: function 1 silicon backplane core registers |
729 | */ | | 728 | */ |
730 | if ((addr & ~0x7ff) == 0) | | 729 | if ((addr & ~0x7ff) == 0) |
731 | sf = sc->sc_sf[0]; | | 730 | sf = sc->sc_sf[0]; |
732 | else | | 731 | else |
733 | sf = sc->sc_sf[1]; | | 732 | sf = sc->sc_sf[1]; |
734 | | | 733 | |
735 | sdmmc_io_write_4(sf, addr, htole32(data)); | | 734 | sdmmc_io_write_4(sf, addr, htole32(data)); |
736 | } | | 735 | } |
737 | | | 736 | |
738 | static int | | 737 | static int |
739 | bwfm_sdio_buf_read(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf, | | 738 | bwfm_sdio_buf_read(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf, |
740 | uint32_t reg, char *data, size_t size) | | 739 | uint32_t reg, char *data, size_t size) |
741 | { | | 740 | { |
742 | int err; | | 741 | int err; |
743 | | | 742 | |
744 | KASSERT(((vaddr_t)data & 0x3) == 0); | | 743 | KASSERT(((vaddr_t)data & 0x3) == 0); |
745 | KASSERT((size & 0x3) == 0); | | 744 | KASSERT((size & 0x3) == 0); |
746 | | | 745 | |
747 | if (sf == sc->sc_sf[1]) | | 746 | if (sf == sc->sc_sf[1]) |
748 | err = sdmmc_io_read_region_1(sf, reg, data, size); | | 747 | err = sdmmc_io_read_region_1(sf, reg, data, size); |
749 | else | | 748 | else |
750 | err = sdmmc_io_read_multi_1(sf, reg, data, size); | | 749 | err = sdmmc_io_read_multi_1(sf, reg, data, size); |
751 | | | 750 | |
752 | if (err) | | 751 | if (err) |
753 | printf("%s: error %d\n", __func__, err); | | 752 | printf("%s: error %d\n", __func__, err); |
754 | | | 753 | |
755 | return err; | | 754 | return err; |
756 | } | | 755 | } |
757 | | | 756 | |
758 | static int | | 757 | static int |
759 | bwfm_sdio_buf_write(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf, | | 758 | bwfm_sdio_buf_write(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf, |
760 | uint32_t reg, char *data, size_t size) | | 759 | uint32_t reg, char *data, size_t size) |
761 | { | | 760 | { |
762 | int err; | | 761 | int err; |
763 | | | 762 | |
764 | KASSERT(((vaddr_t)data & 0x3) == 0); | | 763 | KASSERT(((vaddr_t)data & 0x3) == 0); |
765 | KASSERT((size & 0x3) == 0); | | 764 | KASSERT((size & 0x3) == 0); |
766 | | | 765 | |
767 | err = sdmmc_io_write_region_1(sf, reg, data, size); | | 766 | err = sdmmc_io_write_region_1(sf, reg, data, size); |
768 | | | 767 | |
769 | if (err) | | 768 | if (err) |
770 | printf("%s: error %d\n", __func__, err); | | 769 | printf("%s: error %d\n", __func__, err); |
771 | | | 770 | |
772 | return err; | | 771 | return err; |
773 | } | | 772 | } |
774 | | | 773 | |
775 | static uint32_t | | 774 | static uint32_t |
776 | bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *sc, uint32_t reg, | | 775 | bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *sc, uint32_t reg, |
777 | char *data, size_t left, int write) | | 776 | char *data, size_t left, int write) |
778 | { | | 777 | { |
779 | uint32_t sbaddr, sdaddr, off; | | 778 | uint32_t sbaddr, sdaddr, off; |
780 | size_t size; | | 779 | size_t size; |
781 | int err; | | 780 | int err; |
782 | | | 781 | |
783 | err = off = 0; | | 782 | err = off = 0; |
784 | while (left > 0) { | | 783 | while (left > 0) { |
785 | sbaddr = reg + off; | | 784 | sbaddr = reg + off; |
786 | bwfm_sdio_backplane(sc, sbaddr); | | 785 | bwfm_sdio_backplane(sc, sbaddr); |
787 | | | 786 | |
788 | sdaddr = sbaddr & BWFM_SDIO_SB_OFT_ADDR_MASK; | | 787 | sdaddr = sbaddr & BWFM_SDIO_SB_OFT_ADDR_MASK; |
789 | size = ulmin(left, (BWFM_SDIO_SB_OFT_ADDR_PAGE - sdaddr)); | | 788 | size = ulmin(left, (BWFM_SDIO_SB_OFT_ADDR_PAGE - sdaddr)); |
790 | sdaddr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; | | 789 | sdaddr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; |
791 | | | 790 | |
792 | if (write) { | | 791 | if (write) { |
793 | memcpy(sc->sc_bounce_buf, data + off, size); | | 792 | memcpy(sc->sc_bounce_buf, data + off, size); |
794 | if (roundup(size, 4) != size) | | 793 | if (roundup(size, 4) != size) |
795 | memset(sc->sc_bounce_buf + size, 0, | | 794 | memset(sc->sc_bounce_buf + size, 0, |
796 | roundup(size, 4) - size); | | 795 | roundup(size, 4) - size); |
797 | err = bwfm_sdio_buf_write(sc, sc->sc_sf[1], sdaddr, | | 796 | err = bwfm_sdio_buf_write(sc, sc->sc_sf[1], sdaddr, |
798 | sc->sc_bounce_buf, roundup(size, 4)); | | 797 | sc->sc_bounce_buf, roundup(size, 4)); |
799 | } else { | | 798 | } else { |
800 | err = bwfm_sdio_buf_read(sc, sc->sc_sf[1], sdaddr, | | 799 | err = bwfm_sdio_buf_read(sc, sc->sc_sf[1], sdaddr, |
801 | sc->sc_bounce_buf, roundup(size, 4)); | | 800 | sc->sc_bounce_buf, roundup(size, 4)); |
802 | memcpy(data + off, sc->sc_bounce_buf, size); | | 801 | memcpy(data + off, sc->sc_bounce_buf, size); |
803 | } | | 802 | } |
804 | if (err) | | 803 | if (err) |
805 | break; | | 804 | break; |
806 | | | 805 | |
807 | off += size; | | 806 | off += size; |
808 | left -= size; | | 807 | left -= size; |
809 | } | | 808 | } |
810 | | | 809 | |
811 | if (err) | | 810 | if (err) |
812 | printf("%s: error %d\n", __func__, err); | | 811 | printf("%s: error %d\n", __func__, err); |
813 | | | 812 | |
814 | return err; | | 813 | return err; |
815 | } | | 814 | } |
816 | | | 815 | |
817 | static uint32_t | | 816 | static uint32_t |
818 | bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *sc, | | 817 | bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *sc, |
819 | char *data, size_t size, int write) | | 818 | char *data, size_t size, int write) |
820 | { | | 819 | { |
821 | uint32_t addr; | | 820 | uint32_t addr; |
822 | int err; | | 821 | int err; |
823 | | | 822 | |
824 | addr = sc->sc_cc->co_base; | | 823 | addr = sc->sc_cc->co_base; |
825 | bwfm_sdio_backplane(sc, addr); | | 824 | bwfm_sdio_backplane(sc, addr); |
826 | | | 825 | |
827 | addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; | | 826 | addr &= BWFM_SDIO_SB_OFT_ADDR_MASK; |
828 | addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; | | 827 | addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG; |
829 | | | 828 | |
830 | if (write) | | 829 | if (write) |
831 | err = bwfm_sdio_buf_write(sc, sc->sc_sf[2], addr, data, size); | | 830 | err = bwfm_sdio_buf_write(sc, sc->sc_sf[2], addr, data, size); |
832 | else | | 831 | else |
833 | err = bwfm_sdio_buf_read(sc, sc->sc_sf[2], addr, data, size); | | 832 | err = bwfm_sdio_buf_read(sc, sc->sc_sf[2], addr, data, size); |
834 | | | 833 | |
835 | if (err) | | 834 | if (err) |
836 | printf("%s: error %d\n", __func__, err); | | 835 | printf("%s: error %d\n", __func__, err); |
837 | | | 836 | |
838 | return err; | | 837 | return err; |
839 | } | | 838 | } |
840 | | | 839 | |
841 | static uint32_t | | 840 | static uint32_t |
842 | bwfm_sdio_dev_read(struct bwfm_sdio_softc *sc, uint32_t reg) | | 841 | bwfm_sdio_dev_read(struct bwfm_sdio_softc *sc, uint32_t reg) |
843 | { | | 842 | { |
844 | struct bwfm_core *core; | | 843 | struct bwfm_core *core; |
845 | uint32_t val; | | 844 | uint32_t val; |
846 | | | 845 | |
847 | core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); | | 846 | core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); |
848 | val = bwfm_sdio_read_4(sc, core->co_base + reg); | | 847 | val = bwfm_sdio_read_4(sc, core->co_base + reg); |
849 | /* TODO: Workaround for 4335/4339 */ | | 848 | /* TODO: Workaround for 4335/4339 */ |
850 | | | 849 | |
851 | return val; | | 850 | return val; |
852 | } | | 851 | } |
853 | | | 852 | |
854 | static void | | 853 | static void |
855 | bwfm_sdio_dev_write(struct bwfm_sdio_softc *sc, uint32_t reg, uint32_t val) | | 854 | bwfm_sdio_dev_write(struct bwfm_sdio_softc *sc, uint32_t reg, uint32_t val) |
856 | { | | 855 | { |
857 | struct bwfm_core *core; | | 856 | struct bwfm_core *core; |
858 | | | 857 | |
859 | core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); | | 858 | core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); |
860 | bwfm_sdio_write_4(sc, core->co_base + reg, val); | | 859 | bwfm_sdio_write_4(sc, core->co_base + reg, val); |
861 | } | | 860 | } |
862 | | | 861 | |
863 | static uint32_t | | 862 | static uint32_t |
864 | bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) | | 863 | bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) |
865 | { | | 864 | { |
866 | struct bwfm_sdio_softc *sc = (void *)bwfm; | | 865 | struct bwfm_sdio_softc *sc = (void *)bwfm; |
867 | uint32_t val; | | 866 | uint32_t val; |
868 | | | 867 | |
869 | mutex_enter(&sc->sc_lock); | | 868 | mutex_enter(&sc->sc_lock); |
870 | val = bwfm_sdio_read_4(sc, reg); | | 869 | val = bwfm_sdio_read_4(sc, reg); |
871 | /* TODO: Workaround for 4335/4339 */ | | 870 | /* TODO: Workaround for 4335/4339 */ |
872 | mutex_exit(&sc->sc_lock); | | 871 | mutex_exit(&sc->sc_lock); |
873 | | | 872 | |
874 | return val; | | 873 | return val; |
875 | } | | 874 | } |
876 | | | 875 | |
877 | static void | | 876 | static void |
878 | bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) | | 877 | bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) |
879 | { | | 878 | { |
880 | struct bwfm_sdio_softc *sc = (void *)bwfm; | | 879 | struct bwfm_sdio_softc *sc = (void *)bwfm; |
881 | | | 880 | |
882 | mutex_enter(&sc->sc_lock); | | 881 | mutex_enter(&sc->sc_lock); |
883 | bwfm_sdio_write_4(sc, reg, val); | | 882 | bwfm_sdio_write_4(sc, reg, val); |
884 | mutex_exit(&sc->sc_lock); | | 883 | mutex_exit(&sc->sc_lock); |
885 | } | | 884 | } |
886 | | | 885 | |
887 | static int | | 886 | static int |
888 | bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm) | | 887 | bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm) |
889 | { | | 888 | { |
890 | struct bwfm_sdio_softc *sc = (void *)bwfm; | | 889 | struct bwfm_sdio_softc *sc = (void *)bwfm; |
891 | uint8_t clkval, clkset, clkmask; | | 890 | uint8_t clkval, clkset, clkmask; |
892 | int i, error = 0; | | 891 | int i, error = 0; |
893 | | | 892 | |
894 | mutex_enter(&sc->sc_lock); | | 893 | mutex_enter(&sc->sc_lock); |
895 | | | 894 | |
896 | clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ | | | 895 | clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ | |
897 | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF; | | 896 | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF; |
898 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); | | 897 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); |
899 | | | 898 | |
900 | clkmask = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL | | | 899 | clkmask = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL | |
901 | BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL; | | 900 | BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL; |
902 | clkval = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); | | 901 | clkval = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); |
903 | | | 902 | |
904 | if ((clkval & ~clkmask) != clkset) { | | 903 | if ((clkval & ~clkmask) != clkset) { |
905 | printf("%s: wrote 0x%02x read 0x%02x\n", DEVNAME(sc), | | 904 | printf("%s: wrote 0x%02x read 0x%02x\n", DEVNAME(sc), |
906 | clkset, clkval); | | 905 | clkset, clkval); |
907 | error = 1; | | 906 | error = 1; |
908 | goto done; | | 907 | goto done; |
909 | } | | 908 | } |
910 | | | 909 | |
911 | for (i = 1000; i > 0; i--) { | | 910 | for (i = 1000; i > 0; i--) { |
912 | clkval = bwfm_sdio_read_1(sc, | | 911 | clkval = bwfm_sdio_read_1(sc, |
913 | BWFM_SDIO_FUNC1_CHIPCLKCSR); | | 912 | BWFM_SDIO_FUNC1_CHIPCLKCSR); |
914 | if (clkval & clkmask) | | 913 | if (clkval & clkmask) |
915 | break; | | 914 | break; |
916 | } | | 915 | } |
917 | if (i == 0) { | | 916 | if (i == 0) { |
918 | printf("%s: timeout on ALPAV wait, clkval 0x%02x\n", | | 917 | printf("%s: timeout on ALPAV wait, clkval 0x%02x\n", |
919 | DEVNAME(sc), clkval); | | 918 | DEVNAME(sc), clkval); |
920 | error = 1; | | 919 | error = 1; |
921 | goto done; | | 920 | goto done; |
922 | } | | 921 | } |
923 | | | 922 | |
924 | clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | | | 923 | clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF | |
925 | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP; | | 924 | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP; |
926 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); | | 925 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset); |
927 | delay(65); | | 926 | delay(65); |
928 | | | 927 | |
929 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SDIOPULLUP, 0); | | 928 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SDIOPULLUP, 0); |
930 | | | 929 | |
931 | done: | | 930 | done: |
932 | mutex_exit(&sc->sc_lock); | | 931 | mutex_exit(&sc->sc_lock); |
933 | | | 932 | |
934 | return error; | | 933 | return error; |
935 | } | | 934 | } |
936 | | | 935 | |
937 | static void | | 936 | static void |
938 | bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) | | 937 | bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) |
939 | { | | 938 | { |
940 | struct bwfm_sdio_softc *sc = (void *)bwfm; | | 939 | struct bwfm_sdio_softc *sc = (void *)bwfm; |
941 | struct bwfm_core *core; | | 940 | struct bwfm_core *core; |
942 | | | 941 | |
943 | core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); | | 942 | core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV); |
944 | bwfm_sdio_buscore_write(&sc->sc_sc, | | 943 | bwfm_sdio_buscore_write(&sc->sc_sc, |
945 | core->co_base + BWFM_SDPCMD_INTSTATUS, 0xFFFFFFFF); | | 944 | core->co_base + BWFM_SDPCMD_INTSTATUS, 0xFFFFFFFF); |
946 | | | 945 | |
947 | mutex_enter(&sc->sc_lock); | | 946 | mutex_enter(&sc->sc_lock); |
948 | if (rstvec) | | 947 | if (rstvec) |
949 | bwfm_sdio_ram_read_write(sc, 0, (char *)&rstvec, | | 948 | bwfm_sdio_ram_read_write(sc, 0, (char *)&rstvec, |
950 | sizeof(rstvec), 1); | | 949 | sizeof(rstvec), 1); |
951 | mutex_exit(&sc->sc_lock); | | 950 | mutex_exit(&sc->sc_lock); |
952 | } | | 951 | } |
953 | | | 952 | |
954 | static struct mbuf * | | 953 | static struct mbuf * |
955 | bwfm_sdio_newbuf(void) | | 954 | bwfm_sdio_newbuf(void) |
956 | { | | 955 | { |
957 | struct mbuf *m; | | 956 | struct mbuf *m; |
958 | | | 957 | |
959 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 958 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
960 | if (m == NULL) | | 959 | if (m == NULL) |
961 | return NULL; | | 960 | return NULL; |
962 | | | 961 | |
963 | MCLGET(m, M_DONTWAIT); | | 962 | MCLGET(m, M_DONTWAIT); |
964 | if (!(m->m_flags & M_EXT)) { | | 963 | if (!(m->m_flags & M_EXT)) { |
965 | m_freem(m); | | 964 | m_freem(m); |
966 | return NULL; | | 965 | return NULL; |
967 | } | | 966 | } |
968 | | | 967 | |
969 | m->m_len = m->m_pkthdr.len = MCLBYTES; | | 968 | m->m_len = m->m_pkthdr.len = MCLBYTES; |
970 | return m; | | 969 | return m; |
971 | } | | 970 | } |
972 | | | 971 | |
973 | static struct mbuf * | | 972 | static struct mbuf * |
974 | bwfm_qget(struct mbuf **q) | | 973 | bwfm_qget(struct mbuf **q) |
975 | { | | 974 | { |
976 | struct mbuf *m = NULL; | | 975 | struct mbuf *m = NULL; |
977 | | | 976 | |
978 | if (*q != NULL) { | | 977 | if (*q != NULL) { |
979 | m = *q; | | 978 | m = *q; |
980 | *q = m->m_next; | | 979 | *q = m->m_next; |
981 | m->m_next = NULL; | | 980 | m->m_next = NULL; |
982 | } | | 981 | } |
983 | | | 982 | |
984 | return m; | | 983 | return m; |
985 | } | | 984 | } |
986 | | | 985 | |
987 | static void | | 986 | static void |
988 | bwfm_qput(struct mbuf **q, struct mbuf *m) | | 987 | bwfm_qput(struct mbuf **q, struct mbuf *m) |
989 | { | | 988 | { |
990 | | | 989 | |
991 | if (*q == NULL) | | 990 | if (*q == NULL) |
992 | *q = m; | | 991 | *q = m; |
993 | else | | 992 | else |
994 | m_cat(*q, m); | | 993 | m_cat(*q, m); |
995 | } | | 994 | } |
996 | | | 995 | |
997 | static int | | 996 | static int |
998 | bwfm_sdio_txcheck(struct bwfm_softc *bwfm) | | 997 | bwfm_sdio_txcheck(struct bwfm_softc *bwfm) |
999 | { | | 998 | { |
1000 | struct bwfm_sdio_softc *sc = (void *)bwfm; | | 999 | struct bwfm_sdio_softc *sc = (void *)bwfm; |
1001 | int error = 0; | | 1000 | int error = 0; |
1002 | | | 1001 | |
1003 | mutex_enter(&sc->sc_lock); | | 1002 | mutex_enter(&sc->sc_lock); |
1004 | if (sc->sc_tx_count >= 64) | | 1003 | if (sc->sc_tx_count >= 64) |
1005 | error = ENOBUFS; | | 1004 | error = ENOBUFS; |
1006 | mutex_exit(&sc->sc_lock); | | 1005 | mutex_exit(&sc->sc_lock); |
1007 | | | 1006 | |
1008 | return error; | | 1007 | return error; |
1009 | } | | 1008 | } |
1010 | | | 1009 | |
1011 | | | 1010 | |
1012 | static int | | 1011 | static int |
1013 | bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf **mp) | | 1012 | bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf **mp) |
1014 | { | | 1013 | { |
1015 | struct bwfm_sdio_softc *sc = (void *)bwfm; | | 1014 | struct bwfm_sdio_softc *sc = (void *)bwfm; |
1016 | | | 1015 | |
1017 | if (sc->sc_tx_count >= 64) { | | 1016 | if (sc->sc_tx_count >= 64) { |
1018 | printf("%s: tx count limit reached\n",DEVNAME(sc)); | | 1017 | printf("%s: tx count limit reached\n",DEVNAME(sc)); |
1019 | return ENOBUFS; | | 1018 | return ENOBUFS; |
1020 | } | | 1019 | } |
1021 | | | 1020 | |
1022 | mutex_enter(&sc->sc_lock); | | 1021 | mutex_enter(&sc->sc_lock); |
1023 | sc->sc_tx_count++; | | 1022 | sc->sc_tx_count++; |
1024 | MBUFQ_ENQUEUE(&sc->sc_tx_queue, *mp); | | 1023 | MBUFQ_ENQUEUE(&sc->sc_tx_queue, *mp); |
1025 | mutex_exit(&sc->sc_lock); | | 1024 | mutex_exit(&sc->sc_lock); |
1026 | | | 1025 | |
1027 | bwfm_sdio_intr1(sc, "sdio_txdata"); | | 1026 | bwfm_sdio_intr1(sc, "sdio_txdata"); |
1028 | | | 1027 | |
1029 | return 0; | | 1028 | return 0; |
1030 | } | | 1029 | } |
1031 | | | 1030 | |
1032 | static int | | 1031 | static int |
1033 | bwfm_sdio_txctl(struct bwfm_softc *bwfm, char *buf, size_t len) | | 1032 | bwfm_sdio_txctl(struct bwfm_softc *bwfm, char *buf, size_t len) |
1034 | { | | 1033 | { |
1035 | struct bwfm_sdio_softc *sc = (void *)bwfm; | | 1034 | struct bwfm_sdio_softc *sc = (void *)bwfm; |
1036 | struct mbuf *m; | | 1035 | struct mbuf *m; |
1037 | | | 1036 | |
1038 | KASSERT(len <= MCLBYTES); | | 1037 | KASSERT(len <= MCLBYTES); |
1039 | | | 1038 | |
1040 | MGET(m, M_DONTWAIT, MT_CONTROL); | | 1039 | MGET(m, M_DONTWAIT, MT_CONTROL); |
1041 | if (m == NULL) | | 1040 | if (m == NULL) |
1042 | goto fail; | | 1041 | goto fail; |
1043 | if (len > MLEN) { | | 1042 | if (len > MLEN) { |
1044 | MCLGET(m, M_DONTWAIT); | | 1043 | MCLGET(m, M_DONTWAIT); |
1045 | if (!(m->m_flags & M_EXT)) { | | 1044 | if (!(m->m_flags & M_EXT)) { |
1046 | m_freem(m); | | 1045 | m_freem(m); |
1047 | goto fail; | | 1046 | goto fail; |
1048 | } | | 1047 | } |
1049 | } | | 1048 | } |
1050 | memcpy(mtod(m, char *), buf, len); | | 1049 | memcpy(mtod(m, char *), buf, len); |
1051 | m->m_len = len; | | 1050 | m->m_len = len; |
1052 | | | 1051 | |
1053 | mutex_enter(&sc->sc_lock); | | 1052 | mutex_enter(&sc->sc_lock); |
1054 | MBUFQ_ENQUEUE(&sc->sc_tx_queue, m); | | 1053 | MBUFQ_ENQUEUE(&sc->sc_tx_queue, m); |
1055 | mutex_exit(&sc->sc_lock); | | 1054 | mutex_exit(&sc->sc_lock); |
1056 | | | 1055 | |
1057 | bwfm_sdio_intr1(sc, "sdio_txctl"); | | 1056 | bwfm_sdio_intr1(sc, "sdio_txctl"); |
1058 | | | 1057 | |
1059 | return 0; | | 1058 | return 0; |
1060 | | | 1059 | |
1061 | fail: | | 1060 | fail: |
1062 | return ENOBUFS; | | 1061 | return ENOBUFS; |
1063 | } | | 1062 | } |
1064 | | | 1063 | |
1065 | static int | | 1064 | static int |
1066 | bwfm_nvram_convert(u_char *buf, size_t len, size_t *newlenp) | | 1065 | bwfm_nvram_convert(u_char *buf, size_t len, size_t *newlenp) |
1067 | { | | 1066 | { |
1068 | u_char *src, *dst, *end = buf + len; | | 1067 | u_char *src, *dst, *end = buf + len; |
1069 | bool skip = false; | | 1068 | bool skip = false; |
1070 | size_t count = 0, pad; | | 1069 | size_t count = 0, pad; |
1071 | uint32_t token; | | 1070 | uint32_t token; |
1072 | | | 1071 | |
1073 | for (src = buf, dst = buf; src != end; ++src) { | | 1072 | for (src = buf, dst = buf; src != end; ++src) { |
1074 | if (*src == '\n') { | | 1073 | if (*src == '\n') { |
1075 | if (count > 0) | | 1074 | if (count > 0) |
1076 | *dst++ = '\0'; | | 1075 | *dst++ = '\0'; |
1077 | count = 0; | | 1076 | count = 0; |
1078 | skip = false; | | 1077 | skip = false; |
1079 | continue; | | 1078 | continue; |
1080 | } | | 1079 | } |
1081 | if (skip) | | 1080 | if (skip) |
1082 | continue; | | 1081 | continue; |
1083 | if (*src == '#' && count == 0) { | | 1082 | if (*src == '#' && count == 0) { |
1084 | skip = true; | | 1083 | skip = true; |
1085 | continue; | | 1084 | continue; |
1086 | } | | 1085 | } |
1087 | if (*src == '\r' || *src == ' ') | | 1086 | if (*src == '\r' || *src == ' ') |
1088 | continue; | | 1087 | continue; |
1089 | *dst++ = *src; | | 1088 | *dst++ = *src; |
1090 | ++count; | | 1089 | ++count; |
1091 | } | | 1090 | } |
1092 | | | 1091 | |
1093 | count = dst - buf; | | 1092 | count = dst - buf; |
1094 | pad = roundup(count + 1, 4) - count; | | 1093 | pad = roundup(count + 1, 4) - count; |
1095 | | | 1094 | |
1096 | if (count + pad + sizeof(token) > len) | | 1095 | if (count + pad + sizeof(token) > len) |
1097 | return 1; | | 1096 | return 1; |
1098 | | | 1097 | |
1099 | memset(dst, 0, pad); | | 1098 | memset(dst, 0, pad); |
1100 | count += pad; | | 1099 | count += pad; |
1101 | dst += pad; | | 1100 | dst += pad; |
1102 | | | 1101 | |
1103 | token = (count / 4) & 0xffff; | | 1102 | token = (count / 4) & 0xffff; |
1104 | token |= ~token << 16; | | 1103 | token |= ~token << 16; |
1105 | token = htole32(token); | | 1104 | token = htole32(token); |
1106 | | | 1105 | |
1107 | memcpy(dst, &token, sizeof(token)); | | 1106 | memcpy(dst, &token, sizeof(token)); |
1108 | count += sizeof(token); | | 1107 | count += sizeof(token); |
1109 | | | 1108 | |
1110 | *newlenp = count; | | 1109 | *newlenp = count; |
1111 | | | 1110 | |
1112 | return 0; | | 1111 | return 0; |
1113 | } | | 1112 | } |
1114 | | | 1113 | |
1115 | static int | | 1114 | static int |
1116 | bwfm_sdio_load_microcode(struct bwfm_sdio_softc *sc, u_char *ucode, size_t size, | | 1115 | bwfm_sdio_load_microcode(struct bwfm_sdio_softc *sc, u_char *ucode, size_t size, |
1117 | u_char *nvram, size_t nvlen) | | 1116 | u_char *nvram, size_t nvlen) |
1118 | { | | 1117 | { |
1119 | struct bwfm_softc *bwfm = &sc->sc_sc; | | 1118 | struct bwfm_softc *bwfm = &sc->sc_sc; |
1120 | char *verify = NULL; | | 1119 | char *verify = NULL; |
1121 | int err = 0; | | 1120 | int err = 0; |
1122 | | | 1121 | |
1123 | bwfm_sdio_clkctl(sc, CLK_AVAIL, false); | | 1122 | bwfm_sdio_clkctl(sc, CLK_AVAIL, false); |
1124 | | | 1123 | |
1125 | DPRINTF(("ucode %zu bytes to 0x%08lx\n", size, | | 1124 | DPRINTF(("ucode %zu bytes to 0x%08lx\n", size, |
1126 | (u_long)bwfm->sc_chip.ch_rambase)); | | 1125 | (u_long)bwfm->sc_chip.ch_rambase)); |
1127 | /* Upload firmware */ | | 1126 | /* Upload firmware */ |
1128 | err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase, | | 1127 | err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase, |
1129 | ucode, size, 1); | | 1128 | ucode, size, 1); |
1130 | if (err) | | 1129 | if (err) |
1131 | goto out; | | 1130 | goto out; |
1132 | | | 1131 | |
1133 | /* Verify firmware */ | | 1132 | /* Verify firmware */ |
1134 | verify = kmem_zalloc(size, KM_SLEEP); | | 1133 | verify = kmem_zalloc(size, KM_SLEEP); |
1135 | err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase, | | 1134 | err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase, |
1136 | verify, size, 0); | | 1135 | verify, size, 0); |
1137 | if (err || memcmp(verify, ucode, size)) { | | 1136 | if (err || memcmp(verify, ucode, size)) { |
1138 | printf("%s: firmware verification failed\n", | | 1137 | printf("%s: firmware verification failed\n", |
1139 | DEVNAME(sc)); | | 1138 | DEVNAME(sc)); |
1140 | kmem_free(verify, size); | | 1139 | kmem_free(verify, size); |
1141 | goto out; | | 1140 | goto out; |
1142 | } | | 1141 | } |
1143 | kmem_free(verify, size); | | 1142 | kmem_free(verify, size); |
1144 | | | 1143 | |
1145 | DPRINTF(("nvram %zu bytes to 0x%08lx\n", nvlen, | | 1144 | DPRINTF(("nvram %zu bytes to 0x%08lx\n", nvlen, |
1146 | (u_long)bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize | | 1145 | (u_long)bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize |
1147 | - nvlen)); | | 1146 | - nvlen)); |
1148 | /* Upload nvram */ | | 1147 | /* Upload nvram */ |
1149 | err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase + | | 1148 | err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase + |
1150 | bwfm->sc_chip.ch_ramsize - nvlen, nvram, nvlen, 1); | | 1149 | bwfm->sc_chip.ch_ramsize - nvlen, nvram, nvlen, 1); |
1151 | if (err) | | 1150 | if (err) |
1152 | goto out; | | 1151 | goto out; |
1153 | | | 1152 | |
1154 | /* Verify nvram */ | | 1153 | /* Verify nvram */ |
1155 | verify = kmem_zalloc(nvlen, KM_SLEEP); | | 1154 | verify = kmem_zalloc(nvlen, KM_SLEEP); |
1156 | err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase + | | 1155 | err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase + |
1157 | bwfm->sc_chip.ch_ramsize - nvlen, verify, nvlen, 0); | | 1156 | bwfm->sc_chip.ch_ramsize - nvlen, verify, nvlen, 0); |
1158 | if (err || memcmp(verify, nvram, nvlen)) { | | 1157 | if (err || memcmp(verify, nvram, nvlen)) { |
1159 | printf("%s: nvram verification failed\n", | | 1158 | printf("%s: nvram verification failed\n", |
1160 | DEVNAME(sc)); | | 1159 | DEVNAME(sc)); |
1161 | kmem_free(verify, nvlen); | | 1160 | kmem_free(verify, nvlen); |
1162 | goto out; | | 1161 | goto out; |
1163 | } | | 1162 | } |
1164 | kmem_free(verify, nvlen); | | 1163 | kmem_free(verify, nvlen); |
1165 | | | 1164 | |
1166 | DPRINTF(("Reset core 0x%08x\n", *(uint32_t *)ucode)); | | 1165 | DPRINTF(("Reset core 0x%08x\n", *(uint32_t *)ucode)); |
1167 | /* Load reset vector from firmware and kickstart core. */ | | 1166 | /* Load reset vector from firmware and kickstart core. */ |
1168 | bwfm_chip_set_active(bwfm, *(uint32_t *)ucode); | | 1167 | bwfm_chip_set_active(bwfm, *(uint32_t *)ucode); |
1169 | | | 1168 | |
1170 | out: | | 1169 | out: |
1171 | bwfm_sdio_clkctl(sc, CLK_SDONLY, false); | | 1170 | bwfm_sdio_clkctl(sc, CLK_SDONLY, false); |
1172 | return err; | | 1171 | return err; |
1173 | } | | 1172 | } |
1174 | | | 1173 | |
1175 | static void | | 1174 | static void |
1176 | bwfm_sdio_clkctl(struct bwfm_sdio_softc *sc, enum bwfm_sdio_clkstate newstate, | | 1175 | bwfm_sdio_clkctl(struct bwfm_sdio_softc *sc, enum bwfm_sdio_clkstate newstate, |
1177 | bool pendok) | | 1176 | bool pendok) |
1178 | { | | 1177 | { |
1179 | enum bwfm_sdio_clkstate oldstate; | | 1178 | enum bwfm_sdio_clkstate oldstate; |
1180 | | | 1179 | |
1181 | oldstate = sc->sc_clkstate; | | 1180 | oldstate = sc->sc_clkstate; |
1182 | if (oldstate == newstate) | | 1181 | if (oldstate == newstate) |
1183 | return; | | 1182 | return; |
1184 | | | 1183 | |
1185 | switch (newstate) { | | 1184 | switch (newstate) { |
1186 | case CLK_AVAIL: | | 1185 | case CLK_AVAIL: |
1187 | if (oldstate == CLK_NONE) | | 1186 | if (oldstate == CLK_NONE) |
1188 | sc->sc_clkstate = CLK_SDONLY; /* XXX */ | | 1187 | sc->sc_clkstate = CLK_SDONLY; /* XXX */ |
1189 | bwfm_sdio_htclk(sc, true, pendok); | | 1188 | bwfm_sdio_htclk(sc, true, pendok); |
1190 | break; | | 1189 | break; |
1191 | case CLK_SDONLY: | | 1190 | case CLK_SDONLY: |
1192 | if (oldstate == CLK_NONE) | | 1191 | if (oldstate == CLK_NONE) |
1193 | sc->sc_clkstate = newstate; | | 1192 | sc->sc_clkstate = newstate; |
1194 | else if (oldstate == CLK_AVAIL) | | 1193 | else if (oldstate == CLK_AVAIL) |
1195 | bwfm_sdio_htclk(sc, false, false); | | 1194 | bwfm_sdio_htclk(sc, false, false); |
1196 | else | | 1195 | else |
1197 | printf("%s: clkctl %d -> %d\n", DEVNAME(sc), | | 1196 | printf("%s: clkctl %d -> %d\n", DEVNAME(sc), |
1198 | sc->sc_clkstate, newstate); | | 1197 | sc->sc_clkstate, newstate); |
1199 | break; | | 1198 | break; |
1200 | case CLK_NONE: | | 1199 | case CLK_NONE: |
1201 | if (oldstate == CLK_AVAIL) | | 1200 | if (oldstate == CLK_AVAIL) |
1202 | bwfm_sdio_htclk(sc, false, false); | | 1201 | bwfm_sdio_htclk(sc, false, false); |
1203 | sc->sc_clkstate = newstate; | | 1202 | sc->sc_clkstate = newstate; |
1204 | break; | | 1203 | break; |
1205 | default: | | 1204 | default: |
1206 | break; | | 1205 | break; |
1207 | } | | 1206 | } |
1208 | | | 1207 | |
1209 | DPRINTF(("%s: %d -> %d = %d\n", DEVNAME(sc), oldstate, newstate, | | 1208 | DPRINTF(("%s: %d -> %d = %d\n", DEVNAME(sc), oldstate, newstate, |
1210 | sc->sc_clkstate)); | | 1209 | sc->sc_clkstate)); |
1211 | } | | 1210 | } |
1212 | | | 1211 | |
1213 | static void | | 1212 | static void |
1214 | bwfm_sdio_htclk(struct bwfm_sdio_softc *sc, bool on, bool pendok) | | 1213 | bwfm_sdio_htclk(struct bwfm_sdio_softc *sc, bool on, bool pendok) |
1215 | { | | 1214 | { |
1216 | uint32_t clkctl, devctl, req; | | 1215 | uint32_t clkctl, devctl, req; |
1217 | int i; | | 1216 | int i; |
1218 | | | 1217 | |
1219 | if (sc->sc_sr_enabled) { | | 1218 | if (sc->sc_sr_enabled) { |
1220 | if (on) | | 1219 | if (on) |
1221 | sc->sc_clkstate = CLK_AVAIL; | | 1220 | sc->sc_clkstate = CLK_AVAIL; |
1222 | else | | 1221 | else |
1223 | sc->sc_clkstate = CLK_SDONLY; | | 1222 | sc->sc_clkstate = CLK_SDONLY; |
1224 | return; | | 1223 | return; |
1225 | } | | 1224 | } |
1226 | | | 1225 | |
1227 | if (on) { | | 1226 | if (on) { |
1228 | if (sc->sc_alp_only) | | 1227 | if (sc->sc_alp_only) |
1229 | req = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ; | | 1228 | req = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ; |
1230 | else | | 1229 | else |
1231 | req = BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL_REQ; | | 1230 | req = BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL_REQ; |
1232 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, req); | | 1231 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, req); |
1233 | | | 1232 | |
1234 | clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); | | 1233 | clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); |
1235 | if (!BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, sc->sc_alp_only) | | 1234 | if (!BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, sc->sc_alp_only) |
1236 | && pendok) { | | 1235 | && pendok) { |
1237 | devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL); | | 1236 | devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL); |
1238 | devctl |= BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY; | | 1237 | devctl |= BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY; |
1239 | bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl); | | 1238 | bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl); |
1240 | sc->sc_clkstate = CLK_PENDING; | | 1239 | sc->sc_clkstate = CLK_PENDING; |
1241 | return; | | 1240 | return; |
1242 | } else if (sc->sc_clkstate == CLK_PENDING) { | | 1241 | } else if (sc->sc_clkstate == CLK_PENDING) { |
1243 | devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL); | | 1242 | devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL); |
1244 | devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY; | | 1243 | devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY; |
1245 | bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl); | | 1244 | bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl); |
1246 | } | | 1245 | } |
1247 | | | 1246 | |
1248 | for (i = 0; i < 50; i++) { | | 1247 | for (i = 0; i < 50; i++) { |
1249 | if (BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, | | 1248 | if (BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, |
1250 | sc->sc_alp_only)) | | 1249 | sc->sc_alp_only)) |
1251 | break; | | 1250 | break; |
1252 | clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR | | 1251 | clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR |
1253 | ); | | 1252 | ); |
1254 | sdmmc_pause(100000, NULL); | | 1253 | sdmmc_pause(100000, NULL); |
1255 | } | | 1254 | } |
1256 | if (i >= 50) { | | 1255 | if (i >= 50) { |
1257 | printf("%s: HT avail timeout\n", DEVNAME(sc)); | | 1256 | printf("%s: HT avail timeout\n", DEVNAME(sc)); |
1258 | return; | | 1257 | return; |
1259 | } | | 1258 | } |
1260 | | | 1259 | |
1261 | sc->sc_clkstate = CLK_AVAIL; | | 1260 | sc->sc_clkstate = CLK_AVAIL; |
1262 | } else { | | 1261 | } else { |
1263 | if (sc->sc_clkstate == CLK_PENDING) { | | 1262 | if (sc->sc_clkstate == CLK_PENDING) { |
1264 | devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL); | | 1263 | devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL); |
1265 | devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY; | | 1264 | devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY; |
1266 | bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl); | | 1265 | bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl); |
1267 | } | | 1266 | } |
1268 | sc->sc_clkstate = CLK_SDONLY; | | 1267 | sc->sc_clkstate = CLK_SDONLY; |
1269 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0); | | 1268 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0); |
1270 | } | | 1269 | } |
1271 | } | | 1270 | } |
1272 | | | 1271 | |
1273 | struct bwfm_sdio_dstab { | | 1272 | struct bwfm_sdio_dstab { |
1274 | uint8_t milli; | | 1273 | uint8_t milli; |
1275 | uint8_t val; | | 1274 | uint8_t val; |
1276 | }; | | 1275 | }; |
1277 | | | 1276 | |
1278 | static struct bwfm_sdio_dstab pmu11_1v8[] = { | | 1277 | static struct bwfm_sdio_dstab pmu11_1v8[] = { |
1279 | {32, 0x6}, | | 1278 | {32, 0x6}, |
1280 | {26, 0x7}, | | 1279 | {26, 0x7}, |
1281 | {22, 0x4}, | | 1280 | {22, 0x4}, |
1282 | {16, 0x5}, | | 1281 | {16, 0x5}, |
1283 | {12, 0x2}, | | 1282 | {12, 0x2}, |
1284 | {8, 0x3}, | | 1283 | {8, 0x3}, |
1285 | {4, 0x0}, | | 1284 | {4, 0x0}, |
1286 | {0, 0x1} | | 1285 | {0, 0x1} |
1287 | }, pmu13_1v8[] = { | | 1286 | }, pmu13_1v8[] = { |
1288 | {6, 0x7}, | | 1287 | {6, 0x7}, |
1289 | {5, 0x6}, | | 1288 | {5, 0x6}, |
1290 | {4, 0x5}, | | 1289 | {4, 0x5}, |
1291 | {3, 0x4}, | | 1290 | {3, 0x4}, |
1292 | {2, 0x2}, | | 1291 | {2, 0x2}, |
1293 | {1, 0x1}, | | 1292 | {1, 0x1}, |
1294 | {0, 0x0} | | 1293 | {0, 0x0} |
1295 | }, pmu17_1v8[] = { | | 1294 | }, pmu17_1v8[] = { |
1296 | {3, 0x3}, | | 1295 | {3, 0x3}, |
1297 | {2, 0x2}, | | 1296 | {2, 0x2}, |
1298 | {1, 0x1}, | | 1297 | {1, 0x1}, |
1299 | {0, 0x0} | | 1298 | {0, 0x0} |
1300 | }, pmu17_3v3[] = { | | 1299 | }, pmu17_3v3[] = { |
1301 | {16, 0x7}, | | 1300 | {16, 0x7}, |
1302 | {12, 0x5}, | | 1301 | {12, 0x5}, |
1303 | {8, 0x3}, | | 1302 | {8, 0x3}, |
1304 | {4, 0x1}, | | 1303 | {4, 0x1}, |
1305 | {0, 0x0} | | 1304 | {0, 0x0} |
1306 | }; | | 1305 | }; |
1307 | | | 1306 | |
1308 | static void | | 1307 | static void |
1309 | bwfm_sdio_drivestrength(struct bwfm_sdio_softc *sc, unsigned milli) | | 1308 | bwfm_sdio_drivestrength(struct bwfm_sdio_softc *sc, unsigned milli) |
1310 | { | | 1309 | { |
1311 | struct bwfm_softc *bwfm = &sc->sc_sc; | | 1310 | struct bwfm_softc *bwfm = &sc->sc_sc; |
1312 | struct bwfm_core *core; | | 1311 | struct bwfm_core *core; |
1313 | struct bwfm_sdio_dstab *tab; | | 1312 | struct bwfm_sdio_dstab *tab; |
1314 | uint32_t tmp, mask; | | 1313 | uint32_t tmp, mask; |
1315 | unsigned i; | | 1314 | unsigned i; |
1316 | | | 1315 | |
1317 | if ((bwfm->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) == 0) | | 1316 | if ((bwfm->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) == 0) |
1318 | return; | | 1317 | return; |
1319 | | | 1318 | |
1320 | switch (bwfm->sc_chip.ch_chip) { | | 1319 | switch (bwfm->sc_chip.ch_chip) { |
1321 | case BRCM_CC_4330_CHIP_ID: | | 1320 | case BRCM_CC_4330_CHIP_ID: |
1322 | tab = pmu11_1v8; | | 1321 | tab = pmu11_1v8; |
1323 | mask = __BITS(11,13); | | 1322 | mask = __BITS(11,13); |
1324 | break; | | 1323 | break; |
1325 | case BRCM_CC_4334_CHIP_ID: | | 1324 | case BRCM_CC_4334_CHIP_ID: |
1326 | tab = pmu17_1v8; | | 1325 | tab = pmu17_1v8; |
1327 | mask = __BITS(11,12); | | 1326 | mask = __BITS(11,12); |
1328 | break; | | 1327 | break; |
1329 | case BRCM_CC_43143_CHIP_ID: | | 1328 | case BRCM_CC_43143_CHIP_ID: |
1330 | tab = pmu17_3v3; | | 1329 | tab = pmu17_3v3; |
1331 | mask = __BITS(0,3); | | 1330 | mask = __BITS(0,3); |
1332 | break; | | 1331 | break; |
1333 | case BRCM_CC_43362_CHIP_ID: | | 1332 | case BRCM_CC_43362_CHIP_ID: |
1334 | tab = pmu13_1v8; | | 1333 | tab = pmu13_1v8; |
1335 | mask = __BITS(11,13); | | 1334 | mask = __BITS(11,13); |
1336 | break; | | 1335 | break; |
1337 | default: | | 1336 | default: |
1338 | return; | | 1337 | return; |
1339 | } | | 1338 | } |
1340 | | | 1339 | |
1341 | for (i=0; tab[i].milli != 0; ++i) { | | 1340 | for (i=0; tab[i].milli != 0; ++i) { |
1342 | if (milli >= tab[i].milli) | | 1341 | if (milli >= tab[i].milli) |
1343 | break; | | 1342 | break; |
1344 | } | | 1343 | } |
1345 | if (tab[i].milli == 0) | | 1344 | if (tab[i].milli == 0) |
1346 | return; | | 1345 | return; |
1347 | | | 1346 | |
1348 | core = bwfm_chip_get_pmu(&sc->sc_sc); | | 1347 | core = bwfm_chip_get_pmu(&sc->sc_sc); |
1349 | tmp = bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_CHIPCONTROL_ADDR); | | 1348 | tmp = bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_CHIPCONTROL_ADDR); |
1350 | tmp &= mask; | | 1349 | tmp &= mask; |
1351 | tmp |= __SHIFTIN(tab[i].val, mask); | | 1350 | tmp |= __SHIFTIN(tab[i].val, mask); |
1352 | bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_CHIPCONTROL_ADDR, tmp); | | 1351 | bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_CHIPCONTROL_ADDR, tmp); |
1353 | } | | 1352 | } |
1354 | | | 1353 | |
1355 | | | 1354 | |
1356 | #if notyet | | 1355 | #if notyet |
1357 | static int | | 1356 | static int |
1358 | bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *sc, bool sleep, bool pendok) | | 1357 | bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *sc, bool sleep, bool pendok) |
1359 | { | | 1358 | { |
1360 | uint32_t clkctl; | | 1359 | uint32_t clkctl; |
1361 | | | 1360 | |
1362 | if (sc->sleeping == sleep) | | 1361 | if (sc->sleeping == sleep) |
1363 | return 0; | | 1362 | return 0; |
1364 | | | 1363 | |
1365 | if (sc->sc_sr_enabled) { | | 1364 | if (sc->sc_sr_enabled) { |
1366 | if (sleep) { | | 1365 | if (sleep) { |
1367 | clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); | | 1366 | clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); |
1368 | if ((clkctl & BWFM_SDIO_FUNC1_CHIPCLKCSR_CSR_MASK) == 0) | | 1367 | if ((clkctl & BWFM_SDIO_FUNC1_CHIPCLKCSR_CSR_MASK) == 0) |
1369 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ); | | 1368 | bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ); |
1370 | } | | 1369 | } |
1371 | /* kso_ctrl(sc, sleep) */ | | 1370 | /* kso_ctrl(sc, sleep) */ |
1372 | } | | 1371 | } |
1373 | | | 1372 | |
1374 | if (sleep) { | | 1373 | if (sleep) { |
1375 | if (!sc->sc_sr_enabled) | | 1374 | if (!sc->sc_sr_enabled) |
1376 | bwfm_sdio_clkctl(sc, CLK_NONE, pendok); | | 1375 | bwfm_sdio_clkctl(sc, CLK_NONE, pendok); |
1377 | } else { | | 1376 | } else { |
1378 | bwfm_sdio_clkctl(sc, CLK_AVAIL, pendok); | | 1377 | bwfm_sdio_clkctl(sc, CLK_AVAIL, pendok); |
1379 | } | | 1378 | } |
1380 | | | 1379 | |
1381 | sc->sleeping = sleep; | | 1380 | sc->sleeping = sleep; |
1382 | | | 1381 | |
1383 | return 0; | | 1382 | return 0; |
1384 | } | | 1383 | } |
1385 | #endif | | 1384 | #endif |
1386 | | | 1385 | |
1387 | static void | | 1386 | static void |
1388 | bwfm_sdio_readshared(struct bwfm_sdio_softc *sc) | | 1387 | bwfm_sdio_readshared(struct bwfm_sdio_softc *sc) |
1389 | { | | 1388 | { |
1390 | struct bwfm_softc *bwfm = &sc->sc_sc; | | 1389 | struct bwfm_softc *bwfm = &sc->sc_sc; |
1391 | struct bwfm_sdio_sdpcm sdpcm; | | 1390 | struct bwfm_sdio_sdpcm sdpcm; |
1392 | uint32_t addr, shaddr; | | 1391 | uint32_t addr, shaddr; |
1393 | int err; | | 1392 | int err; |
1394 | | | 1393 | |
1395 | bwfm_sdio_clkctl(sc, CLK_AVAIL, false); | | 1394 | bwfm_sdio_clkctl(sc, CLK_AVAIL, false); |
1396 | if (sc->sc_clkstate != CLK_AVAIL) | | 1395 | if (sc->sc_clkstate != CLK_AVAIL) |
1397 | return; | | 1396 | return; |
1398 | | | 1397 | |
1399 | shaddr = bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4; | | 1398 | shaddr = bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4; |
1400 | if (!bwfm->sc_chip.ch_rambase && sc->sc_sr_enabled) | | 1399 | if (!bwfm->sc_chip.ch_rambase && sc->sc_sr_enabled) |
1401 | shaddr -= bwfm->sc_chip.ch_srsize; | | 1400 | shaddr -= bwfm->sc_chip.ch_srsize; |
1402 | | | 1401 | |
1403 | err = bwfm_sdio_ram_read_write(sc, shaddr, (char *)&addr, | | 1402 | err = bwfm_sdio_ram_read_write(sc, shaddr, (char *)&addr, |
1404 | sizeof(addr), 0); | | 1403 | sizeof(addr), 0); |
1405 | if (err) | | 1404 | if (err) |
1406 | return; | | 1405 | return; |
1407 | | | 1406 | |
1408 | addr = le32toh(addr); | | 1407 | addr = le32toh(addr); |
1409 | if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) | | 1408 | if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) |
1410 | return; | | 1409 | return; |
1411 | | | 1410 | |
1412 | err = bwfm_sdio_ram_read_write(sc, addr, (char *)&sdpcm, | | 1411 | err = bwfm_sdio_ram_read_write(sc, addr, (char *)&sdpcm, |
1413 | sizeof(sdpcm), 0); | | 1412 | sizeof(sdpcm), 0); |
1414 | if (err) | | 1413 | if (err) |
1415 | return; | | 1414 | return; |
1416 | | | 1415 | |
1417 | sc->sc_console_addr = le32toh(sdpcm.console_addr); | | 1416 | sc->sc_console_addr = le32toh(sdpcm.console_addr); |
1418 | } | | 1417 | } |
1419 | | | 1418 | |
1420 | static int | | 1419 | static int |
1421 | bwfm_sdio_intr1(void *v, const char *name) | | 1420 | bwfm_sdio_intr1(void *v, const char *name) |
1422 | { | | 1421 | { |
1423 | struct bwfm_sdio_softc *sc = (void *)v; | | 1422 | struct bwfm_sdio_softc *sc = (void *)v; |
1424 | | | 1423 | |
1425 | DPRINTF(("%s: %s\n", DEVNAME(sc), name)); | | 1424 | DPRINTF(("%s: %s\n", DEVNAME(sc), name)); |
1426 | | | 1425 | |
1427 | sdmmc_add_task(sc->sc_sf[1]->sc, &sc->sc_task); | | 1426 | sdmmc_add_task(sc->sc_sf[1]->sc, &sc->sc_task); |
1428 | return 1; | | 1427 | return 1; |
1429 | } | | 1428 | } |
1430 | | | 1429 | |
1431 | static int | | 1430 | static int |
1432 | bwfm_sdio_intr(void *v) | | 1431 | bwfm_sdio_intr(void *v) |
1433 | { | | 1432 | { |
1434 | return bwfm_sdio_intr1(v, "sdio_intr"); | | 1433 | return bwfm_sdio_intr1(v, "sdio_intr"); |
1435 | } | | 1434 | } |
1436 | | | 1435 | |
1437 | static void | | 1436 | static void |
1438 | bwfm_sdio_task(void *v) | | 1437 | bwfm_sdio_task(void *v) |
1439 | { | | 1438 | { |
1440 | struct bwfm_sdio_softc *sc = (void *)v; | | 1439 | struct bwfm_sdio_softc *sc = (void *)v; |
1441 | | | 1440 | |
1442 | mutex_enter(&sc->sc_lock); | | 1441 | mutex_enter(&sc->sc_lock); |
1443 | bwfm_sdio_task1(sc); | | 1442 | bwfm_sdio_task1(sc); |
1444 | #ifdef BWFM_DEBUG | | 1443 | #ifdef BWFM_DEBUG |
1445 | bwfm_sdio_debug_console(sc); | | 1444 | bwfm_sdio_debug_console(sc); |
1446 | #endif | | 1445 | #endif |
1447 | mutex_exit(&sc->sc_lock); | | 1446 | mutex_exit(&sc->sc_lock); |
1448 | } | | 1447 | } |
1449 | | | 1448 | |
1450 | static void | | 1449 | static void |
1451 | bwfm_sdio_task1(struct bwfm_sdio_softc *sc) | | 1450 | bwfm_sdio_task1(struct bwfm_sdio_softc *sc) |
1452 | { | | 1451 | { |
1453 | uint32_t clkctl, devctl, intstat, hostint; | | 1452 | uint32_t clkctl, devctl, intstat, hostint; |
1454 | bool dorecv, dosend; | | 1453 | bool dorecv, dosend; |
1455 | | | 1454 | |
1456 | if (!sc->sc_sr_enabled && sc->sc_clkstate == CLK_PENDING) { | | 1455 | if (!sc->sc_sr_enabled && sc->sc_clkstate == CLK_PENDING) { |
1457 | clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); | | 1456 | clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR); |
1458 | if (BWFM_SDIO_FUNC1_CHIPCLKCSR_HTAV(clkctl)) { | | 1457 | if (BWFM_SDIO_FUNC1_CHIPCLKCSR_HTAV(clkctl)) { |
1459 | devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL); | | 1458 | devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL); |
1460 | devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY; | | 1459 | devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY; |
1461 | bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl); | | 1460 | bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl); |
1462 | sc->sc_clkstate = CLK_AVAIL; | | 1461 | sc->sc_clkstate = CLK_AVAIL; |
1463 | } | | 1462 | } |
1464 | } | | 1463 | } |
1465 | | | 1464 | |
1466 | dorecv = dosend = sc->sc_clkstate == CLK_AVAIL; | | 1465 | dorecv = dosend = sc->sc_clkstate == CLK_AVAIL; |
1467 | | | 1466 | |
1468 | intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS); | | 1467 | intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS); |
1469 | DPRINTF(("%s: intstat 0x%" PRIx32 "\n", DEVNAME(sc), intstat)); | | 1468 | DPRINTF(("%s: intstat 0x%" PRIx32 "\n", DEVNAME(sc), intstat)); |
1470 | intstat &= (SDPCMD_INTSTATUS_HMB_SW_MASK|SDPCMD_INTSTATUS_CHIPACTIVE); | | 1469 | intstat &= (SDPCMD_INTSTATUS_HMB_SW_MASK|SDPCMD_INTSTATUS_CHIPACTIVE); |
1471 | if (intstat) | | 1470 | if (intstat) |
1472 | bwfm_sdio_dev_write(sc, BWFM_SDPCMD_INTSTATUS, intstat); | | 1471 | bwfm_sdio_dev_write(sc, BWFM_SDPCMD_INTSTATUS, intstat); |
1473 | | | 1472 | |
1474 | if (intstat & SDPCMD_INTSTATUS_CHIPACTIVE) | | 1473 | if (intstat & SDPCMD_INTSTATUS_CHIPACTIVE) |
1475 | printf("%s: CHIPACTIVE\n", DEVNAME(sc)); | | 1474 | printf("%s: CHIPACTIVE\n", DEVNAME(sc)); |
1476 | | | 1475 | |
1477 | if (intstat & SDPCMD_INTSTATUS_HMB_HOST_INT) { | | 1476 | if (intstat & SDPCMD_INTSTATUS_HMB_HOST_INT) { |
1478 | hostint = bwfm_sdio_dev_read(sc, SDPCMD_TOHOSTMAILBOXDATA); | | 1477 | hostint = bwfm_sdio_dev_read(sc, SDPCMD_TOHOSTMAILBOXDATA); |
1479 | DPRINTF(("%s: hostint 0x%" PRIx32 "\n", DEVNAME(sc), hostint)); | | 1478 | DPRINTF(("%s: hostint 0x%" PRIx32 "\n", DEVNAME(sc), hostint)); |
1480 | bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOX, | | 1479 | bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOX, |
1481 | SDPCMD_TOSBMAILBOX_INT_ACK); | | 1480 | SDPCMD_TOSBMAILBOX_INT_ACK); |
1482 | if (hostint & SDPCMD_TOHOSTMAILBOXDATA_NAKHANDLED) | | 1481 | if (hostint & SDPCMD_TOHOSTMAILBOXDATA_NAKHANDLED) |
1483 | sc->sc_rxskip = false; | | 1482 | sc->sc_rxskip = false; |
1484 | if (hostint & SDPCMD_TOHOSTMAILBOXDATA_DEVREADY || | | 1483 | if (hostint & SDPCMD_TOHOSTMAILBOXDATA_DEVREADY || |
1485 | hostint & SDPCMD_TOHOSTMAILBOXDATA_FWREADY) | | 1484 | hostint & SDPCMD_TOHOSTMAILBOXDATA_FWREADY) |
1486 | bwfm_sdio_readshared(sc); | | 1485 | bwfm_sdio_readshared(sc); |
1487 | } | | 1486 | } |
1488 | | | 1487 | |
1489 | if (intstat & SDPCMD_INTSTATUS_HMB_FRAME_IND) { | | 1488 | if (intstat & SDPCMD_INTSTATUS_HMB_FRAME_IND) { |
1490 | /* ignore receive indications while recovering */ | | 1489 | /* ignore receive indications while recovering */ |
1491 | if (dorecv && !sc->sc_rxskip) { | | 1490 | if (dorecv && !sc->sc_rxskip) { |
1492 | DPRINTF(("%s: recv\n", DEVNAME(sc))); | | 1491 | DPRINTF(("%s: recv\n", DEVNAME(sc))); |
1493 | bwfm_sdio_rx_frames(sc); | | 1492 | bwfm_sdio_rx_frames(sc); |
1494 | } | | 1493 | } |
1495 | } | | 1494 | } |
1496 | | | 1495 | |
1497 | if (intstat & SDPCMD_INTSTATUS_HMB_FC_STATE) | | 1496 | if (intstat & SDPCMD_INTSTATUS_HMB_FC_STATE) |
1498 | dosend = false; | | 1497 | dosend = false; |
1499 | | | 1498 | |
1500 | if (intstat & SDPCMD_INTSTATUS_HMB_FC_CHANGE) { | | 1499 | if (intstat & SDPCMD_INTSTATUS_HMB_FC_CHANGE) { |
1501 | if (dosend) { | | 1500 | if (dosend) { |
1502 | intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS); | | 1501 | intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS); |
1503 | DPRINTF(("%s: intstat2 0x%" PRIx32 "\n", DEVNAME(sc), intstat)); | | 1502 | DPRINTF(("%s: intstat2 0x%" PRIx32 "\n", DEVNAME(sc), intstat)); |
1504 | if (intstat & (SDPCMD_INTSTATUS_HMB_FC_STATE | SDPCMD_INTSTATUS_HMB_FC_CHANGE)) | | 1503 | if (intstat & (SDPCMD_INTSTATUS_HMB_FC_STATE | SDPCMD_INTSTATUS_HMB_FC_CHANGE)) |
1505 | dosend = false; | | 1504 | dosend = false; |
1506 | } | | 1505 | } |
1507 | } | | 1506 | } |
1508 | | | 1507 | |
1509 | if (!dosend && MBUFQ_FIRST(&sc->sc_tx_queue)) printf("%s: flowctl\n", DEVNAME(sc)); | | 1508 | if (!dosend && MBUFQ_FIRST(&sc->sc_tx_queue)) printf("%s: flowctl\n", DEVNAME(sc)); |