Search Linux Wireless

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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Viktor Barna <viktor.barna@xxxxxxxxxx>

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

Signed-off-by: Viktor Barna <viktor.barna@xxxxxxxxxx>
---
 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

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);
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux