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, ®); 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, ®); 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, ®)); 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, ®)); 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, ®)); 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 } 265