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 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 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 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 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 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 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 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