From 95f83adcf6c2988e8fe9ee1f7a5fb43404aa1f54 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Tue, 22 Nov 2022 10:58:50 +0800 Subject: [PATCH] mfd: Add rockchip rkx110/x120 serdes support support display topologys as follow: 1 video source input, 1 channel, 1 lane, 1 remote, 1 video output: +-------+ +---------+ +---------+ +--------+ | | disp in | | cable0 | | disp out| | | soc |--------->| RK110 +----------->| RK120 +-------->| screen | | | | | | | | | +-------+ +---------+ +---------+ +--------+ 1 video source input, 1 channel, 2 lane, 1 remote, 1 video output: +-------+ +---------+ cable0 +---------+ +--------+ | | disp in | +----------->| | disp out| | | soc |--------->| RK110 | cable1 | RK120 +-------->| screen | | | | +----------->| | | | +-------+ +---------+ +---------+ +--------+ 1 video source input, 2 channel, 2 lane, 2 remote, 2 video output: +---------+ +--------+ cable0 | |disp0 out| | +------->| RK120 +-------->| screen | | | | | | +-------+ +---------+ | +---------+ +--------+ | | disp in | +---+ | soc |--------->| RK110 | | | | +---+ +-------+ +---------+ | +---------+ +--------+ |cable1 | |disp1 out| | +------->| RK120 +-------->| screen | | | | | +---------+ +--------+ 1 video source input, 2 channel, 1 lane, 1 remote, 2 video output: +--------+ lvds0_tx | | +--->| screen | +-------+ +---------+ +---------+ | | | | | disp in | | cable0 | |----+ +--------+ | soc |--------->| RK110 +----------->| RK120 | | | | | | |----+ +--------+ +-------+ +---------+ +---------+ | | | +--->| screen | lvds1_tx | | +--------+ 2 video source input, 2 channel, 1 lane, 1 remote, 2 video output: +--------+ lvds0_tx | | +--->| screen | +-------+ disp0_rx +---------+ +---------+ | | | | |--------->| | cable0 | |----+ +--------+ | soc | disp1_rx | RK110 +----------->| RK120 | | |--------->| | | |----+ +--------+ +-------+ +---------+ +---------+ | | | +--->| screen | lvds1_tx | | +--------+ 2 video source input, 2 channel, 2 lane, 1 remote, 2 video output: +--------+ lvds0_tx | | +--->| screen | +-------+ disp0_rx +---------+ cable0 +---------+ | | | | |--------->| +----------->| |----+ +--------+ | soc | disp1_rx | RK110 | cable1 | RK120 | | |--------->| +----------->| |----+ +--------+ +-------+ +---------+ +---------+ | | | +--->| screen | lvds1_tx | | +--------+ 2 video source input, 2 channel, 2 lane, 2 remote, 2 video output: +---------+ +--------+ cable0 | |disp0 out| | +------->| RK120 +-------->| screen | | | | | | +-------+ disp0_rx +---------+ | +---------+ +--------+ | |--------->| +---+ | soc | disp1_rx | RK110 | | |--------->| +---+ +-------+ +---------+ | +---------+ +--------+ |cable1 | |disp1 out| | +------->| RK120 +-------->| screen | | | | | +---------+ +--------+ Signed-off-by: Andy Yan Signed-off-by: Guochun Huang Signed-off-by: Zhang Yubing Signed-off-by: Joseph Chen Signed-off-by: Tao Huang Signed-off-by: Wyon Bi Signed-off-by: Steven Liu Change-Id: Ifbf44ff7d5dcab668b50cf101d8dbff10dc71467 --- drivers/mfd/Kconfig | 2 + drivers/mfd/Makefile | 1 + drivers/mfd/rkx110_x120/Kconfig | 18 + drivers/mfd/rkx110_x120/Makefile | 23 + drivers/mfd/rkx110_x120/hal/cru_api.h | 210 +++ drivers/mfd/rkx110_x120/hal/cru_core.c | 904 +++++++++++++ drivers/mfd/rkx110_x120/hal/cru_core.h | 450 +++++++ drivers/mfd/rkx110_x120/hal/cru_rkx110.c | 612 +++++++++ drivers/mfd/rkx110_x120/hal/cru_rkx110.h | 358 +++++ drivers/mfd/rkx110_x120/hal/cru_rkx111.c | 706 ++++++++++ drivers/mfd/rkx110_x120/hal/cru_rkx111.h | 117 ++ drivers/mfd/rkx110_x120/hal/cru_rkx120.c | 599 +++++++++ drivers/mfd/rkx110_x120/hal/cru_rkx120.h | 305 +++++ drivers/mfd/rkx110_x120/hal/cru_rkx121.c | 626 +++++++++ drivers/mfd/rkx110_x120/hal/cru_rkx121.h | 48 + drivers/mfd/rkx110_x120/hal/hal_def.h | 58 + drivers/mfd/rkx110_x120/hal/hal_os_def.h | 33 + drivers/mfd/rkx110_x120/hal/pinctrl_api.h | 45 + .../mfd/rkx110_x120/hal/pinctrl_rkx110_x120.c | 612 +++++++++ .../mfd/rkx110_x120/hal/pinctrl_rkx110_x120.h | 166 +++ drivers/mfd/rkx110_x120/pattern_gen.c | 141 ++ drivers/mfd/rkx110_x120/rkx110.c | 304 +++++ drivers/mfd/rkx110_x120/rkx110_combrxphy.c | 280 ++++ drivers/mfd/rkx110_x120/rkx110_dsi_rx.c | 124 ++ drivers/mfd/rkx110_x120/rkx110_dsi_rx.h | 14 + drivers/mfd/rkx110_x120/rkx110_linktx.c | 738 ++++++++++ drivers/mfd/rkx110_x120/rkx110_reg.h | 515 +++++++ drivers/mfd/rkx110_x120/rkx110_x120.h | 366 +++++ drivers/mfd/rkx110_x120/rkx110_x120_core.c | 1100 +++++++++++++++ drivers/mfd/rkx110_x120/rkx110_x120_panel.c | 642 +++++++++ drivers/mfd/rkx110_x120/rkx120.c | 309 +++++ drivers/mfd/rkx110_x120/rkx120_combtxphy.c | 416 ++++++ drivers/mfd/rkx110_x120/rkx120_dsi_tx.c | 1182 +++++++++++++++++ drivers/mfd/rkx110_x120/rkx120_dsi_tx.h | 23 + drivers/mfd/rkx110_x120/rkx120_linkrx.c | 797 +++++++++++ drivers/mfd/rkx110_x120/rkx120_reg.h | 468 +++++++ drivers/mfd/rkx110_x120/serdes_combphy.c | 87 ++ drivers/mfd/rkx110_x120/serdes_combphy.h | 28 + 38 files changed, 13427 insertions(+) create mode 100644 drivers/mfd/rkx110_x120/Kconfig create mode 100644 drivers/mfd/rkx110_x120/Makefile create mode 100644 drivers/mfd/rkx110_x120/hal/cru_api.h create mode 100644 drivers/mfd/rkx110_x120/hal/cru_core.c create mode 100644 drivers/mfd/rkx110_x120/hal/cru_core.h create mode 100644 drivers/mfd/rkx110_x120/hal/cru_rkx110.c create mode 100644 drivers/mfd/rkx110_x120/hal/cru_rkx110.h create mode 100644 drivers/mfd/rkx110_x120/hal/cru_rkx111.c create mode 100644 drivers/mfd/rkx110_x120/hal/cru_rkx111.h create mode 100644 drivers/mfd/rkx110_x120/hal/cru_rkx120.c create mode 100644 drivers/mfd/rkx110_x120/hal/cru_rkx120.h create mode 100644 drivers/mfd/rkx110_x120/hal/cru_rkx121.c create mode 100644 drivers/mfd/rkx110_x120/hal/cru_rkx121.h create mode 100644 drivers/mfd/rkx110_x120/hal/hal_def.h create mode 100644 drivers/mfd/rkx110_x120/hal/hal_os_def.h create mode 100644 drivers/mfd/rkx110_x120/hal/pinctrl_api.h create mode 100644 drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.c create mode 100644 drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.h create mode 100644 drivers/mfd/rkx110_x120/pattern_gen.c create mode 100644 drivers/mfd/rkx110_x120/rkx110.c create mode 100644 drivers/mfd/rkx110_x120/rkx110_combrxphy.c create mode 100644 drivers/mfd/rkx110_x120/rkx110_dsi_rx.c create mode 100644 drivers/mfd/rkx110_x120/rkx110_dsi_rx.h create mode 100644 drivers/mfd/rkx110_x120/rkx110_linktx.c create mode 100644 drivers/mfd/rkx110_x120/rkx110_reg.h create mode 100644 drivers/mfd/rkx110_x120/rkx110_x120.h create mode 100644 drivers/mfd/rkx110_x120/rkx110_x120_core.c create mode 100644 drivers/mfd/rkx110_x120/rkx110_x120_panel.c create mode 100644 drivers/mfd/rkx110_x120/rkx120.c create mode 100644 drivers/mfd/rkx110_x120/rkx120_combtxphy.c create mode 100644 drivers/mfd/rkx110_x120/rkx120_dsi_tx.c create mode 100644 drivers/mfd/rkx110_x120/rkx120_dsi_tx.h create mode 100644 drivers/mfd/rkx110_x120/rkx120_linkrx.c create mode 100644 drivers/mfd/rkx110_x120/rkx120_reg.h create mode 100644 drivers/mfd/rkx110_x120/serdes_combphy.c create mode 100644 drivers/mfd/rkx110_x120/serdes_combphy.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1ec588cae247..d90b49d50531 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1218,6 +1218,8 @@ config MFD_RK1000 if you say yes here you get support for the RK1000, with func as TVEncoder or CODEC. +source "drivers/mfd/rkx110_x120/Kconfig" + config MFD_RN5T618 tristate "Ricoh RN5T567/618 PMIC" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 1b45f971e083..70ec822acfeb 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -230,6 +230,7 @@ obj-$(CONFIG_MFD_RK806) += rk806-core.o obj-$(CONFIG_MFD_RK806_SPI) += rk806-spi.o obj-$(CONFIG_MFD_RK808) += rk808.o obj-$(CONFIG_MFD_RK1000) += rk1000-core.o +obj-y += rkx110_x120/ obj-$(CONFIG_MFD_RN5T618) += rn5t618.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o obj-$(CONFIG_MFD_SYSCON) += syscon.o diff --git a/drivers/mfd/rkx110_x120/Kconfig b/drivers/mfd/rkx110_x120/Kconfig new file mode 100644 index 000000000000..e8af3583ccd8 --- /dev/null +++ b/drivers/mfd/rkx110_x120/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +config MFD_RKX110_X120 + tristate "Rockchip RKx110 RKx120 SerDes MFD Driver" + depends on I2C + depends on OF + select MFD_CORE + help + if you say yes here you get support for the RKx110 RKx120 from Rockchip. + +config ROCKCHIP_SERDES_DRM_PANEL + tristate "Generic RK Serdes panel driver" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + help + This driver supports rk serdes panels. + diff --git a/drivers/mfd/rkx110_x120/Makefile b/drivers/mfd/rkx110_x120/Makefile new file mode 100644 index 000000000000..c0b23cb46ea3 --- /dev/null +++ b/drivers/mfd/rkx110_x120/Makefile @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +obj-$(CONFIG_MFD_RKX110_X120) += rkx110_x120.o +rkx110_x120-objs := \ + hal/cru_core.o \ + hal/cru_rkx110.o \ + hal/cru_rkx120.o \ + hal/cru_rkx111.o \ + hal/cru_rkx121.o \ + hal/pinctrl_rkx110_x120.o \ + pattern_gen.o \ + rkx110_combrxphy.o \ + rkx110_dsi_rx.o \ + rkx110_x120_core.o \ + rkx110_linktx.o \ + rkx110.o \ + rkx120.o \ + rkx120_combtxphy.o \ + rkx120_dsi_tx.o \ + rkx120_linkrx.o \ + serdes_combphy.o + +obj-$(CONFIG_ROCKCHIP_SERDES_DRM_PANEL) += rkx110_x120_panel.o diff --git a/drivers/mfd/rkx110_x120/hal/cru_api.h b/drivers/mfd/rkx110_x120/hal/cru_api.h new file mode 100644 index 000000000000..97de82c45b6b --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_api.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#ifndef _CRU_API_H_ +#define _CRU_API_H_ + +#include "hal_def.h" +#include "hal_os_def.h" +#include "cru_core.h" +#include "cru_rkx110.h" +#include "cru_rkx120.h" +#include "cru_rkx111.h" +#include "cru_rkx121.h" + +static HAL_DEFINE_MUTEX(top_lock); + +static inline bool hwclk_is_enabled(struct hwclk *hw, uint32_t clk) +{ + bool ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkIsEnabled(hw, clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline int hwclk_enable(struct hwclk *hw, uint32_t clk) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkEnable(hw, clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline int hwclk_disable(struct hwclk *hw, uint32_t clk) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkDisable(hw, clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline bool hwclk_is_reset(struct hwclk *hw, uint32_t clk) +{ + bool ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkIsReset(hw, clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline int hwclk_reset(struct hwclk *hw, uint32_t clk) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkResetAssert(hw, clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline int hwclk_reset_deassert(struct hwclk *hw, uint32_t clk) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkResetDeassert(hw, clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline int hwclk_set_div(struct hwclk *hw, uint32_t clk, uint32_t div) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkSetDiv(hw, clk, div); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline uint32_t hwclk_get_div(struct hwclk *hw, uint32_t clk) +{ + uint32_t ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkGetDiv(hw, clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline int hwclk_set_mux(struct hwclk *hw, uint32_t clk, uint32_t mux) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkSetMux(hw, clk, mux); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline uint32_t hwclk_get_mux(struct hwclk *hw, uint32_t clk) +{ + uint32_t ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkGetMux(hw, clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline uint32_t hwclk_get_rate(struct hwclk *hw, uint32_t composite_clk) +{ + uint32_t ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkGetFreq(hw, composite_clk); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline int hwclk_set_rate(struct hwclk *hw, uint32_t composite_clk, uint32_t rate) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkSetFreq(hw, composite_clk, rate); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline int hwclk_set_testout(struct hwclk *hw, uint32_t composite_clk, + uint32_t mux, uint32_t div) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_ClkSetTestout(hw, composite_clk, mux, div); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline void hwclk_dump_tree(HAL_ClockType type) +{ + HAL_MutexLock(&top_lock); + HAL_CRU_ClkDumpTree(type); + HAL_MutexUnlock(&top_lock); +} + +static inline int hwclk_set_glbsrst(struct hwclk *hw, uint32_t type) +{ + int ret; + + HAL_MutexLock(&hw->lock); + ret = HAL_CRU_SetGlbSrst(hw, type); + HAL_MutexUnlock(&hw->lock); + + return ret; +} + +static inline struct hwclk *hwclk_register(struct xferclk xfer) +{ + struct hwclk *ret; + + HAL_MutexLock(&top_lock); + ret = HAL_CRU_Register(xfer); + HAL_MutexUnlock(&top_lock); + + return ret; +} + +static inline struct hwclk *hwclk_get(void *client) +{ + struct hwclk *ret; + + HAL_MutexLock(&top_lock); + ret = HAL_CRU_ClkGet(client); + HAL_MutexUnlock(&top_lock); + + return ret; +} + +static inline int hwclk_init(void) +{ + return HAL_CRU_Init(); +} + +#endif diff --git a/drivers/mfd/rkx110_x120/hal/cru_core.c b/drivers/mfd/rkx110_x120/hal/cru_core.c new file mode 100644 index 000000000000..985a30d21d35 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_core.c @@ -0,0 +1,904 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#include "cru_core.h" + +/********************* Private MACRO Definition ******************************/ +#define REG_X4(i) ((i) * 4) + +#define PWRDOWN_SHIFT 13 +#define PWRDOWN_MASK (1 << PWRDOWN_SHIFT) +#define PLL_POSTDIV1_SHIFT 12 +#define PLL_POSTDIV1_MASK (0x7 << PLL_POSTDIV1_SHIFT) +#define PLL_FBDIV_SHIFT 0 +#define PLL_FBDIV_MASK (0xfff << PLL_FBDIV_SHIFT) +#define PLL_POSTDIV2_SHIFT 6 +#define PLL_POSTDIV2_MASK (0x7 << PLL_POSTDIV2_SHIFT) +#define PLL_REFDIV_SHIFT 0 +#define PLL_REFDIV_MASK (0x3f << PLL_REFDIV_SHIFT) +#define PLL_DSMPD_SHIFT 12 +#define PLL_DSMPD_MASK (1 << PLL_DSMPD_SHIFT) +#define PLL_FRAC_SHIFT 0 +#define PLL_FRAC_MASK (0xffffff << PLL_FRAC_SHIFT) + +#define EXPONENT_OF_FRAC_PLL 24 +#define RK_PLL_MODE_SLOW 0 +#define RK_PLL_MODE_NORMAL 1 +#define RK_PLL_MODE_DEEP 2 +#define MHZ 1000000 + +#define PLL_GET_PLLMODE(val, shift, mask) \ + (((uint32_t)(val) & mask) >> shift) +#define PLL_GET_FBDIV(x) \ + (((uint32_t)(x) & (PLL_FBDIV_MASK)) >> PLL_FBDIV_SHIFT) +#define PLL_GET_REFDIV(x) \ + (((uint32_t)(x) & (PLL_REFDIV_MASK)) >> PLL_REFDIV_SHIFT) +#define PLL_GET_POSTDIV1(x) \ + (((uint32_t)(x) & (PLL_POSTDIV1_MASK)) >> PLL_POSTDIV1_SHIFT) +#define PLL_GET_POSTDIV2(x) \ + (((uint32_t)(x) & (PLL_POSTDIV2_MASK)) >> PLL_POSTDIV2_SHIFT) +#define PLL_GET_DSMPD(x) \ + (((uint32_t)(x) & (PLL_DSMPD_MASK)) >> PLL_DSMPD_SHIFT) +#define PLL_GET_FRAC(x) \ + (((uint32_t)(x) & (PLL_FRAC_MASK)) >> PLL_FRAC_SHIFT) +#define CRU_PLL_ROUND_UP_TO_KHZ(x) \ + (HAL_DIV_ROUND_UP((x), 1000) * 1000) + +static struct hwclk g_hwclk_desc[HAL_HWCLK_MAX_NUM]; +static struct PLL_CONFIG g_AutoTable; + +/********************* Private Function Definition ***************************/ +uint32_t HAL_CRU_Read(struct hwclk *hw, uint32_t reg) +{ + uint32_t val; + int ret; + + ret = hw->xfer.read(hw->xfer.client, reg, &val); + if (ret) { + CRU_ERR("%s: read reg=0x%08x failed, ret=%d\n", hw->name, reg, ret); + } + + CRU_DBGR("%s: %s: reg=0x%08x, val=0x%08x\n", __func__, hw->name, reg, val); + + return val; +} + +uint32_t HAL_CRU_Write(struct hwclk *hw, uint32_t reg, uint32_t val) +{ + int ret; + + CRU_DBGR("%s: %s: reg=0x%08x, val=0x%08x\n", __func__, hw->name, reg, val); + + ret = hw->xfer.write(hw->xfer.client, reg, val); + if (ret) { + CRU_ERR("%s: write reg=0x%08x, val=0x%08x failed, ret=%d\n", + hw->name, reg, val, ret); + } + + return ret; +} + +uint32_t HAL_CRU_WriteMask(struct hwclk *hw, uint32_t reg, + uint32_t msk, uint32_t val) +{ + return HAL_CRU_Write(hw, reg, VAL_MASK_WE(msk, val)); +} + +static int isBetterFreq(uint32_t now, uint32_t new, uint32_t best) +{ + return (new <= now && new > best); +} + +int HAL_CRU_FreqGetMux4(struct hwclk *hw, + uint32_t freq, uint32_t freq0, + uint32_t freq1, uint32_t freq2, uint32_t freq3) +{ + uint32_t best = 0; + + if (isBetterFreq(freq, freq0, best)) { + best = freq0; + } + + if (isBetterFreq(freq, freq1, best)) { + best = freq1; + } + + if (isBetterFreq(freq, freq2, best)) { + best = freq2; + } + + if (isBetterFreq(freq, freq3, best)) { + best = freq3; + } + + if (best == freq0) { + return 0; + } else if (best == freq1) { + return 1; + } else if (best == freq2) { + return 2; + } else if (best == freq3) { + return 3; + } + + return HAL_INVAL; +} + +int HAL_CRU_FreqGetMux3(struct hwclk *hw, + uint32_t freq, uint32_t freq0, + uint32_t freq1, uint32_t freq2) +{ + return HAL_CRU_FreqGetMux4(hw, freq, freq0, freq1, freq2, freq2); +} + +int HAL_CRU_FreqGetMux2(struct hwclk *hw, + uint32_t freq, uint32_t freq0, uint32_t freq1) +{ + return HAL_CRU_FreqGetMux4(hw, freq, freq0, freq1, freq1, freq1); +} + +uint32_t HAL_CRU_MuxGetFreq4(struct hwclk *hw, uint32_t muxName, + uint32_t freq0, uint32_t freq1, + uint32_t freq2, uint32_t freq3) +{ + switch (HAL_CRU_ClkGetMux(hw, muxName)) { + case 0: + + return freq0; + case 1: + + return freq1; + case 2: + + return freq2; + case 3: + + return freq3; + } + + return HAL_INVAL; +} + +uint32_t HAL_CRU_MuxGetFreq3(struct hwclk *hw, uint32_t muxName, + uint32_t freq0, uint32_t freq1, uint32_t freq2) +{ + return HAL_CRU_MuxGetFreq4(hw, muxName, freq0, freq1, freq2, freq2); +} + +uint32_t HAL_CRU_MuxGetFreq2(struct hwclk *hw, uint32_t muxName, + uint32_t freq0, uint32_t freq1) +{ + return HAL_CRU_MuxGetFreq4(hw, muxName, freq0, freq1, freq1, freq1); +} + +int HAL_CRU_RoundFreqGetMux4(struct hwclk *hw, uint32_t freq, + uint32_t pFreq0, uint32_t pFreq1, + uint32_t pFreq2, uint32_t pFreq3, uint32_t *pFreqOut) +{ + uint32_t mux; + + if (pFreq3 && (pFreq3 % freq == 0)) { + *pFreqOut = pFreq3; + mux = 3; + } else if (pFreq2 && (pFreq2 % freq == 0)) { + *pFreqOut = pFreq2; + mux = 2; + } else if (pFreq1 % freq == 0) { + *pFreqOut = pFreq1; + mux = 1; + } else { + *pFreqOut = pFreq0; + mux = 0; + } + + return mux; +} + +int HAL_CRU_RoundFreqGetMux3(struct hwclk *hw, uint32_t freq, + uint32_t pFreq0, uint32_t pFreq1, + uint32_t pFreq2, uint32_t *pFreqOut) +{ + return HAL_CRU_RoundFreqGetMux4(hw, freq, pFreq0, pFreq1, pFreq2, 0, pFreqOut); +} + +int HAL_CRU_RoundFreqGetMux2(struct hwclk *hw, uint32_t freq, + uint32_t pFreq0, uint32_t pFreq1, uint32_t *pFreqOut) +{ + return HAL_CRU_RoundFreqGetMux4(hw, freq, pFreq0, pFreq1, 0, 0, pFreqOut); +} + +/******************************************************************************/ +uint32_t HAL_CRU_GetPllFreq(struct hwclk *hw, struct PLL_SETUP *pSetup) +{ + uint32_t refDiv, fbDiv, postdDv1, postDiv2, frac, dsmpd; + uint32_t mode = 0, rate = OSC_24M; + + mode = PLL_GET_PLLMODE(HAL_CRU_Read(hw, pSetup->modeOffset), + pSetup->modeShift, + pSetup->modeMask); + + switch (mode) { + case RK_PLL_MODE_SLOW: + rate = OSC_24M; + break; + case RK_PLL_MODE_NORMAL: + postdDv1 = PLL_GET_POSTDIV1(HAL_CRU_Read(hw, pSetup->conOffset0)); + fbDiv = PLL_GET_FBDIV(HAL_CRU_Read(hw, pSetup->conOffset0)); + postDiv2 = PLL_GET_POSTDIV2(HAL_CRU_Read(hw, pSetup->conOffset1)); + refDiv = PLL_GET_REFDIV(HAL_CRU_Read(hw, pSetup->conOffset1)); + dsmpd = PLL_GET_DSMPD(HAL_CRU_Read(hw, pSetup->conOffset1)); + frac = PLL_GET_FRAC(HAL_CRU_Read(hw, pSetup->conOffset2)); + rate = (rate / refDiv) * fbDiv; + if (dsmpd == 0) { + uint64_t fracRate = OSC_24M; + + fracRate *= frac; + fracRate = fracRate >> EXPONENT_OF_FRAC_PLL; + fracRate = fracRate / refDiv; + rate += fracRate; + } + rate = rate / (postdDv1 * postDiv2); + rate = CRU_PLL_ROUND_UP_TO_KHZ(rate); + break; + case RK_PLL_MODE_DEEP: + default: + rate = 32768; + break; + } + + return rate; +} + +static uint32_t CRU_Gcd(uint32_t m, uint32_t n) +{ + int t; + + while (m > 0) { + if (n > m) { + t = m; + m = n; + n = t; + } + m -= n; + } + + return n; +} + +static uint64_t HAL_DivU64Rem(uint64_t numerator, uint32_t denominator, uint32_t *pRemainder) +{ + uint64_t remainder = numerator; + uint64_t b = denominator; + uint64_t result; + uint64_t d = 1; + uint32_t high = numerator >> 32; + + result = 0; + if (high >= denominator) { + high /= denominator; + result = (uint64_t)high << 32; + remainder -= (uint64_t)(high * denominator) << 32; + } + + while ((int64_t)b > 0 && b < remainder) { + b = b + b; + d = d + d; + } + + do { + if (remainder >= b) { + remainder -= b; + result += d; + } + b >>= 1; + d >>= 1; + } while (d); + + if (pRemainder) { + *pRemainder = remainder; + } + + return result; +} + +static inline uint64_t HAL_DivU64(uint64_t numerator, uint32_t denominator) +{ + return HAL_DivU64Rem(numerator, denominator, HAL_NULL); +} + +static const struct PLL_CONFIG *CRU_PllSetByAuto(struct hwclk *hw, + struct PLL_SETUP *pSetup, + uint32_t finHz, + uint32_t foutHz) +{ + struct PLL_CONFIG *rateTable = &g_AutoTable; + uint32_t refDiv, fbDiv, dsmpd; + uint32_t postDiv1, postDiv2; + uint32_t clkGcd = 0; + uint64_t foutVco; + uint64_t intVco; + uint64_t frac64; + + CRU_DBGF("%s: %s: pll=%d, refdiv: [%u, %u], foutVco: [%u, %u], fout: [%u, %u]\n", + __func__, hw->name, pSetup->id, pSetup->minRefdiv, pSetup->maxRefdiv, + pSetup->minVco, pSetup->maxVco, pSetup->minFout, pSetup->maxFout); + + if (finHz == 0 || foutHz == 0 || foutHz == finHz) { + return HAL_NULL; + } + + if ((foutHz < pSetup->minFout) || (foutHz > pSetup->maxFout)) { + return HAL_NULL; + } + + for (postDiv1 = 1; postDiv1 <= 7; postDiv1++) { + for (postDiv2 = 1; postDiv2 <= 7; postDiv2++) { + if (postDiv1 < postDiv2) { + CRU_DBGF("%s: %s: pll=%d, Invalid postDiv1(%u) < postDiv2(%u)\n", + __func__, hw->name, pSetup->id, postDiv1, postDiv2); + continue; + } + + foutVco = (uint64_t)foutHz * postDiv1 * postDiv2; + if ((foutVco < pSetup->minVco) || (foutVco > pSetup->maxVco)) { + CRU_DBGF("%s: %s: pll=%d, Invalid foutVco(%llu), min_max[%u, %u]\n", + __func__, hw->name, pSetup->id, foutVco, pSetup->minVco, pSetup->maxVco); + continue; + } + + intVco = foutVco / MHZ * MHZ; + clkGcd = CRU_Gcd(finHz, intVco); + refDiv = finHz / clkGcd; + fbDiv = intVco / clkGcd; + + if ((refDiv < pSetup->minRefdiv) || (refDiv > pSetup->maxRefdiv)) { + CRU_DBGF("%s: %s: pll=%d, Invalid refDiv(%u), min_max[%u, %u]\n", + __func__, hw->name, pSetup->id, refDiv, pSetup->minRefdiv, pSetup->maxRefdiv); + continue; + } + + if (foutHz / MHZ * MHZ == foutHz) { + dsmpd = 1; + frac64 = 0; + } else { + frac64 = (foutVco % MHZ) * refDiv; + frac64 = HAL_DivU64(frac64 << EXPONENT_OF_FRAC_PLL, OSC_24M); + if (frac64 > 0) { + dsmpd = 0; + } else { + dsmpd = 1; + } + } + + if (dsmpd && !(fbDiv >= 16 && fbDiv <= 2500)) { + CRU_DBGF("%s: %s: pll=%d, Invalid fbDiv(%u) on int mode, min_max[16, 2500]\n", + __func__, hw->name, pSetup->id, fbDiv); + continue; + } + if (!dsmpd && !(fbDiv >= 20 && fbDiv <= 500)) { + CRU_DBGF("%s: %s: pll=%d, Invalid fbDiv(%u) on frac mode, min_max[20, 500]\n", + __func__, hw->name, pSetup->id, fbDiv); + continue; + } + if (frac64 > 0x00ffffff) { + CRU_DBGF("%s: %s: pll=%d, Invalid frac64(0x%llx) over max 0x00ffffff\n", + __func__, hw->name, pSetup->id, frac64); + continue; + } + + rateTable->refDiv = refDiv; + rateTable->fbDiv = fbDiv; + rateTable->postDiv1 = postDiv1; + rateTable->postDiv2 = postDiv2; + rateTable->dsmpd = dsmpd; + rateTable->frac = frac64; + + return rateTable; + } + } + + return HAL_NULL; +} + +static const struct PLL_CONFIG *CRU_PllGetSettings(struct hwclk *hw, + struct PLL_SETUP *pSetup, + uint32_t rate) +{ + const struct PLL_CONFIG *rateTable = pSetup->rateTable; + + if (!rateTable) { + CRU_ERR("%s: %s: Unavailable pll=%d rate table\n", __func__, hw->name, pSetup->id); + + return HAL_NULL; + } + + while (rateTable->rate) { + if (rateTable->rate == rate) { + return rateTable; + } + rateTable++; + } + + rateTable = CRU_PllSetByAuto(hw, pSetup, OSC_24M, rate); + if (!rateTable) { + CRU_ERR("%s: %s: Unsupported pll=%d rate %d\n", __func__, hw->name, pSetup->id, rate); + + return HAL_NULL; + } else { + CRU_MSG("%s: Auto PLL=%d: (%d, %d, %d, %d, %d, %d, %d)\n", + hw->name, pSetup->id, rate, rateTable->refDiv, rateTable->fbDiv, + rateTable->postDiv1, rateTable->postDiv2, + rateTable->dsmpd, rateTable->frac); + } + + return rateTable; +} + +/* + * Force PLL into slow mode + * Pll Power down + * Pll Config fbDiv, refDiv, postdDv1, postDiv2, dsmpd, frac + * Pll Power up + * Waiting for pll lock + * Force PLL into normal mode + */ +HAL_Status HAL_CRU_SetPllFreq(struct hwclk *hw, struct PLL_SETUP *pSetup, uint32_t rate) +{ + const struct PLL_CONFIG *pConfig; + int delay = 2400; + + if (rate == HAL_CRU_GetPllFreq(hw, pSetup)) { + return HAL_OK; + } + + pConfig = CRU_PllGetSettings(hw, pSetup, rate); + if (!pConfig) { + return HAL_ERROR; + } + + /* Force PLL into slow mode to ensure output stable clock */ + HAL_CRU_WriteMask(hw, pSetup->modeOffset, pSetup->modeMask, RK_PLL_MODE_SLOW << pSetup->modeShift); + + /* Pll Power down */ + HAL_CRU_WriteMask(hw, pSetup->conOffset1, PWRDOWN_MASK, 1 << PWRDOWN_SHIFT); + + /* Pll Config */ + HAL_CRU_WriteMask(hw, pSetup->conOffset1, PLL_POSTDIV2_MASK, pConfig->postDiv2 << PLL_POSTDIV2_SHIFT); + HAL_CRU_WriteMask(hw, pSetup->conOffset1, PLL_REFDIV_MASK, pConfig->refDiv << PLL_REFDIV_SHIFT); + HAL_CRU_WriteMask(hw, pSetup->conOffset0, PLL_POSTDIV1_MASK, pConfig->postDiv1 << PLL_POSTDIV1_SHIFT); + HAL_CRU_WriteMask(hw, pSetup->conOffset0, PLL_FBDIV_MASK, pConfig->fbDiv << PLL_FBDIV_SHIFT); + if (pSetup->sscgEn) { + HAL_CRU_WriteMask(hw, pSetup->conOffset1, PLL_DSMPD_MASK, 0 << PLL_DSMPD_SHIFT); + } else { + HAL_CRU_WriteMask(hw, pSetup->conOffset1, PLL_DSMPD_MASK, pConfig->dsmpd << PLL_DSMPD_SHIFT); + } + + if (pConfig->frac) { + HAL_CRU_Write(hw, pSetup->conOffset2, (HAL_CRU_Read(hw, pSetup->conOffset2) & 0xff000000) | pConfig->frac); + } + + /* Pll Power up */ + HAL_CRU_WriteMask(hw, pSetup->conOffset1, PWRDOWN_MASK, 0 << PWRDOWN_SHIFT); + + /* Waiting for pll lock */ + while (delay > 0) { + if (pSetup->stat0) { + if (HAL_CRU_Read(hw, pSetup->stat0) & (1 << pSetup->lockShift)) { + break; + } + } else { + if (HAL_CRU_Read(hw, pSetup->conOffset1) & (1 << pSetup->lockShift)) { + break; + } + } + HAL_DelayUs(2); + delay--; + } + if (delay == 0) { + return HAL_TIMEOUT; + } + + /* Force PLL into normal mode */ + HAL_CRU_WriteMask(hw, pSetup->modeOffset, pSetup->modeMask, RK_PLL_MODE_NORMAL << pSetup->modeShift); + + return HAL_OK; +} + +HAL_Status HAL_CRU_SetPllPowerUp(struct hwclk *hw, struct PLL_SETUP *pSetup) +{ + int delay = 2400; + + /* Pll Power up */ + HAL_CRU_WriteMask(hw, pSetup->conOffset1, PWRDOWN_MASK, 0 << PWRDOWN_SHIFT); + + /* Waiting for pll lock */ + while (delay > 0) { + if (pSetup->stat0) { + if (HAL_CRU_Read(hw, pSetup->stat0) & (1 << pSetup->lockShift)) { + break; + } + } else { + if (HAL_CRU_Read(hw, pSetup->conOffset1) & (1 << pSetup->lockShift)) { + break; + } + } + HAL_DelayUs(1000); + delay--; + } + if (delay == 0) { + return HAL_TIMEOUT; + } + + return HAL_OK; +} + +HAL_Status HAL_CRU_SetPllPowerDown(struct hwclk *hw, struct PLL_SETUP *pSetup) +{ + HAL_CRU_Write(hw, pSetup->conOffset1, VAL_MASK_WE(PWRDOWN_MASK, 1 << PWRDOWN_SHIFT)); + + return HAL_OK; +} + +HAL_Check HAL_CRU_ClkIsEnabled(struct hwclk *hw, uint32_t clk) +{ + uint32_t index = CLK_GATE_GET_REG_OFFSET(clk); + uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk); + + return (HAL_Check)((HAL_CRU_Read(hw, hw->gate_con0 + REG_X4(index)) & (1 << shift)) >> shift); +} + +HAL_Status HAL_CRU_ClkEnable(struct hwclk *hw, uint32_t clk) +{ + uint32_t index = CLK_GATE_GET_REG_OFFSET(clk); + uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk); + uint32_t gid = 16 * index + shift; + + if (gid >= hw->num_gate) { + CRU_ERR("%s: %s: clock(#%08x) is unsupported, gid=%d\n", __func__, hw->name, clk, gid); + + return HAL_INVAL; + } + + if (hw->gate[gid].enable_count == 0) { + CRU_DBGF("%s: %s: clock(#%08x), gid=%d\n", __func__, hw->name, clk, gid); + HAL_CRU_Write(hw, hw->gate_con0 + REG_X4(index), VAL_MASK_WE(1U << shift, 0U << shift)); + } + + hw->gate[gid].enable_count++; + + return HAL_OK; +} + +HAL_Status HAL_CRU_ClkDisable(struct hwclk *hw, uint32_t clk) +{ + uint32_t index = CLK_GATE_GET_REG_OFFSET(clk); + uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk); + uint32_t gid = 16 * index + shift; + + if (gid >= hw->num_gate) { + CRU_ERR("%s: %s: clock(#%08x) is unsupported\n", __func__, hw->name, clk); + + return HAL_INVAL; + } + + if (hw->gate[gid].enable_count == 0) { + CRU_ERR("%s: %s: clock(#%08x) is already disabled\n", __func__, hw->name, clk); + + return HAL_OK; + } + + hw->gate[gid].enable_count--; + if (hw->gate[gid].enable_count == 0) { + CRU_DBGF("%s: %s: clock(#%08x), gid=%d\n", __func__, hw->name, clk, gid); + HAL_CRU_Write(hw, hw->gate_con0 + REG_X4(index), VAL_MASK_WE(1U << shift, 1U << shift)); + } + + return HAL_OK; +} + +HAL_Check HAL_CRU_ClkIsReset(struct hwclk *hw, uint32_t clk) +{ + uint32_t index = CLK_GATE_GET_REG_OFFSET(clk); + uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk); + + return (HAL_Check)((HAL_CRU_Read(hw, hw->softrst_con0 + REG_X4(index)) & (1 << shift)) >> shift); +} + +HAL_Status HAL_CRU_ClkResetAssert(struct hwclk *hw, uint32_t clk) +{ + uint32_t index = CLK_RESET_GET_REG_OFFSET(clk); + uint32_t shift = CLK_RESET_GET_BITS_SHIFT(clk); + + HAL_CRU_Write(hw, hw->softrst_con0 + REG_X4(index), VAL_MASK_WE(1U << shift, 1U << shift)); + + return HAL_OK; +} + +HAL_Status HAL_CRU_ClkResetDeassert(struct hwclk *hw, uint32_t clk) +{ + uint32_t index = CLK_RESET_GET_REG_OFFSET(clk); + uint32_t shift = CLK_RESET_GET_BITS_SHIFT(clk); + + HAL_CRU_Write(hw, hw->softrst_con0 + REG_X4(index), VAL_MASK_WE(1U << shift, 0U << shift)); + + return HAL_OK; +} + +HAL_Status HAL_CRU_ClkSetDiv(struct hwclk *hw, uint32_t divName, uint32_t divValue) +{ + uint32_t shift, mask, index; + + index = CLK_DIV_GET_REG_OFFSET(divName); + shift = CLK_DIV_GET_BITS_SHIFT(divName); + mask = CLK_DIV_GET_MASK(divName); + if (divValue > mask) { + divValue = mask; + } + + CRU_DBGF("%s: %s: clock(#%08x), selcon%d=0x%08x, shift=%d, mask=0x%x, div=%d\n", + __func__, hw->name, divName, index, hw->sel_con0 + REG_X4(index), shift, mask, divValue); + + HAL_CRU_Write(hw, hw->sel_con0 + REG_X4(index), VAL_MASK_WE(mask, (divValue - 1U) << shift)); + + return HAL_OK; +} + +uint32_t HAL_CRU_ClkGetDiv(struct hwclk *hw, uint32_t divName) +{ + uint32_t shift, mask, index, divValue; + + index = CLK_DIV_GET_REG_OFFSET(divName); + shift = CLK_DIV_GET_BITS_SHIFT(divName); + mask = CLK_DIV_GET_MASK(divName); + + divValue = ((HAL_CRU_Read(hw, hw->sel_con0 + REG_X4(index)) & mask) >> shift) + 1; + + return divValue; +} + +HAL_Status HAL_CRU_ClkSetMux(struct hwclk *hw, uint32_t muxName, uint32_t muxValue) +{ + uint32_t shift, mask, index; + + index = CLK_MUX_GET_REG_OFFSET(muxName); + shift = CLK_MUX_GET_BITS_SHIFT(muxName); + mask = CLK_MUX_GET_MASK(muxName); + + CRU_DBGF("%s: %s: clock(#%08x), selcon%d=0x%08x, shift=%d, mask=0x%x, mux=%d\n", + __func__, hw->name, muxName, index, hw->sel_con0 + REG_X4(index), shift, mask, muxValue); + + HAL_CRU_Write(hw, hw->sel_con0 + REG_X4(index), VAL_MASK_WE(mask, muxValue << shift)); + + return HAL_OK; +} + +uint32_t HAL_CRU_ClkGetMux(struct hwclk *hw, uint32_t muxName) +{ + uint32_t shift, mask, index, muxValue; + + index = CLK_MUX_GET_REG_OFFSET(muxName); + shift = CLK_MUX_GET_BITS_SHIFT(muxName); + mask = CLK_MUX_GET_MASK(muxName); + + muxValue = (HAL_CRU_Read(hw, hw->sel_con0 + REG_X4(index)) & mask) >> shift; + + return muxValue; +} + +HAL_Status HAL_CRU_ClkSetTestout(struct hwclk *hw, uint32_t clockName, + uint32_t muxValue, uint32_t divValue) +{ + if (hw->ops->clkInitTestout) { + hw->ops->clkInitTestout(hw, clockName, muxValue, divValue); + } + + return HAL_OK; +} + +void HAL_CRU_ClkDumpTree(HAL_ClockType type) +{ + struct hwclk *hw = &g_hwclk_desc[0]; + struct clkTable *c; + const char *parent; + uint32_t clkMux, mux; + uint32_t i, freq; + + for (i = 0; i < HAL_HWCLK_MAX_NUM; i++, hw++) { + if (hw->type == CLK_UNDEF) { + break; + } + + if ((type != hw->type) && (type != CLK_ALL)) { + continue; + } + + if (!hw->ops->clkTable) { + continue; + } + + CRU_MSG(" ================== %s ==================\n", hw->name); + CRU_MSG(" Name Rate:hz Parent\n"); + CRU_MSG(" ====================================================\n"); + + for (c = hw->ops->clkTable; c->name; c++) { + if (c->type == DUMP_INT) { + if (c->numParents == 1) { + mux = 0; + } else { + clkMux = CLK_GET_MUX(c->clk); + mux = HAL_CRU_ClkGetMux(hw, clkMux); + } + freq = HAL_CRU_ClkGetFreq(hw, c->clk); + parent = c->parents[mux]; + } else if (c->type == DUMP_EXT) { + freq = c->getFreq(hw, c->clk); + parent = c->extParent ? c->extParent : "ext-in"; + } else { + continue; + } + + CRU_MSG(" %-30s %10d %s\n", c->name, freq, parent); + } + CRU_MSG("\n"); + } +} + +HAL_Status HAL_CRU_SetGlbSrst(struct hwclk *hw, eCRU_GlbSrstType type) +{ + if (type == GLB_SRST_FST) { + HAL_CRU_Write(hw, hw->gbl_srst_fst, GLB_SRST_FST); + } + + return HAL_INVAL; +} + +uint32_t HAL_CRU_ClkGetFreq(struct hwclk *hw, uint32_t clockName) +{ + uint32_t rate; + + rate = hw->ops->clkGetFreq(hw, clockName); + + CRU_DBGF("%s: %s: clock(#%08x) get rate: %d\n", __func__, hw->name, clockName, rate); + + return rate; +} + +HAL_Status HAL_CRU_ClkSetFreq(struct hwclk *hw, uint32_t clockName, uint32_t rate) +{ + HAL_Status ret; + uint32_t now; + + CRU_DBGF("%s: %s: clock(#%08x) set rate: %d\n", __func__, hw->name, clockName, rate); + + ret = hw->ops->clkSetFreq(hw, clockName, rate); + if (hw->flags & CLK_FLG_SET_RATE_VERIFY) { + now = hw->ops->clkGetFreq(hw, clockName); + if (rate != now) { + CRU_MSG("%s: Set rate %d, but %d returned\n", + hw->name, rate, now); + ret = HAL_ERROR; + } + } + + return ret; +} + +HAL_Status HAL_CRU_Init(void) +{ + return HAL_OK; +} + +struct hwclk *HAL_CRU_ClkGet(void *client) +{ + struct hwclk *hw = &g_hwclk_desc[0]; + int i; + + if (!client) { + return HAL_NULL; + } + + for (i = 0; i < HAL_HWCLK_MAX_NUM; i++, hw++) { + if (hw->xfer.client == client) { + return hw; + } + } + + return HAL_NULL; +} + +struct hwclk *HAL_CRU_Register(struct xferclk xfer) +{ + struct hwclk hw; + int i, ret; + + if (!xfer.read || !xfer.write || !xfer.client || !xfer.name[0]) { + return HAL_NULL; + } + + if (xfer.type == CLK_UNDEF || xfer.type >= CLK_MAX) { + return HAL_NULL; + } + + /* registered ? */ + for (i = 0; i < HAL_HWCLK_MAX_NUM; i++) { + if (g_hwclk_desc[i].type == CLK_UNDEF) { + break; + } + + if (g_hwclk_desc[i].xfer.client == xfer.client) { + return &g_hwclk_desc[i]; + } + } + + if (i >= HAL_HWCLK_MAX_NUM) { + CRU_ERR("CLK: No more space for register\n"); + + return HAL_NULL; + } + + memset(&hw, 0, sizeof(hw)); + hw.type = xfer.type; + hw.xfer = xfer; + + switch (xfer.type) { + case CLK_RKX110: + if (xfer.version == 0) { + hw.ops = &rkx110_clk_ops; + } else if (xfer.version == 1) { + hw.ops = &rkx111_clk_ops; + } + break; + + case CLK_RKX120: + if (xfer.version == 0) { + hw.ops = &rkx120_clk_ops; + } else if (xfer.version == 1) { + hw.ops = &rkx121_clk_ops; + } + break; + + default: + CRU_ERR("%s: Invalid type: %d\n", __func__, xfer.type); + + return HAL_NULL; + } + + if (!hw.ops || !hw.ops->clkInit || !hw.ops->clkGetFreq || !hw.ops->clkSetFreq) { + CRU_ERR("No available clkOps or .clkInit() or .clkGetFreq() or .clkSetFreq()\n"); + + return HAL_NULL; + } + + HAL_MutexInit(&hw.lock); + ret = hw.ops->clkInit(&hw, &xfer); + if (ret) { + CRU_ERR("%s: Init clock failed, ret=%d\n", hw.name, ret); + + return HAL_NULL; + } + + if (!hw.num_gate) { + CRU_ERR("No available .gate\n"); + + return HAL_NULL; + } + +#if HAL_ENABLE_SET_RATE_VERIFY + hw->flags |= CLK_FLG_SET_RATE_VERIFY; +#endif + + g_hwclk_desc[i] = hw; + + CRU_MSG("CLK: register '%s' with client 0x%08lx successfully.\n", + hw.name, (unsigned long)hw.xfer.client); + +#if DEBUG_CRU_INIT + HAL_CRU_ClkDumpTree(xfer.type); +#endif + + return &g_hwclk_desc[i]; +} diff --git a/drivers/mfd/rkx110_x120/hal/cru_core.h b/drivers/mfd/rkx110_x120/hal/cru_core.h new file mode 100644 index 000000000000..33bf8262271e --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_core.h @@ -0,0 +1,450 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#ifndef _CRU_CORE_H_ +#define _CRU_CORE_H_ + +#include "hal_def.h" +#include "hal_os_def.h" + +#define DEBUG_CRU_INIT 0 +#define CRU_LOGLEVEL 3 + +#define __cru_print(level, fmt, ...) \ +({ \ + level < CRU_LOGLEVEL ? HAL_SYSLOG("[HAL CRU] " fmt, ##__VA_ARGS__) : 0; \ +}) +#define CRU_ERR(fmt, ...) __cru_print(0, "ERROR: " fmt, ##__VA_ARGS__) +#define CRU_WARN(fmt, ...) __cru_print(1, "WARN: " fmt, ##__VA_ARGS__) +#define CRU_MSG(fmt, ...) __cru_print(2, fmt, ##__VA_ARGS__) +#define CRU_DBG(fmt, ...) __cru_print(3, fmt, ##__VA_ARGS__) /* driver */ +#define CRU_DBGF(fmt, ...) __cru_print(4, fmt, ##__VA_ARGS__) /* core function */ +#define CRU_DBGR(fmt, ...) __cru_print(5, fmt, ##__VA_ARGS__) /* core register */ + +#define HAL_ENABLE_SET_RATE_VERIFY 0 + +#define _MHZ(n) ((n) * 1000000U) +#define OSC_24M _MHZ(24) +#define HAL_HWCLK_MAX_NUM 16 +#define PLL_MAX_NUM 2 + +typedef enum { + RKX110_CPLL = 0, + RKX110_RXPLL, + RKX120_CPLL = 0, + RKX120_TXPLL, +} HAL_PLLType; + +typedef enum { + CLK_UNDEF, + CLK_RKX110, + CLK_RKX120, + CLK_ALL, + CLK_MAX, +} HAL_ClockType; + +/* + * hwclk flags + */ +#define CLK_FLG_SET_RATE_VERIFY (1 << 0) /* set and readback verify */ + +struct hwclk; + +struct xferclk { + HAL_ClockType type; + u32 version; + char *name; /* slave addr is expected */ + void *client; + HAL_RegRead_t *read; + HAL_RegWrite_t *write; +}; + +struct clkTable { + uint8_t type; + const char *name; + uint32_t clk; + const char * *parents; + uint32_t numParents; + const char *extParent; + uint32_t (*getFreq)(struct hwclk *hw, uint32_t clockName); +}; + +struct clkOps { + struct clkTable *clkTable; + HAL_Status (*clkInit)(struct hwclk *hw, struct xferclk *xfer); + HAL_Status (*clkInitTestout)(struct hwclk *hw, uint32_t clockName, + uint32_t muxValue, uint32_t divValue); + HAL_Status (*clkSetFreq)(struct hwclk *hw, uint32_t clockName, uint32_t rate); + uint32_t (*clkGetFreq)(struct hwclk *hw, uint32_t clockName); +}; + +struct clkGate { + uint8_t enable_count; +}; + +struct hwclk { + char name[32]; + uint32_t flags; + HAL_ClockType type; + uint32_t pllRate[PLL_MAX_NUM]; + + uint32_t cru_base; + uint32_t gate_con0; + uint32_t sel_con0; + uint32_t softrst_con0; + uint32_t gbl_srst_fst; + + struct xferclk xfer; + struct clkOps *ops; + struct clkGate *gate; + uint32_t num_gate; + + HAL_Mutex lock; +}; + +#define MASK_TO_WE(msk) ((msk) << 16) +#define VAL_MASK_WE(msk, val) ((MASK_TO_WE(msk)) | (val)) +#define WRITE_REG_MASK_WE(reg, msk, val) \ + WRITE_REG(reg, (VAL_MASK_WE(msk, val))) + +#define _GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (HAL_BITS_PER_LONG - 1 - (h)))) +#define _GENVAL(x, h, l) ((uint32_t)(((x) & _GENMASK(h, l)) >> (l))) +#define _GENVAL_D16(x, h, l) ((uint32_t)(((x) & _GENMASK(h, l)) / 16)) +#define _GENVAL_D16_REM(x, h, l) ((uint32_t)(((x) & _GENMASK(h, l)) % 16)) +#define _WIDTH_TO_MASK(w) ((1 << (w)) - 1) + +/* + * RESET/GATE fields: + * [31:16]: reserved + * [15:12]: bank + * [11:0]: id + */ +#define CLK_RESET_GET_REG_OFFSET(x) _GENVAL_D16(x, 11, 0) +#define CLK_RESET_GET_BITS_SHIFT(x) _GENVAL_D16_REM(x, 11, 0) +#define CLK_RESET_GET_REG_BANK(x) _GENVAL(x, 15, 12) + +#define CLK_GATE_GET_REG_OFFSET(x) CLK_RESET_GET_REG_OFFSET(x) +#define CLK_GATE_GET_BITS_SHIFT(x) CLK_RESET_GET_BITS_SHIFT(x) +#define CLK_GATE_GET_REG_BANK(x) CLK_RESET_GET_REG_BANK(x) + +/* + * MUX/DIV fields: + * [31:24]: width + * [23:16]: shift + * [15:12]: reserved + * [11:8]: bank + * [7:0]: reg + */ +#define CLK_MUX_GET_REG_OFFSET(x) _GENVAL(x, 7, 0) +#define CLK_MUX_GET_BANK(x) _GENVAL(x, 11, 8) +#define CLK_MUX_GET_BITS_SHIFT(x) _GENVAL(x, 23, 16) +#define CLK_MUX_GET_WIDTH(x) _GENVAL(x, 31, 24) +#define CLK_MUX_GET_MASK(x) (_WIDTH_TO_MASK(CLK_MUX_GET_WIDTH(x)) << CLK_MUX_GET_BITS_SHIFT(x)) + +#define CLK_DIV_GET_REG_OFFSET(x) CLK_MUX_GET_REG_OFFSET(x) +#define CLK_DIV_GET_BANK(x) CLK_MUX_GET_BANK(x) +#define CLK_DIV_GET_BITS_SHIFT(x) CLK_MUX_GET_BITS_SHIFT(x) +#define CLK_DIV_GET_WIDTH(x) CLK_MUX_GET_WIDTH(x) +#define CLK_DIV_GET_MASK(x) CLK_MUX_GET_MASK(x) +#define CLK_DIV_GET_MAXDIV(x) ((1 << CLK_DIV_GET_WIDTH(x)) - 1) + +#define CLK_GET_MUX(v32) \ + ((uint32_t)((v32) & 0x0F0F00FFU)) +#define CLK_GET_DIV(v32) \ + ((uint32_t)((((v32) & 0x0000FF00U) >> 8) | \ + (((v32) & 0xF0F00000U) >> 4))) +#define COMPOSITE_CLK(mux, div) \ + (((mux) & 0x0F0F00FFU) | (((div) & 0xFFU) << 8) | \ + (((div) & 0x0F0F0000U) << 4)) + +#define PNAME(x) static const char *x[] + +typedef enum { + DUMP_UNDEF, + DUMP_INT, + DUMP_EXT, +} HAL_DumpType; + +#define CLK_DECLARE(_type, _name, _clk, _parents, _numParents, _extParent, _getFreq) \ +{ \ + .type = _type, \ + .name = _name, \ + .clk = _clk, \ + .parents = _parents, \ + .numParents = _numParents, \ + .extParent = _extParent, \ + .getFreq = _getFreq, \ +} + +#define CLK_DECLARE_INT(_name, _clk, _parents) \ + CLK_DECLARE(DUMP_INT, _name, _clk, _parents, HAL_ARRAY_SIZE(_parents), HAL_NULL, HAL_NULL) + +#define CLK_DECLARE_EXT_PARENT(_name, _clk, _extParent, _getFreq) \ + CLK_DECLARE(DUMP_EXT, _name, _clk, HAL_NULL, 0, _extParent, _getFreq) + +#define CLK_DECLARE_EXT(_name, _clk, _getFreq) \ + CLK_DECLARE_EXT_PARENT(_name, _clk, HAL_NULL, _getFreq) + +#define RK_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \ + { \ + .rate = _rate##U, .fbDiv = _fbdiv, .postDiv1 = _postdiv1, \ + .refDiv = _refdiv, .postDiv2 = _postdiv2, .dsmpd = _dsmpd, \ + .frac = _frac, \ + } + +#define DIV_NO_REM(pFreq, freq, maxDiv) \ + ((!((pFreq) % (freq))) && ((pFreq) / (freq) <= (maxDiv))) + +#define HAL_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) + +/***************************** Structure Definition **************************/ + +struct PLL_CONFIG { + uint32_t rate; + + union { + struct { + uint32_t fbDiv; + uint32_t postDiv1; + uint32_t refDiv; + uint32_t postDiv2; + uint32_t dsmpd; + uint32_t frac; + }; + }; +}; + +typedef enum { + PLL_CPLL, + PLL_RXPLL, + PLL_TXPLL, +} eCRU_PLL; + +struct PLL_SETUP { + eCRU_PLL id; + uint32_t conOffset0; + uint32_t conOffset1; + uint32_t conOffset2; + uint32_t conOffset3; + uint32_t conOffset6; + uint32_t modeOffset; + uint32_t stat0; + uint32_t modeShift; + uint32_t lockShift; + uint32_t modeMask; + const struct PLL_CONFIG *rateTable; + uint8_t minRefdiv; + uint8_t maxRefdiv; + uint32_t minVco; + uint32_t maxVco; + uint32_t minFout; + uint32_t maxFout; + uint8_t sscgEn; +}; + +typedef enum { + GLB_SRST_FST = 0xfdb9, + GLB_SRST_SND = 0xeca8, +} eCRU_GlbSrstType; + +/***************************** Function Declare ******************************/ +uint32_t HAL_CRU_Read(struct hwclk *hw, uint32_t reg); +uint32_t HAL_CRU_Write(struct hwclk *hw, uint32_t reg, uint32_t val); +uint32_t HAL_CRU_WriteMask(struct hwclk *hw, uint32_t reg, + uint32_t msk, uint32_t val); + +int HAL_CRU_FreqGetMux4(struct hwclk *hw, + uint32_t freq, uint32_t freq0, + uint32_t freq1, uint32_t freq2, uint32_t freq3); +int HAL_CRU_FreqGetMux3(struct hwclk *hw, + uint32_t freq, uint32_t freq0, + uint32_t freq1, uint32_t freq2); +int HAL_CRU_FreqGetMux2(struct hwclk *hw, + uint32_t freq, uint32_t freq0, uint32_t freq1); + +uint32_t HAL_CRU_MuxGetFreq4(struct hwclk *hw, uint32_t muxName, + uint32_t freq0, uint32_t freq1, + uint32_t freq2, uint32_t freq3); +uint32_t HAL_CRU_MuxGetFreq3(struct hwclk *hw, uint32_t muxName, + uint32_t freq0, uint32_t freq1, uint32_t freq2); +uint32_t HAL_CRU_MuxGetFreq2(struct hwclk *hw, uint32_t muxName, + uint32_t freq0, uint32_t freq1); + +int HAL_CRU_RoundFreqGetMux4(struct hwclk *hw, uint32_t freq, + uint32_t pFreq0, uint32_t pFreq1, + uint32_t pFreq2, uint32_t pFreq3, uint32_t *pFreqOut); +int HAL_CRU_RoundFreqGetMux3(struct hwclk *hw, uint32_t freq, + uint32_t pFreq0, uint32_t pFreq1, + uint32_t pFreq2, uint32_t *pFreqOut); +int HAL_CRU_RoundFreqGetMux2(struct hwclk *hw, uint32_t freq, + uint32_t pFreq0, uint32_t pFreq1, uint32_t *pFreqOut); + +/** + * @brief Get pll freq. + * @param pSetup: Contains PLL register parameters + * @return pll rate. + */ +uint32_t HAL_CRU_GetPllFreq(struct hwclk *hw, struct PLL_SETUP *pSetup); + +/** + * @brief Set pll freq. + * @param pSetup: Contains PLL register parameters + * @param rate: pll set + * @return HAL_Status. + */ +HAL_Status HAL_CRU_SetPllFreq(struct hwclk *hw, struct PLL_SETUP *pSetup, uint32_t rate); + +/** + * @brief Set pll power up. + * @param pSetup: Contains PLL register parameters + * @return HAL_Status. + */ +HAL_Status HAL_CRU_SetPllPowerUp(struct hwclk *hw, struct PLL_SETUP *pSetup); + +/** + * @brief Set pll power down. + * @param pSetup: Contains PLL register parameters + * @return HAL_Status. + */ +HAL_Status HAL_CRU_SetPllPowerDown(struct hwclk *hw, struct PLL_SETUP *pSetup); + +/** + * @brief Check if clk is enabled + * @param clk: clock to check + * @return HAL_Check. + */ +HAL_Check HAL_CRU_ClkIsEnabled(struct hwclk *hw, uint32_t clk); + +/** + * @brief Enable clk + * @param clk: clock to set + * @return HAL_Status. + */ +HAL_Status HAL_CRU_ClkEnable(struct hwclk *hw, uint32_t clk); + +/** + * @brief Disable clk + * @param clk: clock to set + * @return HAL_Status. + */ +HAL_Status HAL_CRU_ClkDisable(struct hwclk *hw, uint32_t clk); + +/** + * @brief Check if clk is reset + * @param clk: clock to check + * @return HAL_Check. + */ +HAL_Check HAL_CRU_ClkIsReset(struct hwclk *hw, uint32_t clk); + +/** + * @brief Assert the reset to the clk + * @param clk: clock to assert + * @return HAL_Status. + */ +HAL_Status HAL_CRU_ClkResetAssert(struct hwclk *hw, uint32_t clk); + +/** + * @brief Deassert the reset to the clk + * @param clk: clock to deassert + * @return HAL_Status. + */ +HAL_Status HAL_CRU_ClkResetDeassert(struct hwclk *hw, uint32_t clk); + +/** + * @brief Set integer div + * @param divName: div id(struct hwclk *hw, Contains div offset, shift, mask information) + * @param divValue: div value + * @return NONE + */ +HAL_Status HAL_CRU_ClkSetDiv(struct hwclk *hw, uint32_t divName, uint32_t divValue); + +/** + * @brief Get integer div + * @param divName: div id (struct hwclk *hw,, Contains div offset, shift, mask information) + * @return div value + */ +uint32_t HAL_CRU_ClkGetDiv(struct hwclk *hw, uint32_t divName); + +/** + * @brief Set mux + * @param muxName: mux id (struct hwclk *hw,, Contains mux offset, shift, mask information) + * @param muxValue: mux value + * @return NONE + */ +HAL_Status HAL_CRU_ClkSetMux(struct hwclk *hw, uint32_t muxName, uint32_t muxValue); + +/** + * @brief Get mux + * @param muxName: mux id (struct hwclk *hw, Contains mux offset, shift, mask information) + * @return mux value + */ +uint32_t HAL_CRU_ClkGetMux(struct hwclk *hw, uint32_t muxName); + +/** + * @brief Get clk freq. + * @param clockName: CLOCK_Name id. + * @return rate. + * @attention these APIs allow direct use in the HAL layer. + */ +uint32_t HAL_CRU_ClkGetFreq(struct hwclk *hw, uint32_t clockName); + +/** + * @brief Set clk freq. + * @param clockName: CLOCK_Name id. + * @param rate: clk rate. + * @return HAL_Status. + * @attention these APIs allow direct use in the HAL layer. + */ +HAL_Status HAL_CRU_ClkSetFreq(struct hwclk *hw, uint32_t clockName, uint32_t rate); + +/** + * @brief assert CRU global software reset. + * @param type: global software reset type. + * @return HAL_INVAL if the SoC does not support. + */ +HAL_Status HAL_CRU_SetGlbSrst(struct hwclk *hw, eCRU_GlbSrstType type); + +/** + * @brief Set clk testout + * @param clockName: CLOCK_Name id. + * @param muxValue: mux value. + * @param divValue: div value. + * @return HAL_INVAL if the SoC does not support. + */ +HAL_Status HAL_CRU_ClkSetTestout(struct hwclk *hw, uint32_t clockName, + uint32_t muxValue, uint32_t divValue); +/** + * @brief Dump all clock tree + */ +void HAL_CRU_ClkDumpTree(HAL_ClockType type); + +/** + * @brief CRU init for chip + * @return HAL_INVAL if the SoC does not support. + */ +HAL_Status HAL_CRU_Init(void); + +/** + * @brief Register CRU + * @param xfer: the data to register + * @return hwclk descriptor. + */ +struct hwclk *HAL_CRU_Register(struct xferclk xfer); + +/** + * @brief Get hwclk + * @param client: the unit data to find hwclk + * @return hwclk descriptor. + */ +struct hwclk *HAL_CRU_ClkGet(void *client); + +/************************** chip ops *************************************/ +extern struct clkOps rkx110_clk_ops; +extern struct clkOps rkx120_clk_ops; +extern struct clkOps rkx111_clk_ops; +extern struct clkOps rkx121_clk_ops; +#endif diff --git a/drivers/mfd/rkx110_x120/hal/cru_rkx110.c b/drivers/mfd/rkx110_x120/hal/cru_rkx110.c new file mode 100644 index 000000000000..5d53ec33dd60 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_rkx110.c @@ -0,0 +1,612 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#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; + + 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) { + pRate = (_MHZ(1200) / rate) * rate; + } + + 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, "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, +}; diff --git a/drivers/mfd/rkx110_x120/hal/cru_rkx110.h b/drivers/mfd/rkx110_x120/hal/cru_rkx110.h new file mode 100644 index 000000000000..7541b7f53764 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_rkx110.h @@ -0,0 +1,358 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#ifndef _CRU_RKX110_H + +#include "cru_core.h" + +// ======================== RXCRU module definition START ====================== +// RXCRU_SOFTRST_CON01(Offset:0x404) +#define RKX110_SRST_PRESETN_RX_CRU 0x00000010 +#define RKX110_SRST_PRESETN_RX_GRF 0x00000011 +#define RKX110_SRST_PRESETN_RX_GPIO0 0x00000012 +#define RKX110_SRST_DRESETN_RX_GPIO0 0x00000013 +#define RKX110_SRST_PRESETN_RX_GPIO1 0x00000014 +#define RKX110_SRST_DRESETN_RX_GPIO1 0x00000015 +#define RKX110_SRST_PRESETN_RX_EFUSE 0x00000016 +#define RKX110_SRST_RESETN_RX_EFUSE 0x00000017 +#define RKX110_SRST_PRESETN_MIPI_GRF_RX0 0x0000001A +#define RKX110_SRST_PRESETN_MIPI_GRF_RX1 0x0000001B +#define RKX110_SRST_PRESETN_RX_I2C2APB 0x0000001E +#define RKX110_SRST_PRESETN_RX_I2C2APB_DEBUG 0x0000001F + +// RXCRU_SOFTRST_CON02(Offset:0x408) +#define RKX110_SRST_DRESETN_VICAP_CSI 0x00000021 +#define RKX110_SRST_HRESETN_VICAP 0x00000022 +#define RKX110_SRST_IRESETN_VICAP 0x00000023 +#define RKX110_SRST_RXPRESETN_VICAP_LVDS 0x00000024 +#define RKX110_SRST_PRESETN_VICAP_DVP_RX 0x00000025 +#define RKX110_SRST_DRESETN_DSI0 0x00000026 +#define RKX110_SRST_HRESETN_DSI0 0x00000027 +#define RKX110_SRST_IRESETN_DSI0 0x00000028 +#define RKX110_SRST_RXPRESETN_LVDS_ALIGN 0x00000029 +#define RKX110_SRST_DRESETN_DSI1 0x0000002A +#define RKX110_SRST_HRESETN_DSI1 0x0000002B +#define RKX110_SRST_IRESETN_DSI1 0x0000002C + +// RXCRU_SOFTRST_CON03(Offset:0x40C) +#define RKX110_SRST_PRESETN_CSIHOST0 0x00000030 +#define RKX110_SRST_PRESETN_CSIHOST1 0x00000032 + +// RXCRU_SOFTRST_CON04(Offset:0x410) +#define RKX110_SRST_PRESETN_RKLINK_TX 0x00000040 +#define RKX110_SRST_RESETN_C_DVP_RKLINK_TX 0x00000041 +#define RKX110_SRST_RESETN_C_CSI_RKLINK_TX 0x00000042 +#define RKX110_SRST_RESETN_C_LVDS_RKLINK_TX 0x00000043 +#define RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX 0x00000044 +#define RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX 0x00000045 +#define RKX110_SRST_RESETN_D_RGB_RKLINK_TX 0x00000046 +#define RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX 0x00000048 +#define RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX 0x0000004A +#define RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX 0x0000004B +#define RKX110_SRST_RESETN_I2S_SRC_RKLINK_TX 0x0000004C +#define RKX110_SRST_RESETN_D_DSI_0_REC_RKLINK_TX 0x0000004D +#define RKX110_SRST_RESETN_D_DSI_1_REC_RKLINK_TX 0x0000004E + +// RXCRU_SOFTRST_CON05(Offset:0x414) +#define RKX110_SRST_RESETN_PMA2LINK2PCS_LINK 0x00000051 +#define RKX110_SRST_RESETN_PMA2LINK2PCS_PCS0 0x00000052 +#define RKX110_SRST_RESETN_PMA2LINK2PCS_PCS1 0x00000053 +#define RKX110_SRST_SRESETN_I2S_PCS0 0x00000054 +#define RKX110_SRST_SRESETN_I2S_PCS1 0x00000055 + +// RXCRU_SOFTRST_CON06(Offset:0x418) +#define RKX110_SRST_RESETN_D_DSI_0_PATTERN_GEN 0x00000060 +#define RKX110_SRST_RESETN_D_DSI_1_PATTERN_GEN 0x00000061 +#define RKX110_SRST_RESETN_D_LVDS0_PATTERN_GEN 0x00000062 +#define RKX110_SRST_RESETN_D_LVDS1_PATTERN_GEN 0x00000063 +#define RKX110_SRST_PRESETN_DSI_0_PATTERN_GEN 0x00000068 +#define RKX110_SRST_PRESETN_DSI_1_PATTERN_GEN 0x00000069 +#define RKX110_SRST_PRESETN_LVDS_0_PATTERN_GEN 0x0000006A +#define RKX110_SRST_PRESETN_LVDS_1_PATTERN_GEN 0x0000006B + +// RXCRU_SOFTRST_CON07(Offset:0x41C) +#define RKX110_SRST_PRESETN_PCS0 0x00000070 +#define RKX110_SRST_RESETN_8X_PMA2PCS0 0x00000071 +#define RKX110_SRST_RESETN_PMA2PCS0 0x00000073 +#define RKX110_SRST_PRESETN_PCS0_ADA 0x00000074 +#define RKX110_SRST_RESETN_PCS0_ADA 0x00000075 + +// RXCRU_SOFTRST_CON08(Offset:0x420) +#define RKX110_SRST_PRESETN_PCS1 0x00000080 +#define RKX110_SRST_RESETN_8X_PMA2PCS1 0x00000081 +#define RKX110_SRST_RESETN_PMA2PCS1 0x00000083 +#define RKX110_SRST_PRESETN_PCS1_ADA 0x00000084 +#define RKX110_SRST_RESETN_PCS1_ADA 0x00000085 + +// RXCRU_SOFTRST_CON10(Offset:0x428) +#define RKX110_SRST_PRESETN_MIPIRXPHY0 0x000000A0 +#define RKX110_SRST_CFGRESETN_MIPIRXPHY0 0x000000A1 +#define RKX110_SRST_PRESETN_MIPIRXPHY1 0x000000A8 +#define RKX110_SRST_CFGRESETN_MIPIRXPHY1 0x000000A9 + +// RXCRU_SOFTRST_CON11(Offset:0x42C) +#define RKX110_SRST_PRESETN_DFT2APB 0x000000B0 + +// RXCRU_GATE_CON00(Offset:0x300) +#define RKX110_CLK_TESTOUT_TOP_GATE 0x00000000 +#define RKX110_BUSCLK_RX_PRE0_GATE 0x00000001 +#define RKX110_BUSCLK_RX_PRE_GATE 0x00000002 + +// RXCRU_GATE_CON01(Offset:0x304) +#define RKX110_PCLK_RX_CRU_GATE 0x00000010 +#define RKX110_PCLK_RX_GRF_GATE 0x00000011 +#define RKX110_PCLK_RX_GPIO0_GATE 0x00000012 +#define RKX110_DCLK_RX_GPIO0_GATE 0x00000013 +#define RKX110_PCLK_RX_GPIO1_GATE 0x00000014 +#define RKX110_DCLK_RX_GPIO1_GATE 0x00000015 +#define RKX110_PCLK_RX_EFUSE_GATE 0x00000016 +#define RKX110_CLK_RX_EFUSE_GATE 0x00000017 +#define RKX110_PCLK_MIPI_GRF_RX0_GATE 0x0000001A +#define RKX110_PCLK_MIPI_GRF_RX1_GATE 0x0000001B +#define RKX110_PCLK_RX_I2C2APB_GATE 0x0000001E +#define RKX110_PCLK_RX_I2C2APB_DEBUG_GATE 0x0000001F + +// RXCRU_GATE_CON02(Offset:0x308) +#define RKX110_DCLK_RX_PRE_GATE 0x00000020 +#define RKX110_DCLK_VICAP_CSI_GATE 0x00000021 +#define RKX110_HCLK_VICAP_GATE 0x00000022 +#define RKX110_ICLK_VICAP_INTER_GATE 0x00000023 +#define RKX110_RXPCLK_VICAP_LVDS_DFT_GATE 0x00000024 +#define RKX110_PCLKIN_VICAP_DVP_RX_DFT_GATE 0x00000025 +#define RKX110_DCLK_DSI0_GATE 0x00000026 +#define RKX110_HCLK_DSI0_GATE 0x00000027 +#define RKX110_ICLK_DSI0_INTER_GATE 0x00000028 +#define RKX110_RXPCLK_LVDS_ALIGN_DFT_GATE 0x00000029 +#define RKX110_DCLK_DSI1_GATE 0x0000002A +#define RKX110_HCLK_DSI1_GATE 0x0000002B +#define RKX110_ICLK_DSI1_INTER_GATE 0x0000002C + +// RXCRU_GATE_CON03(Offset:0x30C) +#define RKX110_PCLK_CSIHOST0_GATE 0x00000030 +#define RKX110_CLK_RXBYTEHS_CSIHOST0_DFT_GATE 0x00000031 +#define RKX110_PCLK_CSIHOST1_GATE 0x00000032 +#define RKX110_CLK_RXBYTEHS_CSIHOST1_DFT_GATE 0x00000033 + +// RXCRU_GATE_CON04(Offset:0x310) +#define RKX110_PCLK_RKLINK_TX_GATE 0x00000040 +#define RKX110_CLK_C_DVP_RKLINK_TX_GATE 0x00000041 +#define RKX110_CLK_C_CSI_RKLINK_TX_GATE 0x00000042 +#define RKX110_CLK_C_LVDS_RKLINK_TX_GATE 0x00000043 +#define RKX110_CLK_D_DSI_0_RKLINK_TX_GATE 0x00000044 +#define RKX110_CLK_D_DSI_1_RKLINK_TX_GATE 0x00000045 +#define RKX110_CLK_D_RGB_RKLINK_TX_DFT_GATE 0x00000046 +#define RKX110_CLK_D_LVDS0_RKLINK_TX_CM_GATE 0x00000047 +#define RKX110_CLK_D_LVDS0_RKLINK_TX_GATE 0x00000048 +#define RKX110_CLK_D_LVDS1_RKLINK_TX_CM_GATE 0x00000049 +#define RKX110_CLK_D_LVDS1_RKLINK_TX_GATE 0x0000004A +#define RKX110_CLK_2X_LVDS_RKLINK_TX_GATE 0x0000004B +#define RKX110_CLK_I2S_SRC_RKLINK_TX_GATE 0x0000004C +#define RKX110_DCLK_D_DSI_0_REC_RKLINK_TX_GATE 0x0000004D +#define RKX110_DCLK_D_DSI_1_REC_RKLINK_TX_GATE 0x0000004E + +// RXCRU_GATE_CON05(Offset:0x314) +#define RKX110_CLK_PMA2LINK2PCS_CM_GATE 0x00000050 +#define RKX110_CLK_PMA2LINK2PCS_LINK_GATE 0x00000051 +#define RKX110_CLK_PMA2LINK2PCS_PSC0_GATE 0x00000052 +#define RKX110_CLK_PMA2LINK2PCS_PSC1_GATE 0x00000053 +#define RKX110_SCLK_I2S_LINK2PCS_INTER1_GATE 0x00000054 +#define RKX110_SCLK_I2S_LINK2PCS_INTER2_GATE 0x00000055 + +// RXCRU_GATE_CON06(Offset:0x318) +#define RKX110_CLK_D_DSI_0_PATTERN_GEN_GATE 0x00000060 +#define RKX110_CLK_D_DSI_1_PATTERN_GEN_GATE 0x00000061 +#define RKX110_CLK_D_LVDS0_PATTERN_GEN_GATE 0x00000062 +#define RKX110_CLK_D_LVDS1_PATTERN_GEN_GATE 0x00000063 +#define RKX110_PCLK_DSI_0_PATTERN_GEN_GATE 0x00000068 +#define RKX110_PCLK_DSI_1_PATTERN_GEN_GATE 0x00000069 +#define RKX110_PCLK_LVDS_0_PATTERN_GEN_GATE 0x0000006A +#define RKX110_PCLK_LVDS_1_PATTERN_GEN_GATE 0x0000006B + +// RXCRU_GATE_CON07(Offset:0x31C) +#define RKX110_PCLK_PCS0_GATE 0x00000070 +#define RKX110_CLK_8X_PMA2PCS0_DFT_GATE 0x00000071 +#define RKX110_CLK_LINK_PCS0_DFT_GATE 0x00000072 +#define RKX110_CLK_PMA2PCS0_GATE 0x00000073 +#define RKX110_PCLK_PCS0_ADA_GATE 0x00000074 +#define RKX110_CLK_PCS0_ADA_GATE 0x00000075 + +// RXCRU_GATE_CON08(Offset:0x320) +#define RKX110_PCLK_PCS1_GATE 0x00000080 +#define RKX110_CLK_8X_PMA2PCS1_DFT_GATE 0x00000081 +#define RKX110_CLK_LINK_PCS1_DFT_GATE 0x00000082 +#define RKX110_CLK_PMA2PCS1_GATE 0x00000083 +#define RKX110_PCLK_PCS1_ADA_GATE 0x00000084 +#define RKX110_CLK_PCS1_ADA_GATE 0x00000085 + +// RXCRU_GATE_CON09(Offset:0x324) +#define RKX110_CLK_CAM_OUT2IO_GATE 0x00000090 + +// RXCRU_GATE_CON10(Offset:0x328) +#define RKX110_PCLK_MIPIRXPHY0_GATE 0x000000A0 +#define RKX110_CFGCLK_MIPIRXPHY0_GATE 0x000000A1 +#define RKX110_CKREF_MIPIRXPHY0_GATE 0x000000A2 +#define RKX110_PCLK_MIPIRXPHY1_GATE 0x000000A8 +#define RKX110_CFGCLK_MIPIRXPHY1_GATE 0x000000A9 +#define RKX110_CKREF_MIPIRXPHY1_GATE 0x000000AA +#define RKX110_CLK_CAM0_OUT2IO_GATE 0x000000AB +#define RKX110_CLK_CAM1_OUT2IO_GATE 0x000000AC + +// RXCRU_GATE_CON11(Offset:0x32C) +#define RKX110_PCLK_DFT2APB_GATE 0x000000B0 + +// RXCRU_CLKSEL_CON00(Offset:0x100) +#define RKX110_TEST_CLKOUT_IOUT_DIV 0x08000000 +#define RKX110_TEST_CLKOUT_IOUT_SEL 0x05080000 +#define RKX110_TEST_CLKOUT_IOUT_SEL_XIN_OSC0_FUNC 0U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_RXPLL_MUX 1U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_CPLL_MUX 2U +#define RKX110_TEST_CLKOUT_IOUT_SEL_RXPCLK_VICAP_LVDS 3U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_RXBYTEHS_CSIHOST0 4U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_RXBYTEHS_CSIHOST1 5U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_D_RGB_RKLINK_TX 6U +#define RKX110_TEST_CLKOUT_IOUT_SEL_DCLK_LVDS0 7U +#define RKX110_TEST_CLKOUT_IOUT_SEL_DCLK_LVDS1 8U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_LINK_PCS0 9U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_LINK_PCS1 10U +#define RKX110_TEST_CLKOUT_IOUT_SEL_BUSCLK_RX_PRE 11U +#define RKX110_TEST_CLKOUT_IOUT_SEL_DCLK_RX_PRE 12U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_2X_LVDS_RKLINK_TX 13U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_I2S_SRC_RKLINK_TX 14U +#define RKX110_TEST_CLKOUT_IOUT_SEL_DCLK_D_DSI_0_REC_RKLINK_TX 15U +#define RKX110_TEST_CLKOUT_IOUT_SEL_DCLK_D_DSI_1_REC_RKLINK_TX 16U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CFGCLK_MIPIRXPHY0 17U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CKREF_MIPIRXPHY0 18U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CFGCLK_MIPIRXPHY1 19U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CKREF_MIPIRXPHY1 20U +#define RKX110_TEST_CLKOUT_IOUT_SEL_PCLKIN_VICAP_DVP_RX 21U +#define RKX110_TEST_CLKOUT_IOUT_SEL_ICLK_DSI0 22U +#define RKX110_TEST_CLKOUT_IOUT_SEL_ICLK_DSI1 23U +#define RKX110_TEST_CLKOUT_IOUT_SEL_RXPCLK_LVDS_ALIGN 24U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_8X_PMA2PCS0 25U +#define RKX110_TEST_CLKOUT_IOUT_SEL_CLK_8X_PMA2PCS1 26U + +// RXCRU_CLKSEL_CON01(Offset:0x104) +#define RKX110_BUSCLK_RX_PRE0_DIV 0x06000001 +#define RKX110_BUSCLK_RX_PRE0_SEL 0x01070001 +#define RKX110_BUSCLK_RX_PRE0_SEL_CLK_RXPLL_MUX 0U +#define RKX110_BUSCLK_RX_PRE0_SEL_CLK_CPLL_MUX 1U +#define RKX110_BUSCLK_RX_PRE_SEL 0x01080001 +#define RKX110_BUSCLK_RX_PRE_SEL_XIN_OSC0_FUNC 0U +#define RKX110_BUSCLK_RX_PRE_SEL_BUSCLK_RX_PRE0 1U + +// RXCRU_CLKSEL_CON02(Offset:0x108) +#define RKX110_DCLK_RX_PRE_DIV 0x06000002 +#define RKX110_DCLK_RX_PRE_SEL 0x02060002 +#define RKX110_DCLK_RX_PRE_SEL_CLK_RXPLL_MUX 0U +#define RKX110_DCLK_RX_PRE_SEL_CLK_CPLL_MUX 1U +#define RKX110_DCLK_RX_PRE_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON03(Offset:0x10C) +#define RKX110_CLK_2X_LVDS_RKLINK_TX_DIV 0x08000003 +#define RKX110_CLK_2X_LVDS_RKLINK_TX_SEL 0x020E0003 +#define RKX110_CLK_2X_LVDS_RKLINK_TX_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CLK_2X_LVDS_RKLINK_TX_SEL_CLK_CPLL_MUX 1U +#define RKX110_CLK_2X_LVDS_RKLINK_TX_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON04(Offset:0x110) +#define RKX110_CLK_I2S_SRC_RKLINK_TX_DIV 0x08000004 +#define RKX110_CLK_I2S_SRC_RKLINK_TX_SEL 0x020E0004 +#define RKX110_CLK_I2S_SRC_RKLINK_TX_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CLK_I2S_SRC_RKLINK_TX_SEL_CLK_CPLL_MUX 1U +#define RKX110_CLK_I2S_SRC_RKLINK_TX_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON05(Offset:0x114) +#define RKX110_DCLK_D_DSI_0_REC_RKLINK_TX_DIV 0x08000005 +#define RKX110_DCLK_D_DSI_0_REC_RKLINK_TX_SEL 0x020E0005 +#define RKX110_DCLK_D_DSI_0_REC_RKLINK_TX_SEL_CLK_RXPLL_MUX 0U +#define RKX110_DCLK_D_DSI_0_REC_RKLINK_TX_SEL_CLK_CPLL_MUX 1U +#define RKX110_DCLK_D_DSI_0_REC_RKLINK_TX_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON06(Offset:0x118) +#define RKX110_DCLK_D_DSI_1_REC_RKLINK_TX_DIV 0x08000006 +#define RKX110_DCLK_D_DSI_1_REC_RKLINK_TX_SEL 0x020E0006 +#define RKX110_DCLK_D_DSI_1_REC_RKLINK_TX_SEL_CLK_RXPLL_MUX 0U +#define RKX110_DCLK_D_DSI_1_REC_RKLINK_TX_SEL_CLK_CPLL_MUX 1U +#define RKX110_DCLK_D_DSI_1_REC_RKLINK_TX_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON07(Offset:0x11C) +#define RKX110_CLK_PMA2LINK2PCS_CM_SEL 0x010F0007 +#define RKX110_CLK_PMA2LINK2PCS_CM_SEL_CLK_LINK_PCS0_DFT 0U +#define RKX110_CLK_PMA2LINK2PCS_CM_SEL_CLK_LINK_PCS1_DFT 1U + +// RXCRU_CLKSEL_CON08(Offset:0x120) +#define RKX110_CLK_CIF_OUT2IO_DIV 0x08000008 +#define RKX110_CLK_CIF_OUT2IO_SEL 0x020E0008 +#define RKX110_CLK_CIF_OUT2IO_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CLK_CIF_OUT2IO_SEL_CLK_CPLL_MUX 1U +#define RKX110_CLK_CIF_OUT2IO_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON09(Offset:0x124) +#define RKX110_CFGCLK_MIPIRXPHY0_DIV 0x08000009 +#define RKX110_CFGCLK_MIPIRXPHY0_SEL 0x010F0009 +#define RKX110_CFGCLK_MIPIRXPHY0_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CFGCLK_MIPIRXPHY0_SEL_CLK_CPLL_MUX 1U + +// RXCRU_CLKSEL_CON10(Offset:0x128) +#define RKX110_CKREF_MIPIRXPHY0_DIV 0x0400000A +#define RKX110_CKREF_MIPIRXPHY0_SEL 0x0107000A +#define RKX110_CKREF_MIPIRXPHY0_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CKREF_MIPIRXPHY0_SEL_CLK_CPLL_MUX 1U + +// RXCRU_CLKSEL_CON11(Offset:0x12C) +#define RKX110_CFGCLK_MIPIRXPHY1_DIV 0x0800000B +#define RKX110_CFGCLK_MIPIRXPHY1_SEL 0x010F000B +#define RKX110_CFGCLK_MIPIRXPHY1_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CFGCLK_MIPIRXPHY1_SEL_CLK_CPLL_MUX 1U + +// RXCRU_CLKSEL_CON12(Offset:0x130) +#define RKX110_CKREF_MIPIRXPHY1_DIV 0x0408000C +#define RKX110_CKREF_MIPIRXPHY1_SEL 0x010F000C +#define RKX110_CKREF_MIPIRXPHY1_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CKREF_MIPIRXPHY1_SEL_CLK_CPLL_MUX 1U + +// RXCRU_CLKSEL_CON15(Offset:0x13C) +#define RKX110_CLK_CAM0_OUT2IO_DIV 0x0600000F +#define RKX110_CLK_CAM1_OUT2IO_DIV 0x0608000F +#define RKX110_CLK_CAM0_OUT2IO_SEL 0x0206000F +#define RKX110_CLK_CAM0_OUT2IO_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CLK_CAM0_OUT2IO_SEL_CLK_CPLL_MUX 1U +#define RKX110_CLK_CAM0_OUT2IO_SEL_XIN_OSC0_FUNC 2U +#define RKX110_CLK_CAM1_OUT2IO_SEL 0x020E000F +#define RKX110_CLK_CAM1_OUT2IO_SEL_CLK_RXPLL_MUX 0U +#define RKX110_CLK_CAM1_OUT2IO_SEL_CLK_CPLL_MUX 1U +#define RKX110_CLK_CAM1_OUT2IO_SEL_XIN_OSC0_FUNC 2U + +// ======================== RXCRU module definition END ======================== +#define RKX110_CPS_INVAL 0 +#define RKX110_CPS_PLL_CPLL 1 +#define RKX110_CPS_PLL_RXPLL 2 +#define RKX110_CPS_DCLK_RX_GPIO0 3 +#define RKX110_CPS_DCLK_RX_GPIO1 4 +#define RKX110_CPS_RX_EFUSE 5 +#define RKX110_CPS_PCS0_ADA 6 +#define RKX110_CPS_PCS1_ADA 7 +#define RKX110_CLK_D_DSI_0_PATTERN_GEN 8 +#define RKX110_CLK_D_DSI_1_PATTERN_GEN 9 +#define RKX110_CPS_DCLK_RX_PRE COMPOSITE_CLK(RKX110_DCLK_RX_PRE_SEL, RKX110_DCLK_RX_PRE_DIV) +#define RKX110_CPS_CLK_2X_LVDS_RKLINK_TX COMPOSITE_CLK(RKX110_CLK_2X_LVDS_RKLINK_TX_SEL, RKX110_CLK_2X_LVDS_RKLINK_TX_DIV) +#define RKX110_CPS_CLK_I2S_SRC_RKLINK_TX COMPOSITE_CLK(RKX110_CLK_I2S_SRC_RKLINK_TX_SEL, RKX110_CLK_I2S_SRC_RKLINK_TX_DIV) +#define RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX COMPOSITE_CLK(RKX110_DCLK_D_DSI_0_REC_RKLINK_TX_SEL, RKX110_DCLK_D_DSI_0_REC_RKLINK_TX_DIV) +#define RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX COMPOSITE_CLK(RKX110_DCLK_D_DSI_1_REC_RKLINK_TX_SEL, RKX110_DCLK_D_DSI_1_REC_RKLINK_TX_DIV) +#define RKX110_CPS_CLK_PMA2LINK2PCS_CM COMPOSITE_CLK(RKX110_CLK_PMA2LINK2PCS_CM_SEL, 0) +#define RKX110_CPS_CLK_CIF_OUT2IO COMPOSITE_CLK(RKX110_CLK_CIF_OUT2IO_SEL, RKX110_CLK_CIF_OUT2IO_DIV) +#define RKX110_CPS_CKREF_MIPIRXPHY0 COMPOSITE_CLK(RKX110_CKREF_MIPIRXPHY0_SEL, RKX110_CKREF_MIPIRXPHY0_DIV) +#define RKX110_CPS_CKREF_MIPIRXPHY1 COMPOSITE_CLK(RKX110_CKREF_MIPIRXPHY1_SEL, RKX110_CKREF_MIPIRXPHY1_DIV) +#define RKX110_CPS_CLK_CAM0_OUT2IO COMPOSITE_CLK(RKX110_CLK_CAM0_OUT2IO_SEL, RKX110_CLK_CAM0_OUT2IO_DIV) +#define RKX110_CPS_CLK_CAM1_OUT2IO COMPOSITE_CLK(RKX110_CLK_CAM1_OUT2IO_SEL, RKX110_CLK_CAM1_OUT2IO_DIV) +#define RKX110_CPS_BUSCLK_RX_PRE0 COMPOSITE_CLK(RKX110_BUSCLK_RX_PRE0_SEL, RKX110_BUSCLK_RX_PRE0_DIV) +#define RKX110_CPS_BUSCLK_RX_PRE COMPOSITE_CLK(RKX110_BUSCLK_RX_PRE_SEL, 0) +#define RKX110_CPS_CFGCLK_MIPIRXPHY0 COMPOSITE_CLK(RKX110_CFGCLK_MIPIRXPHY0_SEL, RKX110_CFGCLK_MIPIRXPHY0_DIV) +#define RKX110_CPS_CFGCLK_MIPIRXPHY1 COMPOSITE_CLK(RKX110_CFGCLK_MIPIRXPHY1_SEL, RKX110_CFGCLK_MIPIRXPHY1_DIV) +#define RKX110_CPS_TEST_CLKOUT COMPOSITE_CLK(RKX110_TEST_CLKOUT_IOUT_SEL, RKX110_TEST_CLKOUT_IOUT_DIV) +#endif + diff --git a/drivers/mfd/rkx110_x120/hal/cru_rkx111.c b/drivers/mfd/rkx110_x120/hal/cru_rkx111.c new file mode 100644 index 000000000000..5f24c6223919 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_rkx111.c @@ -0,0 +1,706 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#include "cru_core.h" +#include "cru_rkx111.h" + +/* + * [RKX111 CHIP]: RX + * + * ================= SECTION: Input clock from devices ========================= + * + * ### 400M ### + * clk_8x_pma2pcs0 + * clk_8x_pma2pcs1 + * + * + * ### 200M ### + * sclk_i2s_link2pcs --|-- sclk_i2s_link2pcs_inter1 + * |-- sclk_i2s_link2pcs_inter2 + * + * + * ### 150M ### + * 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 + * + * + * ### 200M ### + * 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 pRate0 = 0, pRate1 = 0; + uint32_t clkMux, clkDiv; + + if (clockName == RKX110_CLK_D_DSI_0_PATTERN_GEN) { + clockName = RKX111_CPS_DCLK_D_DSI_0_REC; + } + if (clockName == RKX110_CLK_D_DSI_1_PATTERN_GEN) { + clockName = RKX111_CPS_DCLK_D_DSI_1_REC; + } + + 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_vicap_csi + * clk_c_csi_rklink_tx + * clk_d_dsi_0_rklink_tx + * + * NOTE: `clk_d_rgb_rklink_tx` is an input clock. + * + */ + case RKX110_CPS_DCLK_RX_PRE: + + /* + * === DCLK_RX_PRE_200M gate children === + * + * clk_c_dvp_rklink_tx + * clk_c_lvds_rklink_tx + * clk_d_dsi_1_rklink_tx + * dclk_dsi1 + * dclk_vicap_csi_ls + */ + case RKX111_CPS_DCLK_RX_PRE_200M: + + /* camera: 150M */ + case RKX110_CPS_CLK_CAM0_OUT2IO: + case RKX110_CPS_CLK_CAM1_OUT2IO: + case RKX110_CPS_CLK_CIF_OUT2IO: + + /* dsi0: 200M, child: clk_d_dsi_0_pattern_gen */ + case RKX111_CPS_DCLK_D_DSI_0_REC: + /* dsi1: 200M, child: clk_d_dsi_1_pattern_gen */ + case RKX111_CPS_DCLK_D_DSI_1_REC: + + /* lvds pattern gen: 150M */ + case RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN: + case RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN: + + /* lvds: 200M */ + 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 + * pclk_lbist_ada_rx (new) + * + * 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 RKX111_CPS_CLK_D_LVDS0_RKLINK_TX: + pRate0 = _MHZ(150); /* input clock: dclk_lvds0 */ + pRate1 = RKX11x_HAL_CRU_ClkGetFreq(hw, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN); + freq = HAL_CRU_MuxGetFreq2(hw, clkMux, pRate0, pRate1); + break; + + case RKX111_CPS_CLK_D_LVDS1_RKLINK_TX: + pRate0 = _MHZ(150); /* input clock: dclk_lvds1 */ + pRate1 = RKX11x_HAL_CRU_ClkGetFreq(hw, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN); + freq = HAL_CRU_MuxGetFreq2(hw, clkMux, pRate0, pRate1); + break; + + case RKX111_CPS_CLK_D_DSI_0_RKLINK_TX: + pRate0 = RKX11x_HAL_CRU_ClkGetFreq(hw, RKX110_CPS_DCLK_RX_PRE); /* 400M */ + pRate1 = RKX11x_HAL_CRU_ClkGetFreq(hw, RKX110_CLK_D_DSI_0_PATTERN_GEN); + freq = HAL_CRU_MuxGetFreq2(hw, clkMux, pRate0, pRate1); + break; + + case RKX111_CPS_CLK_D_DSI_1_RKLINK_TX: + pRate0 = RKX11x_HAL_CRU_ClkGetFreq(hw, RKX111_CPS_DCLK_RX_PRE_200M); + pRate1 = RKX11x_HAL_CRU_ClkGetFreq(hw, RKX110_CLK_D_DSI_1_PATTERN_GEN); + freq = HAL_CRU_MuxGetFreq2(hw, clkMux, pRate0, pRate1); + 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; + + if (clockName == RKX110_CLK_D_DSI_0_PATTERN_GEN) { + clockName = RKX111_CPS_DCLK_D_DSI_0_REC; + } + if (clockName == RKX110_CLK_D_DSI_1_PATTERN_GEN) { + clockName = RKX111_CPS_DCLK_D_DSI_1_REC; + } + + 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 RKX111_CPS_DCLK_D_DSI_0_REC: + case RKX111_CPS_DCLK_D_DSI_1_REC: + 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) { + pRate = (_MHZ(1200) / rate) * rate; + } + + 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: + case RKX111_CPS_DCLK_RX_PRE_200M: + /* lvds */ + case RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN: + case RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN: + /* 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; + + /* lvds0/1 rklink */ + case RKX111_CPS_CLK_D_LVDS0_RKLINK_TX: + if (rate == _MHZ(150)) { /* input clock: dclk_lvds0/1 */ + return HAL_CRU_ClkSetMux(hw, clkMux, 0); + } else { + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN, rate); + + return HAL_CRU_ClkSetMux(hw, clkMux, 1); + } + break; + + case RKX111_CPS_CLK_D_LVDS1_RKLINK_TX: + if (rate == _MHZ(150)) { /* input clock: dclk_lvds0/1 */ + return HAL_CRU_ClkSetMux(hw, clkMux, 0); + } else { + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN, rate); + + return HAL_CRU_ClkSetMux(hw, clkMux, 1); + } + break; + + case RKX111_CPS_CLK_D_DSI_0_RKLINK_TX: + if (rate == _MHZ(400)) { /* RKX110_CPS_DCLK_RX_PRE */ + return HAL_CRU_ClkSetMux(hw, clkMux, 0); + } else { + return HAL_CRU_ClkSetMux(hw, clkMux, 1); + } + break; + + case RKX111_CPS_CLK_D_DSI_1_RKLINK_TX: + if (rate == _MHZ(200)) { /* RKX111_CPS_DCLK_RX_PRE_200M */ + return HAL_CRU_ClkSetMux(hw, clkMux, 0); + } else { + return HAL_CRU_ClkSetMux(hw, clkMux, 1); + } + 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, "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(100)); + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_CLK_PMA2LINK2PCS_CM, _MHZ(200)); + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_DCLK_RX_PRE, _MHZ(400)); + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX111_CPS_DCLK_RX_PRE_200M, _MHZ(200)); + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX111_CPS_DCLK_D_DSI_0_REC, _MHZ(200)); + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX111_CPS_DCLK_D_DSI_1_REC, _MHZ(200)); + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN, _MHZ(150)); + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN, _MHZ(150)); + RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_CLK_I2S_SRC_RKLINK_TX, _MHZ(400)); + 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 +#define CAL_FREQ_EN_REG 0xf04 + +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, clk); + HAL_CRU_Write(hw, CAL_FREQ_EN_REG, 1); /* NOTE: 1: disable, 0: enable */ + HAL_CRU_Write(hw, CAL_FREQ_EN_REG, 0); + HAL_SleepMs(3); + freq = HAL_CRU_Read(hw, CAL_FREQ_REG); + HAL_CRU_Write(hw, CAL_FREQ_EN_REG, 1); + + /* 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", RKX111_CPS_DCLK_D_DSI_0_REC, mux_rxpll_cpll_24m_p), + CLK_DECLARE_INT("dclk_d_dsi_1_rec", RKX111_CPS_DCLK_D_DSI_1_REC, 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), + CLK_DECLARE_INT("dclk_rx_pre_200m", RKX111_CPS_DCLK_RX_PRE_200M, mux_rxpll_cpll_24m_p), + CLK_DECLARE_INT("clk_d_lvds0_pattern_gen", RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN, mux_rxpll_cpll_24m_p), + CLK_DECLARE_INT("clk_d_lvds1_pattern_gen", RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN, mux_rxpll_cpll_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 rkx111_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, +}; diff --git a/drivers/mfd/rkx110_x120/hal/cru_rkx111.h b/drivers/mfd/rkx110_x120/hal/cru_rkx111.h new file mode 100644 index 000000000000..fc9b493cafd6 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_rkx111.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#ifndef _CRU_RKX111_H + +#include "cru_rkx110.h" + +// RXCRU_SOFTRST_CON02(Offset:0x408) +#define RKX111_SRST_DRESETN_VICAP_CSI_LS 0x0000002E + +// RXCRU_SOFTRST_CON05(Offset:0x414) +#define RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX 0x00000056 +#define RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX 0x00000057 + +// RXCRU_SOFTRST_CON06(Offset:0x418) +#define RKX111_SRST_RESETN_D_LVDS0_PATTERN_GEN 0x00000066 +#define RKX111_SRST_RESETN_D_LVDS1_PATTERN_GEN 0x00000067 + +// RXCRU_SOFTRST_CON11(Offset:0x42C) +#define RKX111_SRST_PRESETN_LBIST_ADA_RX 0x000000B1 + +// RXCRU_GATE_CON02(Offset:0x308) +#define RKX111_DCLK_RX_PRE_200M_GATE 0x0000002D +#define RKX111_DCLK_VICAP_CSI_LS_GATE 0x0000002E + +// RXCRU_GATE_CON04(Offset:0x310) +#define RKX111_CLK_D_DSI_0_RKLINK_TX_PRE_GATE 0x00000044 +#define RKX111_CLK_D_DSI_1_RKLINK_TX_PRE_GATE 0x00000045 +#define RKX111_CLK_D_LVDS0_RKLINK_TX_GATE 0x00000047 +#define RKX111_CLK_D_LVDS0_RKLINK_TX_PRE_GATE 0x00000048 +#define RKX111_CLK_D_LVDS1_RKLINK_TX_GATE 0x00000049 +#define RKX111_CLK_D_LVDS1_RKLINK_TX_PRE_GATE 0x0000004A +#define RKX111_DCLK_D_DSI_0_REC_GATE 0x0000004D +#define RKX111_DCLK_D_DSI_1_REC_GATE 0x0000004E + +// RXCRU_GATE_CON05(Offset:0x314) +#define RKX111_DCLK_D_DSI_0_REC_RKLINK_TX_GATE 0x00000056 +#define RKX111_DCLK_D_DSI_1_REC_RKLINK_TX_GATE 0x00000057 +#define RKX111_CLK_D_DSI_0_RKLINK_TX_GATE 0x00000058 +#define RKX111_CLK_D_DSI_1_RKLINK_TX_GATE 0x00000059 + +// RXCRU_GATE_CON06(Offset:0x318) +#define RKX111_CLK_D_LVDS0_PATTERN_GEN_GATE 0x00000066 +#define RKX111_CLK_D_LVDS1_PATTERN_GEN_GATE 0x00000067 + +// RXCRU_GATE_CON11(Offset:0x32C) +#define RKX111_PCLK_LBIST_ADA_RX_GATE 0x000000B1 + +// RXCRU_CLKSEL_CON05(Offset:0x114) +#define RKX111_DCLK_D_DSI_0_REC_DIV 0x08000005 +#define RKX111_DCLK_D_DSI_0_REC_SEL 0x020E0005 +#define RKX111_DCLK_D_DSI_0_REC_SEL_CLK_RXPLL_MUX 0U +#define RKX111_DCLK_D_DSI_0_REC_SEL_CLK_CPLL_MUX 1U +#define RKX111_DCLK_D_DSI_0_REC_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON06(Offset:0x118) +#define RKX111_DCLK_D_DSI_1_REC_DIV 0x08000006 +#define RKX111_DCLK_D_DSI_1_REC_SEL 0x020E0006 +#define RKX111_DCLK_D_DSI_1_REC_SEL_CLK_RXPLL_MUX 0U +#define RKX111_DCLK_D_DSI_1_REC_SEL_CLK_CPLL_MUX 1U +#define RKX111_DCLK_D_DSI_1_REC_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON13(Offset:0x134) +#define RKX111_CLK_D_LVDS0_PATTERN_GEN_DIV 0x0800000D +#define RKX111_CLK_D_LVDS0_PATTERN_GEN_SEL 0x020E000D +#define RKX111_CLK_D_LVDS0_PATTERN_GEN_SEL_CLK_RXPLL_MUX 0U +#define RKX111_CLK_D_LVDS0_PATTERN_GEN_SEL_CLK_CPLL_MUX 1U +#define RKX111_CLK_D_LVDS0_PATTERN_GEN_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON14(Offset:0x138) +#define RKX111_CLK_D_LVDS1_PATTERN_GEN_DIV 0x0800000E +#define RKX111_CLK_D_LVDS1_PATTERN_GEN_SEL 0x020E000E +#define RKX111_CLK_D_LVDS1_PATTERN_GEN_SEL_CLK_RXPLL_MUX 0U +#define RKX111_CLK_D_LVDS1_PATTERN_GEN_SEL_CLK_CPLL_MUX 1U +#define RKX111_CLK_D_LVDS1_PATTERN_GEN_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON16(Offset:0x140) +#define RKX111_DCLK_RX_PRE_200M_DIV 0x06000010 +#define RKX111_DCLK_RX_PRE_200M_SEL 0x02060010 +#define RKX111_DCLK_RX_PRE_200M_SEL_CLK_RXPLL_MUX 0U +#define RKX111_DCLK_RX_PRE_200M_SEL_CLK_CPLL_MUX 1U +#define RKX111_DCLK_RX_PRE_200M_SEL_XIN_OSC0_FUNC 2U + +// RXCRU_CLKSEL_CON17(Offset:0x144) +#define RKX111_CLK_D_DSI_0_RKLINK_TX_SEL 0x010C0011 +#define RKX111_CLK_D_DSI_0_RKLINK_TX_SEL_CLK_D_DSI_0_RKLINK_TX_PRE 0U +#define RKX111_CLK_D_DSI_0_RKLINK_TX_SEL_CLK_D_DSI_0_PATTERN_GEN 1U +#define RKX111_CLK_D_DSI_1_RKLINK_TX_SEL 0x010D0011 +#define RKX111_CLK_D_DSI_1_RKLINK_TX_SEL_CLK_D_DSI_1_RKLINK_TX_PRE 0U +#define RKX111_CLK_D_DSI_1_RKLINK_TX_SEL_CLK_D_DSI_1_PATTERN_GEN 1U +#define RKX111_CLK_D_LVDS0_RKLINK_TX_SEL 0x010E0011 +#define RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_RKLINK_TX_PRE 0U +#define RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_PATTERN_GEN 1U +#define RKX111_CLK_D_LVDS1_RKLINK_TX_SEL 0x010F0011 +#define RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_RKLINK_TX_PRE 0U +#define RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_PATTERN_GEN 1U + +/* COMPOSITE */ +#define RKX111_CPS_DCLK_RX_PRE_200M COMPOSITE_CLK(RKX111_DCLK_RX_PRE_200M_SEL, RKX111_DCLK_RX_PRE_200M_DIV) + +/* lvds_pattern_gen => lvds_rklink */ +#define RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN COMPOSITE_CLK(RKX111_CLK_D_LVDS0_PATTERN_GEN_SEL, RKX111_CLK_D_LVDS0_PATTERN_GEN_DIV) +#define RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN COMPOSITE_CLK(RKX111_CLK_D_LVDS1_PATTERN_GEN_SEL, RKX111_CLK_D_LVDS1_PATTERN_GEN_DIV) +#define RKX111_CPS_CLK_D_LVDS0_RKLINK_TX COMPOSITE_CLK(RKX111_CLK_D_LVDS0_RKLINK_TX_SEL, 0) +#define RKX111_CPS_CLK_D_LVDS1_RKLINK_TX COMPOSITE_CLK(RKX111_CLK_D_LVDS1_RKLINK_TX_SEL, 0) + +/* dsi_rec => dsi_rklink */ +#define RKX111_CPS_DCLK_D_DSI_0_REC COMPOSITE_CLK(RKX111_DCLK_D_DSI_0_REC_SEL, RKX111_DCLK_D_DSI_0_REC_DIV) +#define RKX111_CPS_DCLK_D_DSI_1_REC COMPOSITE_CLK(RKX111_DCLK_D_DSI_1_REC_SEL, RKX111_DCLK_D_DSI_1_REC_DIV) +#define RKX111_CPS_CLK_D_DSI_0_RKLINK_TX COMPOSITE_CLK(RKX111_CLK_D_DSI_0_RKLINK_TX_SEL, 0) +#define RKX111_CPS_CLK_D_DSI_1_RKLINK_TX COMPOSITE_CLK(RKX111_CLK_D_DSI_1_RKLINK_TX_SEL, 0) + +#endif diff --git a/drivers/mfd/rkx110_x120/hal/cru_rkx120.c b/drivers/mfd/rkx110_x120/hal/cru_rkx120.c new file mode 100644 index 000000000000..07da30ba0fd4 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_rkx120.c @@ -0,0 +1,599 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#include "cru_core.h" +#include "cru_rkx120.h" + +/* + * [RKX120 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; + + 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; + + /* 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); + + /* 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 + */ + 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; + + 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) { + pRate = (_MHZ(1200) / rate) * rate; + } + + ret = RKX12x_HAL_CRU_ClkSetFreq(hw, pll, pRate); + if (ret != HAL_OK) { + return ret; + } + + /* if success, continue to set divider */ + } + break; + + /* 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); + + /* 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, "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(24)); + 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(300)); + 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 + +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, 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 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 rkx120_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, +}; diff --git a/drivers/mfd/rkx110_x120/hal/cru_rkx120.h b/drivers/mfd/rkx110_x120/hal/cru_rkx120.h new file mode 100644 index 000000000000..e27246b1b323 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_rkx120.h @@ -0,0 +1,305 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#ifndef _CRU_RKX120_H + +#include "cru_core.h" + +// ======================== TXCRU module definition START ====================== +// TXCRU_SOFTRST_CON01(Offset:0x404) +#define RKX120_SRST_PRESETN_TX_CRU 0x00000010 +#define RKX120_SRST_PRESETN_TX_GRF 0x00000011 +#define RKX120_SRST_PRESETN_TX_GPIO0 0x00000012 +#define RKX120_SRST_DRESETN_TX_GPIO0 0x00000013 +#define RKX120_SRST_PRESETN_TX_GPIO1 0x00000014 +#define RKX120_SRST_DRESETN_TX_GPIO1 0x00000015 +#define RKX120_SRST_PRESETN_TX_EFUSE 0x00000016 +#define RKX120_SRST_RESETN_TX_EFUSE 0x00000017 +#define RKX120_SRST_PRESETN_MIPI_GRF_TX0 0x0000001A +#define RKX120_SRST_PRESETN_MIPI_GRF_TX1 0x0000001B +#define RKX120_SRST_PRESETN_TX_I2C2APB 0x0000001E +#define RKX120_SRST_PRESETN_TX_I2C2APB_DEBUG 0x0000001F + +// TXCRU_SOFTRST_CON02(Offset:0x408) +#define RKX120_SRST_HRESETN_DVP_TX 0x00000020 + +// TXCRU_SOFTRST_CON03(Offset:0x40C) +#define RKX120_SRST_PRESETN_CSITX0 0x00000030 +#define RKX120_SRST_RESETN_TXBYTEHS_CSITX0 0x00000031 +#define RKX120_SRST_RESETN_TXESC_CSITX0 0x00000032 +#define RKX120_SRST_PRESETN_CSITX1 0x00000034 +#define RKX120_SRST_RESETN_TXBYTEHS_CSITX1 0x00000035 +#define RKX120_SRST_RESETN_TXESC_CSITX1 0x00000036 +#define RKX120_SRST_PRESETN_DSITX 0x00000038 + +// TXCRU_SOFTRST_CON04(Offset:0x410) +#define RKX120_SRST_PRESETN_RKLINK_RX 0x00000040 +#define RKX120_SRST_RESETN_I2S_SRC_RKLINK_RX 0x00000041 +#define RKX120_SRST_RESETN_E0_RKLINK_RX 0x00000045 +#define RKX120_SRST_IRESETN_C_CSI0 0x00000046 +#define RKX120_SRST_RESETN_E1_RKLINK_RX 0x00000049 +#define RKX120_SRST_IRESETN_C_CSI1 0x0000004A + +// TXCRU_SOFTRST_CON05(Offset:0x414) +#define RKX120_SRST_DRESETN_C_DVP 0x00000051 +#define RKX120_SRST_RESETN_LVDS0 0x0000005B +#define RKX120_SRST_RESETN_LVDS1 0x0000005D + +// TXCRU_SOFTRST_CON06(Offset:0x418) +#define RKX120_SRST_RESETN_PMA2PCS2LINK_LINK 0x00000061 +#define RKX120_SRST_RESETN_PMA2PCS2LINK_PCS0 0x00000062 +#define RKX120_SRST_RESETN_PMA2PCS2LINK_PCS1 0x00000063 +#define RKX120_SRST_PRESETN_D_DSI_PATTERN_GEN 0x00000064 +#define RKX120_SRST_PRESETN_LVDS0_PATTERN_GEN 0x00000065 +#define RKX120_SRST_PRESETN_LVDS1_PATTERN_GEN 0x00000066 +#define RKX120_SRST_DRESETN_D_DSI_PATTERN_GEN 0x00000067 +#define RKX120_SRST_RESETN_LVDS0_PATTERN_GEN 0x00000068 +#define RKX120_SRST_RESETN_LVDS1_PATTERN_GEN 0x00000069 + +// TXCRU_SOFTRST_CON07(Offset:0x41C) +#define RKX120_SRST_PRESETN_PCS0 0x00000070 +#define RKX120_SRST_RESETN_2X_PMA2PCS0 0x00000071 +#define RKX120_SRST_RESETN_LINK_PCS0 0x00000073 +#define RKX120_SRST_PRESETN_PCS0_ADA 0x00000074 +#define RKX120_SRST_RESETN_PCS0_ADA 0x00000075 + +// TXCRU_SOFTRST_CON08(Offset:0x420) +#define RKX120_SRST_PRESETN_PCS1 0x00000080 +#define RKX120_SRST_RESETN_2X_PMA2PCS1 0x00000081 +#define RKX120_SRST_RESETN_LINK_PCS1 0x00000083 +#define RKX120_SRST_PRESETN_PCS1_ADA 0x00000084 +#define RKX120_SRST_RESETN_PCS1_ADA 0x00000085 + +// TXCRU_SOFTRST_CON09(Offset:0x424) +#define RKX120_SRST_PRESETN_DVPTX 0x00000090 +#define RKX120_SRST_PRESETN_MIPITXPHY0 0x00000098 +#define RKX120_SRST_RESETN_MIPITXPHY0 0x00000099 +#define RKX120_SRST_PRESETN_MIPITXPHY1 0x0000009A +#define RKX120_SRST_RESETN_MIPITXPHY1 0x0000009B + +// TXCRU_SOFTRST_CON10(Offset:0x428) +#define RKX120_SRST_PRESETN_PWM_TX 0x000000A0 +#define RKX120_SRST_RESETN_PWM_TX 0x000000A1 + +// TXCRU_SOFTRST_CON11(Offset:0x42C) +#define RKX120_SRST_PRESETN_DFT2APB 0x000000B0 + +// TXCRU_GATE_CON00(Offset:0x300) +#define RKX120_CLK_TESTOUT_TOP_GATE 0x00000000 +#define RKX120_BUSCLK_TX_PRE0_GATE 0x00000001 +#define RKX120_BUSCLK_TX_PRE_GATE 0x00000002 + +// TXCRU_GATE_CON01(Offset:0x304) +#define RKX120_PCLK_TX_CRU_GATE 0x00000010 +#define RKX120_PCLK_TX_GRF_GATE 0x00000011 +#define RKX120_PCLK_TX_GPIO0_GATE 0x00000012 +#define RKX120_DCLK_TX_GPIO0_GATE 0x00000013 +#define RKX120_PCLK_TX_GPIO1_GATE 0x00000014 +#define RKX120_DCLK_TX_GPIO1_GATE 0x00000015 +#define RKX120_PCLK_TX_EFUSE_GATE 0x00000016 +#define RKX120_CLK_TX_EFUSE_GATE 0x00000017 +#define RKX120_PCLK_MIPI_GRF_TX0_GATE 0x0000001A +#define RKX120_PCLK_MIPI_GRF_TX1_GATE 0x0000001B +#define RKX120_PCLK_TX_I2C2APB_GATE 0x0000001E +#define RKX120_PCLK_TX_I2C2APB_DEBUG_GATE 0x0000001F + +// TXCRU_GATE_CON02(Offset:0x308) +#define RKX120_HCLK_DVP_TX_GATE 0x00000020 + +// TXCRU_GATE_CON03(Offset:0x30C) +#define RKX120_PCLK_CSITX0_GATE 0x00000030 +#define RKX120_CLK_TXBYTEHS_DSITX_CSITX0_DFT_GATE 0x00000031 +#define RKX120_CLK_TXESC_CSITX0_GATE 0x00000032 +#define RKX120_PCLK_CSITX1_GATE 0x00000034 +#define RKX120_CLK_TXBYTEHS_CSITX1_DFT_GATE 0x00000035 +#define RKX120_CLK_TXESC_CSITX1_GATE 0x00000036 +#define RKX120_PCLK_DSITX_GATE 0x00000038 +#define RKX120_CLK_RXESC_DSITX_DFT_GATE 0x0000003A + +// TXCRU_GATE_CON04(Offset:0x310) +#define RKX120_PCLK_RKLINK_RX_GATE 0x00000040 +#define RKX120_CLK_I2S_SRC_RKLINK_RX_GATE 0x00000041 +#define RKX120_E0_CLK_RKLINK_RX_PRE_GATE 0x00000044 +#define RKX120_E0_CLK_RKLINK_RX_GATE 0x00000045 +#define RKX120_ICLK_C_CSI0_GATE 0x00000046 +#define RKX120_E1_CLK_RKLINK_RX_PRE_GATE 0x00000048 +#define RKX120_E1_CLK_RKLINK_RX_GATE 0x00000049 +#define RKX120_ICLK_C_CSI1_GATE 0x0000004A + +// TXCRU_GATE_CON05(Offset:0x314) +#define RKX120_DCLK_RGB_GATE 0x00000050 +#define RKX120_DCLK_C_DVP_GATE 0x00000051 +#define RKX120_DCLK_D_DSI_CM_GATE 0x00000058 +#define RKX120_DCLK_D_DSI_GATE 0x00000059 +#define RKX120_CLK_LVDS0_CM_GATE 0x0000005A +#define RKX120_CLK_LVDS0_GATE 0x0000005B +#define RKX120_CLK_LVDS1_CM_GATE 0x0000005C +#define RKX120_CLK_LVDS1_GATE 0x0000005D + +// TXCRU_GATE_CON06(Offset:0x318) +#define RKX120_CLK_PMA2PCS2LINK_CM_GATE 0x00000060 +#define RKX120_CLK_PMA2PCS2LINK_LINK_GATE 0x00000061 +#define RKX120_CLK_PMA2PCS2LINK_PCS0_GATE 0x00000062 +#define RKX120_CLK_PMA2PCS2LINK_PCS1_GATE 0x00000063 +#define RKX120_PCLK_D_DSI_PATTERN_GEN_GATE 0x00000064 +#define RKX120_PCLK_LVDS0_PATTERN_GEN_GATE 0x00000065 +#define RKX120_PCLK_LVDS1_PATTERN_GEN_GATE 0x00000066 +#define RKX120_DCLK_D_DSI_PATTERN_GEN_GATE 0x00000067 +#define RKX120_CLK_LVDS0_PATTERN_GEN_GATE 0x00000068 +#define RKX120_CLK_LVDS1_PATTERN_GEN_GATE 0x00000069 + +// TXCRU_GATE_CON07(Offset:0x31C) +#define RKX120_PCLK_PCS0_GATE 0x00000070 +#define RKX120_CLK_2X_PMA2PCS0_DFT_GATE 0x00000071 +#define RKX120_CLK_LINK_PCS0_DFT_GATE 0x00000072 +#define RKX120_CLK_LINK_PCS0_GATE 0x00000073 +#define RKX120_PCLK_PCS0_ADA_GATE 0x00000074 +#define RKX120_CLK_PCS0_ADA_GATE 0x00000075 + +// TXCRU_GATE_CON08(Offset:0x320) +#define RKX120_PCLK_PCS1_GATE 0x00000080 +#define RKX120_CLK_2X_PMA2PCS1_DFT_GATE 0x00000081 +#define RKX120_CLK_LINK_PCS1_DFT_GATE 0x00000082 +#define RKX120_CLK_LINK_PCS1_GATE 0x00000083 +#define RKX120_PCLK_PCS1_ADA_GATE 0x00000084 +#define RKX120_CLK_PCS1_ADA_GATE 0x00000085 + +// TXCRU_GATE_CON09(Offset:0x324) +#define RKX120_PCLKOUT_DVPTX_GATE 0x00000090 +#define RKX120_PCLK_MIPITXPHY0_GATE 0x00000098 +#define RKX120_PCLK_MIPITXPHY1_GATE 0x0000009A + +// TXCRU_GATE_CON10(Offset:0x328) +#define RKX120_PCLK_PWM_TX_GATE 0x000000A0 +#define RKX120_CLK_PWM_TX_GATE 0x000000A1 +#define RKX120_CLK_CAPTURE_PWM_TX_GATE 0x000000A2 +#define RKX120_CLK_TXESC_MIPITXPHY0_GATE 0x000000A8 + +// TXCRU_GATE_CON11(Offset:0x32C) +#define RKX120_PCLK_DFT2APB_GATE 0x000000B0 + +// TXCRU_CLKSEL_CON00(Offset:0x100) +#define RKX120_TEST_CLKOUT_IOUT_DIV 0x08000000 +#define RKX120_TEST_CLKOUT_IOUT_SEL 0x05080000 +#define RKX120_TEST_CLKOUT_IOUT_SEL_XIN_OSC0_FUNC 0U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_TXPLL_MUX 1U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_CPLL_MUX 2U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_TXBYTEHS_CSITX0 3U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_TXESC_CSITX0 4U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_TXBYTEHS_CSITX1 5U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_TXESC_CSITX1 6U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_TXBYTEHS_DSITX 7U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_RXESC_DSITX 8U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_LINK_PCS0 9U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_LINK_PCS1 10U +#define RKX120_TEST_CLKOUT_IOUT_SEL_TESTCLK_PMARX0_PIXEL 11U +#define RKX120_TEST_CLKOUT_IOUT_SEL_TESTCLK_PMARX1_PIXEL 12U +#define RKX120_TEST_CLKOUT_IOUT_SEL_TESTCLK_MIPITXPHY0_LVDS 13U +#define RKX120_TEST_CLKOUT_IOUT_SEL_TESTCLK_MIPITXPHY0_PIXEL 14U +#define RKX120_TEST_CLKOUT_IOUT_SEL_TESTCLK_MIPITXPHY1_LVDS 15U +#define RKX120_TEST_CLKOUT_IOUT_SEL_TESTCLK_MIPITXPHY1_PIXEL 16U +#define RKX120_TEST_CLKOUT_IOUT_SEL_BUSCLK_TX_PRE 17U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_I2S_SRC_RKLINK_RX 20U +#define RKX120_TEST_CLKOUT_IOUT_SEL_E0_CLK_RKLINK_RX_PRE 21U +#define RKX120_TEST_CLKOUT_IOUT_SEL_PCLKOUT_DVPTX 22U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_TXBYTEHS_DSITX_CSITX0 23U +#define RKX120_TEST_CLKOUT_IOUT_SEL_DCLK_C_DVP_SRC 24U +#define RKX120_TEST_CLKOUT_IOUT_SEL_DCLK_D_DSI_SRC 25U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_LVDS0_SRC 26U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_LVDS1_SRC 27U +#define RKX120_TEST_CLKOUT_IOUT_SEL_DCLK_RGB_SRC 28U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_2X_PMA2PCS0 29U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_2X_PMA2PCS1 30U +#define RKX120_TEST_CLKOUT_IOUT_SEL_CLK_TXESC_MIPITXPHY0 31U + +// TXCRU_CLKSEL_CON01(Offset:0x104) +#define RKX120_BUSCLK_TX_PRE0_DIV 0x06000001 +#define RKX120_BUSCLK_TX_PRE0_SEL 0x01070001 +#define RKX120_BUSCLK_TX_PRE0_SEL_CLK_TXPLL_MUX 0U +#define RKX120_BUSCLK_TX_PRE0_SEL_CLK_CPLL_MUX 1U +#define RKX120_BUSCLK_TX_PRE_SEL 0x01080001 +#define RKX120_BUSCLK_TX_PRE_SEL_XIN_OSC0_FUNC 0U +#define RKX120_BUSCLK_TX_PRE_SEL_BUSCLK_TX_PRE0 1U + +// TXCRU_CLKSEL_CON03(Offset:0x10C) +#define RKX120_CLK_TXESC_CSITX0_DIV 0x08000003 +#define RKX120_CLK_TXESC_CSITX0_SEL 0x020E0003 +#define RKX120_CLK_TXESC_CSITX0_SEL_CLK_TXPLL_MUX 0U +#define RKX120_CLK_TXESC_CSITX0_SEL_CLK_CPLL_MUX 1U +#define RKX120_CLK_TXESC_CSITX0_SEL_XIN_OSC0_FUNC 2U + +// TXCRU_CLKSEL_CON04(Offset:0x110) +#define RKX120_CLK_TXESC_CSITX1_DIV 0x08000004 +#define RKX120_CLK_TXESC_CSITX1_SEL 0x020E0004 +#define RKX120_CLK_TXESC_CSITX1_SEL_CLK_TXPLL_MUX 0U +#define RKX120_CLK_TXESC_CSITX1_SEL_CLK_CPLL_MUX 1U +#define RKX120_CLK_TXESC_CSITX1_SEL_XIN_OSC0_FUNC 2U + +// TXCRU_CLKSEL_CON05(Offset:0x114) +#define RKX120_CLK_I2S_SRC_RKLINK_RX_DIV 0x08000005 +#define RKX120_CLK_I2S_SRC_RKLINK_RX_SEL 0x020E0005 +#define RKX120_CLK_I2S_SRC_RKLINK_RX_SEL_CLK_TXPLL_MUX 0U +#define RKX120_CLK_I2S_SRC_RKLINK_RX_SEL_CLK_CPLL_MUX 1U +#define RKX120_CLK_I2S_SRC_RKLINK_RX_SEL_XIN_OSC0_FUNC 2U + +// TXCRU_CLKSEL_CON06(Offset:0x118) +#define RKX120_E0_CLK_RKLINK_RX_PRE_DIV 0x08000006 +#define RKX120_E0_CLK_RKLINK_RX_PRE_SEL 0x020E0006 +#define RKX120_E0_CLK_RKLINK_RX_PRE_SEL_CLK_TXPLL_MUX 0U +#define RKX120_E0_CLK_RKLINK_RX_PRE_SEL_CLK_CPLL_MUX 1U +#define RKX120_E0_CLK_RKLINK_RX_PRE_SEL_XIN_OSC0_FUNC 2U + +// TXCRU_CLKSEL_CON07(Offset:0x11C) +#define RKX120_E1_CLK_RKLINK_RX_PRE_DIV 0x08000007 +#define RKX120_E1_CLK_RKLINK_RX_PRE_SEL 0x020E0007 +#define RKX120_E1_CLK_RKLINK_RX_PRE_SEL_CLK_TXPLL_MUX 0U +#define RKX120_E1_CLK_RKLINK_RX_PRE_SEL_CLK_CPLL_MUX 1U +#define RKX120_E1_CLK_RKLINK_RX_PRE_SEL_XIN_OSC0_FUNC 2U + +// TXCRU_CLKSEL_CON08(Offset:0x120) +#define RKX120_CLK_PMA2PCS2LINK_CM_SEL 0x01000008 +#define RKX120_CLK_PMA2PCS2LINK_CM_SEL_CLK_LINK_PCS0_DFT 0U +#define RKX120_CLK_PMA2PCS2LINK_CM_SEL_CLK_LINK_PCS1_DFT 1U + +// TXCRU_CLKSEL_CON10(Offset:0x128) +#define RKX120_CLK_PWM_TX_DIV 0x0800000A +#define RKX120_CLK_PWM_TX_SEL 0x020E000A +#define RKX120_CLK_PWM_TX_SEL_CLK_TXPLL_MUX 0U +#define RKX120_CLK_PWM_TX_SEL_CLK_CPLL_MUX 1U +#define RKX120_CLK_PWM_TX_SEL_XIN_OSC0_FUNC 2U + +// TXCRU_CLKSEL_CON12(Offset:0x130) +#define RKX120_PCLKOUT_DVPTX_DIV 0x0800000C +#define RKX120_PCLKOUT_DVPTX_SEL 0x020E000C +#define RKX120_PCLKOUT_DVPTX_SEL_CLK_TXPLL_MUX 0U +#define RKX120_PCLKOUT_DVPTX_SEL_CLK_CPLL_MUX 1U +#define RKX120_PCLKOUT_DVPTX_SEL_XIN_OSC0_FUNC 2U + +// ======================== TXCRU module definition END ======================== +#define RKX120_CPS_INVAL 0 +#define RKX120_CPS_PLL_CPLL 1 +#define RKX120_CPS_PLL_TXPLL 2 +#define RKX120_CPS_DCLK_TX_GPIO0 3 +#define RKX120_CPS_DCLK_TX_GPIO1 4 +#define RKX120_CPS_CLK_TX_EFUSE 5 +#define RKX120_CPS_CLK_PCS0_ADA 6 +#define RKX120_CPS_CLK_PCS1_ADA 7 +#define RKX120_CPS_CLK_CAPTURE_PWM_TX 8 +#define RKX120_CPS_ICLK_C_CSI0 9 +#define RKX120_CPS_ICLK_C_CSI1 10 +#define RKX120_CPS_CLK_TXESC_CSITX0 COMPOSITE_CLK(RKX120_CLK_TXESC_CSITX0_SEL, RKX120_CLK_TXESC_CSITX0_DIV) +#define RKX120_CPS_CLK_TXESC_CSITX1 COMPOSITE_CLK(RKX120_CLK_TXESC_CSITX1_SEL, RKX120_CLK_TXESC_CSITX1_DIV) +#define RKX120_CPS_CLK_I2S_SRC_RKLINK_RX COMPOSITE_CLK(RKX120_CLK_I2S_SRC_RKLINK_RX_SEL, RKX120_CLK_I2S_SRC_RKLINK_RX_DIV) +#define RKX120_CPS_E0_CLK_RKLINK_RX_PRE COMPOSITE_CLK(RKX120_E0_CLK_RKLINK_RX_PRE_SEL, RKX120_E0_CLK_RKLINK_RX_PRE_DIV) +#define RKX120_CPS_E1_CLK_RKLINK_RX_PRE COMPOSITE_CLK(RKX120_E1_CLK_RKLINK_RX_PRE_SEL, RKX120_E1_CLK_RKLINK_RX_PRE_DIV) +#define RKX120_CPS_CLK_PMA2PCS2LINK_CM COMPOSITE_CLK(RKX120_CLK_PMA2PCS2LINK_CM_SEL, 0) +#define RKX120_CPS_PCLKOUT_DVPTX COMPOSITE_CLK(RKX120_PCLKOUT_DVPTX_SEL, RKX120_PCLKOUT_DVPTX_DIV) +#define RKX120_CPS_CLK_PWM_TX COMPOSITE_CLK(RKX120_CLK_PWM_TX_SEL, RKX120_CLK_PWM_TX_DIV) +#define RKX120_CPS_BUSCLK_TX_PRE0 COMPOSITE_CLK(RKX120_BUSCLK_TX_PRE0_SEL, RKX120_BUSCLK_TX_PRE0_DIV) +#define RKX120_CPS_BUSCLK_TX_PRE COMPOSITE_CLK(RKX120_BUSCLK_TX_PRE_SEL, 0) +#define RKX120_CPS_TEST_CLKOUT COMPOSITE_CLK(RKX120_TEST_CLKOUT_IOUT_SEL, RKX120_TEST_CLKOUT_IOUT_DIV) +#endif diff --git a/drivers/mfd/rkx110_x120/hal/cru_rkx121.c b/drivers/mfd/rkx110_x120/hal/cru_rkx121.c new file mode 100644 index 000000000000..350ce6c47f48 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_rkx121.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#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; + + 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) { + pRate = (_MHZ(1200) / rate) * rate; + } + + 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, "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, +}; diff --git a/drivers/mfd/rkx110_x120/hal/cru_rkx121.h b/drivers/mfd/rkx110_x120/hal/cru_rkx121.h new file mode 100644 index 000000000000..96cd659b13cd --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/cru_rkx121.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#ifndef _CRU_RKX121_H + +#include "cru_rkx120.h" + +// TXCRU_SOFTRST_CON06(Offset:0x418) +#define RKX121_SRST_DRESETN_C_LVDS_TX 0x0000006A +#define RKX121_SRST_LVDS_RESETN_C_LVDS_TX 0x0000006B +#define RKX121_SRST_PRESETN_C_LVDS_TX 0x0000006C + +// TXCRU_SOFTRST_CON11(Offset:0x42C) +#define RKX121_SRST_PRESETN_LBIST_ADA_TX 0x000000B1 + +// TXCRU_GATE_CON06(Offset:0x318) +#define RKX121_DCLK_C_LVDS_TX_GATE 0x0000006A +#define RKX121_CLK_LVDS_C_LVDS_TX_GATE 0x0000006B +#define RKX121_PCLK_C_LVDS_TX_GATE 0x0000006C + +// TXCRU_GATE_CON11(Offset:0x32C) +#define RKX121_PCLK_LBIST_ADA_TX_GATE 0x000000B1 + +// TXCRU_CLKSEL_CON08(Offset:0x120) +#define RKX121_CLK_LVDS1_SEL 0x01010008 +#define RKX121_CLK_LVDS1_SEL_CLK_LVDS1_CM 0U +#define RKX121_CLK_LVDS1_SEL_CLK_LVDS_C_LVDS_TX 1U +#define RKX121_CLK_LVDS0_SEL 0x01020008 +#define RKX121_CLK_LVDS0_SEL_CLK_LVDS0_CM 0U +#define RKX121_CLK_LVDS0_SEL_CLK_LVDS_C_LVDS_TX 1U + +// TXCRU_CLKSEL_CON09(Offset:0x124) +#define RKX121_CLK_LVDS_C_LVDS_TX_DIV 0x08000009 +#define RKX121_CLK_LVDS_C_LVDS_TX_SEL 0x020E0009 +#define RKX121_CLK_LVDS_C_LVDS_TX_SEL_CLK_TXPLL_MUX 0U +#define RKX121_CLK_LVDS_C_LVDS_TX_SEL_CLK_CPLL_MUX 1U +#define RKX121_CLK_LVDS_C_LVDS_TX_SEL_XIN_OSC0_FUNC 2U + +/* COMPOSITE */ +#define RKX121_CPS_CLK_LVDS_C_LVDS_TX COMPOSITE_CLK(RKX121_CLK_LVDS_C_LVDS_TX_SEL, RKX121_CLK_LVDS_C_LVDS_TX_DIV) +#define RKX121_CPS_CLK_LVDS0 COMPOSITE_CLK(RKX121_CLK_LVDS0_SEL, 0) +#define RKX121_CPS_CLK_LVDS1 COMPOSITE_CLK(RKX121_CLK_LVDS1_SEL, 0) + +#endif diff --git a/drivers/mfd/rkx110_x120/hal/hal_def.h b/drivers/mfd/rkx110_x120/hal/hal_def.h new file mode 100644 index 000000000000..12cfbed5c2d8 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/hal_def.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Steven Liu + */ + +#ifndef _HAL_DEF_H_ +#define _HAL_DEF_H_ + +#include "hal_os_def.h" + +#define HAL_LOGLEVEL 3 + +#define __hal_print(level, fmt, ...) \ +({ \ + level < HAL_LOGLEVEL ? HAL_SYSLOG("[HAL] " fmt, ##__VA_ARGS__) : 0; \ +}) +#define HAL_ERR(fmt, ...) __hal_print(0, "ERROR: " fmt, ##__VA_ARGS__) +#define HAL_WARN(fmt, ...) __hal_print(1, "WARN: " fmt, ##__VA_ARGS__) +#define HAL_MSG(fmt, ...) __hal_print(2, fmt, ##__VA_ARGS__) +#define HAL_DBG(fmt, ...) __hal_print(3, fmt, ##__VA_ARGS__) + +#define HAL_NULL ((void *)0) +#define HAL_BIT(nr) (1UL << (nr)) + +/***************************** Structure Definition **************************/ +/** HAL boolean type definition */ +typedef enum { + HAL_FALSE = 0x00U, + HAL_TRUE = 0x01U +} HAL_Check; + +/** HAL error code definition */ +typedef enum { + HAL_OK = 0x00U, + HAL_ERROR = (-1), + HAL_NOMEM = (-12), + HAL_BUSY = (-16), + HAL_NODEV = (-19), + HAL_INVAL = (-22), + HAL_NOSYS = (-38), + HAL_TIMEOUT = (-110) +} HAL_Status; + +/** HAL functional status definition */ +typedef enum { + HAL_DISABLE = 0x00U, + HAL_ENABLE = 0x01U +} HAL_FuncStatus; + +/** HAL lock structures definition */ +typedef enum { + HAL_UNLOCKED = 0x00U, + HAL_LOCKED = 0x01U +} HAL_LockStatus; + +#endif /* _HAL_DEF_H_ */ diff --git a/drivers/mfd/rkx110_x120/hal/hal_os_def.h b/drivers/mfd/rkx110_x120/hal/hal_os_def.h new file mode 100644 index 000000000000..c93a28becddb --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/hal_os_def.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Joseph Chen + */ + +#ifndef _HAL_OS_DEF_H_ +#define _HAL_OS_DEF_H_ + +#include +#include +#include +#include + +#define HAL_BITS_PER_LONG BITS_PER_LONG +#define HAL_SYSLOG pr_info +#define HAL_DelayUs udelay +#define HAL_SleepMs msleep +#define HAL_ARRAY_SIZE ARRAY_SIZE + +#define HAL_DEFINE_MUTEX DEFINE_MUTEX +#define HAL_Mutex struct mutex +#define HAL_MutexInit mutex_init +#define HAL_MutexLock mutex_lock +#define HAL_MutexUnlock mutex_unlock + +#define HAL_KCALLOC(n, size) kcalloc(n, size, GFP_KERNEL) + +typedef int (HAL_RegRead_t)(struct i2c_client *client, uint32_t addr, uint32_t *value); +typedef int (HAL_RegWrite_t)(struct i2c_client *client, uint32_t addr, uint32_t value); + +#endif /* _HAL_OS_DEF_H_ */ diff --git a/drivers/mfd/rkx110_x120/hal/pinctrl_api.h b/drivers/mfd/rkx110_x120/hal/pinctrl_api.h new file mode 100644 index 000000000000..9a15c8c057b3 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/pinctrl_api.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Steven Liu + */ + +#ifndef _PINCTRL_API_H_ +#define _PINCTRL_API_H_ + +#include "hal_def.h" +#include "hal_os_def.h" +#include "pinctrl_rkx110_x120.h" + +static inline int hwpin_set(struct xferpin xfer) +{ + struct hwpin hw; + int ret; + + if (!xfer.read || !xfer.write || !xfer.client || !xfer.name[0]) { + return HAL_ERROR; + } + + if (xfer.type == PIN_UNDEF || xfer.type >= PIN_MAX) { + return HAL_INVAL; + } + + memset(&hw, 0, sizeof(hw)); + hw.type = xfer.type; + hw.xfer = xfer; + hw.bank = xfer.bank; + hw.mpins = xfer.mpins; + hw.param = xfer.param; + + ret = HAL_PINCTRL_SetParam(&hw, hw.mpins, hw.param); + + return ret; +} + +static inline int hwpin_init(void) +{ + return HAL_PINCTRL_Init(); +} + +#endif diff --git a/drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.c b/drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.c new file mode 100644 index 000000000000..1709e41c00ce --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.c @@ -0,0 +1,612 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Steven Liu + */ + +#include "pinctrl_rkx110_x120.h" + +/********************* Private MACRO Definition ******************************/ + +#define _PINCTRL_GENMASK(w) ((1U << (w)) - 1U) +#define _PINCTRL_OFFSET(gp, w) ((gp) * (w)) +#define _PINCTRL_GENVAL(gp, v, w) ((_PINCTRL_GENMASK(w) << (_PINCTRL_OFFSET(gp, w) + 16)) \ + | (((v) & _PINCTRL_GENMASK(w)) << _PINCTRL_OFFSET(gp, w))) + +#define RKX110_GRF_BASE 0x00010000U +#define RKX120_GRF_BASE 0x01010000U + +#define RKX110_GRF_REG(x) ((x) + RKX110_GRF_BASE) +#define RKX120_GRF_REG(x) ((x) + RKX120_GRF_BASE) + +/************************** SER_GRF Register Define ***************************/ +#define RKX110_GRF_GPIO0A_IOMUX_L RKX110_GRF_REG(0x0000) +#define RKX110_GRF_GPIO0A_IOMUX_H RKX110_GRF_REG(0x0004) +#define RKX110_GRF_GPIO0B_IOMUX_L RKX110_GRF_REG(0x0008) +#define RKX110_GRF_GPIO0B_IOMUX_H RKX110_GRF_REG(0x000c) +#define RKX110_GRF_GPIO0C_IOMUX_L RKX110_GRF_REG(0x0010) +#define RKX110_GRF_GPIO0C_IOMUX_H RKX110_GRF_REG(0x0014) + +#define RKX110_GRF_GPIO0A_P RKX110_GRF_REG(0x0020) +#define RKX110_GRF_GPIO0B_P RKX110_GRF_REG(0x0024) +#define RKX110_GRF_GPIO0C_P RKX110_GRF_REG(0x0028) + +#define RKX110_GRF_GPIO1A_IOMUX RKX110_GRF_REG(0x0080) +#define RKX110_GRF_GPIO1B_IOMUX RKX110_GRF_REG(0x0084) +#define RKX110_GRF_GPIO1C_IOMUX RKX110_GRF_REG(0x0088) + +#define RKX110_GRF_GPIO1A_P RKX110_GRF_REG(0x0090) +#define RKX110_GRF_GPIO1B_P RKX110_GRF_REG(0x0094) +#define RKX110_GRF_GPIO1C_P RKX110_GRF_REG(0x0098) + +#define RKX110_GRF_GPIO1A_SMT RKX110_GRF_REG(0x00A0) +#define RKX110_GRF_GPIO1B_SMT RKX110_GRF_REG(0x00A4) +#define RKX110_GRF_GPIO1C_SMT RKX110_GRF_REG(0x00A8) + +#define RKX110_GRF_GPIO1A_E RKX110_GRF_REG(0x00B0) +#define RKX110_GRF_GPIO1B_E RKX110_GRF_REG(0x00B4) +#define RKX110_GRF_GPIO1C_E RKX110_GRF_REG(0x00B8) + +#define RKX110_GRF_GPIO1A_IE RKX110_GRF_REG(0x00C0) +#define RKX110_GRF_GPIO1B_IE RKX110_GRF_REG(0x00C4) +#define RKX110_GRF_GPIO1C_IE RKX110_GRF_REG(0x00C8) + +/************************** DES_GRF Register Define ***************************/ +#define RKX120_GRF_GPIO0A_IOMUX_L RKX120_GRF_REG(0x0000) +#define RKX120_GRF_GPIO0A_IOMUX_H RKX120_GRF_REG(0x0004) +#define RKX120_GRF_GPIO0B_IOMUX_L RKX120_GRF_REG(0x0008) +#define RKX120_GRF_GPIO0B_IOMUX_H RKX120_GRF_REG(0x000C) +#define RKX120_GRF_GPIO0C_IOMUX_L RKX120_GRF_REG(0x0010) +#define RKX120_GRF_GPIO0C_IOMUX_H RKX120_GRF_REG(0x0014) + +#define RKX120_GRF_GPIO0A_P RKX120_GRF_REG(0x0020) +#define RKX120_GRF_GPIO0B_P RKX120_GRF_REG(0x0024) +#define RKX120_GRF_GPIO0C_P RKX120_GRF_REG(0x0028) + +#define RKX120_GRF_GPIO1A_IOMUX RKX120_GRF_REG(0x0080) +#define RKX120_GRF_GPIO1B_IOMUX RKX120_GRF_REG(0x0084) +#define RKX120_GRF_GPIO1C_IOMUX RKX120_GRF_REG(0x0088) + +#define RKX120_GRF_GPIO1A_P RKX120_GRF_REG(0x0090) +#define RKX120_GRF_GPIO1B_P RKX120_GRF_REG(0x0094) +#define RKX120_GRF_GPIO1C_P RKX120_GRF_REG(0x0098) + +#define RKX120_GRF_GPIO1A_SMT RKX120_GRF_REG(0x00A0) +#define RKX120_GRF_GPIO1B_SMT RKX120_GRF_REG(0x00A4) +#define RKX120_GRF_GPIO1C_SMT RKX120_GRF_REG(0x00A8) + +#define RKX120_GRF_GPIO1A_E RKX120_GRF_REG(0x00B0) +#define RKX120_GRF_GPIO1B_E RKX120_GRF_REG(0x00B4) +#define RKX120_GRF_GPIO1C_E RKX120_GRF_REG(0x00B8) + +#define RKX120_GRF_GPIO1A_IE RKX120_GRF_REG(0x00C0) +#define RKX120_GRF_GPIO1B_IE RKX120_GRF_REG(0x00C4) +#define RKX120_GRF_GPIO1C_IE RKX120_GRF_REG(0x00C8) + +#define IOMUX_3_BIT_PER_PIN (3) +#define IOMUX_PER_REG (8) +#define RKX110_IOMUX_L(__B, __G) (RKX110_GRF_GPIO##__B##__G##_IOMUX_L) +#define RKX110_IOMUX_H(__B, __G) (RKX110_GRF_GPIO##__B##__G##_IOMUX_H) +#define RKX110_SET_IOMUX_L(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX110_IOMUX_L(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} +#define RKX110_SET_IOMUX_H(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX110_IOMUX_H(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} +#define HAL_RKX110_SET_IOMUX_L(HW, B, G, BP, V) \ + RKX110_SET_IOMUX_L(HW, B, G, BP % IOMUX_PER_REG, V, IOMUX_3_BIT_PER_PIN) +#define HAL_RKX110_SET_IOMUX_H(HW, B, G, BP, V) \ + RKX110_SET_IOMUX_H(HW, B, G, (BP % IOMUX_PER_REG - 5), V, IOMUX_3_BIT_PER_PIN) + +#define RKX120_IOMUX_L(__B, __G) (RKX120_GRF_GPIO##__B##__G##_IOMUX_L) +#define RKX120_IOMUX_H(__B, __G) (RKX120_GRF_GPIO##__B##__G##_IOMUX_H) +#define RKX120_SET_IOMUX_L(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX120_IOMUX_L(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} +#define RKX120_SET_IOMUX_H(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX120_IOMUX_H(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} +#define HAL_RKX120_SET_IOMUX_L(HW, B, G, BP, V) \ + RKX120_SET_IOMUX_L(HW, B, G, BP % IOMUX_PER_REG, V, IOMUX_3_BIT_PER_PIN) +#define HAL_RKX120_SET_IOMUX_H(HW, B, G, BP, V) \ + RKX120_SET_IOMUX_H(HW, B, G, (BP % IOMUX_PER_REG - 5), V, IOMUX_3_BIT_PER_PIN) + +#define IOMUX_2_BIT_PER_PIN (2) +#define IOMUX_8_PIN_PER_REG (8) +#define RKX110_IOMUX_0(__B, __G) (RKX110_GRF_GPIO##__B##__G##_IOMUX) + +#define RKX110_SET_IOMUX_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX110_IOMUX_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX110_SET_IOMUX_0(HW, B, G, BP, V) \ + RKX110_SET_IOMUX_0(HW, B, G, BP % IOMUX_8_PIN_PER_REG, V, IOMUX_2_BIT_PER_PIN) + +#define RKX120_IOMUX_0(__B, __G) (RKX120_GRF_GPIO##__B##__G##_IOMUX) + +#define RKX120_SET_IOMUX_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX120_IOMUX_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX120_SET_IOMUX_0(HW, B, G, BP, V) \ + RKX120_SET_IOMUX_0(HW, B, G, BP % IOMUX_8_PIN_PER_REG, V, IOMUX_2_BIT_PER_PIN) + +#define PULL_2_BIT_PER_PIN (2) +#define PULL_8_PIN_PER_REG (8) +#define RKX110_PULL_0(__B, __G) (RKX110_GRF_GPIO##__B##__G##_P) + +#define RKX110_SET_PULL_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX110_PULL_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX110_SET_PULL_0(HW, B, G, BP, V) \ + RKX110_SET_PULL_0(HW, B, G, BP % PULL_8_PIN_PER_REG, V, PULL_2_BIT_PER_PIN) + +#define RKX120_PULL_0(__B, __G) (RKX120_GRF_GPIO##__B##__G##_P) + +#define RKX120_SET_PULL_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX120_PULL_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX120_SET_PULL_0(HW, B, G, BP, V) \ + RKX120_SET_PULL_0(HW, B, G, BP % PULL_8_PIN_PER_REG, V, PULL_2_BIT_PER_PIN) + +#define PULLEN_1_BIT_PER_PIN (1) +#define PULLEN_8_PIN_PER_REG (8) +#define RKX110_PULLEN_0(__B, __G) (RKX110_GRF_GPIO##__B##__G##_P) + +#define RKX110_SET_PULLEN_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX110_PULLEN_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX110_SET_PULLEN_0(HW, B, G, BP, V) \ + RKX110_SET_PULLEN_0(HW, B, G, BP % PULLEN_8_PIN_PER_REG, V, PULLEN_1_BIT_PER_PIN) + +#define RKX120_PULLEN_0(__B, __G) (RKX120_GRF_GPIO##__B##__G##_P) + +#define RKX120_SET_PULLEN_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX120_PULLEN_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX120_SET_PULLEN_0(HW, B, G, BP, V) \ + RKX120_SET_PULLEN_0(HW, B, G, BP % PULLEN_8_PIN_PER_REG, V, PULLEN_1_BIT_PER_PIN) + +#define DRV_2_BIT_PER_PIN (2) +#define DRV_8_PIN_PER_REG (8) +#define RKX110_DRV_0(__B, __G) (RKX110_GRF_GPIO##__B##__G##_E) + +#define RKX110_SET_DRV_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX110_DRV_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX110_SET_DRV_0(HW, B, G, BP, V) \ + RKX110_SET_DRV_0(HW, B, G, BP % DRV_8_PIN_PER_REG, V, DRV_2_BIT_PER_PIN) + +#define RKX120_DRV_0(__B, __G) (RKX120_GRF_GPIO##__B##__G##_E) + +#define RKX120_SET_DRV_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX120_DRV_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX120_SET_DRV_0(HW, B, G, BP, V) \ + RKX120_SET_DRV_0(HW, B, G, BP % DRV_8_PIN_PER_REG, V, DRV_2_BIT_PER_PIN) + +#define SMT_1_BIT_PER_PIN (1) +#define SMT_8_PIN_PER_REG (8) +#define RKX110_SMT_0(__B, __G) (RKX110_GRF_GPIO##__B##__G##_SMT) + +#define RKX110_SET_SMT_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX110_SMT_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX110_SET_SMT_0(HW, B, G, BP, V) \ + RKX110_SET_SMT_0(HW, B, G, BP % SMT_8_PIN_PER_REG, V, SMT_1_BIT_PER_PIN) + +#define RKX120_SMT_0(__B, __G) (RKX120_GRF_GPIO##__B##__G##_SMT) + +#define RKX120_SET_SMT_0(_HW, _B, _G, _GP, _V, _W) \ +{ \ + HAL_PINCTRL_Write(_HW, RKX120_SMT_0(_B, _G), _PINCTRL_GENVAL(_GP, _V, _W)); \ +} + +#define HAL_RKX120_SET_SMT_0(HW, B, G, BP, V) \ + RKX120_SET_SMT_0(HW, B, G, BP % SMT_8_PIN_PER_REG, V, SMT_1_BIT_PER_PIN) + +/********************* Private Function Definition ***************************/ + +static HAL_Status RKX110_PINCTRL_SetIOMUX(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 0: + if (pin < 5) { + HAL_RKX110_SET_IOMUX_L(hw, 0, A, pin, val); + } else if (pin < 8) { + HAL_RKX110_SET_IOMUX_H(hw, 0, A, pin, val); + } else if (pin < 13) { + HAL_RKX110_SET_IOMUX_L(hw, 0, B, pin, val); + } else if (pin < 16) { + HAL_RKX110_SET_IOMUX_H(hw, 0, B, pin, val); + } else if (pin < 21) { + HAL_RKX110_SET_IOMUX_L(hw, 0, C, pin, val); + } else if (pin < 24) { + HAL_RKX110_SET_IOMUX_H(hw, 0, C, pin, val); + } else { + HAL_ERR("PINCTRL: iomux unknown gpio pin-%d\n", pin); + } + break; + case 1: + if (pin < 8) { + HAL_RKX110_SET_IOMUX_0(hw, 1, A, pin, val); + } else if (pin < 16) { + HAL_RKX110_SET_IOMUX_0(hw, 1, B, pin, val); + } else if (pin < 24) { + HAL_RKX110_SET_IOMUX_0(hw, 1, C, pin, val); + } else { + HAL_ERR("PINCTRL: iomux unknown gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: iomux unknown gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX110_PINCTRL_SetPULL(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 1: + if (pin < 8) { + HAL_RKX110_SET_PULL_0(hw, 1, A, pin, val); + } else if (pin < 16) { + HAL_RKX110_SET_PULL_0(hw, 1, B, pin, val); + } else if (pin < 24) { + HAL_RKX110_SET_PULL_0(hw, 1, C, pin, val); + } else { + HAL_ERR("PINCTRL: pull unknown gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: pull unknown gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX110_PINCTRL_SetPULLEN(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 0: + if (pin < 8) { + HAL_RKX110_SET_PULLEN_0(hw, 0, A, pin, val); + } else if (pin < 16) { + HAL_RKX110_SET_PULLEN_0(hw, 0, B, pin, val); + } else if (pin < 24) { + HAL_RKX110_SET_PULLEN_0(hw, 0, C, pin, val); + } else { + HAL_ERR("PINCTRL: pull enable unknown gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: pull enable unknown gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX110_PINCTRL_SetDRV(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 1: + if (pin < 8) { + HAL_RKX110_SET_DRV_0(hw, 1, A, pin, val); + } else if (pin < 16) { + HAL_RKX110_SET_DRV_0(hw, 1, B, pin, val); + } else if (pin < 24) { + HAL_RKX110_SET_DRV_0(hw, 1, C, pin, val); + } else { + HAL_ERR("PINCTRL: drive strengh unknown gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: drive strengh gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX110_PINCTRL_SetSMT(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 1: + if (pin < 8) { + HAL_RKX110_SET_SMT_0(hw, 1, A, pin, val); + } else if (pin < 16) { + HAL_RKX110_SET_SMT_0(hw, 1, B, pin, val); + } else if (pin < 24) { + HAL_RKX110_SET_SMT_0(hw, 1, C, pin, val); + } else { + HAL_ERR("PINCTRL: smt gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: smt gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX120_PINCTRL_SetIOMUX(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 5: + if (pin < 5) { + HAL_RKX120_SET_IOMUX_L(hw, 0, A, pin, val); + } else if (pin < 8) { + HAL_RKX120_SET_IOMUX_H(hw, 0, A, pin, val); + } else if (pin < 13) { + HAL_RKX120_SET_IOMUX_L(hw, 0, B, pin, val); + } else if (pin < 16) { + HAL_RKX120_SET_IOMUX_H(hw, 0, B, pin, val); + } else if (pin < 21) { + HAL_RKX120_SET_IOMUX_L(hw, 0, C, pin, val); + } else if (pin < 24) { + HAL_RKX120_SET_IOMUX_H(hw, 0, C, pin, val); + } else { + HAL_ERR("PINCTRL: iomux unknown gpio pin-%d\n", pin); + } + break; + case 6: + if (pin < 8) { + HAL_RKX120_SET_IOMUX_0(hw, 1, A, pin, val); + } else if (pin < 16) { + HAL_RKX120_SET_IOMUX_0(hw, 1, B, pin, val); + } else if (pin < 24) { + HAL_RKX120_SET_IOMUX_0(hw, 1, C, pin, val); + } else { + HAL_ERR("PINCTRL: iomux unknown gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: iomux unknown gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX120_PINCTRL_SetPULL(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 6: + if (pin < 8) { + HAL_RKX120_SET_PULL_0(hw, 1, A, pin, val); + } else if (pin < 16) { + HAL_RKX120_SET_PULL_0(hw, 1, B, pin, val); + } else if (pin < 24) { + HAL_RKX120_SET_PULL_0(hw, 1, C, pin, val); + } else { + HAL_ERR("PINCTRL: pull unknown gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: pull unknown gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX120_PINCTRL_SetPULLEN(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 5: + if (pin < 8) { + HAL_RKX120_SET_PULLEN_0(hw, 0, A, pin, val); + } else if (pin < 16) { + HAL_RKX120_SET_PULLEN_0(hw, 0, B, pin, val); + } else if (pin < 24) { + HAL_RKX120_SET_PULLEN_0(hw, 0, C, pin, val); + } else { + HAL_ERR("PINCTRL: pull enable unknown gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: pull enable unknown gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX120_PINCTRL_SetDRV(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 6: + if (pin < 8) { + HAL_RKX120_SET_DRV_0(hw, 1, A, pin, val); + } else if (pin < 16) { + HAL_RKX120_SET_DRV_0(hw, 1, B, pin, val); + } else if (pin < 24) { + HAL_RKX120_SET_DRV_0(hw, 1, C, pin, val); + } else { + HAL_ERR("PINCTRL: drive strengh unknown gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: drive strengh gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status RKX120_PINCTRL_SetSMT(struct hwpin *hw, uint8_t pin, uint32_t val) +{ + switch (hw->bank) { + case 6: + if (pin < 8) { + HAL_RKX120_SET_SMT_0(hw, 1, A, pin, val); + } else if (pin < 16) { + HAL_RKX120_SET_SMT_0(hw, 1, B, pin, val); + } else if (pin < 24) { + HAL_RKX120_SET_SMT_0(hw, 1, C, pin, val); + } else { + HAL_ERR("PINCTRL: smt gpio pin-%d\n", pin); + } + break; + default: + HAL_ERR("PINCTRL: smt gpio bank-%d\n", hw->bank); + break; + } + + return HAL_OK; +} + +static HAL_Status PINCTRL_SetPinParam(struct hwpin *hw, uint8_t pin, uint32_t param) +{ + HAL_Status rc = HAL_OK; + uint8_t val; + + if (hw->type == PIN_RKX110) { + if (param & RK_SERDES_FLAG_MUX) { + val = (param & RK_SERDES_MASK_MUX) >> RK_SERDES_SHIFT_MUX; + rc |= RKX110_PINCTRL_SetIOMUX(hw, pin, val); + } + + if (param & RK_SERDES_FLAG_PUL) { + val = (param & RK_SERDES_MASK_PUL) >> RK_SERDES_SHIFT_PUL; + rc |= RKX110_PINCTRL_SetPULL(hw, pin, val); + } + + if (param & RK_SERDES_FLAG_PEN) { + val = (param & RK_SERDES_MASK_PEN) >> RK_SERDES_SHIFT_PEN; + rc |= RKX110_PINCTRL_SetPULLEN(hw, pin, val); + } + + if (param & RK_SERDES_FLAG_DRV) { + val = (param & RK_SERDES_MASK_DRV) >> RK_SERDES_SHIFT_DRV; + rc |= RKX110_PINCTRL_SetDRV(hw, pin, val); + } + + if (param & RK_SERDES_FLAG_SMT) { + val = (param & RK_SERDES_MASK_SMT) >> RK_SERDES_SHIFT_SMT; + rc |= RKX110_PINCTRL_SetSMT(hw, pin, val); + } + } else if (hw->type == PIN_RKX120) { + if (param & RK_SERDES_FLAG_MUX) { + val = (param & RK_SERDES_MASK_MUX) >> RK_SERDES_SHIFT_MUX; + rc |= RKX120_PINCTRL_SetIOMUX(hw, pin, val); + } + + if (param & RK_SERDES_FLAG_PUL) { + val = (param & RK_SERDES_MASK_PUL) >> RK_SERDES_SHIFT_PUL; + rc |= RKX120_PINCTRL_SetPULL(hw, pin, val); + } + + if (param & RK_SERDES_FLAG_PEN) { + val = (param & RK_SERDES_MASK_PEN) >> RK_SERDES_SHIFT_PEN; + rc |= RKX120_PINCTRL_SetPULLEN(hw, pin, val); + } + + if (param & RK_SERDES_FLAG_DRV) { + val = (param & RK_SERDES_MASK_DRV) >> RK_SERDES_SHIFT_DRV; + rc |= RKX120_PINCTRL_SetDRV(hw, pin, val); + } + + if (param & RK_SERDES_FLAG_SMT) { + val = (param & RK_SERDES_MASK_SMT) >> RK_SERDES_SHIFT_SMT; + rc |= RKX120_PINCTRL_SetSMT(hw, pin, val); + } + } else { + HAL_ERR("PINCTRL: error pin type %d\n", hw->type); + } + + return rc; +} + +/********************* Public Function Definition ***************************/ + +uint32_t HAL_PINCTRL_Read(struct hwpin *hw, uint32_t reg) +{ + uint32_t val; + int ret; + + ret = hw->xfer.read(hw->xfer.client, reg, &val); + if (ret) { + HAL_ERR("%s: read reg=0x%08x failed, ret=%d\n", hw->name, reg, ret); + } + + HAL_DBG("%s: %s: reg=0x%08x, val=0x%08x\n", __func__, hw->name, reg, val); + + return val; +} + +uint32_t HAL_PINCTRL_Write(struct hwpin *hw, uint32_t reg, uint32_t val) +{ + int ret; + + HAL_DBG("%s: %s: reg=0x%08x, val=0x%08x\n", __func__, hw->name, reg, val); + + ret = hw->xfer.write(hw->xfer.client, reg, val); + if (ret) { + HAL_ERR("%s: write reg=0x%08x, val=0x%08x failed, ret=%d\n", + hw->name, reg, val, ret); + } + + return ret; +} + +HAL_Status HAL_PINCTRL_Init(void) +{ + return HAL_OK; +} + +HAL_Status HAL_PINCTRL_SetParam(struct hwpin *hw, uint32_t mPins, uint32_t param) +{ + uint8_t pin; + HAL_Status rc; + + if (!(param & (RK_SERDES_FLAG_MUX | RK_SERDES_FLAG_PUL | RK_SERDES_FLAG_PEN | + RK_SERDES_FLAG_DRV | RK_SERDES_FLAG_SMT))) { + HAL_ERR("PINCTRL: no parameter!\n"); + + return HAL_ERROR; + } + + for (pin = 0; pin < 32; pin++) { + if (mPins & (1 << pin)) { + rc = PINCTRL_SetPinParam(hw, pin, param); + if (rc) { + return rc; + } + } + } + + return HAL_OK; +} + +HAL_Status HAL_PINCTRL_SetIOMUX(struct hwpin *hw, uint32_t mPins, uint32_t param) +{ + return HAL_PINCTRL_SetParam(hw, mPins, param); +} + diff --git a/drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.h b/drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.h new file mode 100644 index 000000000000..0f28be9fb326 --- /dev/null +++ b/drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Steven Liu + */ + +#ifndef _PINCTRL_CORE_H_ +#define _PINCTRL_CORE_H_ + +#include + +#include "hal_def.h" +#include "hal_os_def.h" + +typedef enum { + PIN_UNDEF, + PIN_RKX110, + PIN_RKX120, + PIN_ALL, + PIN_MAX, +} HAL_PinType; + +struct hwpin; + +struct xferpin { + HAL_PinType type; + char *name; /* slave addr is expected */ + void *client; + uint32_t bank; + uint32_t mpins; + uint32_t param; + HAL_RegRead_t *read; + HAL_RegWrite_t *write; +}; + +struct hwpin { + char name[32]; + HAL_PinType type; + uint32_t grf_base; + uint32_t bank; + uint32_t mpins; + uint32_t param; + struct xferpin xfer; +}; + +typedef enum { + GPIO0_A0 = 0, + GPIO0_A1, + GPIO0_A2, + GPIO0_A3, + GPIO0_A4, + GPIO0_A5, + GPIO0_A6, + GPIO0_A7, + GPIO0_B0 = 8, + GPIO0_B1, + GPIO0_B2, + GPIO0_B3, + GPIO0_B4, + GPIO0_B5, + GPIO0_B6, + GPIO0_B7, + GPIO0_C0 = 16, + GPIO0_C1, + GPIO0_C2, + GPIO0_C3, + GPIO0_C4, + GPIO0_C5, + GPIO0_C6, + GPIO0_C7, + GPIO0_D0 = 24, + GPIO0_D1, + GPIO0_D2, + GPIO0_D3, + GPIO0_D4, + GPIO0_D5, + GPIO0_D6, + GPIO0_D7, + GPIO1_A0 = 32, + GPIO1_A1, + GPIO1_A2, + GPIO1_A3, + GPIO1_A4, + GPIO1_A5, + GPIO1_A6, + GPIO1_A7, + GPIO1_B0 = 40, + GPIO1_B1, + GPIO1_B2, + GPIO1_B3, + GPIO1_B4, + GPIO1_B5, + GPIO1_B6, + GPIO1_B7, + GPIO1_C0 = 48, + GPIO1_C1, + GPIO1_C2, + GPIO1_C3, + GPIO1_C4, + GPIO1_C5, + GPIO1_C6, + GPIO1_C7, + GPIO1_D0 = 56, + GPIO1_D1, + GPIO1_D2, + GPIO1_D3, + GPIO1_D4, + GPIO1_D5, + GPIO1_D6, + GPIO1_D7, + GPIO_NUM_MAX +} ePINCTRL_PIN; + +typedef enum { + PINCTRL_IOMUX_FUNC0, + PINCTRL_IOMUX_FUNC1, + PINCTRL_IOMUX_FUNC2, + PINCTRL_IOMUX_FUNC3, + PINCTRL_IOMUX_FUNC4, + PINCTRL_IOMUX_FUNC5, + PINCTRL_IOMUX_FUNC6, + PINCTRL_IOMUX_FUNC7, +} ePINCTRL_iomuxFunc; + +typedef enum { + PINCTRL_PULL_NORMAL, + PINCTRL_PULL_UP, + PINCTRL_PULL_DOWN, + PINCTRL_PULL_KEEP +} ePINCTRL_pullMode; + +/* + * Special pull configuration. + * Only enable and disable. + * The specific pull-up or pull-down can not be configured. + */ +typedef enum { + PINCTRL_PULL_DIS, + PINCTRL_PULL_EN +} ePINCTRL_pullEnable; + +typedef enum { + PINCTRL_DRIVE_LEVEL0, + PINCTRL_DRIVE_LEVEL1, + PINCTRL_DRIVE_LEVEL2, + PINCTRL_DRIVE_LEVEL3, + PINCTRL_DRIVE_LEVEL4, + PINCTRL_DRIVE_LEVEL5, + PINCTRL_DRIVE_LEVEL6, + PINCTRL_DRIVE_LEVEL7 +} ePINCTRL_driveLevel; + +typedef enum { + PINCTRL_SCHMITT_DIS, + PINCTRL_SCHMITT_EN +} ePINCTRL_schmitt; + +uint32_t HAL_PINCTRL_Read(struct hwpin *hw, uint32_t reg); +uint32_t HAL_PINCTRL_Write(struct hwpin *hw, uint32_t reg, uint32_t val); + +HAL_Status HAL_PINCTRL_Init(void); +HAL_Status HAL_PINCTRL_SetParam(struct hwpin *hw, uint32_t mPins, uint32_t param); +HAL_Status HAL_PINCTRL_SetIOMUX(struct hwpin *hw, uint32_t mPins, uint32_t param); + +#endif /* _PINCTRL_CORE_H_ */ diff --git a/drivers/mfd/rkx110_x120/pattern_gen.c b/drivers/mfd/rkx110_x120/pattern_gen.c new file mode 100644 index 000000000000..488d372b536b --- /dev/null +++ b/drivers/mfd/rkx110_x120/pattern_gen.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + */ + +#include +#include + +#include "rkx110_x120.h" + +#define PATTERN_GEN_PATTERN_CTRL 0x0000 +#define PATTERN_START_PCLK BIT(31) +#define PATTERN_START BIT(30) +#define PATTERN_RECTANGLE_H GENMASK(29, 16) +#define PATTERN_RECTANGLE_V GENMASK(13, 0) +#define PATTERN_GEN_PATERN_VH_CFG0 0x0004 +#define PATTERN_HACT GENMASK(29, 16) +#define PATTERN_VACT GENMASK(13, 0) +#define PATTERN_GEN_PATERN_VH_CFG1 0x0008 +#define PATTERN_VFP GENMASK(29, 20) +#define PATTERN_VBP GENMASK(19, 10) +#define PATTERN_VSA GENMASK(9, 0) +#define PATTERN_GEN_PATERN_VH_CFG2 0x000C +#define PATTERN_HFP GENMASK(27, 16) +#define PATTERN_HBP GENMASK(11, 0) +#define PATTERN_GEN_PATERN_VH_CFG3 0x0010 +#define PATTERN_HSA GENMASK(11, 0) +#define PATTERN_GEN_VALUE0 0x0014 +#define PATTERN_GEN_VALUE1 0x0018 + +static void pattern_gen_enable(struct pattern_gen *pattern_gen) +{ + struct i2c_client *client = pattern_gen->chip->client; + struct rk_serdes *serdes = pattern_gen->chip->serdes; + const struct videomode *vm = serdes->vm; + + serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL, + PATTERN_RECTANGLE_H | PATTERN_RECTANGLE_V, + FIELD_PREP(PATTERN_RECTANGLE_H, 128) | + FIELD_PREP(PATTERN_RECTANGLE_V, 128)); + + serdes->i2c_write_reg(client, pattern_gen->base + PATTERN_GEN_PATERN_VH_CFG0, + FIELD_PREP(PATTERN_HACT, vm->hactive) | + FIELD_PREP(PATTERN_VACT, vm->vactive)); + serdes->i2c_write_reg(client, pattern_gen->base + PATTERN_GEN_PATERN_VH_CFG1, + FIELD_PREP(PATTERN_VFP, vm->vfront_porch) | + FIELD_PREP(PATTERN_VBP, vm->vback_porch) | + FIELD_PREP(PATTERN_VSA, vm->vsync_len)); + serdes->i2c_write_reg(client, pattern_gen->base + PATTERN_GEN_PATERN_VH_CFG2, + FIELD_PREP(PATTERN_HFP, vm->hfront_porch) | + FIELD_PREP(PATTERN_HBP, vm->hback_porch)); + serdes->i2c_write_reg(client, pattern_gen->base + PATTERN_GEN_PATERN_VH_CFG3, + FIELD_PREP(PATTERN_HSA, vm->hsync_len)); + + serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL, + PATTERN_START_PCLK, + FIELD_PREP(PATTERN_START_PCLK, 1)); + serdes->i2c_write_reg(client, pattern_gen->link_src_reg, + BIT(pattern_gen->link_src_offset + 16) | + BIT(pattern_gen->link_src_offset)); +} + +static void pattern_gen_disable(struct pattern_gen *pattern_gen) +{ + struct i2c_client *client = pattern_gen->chip->client; + struct rk_serdes *serdes = pattern_gen->chip->serdes; + + serdes->i2c_write_reg(client, pattern_gen->link_src_reg, + BIT(pattern_gen->link_src_offset + 16)); + serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL, + PATTERN_START_PCLK, + FIELD_PREP(PATTERN_START_PCLK, 0)); +} + +static ssize_t pattern_gen_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct pattern_gen *pattern_gen = m->private; + char buf[5]; + + if (len > sizeof(buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, len)) + return -EFAULT; + + buf[len] = '\0'; + + if (sysfs_streq(buf, "on")) + pattern_gen_enable(pattern_gen); + else if (sysfs_streq(buf, "off")) + pattern_gen_disable(pattern_gen); + else + return -EINVAL; + + return len; +} + +static int pattern_gen_show(struct seq_file *m, void *data) +{ + struct pattern_gen *pattern_gen = m->private; + struct i2c_client *client = pattern_gen->chip->client; + struct rk_serdes *serdes = pattern_gen->chip->serdes; + u32 reg = 0; + + serdes->i2c_read_reg(client, pattern_gen->link_src_reg, ®); + if (reg & BIT(pattern_gen->link_src_offset)) + seq_printf(m, "%s\n", "on"); + else + seq_printf(m, "%s\n", "off"); + + return 0; +} + +static int pattern_gen_open(struct inode *inode, struct file *file) +{ + struct pattern_gen *pattern_gen = inode->i_private; + + return single_open(file, pattern_gen_show, pattern_gen); +} + +static const struct file_operations pattern_gen_fops = { + .owner = THIS_MODULE, + .open = pattern_gen_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = pattern_gen_write, +}; + +void rkx110_x120_pattern_gen_debugfs_create_file(struct pattern_gen *pattern_gen, + struct rk_serdes_chip *chip, + struct dentry *dentry) +{ + pattern_gen->chip = chip; + + debugfs_create_file(pattern_gen->name, 0600, dentry, pattern_gen, + &pattern_gen_fops); +} diff --git a/drivers/mfd/rkx110_x120/rkx110.c b/drivers/mfd/rkx110_x120/rkx110.c new file mode 100644 index 000000000000..0e3fc4f7c274 --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Rockchip Electronics Co. Ltd. + */ +#include +#include "hal/pinctrl_api.h" +#include "rkx110_x120.h" +#include "rkx110_reg.h" +#include "serdes_combphy.h" + +#if defined(CONFIG_DEBUG_FS) +static struct pattern_gen rkx110_pattern_gen[] = { + { + .name = "dsi0", + .base = RKX110_PATTERN_GEN_DSI0_BASE, + .link_src_reg = SER_GRF_SOC_CON4, + .link_src_offset = 12, + }, { + .name = "dsi1", + .base = RKX110_PATTERN_GEN_DSI1_BASE, + .link_src_reg = SER_GRF_SOC_CON4, + .link_src_offset = 13, + }, { + .name = "lvds0", + .base = RKX110_PATTERN_GEN_LVDS0_BASE, + .link_src_reg = SER_GRF_SOC_CON4, + .link_src_offset = 14, + }, { + .name = "lvds1", + .base = RKX110_PATTERN_GEN_LVDS1_BASE, + .link_src_reg = SER_GRF_SOC_CON4, + .link_src_offset = 15, + }, + { /* sentinel */ } +}; + +static const struct rk_serdes_reg rkx110_regs[] = { + { + .name = "cru", + .reg_base = RKX110_SER_CRU_BASE, + .reg_len = 0xF04, + }, + { + .name = "grf", + .reg_base = RKX110_SER_GRF_BASE, + .reg_len = 0x220, + + }, + { + .name = "grf_mipi0", + .reg_base = RKX110_GRF_MIPI0_BASE, + .reg_len = 0x600, + }, + { + .name = "grf_mipi1", + .reg_base = RKX110_GRF_MIPI1_BASE, + .reg_len = 0x600, + }, + { + .name = "mipi_lvds_phy0", + .reg_base = RKX110_MIPI_LVDS_RX_PHY0_BASE, + .reg_len = 0xb0, + }, + { + .name = "mipi_lvds_phy1", + .reg_base = RKX110_MIPI_LVDS_RX_PHY1_BASE, + .reg_len = 0xb0, + }, + + { + .name = "host0", + .reg_base = RKX110_CSI2HOST0_BASE, + .reg_len = 0x60, + }, + { + .name = "host1", + .reg_base = RKX110_CSI2HOST1_BASE, + .reg_len = 0x60, + }, + { + .name = "vicap", + .reg_base = RKX110_VICAP_BASE, + .reg_len = 0x220, + }, + { + .name = "gpio0", + .reg_base = RKX110_GPIO0_BASE, + .reg_len = 0x80, + }, + { + .name = "gpio1", + .reg_base = RKX110_GPIO1_BASE, + .reg_len = 0x80, + }, + { + .name = "dsi0", + .reg_base = RKX110_DSI_RX0_BASE, + .reg_len = 0x1D0, + }, + { + .name = "dsi1", + .reg_base = RKX110_DSI_RX1_BASE, + .reg_len = 0x1D0, + }, + { + .name = "rklink", + .reg_base = RKX110_SER_RKLINK_BASE, + .reg_len = 0xD4, + }, + { + .name = "pcs0", + .reg_base = RKX110_SER_PCS0_BASE, + .reg_len = 0x1c0, + }, + { + .name = "pcs1", + .reg_base = RKX110_SER_PCS1_BASE, + .reg_len = 0x1c0, + }, + { + .name = "pma0", + .reg_base = RKX110_SER_PMA0_BASE, + .reg_len = 0x100, + }, + { + .name = "pma1", + .reg_base = RKX110_SER_PMA1_BASE, + .reg_len = 0x100, + }, + { + .name = "dsi0_pattern_gen", + .reg_base = RKX110_PATTERN_GEN_DSI0_BASE, + .reg_len = 0x18, + }, + { + .name = "dsi1_pattern_gen", + .reg_base = RKX110_PATTERN_GEN_DSI1_BASE, + .reg_len = 0x18, + }, + { + .name = "lvds0_pattern_gen", + .reg_base = RKX110_PATTERN_GEN_LVDS0_BASE, + .reg_len = 0x18, + }, + { + .name = "lvds1_pattern_gen", + .reg_base = RKX110_PATTERN_GEN_LVDS1_BASE, + .reg_len = 0x18, + }, + { /* sentinel */ } +}; + +static int rkx110_reg_show(struct seq_file *s, void *v) +{ + const struct rk_serdes_reg *regs = rkx110_regs; + struct rk_serdes_chip *chip = s->private; + struct rk_serdes *serdes = chip->serdes; + struct i2c_client *client = chip->client; + int i; + u32 val = 0; + + seq_printf(s, "rkx110_%s:\n", file_dentry(s->file)->d_iname); + + while (regs->name) { + if (!strcmp(regs->name, file_dentry(s->file)->d_iname)) + break; + regs++; + } + + if (!regs->name) + return -ENODEV; + + for (i = 0; i <= regs->reg_len; i += 4) { + serdes->i2c_read_reg(client, regs->reg_base + i, &val); + + if (i % 16 == 0) + seq_printf(s, "\n0x%04x:", i); + seq_printf(s, " %08x", val); + } + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t rkx110_reg_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + const struct rk_serdes_reg *regs = rkx110_regs; + struct rk_serdes_chip *chip = file->f_path.dentry->d_inode->i_private; + struct rk_serdes *serdes = chip->serdes; + struct i2c_client *client = chip->client; + u32 addr; + u32 val; + char kbuf[25]; + int ret; + + if (count >= sizeof(kbuf)) + return -ENOSPC; + + if (copy_from_user(kbuf, buf, count)) + return -EFAULT; + + kbuf[count] = '\0'; + + ret = sscanf(kbuf, "%x%x", &addr, &val); + if (ret != 2) + return -EINVAL; + + while (regs->name) { + if (!strcmp(regs->name, file_dentry(file)->d_iname)) + break; + regs++; + } + + if (!regs->name) + return -ENODEV; + + addr += regs->reg_base; + + serdes->i2c_write_reg(client, addr, val); + + return count; +} + +static int rkx110_reg_open(struct inode *inode, struct file *file) +{ + struct rk_serdes_chip *chip = inode->i_private; + + return single_open(file, rkx110_reg_show, chip); +} + +static const struct file_operations rkx110_reg_fops = { + .owner = THIS_MODULE, + .open = rkx110_reg_open, + .read = seq_read, + .write = rkx110_reg_write, + .llseek = seq_lseek, + .release = single_release, +}; + +void rkx110_debugfs_init(struct rk_serdes_chip *chip, struct dentry *dentry) +{ + struct pattern_gen *pattern_gen = rkx110_pattern_gen; + const struct rk_serdes_reg *regs = rkx110_regs; + struct dentry *dir; + + dir = debugfs_create_dir("registers", dentry); + if (!IS_ERR(dir)) { + while (regs->name) { + debugfs_create_file(regs->name, 0600, dir, chip, &rkx110_reg_fops); + regs++; + } + } + + dir = debugfs_create_dir("pattern_gen", dentry); + if (!IS_ERR(dir)) { + while (pattern_gen->name) { + rkx110_x120_pattern_gen_debugfs_create_file(pattern_gen, chip, dir); + pattern_gen++; + } + } +} +#endif + +static int rkx110_rgb_rx_iomux_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route) +{ + struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client; + uint32_t pins; + + pins = RK_SERDES_GPIO_PIN_C0 | RK_SERDES_GPIO_PIN_C1 | RK_SERDES_GPIO_PIN_C2 | + RK_SERDES_GPIO_PIN_C3 | RK_SERDES_GPIO_PIN_C4 | RK_SERDES_GPIO_PIN_C5 | + RK_SERDES_GPIO_PIN_C6 | RK_SERDES_GPIO_PIN_C7; + serdes->set_hwpin(serdes, client, PIN_RKX110, RK_SERDES_SER_GPIO_BANK0, pins, + RK_SERDES_PIN_CONFIG_MUX_FUNC1); + + pins = RK_SERDES_GPIO_PIN_A0 | RK_SERDES_GPIO_PIN_A1 | RK_SERDES_GPIO_PIN_A2 | + RK_SERDES_GPIO_PIN_A3 | RK_SERDES_GPIO_PIN_A4 | RK_SERDES_GPIO_PIN_A5 | + RK_SERDES_GPIO_PIN_A6 | RK_SERDES_GPIO_PIN_A7 | RK_SERDES_GPIO_PIN_B0 | + RK_SERDES_GPIO_PIN_B1 | RK_SERDES_GPIO_PIN_B2 | RK_SERDES_GPIO_PIN_B3 | + RK_SERDES_GPIO_PIN_B4 | RK_SERDES_GPIO_PIN_B5 | RK_SERDES_GPIO_PIN_B6 | + RK_SERDES_GPIO_PIN_B7 | RK_SERDES_GPIO_PIN_C0 | RK_SERDES_GPIO_PIN_C1 | + RK_SERDES_GPIO_PIN_C2 | RK_SERDES_GPIO_PIN_C3; + serdes->set_hwpin(serdes, client, PIN_RKX110, RK_SERDES_SER_GPIO_BANK1, pins, + RK_SERDES_PIN_CONFIG_MUX_FUNC1); + + return 0; +} + +int rkx110_rgb_rx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route) +{ + rkx110_rgb_rx_iomux_cfg(serdes, route); + + return 0; +} + +int rkx110_lvds_rx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, int id) +{ + rkx110_combrxphy_set_mode(serdes, COMBRX_PHY_MODE_VIDEO_LVDS); + + rkx110_combrxphy_power_on(serdes, id ? COMBPHY_1 : COMBPHY_0); + + return 0; +} + diff --git a/drivers/mfd/rkx110_x120/rkx110_combrxphy.c b/drivers/mfd/rkx110_x120/rkx110_combrxphy.c new file mode 100644 index 000000000000..4152728aec9b --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110_combrxphy.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Guochun Huang + */ + +#include "hal/cru_api.h" +#include +#include +#include "rkx110_x120.h" +#include "rkx110_reg.h" +#include "serdes_combphy.h" + +#define SOFT_RST 0x0000 +#define HS_CLK_SOFT_RST BIT(1) +#define CFG_CLK_SOFT_RST BIT(0) +#define PHY_RCAL 0x0004 +#define RCAL_DONE BIT(17) +#define RCAL_OUT(x) UPDATE(x, 16, 13) +#define RCAL_CTL(x) UPDATE(x, 12, 5) +#define RCAL_TRIM(x) UPDATE(x, 4, 1) +#define RCAL_EN BIT(0) +#define ULP_RX_EN 0x0008 +#define VOFFCAL_OUT 0x000c +#define CSI_CLK_VOFFCAL_DONE BIT(29) +#define CSI_CLK_VOFFCAL_OUT(x) UPDATE(x, 28, 24) +#define CSI_0_VOFFCAL_DONE BIT(23) +#define CSI_0_VOFFCAL_OUT(x) UPDATE(x, 22, 18) +#define CSI_1_VOFFCAL_DONE BIT(17) +#define CSI_1_VOFFCAL_OUT(x) UPDATE(x, 16, 12) +#define CSI_2_VOFFCAL_DONE BIT(11) +#define CSI_2_VOFFCAL_OUT(x) UPDATE(x, 10, 6) +#define CSI_3_VOFFCAL_DONE BIT(5) +#define CSI_3_VOFFCAL_OUT(x) UPDATE(x, 4, 0) +#define CSI_CTL01 0x0010 +#define CSI_CTL1(x) UPDATE(x, 31, 16) +#define CSI_CTL0(x) UPDATE(x, 15, 0) +#define CSI_CTL23 0x0014 +#define CSI_CTL3(x) UPDATE(x, 31, 16) +#define CSI_CTL2(x) UPDATE(x, 15, 0) +#define CSI_VINIT 0x001c +#define CSI_LPRX_VREF_TRIM UPDATE(x, 23, 20) +#define CSI_CLK_LPRX_VINIT(x) UPDATE(x, 19, 16) +#define CSI_3_LPRX_VINIT(x) UPDATE(x, 15, 12) +#define CSI_2_LPRX_VINIT(x) UPDATE(x, 11, 8) +#define CSI_1_LPRX_VINIT(x) UPDATE(x, 7, 4) +#define CSI_0_LPRX_VINIT(x) UPDATE(x, 3, 0) +#define CLANE_PARA 0x0020 +#define T_CLK_TERM_EN(x) UPDATE(x, 15, 8) +#define T_CLK_SETTLE(x) UPDATE(x, 7, 0) +#define T_HS_TERMEN 0x0024 +#define T_D3_TERMEN(x) UPDATE(x, 31, 24) +#define T_D2_TERMEN(x) UPDATE(x, 23, 16) +#define T_D1_TERMEN(x) UPDATE(x, 15, 8) +#define T_D0_TERMEN(x) UPDATE(x, 7, 0) +#define T_HS_SETTLE 0x0028 +#define T_D3_SETTLE(x) UPDATE(x, 31, 24) +#define T_D2_SETTLE(x) UPDATE(x, 23, 16) +#define T_D1_SETTLE(x) UPDATE(x, 15, 8) +#define T_D0_SETTLE(x) UPDATE(x, 7, 0) +#define T_CLANE_INIT 0x0030 +#define T_CLK_INIT(x) UPDATE(x, 23, 0) +#define T_LANE0_INIT 0x0034 +#define T_D0_INIT(x) UPDATE(x, 23, 0) +#define T_LANE1_INIT 0x0038 +#define T_D1_INIT(x) UPDATE(x, 23, 0) +#define T_LANE2_INIT 0x003c +#define T_D2_INIT(x) UPDATE(x, 23, 0) +#define T_LANE3_INIT 0x0040 +#define T_D3_INIT(x) UPDATE(x, 23, 0) +#define TLPX_CTRL 0x0044 +#define EN_TLPX_CHECK BIT(8) +#define TLPX(x) UPDATE(x, 7, 0) +#define NE_SWAP 0x0048 +#define DPDN_SWAP_LANE(x) UPDATE(1 << x, 11, 8) +#define LANE_SWAP_LAN3(x) UPDATE(x, 7, 6) +#define LANE_SWAP_LANE2(x) UPDATE(x, 5, 4) +#define LANE_SWAP_LANE1(x) UPDATE(x, 3, 2) +#define LANE_SWAP_LANE0(x) UPDATE(x, 1, 0) +#define MISC_INFO 0x004c +#define ULPS_LP10_SEL BIT(1) +#define LONG_SOTSYNC_EN BIT(0) + +#define GRF_MIPI_RX_CON0 0x0000 +#define RXCK_RTRM(x) HIWORD_UPDATE(x, GENMASK(15, 12), 12) +#define LVDS_RX3_PD(x) HIWORD_UPDATE(x, BIT(10), 10) +#define LVDS_RX2_PD(x) HIWORD_UPDATE(x, BIT(9), 9) +#define LVDS_RX1_PD(x) HIWORD_UPDATE(x, BIT(8), 8) +#define LVDS_RX0_PD(x) HIWORD_UPDATE(x, BIT(7), 7) +#define LVDS_RXCK_PD(x) HIWORD_UPDATE(x, BIT(6), 6) +#define LANE3_ENABLE(x) HIWORD_UPDATE(x, BIT(5), 5) +#define LANE2_ENABLE(x) HIWORD_UPDATE(x, BIT(4), 4) +#define LANE1_ENABLE(x) HIWORD_UPDATE(x, BIT(3), 3) +#define LANE0_ENABLE(x) HIWORD_UPDATE(x, BIT(2), 2) +#define PHY_MODE(x) HIWORD_UPDATE(x, GENMASK(1, 0), 0) + +#define GRF_MIPI_RX_CON2 0x0008 +#define RXCK_CTL_5(x) HIWORD_UPDATE(x, BIT(11), 11) +#define DDR_CLK_DUTY_CYCLE(x) HIWORD_UPDATE(x, GENMASK(10, 8), 8) +#define BUS_WIDTH_SELECTION(x) HIWORD_UPDATE(x, GENMASK(7, 5), 5) +#define RXCK_CTL_2(x) HIWORD_UPDATE(x, BIT(4), 4) +#define RXCK_CTL_1(x) HIWORD_UPDATE(x, GENMASK(2, 1), 1) +#define RXCK_CTL_0(x) HIWORD_UPDATE(x, BIT(0), 0) + +#define GRF_MIPI_RX_CON4 0x0010 +#define GRF_MIPI_RX_CON5 0x0014 +#define GRF_MIPI_RX_CON6 0x0018 +#define GRF_MIPI_RX_CON7 0x001c +#define GRF_SOC_STATUS 0x0080 +#define DLL_LOCK BIT(24) + +#define LVDS1_MSBSEL(x) HIWORD_UPDATE(x, BIT(5), 5) +#define LVDS0_MSBSEL(x) HIWORD_UPDATE(x, BIT(2), 2) + +static void +rkx110_combrxphy_dsi_timing_init(struct rk_serdes *ser, enum comb_phy_id id) +{ +} + +static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser, enum comb_phy_id id) +{ + struct hwclk *hwclk = ser->chip[DEVICE_LOCAL].hwclk; + struct rkx110_combrxphy *combrxphy = &ser->combrxphy; + struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + u32 val = 0; + u32 grf_base; + + switch (id) { + case COMBPHY_0: + hwclk_set_rate(hwclk, RKX110_CPS_CFGCLK_MIPIRXPHY0, 100 * USEC_PER_SEC); + dev_info(ser->dev, "RKX110_CPS_CFGCLK_MIPIRXPHY0:%d\n", + hwclk_get_rate(hwclk, RKX110_CPS_CFGCLK_MIPIRXPHY0)); + break; + case COMBPHY_1: + hwclk_set_rate(hwclk, RKX110_CPS_CFGCLK_MIPIRXPHY1, 100 * USEC_PER_SEC); + dev_info(ser->dev, "RKX110_CPS_CFGCLK_MIPIRXPHY1:%d\n", + hwclk_get_rate(hwclk, RKX110_CPS_CFGCLK_MIPIRXPHY1)); + break; + default: + break; + } + + serdes_combphy_get_default_config(combrxphy->rate, + &combrxphy->mipi_dphy_cfg); + + switch (ser->dsi_rx.lanes) { + case 4: + val |= LANE3_ENABLE(1); + fallthrough; + case 3: + val |= LANE2_ENABLE(1); + fallthrough; + case 2: + val |= LANE1_ENABLE(1); + fallthrough; + case 1: + default: + val |= LANE0_ENABLE(1); + break; + } + + grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE; + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0, + PHY_MODE(COMBRX_PHY_MODE_VIDEO_MIPI) | val); + + rkx110_combrxphy_dsi_timing_init(ser, id); +} + +static void rkx110_combrxphy_dsi_power_off(struct rk_serdes *ser, enum comb_phy_id id) +{ + struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + u32 grf_base; + + grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE; + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0, + LANE3_ENABLE(0) | LANE2_ENABLE(0) | + LANE1_ENABLE(0) | LANE0_ENABLE(0)); +} + +static void rkx110_combrxphy_lvds_power_on(struct rk_serdes *ser, enum comb_phy_id id) +{ + struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + u32 grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE; + u32 val; + int ret; + + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0, + LVDS_RXCK_PD(0) | PHY_MODE(COMBRX_PHY_MODE_VIDEO_LVDS)); + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON2, + BUS_WIDTH_SELECTION(7) | RXCK_CTL_2(1) | + RXCK_CTL_1(1) | RXCK_CTL_0(0)); + ser->i2c_write_reg(client, SER_GRF_SOC_CON2, + id ? LVDS1_MSBSEL(0) : LVDS0_MSBSEL(0)); + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON4, 0xffff0f08); + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON5, 0xffff0f08); + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON6, 0xffff0f08); + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON7, 0xffff0f08); + + ret = read_poll_timeout(ser->i2c_read_reg, ret, + !(ret < 0) && (val & DLL_LOCK), + 0, MSEC_PER_SEC, false, client, + grf_base + GRF_SOC_STATUS, &val); + if (ret < 0) + dev_err(ser->dev, "DLL is not locked\n"); + + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0, + LVDS_RX3_PD(0) | LVDS_RX2_PD(0) | + LVDS_RX1_PD(0) | LVDS_RX0_PD(0)); +} + +static void rkx110_combrxphy_lvds_power_off(struct rk_serdes *ser, enum comb_phy_id id) +{ + struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + u32 grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE; + + ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0, + LVDS_RX3_PD(1) | LVDS_RX2_PD(1) | + LVDS_RX1_PD(1) | LVDS_RX0_PD(1)); +} + +static void rkx110_combrxphy_lvds_camera_power_on(struct rk_serdes *ser, enum comb_phy_id id) +{ +} + +static void rkx110_combrxphy_lvds_camera_power_off(struct rk_serdes *ser, enum comb_phy_id id) +{ +} + +void rkx110_combrxphy_power_on(struct rk_serdes *ser, enum comb_phy_id id) +{ + struct rkx110_combrxphy *combrxphy = &ser->combrxphy; + + switch (combrxphy->mode) { + case COMBRX_PHY_MODE_VIDEO_MIPI: + rkx110_combrxphy_dsi_power_on(ser, id); + break; + case COMBRX_PHY_MODE_VIDEO_LVDS: + rkx110_combrxphy_lvds_power_on(ser, id); + break; + case COMBRX_PHY_MODE_LVDS_CAMERA: + rkx110_combrxphy_lvds_camera_power_on(ser, id); + break; + default: + break; + } +} + +void rkx110_combrxphy_power_off(struct rk_serdes *ser, enum comb_phy_id id) +{ + struct rkx110_combrxphy *combrxphy = &ser->combrxphy; + + switch (combrxphy->mode) { + case COMBRX_PHY_MODE_VIDEO_MIPI: + rkx110_combrxphy_dsi_power_off(ser, id); + break; + case COMBRX_PHY_MODE_VIDEO_LVDS: + rkx110_combrxphy_lvds_power_off(ser, id); + break; + case COMBRX_PHY_MODE_LVDS_CAMERA: + rkx110_combrxphy_lvds_camera_power_off(ser, id); + break; + default: + break; + } +} + +void rkx110_combrxphy_set_rate(struct rk_serdes *ser, u64 rate) +{ + struct rkx110_combrxphy *combrxphy = &ser->combrxphy; + + combrxphy->rate = rate; +} + +void rkx110_combrxphy_set_mode(struct rk_serdes *ser, enum combrx_phy_mode mode) +{ + struct rkx110_combrxphy *combrxphy = &ser->combrxphy; + + combrxphy->mode = mode; +} diff --git a/drivers/mfd/rkx110_x120/rkx110_dsi_rx.c b/drivers/mfd/rkx110_x120/rkx110_dsi_rx.c new file mode 100644 index 000000000000..8c012caa5063 --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110_dsi_rx.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Guochun Huang + */ + +#include +#include +#include "rkx110_reg.h" +#include "rkx110_x120.h" +#include "rkx110_dsi_rx.h" +#include "serdes_combphy.h" + +#define DSI_RX_MIPI_IDX_CTRL0(x) (0x0100 + x * 8) +#define SW_COMMAND_MODE_EN BIT(26) +#define SW_DT(x) UPDATE(x, 15, 10) +#define SW_VC(x) UPDATE(x, 9, 8) +#define SW_CAP_EN BIT(0) +#define DSI_RX_MIPI_IDX_CTRL1(x) (0X0104 + x * 8) +#define SW_HEIGHT(x) UPDATE(x, 29, 16) +#define SW_WIDTH(x) UPDATE(x, 13, 0) +#define DSI_RX_MIPI_INTEN 0x0174 +#define DSI_RX_MIPI_INTSTAT 0x0178 +#define DSI_RX_MIPI_SIZE_NUM(x) (0x01c0 + x * 4) + +enum { + VSYNC_START = 0x01, + VSYNC_END = 0x11, + HSYNC_START = 0x21, + HSYNC_END = 0x31, +}; + +static inline int dsi_rx_write(struct rk_serdes *ser, u32 reg, u32 val) +{ + struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + + return ser->i2c_write_reg(client, reg, val); +} + +static inline int dsi_rx_read(struct rk_serdes *ser, u32 reg, u32 *val) +{ + struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + + return ser->i2c_read_reg(client, reg, val); +} + +static inline int dsi_rx_update_bits(struct rk_serdes *ser, + u32 reg, u32 mask, u32 val) +{ + struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + + return ser->i2c_update_bits(client, reg, mask, val); +} + +void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route, int id) +{ + struct rkx110_dsi_rx *dsi = &ser->dsi_rx; + const struct videomode *vm = &route->vm; + unsigned long pixelclock; + u32 hactive, vactive; + u64 rate; + u32 val = 0; + u32 csi_base, dsirx_base; + + switch (route->frame_mode) { + case SERDES_SP_PIXEL_INTERLEAVED: + fallthrough; + case SERDES_SP_LEFT_RIGHT_SPLIT: + pixelclock = vm->pixelclock * 2; + hactive = vm->hactive * 2; + vactive = vm->vactive; + break; + case SERDES_SP_LINE_INTERLEAVED: + pixelclock = vm->pixelclock * 2; + vactive = vm->vactive * 2; + hactive = vm->hactive; + break; + case SERDES_FRAME_NORMAL_MODE: + fallthrough; + default: + pixelclock = vm->pixelclock; + hactive = vm->hactive; + vactive = vm->vactive; + break; + } + + rate = DIV_ROUND_CLOSEST_ULL(pixelclock, dsi->lanes); + + rkx110_combrxphy_set_mode(ser, COMBRX_PHY_MODE_VIDEO_MIPI); + rkx110_combrxphy_set_rate(ser, rate * MSEC_PER_SEC); + rkx110_combrxphy_power_on(ser, id ? COMBPHY_1 : COMBPHY_0); + + csi_base = id ? RKX110_CSI2HOST1_BASE : RKX110_CSI2HOST0_BASE; + dsirx_base = id ? RKX110_DSI_RX1_BASE : RKX110_DSI_RX0_BASE; + + + dsi_rx_write(ser, csi_base + CSI2HOST_N_LANES, dsi->lanes - 1); + dsi_rx_write(ser, csi_base + CSI2HOST_RESETN, 0); + + val |= SW_DSI_EN | SW_DATETYPE_FE(VSYNC_END) | SW_DATETYPE_FS(VSYNC_START); + dsi_rx_update_bits(ser, csi_base + CSI2HOST_CONTROL, + SW_DATETYPE_FE_MASK | + SW_DATETYPE_FS_MASK | + SW_DSI_EN, val); + + dsi_rx_write(ser, csi_base + CSI2HOST_RESETN, 1); + + val = SW_CAP_EN | SW_VC(0); + /* + * video mode only support rgb888(0x3e), command mode + * only support DCS Long Write(0x39) + */ + val |= (dsi->mode_flags & SERDES_MIPI_DSI_MODE_VIDEO) ? + (0 | SW_DT(0x3e)) : (SW_COMMAND_MODE_EN | SW_DT(0x39)); + dsi_rx_write(ser, dsirx_base + DSI_RX_MIPI_IDX_CTRL0(0), val); + dsi_rx_write(ser, dsirx_base + DSI_RX_MIPI_IDX_CTRL1(0), + SW_HEIGHT(vactive) | SW_WIDTH(hactive)); +} + +void rkx110_dsi_rx_disable(struct rk_serdes *ser, struct rk_serdes_route *route, int id) +{ + rkx110_combrxphy_power_off(ser, id ? COMBPHY_1 : COMBPHY_0); +} diff --git a/drivers/mfd/rkx110_x120/rkx110_dsi_rx.h b/drivers/mfd/rkx110_x120/rkx110_dsi_rx.h new file mode 100644 index 000000000000..8eaf45543931 --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110_dsi_rx.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Guochun Huang + */ + +#ifndef _RKX110_DSI_RX_H +#define _RKX110_DSI_RX_H + +void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route, int id); +void rkx110_dsi_rx_disable(struct rk_serdes *ser, struct rk_serdes_route *route, int id); + +#endif diff --git a/drivers/mfd/rkx110_x120/rkx110_linktx.c b/drivers/mfd/rkx110_x120/rkx110_linktx.c new file mode 100644 index 000000000000..007a825ab19e --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110_linktx.c @@ -0,0 +1,738 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Zhang Yubing + */ + +#include +#include +#include +#include +#include + +#include "hal/cru_api.h" +#include "hal/pinctrl_api.h" +#include "rkx110_x120.h" +#include "rkx110_reg.h" + +#define LINK_REG(x) ((x) + RKX110_SER_RKLINK_BASE) + +#define RKLINK_TX_SERDES_CTRL LINK_REG(0x0000) + +#define VIDEO_CH0_EN_MASK BIT(31) +#define VIDEO_CH1_EN_MASK BIT(30) +#define STOP_AUDIO BIT(18) +#define STOP_VIDEO_CH1 BIT(17) +#define STOP_VIDEO_CH0 BIT(16) +#define CH1_LVDS_SEL_EN BIT(15) +#define TRAIN_CLK_SEL_MASK GENMASK(14, 13) +#define TRAIN_CLK_SEL_CH0 UPDATE(0, 14, 13) +#define TRAIN_CLK_SEL_CH1 UPDATE(1, 14, 13) +#define TRAIN_CLK_SEL_I2S UPDATE(2, 14, 13) + +#define STREAM_TYPE_MASK BIT(12) + +#define SER_STREAM_CAMERA UPDATE(0, 12, 12) +#define SER_STREAM_DISPLAY UPDATE(1, 12, 12) + +#define VIDEO_EN BIT(11) +#define SERDES_LANE_SWAP_EN BIT(10) +#define SERDES_MIRROR_EN BIT(9) + +#define SER_CH1_EN BIT(8) + +#define CH1_DSOURCE_ID(x) UPDATE(x, 7, 6) +#define CH0_DSOURCE_ID(x) UPDATE(x, 5, 4) + +#define SERDES_DATA_WIDTH_MASK GENMASK(3, 2) +#define SERDES_DATA_WIDTH_8BIT UPDATE(0, 3, 2) +#define SERDES_DATA_WIDTH_16BIT UPDATE(1, 3, 2) +#define SERDES_DATA_WIDTH_24BIT UPDATE(2, 3, 2) +#define SERDES_DATA_WIDTH_32BIT UPDATE(3, 3, 2) + +#define SERDES_DUAL_LANE_EN BIT(1) +#define SER_EN BIT(0) + +#define RKLINK_TX_VIDEO_CTRL LINK_REG(0x0004) +#define VIDEO_REPKT_LENGTH(x) UPDATE(x, 29, 16) +#define DUAL_LVDS_CYCLE_DIFF(x) UPDATE(x, 13, 4) +#define PIXEL_VSYNC_SEL BIT(3) +#define SOURCE_ID_MASK UPDATE(7, 2, 0) +#define CAMERA_SRC_CSI UPDATE(0, 2, 0) +#define CAMERA_SRC_LVDS UPDATE(1, 2, 0) +#define CAMERA_SRC_DVP UPDATE(2, 2, 0) +#define DISPLAY_SRC_DSI UPDATE(0, 2, 0) +#define DISPLAY_SRC_DUAL_LDVS UPDATE(1, 2, 0) +#define DISPLAY_SRC_LVDS0 UPDATE(2, 2, 0) +#define DISPLAY_SRC_LVDS1 UPDATE(3, 2, 0) +#define DISPLAY_SRC_RGB UPDATE(5, 2, 0) + +#define SER_RKLINK_DSI_REC0(x) LINK_REG(0x0008 + 0x10 * x) + #define DSI_REC_START BIT(31) + #define DSI_CMD_TYPE BIT(30) + #define DSI_HACT(x) UPDATE(x, 29, 16) + #define DSI_VACT(x) UPDATE(x, 13, 0) + +#define SER_RKLINK_DSI_REC1(x) LINK_REG(0x000C + 0x10 * x) + #define DSI_SPLIT_LR_SWAP BIT(30) +#define DSI_FRAME_MODE(x) UPDATE(x, 29, 28) + #define DSI_HFP(x) UPDATE(x, 27, 16) + #define DSI_HBP(x) UPDATE(x, 11, 0) + +#define SER_RKLINK_DSI_REC2(x) LINK_REG(0x0010 + 0x10 * x) +#define DSI_0_DST_MASK GENMASK(31, 30) +#define DSI_0_DST(x) UPDATE(x, 31, 30) + #define DSI_CHANNEL_SWAP UPDATE(2, 31, 30) + #define DSI0_SPLIT_MODE UPDATE(0, 31, 30) + #define DSI1_SPLIT_MODE UPDATE(3, 31, 30) + #define DSI_VFP(x) UPDATE(x, 29, 20) + #define DSI_VBP(x) UPDATE(x, 19, 10) + #define DSI_VSA(x) UPDATE(x, 9, 0) + +#define SER_RKLINK_DSI_REC3(x) LINK_REG(0x0014 + 0x10 * x) + #define DSI_DELAY_LENGTH(x) UPDATE(x, 31, 12) + #define DSI_HSA(x) UPDATE(x, 11, 0) + +#define SER_RKLINK_AUDIO_CRTL LINK_REG(0x0028) +#define SER_RKLINK_AUDIO_CTRL LINK_REG(0x0028) +#define SER_RKLINK_AUDIO_FDIV LINK_REG(0x002C) +#define SER_RKLINK_AUDIO_LRCK LINK_REG(0x0030) +#define SER_RKLINK_AUDIO_RECOVER LINK_REG(0x0034) +#define SER_RKLINK_AUDIO_FM_STATUS LINK_REG(0x0038) +#define SER_RKLINK_FIFO_STATUS LINK_REG(0x003C) +#define SER_RKLINK_SOURCE_IRQ_EN LINK_REG(0x0040) + +#define SER_RKLINK_TRAIN_CTRL LINK_REG(0x0044) +#define SER_RKLINK_I2C_CFG LINK_REG(0x00C0) +#define SER_RKLINK_SPI_CFG LINK_REG(0x00C4) +#define SER_RKLINK_UART_CFG LINK_REG(0x00C8) + +#define SER_RKLINK_GPIO_CFG LINK_REG(0x00CC) + #define GPIO_GROUP1_EN BIT(17) + #define GPIO_GROUP0_EN BIT(16) + +#define SER_RKLINK_IO_DEF_INV_CFG LINK_REG(0x00D0) + +#define OTHER_LANE_ACTIVE(x) HIWORD_UPDATE(x, 12, 12) +#define FORWARD_NON_ACK(x) HIWORD_UPDATE(x, 11, 11) + +#define SER_RKLINK_DISP_DSI_SPLIT BIT(1) +#define SER_RKLINK_DISP_MIRROR BIT(2) +#define SER_RKLINK_DISP_DUAL_CHANNEL BIT(3) + +#define PCS_REG(id, x) ((x) + RKX110_SER_PCS0_BASE + (id) * RKX110_SER_PCS_OFFSET) + +#define PCS_REG00(id) PCS_REG(id, 0x00) + #define PCS_DUAL_LANE_MODE_EN HIWORD_UPDATE(1, GENMASK(12, 12), 12) + #define PCS_AUTO_START_EN HIWORD_UPDATE(1, GENMASK(3, 3), 3) + #define PCS_EN_MASK HIWORD_MASK(2, 2) + #define PCS_EN HIWORD_UPDATE(1, GENMASK(2, 2), 2) + #define PCS_DISABLE HIWORD_UPDATE(0, GENMASK(2, 2), 2) + #define PCS_ECU_MODE HIWORD_UPDATE(0, GENMASK(2, 2), 1) + #define PCS_REMOTE_MODE HIWORD_UPDATE(1, GENMASK(2, 2), 1) + #define PCS_SAFE_MODE_EN HIWORD_UPDATE(1, GENMASK(0, 0), 0) + +#define PCS_REG04(id) PCS_REG(id, 0x04) +#define PCS_REG08(id) PCS_REG(id, 0x08) + #define VIDEO_SUS_EN(x) HIWORD_UPDATE(x, GENMASK(15, 15), 15) +#define PCS_REG10(id) PCS_REG(id, 0x10) +#define PCS_REG14(id) PCS_REG(id, 0x14) +#define PCS_REG18(id) PCS_REG(id, 0x18) +#define PCS_REG1C(id) PCS_REG(id, 0x1C) +#define PCS_REG20(id) PCS_REG(id, 0x20) +#define PCS_REG24(id) PCS_REG(id, 0x24) +#define PCS_REG28(id) PCS_REG(id, 0x28) +#define PCS_REG30(id) PCS_REG(id, 0x30) +#define PCS_REG34(id) PCS_REG(id, 0x34) +#define PCS_REG40(id) PCS_REG(id, 0x40) + +#define PMA_REG(id, x) ((x) + RKX110_SER_PMA0_BASE + (id) * RKX110_SER_PMA_OFFSET) + +#define SER_PMA_STATUS(id) PMA_REG(id, 0x00) + #define SER_PMA_FORCE_INIT_STA BIT(8) + +#define SER_PMA_CTRL(id) PMA_REG(id, 0x04) + #define SER_PMA_FORCE_INIT_MASK HIWORD_MASK(8, 8) + #define SER_PMA_FORCE_INIT_EN HIWORD_UPDATE(1, BIT(8), 8) + #define SER_PMA_FORCE_INIT_DISABLE HIWORD_UPDATE(0, BIT(8), 8) + #define SER_PMA_DUAL_CHANNEL HIWORD_UPDATE(1, BIT(3), 3) + #define SER_PMA_INIT_CNT_CLR_MASK HIWORD_MASK(2, 2) + #define SER_PMA_INIT_CNT_CLR HIWORD_UPDATE(1, BIT(2), 2) + +#define SER_PMA_LOAD00(id) PMA_REG(id, 0x10) + #define PMA_RATE_MODE_MASK HIWORD_MASK(2, 0) + #define PMA_FDR_MODE HIWORD_UPDATE(1, GENMASK(2, 0), 0) + #define PMA_HDR_MODE HIWORD_UPDATE(2, GENMASK(2, 0), 0) + #define PMA_QDR_MODE HIWORD_UPDATE(4, GENMASK(2, 0), 0) + +#define SER_PMA_LOAD01(id) PMA_REG(id, 0x14) +#define SER_PMA_LOAD02(id) PMA_REG(id, 0x18) +#define SER_PMA_LOAD03(id) PMA_REG(id, 0x1C) +#define SER_PMA_LOAD04(id) PMA_REG(id, 0x20) + #define PMA_PLL_DIV_MASK HIWORD_MASK(14, 0) + #define PLL_I_POST_DIV(x) HIWORD_UPDATE(x, GENMASK(14, 10), 10) + #define PLL_F_POST_DIV(x) HIWORD_UPDATE(x, GENMASK(9, 0), 0) + #define PMA_PLL_DIV(x) HIWORD_UPDATE(x, GENMASK(14, 0), 0) + +#define SER_PMA_LOAD05(id) PMA_REG(id, 0x2C) + #define PMA_PLL_REFCLK_DIV_MASK HIWORD_MASK(3, 0) + #define PMA_PLL_REFCLK_DIV(x) HIWORD_UPDATE(x, GENMASK(3, 0), 0) + +#define SER_PMA_LOAD06(id) PMA_REG(id, 0x28) +#define SER_PMA_LOAD07(id) PMA_REG(id, 0x2C) +#define SER_PMA_LOAD08(id) PMA_REG(id, 0x30) + #define PMA_FCK_VCO_MASK HIWORD_MASK(15, 15) + #define PMA_FCK_VCO HIWORD_UPDATE(1, BIT(15), 15) + #define PMA_FCK_VCO_DIV2 HIWORD_UPDATE(0, BIT(15), 15) + +#define SER_PMA_LOAD09(id) PMA_REG(id, 0x34) + #define PMA_PLL_DIV4_MASK HIWORD_MASK(12, 12) + #define PMA_PLL_DIV4 HIWORD_UPDATE(1, GENMASK(12, 12), 12) + #define PMA_PLL_DIV8 HIWORD_UPDATE(0, GENMASK(12, 12), 12) + +#define SER_PMA_LOAD0A(id) PMA_REG(id, 0x38) + #define PMA_CLK_8X_DIV_MASK HIWORD_MASK(7, 1) + #define PMA_CLK_8X_DIV(x) HIWORD_UPDATE(x, GENMASK(7, 1), 1) + +enum { + SER_LINK_CH_ID0 = 0, + SER_LINK_CH_ID1, + SER_LINK_CH_ID2, + SER_LINK_CH_ID3, +}; + +static const struct rk_serdes_pt ser_pt[] = { + { + /* gpi_gpo_0 */ + .en_reg = SER_RKLINK_GPIO_CFG, + .en_mask = 0x10001, + .en_val = 0x10001, + .dir_reg = SER_RKLINK_GPIO_CFG, + .dir_mask = 0x10, + .dir_val = 0x10, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_A5, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC6, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC5, + }, + }, + }, { + /* gpi_gpo_1 */ + .en_reg = SER_RKLINK_GPIO_CFG, + .en_mask = 0x10002, + .en_val = 0x10002, + .dir_reg = SER_RKLINK_GPIO_CFG, + .dir_mask = 0x20, + .dir_val = 0x20, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_A6, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC6, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC5, + }, + }, + }, { + /* gpi_gpo_2 */ + .en_reg = SER_RKLINK_GPIO_CFG, + .en_mask = 0x10004, + .en_val = 0x10004, + .dir_reg = SER_RKLINK_GPIO_CFG, + .dir_mask = 0x40, + .dir_val = 0x40, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_A7, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC6, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC5, + }, + }, + }, { + /* gpi_gpo_3 */ + .en_reg = SER_RKLINK_GPIO_CFG, + .en_mask = 0x10008, + .en_val = 0x10008, + .dir_reg = SER_RKLINK_GPIO_CFG, + .dir_mask = 0x80, + .dir_val = 0x80, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_B0, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC6, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC5, + }, + }, + }, { + /* gpi_gpo_4 */ + .en_reg = SER_RKLINK_GPIO_CFG, + .en_mask = 0x20100, + .en_val = 0x20100, + .dir_reg = SER_RKLINK_GPIO_CFG, + .dir_mask = 0x1000, + .dir_val = 0x1000, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_B3, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, + }, + }, + }, { + /* gpi_gpo_5 */ + .en_reg = SER_RKLINK_GPIO_CFG, + .en_mask = 0x20200, + .en_val = 0x20200, + .dir_reg = SER_RKLINK_GPIO_CFG, + .dir_mask = 0x2000, + .dir_val = 0x2000, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_B4, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, + }, + }, + }, { + /* gpi_gpo_6 */ + .en_reg = SER_RKLINK_GPIO_CFG, + .en_mask = 0x20400, + .en_val = 0x20400, + .dir_reg = SER_RKLINK_GPIO_CFG, + .dir_mask = 0x4000, + .dir_val = 0x4000, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_B5, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, + }, + }, + }, { + /* passthrough irq */ + .en_reg = SER_RKLINK_GPIO_CFG, + .en_mask = 0x20800, + .en_val = 0x20800, + .dir_reg = SER_RKLINK_GPIO_CFG, + .dir_mask = 0x8000, + .dir_val = 0x8000, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_A4, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC1, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, + }, + }, + }, { + /* passthrough uart0 */ + .en_reg = SER_RKLINK_UART_CFG, + .en_mask = 0x1, + .en_val = 0x1, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_A5 | RK_SERDES_GPIO_PIN_A6, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC4, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, + }, + }, + }, { + /* passthrough uart1 */ + .en_reg = SER_RKLINK_UART_CFG, + .en_mask = 0x2, + .en_val = 0x2, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_A7 | RK_SERDES_GPIO_PIN_B0, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC4, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, + }, + }, + }, { + /* passthrough spi */ + .en_reg = SER_RKLINK_SPI_CFG, + .en_mask = 0x4, + .en_val = 0x4, + .dir_reg = SER_RKLINK_SPI_CFG, + .dir_mask = 0x1, + .dir_val = 0x0, + .configs = 1, + { + { + .bank = RK_SERDES_SER_GPIO_BANK0, + .pin = RK_SERDES_GPIO_PIN_A5 | RK_SERDES_GPIO_PIN_A6 | + RK_SERDES_GPIO_PIN_A7 | RK_SERDES_GPIO_PIN_B0, + .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, + .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC1, + }, + }, + }, +}; + +static int rk_serdes_get_stream_source(struct rk_serdes *serdes, int local_port) +{ + if (serdes->stream_type == STREAM_DISPLAY) { + if (local_port & RK_SERDES_RGB_RX) + return DISPLAY_SRC_RGB; + else if (local_port & RK_SERDES_LVDS_RX0) + return DISPLAY_SRC_LVDS0; + else if (local_port & RK_SERDES_LVDS_RX1) + return DISPLAY_SRC_LVDS1; + else if (local_port & RK_SERDES_DUAL_LVDS_RX) + return DISPLAY_SRC_DUAL_LDVS; + else if (local_port & RK_SERDES_DSI_RX0) + return DISPLAY_SRC_DSI; + else if (local_port & RK_SERDES_DSI_RX1) + return DISPLAY_SRC_DSI; + } else { + return CAMERA_SRC_CSI; + } + + return 0; +} + +void rkx110_set_stream_source(struct rk_serdes *serdes, int local_port, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val, rx_src; + + serdes->i2c_read_reg(client, RKLINK_TX_VIDEO_CTRL, &val); + val &= ~SOURCE_ID_MASK; + rx_src = rk_serdes_get_stream_source(serdes, local_port); + val |= rx_src; + serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val); +} + +static int rk_serdes_link_tx_ctrl_enable(struct rk_serdes *serdes, + struct rk_serdes_route *route, + u8 remote_id) +{ + struct hwclk *hwclk = serdes->chip[remote_id].hwclk; + struct i2c_client *client; + u32 ctrl_val, val; + u32 rx_src; + u32 stream_type; + + if (route->stream_type == STREAM_DISPLAY) { + client = serdes->chip[DEVICE_LOCAL].client; + stream_type = SER_STREAM_DISPLAY; + } else { + client = serdes->chip[remote_id].client; + stream_type = SER_STREAM_CAMERA; + } + + serdes->i2c_read_reg(client, RKLINK_TX_SERDES_CTRL, &ctrl_val); + + ctrl_val &= ~(SER_EN | SERDES_DUAL_LANE_EN | SER_CH1_EN | SERDES_MIRROR_EN | + CH1_LVDS_SEL_EN); + ctrl_val |= stream_type; + if (serdes->route_flag & ROUTE_MULTI_LANE) + ctrl_val |= SERDES_DUAL_LANE_EN; + if (serdes->route_flag & ROUTE_MULTI_CHANNEL) + ctrl_val |= SER_CH1_EN; + if (serdes->route_flag & ROUTE_MULTI_MIRROR) + ctrl_val |= SERDES_MIRROR_EN; + if (serdes->route_flag & ROUTE_MULTI_LVDS_INPUT) + ctrl_val |= CH1_LVDS_SEL_EN; + + serdes->i2c_write_reg(client, RKLINK_TX_SERDES_CTRL, ctrl_val); + + serdes->i2c_read_reg(client, RKLINK_TX_VIDEO_CTRL, &val); + rx_src = rk_serdes_get_stream_source(serdes, route->local_port0); + val |= rx_src; + serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val); + + if (route->local_port0 & RK_SERDES_DUAL_LVDS_RX) { + hwclk_set_rate(hwclk, RKX110_CPS_CLK_2X_LVDS_RKLINK_TX, route->vm.pixelclock); + dev_info(serdes->dev, "RKX110_CPS_CLK_2X_LVDS_RKLINK_TX:%d\n", + hwclk_get_rate(hwclk, RKX110_CPS_CLK_2X_LVDS_RKLINK_TX)); + } + + ctrl_val |= SER_EN; + serdes->i2c_write_reg(client, RKLINK_TX_SERDES_CTRL, ctrl_val); + + return 0; +} + +static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, + int id) +{ + struct videomode *vm = &route->vm; + struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client; + struct hwclk *hwclk = serdes->chip[DEVICE_LOCAL].hwclk; + int delay_length; + u32 value, type; + + if (id == 0) { + hwclk_set_rate(hwclk, RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX, + route->vm.pixelclock); + dev_info(serdes->dev, "RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX:%d\n", + hwclk_get_rate(hwclk, RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX)); + } else if (id == 1) { + hwclk_set_rate(hwclk, RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX, + route->vm.pixelclock); + dev_info(serdes->dev, "RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX:%d\n", + hwclk_get_rate(hwclk, RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX)); + + } else { + return 0; + } + + /* config SER_RKLINK_DSI_REC1 */ + value = DSI_FRAME_MODE(route->frame_mode); + value |= DSI_HFP(vm->hfront_porch); + value |= DSI_HBP(vm->hback_porch); + serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC1(id), value); + + /* config SER_RKLINK_DSI_REC2 */ + value = DSI_VFP(vm->vfront_porch); + value |= DSI_VBP(vm->vback_porch); + value |= DSI_VSA(vm->vsync_len); + serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC2(id), value); + + if (id) + type = (serdes->route_flag & ROUTE_MULTI_CHANNEL) ? DSI_0_DST(0) : DSI_0_DST(2); + else + type = (serdes->route_flag & ROUTE_MULTI_CHANNEL) ? DSI_0_DST(3) : DSI_0_DST(1); + + serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC2(0), DSI_0_DST_MASK, type); + + /* config SER_RKLINK_DSI_REC3 */ + if (serdes->dsi_rx.mode_flags & SERDES_MIPI_DSI_MODE_VIDEO) + delay_length = vm->hsync_len + vm->hback_porch + + vm->hactive + vm->hfront_porch; + else + delay_length = (vm->vfront_porch + 1) * (vm->hsync_len + + vm->hback_porch + vm->hactive + vm->hfront_porch); + + value = DSI_DELAY_LENGTH(delay_length); + value |= DSI_HSA(vm->hsync_len); + + serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC3(id), value); + + /* config SER_RKLINK_DSI_REC0 */ + value = DSI_REC_START; + if (!(serdes->dsi_rx.mode_flags & SERDES_MIPI_DSI_MODE_VIDEO)) + value |= DSI_CMD_TYPE; + + value |= DSI_HACT(vm->hactive); + value |= DSI_VACT(vm->vactive); + serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC0(id), value); + + return 0; +} + +static int rk110_linktx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route) +{ + u8 remote_id = 0; + + rk_serdes_link_tx_ctrl_enable(serdes, route, remote_id); + + if (route->local_port0 & RK_SERDES_DSI_RX0) { + rk_serdes_link_tx_dsi_enable(serdes, route, 0); + if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT) + rk_serdes_link_tx_dsi_enable(serdes, route, 1); + } + + if (route->local_port0 & RK_SERDES_DSI_RX1) { + rk_serdes_link_tx_dsi_enable(serdes, route, 1); + if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT) + rk_serdes_link_tx_dsi_enable(serdes, route, 0); + } + + return 0; +} + +static int rk110_ser_pcs_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 pcs_id) +{ + struct i2c_client *client; + u8 remote_id = 0; + + if (route->stream_type == STREAM_DISPLAY) + client = serdes->chip[DEVICE_LOCAL].client; + else + client = serdes->chip[remote_id].client; + + if (serdes->version == SERDES_V1) + serdes->i2c_write_reg(client, PCS_REG08(pcs_id), VIDEO_SUS_EN(0)); + + return 0; +} + +static int rk110_ser_pma_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 pcs_id) +{ + return 0; +} + +int rkx110_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route) +{ + rk110_linktx_cfg(serdes, route); + rk110_ser_pcs_cfg(serdes, route, 0); + rk110_ser_pma_cfg(serdes, route, 0); + if (serdes->route_flag & ROUTE_MULTI_LANE) { + rk110_ser_pcs_cfg(serdes, route, 1); + rk110_ser_pma_cfg(serdes, route, 1); + } + + return 0; +} + +void rkx110_linktx_video_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, VIDEO_EN, enable ? VIDEO_EN : 0); +} + +void rkx110_linktx_channel_enable(struct rk_serdes *serdes, u8 ch_id, u8 dev_id, bool enable) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + if (ch_id) + serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, STOP_VIDEO_CH1, + enable ? 0 : STOP_VIDEO_CH1); + else + serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, STOP_VIDEO_CH0, + enable ? 0 : STOP_VIDEO_CH0); +} + +void rkx110_linktx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32 func_id, + bool is_rx) +{ + struct i2c_client *client = serdes->chip[client_id].client; + const struct rk_serdes_pt_pin *pt_pin = ser_pt[func_id].pt_pins; + int i; + + /* config link passthrough */ + serdes->i2c_update_bits(client, ser_pt[func_id].en_reg, ser_pt[func_id].en_mask, + ser_pt[func_id].en_val); + if (ser_pt[func_id].en_reg) + serdes->i2c_update_bits(client, ser_pt[func_id].dir_reg, ser_pt[func_id].dir_mask, + is_rx ? ser_pt[func_id].dir_val : ~ser_pt[func_id].dir_val); + + /* config passthrough pinctrl */ + for (i = 0; i < ser_pt[func_id].configs; i++) { + serdes->set_hwpin(serdes, client, PIN_RKX110, pt_pin[i].bank, pt_pin[i].pin, + is_rx ? pt_pin[i].incfgs : pt_pin[i].outcfgs); + } +} + +void rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id) +{ + struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client; + u32 val; + int ret; + int sta; + + if (id) + sta = SER_PCS1_READY; + else + sta = SER_PCS0_READY; + + ret = read_poll_timeout(serdes->i2c_read_reg, ret, + !(ret < 0) && (val & sta), + 1000, USEC_PER_SEC, false, client, + SER_GRF_SOC_STATUS0, &val); + if (ret < 0) + dev_err(&client->dev, "wait link ready timeout: 0x%08x\n", val); + else + dev_info(&client->dev, "link success: 0x%08x\n", val); +} + +void rkx110_pma_set_rate(struct rk_serdes *serdes, struct rk_serdes_pma_pll *pll, + u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val; + + serdes->i2c_read_reg(client, SER_PMA_STATUS(pcs_id), &val); + if (val & SER_PMA_FORCE_INIT_STA) + serdes->i2c_update_bits(client, SER_PMA_CTRL(pcs_id), SER_PMA_INIT_CNT_CLR_MASK, + SER_PMA_INIT_CNT_CLR); + + if (pll->force_init_en) + serdes->i2c_update_bits(client, SER_PMA_CTRL(pcs_id), SER_PMA_FORCE_INIT_MASK, + SER_PMA_FORCE_INIT_EN); + else + serdes->i2c_update_bits(client, SER_PMA_CTRL(pcs_id), SER_PMA_FORCE_INIT_MASK, + SER_PMA_FORCE_INIT_DISABLE); + + if (pll->rate_mode == FDR_RATE_MODE) + serdes->i2c_update_bits(client, SER_PMA_LOAD00(pcs_id), PMA_RATE_MODE_MASK, + PMA_FDR_MODE); + else if (pll->rate_mode == HDR_RATE_MODE) + serdes->i2c_update_bits(client, SER_PMA_LOAD00(pcs_id), PMA_RATE_MODE_MASK, + PMA_HDR_MODE); + else + serdes->i2c_update_bits(client, SER_PMA_LOAD00(pcs_id), PMA_RATE_MODE_MASK, + PMA_QDR_MODE); + + serdes->i2c_update_bits(client, SER_PMA_LOAD04(pcs_id), PMA_PLL_DIV_MASK, + PMA_PLL_DIV(pll->pll_div)); + serdes->i2c_update_bits(client, SER_PMA_LOAD05(pcs_id), PMA_PLL_REFCLK_DIV_MASK, + PMA_PLL_REFCLK_DIV(pll->pll_refclk_div)); + + if (pll->pll_fck_vco_div2) + serdes->i2c_update_bits(client, SER_PMA_LOAD08(pcs_id), PMA_FCK_VCO_MASK, + PMA_FCK_VCO_DIV2); + else + serdes->i2c_update_bits(client, SER_PMA_LOAD08(pcs_id), PMA_FCK_VCO_MASK, + PMA_FCK_VCO); + + if (pll->pll_div4) + serdes->i2c_update_bits(client, SER_PMA_LOAD09(pcs_id), PMA_PLL_DIV4_MASK, + PMA_PLL_DIV4); + else + serdes->i2c_update_bits(client, SER_PMA_LOAD09(pcs_id), PMA_PLL_DIV4_MASK, + PMA_PLL_DIV8); + + serdes->i2c_update_bits(client, SER_PMA_LOAD0A(pcs_id), PMA_CLK_8X_DIV_MASK, + PMA_CLK_8X_DIV(pll->clk_div)); +} + +void rkx110_pcs_enable(struct rk_serdes *serdes, bool enable, u8 pcs_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + dev_info(serdes->dev, "%s: %d\n", __func__, enable); + + if (enable) + serdes->i2c_update_bits(client, PCS_REG00(pcs_id), PCS_EN_MASK, PCS_EN); + else + serdes->i2c_update_bits(client, PCS_REG00(pcs_id), PCS_EN_MASK, PCS_DISABLE); +} + +void rkx110_ser_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 dev_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 mask, val; + + if (pma_id) { + mask = PMA1_EN_MASK; + val = enable ? PMA1_EN : PMA1_DISABLE; + } else { + mask = PMA0_EN_MASK; + val = enable ? PMA0_EN : PMA0_DISABLE; + } + + serdes->i2c_update_bits(client, SER_GRF_SOC_CON7, mask, val); +} diff --git a/drivers/mfd/rkx110_x120/rkx110_reg.h b/drivers/mfd/rkx110_x120/rkx110_reg.h new file mode 100644 index 000000000000..4d6db3d3c326 --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110_reg.h @@ -0,0 +1,515 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Zhang Yubing + */ + +#ifndef _RKX110_REG_H +#define _RKX110_REG_H + +#include + +#define HIWORD_MASK(h, l) (GENMASK(h, l) | GENMASK(h, l) << 16) +#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) +#define HIWORD_UPDATE(v, m, l) (((v) << (l)) | (m << 16)) + +/************** RKX110 SER TX ***************/ +#define RKX110_SER_CRU_BASE 0x00000000 + +#define RKX110_SER_GRF_BASE 0x00010000 +#define GRF_REG(x) ((x) + RKX110_SER_GRF_BASE) +#define SER_GRF_GPIO0A_IOMUX_L GRF_REG(0x0) +#define SER_GRF_GPIO0A_IOMUX_H GRF_REG(0x4) +#define SER_GRF_GPIO0B_IOMUX_L GRF_REG(0x8) +#define SER_GRF_GPIO0B_IOMUX_H GRF_REG(0xC) +#define SER_GRF_GPIO0C_IOMUX_L GRF_REG(0x10) +#define SER_GRF_GPIO0C_IOMUX_H GRF_REG(0x14) +#define SER_GRF_GPIO0A_PULL_EN GRF_REG(0x20) +#define SER_GRF_GPIO0B_PULL_EN GRF_REG(0x24) +#define SER_GRF_GPIO0C_PULL_EN GRF_REG(0x28) +#define SER_GRF_GPIO1A_IOMUX GRF_REG(0x80) +#define SER_GRF_GPIO1B_IOMUX GRF_REG(0x84) +#define SER_GRF_GPIO1C_IOMUX GRF_REG(0x88) +#define SER_GRF_GPIO1A_PULL_CFG GRF_REG(0x90) +#define SER_GRF_GPIO1B_PULL_CFG GRF_REG(0x94) +#define SER_GRF_GPIO1C_PULL_CFG GRF_REG(0x98) + +enum { + /* GPIO0A_IOMUX_H */ + GPIO0A7_SHIFT = 12, + GPIO0A7_MASK = GENMASK(14, 12), + GPIO0A7_GPIO = 0, + GPIO0A7_SPI_MISO_M, + GPIO0A7_SPI_MISO_S, + GPIO0A7_UART1_TX_M, + GPIO0A7_UART1_TX_S, + GPIO0A7_GPO_2, + GPIO0A7_GPI_2, + GPIO0A7_TP15, + + GPIO0A6_SHIFT = 8, + GPIO0A6_MASK = GENMASK(10, 8), + GPIO0A6_GPIO = 0, + GPIO0A6_SPI_MOSI_M, + GPIO0A6_SPI_MOSI_S, + GPIO0A6_UART0_RX_M, + GPIO0A6_UART0_RX_S, + GPIO0A6_GPO_1, + GPIO0A6_GPI_1, + GPIO0A6_I2C_DEBUG_SDA, + + GPIO0A5_SHIFT = 4, + GPIO0A5_MASK = GENMASK(6, 4), + GPIO0A5_GPIO = 0, + GPIO0A5_SPI_CLK_M, + GPIO0A5_SPI_CLK_S, + GPIO0A5_UART0_TX_M, + GPIO0A5_UART0_TX_S, + GPIO0A5_GPO_0, + GPIO0A5_GPI_0, + GPIO0A5_I2C_DEBUG_SCL, + + GPIO0A4_SHIFT = 0, + GPIO0A4_MASK = GENMASK(2, 0), + GPIO0A4_GPIO = 0, + GPIO0A4_INT_RX, + GPIO0A4_INT_TX, + + /* GPIO0B_IOMUX_L */ + GPIO0B3_SHIFT = 12, + GPIO0B3_MASK = GENMASK(14, 12), + GPIO0B3_GPIO = 0, + GPIO0B3_I2S_SDI0, + GPIO0B3_GPI_4, + GPIO0B3_GPO_4, + GPIO0B3_TP2, + + GPIO0B2_SHIFT = 8, + GPIO0B2_MASK = GENMASK(10, 8), + GPIO0B2_GPIO = 0, + GPIO0B2_I2S_LRCK_M, + GPIO0B2_I2S_LRCK_S, + GPIO0B2_TP1, + + GPIO0B1_SHIFT = 4, + GPIO0B1_MASK = GENMASK(6, 4), + GPIO0B1_GPIO = 0, + GPIO0B1_I2S_SCLK_M, + GPIO0B1_I2S_SCLK_S, + GPIO0B1_TP0, + + GPIO0B0_SHIFT = 0, + GPIO0B0_MASK = GENMASK(2, 0), + GPIO0B0_GPIO = 0, + GPIO0B0_SPI_CSN_M, + GPIO0B0_SPI_CSN_S, + GPIO0B0_UART1_RX_M, + GPIO0B0_UART1_RX_S, + GPIO0B0_GPO_3, + GPIO0B0_GPI_3, + GPIO0B0_TP16, + + /* GPIO0B_IOMUX_H */ + GPIO0B7_SHIFT = 12, + GPIO0B7_MASK = GENMASK(14, 12), + GPIO0B7_GPIO = 0, + GPIO0B7_I2S_MCLK, + GPIO0B7_TEST_CLK_OUT, + GPIO0B7_MIPI_MCLK0, + GPIO0B7_TP6, + + GPIO0B6_SHIFT = 8, + GPIO0B6_MASK = GENMASK(10, 8), + GPIO0B6_GPIO = 0, + GPIO0B6_I2S_SDI3, + GPIO0B6_I2S_SDO0, + GPIO0B6_TP5, + + GPIO0B5_SHIFT = 4, + GPIO0B5_MASK = GENMASK(6, 4), + GPIO0B5_GPIO = 0, + GPIO0B5_I2S_SDI2, + GPIO0B5_GPI_6, + GPIO0B5_GPO_6, + GPIO0B5_I2C1_SDA_M, + GPIO0B5_I2C1_SDA_S, + GPIO0B5_TP4, + + GPIO0B4_SHIFT = 0, + GPIO0B4_MASK = GENMASK(2, 0), + GPIO0B4_GPIO = 0, + GPIO0B4_I2S_SDI1, + GPIO0B4_GPI_5, + GPIO0B4_GPO_5, + GPIO0B5_I2C1_SCL_M, + GPIO0B5_I2C1_SCL_S, + GPIO0B5_TP3, + + /* GPIO0C_IOMUX_L */ + GPIO0C4_SHIFT = 12, + GPIO0C4_MASK = GENMASK(14, 12), + GPIO0C4_GPIO = 0, + GPIO0C4_LCDC_D0, + GPIO0C4_CIF_D0, + GPIO0C4_TP11, + + GPIO0C3_SHIFT = 9, + GPIO0C3_MASK = GENMASK(11, 9), + GPIO0C3_GPIO = 0, + GPIO0C3_LCDC_DEN, + GPIO0C3_CIF_CLK_OUT, + GPIO0C3_MIPI_CLK1, + GPIO0C3_TP10, + + GPIO0C2_SHIFT = 6, + GPIO0C2_MASK = GENMASK(8, 6), + GPIO0C2_GPIO = 0, + GPIO0C2_LCDC_HSYNC, + GPIO0C2_CIF_HSYNC, + GPIO0C2_TP9, + + GPIO0C1_SHIFT = 3, + GPIO0C1_MASK = GENMASK(5, 3), + GPIO0C1_GPIO = 0, + GPIO0C1_LCDC_VSYNC, + GPIO0C1_CIF_VSYNC, + GPIO0C1_TP8, + + GPIO0C0_SHIFT = 0, + GPIO0C0_MASK = GENMASK(2, 0), + GPIO0C0_GPIO = 0, + GPIO0C0_LCDC_CLK, + GPIO0C0_CIF_CLK, + GPIO0C0_TP7, + + /* GPIO0C_IOMUX_H */ + GPIO0C7_SHIFT = 6, + GPIO0C7_MASK = GENMASK(8, 6), + GPIO0C7_GPIO = 0, + GPIO0C7_LCDC_D3, + GPIO0C7_CIF_D3, + GPIO0C7_TP14, + + GPIO0C6_SHIFT = 3, + GPIO0C6_MASK = GENMASK(5, 3), + GPIO0C6_GPIO = 0, + GPIO0C6_LCDC_D2, + GPIO0C6_CIF_D2, + GPIO0C6_TP13, + + GPIO0C5_SHIFT = 0, + GPIO0C5_MASK = GENMASK(2, 0), + GPIO0C5_GPIO = 0, + GPIO0C5_LCDC_D1, + GPIO0C5_CIF_D1, + GPIO0C5_TP12, + + /* GPIO1A_IOMUX */ + GPIO1A7_SHIFT = 14, + GPIO1A7_MASK = GENMASK(15, 14), + GPIO1A7_GPIO = 0, + GPIO1A7_LCDC_D11, + GPIO1A7_CIF_D11, + GPIO1A7_MIPI0_RX2_P, + + GPIO1A6_SHIFT = 12, + GPIO1A6_MASK = GENMASK(13, 12), + GPIO1A6_GPIO = 0, + GPIO1A6_LCDC_D10, + GPIO1A6_CIF_D10, + GPIO1A6_MIPI0_RX2_N, + + GPIO1A5_SHIFT = 10, + GPIO1A5_MASK = GENMASK(11, 10), + GPIO1A5_GPIO = 0, + GPIO1A5_LCDC_D9, + GPIO1A5_CIF_D9, + GPIO1A5_MIPI0_TCK_P, + + GPIO1A4_SHIFT = 8, + GPIO1A4_MASK = GENMASK(9, 8), + GPIO1A4_GPIO = 0, + GPIO1A4_LCDC_D8, + GPIO1A4_CIF_D8, + GPIO1A4_MIPI0_TCK_N, + + GPIO1A3_SHIFT = 6, + GPIO1A3_MASK = GENMASK(7, 6), + GPIO1A3_GPIO = 0, + GPIO1A3_LCDC_D7, + GPIO1A3_CIF_D7, + GPIO1A3_MIPI0_RX1_P, + + GPIO1A2_SHIFT = 4, + GPIO1A2_MASK = GENMASK(5, 4), + GPIO1A2_GPIO = 0, + GPIO1A2_LCDC_D6, + GPIO1A2_CIF_D6, + GPIO1A2_MIPI0_RX1_N, + + GPIO1A1_SHIFT = 2, + GPIO1A1_MASK = GENMASK(3, 2), + GPIO1A1_GPIO = 0, + GPIO1A1_LCDC_D5, + GPIO1A1_CIF_D5, + GPIO1A1_MIPI0_RX0_P, + + GPIO1A0_SHIFT = 0, + GPIO1A0_MASK = GENMASK(1, 0), + GPIO1A0_GPIO = 0, + GPIO1A0_LCDC_D4, + GPIO1A0_CIF_D4, + GPIO1A0_MIPI0_RX0_N, + + /* GPIO1B_IOMUX */ + GPIO1B7_SHIFT = 14, + GPIO1B7_MASK = GENMASK(15, 14), + GPIO1B7_GPIO = 0, + GPIO1B7_LCDC_D19, + GPIO1B7_CIF_D19, + GPIO1B7_MIPI1_TCK_P, + + GPIO1B6_SHIFT = 12, + GPIO1B6_MASK = GENMASK(13, 12), + GPIO1B6_GPIO = 0, + GPIO1B6_LCDC_D18, + GPIO1B6_CIF_D18, + GPIO1B6_MIPI1_TCK_N, + + GPIO1B5_SHIFT = 10, + GPIO1B5_MASK = GENMASK(11, 10), + GPIO1B5_GPIO = 0, + GPIO1B5_LCDC_D17, + GPIO1B5_CIF_D17, + GPIO1B5_MIPI1_RX1_P, + + GPIO1B4_SHIFT = 8, + GPIO1B4_MASK = GENMASK(9, 8), + GPIO1B4_GPIO = 0, + GPIO1B4_LCDC_D16, + GPIO1B4_CIF_D16, + GPIO1B4_MIPI1_RX1_N, + + GPIO1B3_SHIFT = 6, + GPIO1B3_MASK = GENMASK(7, 6), + GPIO1B3_GPIO = 0, + GPIO1B3_LCDC_D15, + GPIO1B3_CIF_D15, + GPIO1B3_MIPI1_RX0_P, + + GPIO1B2_SHIFT = 4, + GPIO1B2_MASK = GENMASK(5, 4), + GPIO1B2_GPIO = 0, + GPIO1B2_LCDC_D14, + GPIO1B2_CIF_D14, + GPIO1B2_MIPI1_RX0_N, + + GPIO1B1_SHIFT = 2, + GPIO1B1_MASK = GENMASK(3, 2), + GPIO1B1_GPIO = 0, + GPIO1B1_LCDC_D13, + GPIO1B1_CIF_D13, + GPIO1B1_MIPI0_RX3_P, + + GPIO1B0_SHIFT = 0, + GPIO1B0_MASK = GENMASK(1, 0), + GPIO1B0_GPIO = 0, + GPIO1B0_LCDC_D12, + GPIO1B0_CIF_D12, + GPIO1B0_MIPI0_RX3_N, + + /* GPIO1C_IOMUX */ + GPIO1C3_SHIFT = 6, + GPIO1C3_MASK = GENMASK(7, 6), + GPIO1C3_GPIO = 0, + GPIO1C3_LCDC_D23, + GPIO1C3_CIF_D23, + GPIO1C3_MIPI1_RX3_P, + + GPIO1C2_SHIFT = 4, + GPIO1C2_MASK = GENMASK(5, 4), + GPIO1C2_GPIO = 0, + GPIO1C2_LCDC_D22, + GPIO1C2_CIF_D22, + GPIO1C2_MIPI1_RX3_N, + + GPIO1C1_SHIFT = 2, + GPIO1C1_MASK = GENMASK(3, 2), + GPIO1C1_GPIO = 0, + GPIO1C1_LCDC_D21, + GPIO1C1_CIF_D21, + GPIO1C1_MIPI1_RX2_P, + + GPIO1C0_SHIFT = 0, + GPIO1C0_MASK = GENMASK(1, 0), + GPIO1C0_GPIO = 0, + GPIO1C0_LCDC_D20, + GPIO1C0_CIF_D20, + GPIO1C0_MIPI1_RX2_N, +}; + +#define SER_GRF_SOC_CON0 GRF_REG(0x100) +#define SER_GRF_SOC_CON1 GRF_REG(0x104) +#define SER_GRF_SOC_CON2 GRF_REG(0x108) +#define SER_GRF_SOC_CON3 GRF_REG(0x10C) +#define SER_GRF_SOC_CON4 GRF_REG(0x110) +#define SER_GRF_SOC_CON5 GRF_REG(0x114) +#define SER_GRF_SOC_CON6 GRF_REG(0x118) +#define SER_GRF_SOC_CON7 GRF_REG(0x11C) +#define SER_GRF_SOC_STATUS0 GRF_REG(0x160) + +enum { + /* SOC_CON0 */ + LVDS_ALIGN_MODE_SHIFT = 13, + LVDS_ALIGN_MODE_MASK = GENMASK(14, 13), + LVDS_ALIGN_8BIT = 0, + LVDS_ALIGN_10BIT = 0, + LVDS_ALIGN_12BIT = 0, + + LVDS_ALIGN_EN_SHIFT = 12, + LVDS_ALIGN_EN_MASK = GENMASK(12, 12), + LVDS_ALIGN_DISABLE = 0, + LVDS_ALIGN_EN, + + /* SOC_CON2 */ + LVDS1_MSB_SHIFT = 5, + LVDS1_MSB_MASK = GENMASK(5, 5), + LVDS_LSB = 0, + LVDS_MSB, + + LVDS1_FORMAT_SHIFT = 3, + LVDS1_FORMAT_MASK = GENMASK(4, 3), + LVDS_FORMAT_VESA_24BIT = 0, + LVDS_FORMAT_JEIDA_24BIT, + LVDS_FORMAT_JEIDA_18BIT, + LVDS_FORMAT_VESA_18BIT, + + LVDS0_MSB_SHIFT = 2, + LVDS0_MSB_MASK = GENMASK(2, 2), + + LVDS0_FORMAT_SHIFT = 0, + LVDS0_FORMAT_MASK = GENMASK(1, 0), + + /* SOC_CON3 */ + AUDIO_PCS_SEL_SHIFT = 15, + AUDIO_PCS_SEL_MASK = GENMASK(15, 15), + AUDIO_SEL_PCS0 = 0, + AUDIO_SEL_PCS1 = 1, + + CMD_PCS_SEL_SHIFT = 14, + CMD_PCS_SEL_MASK = GENMASK(14, 14), + CMD_SEL_PCS0 = 0, + CMD_SEL_PCS1 = 1, + + /* SOC_CON4 */ + LVDS1_LINK_SEL_SHIFT = 15, + LVDS1_LINK_SEL_MASK = GENMASK(15, 15), + /* enable lvds source from pattern generation */ + LINK_SEL_PG_DISABLE = 0, + LINK_SEL_PG_EN = 1, + + LVDS0_LINK_SEL_SHIFT = 14, + LVDS0_LINK_SEL_MASK = GENMASK(14, 14), + + DSI1_LINK_SEL_SHIFT = 13, + DSI1_LINK_SEL_MASK = GENMASK(13, 13), + + DSI0_LINK_SEL_SHIFT = 12, + DSI0_LINK_SEL_MASK = GENMASK(12, 12), + + RGB_DCLK_BYPASS_SHIFT = 9, + RGB_DCLK_BYPASS_MASK = GENMASK(9, 9), + + RGB_DCLK_DCLK_DLY_SHIFT = 1, + RGB_DCLK_DCLK_DLY_MASK = GENMASK(8, 1), + + RGB_DCLK_INV_SHIFT = 0, + RGB_DCLK_INV_MASK = GENMASK(0, 0), + + /* SOC_CON5 */ + LDO_PLC_SEL_SHIFT = 8, + LDO_PLC_SEL_MASK = GENMASK(8, 8), + LDO_PLC_170 = 0, + LDO_PLC_270, + + LDO_VOL_SEL_SHIFT = 4, + LDO_VOL_SEL_MASK = HIWORD_MASK(7, 4), + LDO_VOL_110 = HIWORD_UPDATE(0, GENMASK(7, 4), 4), + LDO_VOL_115 = HIWORD_UPDATE(1, GENMASK(7, 4), 4), + LDO_VOL_120 = HIWORD_UPDATE(2, GENMASK(7, 4), 4), + LDO_VOL_125 = HIWORD_UPDATE(3, GENMASK(7, 4), 4), + LDO_VOL_130 = HIWORD_UPDATE(4, GENMASK(7, 4), 4), + LDO_VOL_135 = HIWORD_UPDATE(5, GENMASK(7, 4), 4), + LDO_VOL_140 = HIWORD_UPDATE(6, GENMASK(7, 4), 4), + LDO_VOL_145 = HIWORD_UPDATE(4, GENMASK(7, 4), 4), + + LDO_BG_TRIM_SHIFT = 4, + LDO_BG_TRIM_MASK = GENMASK(7, 4), + LDO_BG_TRIM_OUT = 0, + LDO_BG_TRIM_OUT_55_N = 0, + LDO_BG_TRIM_OUT_110_N, + + /* SOC_CON7 */ + PMA_PLL_CTRL_SEL_SHIFT = 15, + PMA_PLL_CTRL_SEL_MASK = GENMASK(15, 15), + PMA_PLL_CTRL_BY_PMA0 = 0, + PMA_PLL_CTRL_BY_PMA1, + + PMA1_EN_SHIFT = 9, + PMA1_EN_MASK = HIWORD_MASK(9, 9), + PMA1_EN = HIWORD_UPDATE(1, BIT(9), 9), + PMA1_DISABLE = HIWORD_UPDATE(0, BIT(9), 9), + + PMA0_EN_SHIFT = 8, + PMA0_EN_MASK = HIWORD_MASK(8, 8), + PMA0_EN = HIWORD_UPDATE(1, BIT(8), 8), + PMA0_DISABLE = HIWORD_UPDATE(0, BIT(8), 8), + + /* SER_GRF_IRQ_EN */ + + /* SER_GRF_SOC_STATUS0 */ + SER_PCS1_READY = BIT(21), + SER_PCS0_READY = BIT(20), +}; + +#define RKX110_CSI2HOST0_BASE 0x00020000 +#define RKX110_CSI2HOST1_BASE 0x00028000 +#define CSI2HOST_N_LANES 0x0004 +#define CSI2HOST_RESETN 0x0010 +#define CSI2HOST_CONTROL 0x0040 +#define SW_DATATYPE_LE(x) UPDATE(x, 31, 26) +#define SW_DATETYPE_LS(x) UPDATE(x, 25, 20) +#define SW_DATETYPE_FE_MASK GENMASK(19, 14) +#define SW_DATETYPE_FE(x) UPDATE(x, 19, 14) +#define SW_DATETYPE_FS_MASK GENMASK(13, 8) +#define SW_DATETYPE_FS(x) UPDATE(x, 13, 8) +#define SW_DSI_EN BIT(4) + +#define RKX110_VICAP_BASE 0x00030000 +#define RKX110_GPIO0_BASE 0x00040000 + + +#define RKX110_DSI_RX0_BASE 0x00060000 +#define RKX110_DSI_RX1_BASE 0x00068000 +#define RKX110_SER_RKLINK_BASE 0x00070000 +#define RKX110_SER_PCS0_BASE 0x00074000 +#define RKX110_SER_PCS1_BASE 0x00075000 +#define RKX110_SER_PCS_OFFSET 0x00001000 +#define RKX110_EFUSE_BASE 0x00800000 +#define RKX110_MIPI_LVDS_RX_PHY0_BASE 0x00090000 +#define RKX110_GRF_MIPI0_BASE 0x000A0000 +#define RKX110_MIPI_LVDS_RX_PHY1_BASE 0x000B0000 +#define RKX110_GRF_MIPI1_BASE 0x000C0000 +#define RKX110_SER_PMA0_BASE 0x000D0000 +#define RKX110_SER_PMA1_BASE 0x000E0000 +#define RKX110_SER_PMA_OFFSET 0x00010000 + +#define RKX110_GPIO1_BASE 0x000F0000 + +#define RKX110_PATTERN_GEN_DSI0_BASE 0x00100000 +#define RKX110_PATTERN_GEN_DSI1_BASE 0x00110000 +#define RKX110_PATTERN_GEN_LVDS0_BASE 0x00120000 +#define RKX110_PATTERN_GEN_LVDS1_BASE 0x00130000 + +#endif diff --git a/drivers/mfd/rkx110_x120/rkx110_x120.h b/drivers/mfd/rkx110_x120/rkx110_x120.h new file mode 100644 index 000000000000..67c2d1fe349d --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110_x120.h @@ -0,0 +1,366 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 Rockchip Electronics Co. Ltd. + * + * Author: Zhang Yubing + */ + +#ifndef _RKX110_X120_H +#define _RKX110_X120_H + +#include +#include +#include +#include