The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
    5  * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
    6  * Copyright (c) 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 #include <sys/linker.h>
   39 
   40 #include <machine/bus.h>
   41 #include <machine/resource.h>
   42 #include <sys/rman.h>
   43 
   44 #include <net/if.h>
   45 #include <net/ethernet.h>
   46 #include <net/if_media.h>
   47 
   48 #include <net80211/ieee80211_var.h>
   49 #include <net80211/ieee80211_radiotap.h>
   50 
   51 #include <dev/rtwn/if_rtwnreg.h>
   52 #include <dev/rtwn/if_rtwnvar.h>
   53 #include <dev/rtwn/if_rtwn_debug.h>
   54 
   55 #include <dev/rtwn/pci/rtwn_pci_var.h>
   56 
   57 #include <dev/rtwn/rtl8192c/pci/r92ce.h>
   58 #include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
   59 
   60 /* Registers to save and restore during IQ calibration. */
   61 struct r92ce_iq_cal_reg_vals {
   62         uint32_t        adda[16];
   63         uint8_t         txpause;
   64         uint8_t         bcn_ctrl[2];
   65         uint32_t        gpio_muxcfg;
   66         uint32_t        ofdm0_trxpathena;
   67         uint32_t        ofdm0_trmuxpar;
   68         uint32_t        fpga0_rfifacesw1;
   69 };
   70 
   71 /* XXX 92CU? */
   72 static int
   73 r92ce_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2],
   74     uint16_t rx[2])
   75 {
   76         uint32_t status;
   77 
   78         if (chain == 0) {       /* IQ calibration for chain 0. */
   79                 /* IQ calibration settings for chain 0. */
   80                 rtwn_bb_write(sc, R92C_TX_IQK_TONE(0), 0x10008c1f);
   81                 rtwn_bb_write(sc, R92C_RX_IQK_TONE(0), 0x10008c1f);
   82                 rtwn_bb_write(sc, R92C_TX_IQK_PI(0), 0x82140102);
   83 
   84                 if (sc->ntxchains > 1) {
   85                         rtwn_bb_write(sc, R92C_RX_IQK_PI(0), 0x28160202);
   86                         /* IQ calibration settings for chain 1. */
   87                         rtwn_bb_write(sc, R92C_TX_IQK_TONE(1), 0x10008c22);
   88                         rtwn_bb_write(sc, R92C_RX_IQK_TONE(1), 0x10008c22);
   89                         rtwn_bb_write(sc, R92C_TX_IQK_PI(1), 0x82140102);
   90                         rtwn_bb_write(sc, R92C_RX_IQK_PI(1), 0x28160202);
   91                 } else
   92                         rtwn_bb_write(sc, R92C_RX_IQK_PI(0), 0x28160502);
   93 
   94                 /* LO calibration settings. */
   95                 rtwn_bb_write(sc, R92C_IQK_AGC_RSP, 0x001028d1);
   96                 /* We're doing LO and IQ calibration in one shot. */
   97                 rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf9000000);
   98                 rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf8000000);
   99 
  100         } else {                /* IQ calibration for chain 1. */
  101                 /* We're doing LO and IQ calibration in one shot. */
  102                 rtwn_bb_write(sc, R92C_IQK_AGC_CONT, 2);
  103                 rtwn_bb_write(sc, R92C_IQK_AGC_CONT, 0);
  104         }
  105 
  106         /* Give LO and IQ calibrations the time to complete. */
  107         rtwn_delay(sc, 1000);
  108 
  109         /* Read IQ calibration status. */
  110         status = rtwn_bb_read(sc, R92C_RX_POWER_IQK_AFTER(0));
  111 
  112         if (status & (1 << (28 + chain * 3)))
  113                 return (0);     /* Tx failed. */
  114         /* Read Tx IQ calibration results. */
  115         tx[0] = MS(rtwn_bb_read(sc, R92C_TX_POWER_IQK_BEFORE(chain)),
  116             R92C_POWER_IQK_RESULT);
  117         tx[1] = MS(rtwn_bb_read(sc, R92C_TX_POWER_IQK_AFTER(chain)),
  118             R92C_POWER_IQK_RESULT);
  119         if (tx[0] == 0x142 || tx[1] == 0x042)
  120                 return (0);     /* Tx failed. */
  121 
  122         if (status & (1 << (27 + chain * 3)))
  123                 return (1);     /* Rx failed. */
  124         /* Read Rx IQ calibration results. */
  125         rx[0] = MS(rtwn_bb_read(sc, R92C_RX_POWER_IQK_BEFORE(chain)),
  126             R92C_POWER_IQK_RESULT);
  127         rx[1] = MS(rtwn_bb_read(sc, R92C_RX_POWER_IQK_AFTER(chain)),
  128             R92C_POWER_IQK_RESULT);
  129         if (rx[0] == 0x132 || rx[1] == 0x036)
  130                 return (1);     /* Rx failed. */
  131 
  132         return (3);     /* Both Tx and Rx succeeded. */
  133 }
  134 
  135 static void
  136 r92ce_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2],
  137     uint16_t rx[2][2], struct r92ce_iq_cal_reg_vals *vals)
  138 {
  139         /* Registers to save and restore during IQ calibration. */
  140         static const uint16_t reg_adda[16] = {
  141                 0x85c, 0xe6c, 0xe70, 0xe74,
  142                 0xe78, 0xe7c, 0xe80, 0xe84,
  143                 0xe88, 0xe8c, 0xed0, 0xed4,
  144                 0xed8, 0xedc, 0xee0, 0xeec
  145         };
  146         int i, chain;
  147         uint32_t hssi_param1;
  148 
  149         if (n == 0) {
  150                 for (i = 0; i < nitems(reg_adda); i++)
  151                         vals->adda[i] = rtwn_bb_read(sc, reg_adda[i]);
  152 
  153                 vals->txpause = rtwn_read_1(sc, R92C_TXPAUSE);
  154                 vals->bcn_ctrl[0] = rtwn_read_1(sc, R92C_BCN_CTRL(0));
  155                 vals->bcn_ctrl[1] = rtwn_read_1(sc, R92C_BCN_CTRL(1));
  156                 vals->gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG);
  157         }
  158 
  159         if (sc->ntxchains == 1) {
  160                 rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0);
  161                 for (i = 1; i < nitems(reg_adda); i++)
  162                         rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0);
  163         } else {
  164                 for (i = 0; i < nitems(reg_adda); i++)
  165                         rtwn_bb_write(sc, reg_adda[i], 0x04db25a4);
  166         }
  167 
  168         hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0));
  169         if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
  170                 rtwn_bb_write(sc, R92C_HSSI_PARAM1(0),
  171                     hssi_param1 | R92C_HSSI_PARAM1_PI);
  172                 rtwn_bb_write(sc, R92C_HSSI_PARAM1(1),
  173                     hssi_param1 | R92C_HSSI_PARAM1_PI);
  174         }
  175 
  176         if (n == 0) {
  177                 vals->ofdm0_trxpathena =
  178                     rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
  179                 vals->ofdm0_trmuxpar = rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR);
  180                 vals->fpga0_rfifacesw1 =
  181                     rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1));
  182         }
  183 
  184         rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600);
  185         rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4);
  186         rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000);
  187         if (sc->ntxchains > 1) {
  188                 rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
  189                 rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000);
  190         }
  191 
  192         rtwn_write_1(sc, R92C_TXPAUSE,
  193             R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH);
  194         rtwn_write_1(sc, R92C_BCN_CTRL(0),
  195             vals->bcn_ctrl[0] & ~R92C_BCN_CTRL_EN_BCN);
  196         rtwn_write_1(sc, R92C_BCN_CTRL(1),
  197             vals->bcn_ctrl[1] & ~R92C_BCN_CTRL_EN_BCN);
  198         rtwn_write_1(sc, R92C_GPIO_MUXCFG,
  199             vals->gpio_muxcfg & ~R92C_GPIO_MUXCFG_ENBT);
  200 
  201         rtwn_bb_write(sc, 0x0b68, 0x00080000);
  202         if (sc->ntxchains > 1)
  203                 rtwn_bb_write(sc, 0x0b6c, 0x00080000);
  204 
  205         rtwn_bb_write(sc, R92C_FPGA0_IQK, 0x80800000);
  206         rtwn_bb_write(sc, R92C_TX_IQK, 0x01007c00);
  207         rtwn_bb_write(sc, R92C_RX_IQK, 0x01004800);
  208 
  209         rtwn_bb_write(sc, 0x0b68, 0x00080000);
  210 
  211         for (chain = 0; chain < sc->ntxchains; chain++) {
  212                 if (chain > 0) {
  213                         /* Put chain 0 on standby. */
  214                         rtwn_bb_write(sc, R92C_FPGA0_IQK, 0);
  215                         rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
  216                         rtwn_bb_write(sc, R92C_FPGA0_IQK, 0x80800000);
  217 
  218                         /* Enable chain 1. */
  219                         for (i = 0; i < nitems(reg_adda); i++)
  220                                 rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4);
  221                 }
  222 
  223                 /* Run IQ calibration twice. */
  224                 for (i = 0; i < 2; i++) {
  225                         int ret;
  226 
  227                         ret = r92ce_iq_calib_chain(sc, chain,
  228                             tx[chain], rx[chain]);
  229                         if (ret == 0) {
  230                                 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
  231                                     "%s: chain %d: Tx failed.\n",
  232                                     __func__, chain);
  233                                 tx[chain][0] = 0xff;
  234                                 tx[chain][1] = 0xff;
  235                                 rx[chain][0] = 0xff;
  236                                 rx[chain][1] = 0xff;
  237                         } else if (ret == 1) {
  238                                 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
  239                                     "%s: chain %d: Rx failed.\n",
  240                                     __func__, chain);
  241                                 rx[chain][0] = 0xff;
  242                                 rx[chain][1] = 0xff;
  243                         } else if (ret == 3) {
  244                                 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
  245                                     "%s: chain %d: Both Tx and Rx "
  246                                     "succeeded.\n", __func__, chain);
  247                         }
  248                 }
  249 
  250                 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
  251                     "%s: results for run %d chain %d: tx[0] 0x%x, "
  252                     "tx[1] 0x%x, rx[0] 0x%x, rx[1] 0x%x\n", __func__, n, chain,
  253                     tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1]);
  254         }
  255 
  256         rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA,
  257             vals->ofdm0_trxpathena);
  258         rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1),
  259             vals->fpga0_rfifacesw1);
  260         rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, vals->ofdm0_trmuxpar);
  261 
  262         rtwn_bb_write(sc, R92C_FPGA0_IQK, 0);
  263         rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3);
  264         if (sc->ntxchains > 1)
  265                 rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3);
  266 
  267         if (n != 0) {
  268                 if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
  269                         rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1);
  270                         rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1);
  271                 }
  272 
  273                 for (i = 0; i < nitems(reg_adda); i++)
  274                         rtwn_bb_write(sc, reg_adda[i], vals->adda[i]);
  275 
  276                 rtwn_write_1(sc, R92C_TXPAUSE, vals->txpause);
  277                 rtwn_write_1(sc, R92C_BCN_CTRL(0), vals->bcn_ctrl[0]);
  278                 rtwn_write_1(sc, R92C_BCN_CTRL(1), vals->bcn_ctrl[1]);
  279                 rtwn_write_4(sc, R92C_GPIO_MUXCFG, vals->gpio_muxcfg);
  280         }
  281 }
  282 
  283 #define RTWN_IQ_CAL_MAX_TOLERANCE 5
  284 static int
  285 r92ce_iq_calib_compare_results(struct rtwn_softc *sc, uint16_t tx1[2][2],
  286     uint16_t rx1[2][2], uint16_t tx2[2][2], uint16_t rx2[2][2])
  287 {
  288         int chain, i, tx_ok[2], rx_ok[2];
  289 
  290         tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0;
  291         for (chain = 0; chain < sc->ntxchains; chain++) {
  292                 for (i = 0; i < 2; i++) {
  293                         if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff ||
  294                             rx1[chain][i] == 0xff || rx2[chain][i] == 0xff)
  295                                 continue;
  296 
  297                         tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <=
  298                             RTWN_IQ_CAL_MAX_TOLERANCE);
  299 
  300                         rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <=
  301                             RTWN_IQ_CAL_MAX_TOLERANCE);
  302                 }
  303         }
  304 
  305         if (sc->ntxchains > 1)
  306                 return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]);
  307         else
  308                 return (tx_ok[0] && rx_ok[0]);
  309 }
  310 #undef RTWN_IQ_CAL_MAX_TOLERANCE
  311 
  312 static void
  313 r92ce_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2],
  314     uint16_t rx[2], int chain)
  315 {
  316         uint32_t reg, val, x;
  317         long y, tx_c;
  318 
  319         if (tx[0] == 0xff || tx[1] == 0xff)
  320                 return;
  321 
  322         reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain));
  323         val = ((reg >> 22) & 0x3ff);
  324         x = tx[0];
  325         if (x & 0x00000200)
  326                 x |= 0xfffffc00;
  327         reg = (((x * val) >> 8) & 0x3ff);
  328         rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(chain), 0x3ff, reg);
  329         rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x80000000,
  330             ((x * val) & 0x80) << 24);
  331 
  332         y = tx[1];
  333         if (y & 0x00000200)
  334                 y |= 0xfffffc00;
  335         tx_c = (y * val) >> 8;
  336         rtwn_bb_setbits(sc, R92C_OFDM0_TXAFE(chain), 0xf0000000,
  337             (tx_c & 0x3c0) << 22);
  338         rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(chain), 0x003f0000,
  339             (tx_c & 0x3f) << 16);
  340         rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x20000000,
  341             ((y * val) & 0x80) << 22);
  342 
  343         if (rx[0] == 0xff || rx[1] == 0xff)
  344                 return;
  345 
  346         rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(chain), 0x3ff,
  347             rx[0] & 0x3ff);
  348         rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(chain), 0xfc00,
  349             (rx[1] & 0x3f) << 10);
  350 
  351         if (chain == 0) {
  352                 rtwn_bb_setbits(sc, R92C_OFDM0_RXIQEXTANTA, 0xf0000000,
  353                     (rx[1] & 0x3c0) << 22);
  354         } else {
  355                 rtwn_bb_setbits(sc, R92C_OFDM0_AGCRSSITABLE, 0xf000,
  356                     (rx[1] & 0x3c0) << 6);
  357         }
  358 }
  359 
  360 #define RTWN_IQ_CAL_NRUN        3
  361 void
  362 r92ce_iq_calib(struct rtwn_softc *sc)
  363 {
  364         struct r92ce_iq_cal_reg_vals vals;
  365         uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2];
  366         int n, valid;
  367 
  368         valid = 0;
  369         for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) {
  370                 r92ce_iq_calib_run(sc, n, tx[n], rx[n], &vals);
  371 
  372                 if (n == 0)
  373                         continue;
  374 
  375                 /* Valid results remain stable after consecutive runs. */
  376                 valid = r92ce_iq_calib_compare_results(sc, tx[n - 1],
  377                     rx[n - 1], tx[n], rx[n]);
  378                 if (valid)
  379                         break;
  380         }
  381 
  382         if (valid) {
  383                 r92ce_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0);
  384                 if (sc->ntxchains > 1)
  385                         r92ce_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1);
  386         }
  387 }
  388 #undef RTWN_IQ_CAL_NRUN

Cache object: 38488dbc02265ca623778fdc2bde7cc5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.