623 lines
20 KiB
C
623 lines
20 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
|
*
|
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
|
*/
|
|
|
|
#include "cru_core.h"
|
|
#include "cru_rkx110.h"
|
|
|
|
/*
|
|
* [RKX110 CHIP]: RX
|
|
*
|
|
* ================= SECTION: Input clock from devices =========================
|
|
*
|
|
* ### 300M ###
|
|
* clk_8x_pma2pcs0
|
|
* clk_8x_pma2pcs1
|
|
*
|
|
*
|
|
* ### 200M ###
|
|
* sclk_i2s_link2pcs --|-- sclk_i2s_link2pcs_inter1
|
|
* |-- sclk_i2s_link2pcs_inter2
|
|
*
|
|
*
|
|
* ### 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_rxbytehs_csihost0
|
|
* clk_rxbytehs_csihost1
|
|
* iclk_dsi0
|
|
* iclk_dsi1
|
|
* iclk_vicap
|
|
*
|
|
*
|
|
* ### 150M ###
|
|
* dclk_lvds0 -- clk_d_lvds0_rklink_tx_cm --|-- clk_d_lvds0_pattern_gen_en
|
|
* |-- clk_d_lvds0_rklink_tx
|
|
*
|
|
* dclk_lvds1 -- clk_d_lvds1_rklink_tx_cm --|-- clk_d_lvds1_pattern_gen_en
|
|
* |-- clk_d_lvds1_rklink_tx
|
|
*
|
|
* clk_d_rgb_rklink_tx
|
|
* pclkin_vicap_dvp_rx
|
|
* rxpclk_lvds_align
|
|
* rxpclk_vicap_lvds
|
|
*/
|
|
|
|
#define RKX110_SSCG_RXPLL_EN 0
|
|
#define RKX110_SSCG_CPLL_EN 0
|
|
#define RKX110_TESTOUT_MUX -1 /* valid options: RKX110_TEST_CLKOUT_IOUT_SEL_? */
|
|
|
|
#define RKX110_GRF_GPIO0B_IOMUX_H 0x0001000c
|
|
#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 RXPLL_SETUP = {
|
|
.id = PLL_RXPLL,
|
|
.conOffset0 = 0x00000020,
|
|
.conOffset1 = 0x00000024,
|
|
.conOffset2 = 0x00000028,
|
|
.conOffset3 = 0x0000002c,
|
|
.modeOffset = 0x00000600,
|
|
.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 = RKX110_SSCG_RXPLL_EN,
|
|
};
|
|
|
|
static struct PLL_SETUP CPLL_SETUP = {
|
|
.id = PLL_CPLL,
|
|
.conOffset0 = 0x00000000,
|
|
.conOffset1 = 0x00000004,
|
|
.conOffset2 = 0x00000008,
|
|
.conOffset3 = 0x0000000c,
|
|
.modeOffset = 0x00000600,
|
|
.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 = RKX110_SSCG_CPLL_EN,
|
|
};
|
|
|
|
static uint32_t RKX11x_HAL_CRU_ClkGetFreq(struct hwclk *hw, uint32_t clockName)
|
|
{
|
|
uint32_t pRate = 0, freq = 0;
|
|
uint32_t clkMux, clkDiv;
|
|
|
|
if (clockName == RKX110_CLK_D_DSI_0_PATTERN_GEN ||
|
|
clockName == RKX110_CLK_D_DSI_1_PATTERN_GEN) {
|
|
clockName = RKX110_CPS_DCLK_RX_PRE;
|
|
}
|
|
|
|
clkMux = CLK_GET_MUX(clockName);
|
|
clkDiv = CLK_GET_DIV(clockName);
|
|
|
|
switch (clockName) {
|
|
case RKX110_CPS_PLL_RXPLL:
|
|
hw->pllRate[RKX110_RXPLL] = HAL_CRU_GetPllFreq(hw, &RXPLL_SETUP);
|
|
|
|
return hw->pllRate[RKX110_RXPLL];
|
|
|
|
case RKX110_CPS_PLL_CPLL:
|
|
hw->pllRate[RKX110_CPLL] = HAL_CRU_GetPllFreq(hw, &CPLL_SETUP);
|
|
|
|
return hw->pllRate[RKX110_CPLL];
|
|
|
|
/*
|
|
* 400MHZ => down to 200M
|
|
* === RX_DCLK_RX_PRE gate children ===
|
|
*
|
|
* dclk_dsi0
|
|
* dclk_dsi1
|
|
* dclk_vicap_csi
|
|
*
|
|
* clk_c_dvp_rklink_tx
|
|
* clk_c_csi_rklink_tx
|
|
*
|
|
* clk_d_dsi_0_rklink_tx
|
|
* clk_d_dsi_1_rklink_tx
|
|
* clk_d_dsi_0_pattern_gen
|
|
* clk_d_dsi_1_pattern_gen
|
|
* clk_c_lvds_rklink_tx
|
|
*
|
|
* NOTE: `clk_d_rgb_rklink_tx` is an input clock.
|
|
*
|
|
*/
|
|
case RKX110_CPS_DCLK_RX_PRE:
|
|
/* camera: 150M */
|
|
case RKX110_CPS_CLK_CAM0_OUT2IO:
|
|
case RKX110_CPS_CLK_CAM1_OUT2IO:
|
|
case RKX110_CPS_CLK_CIF_OUT2IO:
|
|
/* dsi: 200M */
|
|
case RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX:
|
|
case RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX:
|
|
/* lvds: 300M */
|
|
case RKX110_CPS_CLK_2X_LVDS_RKLINK_TX:
|
|
/* i2s: 600M => down to 300M */
|
|
case RKX110_CPS_CLK_I2S_SRC_RKLINK_TX:
|
|
freq = HAL_CRU_MuxGetFreq3(hw, clkMux, hw->pllRate[RKX110_RXPLL],
|
|
hw->pllRate[RKX110_CPLL], OSC_24M);
|
|
break;
|
|
|
|
/* mipi: ref_1000M, cfg_100M */
|
|
case RKX110_CPS_CKREF_MIPIRXPHY0:
|
|
case RKX110_CPS_CKREF_MIPIRXPHY1:
|
|
case RKX110_CPS_CFGCLK_MIPIRXPHY0:
|
|
case RKX110_CPS_CFGCLK_MIPIRXPHY1:
|
|
/* pre-bus: 100M */
|
|
case RKX110_CPS_BUSCLK_RX_PRE0:
|
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux, hw->pllRate[RKX110_RXPLL],
|
|
hw->pllRate[RKX110_CPLL]);
|
|
break;
|
|
|
|
/*
|
|
* bus: 100MHZ => down to 24M
|
|
*
|
|
* === RX_BUSCLK_RX_PRE gate children ===
|
|
*
|
|
* pclk_rx_cru
|
|
* pclk_rx_grf
|
|
* pclk_rx_gpio0/1
|
|
* pclk_rx_efuse
|
|
* pclk_mipi_grf_rx0/1
|
|
* pclk_rx_i2c2apb
|
|
* pclk_rx_i2c2apb_debug
|
|
* pclk_csihost0/1
|
|
* pclk_rklink_tx
|
|
* pclk_dsi_{0,1}_pattern_gen
|
|
* pclk_lvds_{0,1}_pattern_gen
|
|
* pclk_pcs0/1
|
|
* pclk_pcs{0,1}_ada
|
|
* pclk_mipirxphy0/1
|
|
* pclk_dft2apb
|
|
*
|
|
* hclk_vicap
|
|
* hclk_dsi0/1
|
|
*/
|
|
case RKX110_CPS_BUSCLK_RX_PRE:
|
|
pRate = RKX11x_HAL_CRU_ClkGetFreq(hw, RKX110_CPS_BUSCLK_RX_PRE0);
|
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux, OSC_24M, pRate);
|
|
break;
|
|
|
|
case RKX110_CPS_CLK_PMA2LINK2PCS_CM:
|
|
|
|
return _MHZ(200);
|
|
|
|
/* gpio: 24M */
|
|
case RKX110_CPS_DCLK_RX_GPIO0:
|
|
case RKX110_CPS_DCLK_RX_GPIO1:
|
|
/* efuse: 24M */
|
|
case RKX110_CPS_RX_EFUSE:
|
|
/* pcs_ada: 24M */
|
|
case RKX110_CPS_PCS0_ADA:
|
|
case RKX110_CPS_PCS1_ADA:
|
|
|
|
return OSC_24M;
|
|
|
|
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 RKX11x_HAL_CRU_ClkSetFreq(struct hwclk *hw, uint32_t clockName, uint32_t rate)
|
|
{
|
|
uint32_t clkMux, clkDiv;
|
|
uint32_t mux = 0, div = 1;
|
|
uint32_t pRate = 0;
|
|
uint32_t maxDiv;
|
|
uint32_t pll;
|
|
uint8_t overMax = 0;
|
|
HAL_Status ret = HAL_OK;
|
|
int i;
|
|
|
|
if (clockName == RKX110_CLK_D_DSI_0_PATTERN_GEN ||
|
|
clockName == RKX110_CLK_D_DSI_1_PATTERN_GEN) {
|
|
clockName = RKX110_CPS_DCLK_RX_PRE;
|
|
}
|
|
|
|
clkMux = CLK_GET_MUX(clockName);
|
|
clkDiv = CLK_GET_DIV(clockName);
|
|
|
|
switch (clockName) {
|
|
case RKX110_CPS_PLL_RXPLL:
|
|
ret = HAL_CRU_SetPllFreq(hw, &RXPLL_SETUP, rate);
|
|
if (ret != HAL_OK) {
|
|
CRU_ERR("%s: RXPLL set rate: %d failed\n", hw->name, rate);
|
|
} else {
|
|
hw->pllRate[RKX110_RXPLL] = rate;
|
|
CRU_MSG("%s: RXPLL set rate: %d\n", hw->name, rate);
|
|
}
|
|
|
|
return ret;
|
|
|
|
case RKX110_CPS_PLL_CPLL:
|
|
ret = HAL_CRU_SetPllFreq(hw, &CPLL_SETUP, rate);
|
|
if (ret != HAL_OK) {
|
|
CRU_ERR("%s: CPLL set rate: %d failed\n", hw->name, rate);
|
|
} else {
|
|
hw->pllRate[RKX110_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 RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX:
|
|
case RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX:
|
|
case RKX110_CPS_CLK_2X_LVDS_RKLINK_TX:
|
|
/* i2s */
|
|
case RKX110_CPS_CLK_I2S_SRC_RKLINK_TX:
|
|
maxDiv = CLK_DIV_GET_MAXDIV(clkDiv);
|
|
|
|
if (DIV_NO_REM(hw->pllRate[RKX110_RXPLL], rate, maxDiv)) {
|
|
mux = 0;
|
|
pRate = hw->pllRate[RKX110_RXPLL];
|
|
} else if (DIV_NO_REM(hw->pllRate[RKX110_CPLL], rate, maxDiv)) {
|
|
mux = 1;
|
|
pRate = hw->pllRate[RKX110_CPLL];
|
|
} else if (DIV_NO_REM(OSC_24M, rate, maxDiv)) {
|
|
mux = 2;
|
|
pRate = OSC_24M;
|
|
} else {
|
|
if (clockName == RKX110_CPS_CLK_I2S_SRC_RKLINK_TX) {
|
|
pll = RKX110_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 = RKX110_CPS_PLL_RXPLL;
|
|
}
|
|
|
|
/* 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 = RKX11x_HAL_CRU_ClkSetFreq(hw, pll, pRate);
|
|
if (ret == HAL_OK)
|
|
break;
|
|
}
|
|
if (ret != HAL_OK)
|
|
return ret;
|
|
} else {
|
|
ret = RKX11x_HAL_CRU_ClkSetFreq(hw, pll, pRate);
|
|
if (ret != HAL_OK) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* if success, continue to set divider */
|
|
}
|
|
break;
|
|
|
|
/* bus */
|
|
case RKX110_CPS_DCLK_RX_PRE:
|
|
/* camera */
|
|
case RKX110_CPS_CLK_CAM0_OUT2IO:
|
|
case RKX110_CPS_CLK_CAM1_OUT2IO:
|
|
case RKX110_CPS_CLK_CIF_OUT2IO:
|
|
mux = HAL_CRU_RoundFreqGetMux3(hw, rate, hw->pllRate[RKX110_RXPLL],
|
|
hw->pllRate[RKX110_CPLL], OSC_24M, &pRate);
|
|
break;
|
|
|
|
/* mipi */
|
|
case RKX110_CPS_CKREF_MIPIRXPHY0:
|
|
case RKX110_CPS_CKREF_MIPIRXPHY1:
|
|
case RKX110_CPS_CFGCLK_MIPIRXPHY0:
|
|
case RKX110_CPS_CFGCLK_MIPIRXPHY1:
|
|
/* pre-bus */
|
|
case RKX110_CPS_BUSCLK_RX_PRE0:
|
|
mux = HAL_CRU_RoundFreqGetMux2(hw, rate, hw->pllRate[RKX110_RXPLL],
|
|
hw->pllRate[RKX110_CPLL], &pRate);
|
|
break;
|
|
|
|
/* bus */
|
|
case RKX110_CPS_BUSCLK_RX_PRE:
|
|
if (rate == OSC_24M) {
|
|
return HAL_CRU_ClkSetMux(hw, clkMux, 0);
|
|
} else {
|
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_BUSCLK_RX_PRE0, rate);
|
|
|
|
return HAL_CRU_ClkSetMux(hw, clkMux, 1);
|
|
}
|
|
break;
|
|
|
|
/* gpio */
|
|
case RKX110_CPS_DCLK_RX_GPIO0:
|
|
case RKX110_CPS_DCLK_RX_GPIO1:
|
|
/* efuse */
|
|
case RKX110_CPS_RX_EFUSE:
|
|
/* pcs_ada */
|
|
case RKX110_CPS_PCS0_ADA:
|
|
case RKX110_CPS_PCS1_ADA:
|
|
|
|
return rate == OSC_24M ? 0 : HAL_INVAL;
|
|
|
|
case RKX110_CPS_CLK_PMA2LINK2PCS_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 RKX110_SSCG_CPLL_EN || RKX110_SSCG_RXPLL_EN
|
|
static void RKX11x_HAL_CRU_Init_SSCG(struct hwclk *hw)
|
|
{
|
|
uint8_t down_spread = 1; /* 0: center spread */
|
|
uint8_t amplitude = 8; /* range: 0x00 - 0x1f */
|
|
|
|
#if RKX110_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 RKX110_SSCG_RXPLL_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: RXPLL enable SSCG\n", hw->name);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
static HAL_Status RKX11x_HAL_CRU_InitTestout(struct hwclk *hw, uint32_t clockName,
|
|
uint32_t muxValue, uint32_t divValue)
|
|
{
|
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
|
|
|
/* gpio0_b7: iomux to clk_testout */
|
|
HAL_CRU_Write(hw, RKX110_GRF_GPIO0B_IOMUX_H, GPIO0B7_TEST_CLKOUT);
|
|
|
|
/* Enable clock */
|
|
HAL_CRU_ClkEnable(hw, RKX110_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 RKX11x_HAL_CRU_Init(struct hwclk *hw, struct xferclk *xfer)
|
|
{
|
|
hw->cru_base = 0x0;
|
|
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.110@");
|
|
strcat(hw->name, xfer->name);
|
|
strcat(hw->name, ">");
|
|
|
|
/* Don't change order */
|
|
#if RKX110_SSCG_CPLL_EN || RKX110_SSCG_RXPLL_EN
|
|
RKX11x_HAL_CRU_Init_SSCG(hw);
|
|
#endif
|
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_PLL_CPLL, _MHZ(1200));
|
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_PLL_RXPLL, _MHZ(1188));
|
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_BUSCLK_RX_PRE, _MHZ(24));
|
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_CLK_PMA2LINK2PCS_CM, _MHZ(200));
|
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_DCLK_RX_PRE, _MHZ(200));
|
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_CLK_I2S_SRC_RKLINK_TX, _MHZ(300));
|
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_CFGCLK_MIPIRXPHY0, _MHZ(100));
|
|
|
|
HAL_CRU_ClkEnable(hw, RKX110_CLK_TESTOUT_TOP_GATE);
|
|
|
|
#if RKX110_TESTOUT_MUX >= 0
|
|
/* clk_testout support max 150M output, so set div=10 by default if not 24M */
|
|
RKX11x_HAL_CRU_InitTestout(hw, RKX110_CPS_TEST_CLKOUT, RKX110_TESTOUT_MUX,
|
|
RKX110_TESTOUT_MUX == 0 ? 1 : 10);
|
|
#endif
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
PNAME(mux_24m_p) = { "xin24m" };
|
|
PNAME(mux_rxpll_cpll_p) = { "rxpll", "cpll" };
|
|
PNAME(mux_rxpll_cpll_24m_p) = { "rxpll", "cpll", "xin24m" };
|
|
PNAME(mux_rxpre0_24m_p) = { "xin24m", "busclk_rx_pre0" };
|
|
|
|
#define CAL_FREQ_REG 0xf00
|
|
|
|
static uint32_t RKX11x_HAL_CRU_ClkGetExtFreq(struct hwclk *hw, uint32_t clk)
|
|
{
|
|
uint32_t clkMux = CLK_GET_MUX(RKX110_CPS_TEST_CLKOUT);
|
|
uint32_t clkDiv = CLK_GET_DIV(RKX110_CPS_TEST_CLKOUT);
|
|
uint32_t freq, mhz;
|
|
uint8_t div = 10;
|
|
|
|
HAL_CRU_ClkSetDiv(hw, clkDiv, div);
|
|
HAL_CRU_ClkSetMux(hw, clkMux, 0);
|
|
HAL_SleepMs(2);
|
|
HAL_CRU_ClkSetMux(hw, clkMux, clk);
|
|
HAL_SleepMs(2);
|
|
freq = HAL_CRU_Read(hw, CAL_FREQ_REG);
|
|
|
|
/* 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 rkx11x_clkTable[] = {
|
|
/* internal */
|
|
CLK_DECLARE_INT("rxpll", RKX110_CPS_PLL_RXPLL, mux_24m_p),
|
|
CLK_DECLARE_INT("cpll", RKX110_CPS_PLL_CPLL, mux_24m_p),
|
|
CLK_DECLARE_INT("dclk_rx_pre", RKX110_CPS_DCLK_RX_PRE, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_d_dsi_0_pattern", RKX110_CPS_DCLK_RX_PRE, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_d_dsi_1_pattern", RKX110_CPS_DCLK_RX_PRE, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_cam0_out2io", RKX110_CPS_CLK_CAM0_OUT2IO, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_cam1_out2io", RKX110_CPS_CLK_CAM1_OUT2IO, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_cif_out2io", RKX110_CPS_CLK_CIF_OUT2IO, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("dclk_d_dsi_0_rec_rklink_tx", RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("dclk_d_dsi_1_rec_rklink_tx", RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_2x_lvds_rklink_tx", RKX110_CPS_CLK_2X_LVDS_RKLINK_TX, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("clk_i2s_src_rklink_tx", RKX110_CPS_CLK_I2S_SRC_RKLINK_TX, mux_rxpll_cpll_24m_p),
|
|
CLK_DECLARE_INT("ckref_mipirxphy0", RKX110_CPS_CKREF_MIPIRXPHY0, mux_rxpll_cpll_p),
|
|
CLK_DECLARE_INT("ckref_mipirxphy1", RKX110_CPS_CKREF_MIPIRXPHY1, mux_rxpll_cpll_p),
|
|
CLK_DECLARE_INT("cfgclk_mipirxphy0", RKX110_CPS_CFGCLK_MIPIRXPHY0, mux_rxpll_cpll_p),
|
|
CLK_DECLARE_INT("cfgclk_mipirxphy1", RKX110_CPS_CFGCLK_MIPIRXPHY1, mux_rxpll_cpll_p),
|
|
CLK_DECLARE_INT("busclk_rx_pre0", RKX110_CPS_BUSCLK_RX_PRE0, mux_rxpll_cpll_p),
|
|
CLK_DECLARE_INT("busclk_rx_pre", RKX110_CPS_BUSCLK_RX_PRE, mux_rxpre0_24m_p),
|
|
CLK_DECLARE_INT("dclk_rx_gpio0", RKX110_CPS_DCLK_RX_GPIO0, mux_24m_p),
|
|
CLK_DECLARE_INT("dclk_rx_gpio1", RKX110_CPS_DCLK_RX_GPIO1, mux_24m_p),
|
|
CLK_DECLARE_INT("rx_efuse", RKX110_CPS_RX_EFUSE, mux_24m_p),
|
|
CLK_DECLARE_INT("pcs0_ada", RKX110_CPS_PCS0_ADA, mux_24m_p),
|
|
CLK_DECLARE_INT("pcs1_ada", RKX110_CPS_PCS1_ADA, mux_24m_p),
|
|
|
|
/* external */
|
|
CLK_DECLARE_EXT("xin24m", 0, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("rxpclk_vicap_lvds", 3, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_rxbytehs_csihost0", 4, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_rxbytehs_csihost1", 5, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_d_rgb_rklink_tx", 6, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("dclk_lvds0", 7, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("dclk_lvds1", 8, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_link_pcs0", 9, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_link_pcs1", 10, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("pclkin_vicap_dvp_rx", 21, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("iclk_dsi0", 22, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("iclk_dsi1", 23, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("rxpclk_lvds_align", 24, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_8x_pma2pcs0", 25, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT("clk_8x_pma2pcs1", 26, RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
|
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds0_rklink_tx_cm", 7, "dclk_lvds0", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds0_rklink_tx", 7, "clk_d_lvds0_rklink_tx_cm", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds0_pattern_gen_en", 7, "clk_d_lvds0_rklink_tx_cm", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds1_rklink_tx_cm", 8, "dclk_lvds1", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds1_rklink_tx", 8, "clk_d_lvds1_rklink_tx_cm", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds1_pattern_gen_en", 8, "clk_d_lvds1_rklink_tx_cm", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_pma2pcs0", 9, "clk_link_pcs0", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_pma2link2pcs_cm", 9, "clk_link_pcs0", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
CLK_DECLARE_EXT_PARENT("clk_pma2pcs1", 9, "clk_link_pcs1", RKX11x_HAL_CRU_ClkGetExtFreq),
|
|
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
struct clkOps rkx110_clk_ops =
|
|
{
|
|
.clkTable = rkx11x_clkTable,
|
|
.clkInit = RKX11x_HAL_CRU_Init,
|
|
.clkGetFreq = RKX11x_HAL_CRU_ClkGetFreq,
|
|
.clkSetFreq = RKX11x_HAL_CRU_ClkSetFreq,
|
|
.clkInitTestout = RKX11x_HAL_CRU_InitTestout,
|
|
};
|