diff --git a/driver/ad9361/ad9361.c b/driver/ad9361/ad9361.c index 9dc720e..e538a63 100644 --- a/driver/ad9361/ad9361.c +++ b/driver/ad9361/ad9361.c @@ -5178,7 +5178,7 @@ static int ad9361_setup(struct ad9361_rf_phy *phy) } -static int ad9361_do_calib_run(struct ad9361_rf_phy *phy, u32 cal, int arg) +int ad9361_do_calib_run(struct ad9361_rf_phy *phy, u32 cal, int arg) { struct ad9361_rf_phy_state *st = phy->state; int ret; @@ -5211,6 +5211,7 @@ static int ad9361_do_calib_run(struct ad9361_rf_phy *phy, u32 cal, int arg) return ret; } +EXPORT_SYMBOL(ad9361_do_calib_run); static int ad9361_update_rf_bandwidth(struct ad9361_rf_phy *phy, u32 rf_rx_bw, u32 rf_tx_bw) diff --git a/driver/hw_def.h b/driver/hw_def.h index b9df61b..9c9b324 100644 --- a/driver/hw_def.h +++ b/driver/hw_def.h @@ -304,6 +304,7 @@ const char *xpu_compatible_str = "sdr,xpu"; #define XPU_REG_BB_RF_DELAY_ADDR (10*4) #define XPU_REG_ACK_CTL_MAX_NUM_RETRANS_ADDR (11*4) #define XPU_REG_AMPDU_ACTION_ADDR (12*4) +#define XPU_REG_SPI_DISABLE_ADDR (13*4) #define XPU_REG_RECV_ACK_COUNT_TOP0_ADDR (16*4) #define XPU_REG_RECV_ACK_COUNT_TOP1_ADDR (17*4) #define XPU_REG_SEND_ACK_WAIT_TOP_ADDR (18*4) @@ -444,6 +445,9 @@ struct xpu_driver_api { void (*XPU_REG_ACK_CTL_MAX_NUM_RETRANS_write)(u32 value); u32 (*XPU_REG_ACK_CTL_MAX_NUM_RETRANS_read)(void); + void (*XPU_REG_SPI_DISABLE_write)(u32 value); + u32 (*XPU_REG_SPI_DISABLE_read)(void); + void (*XPU_REG_AMPDU_ACTION_write)(u32 value); u32 (*XPU_REG_AMPDU_ACTION_read)(void); diff --git a/driver/sdr.c b/driver/sdr.c index def451e..4acc641 100644 --- a/driver/sdr.c +++ b/driver/sdr.c @@ -55,6 +55,7 @@ extern int ad9361_set_tx_atten(struct ad9361_rf_phy *phy, u32 atten_mdb, bool tx1, bool tx2, bool immed); extern int ad9361_ctrl_outs_setup(struct ad9361_rf_phy *phy, struct ctrl_outs_control *ctrl); +extern int ad9361_do_calib_run(struct ad9361_rf_phy *phy, u32 cal, int arg); #include "../user_space/sdrctl_src/nl80211_testmode_def.h" #include "hw_def.h" @@ -175,11 +176,17 @@ static void ad9361_rf_set_channel(struct ieee80211_hw *dev, struct openwifi_priv *priv = dev->priv; u32 actual_rx_lo = conf->chandef.chan->center_freq - priv->rx_freq_offset_to_lo_MHz; u32 actual_tx_lo; + u32 spi_disable; + u32 diff_tx_lo; bool change_flag = (actual_rx_lo != priv->actual_rx_lo); int static_lbt_th, auto_lbt_th, fpga_lbt_th, receiver_rssi_dbm_th; + struct timeval tv; + unsigned long time_before = 0; + unsigned long time_after = 0; if (change_flag) { actual_tx_lo = conf->chandef.chan->center_freq - priv->tx_freq_offset_to_lo_MHz; + diff_tx_lo = priv->last_tx_quad_cal_lo > actual_tx_lo ? priv->last_tx_quad_cal_lo - actual_tx_lo : actual_tx_lo - priv->last_tx_quad_cal_lo; // -------------------Tx Lo tuning------------------- clk_set_rate(priv->ad9361_phy->clks[TX_RFPLL], ( ( ((u64)1000000ull)*((u64)actual_tx_lo ) + priv->rf_reg_val[RF_TX_REG_IDX_FO] )>>1) ); @@ -188,6 +195,20 @@ static void ad9361_rf_set_channel(struct ieee80211_hw *dev, // -------------------Rx Lo tuning------------------- clk_set_rate(priv->ad9361_phy->clks[RX_RFPLL], ( ( ((u64)1000000ull)*((u64)actual_rx_lo ) + priv->rf_reg_val[RF_RX_REG_IDX_FO] )>>1) ); priv->actual_rx_lo = actual_rx_lo; + + // call Tx Quadrature calibration if frequency change is more than 100MHz + if (diff_tx_lo > 100) { + priv->last_tx_quad_cal_lo = actual_tx_lo; + do_gettimeofday(&tv); + time_before = tv.tv_usec + ((u64)1000000ull)*((u64)tv.tv_sec ); + spi_disable = xpu_api->XPU_REG_SPI_DISABLE_read(); // disable FPGA SPI module + xpu_api->XPU_REG_SPI_DISABLE_write(1); + ad9361_do_calib_run(priv->ad9361_phy, TX_QUAD_CAL, (int)priv->ad9361_phy->state->last_tx_quad_cal_phase); + // restore original SPI disable state + xpu_api->XPU_REG_SPI_DISABLE_write(spi_disable); + do_gettimeofday(&tv); + time_after = tv.tv_usec + ((u64)1000000ull)*((u64)tv.tv_sec ); + } // get rssi correction value from lookup table priv->rssi_correction = rssi_correction_lookup_table(actual_rx_lo); @@ -217,7 +238,7 @@ static void ad9361_rf_set_channel(struct ieee80211_hw *dev, xpu_api->XPU_REG_BAND_CHANNEL_write( (priv->use_short_slot<<24)|(priv->band<<16) ); } } - printk("%s ad9361_rf_set_channel %dM rssi_correction %d (change flag %d) fpga_lbt_th %d(%ddBm) (auto %d static %d)\n", sdr_compatible_str,conf->chandef.chan->center_freq,priv->rssi_correction,change_flag,fpga_lbt_th,rssi_half_db_to_rssi_dbm(fpga_lbt_th, priv->rssi_correction),auto_lbt_th,static_lbt_th); + printk("%s ad9361_rf_set_channel %dM rssi_correction %d (change flag %d) fpga_lbt_th %d(%ddBm) (auto %d static %d) tx_quad_cal duration %lu us\n", sdr_compatible_str,conf->chandef.chan->center_freq,priv->rssi_correction,change_flag,fpga_lbt_th,rssi_half_db_to_rssi_dbm(fpga_lbt_th, priv->rssi_correction),auto_lbt_th,static_lbt_th, time_after-time_before); } } @@ -1297,6 +1318,10 @@ static void openwifi_stop(struct ieee80211_hw *dev) u32 reg, reg1; int i; + // enable ad9361 auto calibration and disable openwifi fpga spi control + priv->ad9361_phy->state->auto_cal_en = true; // turn on auto Tx quadrature calib. + priv->ad9361_phy->state->manual_tx_quad_cal_en = false; // turn off manual Tx quadrature calib. + xpu_api->XPU_REG_SPI_DISABLE_write(1); //turn off radio #if 1 @@ -1776,6 +1801,7 @@ static int openwifi_dev_probe(struct platform_device *pdev) // //-------------find ad9361-phy driver for lo/channel control--------------- priv->actual_rx_lo = 1000; //Some value aligned with rf_init/rf_init_11n.sh that is not WiFi channel to force ad9361_rf_set_channel execution triggered by Linux priv->actual_tx_lo = 1000; //Some value aligned with rf_init/rf_init_11n.sh that is not WiFi channel to force ad9361_rf_set_channel execution triggered by Linux + priv->last_tx_quad_cal_lo = 1000; tmp_dev = bus_find_device( &spi_bus_type, NULL, "ad9361-phy", custom_match_spi_dev ); if (tmp_dev == NULL) { printk(KERN_ERR "%s find_dev ad9361-phy failed\n",sdr_compatible_str); diff --git a/driver/sdr.h b/driver/sdr.h index d4097ca..46c1ed3 100644 --- a/driver/sdr.h +++ b/driver/sdr.h @@ -384,6 +384,7 @@ struct openwifi_priv { u32 rf_bw; u32 actual_rx_lo; u32 actual_tx_lo; + u32 last_tx_quad_cal_lo; struct ieee80211_rate rates_2GHz[12]; struct ieee80211_rate rates_5GHz[12]; diff --git a/driver/xpu/xpu.c b/driver/xpu/xpu.c index a25cf66..b3603f4 100644 --- a/driver/xpu/xpu.c +++ b/driver/xpu/xpu.c @@ -280,6 +280,14 @@ static inline u32 XPU_REG_AMPDU_ACTION_read(void){ return reg_read(XPU_REG_AMPDU_ACTION_ADDR); } +static inline void XPU_REG_SPI_DISABLE_write(u32 Data) { + reg_write(XPU_REG_SPI_DISABLE_ADDR, Data); +} + +static inline u32 XPU_REG_SPI_DISABLE_read(void){ + return reg_read(XPU_REG_SPI_DISABLE_ADDR); +} + static inline void XPU_REG_MAC_ADDR_write(u8 *mac_addr) {//, u32 en_flag){ XPU_REG_MAC_ADDR_LOW_write( *( (u32*)(mac_addr) ) ); XPU_REG_MAC_ADDR_HIGH_write( *( (u16*)(mac_addr + 4) ) ); @@ -359,8 +367,8 @@ static inline u32 hw_init(enum xpu_mode mode){ //xpu_api->XPU_REG_ACK_CTL_MAX_NUM_RETRANS_write(3); // if this > 0, it will override mac80211 set value, and set static retransmission limit - // xpu_api->XPU_REG_BB_RF_DELAY_write((1<<8)|47); - xpu_api->XPU_REG_BB_RF_DELAY_write((10<<8)|40); // extended rf is ongoing for perfect muting. (10<<8)|40 is verified good for zcu102/zed + // From CMW measurement: lo up 1us before the packet; lo down 0.4us after the packet/RF port switches 1.2us before and 0.2us after + xpu_api->XPU_REG_BB_RF_DELAY_write((16<<24)|(0<<16)|(26<<8)|9); // calibrated by ila and spectrum analyzer (trigger mode) // setup time schedule of 4 slices // slice 0 @@ -540,6 +548,9 @@ static int dev_probe(struct platform_device *pdev) xpu_api->XPU_REG_AMPDU_ACTION_write=XPU_REG_AMPDU_ACTION_write; xpu_api->XPU_REG_AMPDU_ACTION_read=XPU_REG_AMPDU_ACTION_read; + xpu_api->XPU_REG_SPI_DISABLE_write=XPU_REG_SPI_DISABLE_write; + xpu_api->XPU_REG_SPI_DISABLE_read=XPU_REG_SPI_DISABLE_read; + xpu_api->XPU_REG_MAC_ADDR_write=XPU_REG_MAC_ADDR_write; /* Request and map I/O memory */