diff options
Diffstat (limited to 'freebsd/sys/dev/rtwn/if_rtwn_efuse.c')
-rw-r--r-- | freebsd/sys/dev/rtwn/if_rtwn_efuse.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_efuse.c b/freebsd/sys/dev/rtwn/if_rtwn_efuse.c new file mode 100644 index 00000000..bdf28a5d --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_efuse.c @@ -0,0 +1,267 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> + * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <rtems/bsd/local/opt_wlan.h> + +#include <rtems/bsd/sys/param.h> +#include <rtems/bsd/sys/lock.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/taskqueue.h> +#include <sys/bus.h> +#include <sys/endian.h> + +#include <net/if.h> +#include <net/ethernet.h> +#include <net/if_media.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_radiotap.h> + +#include <dev/rtwn/if_rtwnreg.h> +#include <dev/rtwn/if_rtwnvar.h> + +#include <dev/rtwn/if_rtwn_debug.h> +#include <dev/rtwn/if_rtwn_efuse.h> + +#include <dev/rtwn/rtl8192c/r92c_reg.h> + + +static int +rtwn_efuse_switch_power(struct rtwn_softc *sc) +{ + uint32_t reg; + int error; + + error = rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON); + if (error != 0) + return (error); + + reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN); + if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { + error = rtwn_write_2(sc, R92C_SYS_FUNC_EN, + reg | R92C_SYS_FUNC_EN_ELDR); + if (error != 0) + return (error); + } + reg = rtwn_read_2(sc, R92C_SYS_CLKR); + if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != + (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { + error = rtwn_write_2(sc, R92C_SYS_CLKR, + reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); + if (error != 0) + return (error); + } + + return (0); +} + +int +rtwn_efuse_read_next(struct rtwn_softc *sc, uint8_t *val) +{ + uint32_t reg; + int ntries, error; + + if (sc->next_rom_addr >= sc->efuse_maxlen) + return (EFAULT); + + reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); + reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->next_rom_addr); + reg &= ~R92C_EFUSE_CTRL_VALID; + + error = rtwn_write_4(sc, R92C_EFUSE_CTRL, reg); + if (error != 0) + return (error); + /* Wait for read operation to complete. */ + for (ntries = 0; ntries < 100; ntries++) { + reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); + if (reg & R92C_EFUSE_CTRL_VALID) + break; + rtwn_delay(sc, 10); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "could not read efuse byte at address 0x%x\n", + sc->next_rom_addr); + return (ETIMEDOUT); + } + + *val = MS(reg, R92C_EFUSE_CTRL_DATA); + sc->next_rom_addr++; + + return (0); +} + +static int +rtwn_efuse_read_data(struct rtwn_softc *sc, uint8_t *rom, uint8_t off, + uint8_t msk) +{ + uint8_t reg; + int addr, i, error; + + for (i = 0; i < 4; i++) { + if (msk & (1 << i)) + continue; + + addr = off * 8 + i * 2; + if (addr + 1 >= sc->efuse_maplen) + return (EFAULT); + + error = rtwn_efuse_read_next(sc, ®); + if (error != 0) + return (error); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n", + addr, reg); + rom[addr] = reg; + + error = rtwn_efuse_read_next(sc, ®); + if (error != 0) + return (error); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n", + addr + 1, reg); + rom[addr + 1] = reg; + } + + return (0); +} + +#ifdef RTWN_DEBUG +static void +rtwn_dump_rom_contents(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ + int i; + + /* Dump ROM contents. */ + device_printf(sc->sc_dev, "%s:", __func__); + for (i = 0; i < size; i++) { + if (i % 32 == 0) + printf("\n%03X: ", i); + else if (i % 4 == 0) + printf(" "); + + printf("%02X", rom[i]); + } + printf("\n"); +} +#endif + +static int +rtwn_efuse_read(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ +#define RTWN_CHK(res) do { \ + if ((error = res) != 0) \ + goto end; \ +} while(0) + uint8_t msk, off, reg; + int error; + + /* Read full ROM image. */ + sc->next_rom_addr = 0; + memset(rom, 0xff, size); + + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + while (reg != 0xff) { + /* check for extended header */ + if ((sc->sc_flags & RTWN_FLAG_EXT_HDR) && + (reg & 0x1f) == 0x0f) { + off = reg >> 5; + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + + if ((reg & 0x0f) != 0x0f) + off = ((reg & 0xf0) >> 1) | off; + else + continue; + } else + off = reg >> 4; + msk = reg & 0xf; + + RTWN_CHK(rtwn_efuse_read_data(sc, rom, off, msk)); + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + } + +end: + +#ifdef RTWN_DEBUG + if (sc->sc_debug & RTWN_DEBUG_ROM) + rtwn_dump_rom_contents(sc, rom, size); +#endif + + /* Device-specific. */ + rtwn_efuse_postread(sc); + + if (error != 0) { + device_printf(sc->sc_dev, "%s: error while reading ROM\n", + __func__); + } + + return (error); +#undef RTWN_CHK +} + +static int +rtwn_efuse_read_prepare(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ + int error; + + error = rtwn_efuse_switch_power(sc); + if (error != 0) + goto fail; + + error = rtwn_efuse_read(sc, rom, size); + +fail: + rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF); + + return (error); +} + +int +rtwn_read_rom(struct rtwn_softc *sc) +{ + uint8_t *rom; + int error; + + rom = malloc(sc->efuse_maplen, M_TEMP, M_WAITOK); + + /* Read full ROM image. */ + RTWN_LOCK(sc); + error = rtwn_efuse_read_prepare(sc, rom, sc->efuse_maplen); + RTWN_UNLOCK(sc); + if (error != 0) + goto fail; + + /* Parse & save data in softc. */ + rtwn_parse_rom(sc, rom); + +fail: + free(rom, M_TEMP); + + return (error); +} |