/** * @file sdrv_ckgen_hw_access.c * @brief taishan ckgen hw access source file. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include "sdrv_ckgen_hw_access.h" #include "sdrv_ckgen_common.h" bool sdrv_ckgen_ip_slice_hardware_gated(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_IP_CTL_BASE(base, id); return !BIT_SET(readl(ctrl_reg), CKGEN_IP_CTL_HW_CG_EN_STATUS); } void sdrv_ckgen_ip_slice_hardware_gate_enable(uint32_t base, uint32_t id, bool en) { uint32_t ctrl_reg = CKGEN_IP_CTL_BASE(base, id); RMWREG32(ctrl_reg, CKGEN_IP_CTL_HW_DIS_EN, 1, en); } bool sdrv_ckgen_core_slice_hardware_gated(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_CORE_CTL_BASE(base, id); return !BIT_SET(readl(ctrl_reg), CKGEN_CORE_CTL_HW_CG_EN_STATUS); } void sdrv_ckgen_core_slice_hardware_gate_enable(uint32_t base, uint32_t id, bool en) { uint32_t ctrl_reg = CKGEN_CORE_CTL_BASE(base, id); RMWREG32(ctrl_reg, CKGEN_CORE_CTL_HW_DIS_EN, 1, en); } bool sdrv_ckgen_bus_slice_hardware_gated(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_BUS_CTL_BASE(base, id); return !BIT_SET(readl(ctrl_reg), CKGEN_BUS_CTL_HW_CG_EN_STATUS); } void sdrv_ckgen_bus_slice_hardware_gate_enable(uint32_t base, uint32_t id, bool en) { uint32_t ctrl_reg = CKGEN_BUS_CTL_BASE(base, id); RMWREG32(ctrl_reg, CKGEN_BUS_CTL_HW_DIS_EN, 1, en); } bool sdrv_ckgen_ip_slice_gated(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_IP_CTL_BASE(base, id); return BITS_SHIFT(readl(ctrl_reg), 30, 29) ? false : true; } bool sdrv_ckgen_core_slice_gated(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_CORE_CTL_BASE(base, id); return BITS_SHIFT(readl(ctrl_reg), 30, 29) ? false : true; } bool sdrv_ckgen_bus_slice_gated(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_BUS_CTL_BASE(base, id); return BITS_SHIFT(readl(ctrl_reg), 30, 29) ? false : true; } int sdrv_ckgen_ip_slice_set_mux(uint32_t base, uint32_t id, uint8_t mux) { uint32_t ctrl_reg = CKGEN_IP_CTL_BASE(base, id); uint32_t ctrl_val = readl(ctrl_reg); if (mux == sdrv_ckgen_ip_slice_get_mux(base, id)) { if ((mux == 4) && BIT(ctrl_val, CKGEN_IP_CTL_MAIN_EN_STATUS) && !BIT(ctrl_val, CKGEN_IP_CTL_D0_ACTIVE)) { RMWREG32(ctrl_reg, CKGEN_IP_CTL_PRE_EN, 1u, 0u); if (sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_STATUS_OK; } else { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } } else if ((mux < 4) && BIT(ctrl_val, CKGEN_IP_CTL_PRE_EN_STATUS) && BIT(ctrl_val, CKGEN_IP_CTL_D0_ACTIVE)) { RMWREG32(ctrl_reg, CKGEN_IP_CTL_MAIN_EN, 1u, 0u); if (sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_MAIN_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_STATUS_OK; } else { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } } } /* sel ck_in4 first */ if (BIT(ctrl_val, CKGEN_IP_CTL_D0_ACTIVE)) { /* Make sure CG is enabled. */ RMWREG32(ctrl_reg, CKGEN_IP_CTL_MAIN_EN, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_MAIN_EN_STATUS, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } /* set clk_src_sel[2] to 1’b1. */ RMWREG32(ctrl_reg, CKGEN_IP_CTL_SRC_SEL_CKIN4, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_D0_ACTIVE, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_D0_ACTIVE_ERROR; } RMWREG32(ctrl_reg, CKGEN_IP_CTL_PRE_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } } /* sel ck_in0 to ck_in3 */ if (mux < 4) { /*set reg_pre_en to 1’b0, wait pre_en_ack to 1’b0.*/ RMWREG32(ctrl_reg, CKGEN_IP_CTL_PRE_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } /* set clk_src_sel[1:0] to select the clock.*/ RMWREG32(ctrl_reg, CKGEN_IP_CTL_SRC_SEL_LSB, 2u, mux); /*set reg_pre_en to 1’b1, wait pre_en_ack to 1’b1.*/ RMWREG32(ctrl_reg, CKGEN_IP_CTL_PRE_EN, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_PRE_EN_STATUS, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } /* set clk_src_sel[2] to 1’b0. */ RMWREG32(ctrl_reg, CKGEN_IP_CTL_SRC_SEL_CKIN4, 1u, 0u); RMWREG32(ctrl_reg, CKGEN_IP_CTL_MAIN_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_MAIN_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_D0_ACTIVE, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_D0_ACTIVE_ERROR; } } return SDRV_STATUS_OK; } uint8_t sdrv_ckgen_ip_slice_get_mux(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_IP_CTL_BASE(base, id); uint32_t ret = (readl(ctrl_reg) >> CKGEN_IP_CTL_SRC_SEL_LSB) & CKGEN_IP_CTL_SRC_SEL_MASK; if (ret & (1 << CKGEN_IP_CTL_SRC_SEL_CKIN4)) { ret = 1 << CKGEN_IP_CTL_SRC_SEL_CKIN4; } return ret; } int sdrv_ckgen_ip_slice_set_div(uint32_t base, uint32_t id, uint32_t div) { uint32_t ctrl_reg = CKGEN_IP_CTL_BASE(base, id); uint32_t ctrl_val = readl(ctrl_reg); RMWREG32(ctrl_reg, CKGEN_IP_CTL_DIV_NUM_LSB, 8u, div - 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_IP_CTL_DIV_CHG_BUSY, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_DIV_CHG_BUSY; } return SDRV_STATUS_OK; } uint32_t sdrv_ckgen_ip_slice_get_div(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_IP_CTL_BASE(base, id); return (readl(ctrl_reg) >> CKGEN_IP_CTL_DIV_NUM_LSB) & CKGEN_IP_CTL_DIV_NUM_MASK; } int sdrv_ckgen_core_slice_set_mux(uint32_t base, uint32_t id, uint8_t mux) { uint32_t ctrl_reg = CKGEN_CORE_CTL_BASE(base, id); uint32_t ctrl_val = readl(ctrl_reg); if (mux == sdrv_ckgen_core_slice_get_mux(base, id)) { if ((mux == 4) && BIT(ctrl_val, CKGEN_CORE_CTL_MAIN_EN_STATUS) && !BIT(ctrl_val, CKGEN_CORE_CTL_D0_ACTIVE)) { RMWREG32(ctrl_reg, CKGEN_CORE_CTL_PRE_EN, 1u, 0u); if (sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_STATUS_OK; } else { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } } else if ((mux < 4) && BIT(ctrl_val, CKGEN_CORE_CTL_PRE_EN_STATUS) && BIT(ctrl_val, CKGEN_CORE_CTL_D0_ACTIVE)) { RMWREG32(ctrl_reg, CKGEN_CORE_CTL_MAIN_EN, 1u, 0u); if (sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_MAIN_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_STATUS_OK; } else { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } } } /* sel ck_in4 first */ if (BIT(ctrl_val, CKGEN_CORE_CTL_D0_ACTIVE)) { /* Make sure CG is enabled. */ RMWREG32(ctrl_reg, CKGEN_CORE_CTL_MAIN_EN, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_MAIN_EN_STATUS, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } /* set clk_src_sel[2] to 1’b1. */ RMWREG32(ctrl_reg, CKGEN_CORE_CTL_SRC_SEL_CKIN4, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_D0_ACTIVE, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_D0_ACTIVE_ERROR; } RMWREG32(ctrl_reg, CKGEN_CORE_CTL_PRE_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } } /* sel ck_in0 to ck_in3 */ if (mux < 4) { /*set reg_pre_en to 1’b0, wait pre_en_ack to 1’b0.*/ RMWREG32(ctrl_reg, CKGEN_CORE_CTL_PRE_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } /* set clk_src_sel[1:0] to select the clock.*/ RMWREG32(ctrl_reg, CKGEN_CORE_CTL_SRC_SEL_LSB, 2u, mux); /*set reg_pre_en to 1’b1, wait pre_en_ack to 1’b1.*/ RMWREG32(ctrl_reg, CKGEN_CORE_CTL_PRE_EN, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_PRE_EN_STATUS, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } /* set clk_src_sel[2] to 1’b0. */ RMWREG32(ctrl_reg, CKGEN_CORE_CTL_SRC_SEL_CKIN4, 1u, 0u); RMWREG32(ctrl_reg, CKGEN_CORE_CTL_MAIN_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_MAIN_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_D0_ACTIVE, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_D0_ACTIVE_ERROR; } } return SDRV_STATUS_OK; } uint8_t sdrv_ckgen_core_slice_get_mux(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_CORE_CTL_BASE(base, id); uint32_t src_sel; uint8_t mux; src_sel = (readl(ctrl_reg) >> CKGEN_CORE_CTL_SRC_SEL_LSB) & CKGEN_CORE_CTL_SRC_SEL_MASK; /* sel ck_in4 */ if (src_sel & (1u << 2u)) { mux = 4; } /* sel ck_in0 ~ ck_in3 */ else { mux = src_sel & 0x3; } return mux; } int sdrv_ckgen_core_slice_ena_pre_div(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_CORE_CTL_BASE(base, id); uint32_t ctrl_val = readl(ctrl_reg); /*set reg_pre_en to 1’b1, wait pre_en_ack to 1’b1.*/ RMWREG32(ctrl_reg, CKGEN_CORE_CTL_PRE_EN, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_PRE_EN_STATUS, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } return SDRV_STATUS_OK; } int sdrv_ckgen_core_slice_set_div(uint32_t base, uint32_t id, uint32_t div) { uint32_t ctrl_reg = CKGEN_CORE_CTL_BASE(base, id); uint32_t ctrl_val = readl(ctrl_reg); RMWREG32(ctrl_reg, CKGEN_CORE_CTL_DIV_NUM_LSB, 5u, div - 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_CORE_CTL_DIV_CHG_BUSY, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_DIV_CHG_BUSY; } return SDRV_STATUS_OK; } uint32_t sdrv_ckgen_core_slice_get_div(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_CORE_CTL_BASE(base, id); return (readl(ctrl_reg) >> CKGEN_CORE_CTL_DIV_NUM_LSB) & CKGEN_CORE_CTL_DIV_NUM_MASK; } int sdrv_ckgen_bus_slice_set_post_mux(uint32_t base, uint32_t id, uint8_t mux) { uint32_t ctrl_reg = CKGEN_BUS_CTL_BASE(base, id); /* Make sure CG is enabled. */ if (mux == 1) { RMWREG32(ctrl_reg, CKGEN_BUS_CTL_MAIN_EN, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_MAIN_EN_STATUS, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } } RMWREG32(ctrl_reg, CKGEN_BUS_CTL_SRC_SEL_CKOUT, 1u, mux); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_POST_MUX_D0_ACTIVE, !mux, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_POST_D0_ACTIVE_ERROR; } return SDRV_STATUS_OK; } int sdrv_ckgen_bus_slice_set_pre_mux(uint32_t base, uint32_t id, uint8_t mux) { uint32_t ctrl_reg = CKGEN_BUS_CTL_BASE(base, id); uint32_t ctrl_val = readl(ctrl_reg); if (mux == sdrv_ckgen_bus_slice_get_pre_mux(base, id)) { if ((mux == 4) && BIT(ctrl_val, CKGEN_BUS_CTL_MAIN_EN_STATUS) && !BIT(ctrl_val, CKGEN_BUS_CTL_PRE_MUX_D0_ACTIVE)) { RMWREG32(ctrl_reg, CKGEN_BUS_CTL_PRE_EN, 1u, 0u); if (sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_STATUS_OK; } else { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } } else if ((mux < 4) && BIT(ctrl_val, CKGEN_BUS_CTL_PRE_EN_STATUS) && BIT(ctrl_val, CKGEN_BUS_CTL_PRE_MUX_D0_ACTIVE)) { RMWREG32(ctrl_reg, CKGEN_BUS_CTL_SRC_SEL_CKOUT, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_POST_MUX_D0_ACTIVE, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_D0_ACTIVE_ERROR; } RMWREG32(ctrl_reg, CKGEN_BUS_CTL_MAIN_EN, 1u, 0u); if (sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_MAIN_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_STATUS_OK; } else { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } } } /* sel ck_in4 first */ if (BIT(ctrl_val, CKGEN_BUS_CTL_PRE_MUX_D0_ACTIVE)) { /* Make sure CG is enabled. */ RMWREG32(ctrl_reg, CKGEN_BUS_CTL_MAIN_EN, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_MAIN_EN_STATUS, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } /* set clk_src_sel[2] to 1’b1. */ RMWREG32(ctrl_reg, CKGEN_BUS_CTL_SRC_SEL_CKIN4, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_PRE_MUX_D0_ACTIVE, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_D0_ACTIVE_ERROR; } RMWREG32(ctrl_reg, CKGEN_BUS_CTL_PRE_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } } /* sel ck_in0 to ck_in3 */ if (mux < 4) { /*set reg_pre_en to 1’b0, wait pre_en_ack to 1’b0.*/ RMWREG32(ctrl_reg, CKGEN_BUS_CTL_PRE_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_PRE_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } /* set clk_src_sel[1:0] to select the clock.*/ RMWREG32(ctrl_reg, CKGEN_BUS_CTL_SRC_SEL_LSB, 2u, mux); /*set reg_pre_en to 1’b1, wait pre_en_ack to 1’b1.*/ RMWREG32(ctrl_reg, CKGEN_BUS_CTL_PRE_EN, 1u, 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_PRE_EN_STATUS, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_PRE_STATUS_ERROR; } /* set clk_src_sel[2] to 1’b0. */ RMWREG32(ctrl_reg, CKGEN_BUS_CTL_SRC_SEL_CKIN4, 1u, 0u); /* if post d0 is 1, need change to 0 */ RMWREG32(ctrl_reg, CKGEN_BUS_CTL_SRC_SEL_CKOUT, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_POST_MUX_D0_ACTIVE, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_D0_ACTIVE_ERROR; } RMWREG32(ctrl_reg, CKGEN_BUS_CTL_MAIN_EN, 1u, 0u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_MAIN_EN_STATUS, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_MAIN_STATUS_ERROR; } if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_PRE_MUX_D0_ACTIVE, 1u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_D0_ACTIVE_ERROR; } } return SDRV_STATUS_OK; } int sdrv_ckgen_bus_slice_set_pre_div(uint32_t base, uint32_t id, uint32_t div) { uint32_t ctrl_reg = CKGEN_BUS_CTL_BASE(base, id); uint32_t ctrl_val = readl(ctrl_reg); RMWREG32(ctrl_reg, CKGEN_BUS_CTL_DIV_NUM_LSB, 5u, div - 1u); if (!sdrv_ckgen_wait(ctrl_reg, CKGEN_BUS_CTL_DIV_CHG_BUSY, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_DIV_CHG_BUSY; } return SDRV_STATUS_OK; } int sdrv_ckgen_bus_slice_set_sf_post_div(uint32_t base, uint32_t id, uint32_t ratio) { if (id == 0) { RMWREG32(base + CKGEN_RES, CKGEN_RES_RS_SF_RATIO_SEL, 1u, ratio); } else { RMWREG32(base + CKGEN_RES, CKGEN_RES_RS_SP_RATIO_SEL, 1u, ratio); } return SDRV_STATUS_OK; } int sdrv_ckgen_bus_slice_set_mnpq_div(uint32_t base, uint32_t id, uint8_t type, uint32_t div) { uint32_t sync_ctrl_reg = CKGEN_BUS_SYNC_CTL_BASE(base, id); uint32_t div_offset; uint32_t div_busy_offset; div_offset = type * 4u + CKGEN_BUS_SYNC_CTL_DIV_M_LSB; div_busy_offset = type + CKGEN_BUS_SYNC_CTL_DIV_CHG_BUSY_LSB; RMWREG32(sync_ctrl_reg, div_offset, 4u, div - 1u); if (!sdrv_ckgen_wait(sync_ctrl_reg, div_busy_offset, 0u, CKGEN_WAIT_TIME)) { return SDRV_CKGEN_SLICE_DIV_CHG_BUSY; } return SDRV_STATUS_OK; } int sdrv_ckgen_bus_slice_set_mnpq_div_onetime(uint32_t base, uint32_t id, uint8_t div_m, uint8_t div_n, uint8_t div_p, uint8_t div_q) { uint32_t sync_ctrl_reg = CKGEN_BUS_SYNC_CTL_BASE(base, id); uint32_t div_flag = 0u; volatile int32_t times_out = (int32_t)CKGEN_WAIT_TIME; uint32_t div_mnpq = readl(sync_ctrl_reg) & 0xffffu; if (div_m > 0u) { div_flag = 1u << CKGEN_HW_BUS_DIV_M; div_mnpq &= ~((uint32_t)0xfu << (CKGEN_BUS_SYNC_CTL_DIV_M_LSB)); div_mnpq |= (((uint32_t)div_m - 1u) & 0xfu) << CKGEN_BUS_SYNC_CTL_DIV_M_LSB; } if (div_n > 0u) { div_flag |= 1u << CKGEN_HW_BUS_DIV_N; div_mnpq &= ~((uint32_t)0xfu << (CKGEN_BUS_SYNC_CTL_DIV_N_LSB)); div_mnpq |= (((uint32_t)div_n - 1u) & 0xfu) << CKGEN_BUS_SYNC_CTL_DIV_N_LSB; } if (div_p > 0u) { div_flag |= 1u << CKGEN_HW_BUS_DIV_P; div_mnpq &= ~((uint32_t)0xfu << (CKGEN_BUS_SYNC_CTL_DIV_P_LSB)); div_mnpq |= (((uint32_t)div_p - 1u) & 0xfu) << CKGEN_BUS_SYNC_CTL_DIV_P_LSB; } if (div_q > 0u) { div_flag |= 1u << CKGEN_HW_BUS_DIV_Q; div_mnpq &= ~((uint32_t)0xfu << (CKGEN_BUS_SYNC_CTL_DIV_Q_LSB)); div_mnpq |= (((uint32_t)div_q - 1u) & 0xfu) << CKGEN_BUS_SYNC_CTL_DIV_Q_LSB; } if (div_flag) { RMWREG32(sync_ctrl_reg, CKGEN_BUS_SYNC_CTL_DIV_M_LSB, 16u, div_mnpq); while ((times_out > 0) && (0u != ((readl(sync_ctrl_reg) >> CKGEN_BUS_SYNC_CTL_DIV_CHG_BUSY_LSB) & div_flag))) { times_out--; } if (times_out <= 0) { return SDRV_CKGEN_SLICE_DIV_CHG_BUSY; } } return SDRV_STATUS_OK; } uint8_t sdrv_ckgen_bus_slice_get_pre_mux(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_BUS_CTL_BASE(base, id); uint32_t src_sel; uint8_t mux; src_sel = (readl(ctrl_reg) >> CKGEN_BUS_CTL_SRC_SEL_LSB) & CKGEN_BUS_CTL_SRC_SEL_MASK; /* sel ck_in4 */ if (src_sel & (1u << 2u)) { mux = 4; } /* sel ck_in0 ~ ck_in3 */ else { mux = src_sel & 0x3; } return mux; } uint32_t sdrv_ckgen_bus_slice_get_pre_div(uint32_t base, uint32_t id) { uint32_t ctrl_reg = CKGEN_BUS_CTL_BASE(base, id); return (readl(ctrl_reg) >> CKGEN_BUS_CTL_DIV_NUM_LSB) & CKGEN_BUS_CTL_DIV_NUM_MASK; } uint32_t sdrv_ckgen_bus_slice_get_mnpq_div(uint32_t base, uint32_t id, uint8_t type) { uint32_t sync_ctrl = CKGEN_BUS_SYNC_CTL_BASE(base, id); uint32_t val; uint32_t div_offset; val = readl(sync_ctrl); div_offset = type * 4u + CKGEN_BUS_SYNC_CTL_DIV_M_LSB; return (val >> div_offset) & CKGEN_BUS_SYNC_CTL_DIV_MASK; } int sdrv_ckgen_xcg_set_gate(uint32_t base, uint8_t cg_type, uint32_t id, uint8_t lp_mode, bool gating) { uint32_t ctrl_reg = CKGEN_XCG_CTL_BASE(base, id, cg_type); RMWREG32(ctrl_reg, CKGEN_CG_CTL_RUN_MODE + lp_mode, 1u, !gating); return SDRV_STATUS_OK; } bool sdrv_ckgen_xcg_is_gated(uint32_t base, uint8_t cg_type, uint32_t id) { uint32_t ctrl_reg = CKGEN_XCG_CTL_BASE(base, id, cg_type); return (readl(ctrl_reg) >> CKGEN_CG_CTL_CG_GATED) & 0x1u; } int sdrv_ckgen_xcg_lp_mask(uint32_t base, uint8_t cg_type, uint32_t id, bool mask) { uint32_t ctrl_reg = CKGEN_XCG_CTL_BASE(base, id, cg_type); RMWREG32(ctrl_reg, CKGEN_CG_CTL_LP_MASK, 1u, mask); return SDRV_STATUS_OK; } int sdrv_ckgen_pll_set_gate(uint32_t base, uint32_t id, uint8_t lp_mode, bool gating) { uint32_t pll_ctrl = CKGEN_PLL_CTL_BASE(base, id); RMWREG32(pll_ctrl, CKGEN_PLL_CTL_IGNORE, 1u, 0u); RMWREG32(pll_ctrl, CKGEN_PLL_CTL_RUN_MODE + lp_mode, 1u, !gating); return SDRV_STATUS_OK; } int sdrv_ckgen_pll_set_pd(uint32_t base, uint32_t id, uint8_t lp_mode, bool pd_state) { RMWREG32(CKGEN_PLL_CTL_BASE(base, id), CKGEN_PLL_PD_RUN_MODE + lp_mode, 1u, pd_state); return SDRV_STATUS_OK; } int sdrv_ckgen_xtal_set_gate(uint32_t base, uint8_t lp_mode, bool gating) { uint32_t xtal_ctrl = base + CKGEN_XTAL_CTL; RMWREG32(xtal_ctrl, CKGEN_XTAL_CTL_IGNORE, 1u, 0u); RMWREG32(xtal_ctrl, CKGEN_XTAL_CTL_RUN_MODE + lp_mode, 1u, !gating); return SDRV_STATUS_OK; } void sdrv_ckgen_enable_rs(uint32_t rs_base, uint8_t rs, bool lock) { uint32_t rs_val; rs_val = readl(rs_base); rs_val &= ~(CKGEN_RS_RS_MASK << CKGEN_RS_RS_LSB); rs_val |= (rs << CKGEN_RS_RS_LSB); rs_val &= ~(1 << CKGEN_RS_LOCK); rs_val |= (lock << CKGEN_RS_LOCK); rs_val |= (1 << CKGEN_RS_EN); writel(rs_val, rs_base); } void sdrv_ckgen_rs_disable(uint32_t rs_base) { RMWREG32(rs_base, CKGEN_RS_EN, 1u, 0u); } void sdrv_ckgen_ip_cor_int_enable(uint32_t base, uint32_t id, bool en) { uint32_t cor_en = CKGEN_IP_CLK_COR_EN_BASE(base, (id / 32u)); RMWREG32(cor_en, (id % 32u), 1u, en); } void sdrv_ckgen_ip_unc_int_enable(uint32_t base, uint32_t id, bool en) { uint32_t unc_en = CKGEN_IP_CLK_UNC_EN_BASE(base, (id / 32u)); RMWREG32(unc_en, (id % 32u), 1u, en); } bool sdrv_ckgen_ip_get_int_state(uint32_t base, uint32_t id) { uint32_t state = CKGEN_IP_CLK_INT_STA_BASE(base, (id / 32u)); return !!(readl(state) >> (id % 32u)); } void sdrv_ckgen_ip_clear_int_state(uint32_t base, uint32_t id) { uint32_t reg = CKGEN_IP_CLK_INT_STA_BASE(base, (id / 32u)); RMWREG32(reg, (id % 32u), 1u, 0u); } void sdrv_ckgen_bus_cor_int_enable(uint32_t base, uint32_t id, bool en) { uint32_t cor_en = CKGEN_BUS_CLK_COR_EN_BASE(base, (id / 32u)); RMWREG32(cor_en, (id % 32u), 1u, en); } void sdrv_ckgen_bus_unc_int_enable(uint32_t base, uint32_t id, bool en) { uint32_t unc_en = CKGEN_BUS_CLK_UNC_EN_BASE(base, (id / 32u)); RMWREG32(unc_en, (id % 32u), 1u, en); } bool sdrv_ckgen_bus_get_int_state(uint32_t base, uint32_t id) { uint32_t state = CKGEN_BUS_CLK_INT_STA_BASE(base, (id / 32u)); return !!(readl(state) >> (id % 32u)); } void sdrv_ckgen_bus_clear_int_state(uint32_t base, uint32_t id) { uint32_t reg = CKGEN_BUS_CLK_INT_STA_BASE(base, (id / 32u)); RMWREG32(reg, (id % 32u), 1u, 0u); } void sdrv_ckgen_core_cor_int_enable(uint32_t base, uint32_t id, bool en) { uint32_t cor_en = CKGEN_CORE_CLK_COR_EN_BASE(base, (id / 32u)); RMWREG32(cor_en, (id % 32u), 1u, en); } void sdrv_ckgen_core_unc_int_enable(uint32_t base, uint32_t id, bool en) { uint32_t unc_en = CKGEN_CORE_CLK_UNC_EN_BASE(base, (id / 32u)); RMWREG32(unc_en, (id % 32u), 1u, en); } bool sdrv_ckgen_core_get_int_state(uint32_t base, uint32_t id) { uint32_t state = CKGEN_CORE_CLK_INT_STA_BASE(base, (id / 32u)); return !!(readl(state) >> (id % 32u)); } void sdrv_ckgen_core_clear_int_state(uint32_t base, uint32_t id) { uint32_t reg = CKGEN_CORE_CLK_INT_STA_BASE(base, (id / 32u)); RMWREG32(reg, (id % 32u), 1u, 0u); } void sdrv_ckgen_xcg_cor_int_enable(uint32_t base, uint8_t type, uint32_t id, bool en) { uint32_t cor_en = CKGEN_XCG_COR_EN_BASE(base, (id/ 32u), type); RMWREG32(cor_en, (id % 32u), 1u, en); } void sdrv_ckgen_xcg_unc_int_enable(uint32_t base, uint8_t type, uint32_t id, bool en) { uint32_t unc_en = CKGEN_XCG_UNC_EN_BASE(base, (id / 32u), type); RMWREG32(unc_en, (id % 32u), 1u, en); } bool sdrv_ckgen_xcg_get_int_state(uint32_t base, uint8_t type, uint32_t id) { uint32_t state = CKGEN_XCG_INT_STA_BASE(base, (id / 32u), type); return !!(readl(state) >> (id % 32u)); } void sdrv_ckgen_xcg_clear_int_state(uint32_t base, uint8_t type, uint32_t id) { uint32_t state = CKGEN_XCG_INT_STA_BASE(base, (id / 32u), type); RMWREG32(state, (id % 32u), 1u, 0u); } static uint32_t sdrv_ckgen_mon_calc_freq(uint32_t base, uint32_t freq_mon, uint8_t div_a_b) { uint32_t glb_ctrl_val; uint32_t div_a_b_num; uint32_t rate = 0; glb_ctrl_val = readl(CKGEN_GLB_CTL_BASE(base)); if (div_a_b) { /* 24M divb */ div_a_b_num = (glb_ctrl_val >> CKGEN_GLB_CTL_24M_DIVB_NUM_LSB) & CKGEN_GLB_CTL_24M_DIVB_NUM_MASK; } else { /* 24M diva */ div_a_b_num = (glb_ctrl_val >> CKGEN_GLB_CTL_24M_DIVA_NUM_LSB) & CKGEN_GLB_CTL_24M_DIVA_NUM_MASK; } rate = 12000000 / (div_a_b_num + 1); rate = rate * freq_mon; return rate; } __UNUSED static void sdrv_ckgen_xcg_debug_enable(uint32_t base, uint8_t cg_type, uint32_t id, bool en) { uint32_t ctrl_reg = CKGEN_XCG_CTL_BASE(base, id, cg_type);; RMWREG32(ctrl_reg, CKGEN_CG_CTL_DBG_EN, 1u, en); } static void sdrv_ckgen_xcg_amon_enable(uint32_t base, uint8_t cg_type, uint32_t id, bool en) { uint32_t ctrl_reg = CKGEN_XCG_CTL_BASE(base, id, cg_type);; RMWREG32(ctrl_reg, CKGEN_CG_CTL_ACTIVE_MON_EN, 1u, en); } static uint8_t sdrv_ckgen_xcg_get_amon_state(uint32_t base, uint8_t cg_type, uint32_t id) { uint32_t ctrl_reg = CKGEN_XCG_CTL_BASE(base, id, cg_type);; return (readl(ctrl_reg) >> CKGEN_CG_CTL_ACTIVE_MON_STA) & 0x1u; } static void sdrv_ckgen_pll_mon_enable(uint32_t base, uint32_t id, uint32_t tout) { uint32_t mon_ctrl = CKGEN_PLL_MON_CTL_BASE(base, id); RMWREG32(mon_ctrl, CKGEN_PLL_MON_CTL_TOUT_VAL_LSB, 16u, tout); RMWREG32(mon_ctrl, CKGEN_PLL_MON_CTL_EN, 1u, 1u); } static void sdrv_ckgen_pll_mon_disable(uint32_t base, uint32_t id) { uint32_t mon_ctrl = CKGEN_PLL_MON_CTL_BASE(base, id); RMWREG32(mon_ctrl, CKGEN_PLL_MON_CTL_EN, 1u, 0u); } static uint8_t sdrv_ckgen_pll_mon_get_state(uint32_t base, uint32_t id) { uint32_t mon_ctrl = CKGEN_PLL_MON_CTL_BASE(base, id); return (readl(mon_ctrl) >> CKGEN_PLL_MON_CTL_CLK_READY) & 0x1u; } static void sdrv_ckgen_xtal_mon_enable(uint32_t base, uint32_t tout) { uint32_t xtal_mon = base + CKGEN_XTAL_MON_CTL; RMWREG32(xtal_mon, CKGEN_XTAL_MON_CTL_TOUT_VAL_LSB, 16u, tout); RMWREG32(xtal_mon, CKGEN_XTAL_MON_CTL_EN, 1u, 1u); sdrv_ckgen_wait(xtal_mon, CKGEN_XTAL_MON_CTL_EN_STA, 1u, CKGEN_WAIT_TIME); } static void sdrv_ckgen_xtal_mon_disable(uint32_t base) { uint32_t xtal_mon = base + CKGEN_XTAL_MON_CTL; RMWREG32(xtal_mon, CKGEN_XTAL_MON_CTL_EN, 1u, 0u); sdrv_ckgen_wait(xtal_mon, CKGEN_XTAL_MON_CTL_EN_STA, 0u, CKGEN_WAIT_TIME); } __UNUSED static uint8_t sdrv_ckgen_xtal_mon_get_rc24m_state(uint32_t base) { uint32_t xtal_mon = base + CKGEN_XTAL_MON_CTL; return (readl(xtal_mon) >> CKGEN_XTAL_MON_CTL_RC24M_ACTIVE) & 0x1u; } static uint8_t sdrv_ckgen_xtal_mon_get_xtal_state(uint32_t base) { uint32_t xtal_mon = base + CKGEN_XTAL_MON_CTL; return (readl(xtal_mon) >> CKGEN_XTAL_MON_CTL_XTAL_ACTIVE) & 0x1u; } static void sdrv_ckgen_dbg_mon_src_config(uint32_t base, uint8_t src, uint32_t id) { uint32_t dbg_mon_src = base + CKGEN_DBG_MON_CLK_SRC; uint32_t dbg_mon_ctl = base + CKGEN_DBG_MON_CTL; RMWREG32(dbg_mon_src, CKGEN_DBG_MON_CLK_SRC_LSB(src), 8u, id); RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_CLK_SEL_LSB, 2u, src); } static uint32_t sdrv_ckgen_dbg_mon_get_rate(uint32_t base, uint8_t src, uint32_t id) { uint32_t dbg_mon_ctl = base + CKGEN_DBG_MON_CTL; uint32_t mon_ctl = base + CKGEN_MON_CTL; uint32_t mon_ctl_val; uint32_t freq_mon; uint32_t div_a_b; uint32_t rate = 0; if (BIT(readl(mon_ctl), CKGEN_MON_CTL_EN)) { RMWREG32(mon_ctl, CKGEN_MON_CTL_EN, 1u, 0u); if (!sdrv_ckgen_wait(mon_ctl, CKGEN_MON_CTL_EN_STA, 0u, CKGEN_WAIT_TIME)) { return 0; } } sdrv_ckgen_dbg_mon_src_config(base, src, id); RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_MON_GATING_EN, 1u, 1u); RMWREG32(mon_ctl, CKGEN_MON_CTL_FREQ_LSB, 16u, 0u); RMWREG32(mon_ctl, CKGEN_MON_CTL_FREQ_UPD, 1u, 0u); RMWREG32(mon_ctl, CKGEN_MON_CTL_EN, 1u, 1u); if (!sdrv_ckgen_wait(mon_ctl, CKGEN_MON_CTL_EN_STA, 1u, CKGEN_WAIT_TIME)) { goto dbg_mon_get_ip_rate_out; } if (!sdrv_ckgen_wait(mon_ctl, CKGEN_MON_CTL_FREQ_UPD, 1u, CKGEN_WAIT_TIME)) { goto dbg_mon_get_ip_rate_out; } mon_ctl_val = readl(mon_ctl); freq_mon = (mon_ctl_val >> CKGEN_MON_CTL_FREQ_LSB) & CKGEN_MON_CTL_FREQ_MASK; div_a_b = (mon_ctl_val >> CKGEN_MON_CTL_SRC_SEL) & 0x1; rate = sdrv_ckgen_mon_calc_freq(base, freq_mon, div_a_b); dbg_mon_get_ip_rate_out: RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_MON_GATING_EN, 1u, 0u); RMWREG32(mon_ctl, CKGEN_MON_CTL_EN, 1u, 0u); sdrv_ckgen_wait(mon_ctl, CKGEN_MON_CTL_EN_STA, 0u, CKGEN_WAIT_TIME); return rate; } void sdrv_ckgen_set_mon_div(uint32_t base, uint8_t div_type, uint32_t div) { uint32_t glb_ctrl = CKGEN_GLB_CTL_BASE(base); uint32_t div_off; uint32_t div_width; if (div_type == CKGEN_MON_DIVA) { div_off = CKGEN_GLB_CTL_24M_DIVA_NUM_LSB; div_width = 10; } else if (div_type == CKGEN_MON_DIVB) { div_off = CKGEN_GLB_CTL_24M_DIVB_NUM_LSB; div_width = 10; } else if (div_type == CKGEN_MON_DIVC) { div_off = CKGEN_GLB_CTL_24M_DIVC_NUM_LSB; div_width = 4; } else { return; } RMWREG32(glb_ctrl, div_off, div_width, div); } uint32_t sdrv_ckgen_ip_mon_get_rate(uint32_t base, uint32_t id) { uint32_t ip_mon_ctrl = CKGEN_IP_MON_CTL_BASE(base, id); uint32_t ip_ctrl = CKGEN_IP_CTL_BASE(base, id); uint32_t ip_mon_ctrl_val; uint32_t freq_mon; uint8_t div_a_b; uint32_t rate = 0; /* disable ip mon */ if (BIT(readl(ip_mon_ctrl), CKGEN_IP_MON_CTL_EN)) { RMWREG32(ip_mon_ctrl, CKGEN_IP_MON_CTL_EN, 1u, 0u); if (!sdrv_ckgen_wait(ip_mon_ctrl, CKGEN_IP_MON_CTL_EN_STA, 0u, CKGEN_WAIT_TIME)) { return 0; } } /* clear freq mon */ RMWREG32(ip_mon_ctrl, CKGEN_IP_MON_CTL_FREQ_LSB, 16u, 0u); RMWREG32(ip_mon_ctrl, CKGEN_IP_MON_CTL_FREQ_UPD, 1u, 0u); /* enable ip slice debug */ RMWREG32(ip_ctrl, CKGEN_IP_CTL_DBG_EN, 1u, 1u); /* enable ip mon */ RMWREG32(ip_mon_ctrl, CKGEN_IP_MON_CTL_EN, 1u, 1u); if (!sdrv_ckgen_wait(ip_mon_ctrl, CKGEN_IP_MON_CTL_EN_STA, 1u, CKGEN_WAIT_TIME)) { goto ip_mon_get_rate_out; } if (!sdrv_ckgen_wait(ip_mon_ctrl, CKGEN_IP_MON_CTL_FREQ_UPD, 1u, CKGEN_WAIT_TIME)) { goto ip_mon_get_rate_out; } ip_mon_ctrl_val = readl(ip_mon_ctrl); freq_mon = (ip_mon_ctrl_val >> CKGEN_IP_MON_CTL_FREQ_LSB) & CKGEN_IP_MON_CTL_FREQ_MASK; div_a_b = (ip_mon_ctrl_val >> CKGEN_IP_MON_CTL_SRC_SEL) & 0x1; rate = sdrv_ckgen_mon_calc_freq(base, freq_mon, div_a_b); ip_mon_get_rate_out: /* disable ip mon */ RMWREG32(ip_mon_ctrl, CKGEN_IP_MON_CTL_EN, 1u, 0u); sdrv_ckgen_wait(ip_mon_ctrl, CKGEN_IP_MON_CTL_EN_STA, 0u, CKGEN_WAIT_TIME); /* disable ip slice debug */ RMWREG32(ip_ctrl, CKGEN_IP_CTL_DBG_EN, 1u, 0u); return rate; } void sdrv_ckgen_ip_mon_set_thrd(uint32_t base, uint32_t id, uint16_t low_thrd, uint16_t high_thrd) { uint32_t mon_thrd = CKGEN_IP_MON_THRD_BASE(base, id); RMWREG32(mon_thrd, CKGEN_IP_MON_THRD_LOW_LSB, 16u, low_thrd); RMWREG32(mon_thrd, CKGEN_IP_MON_THRD_HIGH_LSB, 16u, high_thrd); } uint32_t sdrv_ckgen_bus_mon_get_rate(uint32_t base, uint32_t id, uint8_t type) { uint32_t bus_mon_ctrl = CKGEN_BUS_MON_CTL0_BASE(base, id); uint32_t bus_mon_out; uint32_t bus_ctrl = CKGEN_BUS_CTL_BASE(base, id); uint32_t freq_lsb; uint32_t out; uint32_t bus_mon_ctrl_val; uint32_t freq_mon; uint8_t div_a_b; uint32_t rate = 0; if (type == CKGEN_HW_BUS_DIV_N) { out = 1; bus_mon_out = CKGEN_BUS_MON_CTL1_BASE(base, id); freq_lsb = CKGEN_BUS_MON_CTL1_FREQ1_LSB; } else if (type == CKGEN_HW_BUS_DIV_P) { out = 2; bus_mon_out = CKGEN_BUS_MON_CTL2_BASE(base, id); freq_lsb = CKGEN_BUS_MON_CTL2_FREQ2_LSB; } else if (type == CKGEN_HW_BUS_DIV_Q) { out = 3; bus_mon_out = CKGEN_BUS_MON_CTL2_BASE(base, id); freq_lsb = CKGEN_BUS_MON_CTL2_FREQ3_LSB; } else { out = 0; bus_mon_out = CKGEN_BUS_MON_CTL1_BASE(base, id); freq_lsb = CKGEN_BUS_MON_CTL1_FREQ0_LSB; } /* disable bus mon */ if (BIT(readl(bus_mon_ctrl), CKGEN_BUS_MON_CTL0_EN)) { RMWREG32(bus_mon_ctrl, CKGEN_BUS_MON_CTL0_EN, 1u, 0u); if (!sdrv_ckgen_wait(bus_mon_ctrl, CKGEN_BUS_MON_CTL0_EN_STA, 0u, CKGEN_WAIT_TIME)) { return 0; } } /* clear freq mon */ writel(0u, bus_mon_out); RMWREG32(bus_mon_ctrl, CKGEN_BUS_MON_CTL0_FREQ_UPD(out), 1u, 0u); /* enable bus slice debug */ RMWREG32(bus_ctrl, CKGEN_BUS_CTL_DBG_EN, 1u, 1u); /* enable bus mon */ RMWREG32(bus_mon_ctrl, CKGEN_BUS_MON_CTL0_EN, 1u, 1u); if (!sdrv_ckgen_wait(bus_mon_ctrl, CKGEN_BUS_MON_CTL0_EN_STA, 1u, CKGEN_WAIT_TIME)) { goto bus_mon_get_rate_out; } if (!sdrv_ckgen_wait(bus_mon_ctrl, CKGEN_BUS_MON_CTL0_FREQ_UPD(out), 1u, CKGEN_WAIT_TIME)) { goto bus_mon_get_rate_out; } freq_mon = (readl(bus_mon_out) >> freq_lsb) & CKGEN_BUS_MON_CTL_FREQ_MASK; bus_mon_ctrl_val = readl(bus_mon_ctrl); div_a_b = (bus_mon_ctrl_val >> CKGEN_BUS_MON_CTL0_SRC_SEL) & 0x1; rate = sdrv_ckgen_mon_calc_freq(base, freq_mon, div_a_b); bus_mon_get_rate_out: /* disable bus mon */ RMWREG32(bus_mon_ctrl, CKGEN_BUS_MON_CTL0_EN, 1u, 0u); sdrv_ckgen_wait(bus_mon_ctrl, CKGEN_BUS_MON_CTL0_EN_STA, 0u, CKGEN_WAIT_TIME); /* disable bus slice debug */ RMWREG32(bus_ctrl, CKGEN_BUS_CTL_DBG_EN, 1u, 0u); return rate; } void sdrv_ckgen_bus_mon_set_thrd(uint32_t base, uint32_t id, uint8_t type, uint16_t low_thrd, uint16_t high_thrd) { uint32_t bus_mon_thrd; if (type == CKGEN_HW_BUS_DIV_N) { bus_mon_thrd = CKGEN_BUS_MON_THRD1_BASE(base, id); } else if (type == CKGEN_HW_BUS_DIV_P) { bus_mon_thrd = CKGEN_BUS_MON_THRD2_BASE(base, id); } else if (type == CKGEN_HW_BUS_DIV_Q) { bus_mon_thrd = CKGEN_BUS_MON_THRD3_BASE(base, id); } else { bus_mon_thrd = CKGEN_BUS_MON_THRD0_BASE(base, id); } RMWREG32(bus_mon_thrd, CKGEN_BUS_MON_THRD_LOW_LSB, 16u, low_thrd); RMWREG32(bus_mon_thrd, CKGEN_BUS_MON_THRD_HIGH_LSB, 16u, high_thrd); } uint32_t sdrv_ckgen_core_mon_get_rate(uint32_t base, uint32_t id) { uint32_t core_mon_ctrl = CKGEN_CORE_MON_CTL_BASE(base, id); uint32_t core_ctrl = CKGEN_CORE_CTL_BASE(base, id); uint32_t core_mon_ctrl_val; uint32_t freq_mon; uint8_t div_a_b; uint32_t rate = 0; /* disable core mon */ if (BIT(readl(core_mon_ctrl), CKGEN_CORE_MON_CTL_EN)) { RMWREG32(core_mon_ctrl, CKGEN_CORE_MON_CTL_EN, 1u, 0u); if (!sdrv_ckgen_wait(core_mon_ctrl, CKGEN_CORE_MON_CTL_EN_STA, 0u, CKGEN_WAIT_TIME)) { return 0; } } /* clear freq mon */ RMWREG32(core_mon_ctrl, CKGEN_CORE_MON_CTL_FREQ_LSB, 16u, 0u); RMWREG32(core_mon_ctrl, CKGEN_CORE_MON_CTL_FREQ_UPD, 1u, 0u); /* enable core slice debug */ RMWREG32(core_ctrl, CKGEN_CORE_CTL_DBG_EN, 1u, 1u); /* enable core mon */ RMWREG32(core_mon_ctrl, CKGEN_CORE_MON_CTL_EN, 1u, 1u); if (!sdrv_ckgen_wait(core_mon_ctrl, CKGEN_CORE_MON_CTL_EN_STA, 1u, CKGEN_WAIT_TIME)) { goto core_mon_get_rate_out; } if (!sdrv_ckgen_wait(core_mon_ctrl, CKGEN_CORE_MON_CTL_FREQ_UPD, 1u, CKGEN_WAIT_TIME)) { goto core_mon_get_rate_out; } core_mon_ctrl_val = readl(core_mon_ctrl); freq_mon = (core_mon_ctrl_val >> CKGEN_CORE_MON_CTL_FREQ_LSB) & CKGEN_CORE_MON_CTL_FREQ_MASK; div_a_b = (core_mon_ctrl_val >> CKGEN_CORE_MON_CTL_SRC_SEL) & 0x1; rate = sdrv_ckgen_mon_calc_freq(base, freq_mon, div_a_b); core_mon_get_rate_out: /* disable core mon */ RMWREG32(core_mon_ctrl, CKGEN_CORE_MON_CTL_EN, 1u, 0u); sdrv_ckgen_wait(core_mon_ctrl, CKGEN_CORE_MON_CTL_EN_STA, 0u, CKGEN_WAIT_TIME); /* disable core slice debug */ RMWREG32(core_ctrl, CKGEN_CORE_CTL_DBG_EN, 1u, 0u); return rate; } void sdrv_ckgen_core_mon_set_thrd(uint32_t base, uint32_t id, uint16_t low_thrd, uint16_t high_thrd) { uint32_t mon_thrd = CKGEN_CORE_MON_THRD_BASE(base, id); RMWREG32(mon_thrd, CKGEN_CORE_MON_THRD_LOW_LSB, 16u, low_thrd); RMWREG32(mon_thrd, CKGEN_CORE_MON_THRD_HIGH_LSB, 16u, high_thrd); } bool sdrv_ckgen_mon_xcg_is_gated(uint32_t base, uint8_t cg_type, uint32_t id) { uint32_t state; sdrv_ckgen_xcg_amon_enable(base, cg_type, id, true); state = sdrv_ckgen_xcg_get_amon_state(base, cg_type, id); sdrv_ckgen_xcg_amon_enable(base, cg_type, id, false); return state ? false : true; } bool sdrv_ckgen_mon_pll_is_gated(uint32_t base, uint32_t id) { uint32_t state; sdrv_ckgen_pll_mon_enable(base, id, 0xffff); state = sdrv_ckgen_pll_mon_get_state(base, id); sdrv_ckgen_pll_mon_disable(base, id); return state ? false : true; } bool sdrv_ckgen_mon_xtal_is_gated(uint32_t base) { uint32_t state; sdrv_ckgen_xtal_mon_enable(base, 0xffff); state = sdrv_ckgen_xtal_mon_get_xtal_state(base); sdrv_ckgen_xtal_mon_disable(base); return state ? false : true; } uint32_t sdrv_ckgen_dbg_mon_get_ip_rate(uint32_t base, uint32_t id) { uint32_t ip_ctrl = CKGEN_IP_CTL_BASE(base, id); uint32_t rate; /* enable ip slice debug */ RMWREG32(ip_ctrl, CKGEN_IP_CTL_DBG_EN, 1u, 1u); rate = sdrv_ckgen_dbg_mon_get_rate(base, 0, id); /* disable ip slice debug */ RMWREG32(ip_ctrl, CKGEN_IP_CTL_DBG_EN, 1u, 0u); return rate; } uint32_t sdrv_ckgen_dbg_mon_get_bus_rate(uint32_t base, uint32_t id) { uint32_t bus_ctrl = CKGEN_BUS_CTL_BASE(base, id); uint32_t rate; /* enable bus slice debug */ RMWREG32(bus_ctrl, CKGEN_BUS_CTL_DBG_EN, 1u, 1u); rate = sdrv_ckgen_dbg_mon_get_rate(base, 1, id); /* disable bus slice debug */ RMWREG32(bus_ctrl, CKGEN_BUS_CTL_DBG_EN, 1u, 0u); return rate; } uint32_t sdrv_ckgen_dbg_mon_get_core_rate(uint32_t base, uint32_t id) { uint32_t core_ctrl = CKGEN_CORE_CTL_BASE(base, id); uint32_t rate; /* enable core slice debug */ RMWREG32(core_ctrl, CKGEN_CORE_CTL_DBG_EN, 1u, 1u); rate = sdrv_ckgen_dbg_mon_get_rate(base, 2, id); /* disable core slice debug */ RMWREG32(core_ctrl, CKGEN_CORE_CTL_DBG_EN, 1u, 0u); return rate; } uint32_t sdrv_ckgen_dbg_mon_get_ext_rate(uint32_t base, uint32_t id) { return sdrv_ckgen_dbg_mon_get_rate(base, 3, id); } void sdrv_ckgen_dbg_mon_ip_select(uint32_t base, uint32_t id) { uint32_t ip_ctrl = CKGEN_IP_CTL_BASE(base, id); uint32_t dbg_mon_ctl = base + CKGEN_DBG_MON_CTL; RMWREG32(ip_ctrl, CKGEN_IP_CTL_DBG_EN, 1u, 1u); sdrv_ckgen_dbg_mon_src_config(base, 0, id); RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_DBG_GATING_EN, 1u, 1u); } void sdrv_ckgen_dbg_mon_bus_select(uint32_t base, uint32_t id) { uint32_t bus_ctrl = CKGEN_BUS_CTL_BASE(base, id); uint32_t dbg_mon_ctl = base + CKGEN_DBG_MON_CTL; RMWREG32(bus_ctrl, CKGEN_BUS_CTL_DBG_EN, 1u, 1u); sdrv_ckgen_dbg_mon_src_config(base, 1, id); RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_DBG_GATING_EN, 1u, 1u); } void sdrv_ckgen_dbg_mon_core_select(uint32_t base, uint32_t id) { uint32_t core_ctrl = CKGEN_CORE_CTL_BASE(base, id); uint32_t dbg_mon_ctl = base + CKGEN_DBG_MON_CTL; RMWREG32(core_ctrl, CKGEN_CORE_CTL_DBG_EN, 1u, 1u); sdrv_ckgen_dbg_mon_src_config(base, 2, id); RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_DBG_GATING_EN, 1u, 1u); } void sdrv_ckgen_dbg_mon_ext_select(uint32_t base, uint32_t id) { uint32_t dbg_mon_ctl = base + CKGEN_DBG_MON_CTL; sdrv_ckgen_dbg_mon_src_config(base, 3, id); RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_DBG_GATING_EN, 1u, 1u); } uint32_t sdrv_ckgen_24M_mon_get_rate(uint32_t base) { uint32_t low_spd_chk_ctl = base + CKGEN_LOW_SPD_CHK_CTL; uint32_t mon_val; uint32_t freq_mon; uint32_t rate = 0; if (BIT(readl(low_spd_chk_ctl), CKGEN_LOW_SPD_CHK_CTL_MON_EN)) { RMWREG32(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_MON_EN, 1u, 0u); if (!sdrv_ckgen_wait(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_MON_EN_STA, 0u, CKGEN_WAIT_TIME)) { return 0; } } /* set 32k 24m src */ RMWREG32(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_24M_SEL, 6u, 0u); RMWREG32(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_32K_SEL, 6u, 0u); /* clear freq mon */ RMWREG32(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_FREQ_MON_LSB, 16u, 0u); RMWREG32(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_MON_UPD, 1u, 0u); /* enable mon */ RMWREG32(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_LOSS_DIS, 1u, 0u); RMWREG32(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_MON_EN, 1u, 1u); if (!sdrv_ckgen_wait(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_MON_EN_STA, 1u, CKGEN_WAIT_TIME)) { goto mon_24m_rate_out; } if (!sdrv_ckgen_wait(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_MON_UPD, 1u, CKGEN_WAIT_TIME)) { goto mon_24m_rate_out; } mon_val = readl(low_spd_chk_ctl); freq_mon = (mon_val >> CKGEN_LOW_SPD_CHK_CTL_FREQ_MON_LSB) & CKGEN_LOW_SPD_CHK_CTL_FREQ_MON_MASK; rate = freq_mon * 32000; mon_24m_rate_out: RMWREG32(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_MON_EN, 1u, 0u); sdrv_ckgen_wait(low_spd_chk_ctl, CKGEN_LOW_SPD_CHK_CTL_MON_EN_STA, 0u, CKGEN_WAIT_TIME); return rate; } void sdrv_ckgen_cqm_enable(uint32_t base, uint32_t id, uint16_t duty, uint16_t jitter) { uint32_t dbg_mon_ctl = base + CKGEN_DBG_MON_CTL; uint32_t cqm_ctl = CKGEN_CQM_CTL_BASE(base, id); /* enable cqm gating */ RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_CQM_GATING_EN, 1u, 1u); /* config cqm jitter and duty */ RMWREG32(cqm_ctl, CKGEN_CQM_CTL_JITTER_RATE_LSB, 6u, jitter); RMWREG32(cqm_ctl, CKGEN_CQM_CTL_DUTY_RATE_LSB, 6u, duty); /* enable cqm mon */ RMWREG32(cqm_ctl, CKGEN_CQM_CTL_MON_EN, 1u, 1u); } void sdrv_ckgen_cqm_disable(uint32_t base, uint32_t id) { uint32_t dbg_mon_ctl = base + CKGEN_DBG_MON_CTL; uint32_t cqm_ctl = CKGEN_CQM_CTL_BASE(base, id); RMWREG32(cqm_ctl, CKGEN_CQM_CTL_MON_EN, 1u, 0u); RMWREG32(dbg_mon_ctl, CKGEN_DBG_MON_CTL_CQM_GATING_EN, 1u, 0u); } void sdrv_ckgen_cqm_cor_int_enable(uint32_t base, uint32_t id, bool en) { RMWREG32(base + CKGEN_CQM_COR_EN, (id % 7u), 1u, en); } void sdrv_ckgen_cqm_unc_int_enable(uint32_t base, uint32_t id, bool en) { RMWREG32(base + CKGEN_CQM_UNC_EN, (id % 7u), 1u, en); } bool sdrv_ckgen_cqm_get_duty_int_state(uint32_t base, uint32_t id) { return !!(readl(base + CKGEN_CQM_DUTY_INT_STA) >> (id % 7u)); } bool sdrv_ckgen_cqm_get_jitter_int_state(uint32_t base, uint32_t id) { return !!(readl(base + CKGEN_CQM_JITTER_INT_STA) >> (id % 7u)); } void sdrv_ckgen_cqm_clear_duty_int_state(uint32_t base, uint32_t id) { RMWREG32(base + CKGEN_CQM_DUTY_INT_STA, (id % 7u), 1u, 0u); } void sdrv_ckgen_cqm_clear_jitter_int_state(uint32_t base, uint32_t id) { RMWREG32(base + CKGEN_CQM_JITTER_INT_STA, (id % 7u), 1u, 0u); }