Files
base/drivers/source/clk/sdrv_ckgen_hw_access.c
2025-11-07 09:57:14 +08:00

1422 lines
44 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file sdrv_ckgen_hw_access.c
* @brief taishan ckgen hw access source file.
*
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include <compiler.h>
#include <bits.h>
#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 1b1. */
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 1b0, wait pre_en_ack to 1b0.*/
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 1b1, wait pre_en_ack to 1b1.*/
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 1b0. */
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 1b1. */
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 1b0, wait pre_en_ack to 1b0.*/
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 1b1, wait pre_en_ack to 1b1.*/
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 1b0. */
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 1b1, wait pre_en_ack to 1b1.*/
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 1b1. */
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 1b0, wait pre_en_ack to 1b0.*/
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 1b1, wait pre_en_ack to 1b1.*/
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 1b0. */
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);
}