1 /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <sys/cdefs.h>
22 #include "opt_wlan.h"
23
24 #include <sys/param.h>
25 #include <sys/lock.h>
26 #include <sys/mutex.h>
27 #include <sys/mbuf.h>
28 #include <sys/kernel.h>
29 #include <sys/socket.h>
30 #include <sys/systm.h>
31 #include <sys/malloc.h>
32 #include <sys/queue.h>
33 #include <sys/taskqueue.h>
34 #include <sys/bus.h>
35 #include <sys/endian.h>
36
37 #include <net/if.h>
38 #include <net/ethernet.h>
39 #include <net/if_media.h>
40
41 #include <net80211/ieee80211_var.h>
42 #include <net80211/ieee80211_radiotap.h>
43
44 #include <dev/rtwn/if_rtwnreg.h>
45 #include <dev/rtwn/if_rtwnvar.h>
46
47 #include <dev/rtwn/if_rtwn_debug.h>
48 #include <dev/rtwn/if_rtwn_efuse.h>
49
50 #include <dev/rtwn/rtl8192c/r92c_reg.h>
51
52 static int
rtwn_efuse_switch_power(struct rtwn_softc * sc)53 rtwn_efuse_switch_power(struct rtwn_softc *sc)
54 {
55 uint32_t reg;
56 int error;
57
58 error = rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON);
59 if (error != 0)
60 return (error);
61
62 reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
63 if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
64 error = rtwn_write_2(sc, R92C_SYS_FUNC_EN,
65 reg | R92C_SYS_FUNC_EN_ELDR);
66 if (error != 0)
67 return (error);
68 }
69 reg = rtwn_read_2(sc, R92C_SYS_CLKR);
70 if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
71 (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
72 error = rtwn_write_2(sc, R92C_SYS_CLKR,
73 reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
74 if (error != 0)
75 return (error);
76 }
77
78 return (0);
79 }
80
81 int
rtwn_efuse_read_next(struct rtwn_softc * sc,uint8_t * val)82 rtwn_efuse_read_next(struct rtwn_softc *sc, uint8_t *val)
83 {
84 uint32_t reg;
85 int ntries, error;
86
87 if (sc->next_rom_addr >= sc->efuse_maxlen)
88 return (EFAULT);
89
90 reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
91 reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->next_rom_addr);
92 reg &= ~R92C_EFUSE_CTRL_VALID;
93
94 error = rtwn_write_4(sc, R92C_EFUSE_CTRL, reg);
95 if (error != 0)
96 return (error);
97 /* Wait for read operation to complete. */
98 for (ntries = 0; ntries < 100; ntries++) {
99 reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
100 if (reg & R92C_EFUSE_CTRL_VALID)
101 break;
102 rtwn_delay(sc, 10);
103 }
104 if (ntries == 100) {
105 device_printf(sc->sc_dev,
106 "could not read efuse byte at address 0x%x\n",
107 sc->next_rom_addr);
108 return (ETIMEDOUT);
109 }
110
111 *val = MS(reg, R92C_EFUSE_CTRL_DATA);
112 sc->next_rom_addr++;
113
114 return (0);
115 }
116
117 static int
rtwn_efuse_read_data(struct rtwn_softc * sc,uint8_t * rom,uint8_t off,uint8_t msk)118 rtwn_efuse_read_data(struct rtwn_softc *sc, uint8_t *rom, uint8_t off,
119 uint8_t msk)
120 {
121 uint8_t reg;
122 int addr, i, error;
123
124 for (i = 0; i < 4; i++) {
125 if (msk & (1 << i))
126 continue;
127
128 addr = off * 8 + i * 2;
129 if (addr + 1 >= sc->efuse_maplen)
130 return (EFAULT);
131
132 error = rtwn_efuse_read_next(sc, ®);
133 if (error != 0)
134 return (error);
135 RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n",
136 addr, reg);
137 rom[addr] = reg;
138
139 error = rtwn_efuse_read_next(sc, ®);
140 if (error != 0)
141 return (error);
142 RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n",
143 addr + 1, reg);
144 rom[addr + 1] = reg;
145 }
146
147 return (0);
148 }
149
150 #ifdef RTWN_DEBUG
151 static void
rtwn_dump_rom_contents(struct rtwn_softc * sc,uint8_t * rom,uint16_t size)152 rtwn_dump_rom_contents(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
153 {
154 int i;
155
156 /* Dump ROM contents. */
157 device_printf(sc->sc_dev, "%s:", __func__);
158 for (i = 0; i < size; i++) {
159 if (i % 32 == 0)
160 printf("\n%03X: ", i);
161 else if (i % 4 == 0)
162 printf(" ");
163
164 printf("%02X", rom[i]);
165 }
166 printf("\n");
167 }
168 #endif
169
170 static int
rtwn_efuse_read(struct rtwn_softc * sc,uint8_t * rom,uint16_t size)171 rtwn_efuse_read(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
172 {
173 #define RTWN_CHK(res) do { \
174 if ((error = res) != 0) \
175 goto end; \
176 } while(0)
177 uint8_t msk, off, reg;
178 int error;
179
180 /* Read full ROM image. */
181 sc->next_rom_addr = 0;
182 memset(rom, 0xff, size);
183
184 RTWN_CHK(rtwn_efuse_read_next(sc, ®));
185 while (reg != 0xff) {
186 /* check for extended header */
187 if ((sc->sc_flags & RTWN_FLAG_EXT_HDR) &&
188 (reg & 0x1f) == 0x0f) {
189 off = reg >> 5;
190 RTWN_CHK(rtwn_efuse_read_next(sc, ®));
191
192 if ((reg & 0x0f) != 0x0f)
193 off = ((reg & 0xf0) >> 1) | off;
194 else
195 continue;
196 } else
197 off = reg >> 4;
198 msk = reg & 0xf;
199
200 RTWN_CHK(rtwn_efuse_read_data(sc, rom, off, msk));
201 RTWN_CHK(rtwn_efuse_read_next(sc, ®));
202 }
203
204 end:
205
206 #ifdef RTWN_DEBUG
207 if (sc->sc_debug & RTWN_DEBUG_ROM)
208 rtwn_dump_rom_contents(sc, rom, size);
209 #endif
210
211 /* Device-specific. */
212 rtwn_efuse_postread(sc);
213
214 if (error != 0) {
215 device_printf(sc->sc_dev, "%s: error while reading ROM\n",
216 __func__);
217 }
218
219 return (error);
220 #undef RTWN_CHK
221 }
222
223 static int
rtwn_efuse_read_prepare(struct rtwn_softc * sc,uint8_t * rom,uint16_t size)224 rtwn_efuse_read_prepare(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
225 {
226 int error;
227
228 error = rtwn_efuse_switch_power(sc);
229 if (error != 0)
230 goto fail;
231
232 error = rtwn_efuse_read(sc, rom, size);
233
234 fail:
235 rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF);
236
237 return (error);
238 }
239
240 int
rtwn_read_rom(struct rtwn_softc * sc)241 rtwn_read_rom(struct rtwn_softc *sc)
242 {
243 uint8_t *rom;
244 int error;
245
246 rom = malloc(sc->efuse_maplen, M_TEMP, M_WAITOK);
247
248 /* Read full ROM image. */
249 RTWN_LOCK(sc);
250 error = rtwn_efuse_read_prepare(sc, rom, sc->efuse_maplen);
251 RTWN_UNLOCK(sc);
252 if (error != 0)
253 goto fail;
254
255 /* Parse & save data in softc. */
256 rtwn_parse_rom(sc, rom);
257
258 fail:
259 free(rom, M_TEMP);
260
261 return (error);
262 }
263