diff mbox series

[RFC,v1,166/256] cl8k: add rf_boot.c

Message ID 20210617160223.160998-167-viktor.barna@celeno.com
State New
Headers show
Series wireless: cl8k driver for Celeno IEEE 802.11ax devices | expand

Commit Message

Viktor Barna June 17, 2021, 4 p.m. UTC
From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rf_boot.c | 354 +++++++++++++++++++++
 1 file changed, 354 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rf_boot.c

--
2.30.0
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/rf_boot.c b/drivers/net/wireless/celeno/cl8k/rf_boot.c
new file mode 100644
index 000000000000..4202c153661b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rf_boot.c
@@ -0,0 +1,354 @@ 
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "rf_boot.h"
+#include "hw.h"
+#include "afe.h"
+#include "utils/file.h"
+#include "phy/phy.h"
+#include "reg/reg_access.h"
+#include "reg/reg_cmu.h"
+#include "reg/reg_modem_gcu.h"
+#include "reg/reg_ricu.h"
+#include "reg/reg_riu.h"
+#include "reg/reg_mac_hw.h"
+#include "reg/reg_lcu_phy.h"
+
+static void cl_clk_init(struct cl_chip *chip)
+{
+       cmu_clk_en_set(chip, CMU_MAC_ALL_CLK_EN);
+
+       cmu_phy_0_clk_en_set(chip, CMU_PHY_0_APB_CLK_EN_BIT | CMU_PHY_0_MAIN_CLK_EN_BIT);
+       cmu_phy_1_clk_en_set(chip, CMU_PHY_1_APB_CLK_EN_BIT | CMU_PHY_1_MAIN_CLK_EN_BIT);
+
+       cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+       modem_gcu_ceva_ctrl_external_wait_setf(chip->cl_hw_tcv0, 1);
+       cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 1);
+
+       cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+       modem_gcu_ceva_ctrl_external_wait_setf(chip->cl_hw_tcv1, 1);
+       cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 1);
+
+       cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 1);
+       cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 1);
+}
+
+static int cl_pll1_init(struct cl_chip *chip)
+{
+       int retry = 0;
+
+       /* Verify pll is locked */
+       while (!cmu_pll_1_stat_pll_lock_getf(chip) && (++retry < 10)) {
+               cl_dbg_chip_verbose(chip, "retry=%d\n", retry);
+               usleep_range(100, 200);
+       }
+
+       /* Pll is not locked - fatal error */
+       if (retry == 10) {
+               cl_dbg_chip_err(chip, "retry limit reached - pll is not locked !!!\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int cl_cmu_init(struct cl_chip *chip)
+{
+       if (cl_pll1_init(chip))
+               return -1;
+
+       /* Set gl_mux_sel bit to work with pll1 instead of crystal */
+       cmu_control_gl_mux_sel_setf(chip, 1);
+
+       cmu_rst_n_ricurst_setf(chip, 1);
+
+       cmu_phy_0_rst_set(chip, CMU_PHY0_RST_EN);
+       cmu_phy_1_rst_set(chip, CMU_PHY1_RST_EN);
+       cmu_phy_0_rst_set(chip, 0x0);
+       cmu_phy_1_rst_set(chip, 0x0);
+       cmu_rst_n_ricurst_setf(chip, 1);
+       cmu_phy_0_rst_set(chip, CMU_PHY0_RST_EN);
+       cmu_phy_1_rst_set(chip, CMU_PHY1_RST_EN);
+
+       return 0;
+}
+
+static void cl_riu_clk_bw_init(struct cl_hw *cl_hw)
+{
+       u32 regval;
+
+       switch (cl_hw->conf->ce_channel_bandwidth) {
+       case CHNL_BW_20:
+               regval = 0x00000100;
+               break;
+       case CHNL_BW_40:
+               regval = 0x00000555;
+               break;
+       case CHNL_BW_160:
+               regval = 0x00000dff;
+               break;
+       case CHNL_BW_80:
+       default:
+               regval = 0x000009aa;
+               break;
+       }
+
+       /* Set RIU modules clock BW */
+       modem_gcu_riu_clk_bw_set(cl_hw, regval);
+}
+
+static int cl_load_riu_rsf_memory(struct cl_chip *chip, const char *filename)
+{
+       struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+       struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+       char *buf = NULL;
+       loff_t size, i = 0;
+       int ret = 0;
+
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf)
+               return -ENOMEM;
+
+       if (size > RIU_RSF_FILE_SIZE) {
+               ret = -EFBIG;
+               goto out;
+       }
+
+       /* Enable re-sampling filter init. */
+       riu_rsf_control_rsf_init_en_setf(cl_hw_tcv0, 0x1);
+       if (cl_hw_tcv1)
+               riu_rsf_control_rsf_init_en_setf(cl_hw_tcv1, 0x1);
+
+       while (i < size) {
+               riu_rsf_init_set(cl_hw_tcv0, *(u32 *)&buf[i]);
+               if (cl_hw_tcv1)
+                       riu_rsf_init_set(cl_hw_tcv1, *(u32 *)&buf[i]);
+               i += 4;
+       }
+
+out:
+       kfree(buf);
+       return ret;
+}
+
+static int cl_load_riu_rsf_memory_recovery(struct cl_hw *cl_hw, const char *filename)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       char *buf = NULL;
+       loff_t size, i = 0;
+       int ret = 0;
+
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf)
+               return -ENOMEM;
+
+       if (size > RIU_RSF_FILE_SIZE) {
+               ret = -EFBIG;
+               goto out;
+       }
+
+       /* Enable re-sampling filter init. */
+       riu_rsf_control_rsf_init_en_setf(cl_hw, 0x1);
+
+       while (i < size) {
+               riu_rsf_init_set(cl_hw, *(u32 *)&buf[i]);
+               i += 4;
+       }
+
+out:
+       kfree(buf);
+       return ret;
+}
+
+static int cl_load_agc_data(struct cl_hw *cl_hw, const char *filename)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       char *buf = NULL;
+       loff_t size, i = 0;
+
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf)
+               return -ENOMEM;
+
+       /* Enable AGC FSM ram init state */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_en_setf(cl_hw, 0x1);
+       /* Start writing the firmware from WPTR=0 */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_setf(cl_hw, 0x0);
+       /* Allow WPTR register to be writable */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_set_setf(cl_hw, 0x1);
+       /* Enable auto increment WPTR by 1 upon any write */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_ainc_1_setf(cl_hw, 0x1);
+
+       while (i < size) {
+               riu_agcfsm_ram_init_2_set(cl_hw, *(u32 *)&buf[i]);
+               i += 4;
+       }
+
+       /* Disable AGC FSM ram init state */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_en_setf(cl_hw, 0x0);
+
+       kfree(buf);
+
+       return 0;
+}
+
+static int cl_load_agc_fw(struct cl_hw *cl_hw, const char *filename)
+{
+       int ret = 0;
+
+       /* Switch AGC to programming mode */
+
+       /* Disable RIU Modules clocks (RC,LB,ModemB,FE,ADC,Regs,AGC,Radar) */
+       modem_gcu_riu_clk_set(cl_hw, 0);
+
+       /* Switch AGC MEM clock to 480MHz */
+       modem_gcu_riu_clk_bw_agc_mem_clk_bw_setf(cl_hw, 3);
+
+       /* Enable RIU Modules clocks (RC,LB,ModemB,FE,ADC,Regs,AGC,Radar) */
+       modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+
+       /* Assert AGC FSM reset */
+       riu_rwnxagccntl_agcfsmreset_setf(cl_hw, 1);
+
+       /* Load AGC RAM data */
+       ret = cl_load_agc_data(cl_hw, filename);
+       if (ret)
+               goto out;
+
+       /* Switch AGC back to operational mode */
+
+       /* Disable RIU Modules clocks (RC, LB, ModemB, FE, ADC, Regs, AGC, Radar) */
+       modem_gcu_riu_clk_set(cl_hw, 0);
+       /* Switch AGC MEM clock back to 80M */
+       modem_gcu_riu_clk_bw_agc_mem_clk_bw_setf(cl_hw, 1);
+       /* Enable RIU Modules clocks (RC, LB, ModemB, FE, ADC, Regs, AGC, Radar) */
+       modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+
+       /* Release AGC FSM reset */
+       riu_rwnxagccntl_agcfsmreset_setf(cl_hw, 0);
+
+out:
+       return ret;
+}
+
+int cl_rf_boot(struct cl_chip *chip)
+{
+       int ret = 0;
+       struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+       struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+
+       /* Call only once per chip after ASIC reset - configure both phys */
+       ret = cl_cmu_init(chip);
+       if (ret != 0)
+               goto out;
+
+       cl_clk_init(chip);
+       cmu_phase_sel_set(chip, (CMU_GP_CLK_PHASE_SEL_BIT |
+                                CMU_DAC_CDB_CLK_PHASE_SEL_BIT |
+                                CMU_DAC_CLK_PHASE_SEL_BIT) &
+                                ~(CMU_ADC_CDB_CLK_PHASE_SEL_BIT |
+                                CMU_ADC_CLK_PHASE_SEL_BIT));
+
+       mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw_tcv0, 1); /* Disable MPIF clock */
+       mac_hw_state_cntrl_next_state_setf(cl_hw_tcv0, 2);        /* Move to doze */
+
+       mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw_tcv1, 1); /* Disable MPIF clock */
+       mac_hw_state_cntrl_next_state_setf(cl_hw_tcv1, 2);        /* Move to doze */
+
+       /* Enable all PHY modules */
+       cl_phy_enable(cl_hw_tcv0);
+       cl_phy_enable(cl_hw_tcv1);
+
+       mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw_tcv0, 1); /* Exit from doze */
+       mac_hw_state_cntrl_next_state_setf(cl_hw_tcv0, 0);  /* Move to idle */
+
+       mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw_tcv1, 1); /* Exit from doze */
+       mac_hw_state_cntrl_next_state_setf(cl_hw_tcv1, 0);  /* Move to idle */
+
+       cl_riu_clk_bw_init(cl_hw_tcv0);
+       cl_riu_clk_bw_init(cl_hw_tcv1);
+
+       /* Load RIU re-sampling filter memory with coefficients */
+       ret = cl_load_riu_rsf_memory(chip, "riu_rsf.bin");
+       if (ret != 0) {
+               pr_err("cl_load_riu_rsf_memory failed with error code %d.\n", ret);
+               goto out;
+       }
+
+       /* Load AGC FW */
+       ret = cl_load_agc_fw(cl_hw_tcv0, "agcram.bin");
+       if (ret) {
+               pr_err("cl_load_agc_fw failed for tcv0 with error code %d.\n", ret);
+               goto out;
+       }
+
+       ret = cl_load_agc_fw(cl_hw_tcv1, "agcram.bin");
+       if (ret) {
+               pr_err("cl_load_agc_fw failed for tcv1 with error code %d.\n", ret);
+               goto out;
+       }
+
+       /* AFE Registers configuration */
+       ret = cl_afe_cfg(chip);
+
+out:
+       return ret;
+}
+
+static void restore_ela_state(struct cl_hw *cl_hw)
+{
+       struct cl_recovery_db *recovery_db = &cl_hw->recovery_db;
+
+       /* Restore eLA state after MAC-HW reset */
+       if (recovery_db->ela_en) {
+               mac_hw_debug_port_sel_a_set(cl_hw, recovery_db->ela_sel_a);
+               mac_hw_debug_port_sel_b_set(cl_hw, recovery_db->ela_sel_b);
+               mac_hw_debug_port_sel_c_set(cl_hw, recovery_db->ela_sel_c);
+       }
+
+       mac_hw_debug_port_en_set(cl_hw, recovery_db->ela_en);
+}
+
+int cl_rf_boot_recovery(struct cl_hw *cl_hw)
+{
+       int ret = 0;
+
+       mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw, 1); /* Disable MPIF clock */
+       mac_hw_state_cntrl_next_state_setf(cl_hw, 2);        /* Move to doze */
+
+       /* Enable all PHY modules */
+       cl_phy_enable(cl_hw);
+
+       /* Restart LCU recording */
+       if (cl_hw_is_tcv0(cl_hw))
+               lcu_phy_lcu_ch_0_stop_set(cl_hw, 0);
+       else
+               lcu_phy_lcu_ch_1_stop_set(cl_hw, 0);
+
+       restore_ela_state(cl_hw);
+
+       mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw, 1); /* Exit from doze */
+       mac_hw_state_cntrl_next_state_setf(cl_hw, 0);  /* Move to idle */
+
+       cl_riu_clk_bw_init(cl_hw);
+
+       /* Load RIU re-sampling filter memory with coefficients */
+       ret = cl_load_riu_rsf_memory_recovery(cl_hw, "riu_rsf.bin");
+       if (ret != 0) {
+               pr_err("cl_load_riu_rsf_memory failed with error code %d.\n", ret);
+               goto out;
+       }
+
+       /* Load AGC FW */
+       ret = cl_load_agc_fw(cl_hw, "agcram.bin");
+       if (ret) {
+               pr_err("cl_load_agc_fw failed for with error code %d.\n", ret);
+               goto out;
+       }
+
+out:
+       return ret;
+}