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