diff mbox series

[RFC,v1,125/256] cl8k: add phy/phy.c

Message ID 20210617160223.160998-126-viktor.barna@celeno.com (mailing list archive)
State RFC
Delegated to: Kalle Valo
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/phy/phy.c | 272 +++++++++++++++++++++
 1 file changed, 272 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy.c

--
2.30.0
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy.c b/drivers/net/wireless/celeno/cl8k/phy/phy.c
new file mode 100644
index 000000000000..f58c7f83f600
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy.c
@@ -0,0 +1,272 @@ 
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "phy/phy.h"
+#include "reg/reg_modem_gcu.h"
+#include "reg/reg_cmu.h"
+#include "reg/reg_mac_hw.h"
+#include "reg/reg_mac_hw_mu.h"
+#include "reg/reg_macsys_gcu.h"
+#include "reg/reg_lcu_phy.h"
+#include "rf_boot.h"
+#include "dsp.h"
+
+static void ceva_disable(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       if (cl_hw_is_tcv0(cl_hw)) {
+               cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+               cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 0);
+       } else {
+               cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+               cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 0);
+       }
+}
+
+static void ceva_reset(struct cl_hw *cl_hw)
+{
+       if (cl_hw_is_tcv0(cl_hw))
+               cmu_phy_0_rst_set(cl_hw->chip, CMU_PHY0_RST_EN);
+       else
+               cmu_phy_1_rst_set(cl_hw->chip, CMU_PHY1_RST_EN);
+}
+
+static void phy_disable(struct cl_hw *cl_hw)
+{
+       /* Modem GCU modules - Reset */
+
+       /* Disable clocks (reset is not asserted) */
+       modem_gcu_mpu_set(cl_hw, MODEM_GCU_MPU_RST_N_BIT | MODEM_GCU_MPU_REG_RST_N_BIT);
+       modem_gcu_bpu_set(cl_hw, MODEM_GCU_BPU_RST_N_BIT | MODEM_GCU_BPU_RX_RST_N_BIT |
+                         MODEM_GCU_BPU_TX_RST_N_BIT | MODEM_GCU_BPU_REG_RST_N_BIT);
+       modem_gcu_tfu_set(cl_hw, MODEM_GCU_TFU_RST_N_BIT | MODEM_GCU_TFU_REG_RST_N_BIT);
+       modem_gcu_smu_set(cl_hw, MODEM_GCU_SMU_RST_N_BIT | MODEM_GCU_SMU_REG_RST_N_BIT);
+       modem_gcu_spu_set(cl_hw, MODEM_GCU_SPU_RST_N_BIT | MODEM_GCU_SPU_REG_RST_N_BIT);
+       modem_gcu_bf_set(cl_hw, MODEM_GCU_BF_RST_N_BIT | MODEM_GCU_BF_REG_RST_N_BIT);
+       modem_gcu_epa_set(cl_hw, MODEM_GCU_EPA_RST_N_BIT | MODEM_GCU_EPA_REG_RST_N_BIT);
+       modem_gcu_lcu_set(cl_hw, MODEM_GCU_LCU_HLF_RST_N_BIT | MODEM_GCU_LCU_RST_N_BIT |
+                         MODEM_GCU_LCU_REG_RST_N_BIT);
+       modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT |
+                             MODEM_GCU_MUX_FIC_RST_N_BIT);
+       modem_gcu_riu_clk_set(cl_hw, 0);
+       modem_gcu_riu_clk_1_set(cl_hw, 0);
+
+       /* Assert reset (clocks already disabled) */
+       modem_gcu_mpu_set(cl_hw, 0);
+       modem_gcu_bpu_set(cl_hw, 0);
+       modem_gcu_tfu_set(cl_hw, 0);
+       modem_gcu_smu_set(cl_hw, 0);
+       modem_gcu_spu_set(cl_hw, 0);
+       modem_gcu_bf_set(cl_hw, 0);
+       modem_gcu_epa_set(cl_hw, 0);
+       modem_gcu_lcu_set(cl_hw, 0);
+       modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT);
+       modem_gcu_riu_rst_set(cl_hw, 0);
+}
+
+static void phy_reset(struct cl_hw *cl_hw)
+{
+       /* Isolate FIC bus in case CEVA reset is not required */
+       modem_gcu_mux_fic_config_fic_isolate_setf(cl_hw, 1);
+       while (modem_gcu_mux_fic_config_fic_isolated_getf(cl_hw) == 0)
+               ;
+       modem_gcu_mux_fic_config_fic_isolate_setf(cl_hw, 0);
+
+       /*
+        * Stop the LCU recording.
+        * Stop on one channel actually stops the recording on all channels.
+        * This stop is required because PHY LCU is going to be reset.
+        */
+       if (cl_hw_is_tcv0(cl_hw))
+               lcu_phy_lcu_ch_0_stop_set(cl_hw, 1);
+       else
+               lcu_phy_lcu_ch_1_stop_set(cl_hw, 1);
+
+       /* PHY reset sequence */
+       phy_disable(cl_hw);
+}
+
+static void phy0_off(struct cl_chip *chip)
+{
+       /* Disable APB0 clock but keep other clocks (main clock and DSP0 clock) active */
+       cmu_phy_0_clk_en_pack(chip, 1, 0, 1);
+       /* DSP0, MPIF0, APB0 reset */
+       cmu_phy_0_rst_set(chip, CMU_PHY_0_RST_N_BIT);
+       /* DSP0, MPIF0 are still in reset, but take APB0 out of reset to allow writing to GCU */
+       cmu_phy_0_rst_set(chip, CMU_PHY_0_RST_N_BIT | CMU_PHY_0_PRESET_N_BIT);
+       /* Enable APB0 clock (all other clocks are already active) */
+       cmu_phy_0_clk_en_phy_0_apb_clk_en_setf(chip, 1);
+}
+
+static void phy1_off(struct cl_chip *chip)
+{
+       /* Disable APB0 clock but keep other clocks (main clock and DSP0 clock) active */
+       cmu_phy_1_clk_en_pack(chip, 1, 0, 1);
+       /* DSP0, MPIF0, APB0 reset */
+       cmu_phy_1_rst_set(chip, CMU_PHY_0_RST_N_BIT);
+       /* DSP0, MPIF0 are still in reset, but take APB0 out of reset to allow writing to GCU */
+       cmu_phy_1_rst_set(chip, CMU_PHY_0_RST_N_BIT | CMU_PHY_0_PRESET_N_BIT);
+       /* Enable APB0 clock (all other clocks are already active) */
+       cmu_phy_1_clk_en_phy_1_apb_clk_en_setf(chip, 1);
+}
+
+static void phy_off(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       if (cl_hw_is_tcv0(cl_hw))
+               phy0_off(chip);
+       else
+               phy1_off(chip);
+
+       phy_disable(cl_hw);
+}
+
+static void system_ctrl_reg_reset(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       u32 regval = macsys_gcu_xt_control_get(chip);
+       u8 i;
+
+       /* Set XMAC_RUN_STALL */
+       regval |= cl_hw->controller_reg.run_stall;
+       /* Clear XMAC_OCD_HALT_ON_RESET and clear XMAC_BRESET */
+       regval &= ~(cl_hw->controller_reg.ocd_halt_on_reset | cl_hw->controller_reg.breset);
+
+       /* Reset MACHW */
+       macsys_gcu_xt_control_set(chip, regval);
+
+       for (i = 0; i < cl_hw->max_mu_cnt; i++)
+               mac_hw_mu_mac_cntrl_2_set(cl_hw, 1, i);
+}
+
+void cl_phy_off(struct cl_hw *cl_hw)
+{
+       system_ctrl_reg_reset(cl_hw);
+       phy_off(cl_hw);
+       ceva_disable(cl_hw);
+}
+
+static void save_ela_state(struct cl_hw *cl_hw)
+{
+       struct cl_recovery_db *recovery_db = &cl_hw->recovery_db;
+
+       /* Save eLA state before MAC-HW reset */
+       recovery_db->ela_en = mac_hw_debug_port_en_get(cl_hw);
+
+       if (recovery_db->ela_en) {
+               recovery_db->ela_sel_a = mac_hw_debug_port_sel_a_get(cl_hw);
+               recovery_db->ela_sel_b = mac_hw_debug_port_sel_b_get(cl_hw);
+               recovery_db->ela_sel_c = mac_hw_debug_port_sel_c_get(cl_hw);
+       }
+}
+
+void cl_phy_reset(struct cl_hw *cl_hw)
+{
+       save_ela_state(cl_hw);
+       system_ctrl_reg_reset(cl_hw);
+       phy_reset(cl_hw);
+       ceva_reset(cl_hw);
+}
+
+int cl_phy_load_recovery(struct cl_hw *cl_hw)
+{
+       int ret = cl_rf_boot_recovery(cl_hw);
+
+       if (ret) {
+               cl_dbg_err(cl_hw, "cl_rf_boot_recovery failed %d\n", ret);
+               return ret;
+       }
+
+       /* Load DSP */
+       ret = cl_dsp_load_recovery(cl_hw);
+       if (ret) {
+               cl_dbg_err(cl_hw, "cl_dsp_load_recovery failed %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * FIXME: It looks like there is a bug in the DSP. If we poll REG_CFG_SPACE
+        * (0x600018) at this point to verify that DSP has been initialized
+        * successfully, we read '1' and continue.
+        * However, the calibration fails.
+        *
+        * Please note that this is a WORKAROUND, not a final fix.
+        * The problem should be investigated
+        * further by the DSP team.
+        */
+       msleep(500);
+       return 0;
+}
+
+int cl_phy_data_alloc(struct cl_hw *cl_hw)
+{
+       struct cl_phy_data *buf = NULL;
+       u32 len = (u32)PAGE_SIZE;
+       dma_addr_t phys_dma_addr;
+
+       buf = dma_alloc_coherent(cl_hw->chip->dev, len, &phys_dma_addr, GFP_KERNEL);
+
+       if (!buf)
+               return -1;
+
+       cl_hw->phy_data_info.data = buf;
+       cl_hw->phy_data_info.dma_addr = cpu_to_le32(phys_dma_addr);
+
+       return 0;
+}
+
+void cl_phy_data_free(struct cl_hw *cl_hw)
+{
+       dma_addr_t phys_dma_addr = le32_to_cpu(cl_hw->phy_data_info.dma_addr);
+
+       if (!cl_hw->phy_data_info.data)
+               return;
+
+       dma_free_coherent(cl_hw->chip->dev, PAGE_SIZE,
+                         (void *)cl_hw->phy_data_info.data, phys_dma_addr);
+       cl_hw->phy_data_info.data = NULL;
+}
+
+void cl_phy_enable(struct cl_hw *cl_hw)
+{
+       /* Modem GCU modules - De-assert Reset */
+
+       /* De-assert reset (clocks disabled) */
+       modem_gcu_mpu_set(cl_hw, MODEM_GCU_MPU_RST_N_BIT | MODEM_GCU_MPU_REG_RST_N_BIT);
+       modem_gcu_bpu_set(cl_hw, MODEM_GCU_BPU_RST_N_BIT | MODEM_GCU_BPU_RX_RST_N_BIT |
+                         MODEM_GCU_BPU_TX_RST_N_BIT | MODEM_GCU_BPU_REG_RST_N_BIT);
+       modem_gcu_tfu_set(cl_hw, MODEM_GCU_TFU_RST_N_BIT | MODEM_GCU_TFU_REG_RST_N_BIT);
+       modem_gcu_smu_set(cl_hw, MODEM_GCU_SMU_RST_N_BIT | MODEM_GCU_SMU_REG_RST_N_BIT);
+       modem_gcu_spu_set(cl_hw, MODEM_GCU_SPU_RST_N_BIT | MODEM_GCU_SPU_REG_RST_N_BIT);
+       modem_gcu_bf_set(cl_hw, MODEM_GCU_BF_RST_N_BIT | MODEM_GCU_BF_REG_RST_N_BIT);
+       modem_gcu_epa_set(cl_hw, MODEM_GCU_EPA_RST_N_BIT | MODEM_GCU_EPA_REG_RST_N_BIT);
+       modem_gcu_lcu_set(cl_hw, MODEM_GCU_LCU_HLF_RST_N_BIT | MODEM_GCU_LCU_RST_N_BIT |
+                         MODEM_GCU_LCU_REG_RST_N_BIT);
+       modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT |
+                             MODEM_GCU_MUX_FIC_RST_N_BIT);
+       modem_gcu_riu_rst_set(cl_hw, MODEM_GCU_RIU_FE_RST_N_BIT | MODEM_GCU_RIU_AGC_RST_N_BIT |
+                             MODEM_GCU_RIU_MDM_B_RST_N_BIT | MODEM_GCU_RIU_LB_RST_N_BIT |
+                             MODEM_GCU_RIU_RC_RST_N_BIT | MODEM_GCU_RIU_RADAR_RST_N_BIT |
+                             MODEM_GCU_RIU_RST_N_BIT | MODEM_GCU_RIU_REG_RST_N_BIT);
+
+       /* Enable clocks */
+       modem_gcu_mpu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_bpu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_tfu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_smu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_spu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_bf_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_epa_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_lcu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_mux_fic_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_riu_clk_1_set(cl_hw, 0xFFFFFFFF);
+
+       /*
+        * Configure minimum latency between 2 masters connected
+        * to same FIC, Read/Write transaction
+        */
+       modem_gcu_mux_fic_config_set(cl_hw, 0x00000808);
+}