mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
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 <andy.yan@rock-chips.com>
Signed-off-by: Guochun Huang <hero.huang@rock-chips.com>
Signed-off-by: Zhang Yubing <yubing.zhang@rock-chips.com>
Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
Signed-off-by: Tao Huang <huangtao@rock-chips.com>
Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
Signed-off-by: Steven Liu <steven.liu@rock-chips.com>
Change-Id: Ifbf44ff7d5dcab668b50cf101d8dbff10dc71467
This commit is contained in:
@@ -1218,6 +1218,8 @@ config MFD_RK1000
|
|||||||
if you say yes here you get support for the RK1000, with func as
|
if you say yes here you get support for the RK1000, with func as
|
||||||
TVEncoder or CODEC.
|
TVEncoder or CODEC.
|
||||||
|
|
||||||
|
source "drivers/mfd/rkx110_x120/Kconfig"
|
||||||
|
|
||||||
config MFD_RN5T618
|
config MFD_RN5T618
|
||||||
tristate "Ricoh RN5T567/618 PMIC"
|
tristate "Ricoh RN5T567/618 PMIC"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ obj-$(CONFIG_MFD_RK806) += rk806-core.o
|
|||||||
obj-$(CONFIG_MFD_RK806_SPI) += rk806-spi.o
|
obj-$(CONFIG_MFD_RK806_SPI) += rk806-spi.o
|
||||||
obj-$(CONFIG_MFD_RK808) += rk808.o
|
obj-$(CONFIG_MFD_RK808) += rk808.o
|
||||||
obj-$(CONFIG_MFD_RK1000) += rk1000-core.o
|
obj-$(CONFIG_MFD_RK1000) += rk1000-core.o
|
||||||
|
obj-y += rkx110_x120/
|
||||||
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
|
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
|
||||||
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
|
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
|
||||||
obj-$(CONFIG_MFD_SYSCON) += syscon.o
|
obj-$(CONFIG_MFD_SYSCON) += syscon.o
|
||||||
|
|||||||
18
drivers/mfd/rkx110_x120/Kconfig
Normal file
18
drivers/mfd/rkx110_x120/Kconfig
Normal file
@@ -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.
|
||||||
|
|
||||||
23
drivers/mfd/rkx110_x120/Makefile
Normal file
23
drivers/mfd/rkx110_x120/Makefile
Normal file
@@ -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
|
||||||
210
drivers/mfd/rkx110_x120/hal/cru_api.h
Normal file
210
drivers/mfd/rkx110_x120/hal/cru_api.h
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
904
drivers/mfd/rkx110_x120/hal/cru_core.c
Normal file
904
drivers/mfd/rkx110_x120/hal/cru_core.c
Normal file
@@ -0,0 +1,904 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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];
|
||||||
|
}
|
||||||
450
drivers/mfd/rkx110_x120/hal/cru_core.h
Normal file
450
drivers/mfd/rkx110_x120/hal/cru_core.h
Normal file
@@ -0,0 +1,450 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
612
drivers/mfd/rkx110_x120/hal/cru_rkx110.c
Normal file
612
drivers/mfd/rkx110_x120/hal/cru_rkx110.c
Normal file
@@ -0,0 +1,612 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cru_core.h"
|
||||||
|
#include "cru_rkx110.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* [RKX110 CHIP]: RX
|
||||||
|
*
|
||||||
|
* ================= SECTION: Input clock from devices =========================
|
||||||
|
*
|
||||||
|
* ### 300M ###
|
||||||
|
* clk_8x_pma2pcs0
|
||||||
|
* clk_8x_pma2pcs1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ### 200M ###
|
||||||
|
* sclk_i2s_link2pcs --|-- sclk_i2s_link2pcs_inter1
|
||||||
|
* |-- sclk_i2s_link2pcs_inter2
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ### 200M ###
|
||||||
|
* clk_link_pcs0 --|-- clk_pma2pcs0 |-- clk_pma2link2pcs_link
|
||||||
|
* | |
|
||||||
|
* |-- clk_pma2link2pcs_cm (MUX) --|-- clk_pma2link2pcs_psc0
|
||||||
|
* clk_link_pcs1 --| |
|
||||||
|
* |-- clk_pma2pcs1 |-- clk_pma2link2pcs_psc1
|
||||||
|
*
|
||||||
|
* clk_rxbytehs_csihost0
|
||||||
|
* clk_rxbytehs_csihost1
|
||||||
|
* iclk_dsi0
|
||||||
|
* iclk_dsi1
|
||||||
|
* iclk_vicap
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ### 150M ###
|
||||||
|
* dclk_lvds0 -- clk_d_lvds0_rklink_tx_cm --|-- clk_d_lvds0_pattern_gen_en
|
||||||
|
* |-- clk_d_lvds0_rklink_tx
|
||||||
|
*
|
||||||
|
* dclk_lvds1 -- clk_d_lvds1_rklink_tx_cm --|-- clk_d_lvds1_pattern_gen_en
|
||||||
|
* |-- clk_d_lvds1_rklink_tx
|
||||||
|
*
|
||||||
|
* clk_d_rgb_rklink_tx
|
||||||
|
* pclkin_vicap_dvp_rx
|
||||||
|
* rxpclk_lvds_align
|
||||||
|
* rxpclk_vicap_lvds
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RKX110_SSCG_RXPLL_EN 0
|
||||||
|
#define RKX110_SSCG_CPLL_EN 0
|
||||||
|
#define RKX110_TESTOUT_MUX -1 /* valid options: RKX110_TEST_CLKOUT_IOUT_SEL_? */
|
||||||
|
|
||||||
|
#define RKX110_GRF_GPIO0B_IOMUX_H 0x0001000c
|
||||||
|
#define GPIO0B7_TEST_CLKOUT 0x01c00080
|
||||||
|
|
||||||
|
#define I2S_122888_BEST_PRATE 393216000
|
||||||
|
#define I2S_112896_BEST_PRATE 756403200
|
||||||
|
|
||||||
|
static struct PLL_CONFIG PLL_TABLE[] = {
|
||||||
|
/* _mhz, _refDiv, _fbDiv, _postdDv1, _postDiv2, _dsmpd, _frac */
|
||||||
|
RK_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
|
||||||
|
RK_PLL_RATE(600000000, 1, 25, 1, 1, 1, 0),
|
||||||
|
|
||||||
|
/* display */
|
||||||
|
RK_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
|
||||||
|
|
||||||
|
/* audio: 12.288M */
|
||||||
|
RK_PLL_RATE(688128000, 1, 86, 3, 1, 0, 268435), /* div=56, vco=2064.384M */
|
||||||
|
RK_PLL_RATE(393216000, 2, 131, 4, 1, 0, 1207959), /* div=32, vco=1572.864M */
|
||||||
|
RK_PLL_RATE(344064000, 1, 43, 3, 1, 0, 134217), /* div=28, vco=1032.192M */
|
||||||
|
/* audio: 11.2896M */
|
||||||
|
RK_PLL_RATE(474163200, 1, 79, 4, 1, 0, 456340), /* div=42, vco=1896.6528M */
|
||||||
|
RK_PLL_RATE(756403200, 1, 63, 2, 1, 0, 563714), /* div=67, vco=1512.8064M */
|
||||||
|
RK_PLL_RATE(564480000, 1, 47, 2, 1, 0, 671088), /* div=50, vco=1128.96M */
|
||||||
|
|
||||||
|
{ /* sentinel */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PLL_SETUP RXPLL_SETUP = {
|
||||||
|
.id = PLL_RXPLL,
|
||||||
|
.conOffset0 = 0x00000020,
|
||||||
|
.conOffset1 = 0x00000024,
|
||||||
|
.conOffset2 = 0x00000028,
|
||||||
|
.conOffset3 = 0x0000002c,
|
||||||
|
.modeOffset = 0x00000600,
|
||||||
|
.modeShift = 0, /* 0: slow-mode, 1: normal-mode */
|
||||||
|
.lockShift = 10,
|
||||||
|
.modeMask = 0x1,
|
||||||
|
.rateTable = PLL_TABLE,
|
||||||
|
|
||||||
|
.minRefdiv = 1,
|
||||||
|
.maxRefdiv = 2,
|
||||||
|
.minVco = _MHZ(375),
|
||||||
|
.maxVco = _MHZ(2400),
|
||||||
|
.minFout = _MHZ(24),
|
||||||
|
.maxFout = _MHZ(1200),
|
||||||
|
.sscgEn = RKX110_SSCG_RXPLL_EN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PLL_SETUP CPLL_SETUP = {
|
||||||
|
.id = PLL_CPLL,
|
||||||
|
.conOffset0 = 0x00000000,
|
||||||
|
.conOffset1 = 0x00000004,
|
||||||
|
.conOffset2 = 0x00000008,
|
||||||
|
.conOffset3 = 0x0000000c,
|
||||||
|
.modeOffset = 0x00000600,
|
||||||
|
.modeShift = 2,
|
||||||
|
.lockShift = 10,
|
||||||
|
.modeMask = 0x1 << 2,
|
||||||
|
.rateTable = PLL_TABLE,
|
||||||
|
|
||||||
|
.minRefdiv = 1,
|
||||||
|
.maxRefdiv = 2,
|
||||||
|
.minVco = _MHZ(375),
|
||||||
|
.maxVco = _MHZ(2400),
|
||||||
|
.minFout = _MHZ(24),
|
||||||
|
.maxFout = _MHZ(1200),
|
||||||
|
.sscgEn = RKX110_SSCG_CPLL_EN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t RKX11x_HAL_CRU_ClkGetFreq(struct hwclk *hw, uint32_t clockName)
|
||||||
|
{
|
||||||
|
uint32_t pRate = 0, freq = 0;
|
||||||
|
uint32_t clkMux, clkDiv;
|
||||||
|
|
||||||
|
if (clockName == RKX110_CLK_D_DSI_0_PATTERN_GEN ||
|
||||||
|
clockName == RKX110_CLK_D_DSI_1_PATTERN_GEN) {
|
||||||
|
clockName = RKX110_CPS_DCLK_RX_PRE;
|
||||||
|
}
|
||||||
|
|
||||||
|
clkMux = CLK_GET_MUX(clockName);
|
||||||
|
clkDiv = CLK_GET_DIV(clockName);
|
||||||
|
|
||||||
|
switch (clockName) {
|
||||||
|
case RKX110_CPS_PLL_RXPLL:
|
||||||
|
hw->pllRate[RKX110_RXPLL] = HAL_CRU_GetPllFreq(hw, &RXPLL_SETUP);
|
||||||
|
|
||||||
|
return hw->pllRate[RKX110_RXPLL];
|
||||||
|
|
||||||
|
case RKX110_CPS_PLL_CPLL:
|
||||||
|
hw->pllRate[RKX110_CPLL] = HAL_CRU_GetPllFreq(hw, &CPLL_SETUP);
|
||||||
|
|
||||||
|
return hw->pllRate[RKX110_CPLL];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 400MHZ => down to 200M
|
||||||
|
* === RX_DCLK_RX_PRE gate children ===
|
||||||
|
*
|
||||||
|
* dclk_dsi0
|
||||||
|
* dclk_dsi1
|
||||||
|
* dclk_vicap_csi
|
||||||
|
*
|
||||||
|
* clk_c_dvp_rklink_tx
|
||||||
|
* clk_c_csi_rklink_tx
|
||||||
|
*
|
||||||
|
* clk_d_dsi_0_rklink_tx
|
||||||
|
* clk_d_dsi_1_rklink_tx
|
||||||
|
* clk_d_dsi_0_pattern_gen
|
||||||
|
* clk_d_dsi_1_pattern_gen
|
||||||
|
* clk_c_lvds_rklink_tx
|
||||||
|
*
|
||||||
|
* NOTE: `clk_d_rgb_rklink_tx` is an input clock.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
case RKX110_CPS_DCLK_RX_PRE:
|
||||||
|
/* camera: 150M */
|
||||||
|
case RKX110_CPS_CLK_CAM0_OUT2IO:
|
||||||
|
case RKX110_CPS_CLK_CAM1_OUT2IO:
|
||||||
|
case RKX110_CPS_CLK_CIF_OUT2IO:
|
||||||
|
/* dsi: 200M */
|
||||||
|
case RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX:
|
||||||
|
case RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX:
|
||||||
|
/* lvds: 300M */
|
||||||
|
case RKX110_CPS_CLK_2X_LVDS_RKLINK_TX:
|
||||||
|
/* i2s: 600M => down to 300M */
|
||||||
|
case RKX110_CPS_CLK_I2S_SRC_RKLINK_TX:
|
||||||
|
freq = HAL_CRU_MuxGetFreq3(hw, clkMux, hw->pllRate[RKX110_RXPLL],
|
||||||
|
hw->pllRate[RKX110_CPLL], OSC_24M);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* mipi: ref_1000M, cfg_100M */
|
||||||
|
case RKX110_CPS_CKREF_MIPIRXPHY0:
|
||||||
|
case RKX110_CPS_CKREF_MIPIRXPHY1:
|
||||||
|
case RKX110_CPS_CFGCLK_MIPIRXPHY0:
|
||||||
|
case RKX110_CPS_CFGCLK_MIPIRXPHY1:
|
||||||
|
/* pre-bus: 100M */
|
||||||
|
case RKX110_CPS_BUSCLK_RX_PRE0:
|
||||||
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux, hw->pllRate[RKX110_RXPLL],
|
||||||
|
hw->pllRate[RKX110_CPLL]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bus: 100MHZ => down to 24M
|
||||||
|
*
|
||||||
|
* === RX_BUSCLK_RX_PRE gate children ===
|
||||||
|
*
|
||||||
|
* pclk_rx_cru
|
||||||
|
* pclk_rx_grf
|
||||||
|
* pclk_rx_gpio0/1
|
||||||
|
* pclk_rx_efuse
|
||||||
|
* pclk_mipi_grf_rx0/1
|
||||||
|
* pclk_rx_i2c2apb
|
||||||
|
* pclk_rx_i2c2apb_debug
|
||||||
|
* pclk_csihost0/1
|
||||||
|
* pclk_rklink_tx
|
||||||
|
* pclk_dsi_{0,1}_pattern_gen
|
||||||
|
* pclk_lvds_{0,1}_pattern_gen
|
||||||
|
* pclk_pcs0/1
|
||||||
|
* pclk_pcs{0,1}_ada
|
||||||
|
* pclk_mipirxphy0/1
|
||||||
|
* pclk_dft2apb
|
||||||
|
*
|
||||||
|
* hclk_vicap
|
||||||
|
* hclk_dsi0/1
|
||||||
|
*/
|
||||||
|
case RKX110_CPS_BUSCLK_RX_PRE:
|
||||||
|
pRate = RKX11x_HAL_CRU_ClkGetFreq(hw, RKX110_CPS_BUSCLK_RX_PRE0);
|
||||||
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux, OSC_24M, pRate);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RKX110_CPS_CLK_PMA2LINK2PCS_CM:
|
||||||
|
|
||||||
|
return _MHZ(200);
|
||||||
|
|
||||||
|
/* gpio: 24M */
|
||||||
|
case RKX110_CPS_DCLK_RX_GPIO0:
|
||||||
|
case RKX110_CPS_DCLK_RX_GPIO1:
|
||||||
|
/* efuse: 24M */
|
||||||
|
case RKX110_CPS_RX_EFUSE:
|
||||||
|
/* pcs_ada: 24M */
|
||||||
|
case RKX110_CPS_PCS0_ADA:
|
||||||
|
case RKX110_CPS_PCS1_ADA:
|
||||||
|
|
||||||
|
return OSC_24M;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CRU_ERR("%s: %s: Unknown clk 0x%08x\n", __func__, hw->name, clockName);
|
||||||
|
|
||||||
|
return HAL_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clkMux && !clkDiv) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clkDiv) {
|
||||||
|
freq /= (HAL_CRU_ClkGetDiv(hw, clkDiv));
|
||||||
|
}
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HAL_Status RKX11x_HAL_CRU_ClkSetFreq(struct hwclk *hw, uint32_t clockName, uint32_t rate)
|
||||||
|
{
|
||||||
|
uint32_t clkMux, clkDiv;
|
||||||
|
uint32_t mux = 0, div = 1;
|
||||||
|
uint32_t pRate = 0;
|
||||||
|
uint32_t maxDiv;
|
||||||
|
uint32_t pll;
|
||||||
|
uint8_t overMax = 0;
|
||||||
|
HAL_Status ret = HAL_OK;
|
||||||
|
|
||||||
|
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, "<CRU.110@");
|
||||||
|
strcat(hw->name, xfer->name);
|
||||||
|
strcat(hw->name, ">");
|
||||||
|
|
||||||
|
/* Don't change order */
|
||||||
|
#if RKX110_SSCG_CPLL_EN || RKX110_SSCG_RXPLL_EN
|
||||||
|
RKX11x_HAL_CRU_Init_SSCG(hw);
|
||||||
|
#endif
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_PLL_CPLL, _MHZ(1200));
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_PLL_RXPLL, _MHZ(1188));
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_BUSCLK_RX_PRE, _MHZ(24));
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_CLK_PMA2LINK2PCS_CM, _MHZ(200));
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_DCLK_RX_PRE, _MHZ(200));
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_CLK_I2S_SRC_RKLINK_TX, _MHZ(300));
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_CFGCLK_MIPIRXPHY0, _MHZ(100));
|
||||||
|
|
||||||
|
HAL_CRU_ClkEnable(hw, RKX110_CLK_TESTOUT_TOP_GATE);
|
||||||
|
|
||||||
|
#if RKX110_TESTOUT_MUX >= 0
|
||||||
|
/* clk_testout support max 150M output, so set div=10 by default if not 24M */
|
||||||
|
RKX11x_HAL_CRU_InitTestout(hw, RKX110_CPS_TEST_CLKOUT, RKX110_TESTOUT_MUX,
|
||||||
|
RKX110_TESTOUT_MUX == 0 ? 1 : 10);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return HAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
PNAME(mux_24m_p) = { "xin24m" };
|
||||||
|
PNAME(mux_rxpll_cpll_p) = { "rxpll", "cpll" };
|
||||||
|
PNAME(mux_rxpll_cpll_24m_p) = { "rxpll", "cpll", "xin24m" };
|
||||||
|
PNAME(mux_rxpre0_24m_p) = { "xin24m", "busclk_rx_pre0" };
|
||||||
|
|
||||||
|
#define CAL_FREQ_REG 0xf00
|
||||||
|
|
||||||
|
static uint32_t RKX11x_HAL_CRU_ClkGetExtFreq(struct hwclk *hw, uint32_t clk)
|
||||||
|
{
|
||||||
|
uint32_t clkMux = CLK_GET_MUX(RKX110_CPS_TEST_CLKOUT);
|
||||||
|
uint32_t clkDiv = CLK_GET_DIV(RKX110_CPS_TEST_CLKOUT);
|
||||||
|
uint32_t freq, mhz;
|
||||||
|
uint8_t div = 10;
|
||||||
|
|
||||||
|
HAL_CRU_ClkSetDiv(hw, clkDiv, div);
|
||||||
|
HAL_CRU_ClkSetMux(hw, clkMux, 0);
|
||||||
|
HAL_SleepMs(2);
|
||||||
|
HAL_CRU_ClkSetMux(hw, clkMux, clk);
|
||||||
|
HAL_SleepMs(2);
|
||||||
|
freq = HAL_CRU_Read(hw, CAL_FREQ_REG);
|
||||||
|
|
||||||
|
/* Fix accuracy */
|
||||||
|
if ((freq % 10) == 0x9) {
|
||||||
|
freq++;
|
||||||
|
}
|
||||||
|
|
||||||
|
freq *= (1000 * div);
|
||||||
|
|
||||||
|
/* If no external input, freq is close to 24M */
|
||||||
|
mhz = freq / 1000000;
|
||||||
|
if ((clk != 0) && (mhz == 23 || mhz == 24)) {
|
||||||
|
freq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clkTable rkx11x_clkTable[] = {
|
||||||
|
/* internal */
|
||||||
|
CLK_DECLARE_INT("rxpll", RKX110_CPS_PLL_RXPLL, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("cpll", RKX110_CPS_PLL_CPLL, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("dclk_rx_pre", RKX110_CPS_DCLK_RX_PRE, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_d_dsi_0_pattern", RKX110_CPS_DCLK_RX_PRE, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_d_dsi_1_pattern", RKX110_CPS_DCLK_RX_PRE, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_cam0_out2io", RKX110_CPS_CLK_CAM0_OUT2IO, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_cam1_out2io", RKX110_CPS_CLK_CAM1_OUT2IO, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_cif_out2io", RKX110_CPS_CLK_CIF_OUT2IO, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("dclk_d_dsi_0_rec_rklink_tx", RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("dclk_d_dsi_1_rec_rklink_tx", RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_2x_lvds_rklink_tx", RKX110_CPS_CLK_2X_LVDS_RKLINK_TX, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_i2s_src_rklink_tx", RKX110_CPS_CLK_I2S_SRC_RKLINK_TX, mux_rxpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("ckref_mipirxphy0", RKX110_CPS_CKREF_MIPIRXPHY0, mux_rxpll_cpll_p),
|
||||||
|
CLK_DECLARE_INT("ckref_mipirxphy1", RKX110_CPS_CKREF_MIPIRXPHY1, mux_rxpll_cpll_p),
|
||||||
|
CLK_DECLARE_INT("cfgclk_mipirxphy0", RKX110_CPS_CFGCLK_MIPIRXPHY0, mux_rxpll_cpll_p),
|
||||||
|
CLK_DECLARE_INT("cfgclk_mipirxphy1", RKX110_CPS_CFGCLK_MIPIRXPHY1, mux_rxpll_cpll_p),
|
||||||
|
CLK_DECLARE_INT("busclk_rx_pre0", RKX110_CPS_BUSCLK_RX_PRE0, mux_rxpll_cpll_p),
|
||||||
|
CLK_DECLARE_INT("busclk_rx_pre", RKX110_CPS_BUSCLK_RX_PRE, mux_rxpre0_24m_p),
|
||||||
|
CLK_DECLARE_INT("dclk_rx_gpio0", RKX110_CPS_DCLK_RX_GPIO0, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("dclk_rx_gpio1", RKX110_CPS_DCLK_RX_GPIO1, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("rx_efuse", RKX110_CPS_RX_EFUSE, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("pcs0_ada", RKX110_CPS_PCS0_ADA, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("pcs1_ada", RKX110_CPS_PCS1_ADA, mux_24m_p),
|
||||||
|
|
||||||
|
/* external */
|
||||||
|
CLK_DECLARE_EXT("xin24m", 0, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("rxpclk_vicap_lvds", 3, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_rxbytehs_csihost0", 4, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_rxbytehs_csihost1", 5, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_d_rgb_rklink_tx", 6, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("dclk_lvds0", 7, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("dclk_lvds1", 8, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_link_pcs0", 9, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_link_pcs1", 10, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("pclkin_vicap_dvp_rx", 21, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("iclk_dsi0", 22, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("iclk_dsi1", 23, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("rxpclk_lvds_align", 24, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_8x_pma2pcs0", 25, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_8x_pma2pcs1", 26, RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds0_rklink_tx_cm", 7, "dclk_lvds0", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds0_rklink_tx", 7, "clk_d_lvds0_rklink_tx_cm", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds0_pattern_gen_en", 7, "clk_d_lvds0_rklink_tx_cm", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds1_rklink_tx_cm", 8, "dclk_lvds1", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds1_rklink_tx", 8, "clk_d_lvds1_rklink_tx_cm", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_d_lvds1_pattern_gen_en", 8, "clk_d_lvds1_rklink_tx_cm", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_pma2pcs0", 9, "clk_link_pcs0", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_pma2link2pcs_cm", 9, "clk_link_pcs0", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_pma2pcs1", 9, "clk_link_pcs1", RKX11x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
|
||||||
|
{ /* sentinel */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clkOps rkx110_clk_ops =
|
||||||
|
{
|
||||||
|
.clkTable = rkx11x_clkTable,
|
||||||
|
.clkInit = RKX11x_HAL_CRU_Init,
|
||||||
|
.clkGetFreq = RKX11x_HAL_CRU_ClkGetFreq,
|
||||||
|
.clkSetFreq = RKX11x_HAL_CRU_ClkSetFreq,
|
||||||
|
.clkInitTestout = RKX11x_HAL_CRU_InitTestout,
|
||||||
|
};
|
||||||
358
drivers/mfd/rkx110_x120/hal/cru_rkx110.h
Normal file
358
drivers/mfd/rkx110_x120/hal/cru_rkx110.h
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
706
drivers/mfd/rkx110_x120/hal/cru_rkx111.c
Normal file
706
drivers/mfd/rkx110_x120/hal/cru_rkx111.c
Normal file
@@ -0,0 +1,706 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cru_core.h"
|
||||||
|
#include "cru_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, "<CRU.111@");
|
||||||
|
strcat(hw->name, xfer->name);
|
||||||
|
strcat(hw->name, ">");
|
||||||
|
|
||||||
|
/* Don't change order */
|
||||||
|
#if RKX110_SSCG_CPLL_EN || RKX110_SSCG_RXPLL_EN
|
||||||
|
RKX11x_HAL_CRU_Init_SSCG(hw);
|
||||||
|
#endif
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_PLL_CPLL, _MHZ(1200));
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_PLL_RXPLL, _MHZ(1188));
|
||||||
|
RKX11x_HAL_CRU_ClkSetFreq(hw, RKX110_CPS_BUSCLK_RX_PRE, _MHZ(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,
|
||||||
|
};
|
||||||
117
drivers/mfd/rkx110_x120/hal/cru_rkx111.h
Normal file
117
drivers/mfd/rkx110_x120/hal/cru_rkx111.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
599
drivers/mfd/rkx110_x120/hal/cru_rkx120.c
Normal file
599
drivers/mfd/rkx110_x120/hal/cru_rkx120.c
Normal file
@@ -0,0 +1,599 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cru_core.h"
|
||||||
|
#include "cru_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, "<CRU.120@");
|
||||||
|
strcat(hw->name, xfer->name);
|
||||||
|
strcat(hw->name, ">");
|
||||||
|
|
||||||
|
/* Don't change order */
|
||||||
|
#if RKX120_SSCG_CPLL_EN || RKX120_SSCG_TXPLL_EN
|
||||||
|
RKX12x_HAL_CRU_Init_SSCG(hw);
|
||||||
|
#endif
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_PLL_CPLL, _MHZ(1200));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_PLL_TXPLL, _MHZ(1188));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_BUSCLK_TX_PRE, _MHZ(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,
|
||||||
|
};
|
||||||
305
drivers/mfd/rkx110_x120/hal/cru_rkx120.h
Normal file
305
drivers/mfd/rkx110_x120/hal/cru_rkx120.h
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
626
drivers/mfd/rkx110_x120/hal/cru_rkx121.c
Normal file
626
drivers/mfd/rkx110_x120/hal/cru_rkx121.c
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cru_core.h"
|
||||||
|
#include "cru_rkx121.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* [RKX121 CHIP]: TX
|
||||||
|
*
|
||||||
|
* ================= SECITON: Input clock from devices =========================
|
||||||
|
*
|
||||||
|
* ### 300M ###
|
||||||
|
* dclk_c_dvp_src
|
||||||
|
* dclk_d_dsi_src --|-- dclk_d_ds
|
||||||
|
* |-- dclk_d_dsi_pattern_gen
|
||||||
|
*
|
||||||
|
* clk_lvds0_src --|-- clk_lvds0
|
||||||
|
* |-- clk_lvds0_pattern_gen
|
||||||
|
*
|
||||||
|
* clk_lvds1_src --|-- clk_lvds1
|
||||||
|
* |-- clk_lvds1_pattern_gen
|
||||||
|
*
|
||||||
|
* dclk_rgc_src
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ### 200M ###
|
||||||
|
* clk_link_pcs0 --|-- clk_pma2pcs0 |-- clk_pma2link2pcs_link
|
||||||
|
* | |
|
||||||
|
* |-- clk_pma2link2pcs_cm (MUX) --|-- clk_pma2link2pcs_psc0
|
||||||
|
* clk_link_pcs1 --| |
|
||||||
|
* |-- clk_pma2pcs1 |-- clk_pma2link2pcs_psc1
|
||||||
|
*
|
||||||
|
* clk_txbytehs_dsitx_csitx0
|
||||||
|
* clk_txbytehs_dsitx_csitx1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ### 150M ###
|
||||||
|
*
|
||||||
|
* rxpclk_vicap_lvds
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ### 100M ###
|
||||||
|
*
|
||||||
|
* clk_2x_pma2pcs0
|
||||||
|
* clk_2x_pma2pcs1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ### 50M ###
|
||||||
|
* clk_txesc_mipitxphy0
|
||||||
|
* clk_rxesc_dsitx
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RKX120_SSCG_TXPLL_EN 0
|
||||||
|
#define RKX120_SSCG_CPLL_EN 0
|
||||||
|
#define RKX120_TESTOUT_MUX -1 /* valid options: RKX120_TEST_CLKOUT_IOUT_SEL_? */
|
||||||
|
|
||||||
|
#define RKX120_GRF_GPIO0B_IOMUX_H 0x0101000c
|
||||||
|
#define GPIO0B7_TEST_CLKOUT 0x01c00080
|
||||||
|
|
||||||
|
#define I2S_122888_BEST_PRATE 393216000
|
||||||
|
#define I2S_112896_BEST_PRATE 756403200
|
||||||
|
|
||||||
|
static struct PLL_CONFIG PLL_TABLE[] = {
|
||||||
|
/* _mhz, _refDiv, _fbDiv, _postdDv1, _postDiv2, _dsmpd, _frac */
|
||||||
|
RK_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
|
||||||
|
RK_PLL_RATE(600000000, 1, 25, 1, 1, 1, 0),
|
||||||
|
|
||||||
|
/* display */
|
||||||
|
RK_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
|
||||||
|
|
||||||
|
/* audio: 12.288M */
|
||||||
|
RK_PLL_RATE(688128000, 1, 86, 3, 1, 0, 268435), /* div=56, vco=2064.384M */
|
||||||
|
RK_PLL_RATE(393216000, 2, 131, 4, 1, 0, 1207959), /* div=32, vco=1572.864M */
|
||||||
|
RK_PLL_RATE(344064000, 1, 43, 3, 1, 0, 134217), /* div=28, vco=1032.192M */
|
||||||
|
/* audio: 11.2896M */
|
||||||
|
RK_PLL_RATE(474163200, 1, 79, 4, 1, 0, 456340), /* div=42, vco=1896.6528M */
|
||||||
|
RK_PLL_RATE(756403200, 1, 63, 2, 1, 0, 563714), /* div=67, vco=1512.8064M */
|
||||||
|
RK_PLL_RATE(564480000, 1, 47, 2, 1, 0, 671088), /* div=50, vco=1128.96M */
|
||||||
|
|
||||||
|
{ /* sentinel */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PLL_SETUP TXPLL_SETUP = {
|
||||||
|
.id = PLL_TXPLL,
|
||||||
|
.conOffset0 = 0x01000020,
|
||||||
|
.conOffset1 = 0x01000024,
|
||||||
|
.conOffset2 = 0x01000028,
|
||||||
|
.conOffset3 = 0x0100002c,
|
||||||
|
.modeOffset = 0x01000600,
|
||||||
|
.modeShift = 0, /* 0: slow-mode, 1: normal-mode */
|
||||||
|
.lockShift = 10,
|
||||||
|
.modeMask = 0x1,
|
||||||
|
.rateTable = PLL_TABLE,
|
||||||
|
|
||||||
|
.minRefdiv = 1,
|
||||||
|
.maxRefdiv = 2,
|
||||||
|
.minVco = _MHZ(375),
|
||||||
|
.maxVco = _MHZ(2400),
|
||||||
|
.minFout = _MHZ(24),
|
||||||
|
.maxFout = _MHZ(1200),
|
||||||
|
.sscgEn = RKX120_SSCG_TXPLL_EN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PLL_SETUP CPLL_SETUP = {
|
||||||
|
.id = PLL_CPLL,
|
||||||
|
.conOffset0 = 0x01000000,
|
||||||
|
.conOffset1 = 0x01000004,
|
||||||
|
.conOffset2 = 0x01000008,
|
||||||
|
.conOffset3 = 0x0100000c,
|
||||||
|
.modeOffset = 0x01000600,
|
||||||
|
.modeShift = 2,
|
||||||
|
.lockShift = 10,
|
||||||
|
.modeMask = 0x1 << 2,
|
||||||
|
.rateTable = PLL_TABLE,
|
||||||
|
|
||||||
|
.minRefdiv = 1,
|
||||||
|
.maxRefdiv = 2,
|
||||||
|
.minVco = _MHZ(375),
|
||||||
|
.maxVco = _MHZ(2400),
|
||||||
|
.minFout = _MHZ(24),
|
||||||
|
.maxFout = _MHZ(1200),
|
||||||
|
.sscgEn = RKX120_SSCG_CPLL_EN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t RKX12x_HAL_CRU_ClkGetFreq(struct hwclk *hw, uint32_t clockName)
|
||||||
|
{
|
||||||
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
||||||
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
||||||
|
uint32_t pRate = 0, freq = 0;
|
||||||
|
uint32_t pRate0 = 0, pRate1 = 0;
|
||||||
|
|
||||||
|
switch (clockName) {
|
||||||
|
case RKX120_CPS_PLL_TXPLL:
|
||||||
|
freq = HAL_CRU_GetPllFreq(hw, &TXPLL_SETUP);
|
||||||
|
hw->pllRate[RKX120_TXPLL] = freq;
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
|
||||||
|
case RKX120_CPS_PLL_CPLL:
|
||||||
|
freq = HAL_CRU_GetPllFreq(hw, &CPLL_SETUP);
|
||||||
|
hw->pllRate[RKX120_CPLL] = freq;
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
|
||||||
|
/* lvds: 200M */
|
||||||
|
case RKX121_CPS_CLK_LVDS_C_LVDS_TX:
|
||||||
|
/* link: 300M */
|
||||||
|
case RKX120_CPS_E0_CLK_RKLINK_RX_PRE:
|
||||||
|
case RKX120_CPS_E1_CLK_RKLINK_RX_PRE:
|
||||||
|
/* csi: 50M */
|
||||||
|
case RKX120_CPS_CLK_TXESC_CSITX0:
|
||||||
|
case RKX120_CPS_CLK_TXESC_CSITX1:
|
||||||
|
/* i2s: 600M */
|
||||||
|
case RKX120_CPS_CLK_I2S_SRC_RKLINK_RX:
|
||||||
|
/* pwm: 100M */
|
||||||
|
case RKX120_CPS_CLK_PWM_TX:
|
||||||
|
case RKX120_CPS_PCLKOUT_DVPTX:
|
||||||
|
freq = HAL_CRU_MuxGetFreq3(hw, clkMux,
|
||||||
|
hw->pllRate[RKX120_TXPLL],
|
||||||
|
hw->pllRate[RKX120_CPLL], OSC_24M);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* gate clock from TX_E0_CLK_RKLINK_RX_PRE */
|
||||||
|
case RKX120_CPS_ICLK_C_CSI0:
|
||||||
|
|
||||||
|
return RKX12x_HAL_CRU_ClkGetFreq(hw, RKX120_CPS_E0_CLK_RKLINK_RX_PRE);
|
||||||
|
|
||||||
|
/* gate clock from TX_E1_CLK_RKLINK_RX_PRE */
|
||||||
|
case RKX120_CPS_ICLK_C_CSI1:
|
||||||
|
|
||||||
|
return RKX12x_HAL_CRU_ClkGetFreq(hw, RKX120_CPS_E1_CLK_RKLINK_RX_PRE);
|
||||||
|
|
||||||
|
case RKX121_CPS_CLK_LVDS0:
|
||||||
|
case RKX121_CPS_CLK_LVDS1:
|
||||||
|
pRate0 = _MHZ(150); /* input clock: clk_lvds1_cm */
|
||||||
|
pRate1 = RKX12x_HAL_CRU_ClkGetFreq(hw, RKX121_CPS_CLK_LVDS_C_LVDS_TX);
|
||||||
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux, pRate0, pRate1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* pre-bus: 100M */
|
||||||
|
case RKX120_CPS_BUSCLK_TX_PRE0:
|
||||||
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux,
|
||||||
|
hw->pllRate[RKX120_TXPLL],
|
||||||
|
hw->pllRate[RKX120_CPLL]);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* bus: 100MHZ
|
||||||
|
*
|
||||||
|
* === TX_BUSCLK_TX_PRE gate children ===
|
||||||
|
*
|
||||||
|
* pclk_tx_cru
|
||||||
|
* pclk_tx_grf
|
||||||
|
* pclk_tx_gpio0/1
|
||||||
|
* pclk_tx_efuse
|
||||||
|
* pclk_mipi_grf_tx0/1
|
||||||
|
* pclk_tx_i2c2apb
|
||||||
|
* pclk_tx_i2c2apb_debug
|
||||||
|
* hclk_dvp_tx
|
||||||
|
* pclk_csitx0/1
|
||||||
|
* pclk_dsitx
|
||||||
|
* pclk_rklink_rx
|
||||||
|
* pclk_d_dsi_pattern_gen
|
||||||
|
* pclk_lvds{0, 1}_pattern_gen
|
||||||
|
* pclk_pcs0/1
|
||||||
|
* pclk_pcs{0,1}_ada
|
||||||
|
* pclk_mipitxphy0/1
|
||||||
|
* pclk_pwm_tx
|
||||||
|
* pclk_dft2apb
|
||||||
|
* pclk_lbist_ada_tx
|
||||||
|
*/
|
||||||
|
case RKX120_CPS_BUSCLK_TX_PRE:
|
||||||
|
pRate = RKX12x_HAL_CRU_ClkGetFreq(hw, RKX120_CPS_BUSCLK_TX_PRE0);
|
||||||
|
freq = HAL_CRU_MuxGetFreq2(hw, clkMux, OSC_24M, pRate);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* gpio: 24M */
|
||||||
|
case RKX120_CPS_DCLK_TX_GPIO0:
|
||||||
|
case RKX120_CPS_DCLK_TX_GPIO1:
|
||||||
|
/* efuse: 24M */
|
||||||
|
case RKX120_CPS_CLK_TX_EFUSE:
|
||||||
|
/* pcs_ada: 24M */
|
||||||
|
case RKX120_CPS_CLK_PCS0_ADA:
|
||||||
|
case RKX120_CPS_CLK_PCS1_ADA:
|
||||||
|
/* capture_pwm: 24M */
|
||||||
|
case RKX120_CPS_CLK_CAPTURE_PWM_TX:
|
||||||
|
|
||||||
|
return OSC_24M;
|
||||||
|
|
||||||
|
case RKX120_CPS_CLK_PMA2PCS2LINK_CM:
|
||||||
|
|
||||||
|
return _MHZ(200);
|
||||||
|
|
||||||
|
default:
|
||||||
|
CRU_ERR("%s: %s: Unknown clk 0x%08x\n", __func__, hw->name, clockName);
|
||||||
|
|
||||||
|
return HAL_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clkMux && !clkDiv) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clkDiv) {
|
||||||
|
freq /= (HAL_CRU_ClkGetDiv(hw, clkDiv));
|
||||||
|
}
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HAL_Status RKX12x_HAL_CRU_ClkSetFreq(struct hwclk *hw, uint32_t clockName, uint32_t rate)
|
||||||
|
{
|
||||||
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
||||||
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
||||||
|
uint32_t mux = 0, div = 1;
|
||||||
|
uint32_t pRate = 0;
|
||||||
|
uint32_t maxDiv;
|
||||||
|
uint32_t pll;
|
||||||
|
uint8_t overMax;
|
||||||
|
HAL_Status ret = HAL_OK;
|
||||||
|
|
||||||
|
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, "<CRU.121@");
|
||||||
|
strcat(hw->name, xfer->name);
|
||||||
|
strcat(hw->name, ">");
|
||||||
|
|
||||||
|
/* Don't change order */
|
||||||
|
#if RKX120_SSCG_CPLL_EN || RKX120_SSCG_TXPLL_EN
|
||||||
|
RKX12x_HAL_CRU_Init_SSCG(hw);
|
||||||
|
#endif
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_PLL_CPLL, _MHZ(1200));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_PLL_TXPLL, _MHZ(1188));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_BUSCLK_TX_PRE, _MHZ(100));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX121_CPS_CLK_LVDS_C_LVDS_TX, _MHZ(200));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_PMA2PCS2LINK_CM, _MHZ(200));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_I2S_SRC_RKLINK_RX, _MHZ(400));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_PWM_TX, _MHZ(24));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_TXESC_CSITX0, _MHZ(20));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_CLK_TXESC_CSITX1, _MHZ(20));
|
||||||
|
|
||||||
|
/* Must be the same rate as RKX110_CPS_DCLK_RX_PRE when camera mode */
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_E0_CLK_RKLINK_RX_PRE, _MHZ(200));
|
||||||
|
RKX12x_HAL_CRU_ClkSetFreq(hw, RKX120_CPS_E1_CLK_RKLINK_RX_PRE, _MHZ(200));
|
||||||
|
|
||||||
|
HAL_CRU_ClkEnable(hw, RKX120_CLK_TESTOUT_TOP_GATE);
|
||||||
|
|
||||||
|
#if RKX120_TESTOUT_MUX >= 0
|
||||||
|
/* clk_testout support max 150M output, so set div=10 by default if not 24M */
|
||||||
|
RKX12x_HAL_CRU_InitTestout(hw, RKX120_CPS_TEST_CLKOUT, RKX120_TESTOUT_MUX,
|
||||||
|
RKX120_TESTOUT_MUX == 0 ? 1 : 10);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return HAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
PNAME(mux_24m_p) = { "xin24m" };
|
||||||
|
PNAME(mux_txpll_cpll_p) = { "txpll", "cpll" };
|
||||||
|
PNAME(mux_txpll_cpll_24m_p) = { "txpll", "cpll", "xin24m" };
|
||||||
|
PNAME(mux_24m_txpre0_p) = { "xin24m", "busclk_tx_pre0" };
|
||||||
|
|
||||||
|
#define CAL_FREQ_REG 0x01000f00
|
||||||
|
#define CAL_FREQ_EN_REG 0x01000f04
|
||||||
|
|
||||||
|
static uint32_t RKX12x_HAL_CRU_ClkGetExtFreq(struct hwclk *hw, uint32_t clk)
|
||||||
|
{
|
||||||
|
uint32_t clkMux = CLK_GET_MUX(RKX120_CPS_TEST_CLKOUT);
|
||||||
|
uint32_t clkDiv = CLK_GET_DIV(RKX120_CPS_TEST_CLKOUT);
|
||||||
|
uint32_t freq, mhz;
|
||||||
|
uint8_t div = 10;
|
||||||
|
|
||||||
|
HAL_CRU_ClkSetDiv(hw, clkDiv, div);
|
||||||
|
HAL_CRU_ClkSetMux(hw, clkMux, clk);
|
||||||
|
HAL_CRU_Write(hw, CAL_FREQ_EN_REG, 1); /* NOTE: 1: enable, 0: disable */
|
||||||
|
HAL_SleepMs(2);
|
||||||
|
freq = HAL_CRU_Read(hw, CAL_FREQ_REG);
|
||||||
|
HAL_CRU_Write(hw, CAL_FREQ_EN_REG, 0x0);
|
||||||
|
|
||||||
|
/* Fix accuracy */
|
||||||
|
if ((freq % 10) == 0x9) {
|
||||||
|
freq++;
|
||||||
|
}
|
||||||
|
|
||||||
|
freq *= (1000 * div);
|
||||||
|
|
||||||
|
/* If no external input, freq is close to 24M */
|
||||||
|
mhz = freq / 1000000;
|
||||||
|
if ((clk != 0) && (mhz == 23 || mhz == 24)) {
|
||||||
|
freq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clkTable rkx12x_clkTable[] = {
|
||||||
|
/* internal */
|
||||||
|
CLK_DECLARE_INT("txpll", RKX120_CPS_PLL_TXPLL, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("cpll", RKX120_CPS_PLL_CPLL, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("e0_clk_rklink_rx_pre", RKX120_CPS_E0_CLK_RKLINK_RX_PRE, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("e1_clk_rklink_rx_pre", RKX120_CPS_E1_CLK_RKLINK_RX_PRE, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("iclk_c_csi0", RKX120_CPS_ICLK_C_CSI0, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("iclk_c_csi1", RKX120_CPS_ICLK_C_CSI1, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_txesc_csitx0", RKX120_CPS_CLK_TXESC_CSITX0, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_txesc_csitx1", RKX120_CPS_CLK_TXESC_CSITX1, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_i2s_src_rklink_rx", RKX120_CPS_CLK_I2S_SRC_RKLINK_RX, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_pwm_tx", RKX120_CPS_CLK_PWM_TX, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("pclkout_dvptx", RKX120_CPS_PCLKOUT_DVPTX, mux_txpll_cpll_24m_p),
|
||||||
|
CLK_DECLARE_INT("busclk_tx_pre0", RKX120_CPS_BUSCLK_TX_PRE0, mux_txpll_cpll_p),
|
||||||
|
CLK_DECLARE_INT("busclk_tx_pre", RKX120_CPS_BUSCLK_TX_PRE, mux_24m_txpre0_p),
|
||||||
|
CLK_DECLARE_INT("dclk_tx_gpio0", RKX120_CPS_DCLK_TX_GPIO0, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("dclk_tx_gpio1", RKX120_CPS_DCLK_TX_GPIO1, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_tx_efuse", RKX120_CPS_CLK_TX_EFUSE, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_pcs0_ada", RKX120_CPS_CLK_PCS0_ADA, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_pcs1_ada", RKX120_CPS_CLK_PCS1_ADA, mux_24m_p),
|
||||||
|
CLK_DECLARE_INT("clk_capture_pwm_tx", RKX120_CPS_CLK_CAPTURE_PWM_TX, mux_24m_p),
|
||||||
|
|
||||||
|
/* external */
|
||||||
|
CLK_DECLARE_EXT("xin24m", 0, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_txbytehs_csitx0", 3, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_txbytehs_csitx1", 5, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_txbytehs_dsitx", 7, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_rxesc_dsitx", 8, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_link_pcs0", 9, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_link_pcs1", 10, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_pmarx0_pixel", 11, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_pmarx1_pixel", 12, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_mipitxphy0_lvds", 13, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_mipitxphy0_pixel", 14, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_mipitxphy1_lvds", 15, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_mipitxphy1_pixel", 16, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_txbytehs_dsitx_csitx0", 23, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("dclk_c_dvp_src", 24, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("dclk_d_dsi_src", 25, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_lvds0_src", 26, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_lvds1_src", 27, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("dclk_rgb_src", 28, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_2x_pma2pcs0", 29, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_2x_pma2pcs1", 30, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT("clk_txesc_mipitxphy0", 31, RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
|
||||||
|
CLK_DECLARE_EXT_PARENT("dclk_d_ds", 25, "dclk_d_dsi_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("dclk_d_dsi_pattern_gen", 25, "dclk_d_dsi_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_lvds0", 26, "clk_lvds0_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_lvds0_pattern_gen", 26, "clk_lvds0_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_lvds1", 27, "clk_lvds1_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_lvds1_pattern_gen", 27, "clk_lvds1_src", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_pma2pcs0", 9, "clk_link_pcs0", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_pma2link2pcs_cm", 9, "clk_link_pcs0", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
CLK_DECLARE_EXT_PARENT("clk_pma2pcs1", 10, "clk_link_pcs1", RKX12x_HAL_CRU_ClkGetExtFreq),
|
||||||
|
|
||||||
|
{ /* sentinel */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clkOps rkx121_clk_ops =
|
||||||
|
{
|
||||||
|
.clkTable = rkx12x_clkTable,
|
||||||
|
.clkInit = RKX12x_HAL_CRU_Init,
|
||||||
|
.clkGetFreq = RKX12x_HAL_CRU_ClkGetFreq,
|
||||||
|
.clkSetFreq = RKX12x_HAL_CRU_ClkSetFreq,
|
||||||
|
.clkInitTestout = RKX12x_HAL_CRU_InitTestout,
|
||||||
|
};
|
||||||
48
drivers/mfd/rkx110_x120/hal/cru_rkx121.h
Normal file
48
drivers/mfd/rkx110_x120/hal/cru_rkx121.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
58
drivers/mfd/rkx110_x120/hal/hal_def.h
Normal file
58
drivers/mfd/rkx110_x120/hal/hal_def.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Steven Liu <steven.liu@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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_ */
|
||||||
33
drivers/mfd/rkx110_x120/hal/hal_os_def.h
Normal file
33
drivers/mfd/rkx110_x120/hal/hal_os_def.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Joseph Chen <chenjh@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HAL_OS_DEF_H_
|
||||||
|
#define _HAL_OS_DEF_H_
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
|
||||||
|
#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_ */
|
||||||
45
drivers/mfd/rkx110_x120/hal/pinctrl_api.h
Normal file
45
drivers/mfd/rkx110_x120/hal/pinctrl_api.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Steven Liu <steven.liu@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
612
drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.c
Normal file
612
drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.c
Normal file
@@ -0,0 +1,612 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Steven Liu <steven.liu@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
166
drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.h
Normal file
166
drivers/mfd/rkx110_x120/hal/pinctrl_rkx110_x120.h
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Steven Liu <steven.liu@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PINCTRL_CORE_H_
|
||||||
|
#define _PINCTRL_CORE_H_
|
||||||
|
|
||||||
|
#include <dt-bindings/mfd/rockchip-serdes.h>
|
||||||
|
|
||||||
|
#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_ */
|
||||||
141
drivers/mfd/rkx110_x120/pattern_gen.c
Normal file
141
drivers/mfd/rkx110_x120/pattern_gen.c
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
304
drivers/mfd/rkx110_x120/rkx110.c
Normal file
304
drivers/mfd/rkx110_x120/rkx110.c
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*/
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
280
drivers/mfd/rkx110_x120/rkx110_combrxphy.c
Normal file
280
drivers/mfd/rkx110_x120/rkx110_combrxphy.c
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Guochun Huang <hero.huang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal/cru_api.h"
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
124
drivers/mfd/rkx110_x120/rkx110_dsi_rx.c
Normal file
124
drivers/mfd/rkx110_x120/rkx110_dsi_rx.c
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Guochun Huang <hero.huang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
#include <dt-bindings/mfd/rockchip-serdes.h>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
14
drivers/mfd/rkx110_x120/rkx110_dsi_rx.h
Normal file
14
drivers/mfd/rkx110_x120/rkx110_dsi_rx.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Guochun Huang <hero.huang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
738
drivers/mfd/rkx110_x120/rkx110_linktx.c
Normal file
738
drivers/mfd/rkx110_x120/rkx110_linktx.c
Normal file
@@ -0,0 +1,738 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Zhang Yubing <yubing.zhang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/mfd/core.h>
|
||||||
|
#include <dt-bindings/mfd/rockchip-serdes.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
515
drivers/mfd/rkx110_x120/rkx110_reg.h
Normal file
515
drivers/mfd/rkx110_x120/rkx110_reg.h
Normal file
@@ -0,0 +1,515 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Zhang Yubing <yubing.zhang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RKX110_REG_H
|
||||||
|
#define _RKX110_REG_H
|
||||||
|
|
||||||
|
#include <linux/bits.h>
|
||||||
|
|
||||||
|
#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
|
||||||
366
drivers/mfd/rkx110_x120/rkx110_x120.h
Normal file
366
drivers/mfd/rkx110_x120/rkx110_x120.h
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Zhang Yubing <yubing.zhang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RKX110_X120_H
|
||||||
|
#define _RKX110_X120_H
|
||||||
|
|
||||||
|
#include <drm/drm_panel.h>
|
||||||
|
#include <dt-bindings/mfd/rockchip-serdes.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <video/videomode.h>
|
||||||
|
|
||||||
|
#define MAX_PANEL 2
|
||||||
|
#define RK_SERDES_PASSTHROUGH_CNT 11
|
||||||
|
|
||||||
|
#define SERDES_VERSION_V0(type) 0x2201
|
||||||
|
#define SERDES_VERSION_V1(type) (type ? 0x1200001 : 0x1100001)
|
||||||
|
|
||||||
|
#define SER_GRF_CHIP_ID 0x10800
|
||||||
|
#define DES_GRF_CHIP_ID 0x1010400
|
||||||
|
#define HIWORD_MASK(h, l) (GENMASK(h, l) | GENMASK(h, l) << 16)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SERDES_V0 = 0,
|
||||||
|
SERDES_V1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LOCAL_MODE = 0,
|
||||||
|
REMOTE_MODE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STREAM_DISPLAY = 0,
|
||||||
|
STREAM_CAMERA,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DEVICE_LOCAL = 0,
|
||||||
|
DEVICE_REMOTE0,
|
||||||
|
DEVICE_REMOTE1,
|
||||||
|
DEVICE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PORT_REMOTE0,
|
||||||
|
PORT_REMOTE1,
|
||||||
|
PORT_REMOTE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LINK_LANE0,
|
||||||
|
LINK_LANE1,
|
||||||
|
LINK_LANE_DUAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum combtx_phy_mode {
|
||||||
|
COMBTX_PHY_MODE_GPIO,
|
||||||
|
COMBTX_PHY_MODE_VIDEO_LVDS,
|
||||||
|
COMBTX_PHY_MODE_VIDEO_MIPI,
|
||||||
|
COMBTX_PHY_MODE_VIDEO_MINI_LVDS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum comb_phy_id {
|
||||||
|
COMBPHY_0,
|
||||||
|
COMBPHY_1,
|
||||||
|
COMBPHY_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum combrx_phy_mode {
|
||||||
|
COMBRX_PHY_MODE_RGB,
|
||||||
|
COMBRX_PHY_MODE_VIDEO_LVDS,
|
||||||
|
COMBRX_PHY_MODE_VIDEO_MIPI,
|
||||||
|
COMBRX_PHY_MODE_LVDS_CAMERA,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serdes_dsi_mode_flags {
|
||||||
|
SERDES_MIPI_DSI_MODE_VIDEO = 1,
|
||||||
|
SERDES_MIPI_DSI_MODE_VIDEO_BURST = 2,
|
||||||
|
SERDES_MIPI_DSI_MODE_VIDEO_SYNC_PULSE = 4,
|
||||||
|
SERDES_MIPI_DSI_MODE_VIDEO_HFP = 8,
|
||||||
|
SERDES_MIPI_DSI_MODE_VIDEO_HBP = 16,
|
||||||
|
SERDES_MIPI_DSI_MODE_EOT_PACKET = 32,
|
||||||
|
SERDES_MIPI_DSI_CLOCK_NON_CONTINUOUS = 64,
|
||||||
|
SERDES_MIPI_DSI_MODE_LPM = 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serdes_dsi_bus_format {
|
||||||
|
SERDES_MIPI_DSI_FMT_RGB888,
|
||||||
|
SERDES_MIPI_DSI_FMT_RGB666,
|
||||||
|
SERDES_MIPI_DSI_FMT_RGB666_PACKED,
|
||||||
|
SERDES_MIPI_DSI_FMT_RGB565,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serdes_frame_mode {
|
||||||
|
SERDES_FRAME_NORMAL_MODE,
|
||||||
|
SERDES_SP_PIXEL_INTERLEAVED,
|
||||||
|
SERDES_SP_LEFT_RIGHT_SPLIT,
|
||||||
|
SERDES_SP_LINE_INTERLEAVED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct configure_opts_combphy {
|
||||||
|
unsigned int clk_miss;
|
||||||
|
unsigned int clk_post;
|
||||||
|
unsigned int clk_pre;
|
||||||
|
unsigned int clk_prepare;
|
||||||
|
unsigned int clk_settle;
|
||||||
|
unsigned int clk_term_en;
|
||||||
|
unsigned int clk_trail;
|
||||||
|
unsigned int clk_zero;
|
||||||
|
unsigned int d_term_en;
|
||||||
|
unsigned int eot;
|
||||||
|
unsigned int hs_exit;
|
||||||
|
unsigned int hs_prepare;
|
||||||
|
unsigned int hs_settle;
|
||||||
|
unsigned int hs_skip;
|
||||||
|
unsigned int hs_trail;
|
||||||
|
unsigned int hs_zero;
|
||||||
|
unsigned int init;
|
||||||
|
unsigned int lpx;
|
||||||
|
unsigned int ta_get;
|
||||||
|
unsigned int ta_go;
|
||||||
|
unsigned int ta_sure;
|
||||||
|
unsigned int wakeup;
|
||||||
|
unsigned long hs_clk_rate;
|
||||||
|
unsigned long lp_clk_rate;
|
||||||
|
unsigned char lanes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rkx120_combtxphy {
|
||||||
|
enum combtx_phy_mode mode;
|
||||||
|
unsigned int flags;
|
||||||
|
u8 ref_div;
|
||||||
|
u16 fb_div;
|
||||||
|
u8 rate_factor;
|
||||||
|
u64 rate;
|
||||||
|
struct configure_opts_combphy mipi_dphy_cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rkx110_combrxphy {
|
||||||
|
enum combrx_phy_mode mode;
|
||||||
|
u64 rate;
|
||||||
|
struct configure_opts_combphy mipi_dphy_cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rkx120_dsi_tx {
|
||||||
|
int bpp; /* 24/18/16*/
|
||||||
|
enum serdes_dsi_bus_format bus_format;
|
||||||
|
enum serdes_dsi_mode_flags mode_flags;
|
||||||
|
struct videomode *vm;
|
||||||
|
uint8_t channel;
|
||||||
|
uint8_t lanes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rkx110_dsi_rx {
|
||||||
|
enum serdes_dsi_mode_flags mode_flags;
|
||||||
|
struct videomode *vm;
|
||||||
|
uint8_t channel;
|
||||||
|
uint8_t lanes;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OUTPUT,
|
||||||
|
INPUT,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rk_serdes_rate {
|
||||||
|
RATE_2GBPS_83M,
|
||||||
|
RATE_4GBPS_83M,
|
||||||
|
RATE_4GBPS_125M,
|
||||||
|
RATE_4GBPS_250M,
|
||||||
|
RATE_4_5GBPS_140M,
|
||||||
|
RATE_4_8GBPS_150M,
|
||||||
|
RATE_5GBPS_156M,
|
||||||
|
RATE_6GBPS_187M,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FDR_RATE_MODE,
|
||||||
|
HDR_RATE_MODE,
|
||||||
|
QDR_RATE_MODE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rk_serdes_route_type {
|
||||||
|
ROUTE_MULTI_SOURCE = BIT(0),
|
||||||
|
ROUTE_MULTI_LANE = BIT(1),
|
||||||
|
ROUTE_MULTI_CHANNEL = BIT(2),
|
||||||
|
ROUTE_MULTI_REMOTE = BIT(3),
|
||||||
|
ROUTE_MULTI_DSI_INPUT = BIT(20),
|
||||||
|
ROUTE_MULTI_LVDS_INPUT = BIT(21),
|
||||||
|
ROUTE_MULTI_MIRROR = BIT(22),
|
||||||
|
ROUTE_MULTI_SPLIT = BIT(23),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_serdes_pma_pll {
|
||||||
|
uint32_t rate_mode;
|
||||||
|
uint32_t pll_refclk_div;
|
||||||
|
uint32_t pll_div;
|
||||||
|
uint32_t clk_div;
|
||||||
|
bool pll_div4;
|
||||||
|
bool pll_fck_vco_div2;
|
||||||
|
bool force_init_en;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_serdes_reg {
|
||||||
|
const char *name;
|
||||||
|
uint32_t reg_base;
|
||||||
|
uint32_t reg_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_serdes_route {
|
||||||
|
u32 stream_type;
|
||||||
|
struct videomode vm;
|
||||||
|
enum serdes_frame_mode frame_mode;
|
||||||
|
u32 local_port0;
|
||||||
|
u32 local_port1;
|
||||||
|
u32 remote0_port0;
|
||||||
|
u32 remote0_port1;
|
||||||
|
u32 remote1_port0;
|
||||||
|
u32 remote1_port1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_serdes_chip {
|
||||||
|
bool is_remote;
|
||||||
|
struct i2c_client *client;
|
||||||
|
struct hwclk *hwclk;
|
||||||
|
struct rk_serdes *serdes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pattern_gen {
|
||||||
|
const char *name;
|
||||||
|
struct rk_serdes_chip *chip;
|
||||||
|
u32 base;
|
||||||
|
u32 link_src_reg;
|
||||||
|
u8 link_src_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_serdes_pt_pin {
|
||||||
|
u32 bank;
|
||||||
|
u32 pin;
|
||||||
|
u32 incfgs;
|
||||||
|
u32 outcfgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_serdes_pt {
|
||||||
|
u32 en_reg;
|
||||||
|
u32 en_mask;
|
||||||
|
u32 en_val;
|
||||||
|
u32 dir_reg;
|
||||||
|
u32 dir_mask;
|
||||||
|
u32 dir_val;
|
||||||
|
int configs;
|
||||||
|
struct rk_serdes_pt_pin pt_pins[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_serdes {
|
||||||
|
struct device *dev;
|
||||||
|
struct rk_serdes_chip chip[DEVICE_MAX];
|
||||||
|
struct gpio_desc *reset;
|
||||||
|
struct gpio_desc *enable;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Control by I2C-Debug
|
||||||
|
*/
|
||||||
|
bool rkx110_debug;
|
||||||
|
bool rkx120_debug;
|
||||||
|
|
||||||
|
enum rk_serdes_rate rate;
|
||||||
|
|
||||||
|
struct dentry *debugfs_root;
|
||||||
|
struct dentry *debugfs_local;
|
||||||
|
struct dentry *debugfs_remote0;
|
||||||
|
struct dentry *debugfs_remote1;
|
||||||
|
struct dentry *debugfs_rate;
|
||||||
|
|
||||||
|
struct videomode *vm;
|
||||||
|
u32 stream_type;
|
||||||
|
u32 version;
|
||||||
|
u32 route_flag;
|
||||||
|
u8 remote_nr;
|
||||||
|
struct rkx110_combrxphy combrxphy;
|
||||||
|
struct rkx110_dsi_rx dsi_rx;
|
||||||
|
struct rkx120_combtxphy combtxphy;
|
||||||
|
struct rkx120_dsi_tx dsi_tx;
|
||||||
|
|
||||||
|
int (*i2c_read_reg)(struct i2c_client *client, u32 addr, u32 *value);
|
||||||
|
int (*i2c_write_reg)(struct i2c_client *client, u32 addr, u32 value);
|
||||||
|
int (*i2c_update_bits)(struct i2c_client *client, u32 reg, u32 mask, u32 val);
|
||||||
|
int (*route_prepare)(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||||
|
int (*route_enable)(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||||
|
int (*route_disable)(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||||
|
int (*route_unprepare)(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||||
|
int (*set_hwpin)(struct rk_serdes *serdes, struct i2c_client *client,
|
||||||
|
int pintype, int bank, uint32_t mpins, uint32_t param);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmd_ctrl_hdr {
|
||||||
|
u8 dtype; /* data type */
|
||||||
|
u8 wait; /* ms */
|
||||||
|
u8 dlen; /* payload len */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct cmd_desc {
|
||||||
|
struct cmd_ctrl_hdr dchdr;
|
||||||
|
u8 *payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct panel_cmds {
|
||||||
|
u8 *buf;
|
||||||
|
int blen;
|
||||||
|
struct cmd_desc *cmds;
|
||||||
|
int cmd_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_serdes_panel {
|
||||||
|
struct drm_panel panel;
|
||||||
|
struct device *dev;
|
||||||
|
struct rk_serdes *parent;
|
||||||
|
struct rk_serdes_route route;
|
||||||
|
unsigned int bus_format;
|
||||||
|
int link_mode;
|
||||||
|
|
||||||
|
struct panel_cmds *on_cmds;
|
||||||
|
struct panel_cmds *off_cmds;
|
||||||
|
|
||||||
|
struct regulator *supply;
|
||||||
|
struct gpio_desc *enable_gpio;
|
||||||
|
struct gpio_desc *reset_gpio;
|
||||||
|
};
|
||||||
|
|
||||||
|
int rkx110_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||||
|
void rkx110_linktx_video_enable(struct rk_serdes *serdes, u8 dev_id, bool enable);
|
||||||
|
void rkx110_linktx_channel_enable(struct rk_serdes *serdes, u8 ch_id, u8 dev_id, bool enable);
|
||||||
|
void rkx120_linkrx_engine_enable(struct rk_serdes *serdes, u8 en_id, u8 dev_id, bool enable);
|
||||||
|
void rkx110_set_stream_source(struct rk_serdes *serdes, int local_port, u8 dev_id);
|
||||||
|
int rkx120_linkrx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id);
|
||||||
|
int rkx120_rgb_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id);
|
||||||
|
int rkx120_lvds_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id,
|
||||||
|
u8 phy_id);
|
||||||
|
void rkx120_linkrx_gpi_gpo_mux_cfg(struct rk_serdes *serdes, u32 mux, u8 remote_id);
|
||||||
|
void rkx110_linktx_gpi_gpo_mux_cfg(struct rk_serdes *serdes, u32 mux, u8 remote_id);
|
||||||
|
int rkx110_rgb_rx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||||
|
int rkx110_lvds_rx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, int id);
|
||||||
|
void rkx110_debugfs_init(struct rk_serdes_chip *chip, struct dentry *dentry);
|
||||||
|
void rkx120_debugfs_init(struct rk_serdes_chip *chip, struct dentry *dentry);
|
||||||
|
void rkx110_pma_set_rate(struct rk_serdes *serdes, struct rk_serdes_pma_pll *pll,
|
||||||
|
u8 pcs_id, u8 dev_id);
|
||||||
|
void rkx120_pma_set_rate(struct rk_serdes *serdes, struct rk_serdes_pma_pll *pll,
|
||||||
|
u8 pcs_id, u8 dev_id);
|
||||||
|
void rkx110_pcs_enable(struct rk_serdes *serdes, bool enable, u8 pcs_id, u8 dev_id);
|
||||||
|
void rkx120_pcs_enable(struct rk_serdes *serdes, bool enable, u8 pcs_id, u8 dev_id);
|
||||||
|
void rkx110_ser_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 remote_id);
|
||||||
|
void rkx120_des_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 remote_id);
|
||||||
|
void rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id);
|
||||||
|
void rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id);
|
||||||
|
void rkx110_x120_pattern_gen_debugfs_create_file(struct pattern_gen *pattern_gen,
|
||||||
|
struct rk_serdes_chip *chip,
|
||||||
|
struct dentry *dentry);
|
||||||
|
void rkx110_linktx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32 func_id,
|
||||||
|
bool is_rx);
|
||||||
|
void rkx120_linkrx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32 func_id,
|
||||||
|
bool is_rx);
|
||||||
|
#endif
|
||||||
1100
drivers/mfd/rkx110_x120/rkx110_x120_core.c
Normal file
1100
drivers/mfd/rkx110_x120/rkx110_x120_core.c
Normal file
File diff suppressed because it is too large
Load Diff
642
drivers/mfd/rkx110_x120/rkx110_x120_panel.c
Normal file
642
drivers/mfd/rkx110_x120/rkx110_x120_panel.c
Normal file
@@ -0,0 +1,642 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* rockchip SerDes Panele driver for drm platform
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/of_graph.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#include <video/display_timing.h>
|
||||||
|
#include <video/of_display_timing.h>
|
||||||
|
#include <video/videomode.h>
|
||||||
|
|
||||||
|
#include <drm/drm_crtc.h>
|
||||||
|
#include <drm/drm_mipi_dsi.h>
|
||||||
|
#include <drm/drm_panel.h>
|
||||||
|
|
||||||
|
#include "rkx110_x120.h"
|
||||||
|
#include "rkx120_dsi_tx.h"
|
||||||
|
|
||||||
|
static inline struct rk_serdes_panel *to_serdes_panel(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
return container_of(panel, struct rk_serdes_panel, panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_prepare(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||||
|
struct rk_serdes_route *route = &sd_panel->route;
|
||||||
|
struct rk_serdes *serdes = sd_panel->parent;
|
||||||
|
|
||||||
|
if (sd_panel->supply) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = regulator_enable(sd_panel->supply);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(sd_panel->dev, "failed to enable supply: %d\n",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
mdelay(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sd_panel->enable_gpio) {
|
||||||
|
gpiod_set_value_cansleep(sd_panel->enable_gpio, 1);
|
||||||
|
mdelay(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sd_panel->reset_gpio) {
|
||||||
|
gpiod_set_value_cansleep(sd_panel->reset_gpio, 1);
|
||||||
|
mdelay(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serdes->route_prepare)
|
||||||
|
serdes->route_prepare(serdes, &sd_panel->route);
|
||||||
|
|
||||||
|
if (route->remote0_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds))
|
||||||
|
rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE0,
|
||||||
|
sd_panel->on_cmds);
|
||||||
|
|
||||||
|
if (route->remote1_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds))
|
||||||
|
rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE1,
|
||||||
|
sd_panel->on_cmds);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_enable(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||||
|
struct rk_serdes *serdes = sd_panel->parent;
|
||||||
|
|
||||||
|
if (serdes->route_enable)
|
||||||
|
serdes->route_enable(serdes, &sd_panel->route);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_disable(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||||
|
struct rk_serdes *serdes = sd_panel->parent;
|
||||||
|
|
||||||
|
|
||||||
|
if (serdes->route_disable)
|
||||||
|
serdes->route_disable(serdes, &sd_panel->route);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_unprepare(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||||
|
struct rk_serdes_route *route = &sd_panel->route;
|
||||||
|
struct rk_serdes *serdes = sd_panel->parent;
|
||||||
|
|
||||||
|
if (route->remote0_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds))
|
||||||
|
rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE0,
|
||||||
|
sd_panel->off_cmds);
|
||||||
|
|
||||||
|
if (route->remote1_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds))
|
||||||
|
rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE1,
|
||||||
|
sd_panel->off_cmds);
|
||||||
|
if (serdes->route_unprepare)
|
||||||
|
serdes->route_unprepare(serdes, &sd_panel->route);
|
||||||
|
|
||||||
|
if (sd_panel->reset_gpio) {
|
||||||
|
gpiod_set_value_cansleep(sd_panel->reset_gpio, 0);
|
||||||
|
mdelay(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sd_panel->enable_gpio) {
|
||||||
|
gpiod_set_value_cansleep(sd_panel->enable_gpio, 0);
|
||||||
|
mdelay(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sd_panel->supply)
|
||||||
|
regulator_disable(sd_panel->supply);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_of_get_native_mode(struct rk_serdes_panel *sd_panel,
|
||||||
|
struct drm_connector *connector)
|
||||||
|
{
|
||||||
|
struct rk_serdes_route *route = &sd_panel->route;
|
||||||
|
struct device_node *timings_np;
|
||||||
|
struct drm_display_mode *mode;
|
||||||
|
struct drm_device *drm = connector->dev;
|
||||||
|
u32 bus_flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
timings_np = of_get_child_by_name(sd_panel->dev->of_node, "display-timings");
|
||||||
|
if (!timings_np) {
|
||||||
|
dev_err(sd_panel->dev, "failed to find display-timings node\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
of_node_put(timings_np);
|
||||||
|
|
||||||
|
mode = drm_mode_create(drm);
|
||||||
|
if (!mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = of_get_drm_display_mode(sd_panel->dev->of_node, mode,
|
||||||
|
&bus_flags, OF_USE_NATIVE_MODE);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(sd_panel->dev, "failed to find dts display timings\n");
|
||||||
|
drm_mode_destroy(drm, mode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_mode_set_name(mode);
|
||||||
|
connector->display_info.bus_flags = bus_flags;
|
||||||
|
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||||
|
drm_mode_probed_add(connector, mode);
|
||||||
|
drm_display_mode_to_videomode(mode, &sd_panel->route.vm);
|
||||||
|
|
||||||
|
if (route->frame_mode == SERDES_SP_LEFT_RIGHT_SPLIT ||
|
||||||
|
route->frame_mode == SERDES_SP_PIXEL_INTERLEAVED) {
|
||||||
|
sd_panel->route.vm.pixelclock /= 2;
|
||||||
|
sd_panel->route.vm.hactive /= 2;
|
||||||
|
sd_panel->route.vm.hfront_porch /= 2;
|
||||||
|
sd_panel->route.vm.hback_porch /= 2;
|
||||||
|
sd_panel->route.vm.hsync_len /= 2;
|
||||||
|
} else if (route->frame_mode == SERDES_SP_LINE_INTERLEAVED) {
|
||||||
|
sd_panel->route.vm.pixelclock /= 2;
|
||||||
|
sd_panel->route.vm.vactive /= 2;
|
||||||
|
sd_panel->route.vm.vfront_porch /= 2;
|
||||||
|
sd_panel->route.vm.vback_porch /= 2;
|
||||||
|
sd_panel->route.vm.vsync_len /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_get_modes(struct drm_panel *panel,
|
||||||
|
struct drm_connector *connector)
|
||||||
|
{
|
||||||
|
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
num += serdes_panel_of_get_native_mode(sd_panel, connector);
|
||||||
|
drm_display_info_set_bus_formats(&connector->display_info,
|
||||||
|
&sd_panel->bus_format, 1);
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_panel_funcs serdes_panel_funcs = {
|
||||||
|
.prepare = serdes_panel_prepare,
|
||||||
|
.enable = serdes_panel_enable,
|
||||||
|
.disable = serdes_panel_disable,
|
||||||
|
.unprepare = serdes_panel_unprepare,
|
||||||
|
.get_modes = serdes_panel_get_modes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
dsi_panel_parse_cmds(struct device *dev, const u8 *data,
|
||||||
|
int blen, struct panel_cmds *pcmds)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
char *buf, *bp;
|
||||||
|
struct cmd_ctrl_hdr *dchdr;
|
||||||
|
int i, cnt;
|
||||||
|
|
||||||
|
if (!pcmds)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
buf = devm_kmemdup(dev, data, blen, GFP_KERNEL);
|
||||||
|
if (!buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* scan init commands */
|
||||||
|
bp = buf;
|
||||||
|
len = blen;
|
||||||
|
cnt = 0;
|
||||||
|
while (len > sizeof(*dchdr)) {
|
||||||
|
dchdr = (struct cmd_ctrl_hdr *)bp;
|
||||||
|
|
||||||
|
if (dchdr->dlen > len) {
|
||||||
|
dev_err(dev, "%s: error, len=%d", __func__, dchdr->dlen);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bp += sizeof(*dchdr);
|
||||||
|
len -= sizeof(*dchdr);
|
||||||
|
bp += dchdr->dlen;
|
||||||
|
len -= dchdr->dlen;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != 0) {
|
||||||
|
dev_err(dev, "%s: dcs_cmd=%x len=%d error!", __func__, buf[0], blen);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcmds->cmds = devm_kcalloc(dev, cnt, sizeof(struct cmd_desc), GFP_KERNEL);
|
||||||
|
if (!pcmds->cmds)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pcmds->cmd_cnt = cnt;
|
||||||
|
pcmds->buf = buf;
|
||||||
|
pcmds->blen = blen;
|
||||||
|
|
||||||
|
bp = buf;
|
||||||
|
len = blen;
|
||||||
|
for (i = 0; i < cnt; i++) {
|
||||||
|
dchdr = (struct cmd_ctrl_hdr *)bp;
|
||||||
|
len -= sizeof(*dchdr);
|
||||||
|
bp += sizeof(*dchdr);
|
||||||
|
pcmds->cmds[i].dchdr = *dchdr;
|
||||||
|
pcmds->cmds[i].payload = bp;
|
||||||
|
bp += dchdr->dlen;
|
||||||
|
len -= dchdr->dlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_dsi_panel_get_cmds(struct rk_serdes_panel *sd_panel)
|
||||||
|
{
|
||||||
|
struct device_node *np = sd_panel->dev->of_node;
|
||||||
|
struct device *dev = sd_panel->dev;
|
||||||
|
const void *data;
|
||||||
|
int len, err;
|
||||||
|
|
||||||
|
data = of_get_property(np, "panel-init-sequence", &len);
|
||||||
|
if (data) {
|
||||||
|
sd_panel->on_cmds = devm_kzalloc(dev, sizeof(*sd_panel->on_cmds), GFP_KERNEL);
|
||||||
|
if (!sd_panel->on_cmds)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
err = dsi_panel_parse_cmds(dev, data, len, sd_panel->on_cmds);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "failed to parse dsi panel init sequence\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data = of_get_property(np, "panel-exit-sequence", &len);
|
||||||
|
if (data) {
|
||||||
|
sd_panel->off_cmds = devm_kzalloc(dev, sizeof(*sd_panel->off_cmds), GFP_KERNEL);
|
||||||
|
if (!sd_panel->off_cmds)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
err = dsi_panel_parse_cmds(dev, data, len, sd_panel->off_cmds);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "failed to parse dsi panel exit sequence\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mipi_dsi_device *serdes_attach_dsi(struct rk_serdes_panel *sd_panel,
|
||||||
|
struct device_node *dsi_node)
|
||||||
|
{
|
||||||
|
const struct mipi_dsi_device_info info = { "serdes", 0, NULL };
|
||||||
|
struct mipi_dsi_device *dsi;
|
||||||
|
struct mipi_dsi_host *host;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
host = of_find_mipi_dsi_host_by_node(dsi_node);
|
||||||
|
if (!host) {
|
||||||
|
dev_err(sd_panel->dev, "failed to find dsi host\n");
|
||||||
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
dsi = mipi_dsi_device_register_full(host, &info);
|
||||||
|
if (IS_ERR(dsi)) {
|
||||||
|
dev_err(sd_panel->dev, "failed to create dsi device\n");
|
||||||
|
return dsi;
|
||||||
|
}
|
||||||
|
|
||||||
|
dsi->lanes = 4;
|
||||||
|
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||||
|
dsi->mode_flags = MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET |
|
||||||
|
MIPI_DSI_CLOCK_NON_CONTINUOUS;
|
||||||
|
|
||||||
|
ret = mipi_dsi_attach(dsi);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(sd_panel->dev, "failed to attach dsi to host\n");
|
||||||
|
mipi_dsi_device_unregister(dsi);
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dsi;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rkx120_dsi_rx_parse(struct rk_serdes_panel *sd_panel)
|
||||||
|
{
|
||||||
|
struct device_node *np = sd_panel->dev->of_node;
|
||||||
|
struct rk_serdes *serdes = sd_panel->parent;
|
||||||
|
struct rkx110_dsi_rx *dsi_rx = &serdes->dsi_rx;
|
||||||
|
struct mipi_dsi_device *dsi;
|
||||||
|
struct device_node *dsi_node;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (of_property_read_u32(np, "dsi-rx,lanes", &val))
|
||||||
|
dsi_rx->lanes = 4;
|
||||||
|
else
|
||||||
|
dsi_rx->lanes = val;
|
||||||
|
|
||||||
|
if (of_property_read_bool(np, "dsi-rx,video-mode"))
|
||||||
|
dsi_rx->mode_flags |= SERDES_MIPI_DSI_MODE_LPM | SERDES_MIPI_DSI_MODE_VIDEO |
|
||||||
|
SERDES_MIPI_DSI_MODE_VIDEO_BURST;
|
||||||
|
else
|
||||||
|
dsi_rx->mode_flags |= SERDES_MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
dsi_node = of_graph_get_remote_node(np, 0, -1);
|
||||||
|
if (!dsi_node)
|
||||||
|
dev_err(sd_panel->dev, "failed to get remote node for primary dsi\n");
|
||||||
|
|
||||||
|
dsi = serdes_attach_dsi(sd_panel, dsi_node);
|
||||||
|
if (IS_ERR(dsi))
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rkx120_dsi_tx_parse(struct rk_serdes_panel *sd_panel)
|
||||||
|
{
|
||||||
|
struct device_node *np = sd_panel->dev->of_node;
|
||||||
|
struct rk_serdes *serdes = sd_panel->parent;
|
||||||
|
struct rkx120_dsi_tx *dsi_tx = &serdes->dsi_tx;
|
||||||
|
const char *string;
|
||||||
|
int ret;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (of_property_read_u32(np, "dsi-tx,lanes", &val))
|
||||||
|
dsi_tx->lanes = 4;
|
||||||
|
else
|
||||||
|
dsi_tx->lanes = val;
|
||||||
|
|
||||||
|
if (of_property_read_bool(np, "dsi-tx,video-mode"))
|
||||||
|
dsi_tx->mode_flags |= SERDES_MIPI_DSI_MODE_LPM | SERDES_MIPI_DSI_MODE_VIDEO |
|
||||||
|
SERDES_MIPI_DSI_MODE_VIDEO_BURST;
|
||||||
|
else
|
||||||
|
dsi_tx->mode_flags |= SERDES_MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
if (of_property_read_bool(np, "dsi-tx,eotp"))
|
||||||
|
dsi_tx->mode_flags |= SERDES_MIPI_DSI_MODE_EOT_PACKET;
|
||||||
|
|
||||||
|
if (!of_property_read_string(np, "dsi-tx,format", &string)) {
|
||||||
|
if (!strcmp(string, "rgb666")) {
|
||||||
|
dsi_tx->bus_format = SERDES_MIPI_DSI_FMT_RGB666;
|
||||||
|
dsi_tx->bpp = 24;
|
||||||
|
} else if (!strcmp(string, "rgb666-packed")) {
|
||||||
|
dsi_tx->bus_format = SERDES_MIPI_DSI_FMT_RGB666_PACKED;
|
||||||
|
dsi_tx->bpp = 18;
|
||||||
|
} else if (!strcmp(string, "rgb565")) {
|
||||||
|
dsi_tx->bus_format = SERDES_MIPI_DSI_FMT_RGB565;
|
||||||
|
dsi_tx->bpp = 16;
|
||||||
|
} else {
|
||||||
|
dsi_tx->bus_format = SERDES_MIPI_DSI_FMT_RGB888;
|
||||||
|
dsi_tx->bpp = 24;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dsi_tx->bus_format = SERDES_MIPI_DSI_FMT_RGB888;
|
||||||
|
dsi_tx->bpp = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = serdes_dsi_panel_get_cmds(sd_panel);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(sd_panel->dev, "failed to get cmds\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_parse_dt(struct rk_serdes_panel *sd_panel)
|
||||||
|
{
|
||||||
|
struct rk_serdes_route *route = &sd_panel->route;
|
||||||
|
struct rk_serdes *serdes = sd_panel->parent;
|
||||||
|
u32 lanes;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
device_property_read_u32(sd_panel->dev, "local-port0", &route->local_port0);
|
||||||
|
device_property_read_u32(sd_panel->dev, "local-port1", &route->local_port1);
|
||||||
|
device_property_read_u32(sd_panel->dev, "remote0-port0", &route->remote0_port0);
|
||||||
|
device_property_read_u32(sd_panel->dev, "remote0-port1", &route->remote0_port1);
|
||||||
|
device_property_read_u32(sd_panel->dev, "remote1-port0", &route->remote1_port0);
|
||||||
|
device_property_read_u32(sd_panel->dev, "remote1-port1", &route->remote1_port1);
|
||||||
|
device_property_read_u32(sd_panel->dev, "num-lanes", &lanes);
|
||||||
|
|
||||||
|
serdes->route_flag = 0;
|
||||||
|
|
||||||
|
if (!route->local_port0) {
|
||||||
|
dev_err(sd_panel->dev, "local_port0 should set\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!route->remote0_port0) {
|
||||||
|
dev_err(sd_panel->dev, "remote0_port0 should set\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route->remote1_port0 && route->remote0_port1) {
|
||||||
|
dev_err(sd_panel->dev, "too many output\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
route->frame_mode = SERDES_FRAME_NORMAL_MODE;
|
||||||
|
|
||||||
|
/* 2 video stream output */
|
||||||
|
if (route->remote1_port0 || route->remote0_port1) {
|
||||||
|
if (route->remote1_port0)
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_REMOTE | ROUTE_MULTI_CHANNEL |
|
||||||
|
ROUTE_MULTI_LANE;
|
||||||
|
|
||||||
|
if (route->remote0_port1) {
|
||||||
|
if ((route->remote0_port0 == RK_SERDES_LVDS_TX0) &&
|
||||||
|
(route->remote0_port1 == RK_SERDES_LVDS_TX1)) {
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_CHANNEL;
|
||||||
|
} else if ((route->remote0_port0 == RK_SERDES_LVDS_TX1) &&
|
||||||
|
(route->remote0_port1 == RK_SERDES_LVDS_TX0)) {
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_CHANNEL;
|
||||||
|
} else {
|
||||||
|
dev_err(sd_panel->dev, "invalid multi output type\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lanes == 2)
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_LANE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route->local_port1) {
|
||||||
|
if ((route->local_port0 == RK_SERDES_DSI_RX0) &&
|
||||||
|
(route->local_port1 == RK_SERDES_DSI_RX1))
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_DSI_INPUT;
|
||||||
|
else if ((route->local_port0 == RK_SERDES_DSI_RX1) &&
|
||||||
|
(route->local_port1 == RK_SERDES_DSI_RX0))
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_DSI_INPUT;
|
||||||
|
else if ((route->local_port0 == RK_SERDES_LVDS_RX0) &&
|
||||||
|
(route->local_port1 == RK_SERDES_LVDS_RX1))
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_LVDS_INPUT;
|
||||||
|
else if ((route->local_port0 == RK_SERDES_LVDS_RX1) &&
|
||||||
|
(route->local_port1 == RK_SERDES_LVDS_RX0))
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_LVDS_INPUT;
|
||||||
|
else {
|
||||||
|
dev_err(sd_panel->dev, "invalid multi input type\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_SOURCE;
|
||||||
|
} else {
|
||||||
|
if (device_property_read_bool(sd_panel->dev, "split-mode")) {
|
||||||
|
/* only dsi input support split mode */
|
||||||
|
if ((route->local_port0 != RK_SERDES_DSI_RX0) &&
|
||||||
|
(route->local_port0 != RK_SERDES_DSI_RX1)) {
|
||||||
|
dev_err(sd_panel->dev,
|
||||||
|
"local_port should be dsi in split mode\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (device_property_read_bool(sd_panel->dev,
|
||||||
|
"sf-pixel-interleaved"))
|
||||||
|
route->frame_mode = SERDES_SP_PIXEL_INTERLEAVED;
|
||||||
|
else if (device_property_read_bool(sd_panel->dev,
|
||||||
|
"sf-line-interleaved"))
|
||||||
|
route->frame_mode = SERDES_SP_LINE_INTERLEAVED;
|
||||||
|
else
|
||||||
|
route->frame_mode = SERDES_SP_LEFT_RIGHT_SPLIT;
|
||||||
|
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_SPLIT;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_MIRROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lanes == 2)
|
||||||
|
serdes->route_flag |= ROUTE_MULTI_LANE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route->remote0_port0 & RK_SERDES_DSI_TX0 ||
|
||||||
|
route->remote1_port0 & RK_SERDES_DSI_TX0) {
|
||||||
|
ret = rkx120_dsi_tx_parse(sd_panel);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(sd_panel->dev, "failed to get cmds\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route->local_port0 & RK_SERDES_DSI_RX0 ||
|
||||||
|
route->local_port0 & RK_SERDES_DSI_TX1) {
|
||||||
|
ret = rkx120_dsi_rx_parse(sd_panel);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct rk_serdes *serdes = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct rk_serdes_panel *sd_panel;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
sd_panel = devm_kzalloc(&pdev->dev, sizeof(*sd_panel), GFP_KERNEL);
|
||||||
|
if (!sd_panel)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
sd_panel->dev = &pdev->dev;
|
||||||
|
sd_panel->parent = serdes;
|
||||||
|
sd_panel->route.stream_type = STREAM_DISPLAY;
|
||||||
|
serdes->vm = &sd_panel->route.vm;
|
||||||
|
|
||||||
|
sd_panel->supply = devm_regulator_get_optional(sd_panel->dev, "power");
|
||||||
|
if (IS_ERR(sd_panel->supply)) {
|
||||||
|
ret = PTR_ERR(sd_panel->supply);
|
||||||
|
|
||||||
|
if (ret != -ENODEV) {
|
||||||
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(sd_panel->dev, "failed to request regulator: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_panel->supply = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get GPIOs and backlight controller. */
|
||||||
|
sd_panel->enable_gpio = devm_gpiod_get_optional(sd_panel->dev, "enable",
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(sd_panel->enable_gpio)) {
|
||||||
|
ret = PTR_ERR(sd_panel->enable_gpio);
|
||||||
|
dev_err(sd_panel->dev, "failed to request %s GPIO: %d\n",
|
||||||
|
"enable", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_panel->reset_gpio = devm_gpiod_get_optional(sd_panel->dev, "reset",
|
||||||
|
GPIOD_OUT_HIGH);
|
||||||
|
if (IS_ERR(sd_panel->reset_gpio)) {
|
||||||
|
ret = PTR_ERR(sd_panel->reset_gpio);
|
||||||
|
dev_err(sd_panel->dev, "failed to request %s GPIO: %d\n",
|
||||||
|
"reset", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register the panel. */
|
||||||
|
drm_panel_init(&sd_panel->panel, sd_panel->dev, &serdes_panel_funcs, 0);
|
||||||
|
|
||||||
|
ret = drm_panel_of_backlight(&sd_panel->panel);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
drm_panel_add(&sd_panel->panel);
|
||||||
|
|
||||||
|
dev_set_drvdata(sd_panel->dev, sd_panel);
|
||||||
|
|
||||||
|
ret = serdes_panel_parse_dt(sd_panel);
|
||||||
|
if (ret < 0) {
|
||||||
|
drm_panel_remove(&sd_panel->panel);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serdes_panel_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct rk_serdes_panel *sd_panel = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
drm_panel_remove(&sd_panel->panel);
|
||||||
|
|
||||||
|
drm_panel_disable(&sd_panel->panel);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id serdes_panel_of_table[] = {
|
||||||
|
{ .compatible = "rockchip,serdes-panel", },
|
||||||
|
{ /* Sentinel */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, serdes_panel_of_table);
|
||||||
|
|
||||||
|
static struct platform_driver serdes_panel_driver = {
|
||||||
|
.probe = serdes_panel_probe,
|
||||||
|
.remove = serdes_panel_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "serdes-panel",
|
||||||
|
.of_match_table = serdes_panel_of_table,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(serdes_panel_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Zhang Yubing <yubing.zhang@rock-chips.com>");
|
||||||
|
MODULE_DESCRIPTION("RKx110 RKx120 Panel Driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
309
drivers/mfd/rkx110_x120/rkx120.c
Normal file
309
drivers/mfd/rkx110_x120/rkx120.c
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Andy Yan <Andy.yan@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dt-bindings/mfd/rockchip-serdes.h>
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
|
||||||
|
#include "hal/cru_api.h"
|
||||||
|
#include "hal/pinctrl_api.h"
|
||||||
|
#include "rkx110_x120.h"
|
||||||
|
#include "rkx120_reg.h"
|
||||||
|
#include "serdes_combphy.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEBUG_FS)
|
||||||
|
static struct pattern_gen rkx120_pattern_gen[] = {
|
||||||
|
{
|
||||||
|
.name = "dsi",
|
||||||
|
.base = RKX120_PATTERN_GEN_DSI_BASE,
|
||||||
|
.link_src_reg = DES_GRF_SOC_CON2,
|
||||||
|
.link_src_offset = 12,
|
||||||
|
}, {
|
||||||
|
.name = "lvds0",
|
||||||
|
.base = RKX120_PATTERN_GEN_LVDS0_BASE,
|
||||||
|
.link_src_reg = DES_GRF_SOC_CON2,
|
||||||
|
.link_src_offset = 13,
|
||||||
|
}, {
|
||||||
|
.name = "lvds1",
|
||||||
|
.base = RKX120_PATTERN_GEN_LVDS1_BASE,
|
||||||
|
.link_src_reg = DES_GRF_SOC_CON2,
|
||||||
|
.link_src_offset = 14,
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rk_serdes_reg rkx120_regs[] = {
|
||||||
|
{
|
||||||
|
.name = "grf",
|
||||||
|
.reg_base = RKX120_DES_GRF_BASE,
|
||||||
|
.reg_len = 0x410,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "cru",
|
||||||
|
.reg_base = RKX120_DES_CRU_BASE,
|
||||||
|
.reg_len = 0xF04,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "dvp",
|
||||||
|
.reg_base = RKX120_DVP_TX_BASE,
|
||||||
|
.reg_len = 0x1d0,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "grf_mipi0",
|
||||||
|
.reg_base = RKX120_GRF_MIPI0_BASE,
|
||||||
|
.reg_len = 0x600,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "grf_mipi1",
|
||||||
|
.reg_base = RKX120_GRF_MIPI1_BASE,
|
||||||
|
.reg_len = 0x600,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "mipi_lvds_phy0",
|
||||||
|
.reg_base = RKX120_MIPI_LVDS_TX_PHY0_BASE,
|
||||||
|
.reg_len = 0x70,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "mipi_lvds_phy1",
|
||||||
|
.reg_base = RKX120_MIPI_LVDS_TX_PHY1_BASE,
|
||||||
|
.reg_len = 0x70,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "dsihost",
|
||||||
|
.reg_base = RKX120_DSI_TX_BASE,
|
||||||
|
.reg_len = 0x190,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "gpio0",
|
||||||
|
.reg_base = RKX120_GPIO0_TX_BASE,
|
||||||
|
.reg_len = 0x80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "gpio1",
|
||||||
|
.reg_base = RKX120_GPIO1_TX_BASE,
|
||||||
|
.reg_len = 0x80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "csi_tx0",
|
||||||
|
.reg_base = RKX120_CSI_TX0_BASE,
|
||||||
|
.reg_len = 0x1D0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "csi_tx1",
|
||||||
|
.reg_base = RKX120_CSI_TX1_BASE,
|
||||||
|
.reg_len = 0x1D0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "rklink",
|
||||||
|
.reg_base = RKX120_DES_RKLINK_BASE,
|
||||||
|
.reg_len = 0xD4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "pcs0",
|
||||||
|
.reg_base = RKX120_DES_PCS0_BASE,
|
||||||
|
.reg_len = 0x1c0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "pcs1",
|
||||||
|
.reg_base = RKX120_DES_PCS1_BASE,
|
||||||
|
.reg_len = 0x1c0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "pma0",
|
||||||
|
.reg_base = RKX120_DES_PMA0_BASE,
|
||||||
|
.reg_len = 0x100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "pma1",
|
||||||
|
.reg_base = RKX120_DES_PMA1_BASE,
|
||||||
|
.reg_len = 0x100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "dsi_pattern_gen",
|
||||||
|
.reg_base = RKX120_PATTERN_GEN_DSI_BASE,
|
||||||
|
.reg_len = 0x18,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "lvds0_pattern_gen",
|
||||||
|
.reg_base = RKX120_PATTERN_GEN_LVDS0_BASE,
|
||||||
|
.reg_len = 0x18,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "lvds1_pattern_gen",
|
||||||
|
.reg_base = RKX120_PATTERN_GEN_LVDS1_BASE,
|
||||||
|
.reg_len = 0x18,
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rkx120_reg_show(struct seq_file *s, void *v)
|
||||||
|
{
|
||||||
|
const struct rk_serdes_reg *regs = rkx120_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, "rkx120_%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 rkx120_reg_write(struct file *file, const char __user *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
const struct rk_serdes_reg *regs = rkx120_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 rkx120_reg_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct rk_serdes_chip *chip = inode->i_private;
|
||||||
|
|
||||||
|
return single_open(file, rkx120_reg_show, chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations rkx120_reg_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = rkx120_reg_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.write = rkx120_reg_write,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
void rkx120_debugfs_init(struct rk_serdes_chip *chip, struct dentry *dentry)
|
||||||
|
{
|
||||||
|
const struct rk_serdes_reg *regs = rkx120_regs;
|
||||||
|
struct pattern_gen *pattern_gen = rkx120_pattern_gen;
|
||||||
|
struct dentry *dir;
|
||||||
|
|
||||||
|
dir = debugfs_create_dir("registers", dentry);
|
||||||
|
if (!IS_ERR(dir)) {
|
||||||
|
while (regs->name) {
|
||||||
|
debugfs_create_file(regs->name, 0600, dir, chip, &rkx120_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 rkx120_rgb_tx_iomux_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route,
|
||||||
|
u8 remote_id)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[remote_id].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_RKX120, RK_SERDES_DES_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_RKX120, RK_SERDES_DES_GPIO_BANK1, pins,
|
||||||
|
RK_SERDES_PIN_CONFIG_MUX_FUNC1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rkx120_rgb_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route,
|
||||||
|
u8 remote_id)
|
||||||
|
{
|
||||||
|
rkx120_rgb_tx_iomux_cfg(serdes, route, remote_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rkx120_lvds_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id,
|
||||||
|
u8 phy_id)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[remote_id].client;
|
||||||
|
|
||||||
|
if (phy_id) {
|
||||||
|
serdes->i2c_write_reg(client, DES_GRF_SOC_CON7, 0xfff00630);
|
||||||
|
serdes->i2c_write_reg(client, DES_GRF_SOC_CON2, 0x00200020);
|
||||||
|
} else {
|
||||||
|
serdes->i2c_write_reg(client, DES_GRF_SOC_CON6, 0x0fff0063);
|
||||||
|
serdes->i2c_write_reg(client, DES_GRF_SOC_CON2, 0x00040004);
|
||||||
|
}
|
||||||
|
|
||||||
|
rkx120_combtxphy_set_mode(serdes, COMBTX_PHY_MODE_VIDEO_LVDS);
|
||||||
|
if (route->remote0_port0 & RK_SERDES_DUAL_LVDS_TX)
|
||||||
|
rkx120_combtxphy_set_rate(serdes, route->vm.pixelclock * 7 / 2);
|
||||||
|
else
|
||||||
|
rkx120_combtxphy_set_rate(serdes, route->vm.pixelclock * 7);
|
||||||
|
rkx120_combtxphy_power_on(serdes, remote_id, phy_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
416
drivers/mfd/rkx110_x120/rkx120_combtxphy.c
Normal file
416
drivers/mfd/rkx110_x120/rkx120_combtxphy.c
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include "rkx110_x120.h"
|
||||||
|
#include "rkx120_reg.h"
|
||||||
|
#include "serdes_combphy.h"
|
||||||
|
|
||||||
|
#define CLANE_PARA0 0x0000
|
||||||
|
#define CLANE_PARA1 0x0004
|
||||||
|
#define T_INITTIME_C(x) UPDATE(x, 31, 0)
|
||||||
|
#define CLANE_PARA2 0x0008
|
||||||
|
#define T_CLKPREPARE_C(x) UPDATE(x, 23, 16)
|
||||||
|
#define T_CLKZERO_C(x) UPDATE(x, 15, 8)
|
||||||
|
#define T_CLKPRE_C(x) UPDATE(x, 7, 0)
|
||||||
|
#define CLANE_PARA3 0x000c
|
||||||
|
#define T_CLKPOST_C_MASK GENMASK(23, 16)
|
||||||
|
#define T_CLKPOST_C(x) UPDATE(x, 23, 16)
|
||||||
|
#define T_CLKTRAIL_C_MASK GENMASK(15, 8)
|
||||||
|
#define T_CLKTRAIL_C(x) UPDATE(x, 15, 8)
|
||||||
|
#define T_HSEXIT_C_MASK GENMASK(7, 0)
|
||||||
|
#define T_HSEXIT_C(x) UPDATE(x, 7, 0)
|
||||||
|
#define DLANE0_PARA0 0x0010
|
||||||
|
#define T_RST2ENLPTX_D(x) UPDATE(x, 15, 0)
|
||||||
|
#define DLANE0_PARA1 0x0014
|
||||||
|
#define T_INITTIME_D(x) UPDATE(x, 31, 0)
|
||||||
|
#define DLANE0_PARA2 0x0018
|
||||||
|
#define T_HSPREPARE_D(x) UPDATE(x, 31, 24)
|
||||||
|
#define T_HSZERO_D(x) UPDATE(x, 23, 16)
|
||||||
|
#define T_HSTRAIL_D(x) UPDATE(x, 15, 8)
|
||||||
|
#define T_HSEXIT_D(x) UPDATE(x, 7, 0)
|
||||||
|
#define DLANE0_PARA3 0x001c
|
||||||
|
#define T_WAKEUP_D(x) UPDATE(x, 31, 0)
|
||||||
|
#define DLANE0_PARA4 0x0020
|
||||||
|
#define T_TAGO_D0(x) UPDATE(x, 23, 16)
|
||||||
|
#define T_TASURE_D0(x) UPDATE(x, 15, 8)
|
||||||
|
#define T_TAGET_D0(x) UPDATE(x, 7, 0)
|
||||||
|
#define DLANE_PARA0(x) (0x0014 + (x * 0x0010))
|
||||||
|
#define DLANE_PARA1(x) (0x0018 + (x * 0x0010))
|
||||||
|
#define DLANE_PARA2(x) (0x001C + (x * 0x0010))
|
||||||
|
#define DLANE_PARA3(x) (0x0020 + (x * 0x0010))
|
||||||
|
#define COMMON_PARA0 (0x0054)
|
||||||
|
#define T_LPX(x) UPDATE(x, 7, 0)
|
||||||
|
#define CTRL_PARA0 0x0058
|
||||||
|
#define PWON_SEL BIT(3)
|
||||||
|
#define PWON_DSI BIT(1)
|
||||||
|
#define SU_IDDQ_EN BIT(0)
|
||||||
|
#define PLL_CTRL_PARA0 0x005c
|
||||||
|
#define PLL_LOCK BIT(27)
|
||||||
|
#define RATE_MASK GENMASK(26, 24)
|
||||||
|
#define RATE(x) UPDATE(x, 26, 24)
|
||||||
|
#define REFCLK_DIV_MASK GENMASK(23, 19)
|
||||||
|
#define REFCLK_DIV(x) UPDATE(x, 23, 19)
|
||||||
|
#define PLL_DIV_MASK GENMASK(18, 4)
|
||||||
|
#define PLL_DIV(x) UPDATE(x, 18, 4)
|
||||||
|
#define DSI_PIXELCLK_DIV(x) UPDATE(x, 3, 0)
|
||||||
|
#define PLL_CTRL_PARA1 0x0060
|
||||||
|
#define PLL_CTRL(x) UPDATE(x, 31, 0)
|
||||||
|
#define RCAL_CTRL 0x0064
|
||||||
|
#define RCAL_EN BIT(13)
|
||||||
|
#define RCAL_TRIM(x) UPDATE(x, 12, 9)
|
||||||
|
#define RCAL_DONE BIT(0)
|
||||||
|
#define TRIM_PARA 0x0068
|
||||||
|
#define HSTX_AMP_TRIM(x) UPDATE(x, 13, 11)
|
||||||
|
#define LPTX_SR_TRIM(x) UPDATE(x, 10, 8)
|
||||||
|
#define LPRX_VREF_TRIM(x) UPDATE(x, 7, 4)
|
||||||
|
#define LPCD_VREF_TRIM(x) UPDATE(x, 3, 0)
|
||||||
|
#define TEST_PARA0 0x006c
|
||||||
|
#define FSET_EN BIT(3)
|
||||||
|
|
||||||
|
#define CLANE_PARA4 0x0078
|
||||||
|
#define INTERFACE_PARA 0x007c
|
||||||
|
#define TXREADYESC_VLD(x) UPDATE(x, 15, 8)
|
||||||
|
#define RXVALIDESC_VLD(x) UPDATE(x, 7, 0)
|
||||||
|
|
||||||
|
#define GRF_MIPITX_CON0 0x0000
|
||||||
|
#define PHYSHUTDWN(x) HIWORD_UPDATE(x, GENMASK(10, 10), 10)
|
||||||
|
#define LVDS_REFCLK_DIV(x) HIWORD_UPDATE(x, GENMASK(9, 6), 6)
|
||||||
|
#define PHY_MODE(x) HIWORD_UPDATE(x, GENMASK(4, 3), 3)
|
||||||
|
#define RATE_LVDS(x) HIWORD_UPDATE(x, GENMASK(2, 1), 1)
|
||||||
|
#define GRF_MIPITX_CON1 0x0004
|
||||||
|
#define PWON_PLL(x) HIWORD_UPDATE(x, GENMASK(15, 15), 15)
|
||||||
|
#define LVDS_PLL_DIV(x) HIWORD_UPDATE(x, GENMASK(14, 0), 0)
|
||||||
|
|
||||||
|
#define GRF_MIPITX_CON5 0x0014
|
||||||
|
#define TXCLK_BUS_WIDTH(x) HIWORD_UPDATE(x, GENMASK(14, 12), 12)
|
||||||
|
#define TX3_BUS_WIDTH(x) HIWORD_UPDATE(x, GENMASK(11, 9), 9)
|
||||||
|
#define TX2_BUS_WIDTH(x) HIWORD_UPDATE(x, GENMASK(8, 6), 6)
|
||||||
|
#define TX1_BUS_WIDTH(x) HIWORD_UPDATE(x, GENMASK(5, 3), 3)
|
||||||
|
#define TX0_BUS_WIDTH(x) HIWORD_UPDATE(x, GENMASK(2, 0), 0)
|
||||||
|
#define GRF_MIPITX_CON6 0x0018
|
||||||
|
#define TX0_CTL_LOW(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0)
|
||||||
|
#define GRF_MIPITX_CON7 0x001c
|
||||||
|
#define TX1_CTL_LOW(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0)
|
||||||
|
#define GRF_MIPITX_CON8 0x0020
|
||||||
|
#define TX2_CTL_LOW(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0)
|
||||||
|
#define GRF_MIPITX_CON9 0x0024
|
||||||
|
#define TX3_CTL_LOW(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0)
|
||||||
|
#define GRF_MIPITX_CON10 0x0028
|
||||||
|
#define TXCK_CTL_LOW(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0)
|
||||||
|
|
||||||
|
#define GRF_MIPITX_CON13 0x0034
|
||||||
|
#define TX_IDLE(x) HIWORD_UPDATE(x, GENMASK(4, 0), 0)
|
||||||
|
#define GRF_MIPITX_CON14 0x0038
|
||||||
|
#define TX_PD(x) HIWORD_UPDATE(x, GENMASK(14, 10), 10)
|
||||||
|
|
||||||
|
#define GRF_MIPI_STATUS 0x0080
|
||||||
|
#define PHYLOCK BIT(0)
|
||||||
|
|
||||||
|
static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des, u8 remote_id)
|
||||||
|
{
|
||||||
|
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||||
|
const struct configure_opts_combphy cfg = combtxphy->mipi_dphy_cfg;
|
||||||
|
u32 byte_clk = DIV_ROUND_CLOSEST_ULL(combtxphy->rate, 8);
|
||||||
|
u32 esc_div = DIV_ROUND_UP(byte_clk, 20 * USEC_PER_SEC);
|
||||||
|
u64 t_byte_clk = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, byte_clk);
|
||||||
|
u32 t_clkprepare, t_clkzero, t_clkpre, t_clkpost, t_clktrail;
|
||||||
|
u32 t_init, t_hsexit, t_hsprepare, t_hszero, t_wakeup, t_hstrail;
|
||||||
|
u32 t_tago, t_tasure, t_taget;
|
||||||
|
u32 base = RKX120_MIPI_LVDS_TX_PHY0_BASE;
|
||||||
|
|
||||||
|
serdes_combphy_write(des, remote_id, base + INTERFACE_PARA,
|
||||||
|
TXREADYESC_VLD(esc_div - 2) |
|
||||||
|
RXVALIDESC_VLD(esc_div - 2));
|
||||||
|
serdes_combphy_write(des, remote_id, base + COMMON_PARA0, esc_div);
|
||||||
|
serdes_combphy_update_bits(des, remote_id, base + TEST_PARA0, FSET_EN, FSET_EN);
|
||||||
|
|
||||||
|
t_init = DIV_ROUND_UP(cfg.init, t_byte_clk) - 1;
|
||||||
|
serdes_combphy_write(des, remote_id, base + CLANE_PARA1, T_INITTIME_C(t_init));
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE0_PARA1, T_INITTIME_D(t_init));
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA1(1), T_INITTIME_D(t_init));
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA1(2), T_INITTIME_D(t_init));
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA1(3), T_INITTIME_D(t_init));
|
||||||
|
|
||||||
|
t_clkprepare = DIV_ROUND_UP(cfg.clk_prepare, t_byte_clk) - 1;
|
||||||
|
t_clkzero = DIV_ROUND_UP(cfg.clk_zero, t_byte_clk) - 1;
|
||||||
|
t_clkpre = DIV_ROUND_UP(cfg.clk_pre, t_byte_clk) - 1;
|
||||||
|
serdes_combphy_write(des, remote_id, base + CLANE_PARA2,
|
||||||
|
T_CLKPREPARE_C(t_clkprepare) |
|
||||||
|
T_CLKZERO_C(t_clkzero) | T_CLKPRE_C(t_clkpre));
|
||||||
|
|
||||||
|
t_clkpost = DIV_ROUND_UP(cfg.clk_post, t_byte_clk) - 1;
|
||||||
|
t_clktrail = DIV_ROUND_UP(cfg.clk_trail, t_byte_clk) - 1;
|
||||||
|
t_hsexit = DIV_ROUND_UP(cfg.hs_exit, t_byte_clk) - 1;
|
||||||
|
serdes_combphy_write(des, remote_id, base + CLANE_PARA3,
|
||||||
|
T_CLKPOST_C(t_clkpost) |
|
||||||
|
T_CLKTRAIL_C(t_clktrail) |
|
||||||
|
T_HSEXIT_C(t_hsexit));
|
||||||
|
|
||||||
|
t_hsprepare = DIV_ROUND_UP(cfg.hs_prepare, t_byte_clk) - 1;
|
||||||
|
t_hszero = DIV_ROUND_UP(cfg.hs_zero, t_byte_clk) - 1;
|
||||||
|
t_hstrail = DIV_ROUND_UP(cfg.hs_trail, t_byte_clk) - 1;
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE0_PARA2,
|
||||||
|
T_HSPREPARE_D(t_hsprepare) |
|
||||||
|
T_HSZERO_D(t_hszero) |
|
||||||
|
T_HSTRAIL_D(t_hstrail) |
|
||||||
|
T_HSEXIT_D(t_hsexit));
|
||||||
|
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA2(1),
|
||||||
|
T_HSPREPARE_D(t_hsprepare) |
|
||||||
|
T_HSZERO_D(t_hszero) |
|
||||||
|
T_HSTRAIL_D(t_hstrail) |
|
||||||
|
T_HSEXIT_D(t_hsexit));
|
||||||
|
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA2(2),
|
||||||
|
T_HSPREPARE_D(t_hsprepare) |
|
||||||
|
T_HSZERO_D(t_hszero) |
|
||||||
|
T_HSTRAIL_D(t_hstrail) |
|
||||||
|
T_HSEXIT_D(t_hsexit));
|
||||||
|
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA2(3),
|
||||||
|
T_HSPREPARE_D(t_hsprepare) |
|
||||||
|
T_HSZERO_D(t_hszero) |
|
||||||
|
T_HSTRAIL_D(t_hstrail) |
|
||||||
|
T_HSEXIT_D(t_hsexit));
|
||||||
|
|
||||||
|
t_wakeup = DIV_ROUND_UP(cfg.wakeup, t_byte_clk) - 1;
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE0_PARA3, T_WAKEUP_D(t_wakeup));
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA3(1), T_WAKEUP_D(t_wakeup));
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA3(2), T_WAKEUP_D(t_wakeup));
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE_PARA3(3), T_WAKEUP_D(t_wakeup));
|
||||||
|
serdes_combphy_write(des, remote_id, base + CLANE_PARA4, T_WAKEUP_D(t_wakeup));
|
||||||
|
|
||||||
|
t_tago = DIV_ROUND_UP(cfg.ta_go, t_byte_clk) - 1;
|
||||||
|
t_tasure = DIV_ROUND_UP(cfg.ta_sure, t_byte_clk) - 1;
|
||||||
|
t_taget = DIV_ROUND_UP(cfg.ta_get, t_byte_clk) - 1;
|
||||||
|
serdes_combphy_write(des, remote_id, base + DLANE0_PARA4,
|
||||||
|
T_TAGO_D0(t_tago) |
|
||||||
|
T_TASURE_D0(t_tasure) |
|
||||||
|
T_TAGET_D0(t_taget));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rkx120_combtxphy_dsi_pll_set(struct rk_serdes *des, u8 remote_id)
|
||||||
|
{
|
||||||
|
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||||
|
u32 base = RKX120_MIPI_LVDS_TX_PHY0_BASE;
|
||||||
|
|
||||||
|
serdes_combphy_update_bits(des, remote_id, base + PLL_CTRL_PARA0,
|
||||||
|
RATE_MASK | REFCLK_DIV_MASK | PLL_DIV_MASK,
|
||||||
|
RATE(combtxphy->rate_factor) |
|
||||||
|
REFCLK_DIV(combtxphy->ref_div - 1) |
|
||||||
|
PLL_DIV(combtxphy->fb_div));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des, u8 remote_id)
|
||||||
|
{
|
||||||
|
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||||
|
struct i2c_client *client = des->chip[remote_id].client;
|
||||||
|
u32 grf_base = RKX120_GRF_MIPI0_BASE;
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0,
|
||||||
|
PHY_MODE(COMBTX_PHY_MODE_VIDEO_MIPI));
|
||||||
|
|
||||||
|
serdes_combphy_get_default_config(combtxphy->rate, &combtxphy->mipi_dphy_cfg);
|
||||||
|
rkx120_combtxphy_dsi_timing_init(des, remote_id);
|
||||||
|
rkx120_combtxphy_dsi_pll_set(des, remote_id);
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0, PHYSHUTDWN(1));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON1, PWON_PLL(1));
|
||||||
|
|
||||||
|
ret = read_poll_timeout(des->i2c_read_reg, ret,
|
||||||
|
!(ret < 0) && (val & PLL_LOCK),
|
||||||
|
0, MSEC_PER_SEC, false, client,
|
||||||
|
RKX120_MIPI_LVDS_TX_PHY0_BASE + PLL_CTRL_PARA0,
|
||||||
|
&val);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(des->dev, "PLL is not locked\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rkx120_combtxphy_dsi_power_off(struct rk_serdes *des, u8 remote_id)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = des->chip[remote_id].client;
|
||||||
|
u32 grf_base = RKX120_GRF_MIPI0_BASE;
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0, PHYSHUTDWN(0));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON1, PWON_PLL(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rkx120_combtxphy_lvds_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id)
|
||||||
|
{
|
||||||
|
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||||
|
struct i2c_client *client = des->chip[remote_id].client;
|
||||||
|
u32 grf_base = (phy_id == 0) ?
|
||||||
|
RKX120_GRF_MIPI0_BASE : RKX120_GRF_MIPI1_BASE;
|
||||||
|
const struct {
|
||||||
|
unsigned long max_lane_mbps;
|
||||||
|
u8 rate_lvds;
|
||||||
|
u8 refclk_div;
|
||||||
|
u16 pll_div;
|
||||||
|
} hsfreqrange_table[] = {
|
||||||
|
{250, 2, 0, 0x3800},
|
||||||
|
{500, 1, 1, 0x3800},
|
||||||
|
{1000, 0, 3, 0x3800},
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
u32 val;
|
||||||
|
u8 index;
|
||||||
|
|
||||||
|
for (index = 0; index < ARRAY_SIZE(hsfreqrange_table); index++)
|
||||||
|
if (combtxphy->rate < hsfreqrange_table[index].max_lane_mbps * USEC_PER_SEC)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (index == ARRAY_SIZE(hsfreqrange_table))
|
||||||
|
--index;
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON13, TX_IDLE(0x1f));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON14, TX_PD(0x1f));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0,
|
||||||
|
LVDS_REFCLK_DIV(hsfreqrange_table[index].refclk_div) |
|
||||||
|
RATE_LVDS(hsfreqrange_table[index].rate_lvds));
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON1,
|
||||||
|
LVDS_PLL_DIV(hsfreqrange_table[index].pll_div));
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON5,
|
||||||
|
TXCLK_BUS_WIDTH(2) | TX3_BUS_WIDTH(2) |
|
||||||
|
TX2_BUS_WIDTH(2) | TX1_BUS_WIDTH(2) |
|
||||||
|
TX0_BUS_WIDTH(2));
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON6, TX0_CTL_LOW(0x80));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON7, TX0_CTL_LOW(0x80));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON8, TX0_CTL_LOW(0x80));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON9, TX0_CTL_LOW(0x80));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON10, TX0_CTL_LOW(0x80));
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON14, TX_PD(0));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0, PHYSHUTDWN(1) |
|
||||||
|
PHY_MODE(COMBTX_PHY_MODE_VIDEO_LVDS));
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON1, PWON_PLL(1));
|
||||||
|
|
||||||
|
ret = read_poll_timeout(des->i2c_read_reg, ret,
|
||||||
|
!(ret < 0) && (val & PHYLOCK),
|
||||||
|
0, MSEC_PER_SEC, false, client,
|
||||||
|
grf_base + GRF_MIPI_STATUS, &val);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(des->dev, "PLL is not locked\n");
|
||||||
|
|
||||||
|
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON13, TX_IDLE(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_combtxphy_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id)
|
||||||
|
{
|
||||||
|
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||||
|
|
||||||
|
switch (combtxphy->mode) {
|
||||||
|
case COMBTX_PHY_MODE_VIDEO_MIPI:
|
||||||
|
rkx120_combtxphy_dsi_power_on(des, remote_id);
|
||||||
|
break;
|
||||||
|
case COMBTX_PHY_MODE_VIDEO_LVDS:
|
||||||
|
rkx120_combtxphy_lvds_power_on(des, remote_id, phy_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_combtxphy_power_off(struct rk_serdes *des, u8 remote_id)
|
||||||
|
{
|
||||||
|
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||||
|
|
||||||
|
switch (combtxphy->mode) {
|
||||||
|
case COMBTX_PHY_MODE_VIDEO_MIPI:
|
||||||
|
rkx120_combtxphy_dsi_power_off(des, remote_id);
|
||||||
|
break;
|
||||||
|
case COMBTX_PHY_MODE_VIDEO_LVDS:
|
||||||
|
break;
|
||||||
|
case COMBTX_PHY_MODE_GPIO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rkx120_combtxphy_dsi_pll_calc_rate(struct rkx120_combtxphy *combtxphy, u64 rate)
|
||||||
|
{
|
||||||
|
const struct {
|
||||||
|
unsigned long max_lane_mbps;
|
||||||
|
u8 refclk_div;
|
||||||
|
u8 post_factor;
|
||||||
|
} hsfreqrange_table[] = {
|
||||||
|
{ 100, 1, 5 },
|
||||||
|
{ 200, 1, 4 },
|
||||||
|
{ 400, 1, 3 },
|
||||||
|
{ 800, 1, 2},
|
||||||
|
{ 1600, 1, 1},
|
||||||
|
};
|
||||||
|
u64 ref_clk = 24 * USEC_PER_SEC;
|
||||||
|
u64 fvco;
|
||||||
|
u16 fb_div;
|
||||||
|
u8 ref_div, post_div, index;
|
||||||
|
|
||||||
|
for (index = 0; index < ARRAY_SIZE(hsfreqrange_table); index++)
|
||||||
|
if (rate <= hsfreqrange_table[index].max_lane_mbps * USEC_PER_SEC)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (index == ARRAY_SIZE(hsfreqrange_table))
|
||||||
|
--index;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FVCO = Fckref * 8 * ( PI_POST_DIV + PF_POST_DIV) / R
|
||||||
|
* data_rate = FVCO / post_div;
|
||||||
|
*/
|
||||||
|
|
||||||
|
ref_div = hsfreqrange_table[index].refclk_div;
|
||||||
|
post_div = 1 << hsfreqrange_table[index].post_factor;
|
||||||
|
fvco = rate * post_div;
|
||||||
|
fb_div = DIV_ROUND_CLOSEST_ULL((fvco * ref_div) << 10, ref_clk * 8);
|
||||||
|
|
||||||
|
rate = DIV_ROUND_CLOSEST_ULL(ref_clk * 8 * fb_div,
|
||||||
|
(u64)(ref_div * post_div) << 10);
|
||||||
|
|
||||||
|
combtxphy->ref_div = ref_div;
|
||||||
|
combtxphy->fb_div = fb_div;
|
||||||
|
combtxphy->rate_factor = hsfreqrange_table[index].post_factor;
|
||||||
|
combtxphy->rate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rkx120_combtxphy_lvds_pll_calc_rate(struct rkx120_combtxphy *combtxphy, u64 rate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_combtxphy_set_rate(struct rk_serdes *des, u64 rate)
|
||||||
|
{
|
||||||
|
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||||
|
|
||||||
|
switch (combtxphy->mode) {
|
||||||
|
case COMBTX_PHY_MODE_VIDEO_MIPI:
|
||||||
|
rkx120_combtxphy_dsi_pll_calc_rate(combtxphy, rate);
|
||||||
|
break;
|
||||||
|
case COMBTX_PHY_MODE_VIDEO_LVDS:
|
||||||
|
rkx120_combtxphy_lvds_pll_calc_rate(combtxphy, rate);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
combtxphy->rate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 rkx120_combtxphy_get_rate(struct rk_serdes *des)
|
||||||
|
{
|
||||||
|
return des->combtxphy.rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_combtxphy_set_mode(struct rk_serdes *des, enum combtx_phy_mode mode)
|
||||||
|
{
|
||||||
|
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||||
|
|
||||||
|
combtxphy->mode = mode;
|
||||||
|
}
|
||||||
1182
drivers/mfd/rkx110_x120/rkx120_dsi_tx.c
Normal file
1182
drivers/mfd/rkx110_x120/rkx120_dsi_tx.c
Normal file
File diff suppressed because it is too large
Load Diff
23
drivers/mfd/rkx110_x120/rkx120_dsi_tx.h
Normal file
23
drivers/mfd/rkx110_x120/rkx120_dsi_tx.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Guochun Huang <hero.huang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RKX120_DSI_TX_H
|
||||||
|
#define RKX120_DSI_TX_H
|
||||||
|
|
||||||
|
#include "rkx110_x120.h"
|
||||||
|
|
||||||
|
int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, u8 remote_id,
|
||||||
|
struct panel_cmds *cmds);
|
||||||
|
void rkx120_dsi_tx_pre_enable(struct rk_serdes *serdes,
|
||||||
|
struct rk_serdes_route *route, u8 remote_id);
|
||||||
|
void rkx120_dsi_tx_enable(struct rk_serdes *serdes,
|
||||||
|
struct rk_serdes_route *route, u8 remote_id);
|
||||||
|
void rkx120_dsi_tx_post_disable(struct rk_serdes *serdes,
|
||||||
|
struct rk_serdes_route *route, u8 remote_id);
|
||||||
|
void rkx120_dsi_tx_disable(struct rk_serdes *serdes,
|
||||||
|
struct rk_serdes_route *route, u8 remote_id);
|
||||||
|
#endif
|
||||||
797
drivers/mfd/rkx110_x120/rkx120_linkrx.c
Normal file
797
drivers/mfd/rkx110_x120/rkx120_linkrx.c
Normal file
@@ -0,0 +1,797 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Zhang Yubing <yubing.zhang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <dt-bindings/mfd/rockchip-serdes.h>
|
||||||
|
|
||||||
|
#include "hal/cru_api.h"
|
||||||
|
#include "hal/pinctrl_api.h"
|
||||||
|
#include "rkx110_x120.h"
|
||||||
|
#include "rkx120_reg.h"
|
||||||
|
|
||||||
|
#define LINK_REG(x) ((x) + RKX120_DES_RKLINK_BASE)
|
||||||
|
|
||||||
|
#define RKLINK_DES_LANE_ENGINE_CFG LINK_REG(0x0000)
|
||||||
|
#define TRAIN_CLK_SEL_MASK GENMASK(31, 30)
|
||||||
|
#define TRAIN_CLK_SEL_E0 UPDATE(0, 31, 30)
|
||||||
|
#define TRAIN_CLK_SEL_E1 UPDATE(1, 31, 30)
|
||||||
|
#define TRAIN_CLK_SEL_I2S UPDATE(2, 31, 30)
|
||||||
|
#define DUAL_LVDS_CHANNEL_SWAP BIT(29)
|
||||||
|
#define VIDEO_FREQ_AUTO_EN BIT(28)
|
||||||
|
#define ENGINE1_2_LANE BIT(23)
|
||||||
|
#define ENGINE1_EN BIT(22)
|
||||||
|
#define ENGINE0_2_LANE BIT(21)
|
||||||
|
#define ENGINE0_EN BIT(20)
|
||||||
|
#define LANE1_DATA_WIDTH_8BIT UPDATE(0, 15, 14)
|
||||||
|
#define LANE1_DATA_WIDTH_16BIT UPDATE(1, 15, 14)
|
||||||
|
#define LANE1_DATA_WIDTH_24BIT UPDATE(2, 15, 14)
|
||||||
|
#define LANE1_DATA_WIDTH_32BIT UPDATE(3, 15, 14)
|
||||||
|
#define LANE0_DATA_WIDTH_8BIT UPDATE(0, 13, 12)
|
||||||
|
#define LANE0_DATA_WIDTH_16BIT UPDATE(1, 13, 12)
|
||||||
|
#define LANE0_DATA_WIDTH_24BIT UPDATE(2, 13, 12)
|
||||||
|
#define LANE0_DATA_WIDTH_32BIT UPDATE(3, 13, 12)
|
||||||
|
#define LANE0_EN BIT(4)
|
||||||
|
#define LANE1_EN BIT(5)
|
||||||
|
#define DES_EN BIT(0)
|
||||||
|
|
||||||
|
#define RKLINK_DES_LANE_ENGINE_DST LINK_REG(0x0004)
|
||||||
|
#define LANE0_ENGINE_CFG_MASK GENMASK(3, 0)
|
||||||
|
#define LANE0_ENGINE0 BIT(0)
|
||||||
|
#define LANE0_ENGINE1 BIT(1)
|
||||||
|
#define LANE1_ENGINE_CFG_MASK GENMASK(7, 4)
|
||||||
|
#define LANE1_ENGINE0 BIT(4)
|
||||||
|
#define LANE1_ENGINE1 BIT(5)
|
||||||
|
|
||||||
|
#define RKLINK_DES_DATA_ID_CFG LINK_REG(0x0008)
|
||||||
|
#define DATA_FIFO3_RD_ID_MASK GENMASK(30, 28)
|
||||||
|
#define DATA_FIFO3_RD_ID(x) UPDATE(x, 30, 28)
|
||||||
|
#define DATA_FIFO2_RD_ID_MASK GENMASK(26, 24)
|
||||||
|
#define DATA_FIFO2_RD_ID(x) UPDATE(x, 26, 24)
|
||||||
|
#define DATA_FIFO1_RD_ID_MASK GENMASK(22, 20)
|
||||||
|
#define DATA_FIFO1_RD_ID(x) UPDATE(x, 22, 20)
|
||||||
|
#define DATA_FIFO0_RD_ID_MASK GENMASK(18, 16)
|
||||||
|
#define DATA_FIFO0_RD_ID(x) UPDATE(x, 18, 16)
|
||||||
|
#define DATA_FIFO3_WR_ID_MASK GENMASK(14, 12)
|
||||||
|
#define DATA_FIFO3_WR_ID(x) UPDATE(x, 14, 12)
|
||||||
|
#define DATA_FIFO2_WR_ID_MASK GENMASK(10, 8)
|
||||||
|
#define DATA_FIFO2_WR_ID(x) UPDATE(x, 10, 8)
|
||||||
|
#define DATA_FIFO1_WR_ID_MASK GENMASK(6, 4)
|
||||||
|
#define DATA_FIFO1_WR_ID(x) UPDATE(x, 6, 4)
|
||||||
|
#define DATA_FIFO0_WR_ID_MASK GENMASK(2, 0)
|
||||||
|
#define DATA_FIFO0_WR_ID(x) UPDATE(x, 2, 0)
|
||||||
|
|
||||||
|
#define RKLINK_DES_ORDER_ID_CFG LINK_REG(0x000C)
|
||||||
|
#define ORDER_FIFO1_RD_ID_MASK GENMASK(22, 20)
|
||||||
|
#define ORDER_FIFO1_RD_ID(x) UPDATE(x, 22, 20)
|
||||||
|
#define ORDER_FIFO0_RD_ID_MASK GENMASK(18, 16)
|
||||||
|
#define ORDER_FIFO0_RD_ID(x) UPDATE(x, 18, 16)
|
||||||
|
#define ORDER_FIFO1_WR_ID_MASK GENMASK(6, 4)
|
||||||
|
#define ORDER_FIFO1_WR_ID(x) UPDATE(x, 6, 4)
|
||||||
|
#define ORDER_FIFO0_WR_ID_MASK GENMASK(2, 0)
|
||||||
|
#define ORDER_FIFO0_WR_ID(x) UPDATE(x, 2, 0)
|
||||||
|
|
||||||
|
#define RKLINK_DES_SOURCE_CFG LINK_REG(0x0024)
|
||||||
|
#define E1_CAMERA_SRC_CSI UPDATE(0, 23, 21)
|
||||||
|
#define E1_CAMERA_SRC_LVDS UPDATE(1, 23, 21)
|
||||||
|
#define E1_CAMERA_SRC_DVP UPDATE(2, 23, 21)
|
||||||
|
#define E1_DISPLAY_SRC_DSI UPDATE(0, 23, 21)
|
||||||
|
#define E1_DISPLAY_SRC_DUAL_LDVS UPDATE(1, 23, 21)
|
||||||
|
#define E1_DISPLAY_SRC_LVDS0 UPDATE(2, 23, 21)
|
||||||
|
#define E1_DISPLAY_SRC_LVDS1 UPDATE(3, 23, 21)
|
||||||
|
#define E1_DISPLAY_SRC_RGB UPDATE(5, 23, 21)
|
||||||
|
#define E1_STREAM_CAMERA UPDATE(0, 20, 20)
|
||||||
|
#define E1_STREAM_DISPLAY UPDATE(1, 20, 20)
|
||||||
|
#define E0_CAMERA_SRC_CSI UPDATE(0, 19, 17)
|
||||||
|
#define E0_CAMERA_SRC_LVDS UPDATE(1, 19, 17)
|
||||||
|
#define E0_CAMERA_SRC_DVP UPDATE(2, 19, 17)
|
||||||
|
#define E0_DISPLAY_SRC_DSI UPDATE(0, 19, 17)
|
||||||
|
#define E0_DISPLAY_SRC_DUAL_LDVS UPDATE(1, 19, 17)
|
||||||
|
#define E0_DISPLAY_SRC_LVDS0 UPDATE(2, 19, 17)
|
||||||
|
#define E0_DISPLAY_SRC_LVDS1 UPDATE(3, 19, 17)
|
||||||
|
#define E0_DISPLAY_SRC_RGB UPDATE(5, 19, 17)
|
||||||
|
#define E0_STREAM_CAMERA UPDATE(0, 16, 16)
|
||||||
|
#define E0_STREAM_DISPLAY UPDATE(1, 16, 16)
|
||||||
|
#define LANE1_ENGINE_ID(x) UPDATE(x, 7, 6)
|
||||||
|
#define LANE1_LANE_ID(x) UPDATE(x, 5, 5)
|
||||||
|
#define LNAE1_ID_SEL(x) UPDATE(x, 4, 4)
|
||||||
|
#define LANE0_ENGINE_ID(x) UPDATE(x, 3, 2)
|
||||||
|
#define LANE0_LANE_ID(x) UPDATE(x, 1, 1)
|
||||||
|
#define LNAE0_ID_SEL(x) UPDATE(x, 0, 0)
|
||||||
|
|
||||||
|
#define RKLINK_DES_REG01_ENGIN_DEL 0x0030
|
||||||
|
#define E1_ENGINE_DELAY(x) UPDATE(x, 31, 16)
|
||||||
|
#define E0_ENGINE_DELAY(x) UPDATE(x, 15, 0)
|
||||||
|
#define RKLINK_DES_REG_PATCH 0X0050
|
||||||
|
#define E3_FIRST_FRAME_DEL BIT(7)
|
||||||
|
#define E2_FIRST_FRAME_DEL BIT(6)
|
||||||
|
#define E1_FIRST_FRAME_DEL BIT(5)
|
||||||
|
#define E0_FIRST_FRAME_DEL BIT(4)
|
||||||
|
|
||||||
|
#define DES_RKLINK_STOP_CFG LINK_REG(0x009C)
|
||||||
|
#define STOP_AUDIO BIT(4)
|
||||||
|
#define STOP_E1 BIT(1)
|
||||||
|
#define STOP_E0 BIT(0)
|
||||||
|
|
||||||
|
#define RKLINK_DES_SPI_CFG LINK_REG(0x00C4)
|
||||||
|
#define RKLINK_DES_UART_CFG LINK_REG(0x00C8)
|
||||||
|
#define RKLINK_DES_GPIO_CFG LINK_REG(0x00CC)
|
||||||
|
#define GPIO_GROUP1_EN BIT(17)
|
||||||
|
#define GPIO_GROUP0_EN BIT(16)
|
||||||
|
|
||||||
|
#define PCS_REG(id, x) ((x) + RKX120_DES_PCS0_BASE + (id) * RKX120_DES_PMA_OFFSET)
|
||||||
|
|
||||||
|
#define PCS_REG00(id) PCS_REG(id, 0x00)
|
||||||
|
#define DES_PCS_DUAL_LANE_MODE_EN HIWORD_UPDATE(1, GENMASK(8, 8), 8)
|
||||||
|
#define DES_PCS_AUTO_START_EN HIWORD_UPDATE(1, GENMASK(4, 4), 4)
|
||||||
|
#define DES_PCS_ECU_MODE HIWORD_UPDATE(0, GENMASK(1, 1), 1)
|
||||||
|
#define DES_PCS_EN_MASK HIWORD_MASK(0, 0)
|
||||||
|
#define DES_PCS_EN HIWORD_UPDATE(1, GENMASK(0, 0), 0)
|
||||||
|
#define DES_PCS_DISABLE HIWORD_UPDATE(0, GENMASK(0, 0), 0)
|
||||||
|
|
||||||
|
#define PCS_REG04(id) PCS_REG(id, 0x04)
|
||||||
|
#define PCS_REG08(id) PCS_REG(id, 0x08)
|
||||||
|
#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) + RKX120_DES_PMA0_BASE + (id) * RKX120_DES_PMA_OFFSET)
|
||||||
|
|
||||||
|
#define DES_PMA_STATUS(id) PMA_REG(id, 0x00)
|
||||||
|
#define DES_PMA_FORCE_INIT_STA BIT(23)
|
||||||
|
#define DES_PMA_RX_LOST BIT(2)
|
||||||
|
#define DES_PMA_RX_PLL_LOCK BIT(1)
|
||||||
|
#define DES_PMA_RX_RDY BIT(0)
|
||||||
|
|
||||||
|
#define DES_PMA_CTRL(id) PMA_REG(id, 0x04)
|
||||||
|
#define DES_PMA_FORCE_INIT_MASK HIWORD_MASK(8, 8)
|
||||||
|
#define DES_PMA_FORCE_INIT_EN HIWORD_UPDATE(1, BIT(8), 8)
|
||||||
|
#define DES_PMA_FORCE_INIT_DISABLE HIWORD_UPDATE(0, BIT(8), 8)
|
||||||
|
#define DES_PMA_DUAL_CHANNEL HIWORD_UPDATE(1, BIT(3), 3)
|
||||||
|
#define DES_PMA_INIT_CNT_CLR_MASK HIWORD_MASK(2, 2)
|
||||||
|
#define DES_PMA_INIT_CNT_CLR HIWORD_UPDATE(1, BIT(2), 2)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD00(id) PMA_REG(id, 0x10)
|
||||||
|
#define PMA_RX_POL BIT(0)
|
||||||
|
#define PMA_RX_WIDTH BIT(1)
|
||||||
|
#define PMA_RX_MSBF_EN BIT(2)
|
||||||
|
#define PMA_PLL_PWRDN BIT(3)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD01(id) PMA_REG(id, 0x14)
|
||||||
|
#define DES_PMA_PLL_FORCE_LK(x) HIWORD_UPDATE(x, GENMASK(13, 13), 13)
|
||||||
|
#define DES_PMA_LOS_VTH(x) HIWORD_UPDATE(x, GENMASK(12, 11), 11)
|
||||||
|
#define DES_PMA_PD_CP_PD(x) HIWORD_UPDATE(x, GENMASK(10, 10), 10)
|
||||||
|
#define DES_PMA_PD_CP_FP(x) HIWORD_UPDATE(x, GENMASK(9, 9), 9)
|
||||||
|
#define DES_PMA_PD_LOOP_DIV(x) HIWORD_UPDATE(x, GENMASK(8, 8), 8)
|
||||||
|
#define DES_PMA_PD_PFD(x) HIWORD_UPDATE(x, GENMASK(7, 7), 7)
|
||||||
|
#define DES_PMA_PD_VBIAS(x) HIWORD_UPDATE(x, GENMASK(6, 6), 6)
|
||||||
|
#define DES_PMA_AFE_VOS_EN(x) HIWORD_UPDATE(x, GENMASK(5, 5), 5)
|
||||||
|
#define DES_PMA_PD_AFE(x) HIWORD_UPDATE(x, GENMASK(4, 4), 4)
|
||||||
|
#define DES_PMA_RX_RTERM(x) HIWORD_UPDATE(x, GENMASK(3, 0), 0)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD02(id) PMA_REG(id, 0x18)
|
||||||
|
#define DES_PMA_LOAD03(id) PMA_REG(id, 0x1C)
|
||||||
|
#define DES_PMA_LOAD04(id) PMA_REG(id, 0x20)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD05(id) PMA_REG(id, 0x24)
|
||||||
|
#define DES_PMA_PLL_REFCLK_DIV_MASK HIWORD_MASK(15, 12)
|
||||||
|
#define DES_PMA_PLL_REFCLK_DIV(x) HIWORD_UPDATE(x, GENMASK(15, 12), 12)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD06(id) PMA_REG(id, 0x28)
|
||||||
|
#define DES_PMA_MDATA_AMP_SEL(x) HIWORD_UPDATE(x, GENMASK(15, 14), 14)
|
||||||
|
#define DES_PMA_RX_TSEQ(x) HIWORD_UPDATE(x, GENMASK(13, 13), 13)
|
||||||
|
#define DES_PMA_FREZ_ADPT_EQ(x) HIWORD_UPDATE(x, GENMASK(12, 12), 12)
|
||||||
|
#define DES_PMA__ADPT_EQ_TRIM(x) HIWORD_UPDATE(x, GENMASK(11, 0), 0)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD07(id) PMA_REG(id, 0x2C)
|
||||||
|
#define DES_PMA_LOAD08(id) PMA_REG(id, 0x30)
|
||||||
|
#define DES_PMA_RX(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD09(id) PMA_REG(id, 0x34)
|
||||||
|
#define DES_PMA_PLL_DIV_MASK HIWORD_MASK(14, 0)
|
||||||
|
#define DES_PLL_I_POST_DIV(x) HIWORD_UPDATE(x, GENMASK(14, 10), 10)
|
||||||
|
#define DES_PLL_F_POST_DIV(x) HIWORD_UPDATE(x, GENMASK(9, 0), 0)
|
||||||
|
#define DES_PMA_PLL_DIV(x) HIWORD_UPDATE(x, GENMASK(14, 0), 0)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD0A(id) PMA_REG(id, 0x38)
|
||||||
|
#define DES_PMA_CLK_2X_DIV_MASK HIWORD_MASK(7, 0)
|
||||||
|
#define DES_PMA_CLK_2X_DIV(x) HIWORD_UPDATE(x, GENMASK(7, 0), 0)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD0B(id) PMA_REG(id, 0x3C)
|
||||||
|
#define DES_PMA_LOAD0C(id) PMA_REG(id, 0x40)
|
||||||
|
#define DES_PMA_FCK_VCO_MASK HIWORD_MASK(15, 15)
|
||||||
|
#define DES_PMA_FCK_VCO HIWORD_UPDATE(1, BIT(15), 15)
|
||||||
|
#define DES_PMA_FCK_VCO_DIV2 HIWORD_UPDATE(0, BIT(15), 15)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD0D(id) PMA_REG(id, 0x44)
|
||||||
|
#define DES_PMA_PLL_DIV4_MASK HIWORD_MASK(12, 12)
|
||||||
|
#define DES_PMA_PLL_DIV4 HIWORD_UPDATE(1, GENMASK(12, 12), 12)
|
||||||
|
#define DES_PMA_PLL_DIV8 HIWORD_UPDATE(0, GENMASK(12, 12), 12)
|
||||||
|
|
||||||
|
#define DES_PMA_LOAD0E(id) PMA_REG(id, 0x48)
|
||||||
|
#define DES_PMA_REG100(id) PMA_REG(id, 0x100)
|
||||||
|
|
||||||
|
static const struct rk_serdes_pt des_pt[] = {
|
||||||
|
{
|
||||||
|
/* gpi_gpo_0 */
|
||||||
|
.en_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.en_mask = 0x10001,
|
||||||
|
.en_val = 0x10001,
|
||||||
|
.dir_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.dir_mask = 0x10,
|
||||||
|
.dir_val = 0x10,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_GPIO_CFG,
|
||||||
|
.en_mask = 0x10002,
|
||||||
|
.en_val = 0x10002,
|
||||||
|
.dir_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.dir_mask = 0x20,
|
||||||
|
.dir_val = 0x20,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_GPIO_CFG,
|
||||||
|
.en_mask = 0x10004,
|
||||||
|
.en_val = 0x10004,
|
||||||
|
.dir_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.dir_mask = 0x40,
|
||||||
|
.dir_val = 0x40,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_GPIO_CFG,
|
||||||
|
.en_mask = 0x10008,
|
||||||
|
.en_val = 0x10008,
|
||||||
|
.dir_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.dir_mask = 0x80,
|
||||||
|
.dir_val = 0x80,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_GPIO_CFG,
|
||||||
|
.en_mask = 0x20100,
|
||||||
|
.en_val = 0x20100,
|
||||||
|
.dir_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.dir_mask = 0x1000,
|
||||||
|
.dir_val = 0x1000,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_GPIO_CFG,
|
||||||
|
.en_mask = 0x20200,
|
||||||
|
.en_val = 0x20200,
|
||||||
|
.dir_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.dir_mask = 0x2000,
|
||||||
|
.dir_val = 0x2000,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_GPIO_CFG,
|
||||||
|
.en_mask = 0x20400,
|
||||||
|
.en_val = 0x20400,
|
||||||
|
.dir_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.dir_mask = 0x4000,
|
||||||
|
.dir_val = 0x4000,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_GPIO_CFG,
|
||||||
|
.en_mask = 0x20800,
|
||||||
|
.en_val = 0x20800,
|
||||||
|
.dir_reg = RKLINK_DES_GPIO_CFG,
|
||||||
|
.dir_mask = 0x8000,
|
||||||
|
.dir_val = 0x8000,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_UART_CFG,
|
||||||
|
.en_mask = 0x1,
|
||||||
|
.en_val = 0x1,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_UART_CFG,
|
||||||
|
.en_mask = 0x2,
|
||||||
|
.en_val = 0x2,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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 = RKLINK_DES_SPI_CFG,
|
||||||
|
.en_mask = 0x4,
|
||||||
|
.en_val = 0x4,
|
||||||
|
.dir_reg = RKLINK_DES_SPI_CFG,
|
||||||
|
.dir_mask = 0x1,
|
||||||
|
.dir_val = 0,
|
||||||
|
.configs = 1,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.bank = RK_SERDES_DES_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_des_get_stream_source(struct rk_serdes_route *route, u32 port, u8 engine_id)
|
||||||
|
{
|
||||||
|
if (route->stream_type == STREAM_DISPLAY) {
|
||||||
|
if (port & RK_SERDES_RGB_TX)
|
||||||
|
return engine_id ? E1_DISPLAY_SRC_RGB : E0_DISPLAY_SRC_RGB;
|
||||||
|
else if (port & RK_SERDES_LVDS_TX0)
|
||||||
|
return engine_id ? E1_DISPLAY_SRC_LVDS0 : E0_DISPLAY_SRC_LVDS0;
|
||||||
|
else if (port & RK_SERDES_LVDS_TX1)
|
||||||
|
return engine_id ? E1_DISPLAY_SRC_LVDS1 : E0_DISPLAY_SRC_LVDS1;
|
||||||
|
else if (port & RK_SERDES_DUAL_LVDS_TX)
|
||||||
|
return engine_id ? E1_DISPLAY_SRC_DUAL_LDVS : E0_DISPLAY_SRC_DUAL_LDVS;
|
||||||
|
else if (port & RK_SERDES_DSI_TX0)
|
||||||
|
return engine_id ? E1_DISPLAY_SRC_DSI : E0_DISPLAY_SRC_DSI;
|
||||||
|
else if (port & RK_SERDES_DSI_TX1)
|
||||||
|
return engine_id ? E1_DISPLAY_SRC_DSI : E0_DISPLAY_SRC_DSI;
|
||||||
|
} else {
|
||||||
|
return engine_id ? E1_CAMERA_SRC_CSI : E0_CAMERA_SRC_CSI;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_serdes_link_rx_rgb_enable(struct rk_serdes *serdes,
|
||||||
|
struct rk_serdes_route *route,
|
||||||
|
u8 remote_id)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[remote_id].client;
|
||||||
|
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_REG01_ENGIN_DEL,
|
||||||
|
E1_ENGINE_DELAY(2800) | E0_ENGINE_DELAY(2800));
|
||||||
|
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_REG_PATCH,
|
||||||
|
E3_FIRST_FRAME_DEL | E2_FIRST_FRAME_DEL |
|
||||||
|
E1_FIRST_FRAME_DEL | E0_FIRST_FRAME_DEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_serdes_link_rx_lvds_enable(struct rk_serdes *serdes,
|
||||||
|
struct rk_serdes_route *route,
|
||||||
|
u8 remote_id)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[remote_id].client;
|
||||||
|
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_REG01_ENGIN_DEL,
|
||||||
|
E1_ENGINE_DELAY(4096) | E0_ENGINE_DELAY(4096));
|
||||||
|
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_REG_PATCH,
|
||||||
|
E3_FIRST_FRAME_DEL | E2_FIRST_FRAME_DEL |
|
||||||
|
E1_FIRST_FRAME_DEL | E0_FIRST_FRAME_DEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_serdes_link_rx_dsi_enable(struct rk_serdes *serdes,
|
||||||
|
struct rk_serdes_route *route,
|
||||||
|
u8 remote_id)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[remote_id].client;
|
||||||
|
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_REG01_ENGIN_DEL,
|
||||||
|
E1_ENGINE_DELAY(4096) | E0_ENGINE_DELAY(4096));
|
||||||
|
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_REG_PATCH,
|
||||||
|
E3_FIRST_FRAME_DEL | E2_FIRST_FRAME_DEL|
|
||||||
|
E1_FIRST_FRAME_DEL | E0_FIRST_FRAME_DEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk120_link_rx_cfg(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 stream_type;
|
||||||
|
u32 rx_src;
|
||||||
|
u32 ctrl_val, mask, val;
|
||||||
|
u32 lane0_dsource_id, lane1_dsource_id;
|
||||||
|
bool is_rx_dual_lanes;
|
||||||
|
bool is_rx_dual_channels;
|
||||||
|
|
||||||
|
if (route->stream_type == STREAM_DISPLAY) {
|
||||||
|
client = serdes->chip[remote_id].client;
|
||||||
|
stream_type = E0_STREAM_DISPLAY;
|
||||||
|
} else {
|
||||||
|
client = serdes->chip[DEVICE_LOCAL].client;
|
||||||
|
stream_type = E0_STREAM_CAMERA;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_rx_dual_lanes = (serdes->route_flag & ROUTE_MULTI_LANE) &&
|
||||||
|
!(serdes->route_flag & ROUTE_MULTI_REMOTE);
|
||||||
|
is_rx_dual_channels = (serdes->route_flag & ROUTE_MULTI_CHANNEL) &&
|
||||||
|
!(serdes->route_flag & ROUTE_MULTI_REMOTE);
|
||||||
|
|
||||||
|
serdes->i2c_read_reg(client, RKLINK_DES_LANE_ENGINE_CFG, &ctrl_val);
|
||||||
|
|
||||||
|
ctrl_val &= ~LANE1_EN;
|
||||||
|
ctrl_val |= LANE0_EN;
|
||||||
|
ctrl_val |= ENGINE0_EN;
|
||||||
|
if (is_rx_dual_lanes) {
|
||||||
|
ctrl_val |= LANE1_EN;
|
||||||
|
if (is_rx_dual_channels)
|
||||||
|
ctrl_val |= ENGINE1_EN;
|
||||||
|
else
|
||||||
|
ctrl_val |= ENGINE0_2_LANE;
|
||||||
|
} else {
|
||||||
|
if (is_rx_dual_channels)
|
||||||
|
ctrl_val |= ENGINE1_EN;
|
||||||
|
}
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_LANE_ENGINE_CFG, ctrl_val);
|
||||||
|
|
||||||
|
mask = LANE0_ENGINE_CFG_MASK;
|
||||||
|
val = LANE0_ENGINE0;
|
||||||
|
if (is_rx_dual_lanes) {
|
||||||
|
if (is_rx_dual_channels) {
|
||||||
|
mask |= LANE1_ENGINE_CFG_MASK;
|
||||||
|
val |= LANE1_ENGINE1;
|
||||||
|
} else {
|
||||||
|
mask |= LANE1_ENGINE_CFG_MASK;
|
||||||
|
val |= LANE1_ENGINE0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (is_rx_dual_channels)
|
||||||
|
val |= LANE0_ENGINE1;
|
||||||
|
}
|
||||||
|
|
||||||
|
serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_DST, mask, val);
|
||||||
|
|
||||||
|
serdes->i2c_read_reg(client, RKLINK_DES_SOURCE_CFG, &val);
|
||||||
|
|
||||||
|
val &= ~(LANE0_ENGINE_ID(1) | LANE0_LANE_ID(1) | LANE1_ENGINE_ID(1) |
|
||||||
|
LANE1_LANE_ID(1) | LNAE0_ID_SEL(1) | LNAE1_ID_SEL(1));
|
||||||
|
|
||||||
|
if (is_rx_dual_lanes) {
|
||||||
|
if (is_rx_dual_channels) {
|
||||||
|
val |= LANE0_ENGINE_ID(0);
|
||||||
|
val |= LANE0_LANE_ID(0);
|
||||||
|
val |= LNAE0_ID_SEL(1);
|
||||||
|
val |= LANE1_ENGINE_ID(1);
|
||||||
|
val |= LANE1_LANE_ID(0);
|
||||||
|
val |= LNAE1_ID_SEL(1);
|
||||||
|
stream_type |= E1_STREAM_DISPLAY;
|
||||||
|
} else {
|
||||||
|
val |= LANE0_ENGINE_ID(0);
|
||||||
|
val |= LANE0_LANE_ID(0);
|
||||||
|
val |= LNAE0_ID_SEL(1);
|
||||||
|
val |= LANE1_ENGINE_ID(0);
|
||||||
|
val |= LANE1_LANE_ID(1);
|
||||||
|
val |= LNAE0_ID_SEL(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (is_rx_dual_channels) {
|
||||||
|
val |= LANE0_ENGINE_ID(0);
|
||||||
|
val |= LANE0_LANE_ID(0);
|
||||||
|
val |= LANE1_ENGINE_ID(1);
|
||||||
|
val |= LANE1_LANE_ID(0);
|
||||||
|
stream_type |= E1_STREAM_DISPLAY;
|
||||||
|
} else {
|
||||||
|
val |= LNAE0_ID_SEL(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val |= stream_type;
|
||||||
|
if (remote_id == DEVICE_REMOTE0)
|
||||||
|
rx_src = rk_des_get_stream_source(route, route->remote0_port0, 0);
|
||||||
|
else
|
||||||
|
rx_src = rk_des_get_stream_source(route, route->remote1_port0, 0);
|
||||||
|
val |= rx_src;
|
||||||
|
if (is_rx_dual_channels) {
|
||||||
|
rx_src = rk_des_get_stream_source(route, route->remote0_port1, 1);
|
||||||
|
val |= rx_src;
|
||||||
|
}
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_SOURCE_CFG, val);
|
||||||
|
|
||||||
|
if (is_rx_dual_lanes || is_rx_dual_channels) {
|
||||||
|
mask = DATA_FIFO0_WR_ID_MASK | DATA_FIFO1_WR_ID_MASK | DATA_FIFO2_WR_ID_MASK |
|
||||||
|
DATA_FIFO3_WR_ID_MASK;
|
||||||
|
mask |= DATA_FIFO0_RD_ID_MASK | DATA_FIFO1_RD_ID_MASK | DATA_FIFO2_RD_ID_MASK |
|
||||||
|
DATA_FIFO3_RD_ID_MASK;
|
||||||
|
if (is_rx_dual_channels) {
|
||||||
|
lane0_dsource_id = (0 << 1) | 0;
|
||||||
|
lane1_dsource_id = (1 << 1) | 0;
|
||||||
|
} else {
|
||||||
|
lane0_dsource_id = (0 << 1) | 0;
|
||||||
|
lane1_dsource_id = (0 << 1) | 1;
|
||||||
|
}
|
||||||
|
val = DATA_FIFO0_WR_ID(lane0_dsource_id) | DATA_FIFO1_WR_ID(lane0_dsource_id);
|
||||||
|
val |= DATA_FIFO0_RD_ID(lane0_dsource_id) | DATA_FIFO1_RD_ID(lane0_dsource_id);
|
||||||
|
|
||||||
|
val |= DATA_FIFO2_WR_ID(lane1_dsource_id) | DATA_FIFO3_WR_ID(lane1_dsource_id);
|
||||||
|
val |= DATA_FIFO2_RD_ID(lane1_dsource_id) | DATA_FIFO3_RD_ID(lane1_dsource_id);
|
||||||
|
|
||||||
|
serdes->i2c_update_bits(client, RKLINK_DES_DATA_ID_CFG, mask, val);
|
||||||
|
|
||||||
|
mask = ORDER_FIFO0_WR_ID_MASK | ORDER_FIFO1_WR_ID_MASK |
|
||||||
|
ORDER_FIFO0_RD_ID_MASK | ORDER_FIFO1_RD_ID_MASK;
|
||||||
|
val = ORDER_FIFO0_WR_ID(lane0_dsource_id) | ORDER_FIFO1_WR_ID(lane1_dsource_id) |
|
||||||
|
ORDER_FIFO0_RD_ID(lane0_dsource_id) | ORDER_FIFO1_RD_ID(lane1_dsource_id);
|
||||||
|
|
||||||
|
serdes->i2c_update_bits(client, RKLINK_DES_ORDER_ID_CFG, mask, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl_val |= DES_EN;
|
||||||
|
serdes->i2c_write_reg(client, RKLINK_DES_LANE_ENGINE_CFG, ctrl_val);
|
||||||
|
|
||||||
|
hwclk_set_rate(hwclk, RKX120_CPS_E0_CLK_RKLINK_RX_PRE, route->vm.pixelclock);
|
||||||
|
dev_info(serdes->dev, "RKX120_CPS_E0_CLK_RKLINK_RX_PRE:%d\n",
|
||||||
|
hwclk_get_rate(hwclk, RKX120_CPS_E0_CLK_RKLINK_RX_PRE));
|
||||||
|
if (is_rx_dual_channels) {
|
||||||
|
hwclk_set_rate(hwclk, RKX120_CPS_E1_CLK_RKLINK_RX_PRE, route->vm.pixelclock);
|
||||||
|
dev_info(serdes->dev, "RKX120_CPS_E1_CLK_RKLINK_RX_PRE:%d\n",
|
||||||
|
hwclk_get_rate(hwclk, RKX120_CPS_E1_CLK_RKLINK_RX_PRE));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route->remote0_port0 == RK_SERDES_RGB_TX || route->remote1_port0 == RK_SERDES_RGB_TX)
|
||||||
|
rk_serdes_link_rx_rgb_enable(serdes, route, remote_id);
|
||||||
|
|
||||||
|
if (route->remote0_port0 == RK_SERDES_LVDS_TX0 ||
|
||||||
|
route->remote1_port0 == RK_SERDES_LVDS_TX0 ||
|
||||||
|
route->remote0_port0 == RK_SERDES_LVDS_TX1 ||
|
||||||
|
route->remote1_port0 == RK_SERDES_LVDS_TX1 ||
|
||||||
|
route->remote0_port0 == RK_SERDES_DUAL_LVDS_TX)
|
||||||
|
rk_serdes_link_rx_lvds_enable(serdes, route, remote_id);
|
||||||
|
|
||||||
|
if (route->remote0_port0 == RK_SERDES_DSI_TX0 || route->remote1_port0 == RK_SERDES_DSI_TX0)
|
||||||
|
rk_serdes_link_rx_dsi_enable(serdes, route, remote_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk120_des_pcs_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route,
|
||||||
|
u8 remote_id, u8 pcs_id)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk120_des_pma_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id,
|
||||||
|
u8 pcs_id)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rkx120_linkrx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id)
|
||||||
|
{
|
||||||
|
rk120_link_rx_cfg(serdes, route, remote_id);
|
||||||
|
|
||||||
|
rk120_des_pcs_cfg(serdes, route, remote_id, 0);
|
||||||
|
rk120_des_pma_cfg(serdes, route, remote_id, 0);
|
||||||
|
if ((serdes->route_flag & ROUTE_MULTI_LANE) &&
|
||||||
|
!(serdes->route_flag & ROUTE_MULTI_REMOTE)) {
|
||||||
|
rk120_des_pcs_cfg(serdes, route, remote_id, 1);
|
||||||
|
rk120_des_pma_cfg(serdes, route, remote_id, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_linkrx_engine_enable(struct rk_serdes *serdes, u8 en_id, u8 dev_id, bool enable)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||||
|
|
||||||
|
if (en_id)
|
||||||
|
serdes->i2c_update_bits(client, DES_RKLINK_STOP_CFG, STOP_E1,
|
||||||
|
enable ? 0 : STOP_E1);
|
||||||
|
else
|
||||||
|
serdes->i2c_update_bits(client, DES_RKLINK_STOP_CFG, STOP_E0,
|
||||||
|
enable ? 0 : STOP_E0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_linkrx_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 = des_pt[func_id].pt_pins;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* config link passthrough */
|
||||||
|
serdes->i2c_update_bits(client, des_pt[func_id].en_reg, des_pt[func_id].en_mask,
|
||||||
|
des_pt[func_id].en_val);
|
||||||
|
if (des_pt[func_id].en_reg)
|
||||||
|
serdes->i2c_update_bits(client, des_pt[func_id].dir_reg, des_pt[func_id].dir_mask,
|
||||||
|
is_rx ? des_pt[func_id].dir_val : ~des_pt[func_id].dir_val);
|
||||||
|
|
||||||
|
/* config passthrough pinctrl */
|
||||||
|
for (i = 0; i < des_pt[func_id].configs; i++) {
|
||||||
|
serdes->set_hwpin(serdes, client, PIN_RKX120, pt_pin[i].bank, pt_pin[i].pin,
|
||||||
|
is_rx ? pt_pin[i].incfgs : pt_pin[i].outcfgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_linkrx_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 = DES_PCS1_READY;
|
||||||
|
else
|
||||||
|
sta = DES_PCS0_READY;
|
||||||
|
|
||||||
|
ret = read_poll_timeout(serdes->i2c_read_reg, ret,
|
||||||
|
!(ret < 0) && (val & sta),
|
||||||
|
1000, USEC_PER_SEC, false, client,
|
||||||
|
DES_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rkx120_pma_link_config(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||||
|
|
||||||
|
serdes->i2c_write_reg(client, DES_PMA_LOAD08(pcs_id), DES_PMA_RX(0x23b1));
|
||||||
|
serdes->i2c_write_reg(client, DES_PMA_LOAD01(pcs_id), DES_PMA_LOS_VTH(0) |
|
||||||
|
DES_PMA_RX_RTERM(0x8));
|
||||||
|
serdes->i2c_write_reg(client, DES_PMA_LOAD06(pcs_id), DES_PMA_MDATA_AMP_SEL(0x3));
|
||||||
|
serdes->i2c_write_reg(client, DES_PMA_REG100(pcs_id), 0xffff0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_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, DES_PMA_STATUS(pcs_id), &val);
|
||||||
|
if (val & DES_PMA_FORCE_INIT_STA)
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_CTRL(pcs_id), DES_PMA_INIT_CNT_CLR_MASK,
|
||||||
|
DES_PMA_INIT_CNT_CLR);
|
||||||
|
|
||||||
|
if (pll->force_init_en)
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_CTRL(pcs_id), DES_PMA_FORCE_INIT_MASK,
|
||||||
|
DES_PMA_FORCE_INIT_EN);
|
||||||
|
else
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_CTRL(pcs_id), DES_PMA_FORCE_INIT_MASK,
|
||||||
|
DES_PMA_FORCE_INIT_DISABLE);
|
||||||
|
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_LOAD09(pcs_id), DES_PMA_PLL_DIV_MASK,
|
||||||
|
DES_PMA_PLL_DIV(pll->pll_div));
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_LOAD05(pcs_id), DES_PMA_PLL_REFCLK_DIV_MASK,
|
||||||
|
DES_PMA_PLL_REFCLK_DIV(pll->pll_refclk_div));
|
||||||
|
|
||||||
|
if (pll->pll_fck_vco_div2)
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_LOAD0C(pcs_id), DES_PMA_FCK_VCO_MASK,
|
||||||
|
DES_PMA_FCK_VCO_DIV2);
|
||||||
|
else
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_LOAD0C(pcs_id), DES_PMA_FCK_VCO_MASK,
|
||||||
|
DES_PMA_FCK_VCO);
|
||||||
|
|
||||||
|
if (pll->pll_div4)
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_LOAD0D(pcs_id), DES_PMA_PLL_DIV4_MASK,
|
||||||
|
DES_PMA_PLL_DIV4);
|
||||||
|
else
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_LOAD0D(pcs_id), DES_PMA_PLL_DIV4_MASK,
|
||||||
|
DES_PMA_PLL_DIV8);
|
||||||
|
|
||||||
|
serdes->i2c_update_bits(client, DES_PMA_LOAD0A(pcs_id), DES_PMA_CLK_2X_DIV_MASK,
|
||||||
|
DES_PMA_CLK_2X_DIV(pll->clk_div));
|
||||||
|
|
||||||
|
rkx120_pma_link_config(serdes, pcs_id, dev_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_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), DES_PCS_EN_MASK, DES_PCS_EN);
|
||||||
|
else
|
||||||
|
serdes->i2c_update_bits(client, PCS_REG00(pcs_id), DES_PCS_EN_MASK,
|
||||||
|
DES_PCS_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rkx120_des_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, DES_GRF_SOC_CON4, mask, val);
|
||||||
|
}
|
||||||
468
drivers/mfd/rkx110_x120/rkx120_reg.h
Normal file
468
drivers/mfd/rkx110_x120/rkx120_reg.h
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Zhang Yubing <yubing.zhang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __X120_REG_H
|
||||||
|
#define __X120_REG_H
|
||||||
|
|
||||||
|
#include <linux/bits.h>
|
||||||
|
|
||||||
|
#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))
|
||||||
|
|
||||||
|
/************** RKX120 DES RX ***************/
|
||||||
|
#define RKX120_DES_CRU_BASE 0x01000000
|
||||||
|
#define RKX120_DES_GRF_BASE 0x01010000
|
||||||
|
#define GRF_REG(x) ((x) + RKX120_DES_GRF_BASE)
|
||||||
|
#define DES_GRF_GPIO0A_IOMUX_L GRF_REG(0x0)
|
||||||
|
#define DES_GRF_GPIO0A_IOMUX_H GRF_REG(0x4)
|
||||||
|
#define DES_GRF_GPIO0B_IOMUX_L GRF_REG(0x8)
|
||||||
|
#define DES_GRF_GPIO0B_IOMUX_H GRF_REG(0xC)
|
||||||
|
#define DES_GRF_GPIO0C_IOMUX_L GRF_REG(0x10)
|
||||||
|
#define DES_GRF_GPIO0C_IOMUX_H GRF_REG(0x14)
|
||||||
|
#define DES_GRF_GPIO0A_PULL_EN GRF_REG(0x20)
|
||||||
|
#define DES_GRF_GPIO0B_PULL_EN GRF_REG(0x24)
|
||||||
|
#define DES_GRF_GPIO0C_PULL_EN GRF_REG(0x28)
|
||||||
|
#define DES_GRF_GPIO1A_IOMUX GRF_REG(0x80)
|
||||||
|
#define DES_GRF_GPIO1B_IOMUX GRF_REG(0x84)
|
||||||
|
#define DES_GRF_GPIO1C_IOMUX GRF_REG(0x88)
|
||||||
|
#define DES_GRF_GPIO1A_PULL_CFG GRF_REG(0x90)
|
||||||
|
#define DES_GRF_GPIO1B_PULL_CFG GRF_REG(0x94)
|
||||||
|
#define DES_GRF_GPIO1C_PULL_CFG GRF_REG(0x98)
|
||||||
|
#define DES_GRF_SOC_CON2 GRF_REG(0x108)
|
||||||
|
#define DES_GRF_SOC_STATUS0 GRF_REG(0x160)
|
||||||
|
|
||||||
|
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_PWM_0,
|
||||||
|
|
||||||
|
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_SDO0,
|
||||||
|
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_PWM_1,
|
||||||
|
|
||||||
|
/* GPIO0B_IOMUX_H */
|
||||||
|
GPIO0B7_SHIFT = 12,
|
||||||
|
GPIO0B7_MASK = GENMASK(14, 12),
|
||||||
|
GPIO0B7_GPIO = 0,
|
||||||
|
GPIO0B7_I2S_MCLK,
|
||||||
|
GPIO0B7_TEST_CLK_OUT,
|
||||||
|
GPIO0B7_TP6,
|
||||||
|
|
||||||
|
GPIO0B6_SHIFT = 8,
|
||||||
|
GPIO0B6_MASK = GENMASK(10, 8),
|
||||||
|
GPIO0B6_GPIO = 0,
|
||||||
|
GPIO0B6_I2S_SDO3,
|
||||||
|
GPIO0B6_I2S_SDI0,
|
||||||
|
GPIO0B6_TP5,
|
||||||
|
|
||||||
|
GPIO0B5_SHIFT = 4,
|
||||||
|
GPIO0B5_MASK = GENMASK(6, 4),
|
||||||
|
GPIO0B5_GPIO = 0,
|
||||||
|
GPIO0B5_I2S_SDO2,
|
||||||
|
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,
|
||||||
|
GPIO0B5_I2S_SDO1,
|
||||||
|
GPIO0B5_GPI_5,
|
||||||
|
GPIO0B5_GPO_5,
|
||||||
|
GPIO0B5_I2C1_SCL_M,
|
||||||
|
GPIO0B5_I2C1_SCL_S,
|
||||||
|
GPIO0B5_PWM2,
|
||||||
|
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_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,
|
||||||
|
|
||||||
|
GPIO1A6_SHIFT = 12,
|
||||||
|
GPIO1A6_MASK = GENMASK(13, 12),
|
||||||
|
GPIO1A6_GPIO = 0,
|
||||||
|
GPIO1A6_LCDC_D10,
|
||||||
|
GPIO1A6_CIF_D10,
|
||||||
|
|
||||||
|
GPIO1A5_SHIFT = 10,
|
||||||
|
GPIO1A5_MASK = GENMASK(11, 10),
|
||||||
|
GPIO1A5_GPIO = 0,
|
||||||
|
GPIO1A5_LCDC_D9,
|
||||||
|
GPIO1A5_CIF_D9,
|
||||||
|
|
||||||
|
GPIO1A4_SHIFT = 8,
|
||||||
|
GPIO1A4_MASK = GENMASK(9, 8),
|
||||||
|
GPIO1A4_GPIO = 0,
|
||||||
|
GPIO1A4_LCDC_D8,
|
||||||
|
GPIO1A4_CIF_D8,
|
||||||
|
|
||||||
|
GPIO1A3_SHIFT = 6,
|
||||||
|
GPIO1A3_MASK = GENMASK(7, 6),
|
||||||
|
GPIO1A3_GPIO = 0,
|
||||||
|
GPIO1A3_LCDC_D7,
|
||||||
|
GPIO1A3_CIF_D7,
|
||||||
|
|
||||||
|
GPIO1A2_SHIFT = 4,
|
||||||
|
GPIO1A2_MASK = GENMASK(5, 4),
|
||||||
|
GPIO1A2_GPIO = 0,
|
||||||
|
GPIO1A2_LCDC_D6,
|
||||||
|
GPIO1A2_CIF_D6,
|
||||||
|
|
||||||
|
GPIO1A1_SHIFT = 2,
|
||||||
|
GPIO1A1_MASK = GENMASK(3, 2),
|
||||||
|
GPIO1A1_GPIO = 0,
|
||||||
|
GPIO1A1_LCDC_D5,
|
||||||
|
GPIO1A1_CIF_D5,
|
||||||
|
|
||||||
|
GPIO1A0_SHIFT = 0,
|
||||||
|
GPIO1A0_MASK = GENMASK(1, 0),
|
||||||
|
GPIO1A0_GPIO = 0,
|
||||||
|
GPIO1A0_LCDC_D4,
|
||||||
|
GPIO1A0_CIF_D4,
|
||||||
|
|
||||||
|
/* GPIO1B_IOMUX */
|
||||||
|
GPIO1B7_SHIFT = 14,
|
||||||
|
GPIO1B7_MASK = GENMASK(15, 14),
|
||||||
|
GPIO1B7_GPIO = 0,
|
||||||
|
GPIO1B7_LCDC_D19,
|
||||||
|
|
||||||
|
GPIO1B6_SHIFT = 12,
|
||||||
|
GPIO1B6_MASK = GENMASK(13, 12),
|
||||||
|
GPIO1B6_GPIO = 0,
|
||||||
|
GPIO1B6_LCDC_D18,
|
||||||
|
|
||||||
|
GPIO1B5_SHIFT = 10,
|
||||||
|
GPIO1B5_MASK = GENMASK(11, 10),
|
||||||
|
GPIO1B5_GPIO = 0,
|
||||||
|
GPIO1B5_LCDC_D17,
|
||||||
|
|
||||||
|
GPIO1B4_SHIFT = 8,
|
||||||
|
GPIO1B4_MASK = GENMASK(9, 8),
|
||||||
|
GPIO1B4_GPIO = 0,
|
||||||
|
GPIO1B4_LCDC_D16,
|
||||||
|
|
||||||
|
GPIO1B3_SHIFT = 6,
|
||||||
|
GPIO1B3_MASK = GENMASK(7, 6),
|
||||||
|
GPIO1B3_GPIO = 0,
|
||||||
|
GPIO1B3_LCDC_D15,
|
||||||
|
GPIO1B3_CIF_D15,
|
||||||
|
|
||||||
|
GPIO1B2_SHIFT = 4,
|
||||||
|
GPIO1B2_MASK = GENMASK(5, 4),
|
||||||
|
GPIO1B2_GPIO = 0,
|
||||||
|
GPIO1B2_LCDC_D14,
|
||||||
|
GPIO1B2_CIF_D14,
|
||||||
|
|
||||||
|
GPIO1B1_SHIFT = 2,
|
||||||
|
GPIO1B1_MASK = GENMASK(3, 2),
|
||||||
|
GPIO1B1_GPIO = 0,
|
||||||
|
GPIO1B1_LCDC_D13,
|
||||||
|
GPIO1B1_CIF_D13,
|
||||||
|
|
||||||
|
GPIO1B0_SHIFT = 0,
|
||||||
|
GPIO1B0_MASK = GENMASK(1, 0),
|
||||||
|
GPIO1B0_GPIO = 0,
|
||||||
|
GPIO1B0_LCDC_D12,
|
||||||
|
GPIO1B0_CIF_D12,
|
||||||
|
|
||||||
|
/* GPIO1C_IOMUX */
|
||||||
|
GPIO1C3_SHIFT = 6,
|
||||||
|
GPIO1C3_MASK = GENMASK(7, 6),
|
||||||
|
GPIO1C3_GPIO = 0,
|
||||||
|
GPIO1C3_LCDC_D23,
|
||||||
|
|
||||||
|
GPIO1C2_SHIFT = 4,
|
||||||
|
GPIO1C2_MASK = GENMASK(5, 4),
|
||||||
|
GPIO1C2_GPIO = 0,
|
||||||
|
GPIO1C2_LCDC_D22,
|
||||||
|
|
||||||
|
GPIO1C1_SHIFT = 2,
|
||||||
|
GPIO1C1_MASK = GENMASK(3, 2),
|
||||||
|
GPIO1C1_GPIO = 0,
|
||||||
|
GPIO1C1_LCDC_D21,
|
||||||
|
|
||||||
|
GPIO1C0_SHIFT = 0,
|
||||||
|
GPIO1C0_MASK = GENMASK(1, 0),
|
||||||
|
GPIO1C0_GPIO = 0,
|
||||||
|
GPIO1C0_LCDC_D20,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DES_GRF_SOC_CON0 GRF_REG(0x100)
|
||||||
|
#define DES_GRF_SOC_CON1 GRF_REG(0x104)
|
||||||
|
#define DES_GRF_SOC_CON2 GRF_REG(0x108)
|
||||||
|
#define DES_GRF_SOC_CON3 GRF_REG(0x10C)
|
||||||
|
#define DES_GRF_SOC_CON4 GRF_REG(0x110)
|
||||||
|
#define DES_GRF_SOC_CON5 GRF_REG(0x114)
|
||||||
|
#define DES_GRF_SOC_CON6 GRF_REG(0x118)
|
||||||
|
#define DES_GRF_SOC_CON7 GRF_REG(0x11C)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* SOC_CON0 */
|
||||||
|
LVDS_ALIGN_EN_SHIFT = 14,
|
||||||
|
LVDS_ALIGN_EN_MASK = GENMASK(15, 14),
|
||||||
|
LVDS_ALIGN_DISABLE = 0,
|
||||||
|
LVDS_ALIGN_EN,
|
||||||
|
|
||||||
|
/* SOC_CON2 */
|
||||||
|
LVDS1_LINK_SEL_SHIFT = 14,
|
||||||
|
LVDS1_LINK_SEL_MASK = GENMASK(14, 14),
|
||||||
|
/* enable lvds source from pattern generation */
|
||||||
|
LINK_SEL_PG_DISABLE = 0,
|
||||||
|
LINK_SEL_PG_EN = 1,
|
||||||
|
|
||||||
|
LVDS0_LINK_SEL_SHIFT = 13,
|
||||||
|
LVDS0_LINK_SEL_MASK = GENMASK(13, 13),
|
||||||
|
|
||||||
|
DSI0_LINK_SEL_SHIFT = 12,
|
||||||
|
DSI0_LINK_SEL_MASK = GENMASK(12, 12),
|
||||||
|
|
||||||
|
LVDS1_MSB_SHIFT = 5,
|
||||||
|
LVDS1_MSB_MASK = GENMASK(5, 5),
|
||||||
|
LVDS_LSB = 0,
|
||||||
|
LVDS_MSB,
|
||||||
|
|
||||||
|
LVDS1_FORMAT_SHIFT = 4,
|
||||||
|
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 */
|
||||||
|
|
||||||
|
/* SOC_CON4 */
|
||||||
|
PMA1_EN_SHIFT = 11,
|
||||||
|
PMA1_EN_MASK = HIWORD_MASK(11, 11),
|
||||||
|
PMA1_EN = HIWORD_UPDATE(1, BIT(11), 11),
|
||||||
|
PMA1_DISABLE = HIWORD_UPDATE(0, BIT(11), 11),
|
||||||
|
|
||||||
|
PMA0_EN_SHIFT = 10,
|
||||||
|
PMA0_EN_MASK = HIWORD_MASK(10, 10),
|
||||||
|
PMA0_EN = HIWORD_UPDATE(1, BIT(10), 10),
|
||||||
|
PMA0_DISABLE = HIWORD_UPDATE(0, BIT(10), 10),
|
||||||
|
|
||||||
|
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 */
|
||||||
|
MIPI_PHY0_MODE_SEL_SHIFT = 4,
|
||||||
|
MIPI_PHY0_MODE_SEL_MASK = GENMASK(7, 4),
|
||||||
|
MIPI_PHY0_MODE_DSI = 0,
|
||||||
|
MIPI_PHY0_MODE_CSI,
|
||||||
|
|
||||||
|
/* SOC_CON6 */
|
||||||
|
LVDS0_CLK_SOURCE_SHIFT = 0,
|
||||||
|
LVDS0_CLK_SOURCE_MASK = GENMASK(3, 0),
|
||||||
|
|
||||||
|
/* SOC_CON7 */
|
||||||
|
LVDS1_CLK_SOURCE_SHIFT = 4,
|
||||||
|
LVDS1_CLK_SOURCE_MASK = GENMASK(15, 4),
|
||||||
|
|
||||||
|
DSI0_DPI_UPDATE_CFG_SHIFT = 2,
|
||||||
|
DSI0_DPI_UPDATE_CFG_MASK = GENMASK(2, 2),
|
||||||
|
|
||||||
|
DSI0_DPI_REDUCED_COLOR_SHIFT = 1,
|
||||||
|
DSI0_DPI_REDUCED_COLOR_MASK = GENMASK(1, 1),
|
||||||
|
|
||||||
|
DSI0_DPI_DISABLE_SHIFT = 0,
|
||||||
|
DSI0_DPI_DISABLE_MASK = GENMASK(0, 0),
|
||||||
|
|
||||||
|
/* SOC_CON8 */
|
||||||
|
|
||||||
|
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 = GENMASK(7, 4),
|
||||||
|
LDO_VOL_110 = 0,
|
||||||
|
LDO_PLC_115,
|
||||||
|
|
||||||
|
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_CON9 */
|
||||||
|
|
||||||
|
/* DES_GRF_IRQ_EN */
|
||||||
|
|
||||||
|
/* DES_GRF_SOC_STATUS0 */
|
||||||
|
DES_PCS1_READY = BIT(1),
|
||||||
|
DES_PCS0_READY = BIT(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RKX120_DVP_TX_BASE 0x01020000
|
||||||
|
#define RKX120_DSI_TX_BASE 0x01030000
|
||||||
|
#define RKX120_CSI_TX0_BASE 0x01040000
|
||||||
|
#define RKX120_CSI_TX1_BASE 0x01050000
|
||||||
|
#define RKX120_GPIO0_TX_BASE 0x01060000
|
||||||
|
#define RKX120_GPIO1_TX_BASE 0x01068000
|
||||||
|
|
||||||
|
#define RKX120_DES_RKLINK_BASE 0x01070000
|
||||||
|
#define RKX120_DES_PCS0_BASE 0x01074000
|
||||||
|
#define RKX120_DES_PCS1_BASE 0x01075000
|
||||||
|
#define RKX120_DES_PCS_OFFSET 0x00001000
|
||||||
|
|
||||||
|
#define RKX120_PWM_BASE 0x01080000
|
||||||
|
#define RKX120_EFUSE_BASE 0x01090000
|
||||||
|
#define RKX120_MIPI_LVDS_TX_PHY0_BASE 0x010A0000
|
||||||
|
#define RKX120_MIPI_LVDS_TX_PHY1_BASE 0x010B0000
|
||||||
|
#define RKX120_GRF_MIPI0_BASE 0x010C0000
|
||||||
|
#define RKX120_GRF_MIPI1_BASE 0x010D0000
|
||||||
|
#define RKX120_DES_PMA0_BASE 0x010E0000
|
||||||
|
#define RKX120_DES_PMA1_BASE 0x010F0000
|
||||||
|
#define RKX120_DES_PMA_OFFSET 0x00010000
|
||||||
|
|
||||||
|
#define RKX120_PATTERN_GEN_DSI_BASE 0x01100000
|
||||||
|
#define RKX120_PATTERN_GEN_LVDS0_BASE 0x01110000
|
||||||
|
#define RKX120_PATTERN_GEN_LVDS1_BASE 0x01120000
|
||||||
|
|
||||||
|
#endif
|
||||||
87
drivers/mfd/rkx110_x120/serdes_combphy.c
Normal file
87
drivers/mfd/rkx110_x120/serdes_combphy.c
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
* Author: Guochun Huang <hero.huang@rock-chips.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include "rkx110_x120.h"
|
||||||
|
#include "serdes_combphy.h"
|
||||||
|
|
||||||
|
int serdes_combphy_write(struct rk_serdes *serdes, u8 remote_id, u32 reg, u32 val)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[remote_id].client;
|
||||||
|
|
||||||
|
return serdes->i2c_write_reg(client, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int serdes_combphy_read(struct rk_serdes *serdes, u8 remote_id, u32 reg, u32 *val)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[remote_id].client;
|
||||||
|
|
||||||
|
return serdes->i2c_read_reg(client, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int serdes_combphy_update_bits(struct rk_serdes *serdes, u8 remote_id,
|
||||||
|
u32 reg, u32 mask, u32 val)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = serdes->chip[remote_id].client;
|
||||||
|
|
||||||
|
return serdes->i2c_update_bits(client, reg, mask, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void serdes_combphy_get_default_config(u64 hs_clk_rate,
|
||||||
|
struct configure_opts_combphy *cfg)
|
||||||
|
{
|
||||||
|
unsigned long long ui;
|
||||||
|
|
||||||
|
ui = ALIGN(NSEC_PER_SEC, hs_clk_rate);
|
||||||
|
do_div(ui, hs_clk_rate);
|
||||||
|
|
||||||
|
cfg->clk_miss = 0;
|
||||||
|
cfg->clk_post = 60 + 52 * ui;
|
||||||
|
cfg->clk_pre = 8;
|
||||||
|
cfg->clk_prepare = 38;
|
||||||
|
cfg->clk_settle = 95;
|
||||||
|
cfg->clk_term_en = 0;
|
||||||
|
cfg->clk_trail = 60;
|
||||||
|
cfg->clk_zero = 262;
|
||||||
|
cfg->d_term_en = 0;
|
||||||
|
cfg->eot = 0;
|
||||||
|
cfg->hs_exit = 100;
|
||||||
|
cfg->hs_prepare = 40 + 4 * ui;
|
||||||
|
cfg->hs_zero = 105 + 6 * ui;
|
||||||
|
cfg->hs_settle = 85 + 6 * ui;
|
||||||
|
cfg->hs_skip = 40;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The MIPI D-PHY specification (Section 6.9, v1.2, Table 14, Page 40)
|
||||||
|
* contains this formula as:
|
||||||
|
*
|
||||||
|
* T_HS-TRAIL = max(n * 8 * ui, 60 + n * 4 * ui)
|
||||||
|
*
|
||||||
|
* where n = 1 for forward-direction HS mode and n = 4 for reverse-
|
||||||
|
* direction HS mode. There's only one setting and this function does
|
||||||
|
* not parameterize on anything other that ui, so this code will
|
||||||
|
* assumes that reverse-direction HS mode is supported and uses n = 4.
|
||||||
|
*/
|
||||||
|
cfg->hs_trail = max(4 * 8 * ui, 60 + 4 * 4 * ui);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that TINIT is considered a protocol-dependent parameter, and
|
||||||
|
* thus the exact requirements for TINIT,MASTER and TINIT,SLAVE (transmitter
|
||||||
|
* and receiver initialization Stop state lengths, respectively,) are defined
|
||||||
|
* by the protocol layer specification and are outside the scope of this document.
|
||||||
|
* However, the D-PHY specification does place a minimum bound on the lengths of
|
||||||
|
* TINIT,MASTER and TINIT,SLAVE, which each shall be no less than 100 µs. A protocol
|
||||||
|
* layer specification using the D-PHY specification may specify any values greater
|
||||||
|
* than this limit, for example, TINIT,MASTER ≥ 1 ms and TINIT,SLAVE = 500 to 800 µs
|
||||||
|
*/
|
||||||
|
cfg->init = NSEC_PER_SEC / MSEC_PER_SEC;
|
||||||
|
cfg->lpx = 50;
|
||||||
|
cfg->ta_get = 5 * cfg->lpx;
|
||||||
|
cfg->ta_go = 4 * cfg->lpx;
|
||||||
|
cfg->ta_sure = cfg->lpx;
|
||||||
|
cfg->wakeup = NSEC_PER_SEC / MSEC_PER_SEC;
|
||||||
|
}
|
||||||
28
drivers/mfd/rkx110_x120/serdes_combphy.h
Normal file
28
drivers/mfd/rkx110_x120/serdes_combphy.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SERDES_COMBPHY_H
|
||||||
|
#define SERDES_COMBPHY_H
|
||||||
|
|
||||||
|
int serdes_combphy_write(struct rk_serdes *serdes, u8 remote_id, u32 reg, u32 val);
|
||||||
|
int serdes_combphy_read(struct rk_serdes *serdes, u8 remote_id, u32 reg, u32 *val);
|
||||||
|
int serdes_combphy_update_bits(struct rk_serdes *serdes, u8 remote_id,
|
||||||
|
u32 reg, u32 mask, u32 val);
|
||||||
|
void serdes_combphy_get_default_config(u64 hs_clk_rate,
|
||||||
|
struct configure_opts_combphy *cfg);
|
||||||
|
|
||||||
|
void rkx110_combrxphy_set_mode(struct rk_serdes *ser, enum combrx_phy_mode mode);
|
||||||
|
void rkx110_combrxphy_set_rate(struct rk_serdes *ser, u64 rate);
|
||||||
|
void rkx110_combrxphy_power_on(struct rk_serdes *ser, enum comb_phy_id id);
|
||||||
|
void rkx110_combrxphy_power_off(struct rk_serdes *ser, enum comb_phy_id id);
|
||||||
|
|
||||||
|
void rkx120_combtxphy_set_mode(struct rk_serdes *des, enum combtx_phy_mode mode);
|
||||||
|
void rkx120_combtxphy_set_rate(struct rk_serdes *des, u64 rate);
|
||||||
|
u64 rkx120_combtxphy_get_rate(struct rk_serdes *des);
|
||||||
|
void rkx120_combtxphy_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id);
|
||||||
|
void rkx120_combtxphy_power_off(struct rk_serdes *des, u8 remote_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
Reference in New Issue
Block a user