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