]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/rtwn/if_rtwn_efuse.c
zfs: merge OpenZFS master-436ab35a5
[FreeBSD/FreeBSD.git] / sys / dev / rtwn / if_rtwn_efuse.c
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 __FBSDID("$FreeBSD$");
23
24 #include "opt_wlan.h"
25
26 #include <sys/param.h>
27 #include <sys/lock.h>
28 #include <sys/mutex.h>
29 #include <sys/mbuf.h>
30 #include <sys/kernel.h>
31 #include <sys/socket.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/queue.h>
35 #include <sys/taskqueue.h>
36 #include <sys/bus.h>
37 #include <sys/endian.h>
38
39 #include <net/if.h>
40 #include <net/ethernet.h>
41 #include <net/if_media.h>
42
43 #include <net80211/ieee80211_var.h>
44 #include <net80211/ieee80211_radiotap.h>
45
46 #include <dev/rtwn/if_rtwnreg.h>
47 #include <dev/rtwn/if_rtwnvar.h>
48
49 #include <dev/rtwn/if_rtwn_debug.h>
50 #include <dev/rtwn/if_rtwn_efuse.h>
51
52 #include <dev/rtwn/rtl8192c/r92c_reg.h>
53
54 static int
55 rtwn_efuse_switch_power(struct rtwn_softc *sc)
56 {
57         uint32_t reg;
58         int error;
59
60         error = rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON);
61         if (error != 0)
62                 return (error);
63
64         reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
65         if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
66                 error = rtwn_write_2(sc, R92C_SYS_FUNC_EN,
67                     reg | R92C_SYS_FUNC_EN_ELDR);
68                 if (error != 0)
69                         return (error);
70         }
71         reg = rtwn_read_2(sc, R92C_SYS_CLKR);
72         if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
73             (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
74                 error = rtwn_write_2(sc, R92C_SYS_CLKR,
75                     reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
76                 if (error != 0)
77                         return (error);
78         }
79
80         return (0);
81 }
82
83 int
84 rtwn_efuse_read_next(struct rtwn_softc *sc, uint8_t *val)
85 {
86         uint32_t reg;
87         int ntries, error;
88
89         if (sc->next_rom_addr >= sc->efuse_maxlen)
90                 return (EFAULT);
91
92         reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
93         reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->next_rom_addr);
94         reg &= ~R92C_EFUSE_CTRL_VALID;
95
96         error = rtwn_write_4(sc, R92C_EFUSE_CTRL, reg);
97         if (error != 0)
98                 return (error);
99         /* Wait for read operation to complete. */
100         for (ntries = 0; ntries < 100; ntries++) {
101                 reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
102                 if (reg & R92C_EFUSE_CTRL_VALID)
103                         break;
104                 rtwn_delay(sc, 10);
105         }
106         if (ntries == 100) {
107                 device_printf(sc->sc_dev,
108                     "could not read efuse byte at address 0x%x\n",
109                     sc->next_rom_addr);
110                 return (ETIMEDOUT);
111         }
112
113         *val = MS(reg, R92C_EFUSE_CTRL_DATA);
114         sc->next_rom_addr++;
115
116         return (0);
117 }
118
119 static int
120 rtwn_efuse_read_data(struct rtwn_softc *sc, uint8_t *rom, uint8_t off,
121     uint8_t msk)
122 {
123         uint8_t reg;
124         int addr, i, error;
125
126         for (i = 0; i < 4; i++) {
127                 if (msk & (1 << i))
128                         continue;
129
130                 addr = off * 8 + i * 2;
131                 if (addr + 1 >= sc->efuse_maplen)
132                         return (EFAULT);
133
134                 error = rtwn_efuse_read_next(sc, &reg);
135                 if (error != 0)
136                         return (error);
137                 RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n",
138                     addr, reg);
139                 rom[addr] = reg;
140
141                 error = rtwn_efuse_read_next(sc, &reg);
142                 if (error != 0)
143                         return (error);
144                 RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n",
145                     addr + 1, reg);
146                 rom[addr + 1] = reg;
147         }
148
149         return (0);
150 }
151
152 #ifdef RTWN_DEBUG
153 static void
154 rtwn_dump_rom_contents(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
155 {
156         int i;
157
158         /* Dump ROM contents. */
159         device_printf(sc->sc_dev, "%s:", __func__);
160         for (i = 0; i < size; i++) {
161                 if (i % 32 == 0)
162                         printf("\n%03X: ", i);
163                 else if (i % 4 == 0)
164                         printf(" ");
165
166                 printf("%02X", rom[i]);
167         }
168         printf("\n");
169 }
170 #endif
171
172 static int
173 rtwn_efuse_read(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
174 {
175 #define RTWN_CHK(res) do {      \
176         if ((error = res) != 0) \
177                 goto end;       \
178 } while(0)
179         uint8_t msk, off, reg;
180         int error;
181
182         /* Read full ROM image. */
183         sc->next_rom_addr = 0;
184         memset(rom, 0xff, size);
185
186         RTWN_CHK(rtwn_efuse_read_next(sc, &reg));
187         while (reg != 0xff) {
188                 /* check for extended header */
189                 if ((sc->sc_flags & RTWN_FLAG_EXT_HDR) &&
190                     (reg & 0x1f) == 0x0f) {
191                         off = reg >> 5;
192                         RTWN_CHK(rtwn_efuse_read_next(sc, &reg));
193
194                         if ((reg & 0x0f) != 0x0f)
195                                 off = ((reg & 0xf0) >> 1) | off;
196                         else
197                                 continue;
198                 } else
199                         off = reg >> 4;
200                 msk = reg & 0xf;
201
202                 RTWN_CHK(rtwn_efuse_read_data(sc, rom, off, msk));
203                 RTWN_CHK(rtwn_efuse_read_next(sc, &reg));
204         }
205
206 end:
207
208 #ifdef RTWN_DEBUG
209         if (sc->sc_debug & RTWN_DEBUG_ROM)
210                 rtwn_dump_rom_contents(sc, rom, size);
211 #endif
212
213         /* Device-specific. */
214         rtwn_efuse_postread(sc);
215
216         if (error != 0) {
217                 device_printf(sc->sc_dev, "%s: error while reading ROM\n",
218                     __func__);
219         }
220
221         return (error);
222 #undef RTWN_CHK
223 }
224
225 static int
226 rtwn_efuse_read_prepare(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
227 {
228         int error;
229
230         error = rtwn_efuse_switch_power(sc);
231         if (error != 0)
232                 goto fail;
233
234         error = rtwn_efuse_read(sc, rom, size);
235
236 fail:
237         rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF);
238
239         return (error);
240 }
241
242 int
243 rtwn_read_rom(struct rtwn_softc *sc)
244 {
245         uint8_t *rom;
246         int error;
247
248         rom = malloc(sc->efuse_maplen, M_TEMP, M_WAITOK);
249
250         /* Read full ROM image. */
251         RTWN_LOCK(sc);
252         error = rtwn_efuse_read_prepare(sc, rom, sc->efuse_maplen);
253         RTWN_UNLOCK(sc);
254         if (error != 0)
255                 goto fail;
256
257         /* Parse & save data in softc. */
258         rtwn_parse_rom(sc, rom);
259
260 fail:
261         free(rom, M_TEMP);
262
263         return (error);
264 }