637 lines
21 KiB
C
637 lines
21 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
|
|
*
|
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
|
*/
|
|
|
|
#include "cru_core.h"
|
|
#include "cru_rkx121.h"
|
|
|
|
/*
|
|
* [RKX121 CHIP]: TX
|
|
*
|
|
* ================= SECITON: Input clock from devices =========================
|
|
*
|
|
* ### 300M ###
|
|
* dclk_c_dvp_src
|
|
* dclk_d_dsi_src --|-- dclk_d_ds
|
|
* |-- dclk_d_dsi_pattern_gen
|
|
*
|
|
* clk_lvds0_src --|-- clk_lvds0
|
|
* |-- clk_lvds0_pattern_gen
|
|
*
|
|
* clk_lvds1_src --|-- clk_lvds1
|
|
* |-- clk_lvds1_pattern_gen
|
|
*
|
|
* dclk_rgc_src
|
|
*
|
|
*
|
|
* ### 200M ###
|
|
* clk_link_pcs0 --|-- clk_pma2pcs0 |-- clk_pma2link2pcs_link
|
|
* | |
|
|
* |-- clk_pma2link2pcs_cm (MUX) --|-- clk_pma2link2pcs_psc0
|
|
* clk_link_pcs1 --| |
|
|
* |-- clk_pma2pcs1 |-- clk_pma2link2pcs_psc1
|
|
*
|
|
* clk_txbytehs_dsitx_csitx0
|
|
* clk_txbytehs_dsitx_csitx1
|
|
*
|
|
*
|
|
*
|
|
* ### 150M ###
|
|
*
|
|
* rxpclk_vicap_lvds
|
|
*
|
|
*
|
|
* ### 100M ###
|
|
*
|
|
* clk_2x_pma2pcs0
|
|
* clk_2x_pma2pcs1
|
|
*
|
|
*
|
|
* ### 50M ###
|
|
* clk_txesc_mipitxphy0
|
|
* clk_rxesc_dsitx
|
|
*
|
|
*/
|
|
|
|
#define RKX120_SSCG_TXPLL_EN 0
|
|
#define RKX120_SSCG_CPLL_EN 0
|
|
#define RKX120_TESTOUT_MUX -1 /* valid options: RKX120_TEST_CLKOUT_IOUT_SEL_? */
|
|
|
|
#define RKX120_GRF_GPIO0B_IOMUX_H 0x0101000c
|
|
#define GPIO0B7_TEST_CLKOUT 0x01c00080
|
|
|
|
#define I2S_122888_BEST_PRATE 393216000
|
|
#define I2S_112896_BEST_PRATE 756403200
|
|
|
|
static struct PLL_CONFIG PLL_TABLE[] = {
|
|
/* _mhz, _refDiv, _fbDiv, _postdDv1, _postDiv2, _dsmpd, _frac */
|
|
RK_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
|
|
RK_PLL_RATE(600000000, 1, 25, 1, 1, 1, 0),
|
|
|
|
/* display */
|
|
RK_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
|
|
|
|
/* audio: 12.288M */
|
|
RK_PLL_RATE(688128000, 1, 86, 3, 1, 0, 268435), /* div=56, vco=2064.384M */
|
|
RK_PLL_RATE(393216000, 2, 131, 4, 1, 0, 1207959), /* div=32, vco=1572.864M */
|
|
RK_PLL_RATE(344064000, 1, 43, 3, 1, 0, 134217), /* div=28, vco=1032.192M */
|
|
/* audio: 11.2896M */
|
|
RK_PLL_RATE(474163200, 1, 79, 4, 1, 0, 456340), /* div=42, vco=1896.6528M */
|
|
RK_PLL_RATE(756403200, 1, 63, 2, 1, 0, 563714), /* div=67, vco=1512.8064M */
|
|
RK_PLL_RATE(564480000, 1, 47, 2, 1, 0, 671088), /* div=50, vco=1128.96M */
|
|
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
static struct PLL_SETUP TXPLL_SETUP = {
|
|
.id = PLL_TXPLL,
|
|
.conOffset0 = 0x01000020,
|
|
.conOffset1 = 0x01000024,
|
|
.conOffset2 = 0x01000028,
|
|
.conOffset3 = 0x0100002c,
|
|
.modeOffset = 0x01000600,
|
|
.modeShift = 0, /* 0: slow-mode, 1: normal-mode */
|
|
.lockShift = 10,
|
|
.modeMask = 0x1,
|
|
.rateTable = PLL_TABLE,
|
|
|
|
.minRefdiv = 1,
|
|
.maxRefdiv = 2,
|
|
.minVco = _MHZ(375),
|
|
.maxVco = _MHZ(2400),
|
|
.minFout = _MHZ(24),
|
|
.maxFout = _MHZ(1200),
|
|
.sscgEn = RKX120_SSCG_TXPLL_EN,
|
|
};
|
|
|
|
static struct PLL_SETUP CPLL_SETUP = {
|
|
.id = PLL_CPLL,
|
|
.conOffset0 = 0x01000000,
|
|
.conOffset1 = 0x01000004,
|
|
.conOffset2 = 0x01000008,
|
|
.conOffset3 = 0x0100000c,
|
|
.modeOffset = 0x01000600,
|
|
.modeShift = 2,
|
|
.lockShift = 10,
|
|
.modeMask = 0x1 << 2,
|
|
.rateTable = PLL_TABLE,
|
|
|
|
.minRefdiv = 1,
|
|
.maxRefdiv = 2,
|
|
.minVco = _MHZ(375),
|
|
.maxVco = _MHZ(2400),
|
|
.minFout = _MHZ(24),
|
|
.maxFout = _MHZ(1200),
|
|
.sscgEn = RKX120_SSCG_CPLL_EN,
|
|
};
|
|
|
|
static uint32_t RKX12x_HAL_CRU_ClkGetFreq(struct hwclk *hw, uint32_t clockName)
|
|
{
|
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
|
uint32_t pRate = 0, freq = 0;
|
|
uint32_t pRate0 = 0, pRate1 = 0;
|
|
|
|
switch (clockName) {
|
|
case RKX120_CPS_PLL_TXPLL:
|
|
freq = HAL_CRU_GetPllFreq(hw, &TXPLL_SETUP);
|
|
hw->pllRate[RKX120_TXPLL] = freq;
|
|
|
|
return freq;
|
|
|
|
case RKX120_CPS_PLL_CPLL:
|
|
freq = HAL_CRU_GetPllFreq(hw, &CPLL_SETUP);
|
|
hw->pllRate[RKX120_CPLL] = freq;
|
|
|
|
return freq;
|
|
|
|
/* lvds: 200M */
|
|
case RKX121_CPS_CLK_LVDS_C_LVDS_TX:
|
|
/* link: 300M */
|
|
case RKX120_CPS_E0_CLK_RKLINK_RX_PRE:
|
|
case RKX120_CPS_E1_CLK_RKLINK_RX_PRE:
|
|
/* csi: 50M */
|
|
case RKX120_CPS_CLK_TXESC_CSITX0:
|
|
case RKX120_CPS_CLK_TXESC_CSITX1:
|
|
/* i2s: 600M */
|
|
case RKX120_CPS_CLK_I2S_SRC_RKLINK_RX:
|
|
/* pwm: 100M */
|
|
case RKX120_CPS_CLK_PWM_TX:
|
|
case RKX120_CPS_PCLKOUT_DVPTX:
|
|
freq = HAL_CRU_MuxGetFreq3(hw, clkMux,
|
|
hw->pllRate[RKX120_TXPLL],
|
|
hw->pllRate[RKX120_CPLL], OSC_24M);
|
|
break;
|
|
|
|
/* gate clock from TX_E0_CLK_RKLINK_RX_PRE */
|
|
case RKX120_CPS_ICLK_C_CSI0:
|
|
|
|
return RKX12x_HAL_CRU_ClkGetFreq(hw, RKX120_CPS_E0_CLK_RKLINK_RX_PRE);
|
|
|
|
/* gate clock from TX_E1_CLK_RKLINK_RX_PRE */
|
|
case RKX120_CPS_ICLK_C_CSI1:
|
|
|
|
return RKX12x_HAL_CRU_ClkGetFreq(hw, RKX120_CPS_E1_CLK_RKLINK_RX_PRE);
|
|
|
|
case RKX121_CPS_CLK_LVDS0:
|
|
case RKX121_CPS_CLK_LVDS1:
|
|
pRate0 = _MHZ(150); /* input clock: clk_lvds1_cm */
|
|
pRate1 = RKX12x_HAL_CRU_ClkGetFreq(hw, RKX121_CPS_CLK_LVDS_C_LVDS_TX);
|
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux, pRate0, pRate1);
|
|
break;
|
|
|
|
/* pre-bus: 100M */
|
|
case RKX120_CPS_BUSCLK_TX_PRE0:
|
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux,
|
|
hw->pllRate[RKX120_TXPLL],
|
|
hw->pllRate[RKX120_CPLL]);
|
|
break;
|
|
/*
|
|
* bus: 100MHZ
|
|
*
|
|
* === TX_BUSCLK_TX_PRE gate children ===
|
|
*
|
|
* pclk_tx_cru
|
|
* pclk_tx_grf
|
|
* pclk_tx_gpio0/1
|
|
* pclk_tx_efuse
|
|
* pclk_mipi_grf_tx0/1
|
|
* pclk_tx_i2c2apb
|
|
* pclk_tx_i2c2apb_debug
|
|
* hclk_dvp_tx
|
|
* pclk_csitx0/1
|
|
* pclk_dsitx
|
|
* pclk_rklink_rx
|
|
* pclk_d_dsi_pattern_gen
|
|
* pclk_lvds{0, 1}_pattern_gen
|
|
* pclk_pcs0/1
|
|
* pclk_pcs{0,1}_ada
|
|
* pclk_mipitxphy0/1
|
|
* pclk_pwm_tx
|
|
* pclk_dft2apb
|
|
* pclk_lbist_ada_tx
|
|
*/
|
|
case RKX120_CPS_BUSCLK_TX_PRE:
|
|
pRate = RKX12x_HAL_CRU_ClkGetFreq(hw, RKX120_CPS_BUSCLK_TX_PRE0);
|
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux, OSC_24M, pRate);
|
|
break;
|
|
|
|
/* gpio: 24M */
|
|
case RKX120_CPS_DCLK_TX_GPIO0:
|
|
case RKX120_CPS_DCLK_TX_GPIO1:
|
|
/* efuse: 24M */
|
|
case RKX120_CPS_CLK_TX_EFUSE:
|
|
/* pcs_ada: 24M */
|
|
case RKX120_CPS_CLK_PCS0_ADA:
|
|
case RKX120_CPS_CLK_PCS1_ADA:
|
|
/* capture_pwm: 24M */
|
|
case RKX120_CPS_CLK_CAPTURE_PWM_TX:
|
|
|
|
return OSC_24M;
|
|
|
|
case RKX120_CPS_CLK_PMA2PCS2LINK_CM:
|
|
|
|
return _MHZ(200);
|
|
|
|
default:
|
|
CRU_ERR("%s: %s: Unknown clk 0x%08x\n", __func__, hw->name, clockName);
|
|
|
|
return HAL_INVAL;
|
|
}
|
|
|
|
if (!clkMux && !clkDiv) {
|
|
return 0;
|
|
}
|
|
|
|
if (clkDiv) {
|
|
freq /= (HAL_CRU_ClkGetDiv(hw, clkDiv));
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
static HAL_Status RKX12x_HAL_CRU_ClkSetFreq(struct hwclk *hw, uint32_t clockName, uint32_t rate)
|
|
{
|
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
|
uint32_t mux = 0, div = 1;
|
|
uint32_t pRate = 0;
|
|
uint32_t maxDiv;
|
|
uint32_t pll;
|
|
uint8_t overMax;
|
|
HAL_Status ret = HAL_OK;
|
|
int i;
|
|
|
|
switch (clockName) {
|
|
case RKX120_CPS_PLL_TXPLL:
|
|
ret = HAL_CRU_SetPllFreq(hw, &TXPLL_SETUP, rate);
|
|
hw->pllRate[RKX120_TXPLL] = rate;
|
|
CRU_MSG("%s: TXPLL set rate: %d\n", hw->name, rate);
|
|
|
|
return ret;
|
|
|
|
case RKX120_CPS_PLL_CPLL:
|
|
ret = HAL_CRU_SetPllFreq(hw, &CPLL_SETUP, rate);
|
|
hw->pllRate[RKX120_CPLL] = rate;
|
|
CRU_MSG("%s: CPLL set rate: %d\n", hw->name, rate);
|
|
|
|
return ret;
|
|
|
|
/* link(dclk): Allowed to change PLL rate if need ! */
|
|
case RKX120_CPS_E0_CLK_RKLINK_RX_PRE:
|
|
case RKX120_CPS_E1_CLK_RKLINK_RX_PRE:
|
|
/* i2s */
|
|
case RKX120_CPS_CLK_I2S_SRC_RKLINK_RX:
|
|
maxDiv = CLK_DIV_GET_MAXDIV(clkDiv);
|
|
|
|
if (DIV_NO_REM(hw->pllRate[RKX120_TXPLL], rate, maxDiv)) {
|
|
mux = 0;
|
|
pRate = hw->pllRate[RKX120_TXPLL];
|
|
} else if (DIV_NO_REM(hw->pllRate[RKX120_CPLL], rate, maxDiv)) {
|
|
mux = 1;
|
|
pRate = hw->pllRate[RKX120_CPLL];
|
|
} else if (DIV_NO_REM(OSC_24M, rate, maxDiv)) {
|
|
mux = 2;
|
|
pRate = OSC_24M;
|
|
} else {
|
|
if (clockName == RKX120_CPS_CLK_I2S_SRC_RKLINK_RX) {
|
|
pll = RKX120_CPS_PLL_CPLL;
|
|
if (DIV_NO_REM(I2S_122888_BEST_PRATE, rate, maxDiv)) {
|
|
pRate = I2S_122888_BEST_PRATE;
|
|
} else if (DIV_NO_REM(I2S_112896_BEST_PRATE, rate, maxDiv)) {
|
|
pRate = I2S_112896_BEST_PRATE;
|
|
}
|
|
} else {
|
|
pll = RKX120_CPS_PLL_TXPLL;
|
|
}
|
|
|
|
/* PLL change closest new rate <= 1200M if need */
|
|
if (!pRate) {
|
|
if (!rate || rate > _MHZ(1200))
|
|
return HAL_ERROR;
|
|
for (i = _MHZ(1200) / rate; i > _MHZ(24) / rate; i--) {
|
|
pRate = i * rate;
|
|
ret = RKX12x_HAL_CRU_ClkSetFreq(hw, pll, pRate);
|
|
if (ret == HAL_OK)
|
|
break;
|
|
}
|
|
if (ret != HAL_OK)
|
|
return ret;
|
|
} else {
|
|
ret = RKX12x_HAL_CRU_ClkSetFreq(hw, pll, pRate);
|
|
if (ret != HAL_OK) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* if success, continue to set divider */
|
|
}
|
|
break;
|
|
|
|
/* lvds */
|
|
case RKX121_CPS_CLK_LVDS_C_LVDS_TX:
|
|
/* csi */
|
|
case RKX120_CPS_CLK_TXESC_CSITX0:
|
|
case RKX120_CPS_CLK_TXESC_CSITX1:
|
|
/* pwm */
|
|
case RKX120_CPS_CLK_PWM_TX:
|
|
case RKX120_CPS_PCLKOUT_DVPTX:
|
|
mux = HAL_CRU_RoundFreqGetMux3(hw, rate,
|
|
hw->pllRate[RKX120_TXPLL],
|
|
hw->pllRate[RKX120_CPLL], OSC_24M, &pRate);
|
|
break;
|
|
/* gate clock from TX_E0_CLK_RKLINK_RX_PRE */
|
|
case RKX120_CPS_ICLK_C_CSI0:
|
|
|
|
return RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_E0_CLK_RKLINK_RX_PRE, rate);
|
|
|
|
/* gate clock from TX_E1_CLK_RKLINK_RX_PRE */
|
|
case RKX120_CPS_ICLK_C_CSI1:
|
|
|
|
return RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_E1_CLK_RKLINK_RX_PRE, rate);
|
|
|
|
/* lvds */
|
|
case RKX121_CPS_CLK_LVDS0:
|
|
case RKX121_CPS_CLK_LVDS1:
|
|
if (rate == _MHZ(150)) {
|
|
return HAL_CRU_ClkSetMux(hw, clkMux, 0); /* input clock: clk_lvds1_cm */
|
|
} else {
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX121_CPS_CLK_LVDS_C_LVDS_TX, rate);
|
|
|
|
return HAL_CRU_ClkSetMux(hw, clkMux, 1);
|
|
}
|
|
break;
|
|
|
|
/* pre-bus */
|
|
case RKX120_CPS_BUSCLK_TX_PRE0:
|
|
mux = HAL_CRU_RoundFreqGetMux2(hw, rate,
|
|
hw->pllRate[RKX120_TXPLL],
|
|
hw->pllRate[RKX120_CPLL], &pRate);
|
|
break;
|
|
|
|
case RKX120_CPS_BUSCLK_TX_PRE:
|
|
if (rate == OSC_24M) {
|
|
return HAL_CRU_ClkSetMux(hw, clkMux, 0);
|
|
} else {
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_BUSCLK_TX_PRE0, rate);
|
|
|
|
return HAL_CRU_ClkSetMux(hw, clkMux, 1);
|
|
}
|
|
break;
|
|
|
|
/* gpio: 24M */
|
|
case RKX120_CPS_DCLK_TX_GPIO0:
|
|
case RKX120_CPS_DCLK_TX_GPIO1:
|
|
/* efuse: 24M */
|
|
case RKX120_CPS_CLK_TX_EFUSE:
|
|
/* pcs_ada: 24M */
|
|
case RKX120_CPS_CLK_PCS0_ADA:
|
|
case RKX120_CPS_CLK_PCS1_ADA:
|
|
/* capture_pwm: 24M */
|
|
case RKX120_CPS_CLK_CAPTURE_PWM_TX:
|
|
|
|
return rate == OSC_24M ? 0 : HAL_INVAL;
|
|
|
|
case RKX120_CPS_CLK_PMA2PCS2LINK_CM:
|
|
if (rate != _MHZ(200)) {
|
|
return HAL_INVAL;
|
|
}
|
|
|
|
HAL_CRU_ClkSetMux(hw, clkMux, 0);
|
|
|
|
return HAL_OK;
|
|
|
|
default:
|
|
CRU_ERR("%s: %s: Unknown clk 0x%08x\n", __func__, hw->name, clockName);
|
|
|
|
return HAL_INVAL;
|
|
}
|
|
|
|
if (!clkMux && !clkDiv) {
|
|
return HAL_INVAL;
|
|
}
|
|
|
|
if (pRate) {
|
|
div = HAL_DIV_ROUND_UP(pRate, rate);
|
|
}
|
|
|
|
if (clkDiv) {
|
|
overMax = div > CLK_DIV_GET_MAXDIV(clkDiv);
|
|
if (overMax) {
|
|
CRU_MSG("%s: %s: Clk '0x%08x' req div(%d) over max(%d)!\n",
|
|
__func__, hw->name, clockName, div, CLK_DIV_GET_MAXDIV(clkDiv));
|
|
div = CLK_DIV_GET_MAXDIV(clkDiv);
|
|
}
|
|
HAL_CRU_ClkSetDiv(hw, clkDiv, div);
|
|
}
|
|
|
|
if (clkMux) {
|
|
HAL_CRU_ClkSetMux(hw, clkMux, mux);
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
#if RKX120_SSCG_CPLL_EN || RKX120_SSCG_TXPLL_EN
|
|
static void RKX12x_HAL_CRU_Init_SSCG(struct hwclk *hw)
|
|
{
|
|
uint8_t down_spread = 1; /* 0: center spread */
|
|
uint8_t amplitude = 8; /* range: 0x00 - 0x1f */
|
|
|
|
#if RKX120_SSCG_CPLL_EN
|
|
/* down-spread, 0.8%, 37.5khz */
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x0c, 0x1f000000 | ((amplitude & 0x1f) << 8));
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x0c, 0x00f00050);
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x0c, 0x00080000 | ((down_spread & 0x1) << 3));
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x04, 0x10000000);
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x0c, 0x00070000);
|
|
CRU_MSG("%s: CPLL enable SSCG\n", hw->name);
|
|
#endif
|
|
#if RKX120_SSCG_TXPLL_EN
|
|
/* down-spread, 0.8%, 37.5khz */
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x2c, 0x1f000000 | ((amplitude & 0x1f) << 8));
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x2c, 0x00f00050);
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x2c, 0x00080000 | ((down_spread & 0x1) << 3));
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x24, 0x10000000);
|
|
HAL_CRU_Write(hw, hw->cru_base + 0x2c, 0x00070000);
|
|
CRU_MSG("%s: TXPLL enable SSCG\n", hw->name);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
static HAL_Status RKX12x_HAL_CRU_InitTestout(struct hwclk *hw, uint32_t clockName,
|
|
uint32_t muxValue, uint32_t divValue)
|
|
{
|
|
uint32_t clkMux = CLK_GET_MUX(RKX120_CPS_TEST_CLKOUT);
|
|
uint32_t clkDiv = CLK_GET_DIV(RKX120_CPS_TEST_CLKOUT);
|
|
|
|
/* gpio0_b7: iomux to clk_testout */
|
|
HAL_CRU_Write(hw, RKX120_GRF_GPIO0B_IOMUX_H, GPIO0B7_TEST_CLKOUT);
|
|
|
|
/* Enable clock */
|
|
HAL_CRU_ClkEnable(hw, RKX120_CLK_TESTOUT_TOP_GATE);
|
|
|
|
/* Mux, div */
|
|
HAL_CRU_ClkSetDiv(hw, clkDiv, divValue);
|
|
HAL_CRU_ClkSetMux(hw, clkMux, muxValue);
|
|
|
|
CRU_MSG("%s: Testout div=%d, mux=%d\n", hw->name, divValue, muxValue);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
static HAL_Status RKX12x_HAL_CRU_Init(struct hwclk *hw, struct xferclk *xfer)
|
|
{
|
|
hw->cru_base = 0x01000000;
|
|
hw->sel_con0 = hw->cru_base + 0x100;
|
|
hw->gate_con0 = hw->cru_base + 0x300;
|
|
hw->softrst_con0 = hw->cru_base + 0x400;
|
|
hw->gbl_srst_fst = 0x0614;
|
|
hw->flags = 0;
|
|
hw->num_gate = 16 * 12;
|
|
hw->gate = HAL_KCALLOC(hw->num_gate, sizeof(struct clkGate));
|
|
if (!hw->gate) {
|
|
return HAL_NOMEM;
|
|
}
|
|
strcat(hw->name, "<CRU.121@");
|
|
strcat(hw->name, xfer->name);
|
|
strcat(hw->name, ">");
|
|
|
|
/* Don't change order */
|
|
#if RKX120_SSCG_CPLL_EN || RKX120_SSCG_TXPLL_EN
|
|
RKX12x_HAL_CRU_Init_SSCG(hw);
|
|
#endif
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_PLL_CPLL, _MHZ(1200));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_PLL_TXPLL, _MHZ(1188));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_BUSCLK_TX_PRE, _MHZ(100));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX121_CPS_CLK_LVDS_C_LVDS_TX, _MHZ(200));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_PMA2PCS2LINK_CM, _MHZ(200));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_I2S_SRC_RKLINK_RX, _MHZ(400));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_PWM_TX, _MHZ(24));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_TXESC_CSITX0, _MHZ(20));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_TXESC_CSITX1, _MHZ(20));
|
|
|
|
/* Must be the same rate as RKX110_CPS_DCLK_RX_PRE when camera mode */
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_E0_CLK_RKLINK_RX_PRE, _MHZ(200));
|
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_E1_CLK_RKLINK_RX_PRE, _MHZ(200));
|
|
|
|
HAL_CRU_ClkEnable(hw, RKX120_CLK_TESTOUT_TOP_GATE);
|
|
|
|
#if RKX120_TESTOUT_MUX >= 0
|
|
/* clk_testout support max 150M output, so set div=10 by default if not 24M */
|
|
RKX12x_HAL_CRU_InitTestout(hw, RKX120_CPS_TEST_CLKOUT, RKX120_TESTOUT_MUX,
|
|
RKX120_TESTOUT_MUX == 0 ? 1 : 10);
|
|
#endif
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
PNAME(mux_24m_p) = { "xin24m" };
|
|
PNAME(mux_txpll_cpll_p) = { "txpll", "cpll" };
|
|
PNAME(mux_txpll_cpll_24m_p) = { "txpll", "cpll", "xin24m" };
|
|
PNAME(mux_24m_txpre0_p) = { "xin24m", "busclk_tx_pre0" };
|
|
|
|
#define CAL_FREQ_REG 0x01000f00
|
|
#define CAL_FREQ_EN_REG 0x01000f04
|
|
|
|
static uint32_t RKX12x_HAL_CRU_ClkGetExtFreq(struct hwclk *hw, uint32_t clk)
|
|
{
|
|
uint32_t clkMux = CLK_GET_MUX(RKX120_CPS_TEST_CLKOUT);
|
|
uint32_t clkDiv = CLK_GET_DIV(RKX120_CPS_TEST_CLKOUT);
|
|
uint32_t freq, mhz;
|
|
uint8_t div = 10;
|
|
|
|
HAL_CRU_ClkSetDiv(hw, clkDiv, div);
|
|
HAL_CRU_ClkSetMux(hw, clkMux, clk);
|
|
HAL_CRU_Write(hw, CAL_FREQ_EN_REG, 1); /* NOTE: 1: enable, 0: disable */
|
|
HAL_SleepMs(2);
|
|
freq = HAL_CRU_Read(hw, CAL_FREQ_REG);
|
|
HAL_CRU_Write(hw, CAL_FREQ_EN_REG, 0x0);
|
|
|
|
/* Fix accuracy */
|
|
if ((freq % 10) == 0x9) {
|
|
freq++;
|
|
}
|
|
|
|
freq *= (1000 * div);
|
|
|
|
/* If no external input, freq is close to 24M */
|
|
mhz = freq / 1000000;
|
|
if ((clk != 0) && (mhz == 23 || mhz == 24)) {
|
|
freq = 0;
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
static struct clkTable rkx12x_clkTable[] = {
|
|
/* internal */
|
|
CLK_DECLARE_INT("txpll", RKX120_CPS_PLL_TXPLL, mux_24m_p),
|
|
CLK_DECLARE_INT("cpll", RKX120_CPS_PLL_CPLL, mux_24m_p),
|
|
CLK_DECLARE_INT("e0_clk_rklink_rx_pre", RKX120_CPS_E0_CLK_RKLINK_RX_PRE, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("e1_clk_rklink_rx_pre", RKX120_CPS_E1_CLK_RKLINK_RX_PRE, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("iclk_c_csi0", RKX120_CPS_ICLK_C_CSI0, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("iclk_c_csi1", RKX120_CPS_ICLK_C_CSI1, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_txesc_csitx0", RKX120_CPS_CLK_TXESC_CSITX0, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_txesc_csitx1", RKX120_CPS_CLK_TXESC_CSITX1, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_i2s_src_rklink_rx", RKX120_CPS_CLK_I2S_SRC_RKLINK_RX, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_pwm_tx", RKX120_CPS_CLK_PWM_TX, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("pclkout_dvptx", RKX120_CPS_PCLKOUT_DVPTX, mux_txpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("busclk_tx_pre0", RKX120_CPS_BUSCLK_TX_PRE0, mux_txpll_cpll_p),
|
|
CLK_DECLARE_INT("busclk_tx_pre", RKX120_CPS_BUSCLK_TX_PRE, mux_24m_txpre0_p),
|
|
CLK_DECLARE_INT("dclk_tx_gpio0", RKX120_CPS_DCLK_TX_GPIO0, mux_24m_p),
|
|
CLK_DECLARE_INT("dclk_tx_gpio1", RKX120_CPS_DCLK_TX_GPIO1, mux_24m_p),
|
|
CLK_DECLARE_INT("clk_tx_efuse", RKX120_CPS_CLK_TX_EFUSE, mux_24m_p),
|
|
CLK_DECLARE_INT("clk_pcs0_ada", RKX120_CPS_CLK_PCS0_ADA, mux_24m_p),
|
|
CLK_DECLARE_INT("clk_pcs1_ada", RKX120_CPS_CLK_PCS1_ADA, mux_24m_p),
|
|
CLK_DECLARE_INT("clk_capture_pwm_tx", RKX120_CPS_CLK_CAPTURE_PWM_TX, mux_24m_p),
|
|
|
|
/* external */
|
|
CLK_DECLARE_EXT("xin24m", 0, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_txbytehs_csitx0", 3, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_txbytehs_csitx1", 5, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_txbytehs_dsitx", 7, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_rxesc_dsitx", 8, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_link_pcs0", 9, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_link_pcs1", 10, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_pmarx0_pixel", 11, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_pmarx1_pixel", 12, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_mipitxphy0_lvds", 13, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_mipitxphy0_pixel", 14, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_mipitxphy1_lvds", 15, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_mipitxphy1_pixel", 16, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_txbytehs_dsitx_csitx0", 23, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("dclk_c_dvp_src", 24, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("dclk_d_dsi_src", 25, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_lvds0_src", 26, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_lvds1_src", 27, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("dclk_rgb_src", 28, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_2x_pma2pcs0", 29, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_2x_pma2pcs1", 30, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_txesc_mipitxphy0", 31, RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
|
|
CLK_DECLARE_EXT_PARENT("dclk_d_ds", 25, "dclk_d_dsi_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("dclk_d_dsi_pattern_gen", 25, "dclk_d_dsi_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_lvds0", 26, "clk_lvds0_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_lvds0_pattern_gen", 26, "clk_lvds0_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_lvds1", 27, "clk_lvds1_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_lvds1_pattern_gen", 27, "clk_lvds1_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_pma2pcs0", 9, "clk_link_pcs0", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_pma2link2pcs_cm", 9, "clk_link_pcs0", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_pma2pcs1", 10, "clk_link_pcs1", RKX12x_HAL_CRU_ClkGetExtFreq),
|
|
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
struct clkOps rkx121_clk_ops =
|
|
{
|
|
.clkTable = rkx12x_clkTable,
|
|
.clkInit = RKX12x_HAL_CRU_Init,
|
|
.clkGetFreq = RKX12x_HAL_CRU_ClkGetFreq,
|
|
.clkSetFreq = RKX12x_HAL_CRU_ClkSetFreq,
|
|
.clkInitTestout = RKX12x_HAL_CRU_InitTestout,
|
|
};
|