misc: Add rk628 misc drivers

Customers may use rk628 drivers on different platforms.
Hence we need drivers that do not rely on the FB/DRM
display framework.

Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
Change-Id: Iaab679e4a72d0fb0e5a76bee89b8e1bdac60f4a7
This commit is contained in:
Algea Cao
2023-06-26 17:11:37 +08:00
parent e847ed9deb
commit 484d7b1bd6
36 changed files with 10683 additions and 0 deletions

View File

@@ -5,6 +5,8 @@
menu "Misc devices"
source "drivers/misc/rk628/Kconfig"
config RK803
tristate "RK803"
default n

View File

@@ -3,6 +3,7 @@
# Makefile for misc devices that really don't fit anywhere else.
#
obj-y += rk628/
obj-$(CONFIG_RK803) += rk803.o
obj-y += rockchip/
obj-$(CONFIG_LT7911D_FB_NOTIFIER) += lt7911d-fb-notifier.o

View File

@@ -0,0 +1,27 @@
# SPDX-License-Identifier: GPL-2.0
menu "RK628 misc driver"
config RK628_MISC
tristate "rk628 misc driver"
default n
help
Say y here to enable Rockchip rk628 misc driver.
This option is used to support rgb/hdmi/bt1120 input and dsi/lvds/gvi/hdmi output.
config RK628_MISC_HDMITX
bool "rk628 misc hdmitx driver"
default n
depends on RK628_MISC
depends on DRM
help
Say y here to enable Rockchip rk628 misc hdmitx driver.
This option is used to support hdmi output.
config ROCKCHIP_THUNDER_BOOT_RK628
bool "Rockchip RK628 Thunder Boot support"
default n
depends on RK628_MISC
help
Say y here to enable Rockchip rk628 thunder boot support.
This option make the kernel boot faster.
endmenu

View File

@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
rk628_misc-$(CONFIG_RK628_MISC) += rk628.o rk628_cru.o rk628_config.o rk628_post_process.o \
rk628_combrxphy.o rk628_hdmirx.o rk628_combtxphy.o rk628_dsi.o \
panel.o rk628_lvds.o rk628_rgb.o rk628_gvi.o rk628_pinctrl.o \
rk628_csi.o
rk628_misc-$(CONFIG_RK628_MISC_HDMITX) += rk628_hdmitx.o
obj-$(CONFIG_RK628_MISC) += rk628_misc.o

245
drivers/misc/rk628/panel.c Normal file
View File

@@ -0,0 +1,245 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include "rk628.h"
#include <linux/gpio/consumer.h>
#include <linux/backlight.h>
#include "panel.h"
static int
dsi_panel_parse_cmds(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 = kmemdup(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) {
pr_err("%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) {
pr_err("%s: dcs_cmd=%x len=%d error!", __func__, buf[0], blen);
kfree(buf);
return -EINVAL;
}
pcmds->cmds = kcalloc(cnt, sizeof(struct cmd_desc), GFP_KERNEL);
if (!pcmds->cmds) {
kfree(buf);
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 dsi_panel_get_cmds(struct rk628 *rk628, struct device_node *dsi_np)
{
struct device_node *np;
const void *data;
int len;
int ret, err;
np = of_find_node_by_name(dsi_np, "rk628-panel");
if (!np)
return -EINVAL;
data = of_get_property(np, "panel-init-sequence", &len);
if (data) {
rk628->panel->on_cmds = kcalloc(1, sizeof(struct panel_cmds), GFP_KERNEL);
if (!rk628->panel->on_cmds)
return -ENOMEM;
err = dsi_panel_parse_cmds(data, len, rk628->panel->on_cmds);
if (err) {
dev_err(rk628->dev, "failed to parse dsi panel init sequence\n");
ret = err;
goto init_err;
}
}
data = of_get_property(np, "panel-exit-sequence", &len);
if (data) {
rk628->panel->off_cmds = kcalloc(1, sizeof(struct panel_cmds), GFP_KERNEL);
if (!rk628->panel->off_cmds) {
ret = -ENOMEM;
goto on_err;
}
err = dsi_panel_parse_cmds(data, len, rk628->panel->off_cmds);
if (err) {
dev_err(rk628->dev, "failed to parse dsi panel exit sequence\n");
ret = err;
goto exit_err;
}
}
return 0;
exit_err:
kfree(rk628->panel->off_cmds);
on_err:
kfree(rk628->panel->on_cmds->cmds);
kfree(rk628->panel->on_cmds->buf);
init_err:
kfree(rk628->panel->on_cmds);
return ret;
}
int rk628_panel_info_get(struct rk628 *rk628, struct device_node *np)
{
struct panel_simple *panel;
struct device *dev = rk628->dev;
struct device_node *backlight;
int ret;
panel = devm_kzalloc(dev, sizeof(struct panel_simple), GFP_KERNEL);
if (!panel)
return -ENOMEM;
panel->supply = devm_regulator_get(dev, "power");
if (IS_ERR(panel->supply)) {
ret = PTR_ERR(panel->supply);
dev_err(dev, "failed to get power regulator: %d\n", ret);
return ret;
}
panel->enable_gpio = devm_gpiod_get_optional(dev, "panel-enable", GPIOD_OUT_LOW);
if (IS_ERR(panel->enable_gpio)) {
ret = PTR_ERR(panel->enable_gpio);
dev_err(dev, "failed to request panel enable GPIO: %d\n", ret);
return ret;
}
panel->reset_gpio = devm_gpiod_get_optional(dev, "panel-reset", GPIOD_OUT_LOW);
if (IS_ERR(panel->reset_gpio)) {
ret = PTR_ERR(panel->reset_gpio);
dev_err(dev, "failed to request panel reset GPIO: %d\n", ret);
return ret;
}
backlight = of_parse_phandle(dev->of_node, "panel-backlight", 0);
if (backlight) {
panel->backlight = of_find_backlight_by_node(backlight);
of_node_put(backlight);
if (!panel->backlight) {
dev_err(dev, "failed to find backlight\n");
return -EPROBE_DEFER;
}
}
rk628->panel = panel;
if (rk628->output_mode == OUTPUT_MODE_DSI) {
ret = dsi_panel_get_cmds(rk628, np);
if (ret) {
dev_err(dev, "failed to get cmds\n");
return ret;
}
}
return 0;
}
void rk628_panel_prepare(struct rk628 *rk628)
{
int ret;
if (rk628->panel->supply) {
ret = regulator_enable(rk628->panel->supply);
if (ret)
dev_info(rk628->dev, "failed to enable panel power supply\n");
}
if (rk628->panel->enable_gpio) {
gpiod_set_value(rk628->panel->enable_gpio, 0);
mdelay(120);
gpiod_set_value(rk628->panel->enable_gpio, 1);
mdelay(120);
}
if (rk628->panel->reset_gpio) {
gpiod_set_value(rk628->panel->reset_gpio, 0);
mdelay(120);
gpiod_set_value(rk628->panel->reset_gpio, 1);
mdelay(120);
gpiod_set_value(rk628->panel->reset_gpio, 0);
mdelay(120);
}
}
void rk628_panel_enable(struct rk628 *rk628)
{
if (rk628->panel->backlight)
backlight_enable(rk628->panel->backlight);
}
void rk628_panel_unprepare(struct rk628 *rk628)
{
if (rk628->panel->reset_gpio) {
gpiod_set_value(rk628->panel->reset_gpio, 1);
mdelay(120);
}
if (rk628->panel->enable_gpio) {
gpiod_set_value(rk628->panel->enable_gpio, 0);
mdelay(120);
}
if (rk628->panel->supply)
regulator_disable(rk628->panel->supply);
}
void rk628_panel_disable(struct rk628 *rk628)
{
if (rk628->panel->backlight)
backlight_disable(rk628->panel->backlight);
}

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#ifndef _PANEL_H
#define _PANEL_H
#include "rk628.h"
int rk628_panel_info_get(struct rk628 *rk628, struct device_node *np);
void rk628_panel_prepare(struct rk628 *rk628);
void rk628_panel_enable(struct rk628 *rk628);
void rk628_panel_unprepare(struct rk628 *rk628);
void rk628_panel_disable(struct rk628 *rk628);
#endif

1310
drivers/misc/rk628/rk628.c Normal file

File diff suppressed because it is too large Load Diff

484
drivers/misc/rk628/rk628.h Normal file
View File

@@ -0,0 +1,484 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#ifndef _RK628_H
#define _RK628_H
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/version.h>
#include <linux/of.h>
#include <linux/wakelock.h>
#include <linux/workqueue.h>
#include <linux/regulator/consumer.h>
#define DRIVER_VERSION "0.0.1"
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
#define HIWORD_UPDATE(v, h, l) ((((v) << (l)) & GENMASK((h), (l))) | \
(GENMASK((h), (l)) << 16))
#define GRF_SYSTEM_CON0 0x0000
#define SW_VSYNC_POL_MASK BIT(26)
#define SW_VSYNC_POL(x) UPDATE(x, 26, 26)
#define SW_HSYNC_POL_MASK BIT(25)
#define SW_HSYNC_POL(x) UPDATE(x, 25, 25)
#define SW_ADAPTER_I2CSLADR_MASK GENMASK(24, 22)
#define SW_ADAPTER_I2CSLADR(x) UPDATE(x, 24, 22)
#define SW_EDID_MODE_MASK BIT(21)
#define SW_EDID_MODE(x) UPDATE(x, 21, 21)
#define SW_I2S_DATA_OEN_MASK BIT(10)
#define SW_I2S_DATA_OEN(x) UPDATE(x, 10, 10)
#define SW_BT_DATA_OEN_MASK BIT(9)
#define SW_BT_DATA_OEN BIT(9)
#define SW_EFUSE_HDCP_EN_MASK BIT(8)
#define SW_EFUSE_HDCP_EN(x) UPDATE(x, 8, 8)
#define SW_OUTPUT_MODE_MASK GENMASK(7, 3)
#define SW_OUTPUT_MODE(x) UPDATE(x, 7, 3)
#define SW_INPUT_MODE_MASK GENMASK(2, 0)
#define SW_INPUT_MODE(x) UPDATE(x, 2, 0)
#define GRF_SYSTEM_CON1 0x0004
#define GRF_SYSTEM_CON2 0x0008
#define GRF_SYSTEM_CON3 0x000c
#define GRF_GPIO_RX_CEC_SEL_MASK BIT(7)
#define GRF_GPIO_RX_CEC_SEL(x) UPDATE(x, 7, 7)
#define GRF_GPIO_RXDDC_SDA_SEL_MASK BIT(6)
#define GRF_GPIO_RXDDC_SDA_SEL(x) UPDATE(x, 6, 6)
#define GRF_GPIO_RXDDC_SCL_SEL_MASK BIT(5)
#define GRF_GPIO_RXDDC_SCL_SEL(x) UPDATE(x, 5, 5)
#define GRF_SCALER_CON0 0x0010
#define SCL_VER_DOWN_MODE(x) HIWORD_UPDATE(x, 8, 8)
#define SCL_HOR_DOWN_MODE(x) HIWORD_UPDATE(x, 7, 7)
#define SCL_BIC_COE_SEL(x) HIWORD_UPDATE(x, 6, 5)
#define SCL_VER_MODE(x) HIWORD_UPDATE(x, 4, 3)
#define SCL_HOR_MODE(x) HIWORD_UPDATE(x, 2, 1)
#define SCL_EN(x) HIWORD_UPDATE(x, 0, 0)
#define GRF_SCALER_CON1 0x0014
#define SCL_V_FACTOR(x) UPDATE(x, 31, 16)
#define SCL_H_FACTOR(x) UPDATE(x, 15, 0)
#define GRF_SCALER_CON2 0x0018
#define DSP_FRAME_VST(x) UPDATE(x, 28, 16)
#define DSP_FRAME_HST(x) UPDATE(x, 12, 0)
#define GRF_SCALER_CON3 0x001c
#define DSP_HS_END(x) UPDATE(x, 23, 16)
#define DSP_HTOTAL(x) UPDATE(x, 12, 0)
#define GRF_SCALER_CON4 0x0020
#define DSP_HACT_ST(x) UPDATE(x, 28, 16)
#define DSP_HACT_END(x) UPDATE(x, 12, 0)
#define GRF_SCALER_CON5 0x0024
#define DSP_VS_END(x) UPDATE(x, 23, 16)
#define DSP_VTOTAL(x) UPDATE(x, 12, 0)
#define GRF_SCALER_CON6 0x0028
#define DSP_VACT_ST(x) UPDATE(x, 28, 16)
#define DSP_VACT_END(x) UPDATE(x, 12, 0)
#define GRF_SCALER_CON7 0x002c
#define DSP_HBOR_ST(x) UPDATE(x, 28, 16)
#define DSP_HBOR_END(x) UPDATE(x, 12, 0)
#define GRF_SCALER_CON8 0x0030
#define DSP_VBOR_ST(x) UPDATE(x, 28, 16)
#define DSP_VBOR_END(x) UPDATE(x, 12, 0)
#define GRF_POST_PROC_CON 0x0034
#define SW_DCLK_OUT_INV_EN BIT(9)
#define SW_DCLK_IN_INV_EN BIT(8)
#define SW_TXPHY_REFCLK_SEL_MASK GENMASK(6, 5)
#define SW_TXPHY_REFCLK_SEL(x) UPDATE(x, 6, 5)
#define SW_HDMITX_VCLK_PLLREF_SEL_MASK BIT(4)
#define SW_HDMITX_VCLK_PLLREF_SEL(x) UPDATE(x, 4, 4)
#define SW_HDMITX_DCLK_INV_EN BIT(3)
#define SW_SPLIT_MODE(x) UPDATE(x, 1, 1)
#define SW_SPLIT_EN BIT(0)
#define GRF_CSC_CTRL_CON 0x0038
#define SW_YUV2VYU_SWP(x) HIWORD_UPDATE(x, 8, 8)
#define SW_R2Y_EN(x) HIWORD_UPDATE(x, 4, 4)
#define SW_Y2R_EN(x) HIWORD_UPDATE(x, 0, 0)
#define GRF_LVDS_TX_CON 0x003c
#define SW_LVDS_CON_DUAL_SEL(x) HIWORD_UPDATE(x, 12, 12)
#define SW_LVDS_CON_DEN_POLARITY(x) HIWORD_UPDATE(x, 11, 11)
#define SW_LVDS_CON_HS_POLARITY(x) HIWORD_UPDATE(x, 10, 10)
#define SW_LVDS_CON_CLKINV(x) HIWORD_UPDATE(x, 9, 9)
#define SW_LVDS_STARTPHASE(x) HIWORD_UPDATE(x, 8, 8)
#define SW_LVDS_CON_STARTSEL(x) HIWORD_UPDATE(x, 7, 7)
#define SW_LVDS_CON_CHASEL(x) HIWORD_UPDATE(x, 6, 6)
#define SW_LVDS_TIE_VSYNC_VALUE(x) HIWORD_UPDATE(x, 5, 5)
#define SW_LVDS_TIE_HSYNC_VALUE(x) HIWORD_UPDATE(x, 4, 4)
#define SW_LVDS_TIE_DEN_ONLY(x) HIWORD_UPDATE(x, 3, 3)
#define SW_LVDS_CON_MSBSEL(x) HIWORD_UPDATE(x, 2, 2)
#define SW_LVDS_CON_SELECT(x) HIWORD_UPDATE(x, 1, 0)
#define GRF_RGB_DEC_CON0 0x0040
#define SW_HRES_MASK GENMASK(28, 16)
#define SW_HRES(x) UPDATE(x, 28, 16)
#define DUAL_DATA_SWAP BIT(6)
#define DEC_DUALEDGE_EN BIT(5)
#define SW_PROGRESS_EN BIT(4)
#define SW_YC_SWAP BIT(3)
#define SW_CAP_EN_ASYNC BIT(1)
#define SW_CAP_EN_PSYNC BIT(0)
#define GRF_RGB_DEC_CON1 0x0044
#define SW_SET_X_MASK GENMASK(28, 16)
#define SW_SET_X(x) HIWORD_UPDATE(x, 28, 16)
#define SW_SET_Y_MASK GENMASK(28, 16)
#define SW_SET_Y(x) HIWORD_UPDATE(x, 28, 16)
#define GRF_RGB_DEC_CON2 0x0048
#define GRF_RGB_ENC_CON 0x004c
#define BT1120_UV_SWAP(x) HIWORD_UPDATE(x, 5, 5)
#define ENC_DUALEDGE_EN(x) HIWORD_UPDATE(x, 3, 3)
#define GRF_MIPI_LANE_DELAY_CON0 0x0050
#define GRF_MIPI_LANE_DELAY_CON1 0x0054
#define GRF_BT1120_DCLK_DELAY_CON0 0x0058
#define GRF_BT1120_DCLK_DELAY_CON1 0x005c
#define GRF_MIPI_TX0_CON 0x0060
#define DPIUPDATECFG BIT(26)
#define DPICOLORM BIT(25)
#define DPISHUTDN BIT(24)
#define CSI_PHYRSTZ BIT(21)
#define CSI_PHYSHUTDOWNZ BIT(20)
#define FORCETXSTOPMODE_MASK GENMASK(19, 16)
#define FORCETXSTOPMODE(x) UPDATE(x, 19, 16)
#define FORCERXMODE_MASK GENMASK(15, 12)
#define FORCERXMODE(x) UPDATE(x, 15, 12)
#define PHY_TESTCLR BIT(10)
#define PHY_TESTCLK BIT(9)
#define PHY_TESTEN BIT(8)
#define PHY_TESTDIN_MASK GENMASK(7, 0)
#define PHY_TESTDIN(x) UPDATE(x, 7, 0)
#define GRF_DPHY0_STATUS 0x0064
#define DPHY_PHYLOCK BIT(24)
#define PHY_TESTDOUT_SHIFT 8
#define GRF_MIPI_TX1_CON 0x0068
#define GRF_DPHY1_STATUS 0x006c
#define GRF_GPIO0AB_SEL_CON 0x0070
#define GRF_GPIO1AB_SEL_CON 0x0074
#define GRF_GPIO2AB_SEL_CON 0x0078
#define GRF_GPIO2C_SEL_CON 0x007c
#define GRF_GPIO3AB_SEL_CON 0x0080
#define GRF_GPIO2A_SMT 0x0090
#define GRF_GPIO2B_SMT 0x0094
#define GRF_GPIO2C_SMT 0x0098
#define GRF_GPIO3AB_SMT 0x009c
#define GRF_GPIO0A_P_CON 0x00a0
#define GRF_GPIO1A_P_CON 0x00a4
#define GRF_GPIO2A_P_CON 0x00a8
#define GRF_GPIO2B_P_CON 0x00ac
#define GRF_GPIO2C_P_CON 0x00b0
#define GRF_GPIO3A_P_CON 0x00b4
#define GRF_GPIO3B_P_CON 0x00b8
#define GRF_GPIO0B_D_CON 0x00c0
#define GRF_GPIO1B_D_CON 0x00c4
#define GRF_GPIO2A_D0_CON 0x00c8
#define GRF_GPIO2A_D1_CON 0x00cc
#define GRF_GPIO2B_D0_CON 0x00d0
#define GRF_GPIO2B_D1_CON 0x00d4
#define GRF_GPIO2C_D0_CON 0x00d8
#define GRF_GPIO2C_D1_CON 0x00dc
#define GRF_GPIO3A_D0_CON 0x00e0
#define GRF_GPIO3A_D1_CON 0x00e4
#define GRF_GPIO3B_D_CON 0x00e8
#define GRF_GPIO_SR_CON 0x00ec
#define GRF_INTR0_EN 0x0100
#define GRF_INTR0_CLR_EN 0x0104
#define GRF_INTR0_STATUS 0x0108
#define GRF_INTR0_RAW_STATUS 0x010c
#define GRF_INTR1_EN 0x0110
#define GRF_INTR1_CLR_EN 0x0114
#define GRF_INTR1_STATUS 0x0118
#define GRF_INTR1_RAW_STATUS 0x011c
#define GRF_SYSTEM_STATUS0 0x0120
/* 0: i2c mode and mcu mode; 1: i2c mode only */
#define I2C_ONLY_FLAG BIT(6)
#define GRF_SYSTEM_STATUS3 0x012c
#define GRF_SYSTEM_STATUS4 0x0130
#define GRF_OS_REG0 0x0140
#define GRF_OS_REG1 0x0144
#define GRF_OS_REG2 0x0148
#define GRF_OS_REG3 0x014c
#define GRF_SOC_VERSION 0x0150
#define GRF_MAX_REGISTER GRF_SOC_VERSION
#define DRM_MODE_FLAG_PHSYNC (1<<0)
#define DRM_MODE_FLAG_NHSYNC (1<<1)
#define DRM_MODE_FLAG_PVSYNC (1<<2)
#define DRM_MODE_FLAG_NVSYNC (1<<3)
enum {
COMBTXPHY_MODULEA_EN = BIT(0),
COMBTXPHY_MODULEB_EN = BIT(1),
};
enum {
RK628_DEV_GRF,
RK628_DEV_COMBRXPHY,
RK628_DEV_HDMIRX = 3,
RK628_DEV_CSI,
RK628_DEV_DSI0,
RK628_DEV_DSI1,
RK628_DEV_HDMITX,
RK628_DEV_GVI,
RK628_DEV_COMBTXPHY,
RK628_DEV_ADAPTER,
RK628_DEV_EFUSE,
RK628_DEV_CRU,
RK628_DEV_GPIO0,
RK628_DEV_GPIO1,
RK628_DEV_GPIO2,
RK628_DEV_GPIO3,
RK628_DEV_MAX,
};
enum rk628_input_mode {
INPUT_MODE_HDMI,
INPUT_MODE_BT1120 = 2,
INPUT_MODE_RGB,
INPUT_MODE_YUV,
};
enum rk628_output_mode {
OUTPUT_MODE_GVI = 1,
OUTPUT_MODE_LVDS,
OUTPUT_MODE_HDMI,
OUTPUT_MODE_CSI,
OUTPUT_MODE_DSI,
OUTPUT_MODE_BT1120 = 8,
OUTPUT_MODE_RGB = 16,
OUTPUT_MODE_YUV = 24,
};
enum phy_mode {
PHY_MODE_INVALID,
PHY_MODE_VIDEO_MIPI,
PHY_MODE_VIDEO_LVDS,
PHY_MODE_VIDEO_GVI,
};
enum lvds_format {
LVDS_FORMAT_VESA_24BIT,
LVDS_FORMAT_JEIDA_24BIT,
LVDS_FORMAT_JEIDA_18BIT,
LVDS_FORMAT_VESA_18BIT,
};
enum lvds_link_type {
LVDS_SINGLE_LINK,
LVDS_DUAL_LINK_ODD_EVEN_PIXELS,
LVDS_DUAL_LINK_EVEN_ODD_PIXELS,
LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS,
LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS,
};
enum gvi_color_depth {
COLOR_DEPTH_RGB_YUV444_18BIT,
COLOR_DEPTH_RGB_YUV444_24BIT,
COLOR_DEPTH_RGB_YUV444_30BIT,
COLOR_DEPTH_YUV422_16BIT = 8,
COLOR_DEPTH_YUV422_20BIT,
};
enum dsi_mode_flags {
MIPI_DSI_MODE_VIDEO = 1,
MIPI_DSI_MODE_VIDEO_BURST = 2,
MIPI_DSI_MODE_VIDEO_SYNC_PULSE = 4,
MIPI_DSI_MODE_VIDEO_HFP = 8,
MIPI_DSI_MODE_VIDEO_HBP = 16,
MIPI_DSI_MODE_EOT_PACKET = 32,
MIPI_DSI_CLOCK_NON_CONTINUOUS = 64,
MIPI_DSI_MODE_LPM = 128,
};
enum dsi_bus_format {
MIPI_DSI_FMT_RGB888,
MIPI_DSI_FMT_RGB666,
MIPI_DSI_FMT_RGB666_PACKED,
MIPI_DSI_FMT_RGB565,
};
enum gvi_bus_format {
GVI_MEDIA_BUS_FMT_RGB666_1X18 = 9,
GVI_MEDIA_BUS_FMT_RGB888_1X24 = 10,
GVI_MEDIA_BUS_FMT_YUYV10_1X20 = 13,
GVI_MEDIA_BUS_FMT_YUYV8_1X16 = 17,
GVI_MEDIA_BUS_FMT_RGB101010_1X30 = 24,
};
enum bus_format {
BUS_FMT_RGB = 0,
BUS_FMT_YUV422 = 1,
BUS_FMT_YUV444 = 2,
BUS_FMT_YUV420 = 3,
BUS_FMT_UNKNOWN,
};
enum rk628_mode_sync_pol {
MODE_FLAG_NSYNC,
MODE_FLAG_PSYNC,
};
#undef BT1120_DUAL_EDGE
struct rk628_videomode {
u32 pixelclock; /* pixelclock in Hz */
u32 hactive;
u32 hfront_porch;
u32 hback_porch;
u32 hsync_len;
u32 vactive;
u32 vfront_porch;
u32 vback_porch;
u32 vsync_len;
unsigned int flags; /* display flags */
};
struct rk628_display_mode {
int clock; /* in kHz */
int hdisplay;
int hsync_start;
int hsync_end;
int htotal;
int vdisplay;
int vsync_start;
int vsync_end;
int vtotal;
unsigned int flags;
};
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 panel_simple {
struct backlight_device *backlight;
struct regulator *supply;
struct gpio_desc *enable_gpio;
struct gpio_desc *reset_gpio;
struct panel_cmds *on_cmds;
struct panel_cmds *off_cmds;
};
struct rk628_dsi {
int bpp; /* 24/18/16*/
enum dsi_bus_format bus_format;
enum dsi_mode_flags mode_flags;
bool slave;
bool master;
uint8_t channel;
uint8_t lanes;
uint8_t id; /* 0:dsi0 1:dsi1 */
struct rk628 *rk628;
};
struct rk628_lvds {
enum lvds_format format;
enum lvds_link_type link_type;
};
struct rk628_gvi {
enum gvi_bus_format bus_format;
enum gvi_color_depth color_depth;
uint8_t lanes;
bool division_mode;
bool frm_rst;
u8 byte_mode;
};
struct rk628_combtxphy {
enum phy_mode mode;
unsigned int flags;
u8 ref_div;
u8 fb_div;
u16 frac_div;
u8 rate_div;
u32 bus_width;
bool division_mode;
};
struct rk628 {
struct device *dev;
struct i2c_client *client;
struct regmap *regmap[RK628_DEV_MAX];
struct gpio_desc *reset_gpio;
struct gpio_desc *enable_gpio;
struct gpio_desc *plugin_det_gpio;
int plugin_irq;
int hdmirx_irq;
struct clk *soc_24M;
struct workqueue_struct *monitor_wq;
struct delayed_work delay_work;
struct workqueue_struct *dsi_wq;
struct delayed_work dsi_delay_work;
struct panel_simple *panel;
void *hdmirx;
bool display_enabled;
enum rk628_input_mode input_mode;
enum rk628_output_mode output_mode;
struct rk628_display_mode src_mode;
struct rk628_display_mode dst_mode;
enum bus_format input_fmt;
enum bus_format output_fmt;
struct rk628_dsi dsi0;
struct rk628_dsi dsi1;
struct rk628_lvds lvds;
struct rk628_gvi gvi;
struct rk628_combtxphy combtxphy;
int sync_pol;
void *csi;
};
static inline int rk628_i2c_write(struct rk628 *rk628, u32 reg, u32 val)
{
int region = (reg >> 16) & 0xff;
int ret = 0;
ret = regmap_write(rk628->regmap[region], reg, val);
if (ret < 0)
pr_info("%s: i2c err reg=0x%x, val=0x%x, ret=%d\n", __func__, reg, val, ret);
return ret;
}
static inline int rk628_i2c_read(struct rk628 *rk628, u32 reg, u32 *val)
{
int region = (reg >> 16) & 0xff;
int ret = 0;
ret = regmap_read(rk628->regmap[region], reg, val);
if (ret < 0)
pr_info("%s: i2c err reg=0x%x, val=0x%x ret=%d\n", __func__, reg, *val, ret);
return ret;
}
static inline int rk628_i2c_update_bits(struct rk628 *rk628, u32 reg, u32 mask,
u32 val)
{
int region = (reg >> 16) & 0xff;
return regmap_update_bits(rk628->regmap[region], reg, mask, val);
}
#include "rk628_grf.h"
#include "rk628_gpio.h"
#include "rk628_pinctrl.h"
#endif

View File

@@ -0,0 +1,567 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Shunqing Chen <csq@rock-chisp.com>
*/
#include "rk628.h"
#include "rk628_combrxphy.h"
#define MAX_ROUND 6
#define MAX_DATA_NUM 16
#define MAX_CHANNEL 3
#define CLK_DET_TRY_TIMES 10
#define CHECK_CNT 100
#define CLK_STABLE_LOOP_CNT 10
#define CLK_STABLE_THRESHOLD 6
static int rk628_combrxphy_try_clk_detect(struct rk628 *rk628)
{
u32 val, i;
int ret;
ret = -1;
/* step1: set pin_rst_n to 1b0.wait 1 period(1us).release reset */
/* step2: select pll clock src and enable auto check */
rk628_i2c_read(rk628, COMBRX_REG(0x6630), &val);
/* clear bit0 and bit3 */
val = val & 0xfffffff6;
rk628_i2c_write(rk628, COMBRX_REG(0x6630), val);
/*
* step3: select hdmi mode and enable chip, read reg6654,
* make sure auto setup done.
*/
/* auto fsm reset related */
rk628_i2c_read(rk628, COMBRX_REG(0x6630), &val);
val = val | BIT(24);
rk628_i2c_write(rk628, COMBRX_REG(0x6630), val);
/* pull down ana rstn */
rk628_i2c_read(rk628, COMBRX_REG(0x66f0), &val);
val = val & 0xfffffeff;
rk628_i2c_write(rk628, COMBRX_REG(0x66f0), val);
/* pull down dig rstn */
rk628_i2c_read(rk628, COMBRX_REG(0x66f4), &val);
val = val & 0xfffffffe;
rk628_i2c_write(rk628, COMBRX_REG(0x66f4), val);
/* pull up ana rstn */
rk628_i2c_read(rk628, COMBRX_REG(0x66f0), &val);
val = val | 0x100;
rk628_i2c_write(rk628, COMBRX_REG(0x66f0), val);
/* pull up dig rstn */
rk628_i2c_read(rk628, COMBRX_REG(0x66f4), &val);
val = val | 0x1;
rk628_i2c_write(rk628, COMBRX_REG(0x66f4), val);
rk628_i2c_read(rk628, COMBRX_REG(0x66f0), &val);
/* set bit0 and bit2 to 1*/
val = (val & 0xfffffff8) | 0x5;
rk628_i2c_write(rk628, COMBRX_REG(0x66f0), val);
/* auto fsm en = 0 */
rk628_i2c_read(rk628, COMBRX_REG(0x66f0), &val);
/* set bit0 and bit2 to 1*/
val = (val & 0xfffffff8) | 0x4;
rk628_i2c_write(rk628, COMBRX_REG(0x66f0), val);
for (i = 0; i < 10; i++) {
mdelay(1);
rk628_i2c_read(rk628, COMBRX_REG(0x6654), &val);
if ((val & 0xf0000000) == 0x80000000) {
ret = 0;
dev_info(rk628->dev, "clock detected!\n");
break;
}
}
return ret;
}
static void rk628_combrxphy_get_data_of_round(struct rk628 *rk628,
u32 *data)
{
u32 i;
for (i = 0; i < MAX_DATA_NUM; i++)
rk628_i2c_read(rk628, COMBRX_REG(0x6740 + i * 4), &data[i]);
}
static void rk628_combrxphy_set_dc_gain(struct rk628 *rk628,
u32 x, u32 y, u32 z)
{
u32 val;
u32 dc_gain_ch0, dc_gain_ch1, dc_gain_ch2;
dc_gain_ch0 = x & 0xf;
dc_gain_ch1 = y & 0xf;
dc_gain_ch2 = z & 0xf;
rk628_i2c_read(rk628, COMBRX_REG(0x661c), &val);
val = (val & 0xff0f0f0f) | (dc_gain_ch0 << 20) | (dc_gain_ch1 << 12) |
(dc_gain_ch2 << 4);
rk628_i2c_write(rk628, COMBRX_REG(0x661c), val);
}
static void rk628_combrxphy_set_data_of_round(u32 *data, u32 *data_in)
{
if ((data != NULL) && (data_in != NULL)) {
data_in[0] = data[0];
data_in[1] = data[7];
data_in[2] = data[13];
data_in[3] = data[14];
data_in[4] = data[15];
data_in[5] = data[1];
data_in[6] = data[2];
data_in[7] = data[3];
data_in[8] = data[4];
data_in[9] = data[5];
data_in[10] = data[6];
data_in[11] = data[8];
data_in[12] = data[9];
data_in[13] = data[10];
data_in[14] = data[11];
data_in[15] = data[12];
}
}
static void
rk628_combrxphy_max_zero_of_round(struct rk628 *rk628,
u32 *data_in, u32 *max_zero,
u32 *max_val, int n, int ch)
{
u32 i;
u32 cnt = 0;
u32 max_cnt = 0;
u32 max_v = 0;
for (i = 0; i < MAX_DATA_NUM; i++) {
if (max_v < data_in[i])
max_v = data_in[i];
}
for (i = 0; i < MAX_DATA_NUM; i++) {
if (data_in[i] == 0)
cnt = cnt + 200;
else if ((data_in[i] > 0) && (data_in[i] < 100))
cnt = cnt + 100 - data_in[i];
}
max_cnt = (cnt >= 3200) ? 0 : cnt;
max_zero[n] = max_cnt;
max_val[n] = max_v;
dev_info(rk628->dev, "channel:%d, round:%d, max_zero_cnt:%d, max_val:%#x\n",
ch, n, max_zero[n], max_val[n]);
}
static int rk628_combrxphy_chose_round_for_ch(struct rk628 *rk628,
u32 *rd_max_zero,
u32 *rd_max_val, int ch)
{
int i, rd = 0;
u32 max = 0;
u32 max_v = 0;
for (i = 0; i < MAX_ROUND; i++) {
if (rd_max_zero[i] > max) {
max = rd_max_zero[i];
max_v = rd_max_val[i];
rd = i;
} else if (rd_max_zero[i] == max && rd_max_val[i] > max_v) {
max = rd_max_zero[i];
max_v = rd_max_val[i];
rd = i;
}
}
dev_info(rk628->dev, "%s channel:%d, rd:%d\n", __func__, ch, rd);
return rd;
}
static void rk628_combrxphy_set_sample_edge_round(struct rk628 *rk628,
u32 x, u32 y, u32 z)
{
u32 val;
u32 equ_gain_ch0, equ_gain_ch1, equ_gain_ch2;
equ_gain_ch0 = (x & 0xf);
equ_gain_ch1 = (y & 0xf);
equ_gain_ch2 = (z & 0xf);
rk628_i2c_read(rk628, COMBRX_REG(0x6618), &val);
val = (val & 0xff00f0ff) | (equ_gain_ch1 << 20) |
(equ_gain_ch0 << 16) | (equ_gain_ch2 << 8);
rk628_i2c_write(rk628, COMBRX_REG(0x6618), val);
}
static void rk628_combrxphy_start_sample_edge(struct rk628 *rk628)
{
u32 val;
rk628_i2c_read(rk628, COMBRX_REG(0x66f0), &val);
val &= 0xfffff1ff;
rk628_i2c_write(rk628, COMBRX_REG(0x66f0), val);
rk628_i2c_read(rk628, COMBRX_REG(0x66f0), &val);
val = (val & 0xfffff1ff) | (0x7 << 9);
rk628_i2c_write(rk628, COMBRX_REG(0x66f0), val);
}
static void rk628_combrxphy_set_sample_edge_mode(struct rk628 *rk628, int ch)
{
u32 val;
rk628_i2c_read(rk628, COMBRX_REG(0x6634), &val);
val = val & (~(0xf << ((ch + 1) * 4)));
rk628_i2c_write(rk628, COMBRX_REG(0x6634), val);
}
static void rk628_combrxphy_select_channel(struct rk628 *rk628, int ch)
{
u32 val;
rk628_i2c_read(rk628, COMBRX_REG(0x6700), &val);
val = (val & 0xfffffffc) | (ch & 0x3);
rk628_i2c_write(rk628, COMBRX_REG(0x6700), val);
}
static void rk628_combrxphy_cfg_6730(struct rk628 *rk628)
{
u32 val;
rk628_i2c_read(rk628, COMBRX_REG(0x6730), &val);
val = (val & 0xffff0000) | 0x1;
rk628_i2c_write(rk628, COMBRX_REG(0x6730), val);
}
static void rk628_combrxphy_sample_edge_procedure_for_cable(struct rk628 *rk628,
u32 cdr_mode)
{
u32 n, ch;
u32 data[MAX_DATA_NUM];
u32 data_in[MAX_DATA_NUM];
u32 round_max_zero[MAX_CHANNEL][MAX_ROUND];
u32 round_max_value[MAX_CHANNEL][MAX_ROUND];
u32 ch_round[MAX_CHANNEL];
u32 edge, dc_gain;
u32 rd_offset;
/* Step1: set sample edge mode for channel 0~2 */
for (ch = 0; ch < MAX_CHANNEL; ch++)
rk628_combrxphy_set_sample_edge_mode(rk628, ch);
/* step2: once per round */
for (ch = 0; ch < MAX_CHANNEL; ch++) {
rk628_combrxphy_select_channel(rk628, ch);
rk628_combrxphy_cfg_6730(rk628);
}
/*
* step3: config sample edge until the end of one frame
* (for example 1080p:2200*1125=32h25c3f8)
*/
if (cdr_mode < 16) {
dc_gain = 0;
rd_offset = 0;
} else if (cdr_mode < 18) {
dc_gain = 1;
rd_offset = 0;
} else {
dc_gain = 3;
rd_offset = 2;
}
/*
* When the pix clk is the same, the low frame rate resolution is used
* to calculate the sampling window (the frame rate is not less than
* 30). The sampling delay time is configured as 40ms.
*/
if (cdr_mode <= 1) { /* 27M vic17 720x576P50 */
edge = 864 * 625;
} else if (cdr_mode <= 4) { /* 59.4M vic81 1680x720P30 */
edge = 2640 * 750;
} else if (cdr_mode <= 7) { /* 74.25M vic34 1920x1080P30 */
edge = 2200 * 1125;
} else if (cdr_mode <= 14) { /* 119M vic88 2560x1180P30 */
edge = 3520 * 1125;
} else if (cdr_mode <= 16) { /* 148.5M vic31 1920x1080P50 */
edge = 2640 * 1125;
} else if (cdr_mode <= 17) { /* 162M vic89 2560x1080P50 */
edge = 3300 * 1125;
} else if (cdr_mode <= 18) { /* 297M vic95 3840x2160P30 */
edge = 4400 * 2250;
} else { /* unknown vic16 1920x1080P60 */
edge = 2200 * 1125;
}
dev_info(rk628->dev, "cdr_mode:%d, dc_gain:%d, rd_offset:%d, edge:%#x\n",
cdr_mode, dc_gain, rd_offset, edge);
for (ch = 0; ch < MAX_CHANNEL; ch++) {
rk628_combrxphy_select_channel(rk628, ch);
rk628_i2c_write(rk628, COMBRX_REG(0x6708), edge);
}
rk628_combrxphy_set_dc_gain(rk628, dc_gain, dc_gain, dc_gain);
for (n = rd_offset; n < (rd_offset + MAX_ROUND); n++) {
/* step4:set sample edge round value n,n=0(n=0~31) */
rk628_combrxphy_set_sample_edge_round(rk628, n, n, n);
/* step5:start sample edge */
rk628_combrxphy_start_sample_edge(rk628);
/* step6:waiting more than one frame time */
mdelay(41);
for (ch = 0; ch < MAX_CHANNEL; ch++) {
/* step7: get data of round n */
rk628_combrxphy_select_channel(rk628, ch);
rk628_combrxphy_get_data_of_round(rk628, data);
rk628_combrxphy_set_data_of_round(data, data_in);
/* step8: get the max constant value of round n */
rk628_combrxphy_max_zero_of_round(rk628, data_in,
round_max_zero[ch], round_max_value[ch],
n - rd_offset, ch);
}
}
/*
* step9: after finish round, get the max constant value and
* corresponding value n.
*/
for (ch = 0; ch < MAX_CHANNEL; ch++) {
ch_round[ch] = rk628_combrxphy_chose_round_for_ch(rk628, round_max_zero[ch],
round_max_value[ch], ch);
ch_round[ch] += rd_offset;
}
dev_info(rk628->dev, "last equ gain ch0:%d, ch1:%d, ch2:%d\n",
ch_round[0], ch_round[1], ch_round[2]);
/* step10: write result to sample edge round value */
rk628_combrxphy_set_sample_edge_round(rk628, ch_round[0], ch_round[1], ch_round[2]);
/* do step5, step6 again */
/* step5:start sample edge */
rk628_combrxphy_start_sample_edge(rk628);
/* step6:waiting more than one frame time */
mdelay(41);
}
static int rk628_combrxphy_set_hdmi_mode_for_cable(struct rk628 *rk628, int f)
{
u32 val, val_a, val_b, data_a, data_b;
u32 i, j, count, ret;
u32 cdr_mode, cdr_data, pll_man;
u32 tmds_bitrate_per_lane;
u32 cdr_data_min, cdr_data_max;
u32 state, channel_st;
bool is_yuv420;
/*
* use the mode of automatic clock detection, only supports fixed TMDS
* frequency.Refer to register 0x6654[21:16]:
* 5'd31:Error mode
* 5'd30:manual mode detected
* 5'd18:rx3p clock = 297MHz
* 5'd17:rx3p clock = 162MHz
* 5'd16:rx3p clock = 148.5MHz
* 5'd15:rx3p clock = 135MHz
* 5'd14:rx3p clock = 119MHz
* 5'd13:rx3p clock = 108MHz
* 5'd12:rx3p clock = 101MHz
* 5'd11:rx3p clock = 92.8125MHz
* 5'd10:rx3p clock = 88.75MHz
* 5'd9:rx3p clock = 85.5MHz
* 5'd8:rx3p clock = 83.5MHz
* 5'd7:rx3p clock = 74.25MHz
* 5'd6:rx3p clock = 68.25MHz
* 5'd5:rx3p clock = 65MHz
* 5'd4:rx3p clock = 59.4MHz
* 5'd3:rx3p clock = 40MHz
* 5'd2:rx3p clock = 33.75MHz
* 5'd1:rx3p clock = 27MHz
* 5'd0:rx3p clock = 25.17MHz
*/
const u32 cdr_mode_to_khz[] = {
25170, 27000, 33750, 40000, 59400, 65000, 68250,
74250, 83500, 85500, 88750, 92812, 101000, 108000,
119000, 135000, 148500, 162000, 297000,
};
for (i = 0; i < CLK_DET_TRY_TIMES; i++) {
if (rk628_combrxphy_try_clk_detect(rk628) >= 0)
break;
mdelay(1);
}
rk628_i2c_read(rk628, COMBRX_REG(0x6654), &val);
dev_info(rk628->dev, "clk det over cnt:%d, reg_0x6654:%#x\n", i, val);
state = (val >> 28) & 0xf;
if (state == 5) {
dev_info(rk628->dev, "Clock detection anomaly\n");
} else if (state == 4) {
channel_st = (val >> 21) & 0x7f;
dev_info(rk628->dev, "%s%s%s%s%s%s%s%s level detection anomaly\n",
channel_st & 0x40 ? "|clk_p|" : "",
channel_st & 0x20 ? "|clk_n|" : "",
channel_st & 0x10 ? "|d0_p|" : "",
channel_st & 0x08 ? "|d0_n|" : "",
channel_st & 0x04 ? "|d1_p|" : "",
channel_st & 0x02 ? "|d1_n|" : "",
channel_st & 0x01 ? "|d2_p|" : "",
channel_st ? "" : "|d2_n|");
}
rk628_i2c_read(rk628, COMBRX_REG(0x6620), &val);
if ((i == CLK_DET_TRY_TIMES) ||
((val & 0x7f000000) == 0) ||
((val & 0x007f0000) == 0) ||
((val & 0x00007f00) == 0) ||
((val & 0x0000007f) == 0)) {
dev_info(rk628->dev, "clock detected failed, cfg resistance manual!\n");
rk628_i2c_write(rk628, COMBRX_REG(0x6620), 0x66666666);
rk628_i2c_update_bits(rk628, COMBRX_REG(0x6604), BIT(31), BIT(31));
mdelay(1);
}
/* step4: get cdr_mode and cdr_data */
for (j = 0; j < CLK_STABLE_LOOP_CNT ; j++) {
cdr_data_min = 0xffffffff;
cdr_data_max = 0;
for (i = 0; i < CLK_DET_TRY_TIMES; i++) {
rk628_i2c_read(rk628, COMBRX_REG(0x6654), &val);
cdr_data = val & 0xffff;
if (cdr_data <= cdr_data_min)
cdr_data_min = cdr_data;
if (cdr_data >= cdr_data_max)
cdr_data_max = cdr_data;
udelay(50);
}
if (((cdr_data_max - cdr_data_min) <= CLK_STABLE_THRESHOLD) &&
(cdr_data_min >= 60)) {
dev_info(rk628->dev, "clock stable!");
break;
}
}
if (j == CLK_STABLE_LOOP_CNT) {
rk628_i2c_read(rk628, COMBRX_REG(0x6630), &val_a);
rk628_i2c_read(rk628, COMBRX_REG(0x6608), &val_b);
dev_err(rk628->dev,
"clk not stable, reg_0x6630:%#x, reg_0x6608:%#x",
val_a, val_b);
/* bypass level detection anomaly */
if (state == 4)
rk628_i2c_update_bits(rk628, COMBRX_REG(0x6628), BIT(31), BIT(31));
else
return -EINVAL;
}
rk628_i2c_read(rk628, COMBRX_REG(0x6654), &val);
if ((val & 0x1f0000) == 0x1f0000) {
rk628_i2c_read(rk628, COMBRX_REG(0x6630), &val_a);
rk628_i2c_read(rk628, COMBRX_REG(0x6608), &val_b);
dev_err(rk628->dev,
"clock error: 0x1f, reg_0x6630:%#x, reg_0x6608:%#x",
val_a, val_b);
return -EINVAL;
}
cdr_mode = (val >> 16) & 0x1f;
cdr_data = val & 0xffff;
dev_info(rk628->dev, "cdr_mode:%d, cdr_data:%d\n", cdr_mode, cdr_data);
f = f & 0x7fffffff;
is_yuv420 = (f & BIT(30)) ? true : false;
f = f & 0xffffff;
dev_info(rk628->dev, "f:%d\n", f);
/*
* step5: manually configure PLL
* cfg reg 66a8 tmds clock div2 for rgb/yuv444 as default
* reg 662c[16:8] pll_pre_div
*/
if (f <= 340000) {
rk628_i2c_write(rk628, COMBRX_REG(0x662c), 0x01000500);
if (is_yuv420)
rk628_i2c_write(rk628, COMBRX_REG(0x66a8), 0x0000c000);
else
rk628_i2c_write(rk628, COMBRX_REG(0x66a8), 0x0000c600);
} else {
rk628_i2c_write(rk628, COMBRX_REG(0x662c), 0x01001400);
rk628_i2c_write(rk628, COMBRX_REG(0x66a8), 0x0000c600);
}
/* when tmds bitrate/lane <= 340M, bitrate/lane = pix_clk * 10 */
tmds_bitrate_per_lane = cdr_mode_to_khz[cdr_mode] * 10;
if (tmds_bitrate_per_lane < 400000)
pll_man = 0x7960c;
else if (tmds_bitrate_per_lane < 600000)
pll_man = 0x7750c;
else if (tmds_bitrate_per_lane < 800000)
pll_man = 0x7964c;
else if (tmds_bitrate_per_lane < 1000000)
pll_man = 0x7754c;
else if (tmds_bitrate_per_lane < 1600000)
pll_man = 0x7a108;
else if (tmds_bitrate_per_lane < 2400000)
pll_man = 0x73588;
else if (tmds_bitrate_per_lane < 3400000)
pll_man = 0x7a108;
else
pll_man = 0x7f0c8;
dev_info(rk628->dev, "cdr_mode:%d, pll_man:%#x\n", cdr_mode, pll_man);
rk628_i2c_write(rk628, COMBRX_REG(0x6630), pll_man);
/* step6: EQ and SAMPLE cfg */
rk628_combrxphy_sample_edge_procedure_for_cable(rk628, cdr_mode);
/* step7: Deassert fifo reset,enable fifo write and read */
/* reset rx_infifo */
rk628_i2c_write(rk628, COMBRX_REG(0x66a0), 0x00000003);
/* rx_infofo wr/rd disable */
rk628_i2c_write(rk628, COMBRX_REG(0x66b0), 0x00080060);
/* deassert rx_infifo reset */
rk628_i2c_write(rk628, COMBRX_REG(0x66a0), 0x00000083);
/* enable rx_infofo wr/rd en */
rk628_i2c_write(rk628, COMBRX_REG(0x66b0), 0x00380060);
/* cfg 0x2260 high_8b to 0x66ac high_8b, low_8b to 0x66b0 low_8b */
rk628_i2c_update_bits(rk628, COMBRX_REG(0x66ac),
GENMASK(31, 24), UPDATE(0x22, 31, 24));
mdelay(6);
/* step8: check all 3 data channels alignment */
count = 0;
for (i = 0; i < CHECK_CNT; i++) {
mdelay(1);
rk628_i2c_read(rk628, COMBRX_REG(0x66b4), &data_a);
rk628_i2c_read(rk628, COMBRX_REG(0x66b8), &data_b);
/* ch0 ch1 ch2 lock */
if (((data_a & 0x00ff00ff) == 0x00ff00ff) &&
((data_b & 0xff) == 0xff)) {
count++;
}
}
if (count >= CHECK_CNT) {
dev_info(rk628->dev, "channel alignment done\n");
dev_info(rk628->dev, "rx initial done\n");
ret = 0;
} else if (count > 0) {
dev_info(rk628->dev, "link not stable, count:%d of 100\n", count);
ret = 0;
} else {
dev_err(rk628->dev, "channel alignment failed!\n");
ret = -EINVAL;
}
return ret;
}
int rk628_combrxphy_power_on(struct rk628 *rk628, int f)
{
return rk628_combrxphy_set_hdmi_mode_for_cable(rk628, f);
}
int rk628_combrxphy_power_off(struct rk628 *rk628)
{
return 0;
}

View File

@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Chen Shunqing <csq@rock-chips.com>
*/
#ifndef COMBRXPHY_H
#define COMBRXPHY_H
#define COMBRX_REG(x) ((x) + 0x10000)
int rk628_combrxphy_power_on(struct rk628 *rk628, int f);
int rk628_combrxphy_power_off(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,309 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include "rk628.h"
#include "rk628_combtxphy.h"
#include "rk628_cru.h"
static void rk628_combtxphy_dsi_power_on(struct rk628 *rk628)
{
struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
u32 val;
int ret;
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_BUS_WIDTH_MASK |
SW_GVI_LVDS_EN_MASK | SW_MIPI_DSI_EN_MASK,
SW_BUS_WIDTH_8BIT | SW_MIPI_DSI_EN);
if (combtxphy->flags & COMBTXPHY_MODULEA_EN)
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_MODULEA_EN_MASK, SW_MODULEA_EN);
if (combtxphy->flags & COMBTXPHY_MODULEB_EN)
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_MODULEB_EN_MASK, SW_MODULEB_EN);
rk628_i2c_write(rk628, COMBTXPHY_CON5,
SW_REF_DIV(combtxphy->ref_div - 1) |
SW_PLL_FB_DIV(combtxphy->fb_div) |
SW_PLL_FRAC_DIV(combtxphy->frac_div) |
SW_RATE(combtxphy->rate_div / 2));
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_PD_PLL, 0);
ret = regmap_read_poll_timeout(rk628->regmap[RK628_DEV_GRF],
GRF_DPHY0_STATUS, val,
val & DPHY_PHYLOCK, 0, 1000);
if (ret < 0)
dev_err(rk628->dev, "phy is not lock\n");
rk628_i2c_update_bits(rk628, COMBTXPHY_CON9,
SW_DSI_FSET_EN_MASK | SW_DSI_RCAL_EN_MASK,
SW_DSI_FSET_EN | SW_DSI_RCAL_EN);
usleep_range(200, 400);
}
static void rk628_combtxphy_lvds_power_on(struct rk628 *rk628)
{
struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
u32 val;
int ret;
/* Adjust terminal resistance 133 ohm, bypass 0.95v ldo for driver. */
rk628_i2c_update_bits(rk628, COMBTXPHY_CON7,
SW_TX_RTERM_MASK | SW_TX_MODE_MASK |
BYPASS_095V_LDO_MASK | TX_COM_VOLT_ADJ_MASK,
SW_TX_RTERM(6) | SW_TX_MODE(3) |
BYPASS_095V_LDO(1) | TX_COM_VOLT_ADJ(0));
rk628_i2c_write(rk628, COMBTXPHY_CON10, TX7_CKDRV_EN | TX2_CKDRV_EN);
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
SW_MIPI_DSI_EN_MASK,
SW_BUS_WIDTH_7BIT | SW_GVI_LVDS_EN);
if (combtxphy->flags & COMBTXPHY_MODULEA_EN)
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_MODULEA_EN_MASK, SW_MODULEA_EN);
if (combtxphy->flags & COMBTXPHY_MODULEB_EN)
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_MODULEB_EN_MASK, SW_MODULEB_EN);
rk628_i2c_write(rk628, COMBTXPHY_CON5,
SW_REF_DIV(combtxphy->ref_div - 1) |
SW_PLL_FB_DIV(combtxphy->fb_div) |
SW_PLL_FRAC_DIV(combtxphy->frac_div) |
SW_RATE(combtxphy->rate_div / 2));
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_PD_PLL, 0);
ret = regmap_read_poll_timeout(rk628->regmap[RK628_DEV_GRF],
GRF_DPHY0_STATUS, val,
val & DPHY_PHYLOCK, 0, 1000);
if (ret < 0)
dev_err(rk628->dev, "phy is not lock\n");
usleep_range(100, 200);
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_TX_IDLE_MASK | SW_TX_PD_MASK, 0);
}
static void rk628_combtxphy_gvi_power_on(struct rk628 *rk628)
{
struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
int ref_div = 0;
if (combtxphy->ref_div % 2) {
ref_div = combtxphy->ref_div - 1;
} else {
ref_div = BIT(4);
ref_div |= combtxphy->ref_div / 2 - 1;
}
rk628_i2c_write(rk628, COMBTXPHY_CON5,
SW_REF_DIV(ref_div) |
SW_PLL_FB_DIV(combtxphy->fb_div) |
SW_PLL_FRAC_DIV(combtxphy->frac_div) |
SW_RATE(combtxphy->rate_div / 2));
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
SW_MIPI_DSI_EN_MASK |
SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
SW_BUS_WIDTH_10BIT | SW_GVI_LVDS_EN |
SW_MODULEB_EN | SW_MODULEA_EN);
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_PD_PLL | SW_TX_PD_MASK, 0);
usleep_range(100, 200);
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_TX_IDLE_MASK, 0);
}
void rk628_combtxphy_power_on(struct rk628 *rk628)
{
struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
SW_TX_IDLE_MASK | SW_TX_PD_MASK |
SW_PD_PLL_MASK, SW_TX_IDLE(0x3ff) |
SW_TX_PD(0x3ff) | SW_PD_PLL);
switch (combtxphy->mode) {
case PHY_MODE_VIDEO_MIPI:
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_TXPHY_REFCLK_SEL_MASK,
SW_TXPHY_REFCLK_SEL(0));
rk628_combtxphy_dsi_power_on(rk628);
break;
case PHY_MODE_VIDEO_LVDS:
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_TXPHY_REFCLK_SEL_MASK,
SW_TXPHY_REFCLK_SEL(1));
rk628_combtxphy_lvds_power_on(rk628);
break;
case PHY_MODE_VIDEO_GVI:
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_TXPHY_REFCLK_SEL_MASK,
SW_TXPHY_REFCLK_SEL(2));
rk628_combtxphy_gvi_power_on(rk628);
break;
default:
break;
}
}
void rk628_combtxphy_power_off(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_TX_IDLE_MASK |
SW_TX_PD_MASK | SW_PD_PLL_MASK |
SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
SW_TX_IDLE(0x3ff) | SW_TX_PD(0x3ff) | SW_PD_PLL);
}
void rk628_combtxphy_set_bus_width(struct rk628 *rk628, u32 bus_width)
{
rk628->combtxphy.bus_width = bus_width;
}
u32 rk628_combtxphy_get_bus_width(struct rk628 *rk628)
{
return rk628->combtxphy.bus_width;
}
void rk628_combtxphy_set_gvi_division_mode(struct rk628 *rk628, bool division)
{
rk628->combtxphy.division_mode = division;
}
void rk628_combtxphy_set_mode(struct rk628 *rk628, enum phy_mode mode)
{
struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
unsigned int fvco, fpfd, frac_rate, fin = 24;
switch (mode) {
case PHY_MODE_VIDEO_MIPI:
{
int bus_width = rk628_combtxphy_get_bus_width(rk628);
unsigned int fhsc = bus_width >> 8;
unsigned int flags = bus_width & 0xff;
fhsc = fin * (fhsc / fin);
if (fhsc < 80 || fhsc > 1500)
return;
else if (fhsc < 375)
combtxphy->rate_div = 4;
else if (fhsc < 750)
combtxphy->rate_div = 2;
else
combtxphy->rate_div = 1;
combtxphy->flags = flags;
fvco = fhsc * 2 * combtxphy->rate_div;
combtxphy->ref_div = 1;
combtxphy->fb_div = fvco / 8 / fin;
frac_rate = fvco - (fin * 8 * combtxphy->fb_div);
if (frac_rate) {
frac_rate <<= 10;
frac_rate /= fin * 8;
combtxphy->frac_div = frac_rate;
} else {
combtxphy->frac_div = 0;
}
fvco = fin * (1024 * combtxphy->fb_div + combtxphy->frac_div);
fvco *= 8;
fvco = DIV_ROUND_UP(fvco, 1024 * combtxphy->ref_div);
fhsc = fvco / 2 / combtxphy->rate_div;
combtxphy->bus_width = fhsc;
break;
}
case PHY_MODE_VIDEO_LVDS:
{
int bus_width = rk628_combtxphy_get_bus_width(rk628);
unsigned int flags = bus_width & 0xff;
unsigned int rate = (bus_width >> 8) * 7;
combtxphy->flags = flags;
combtxphy->ref_div = 1;
combtxphy->fb_div = 14;
combtxphy->frac_div = 0;
if (rate < 500)
combtxphy->rate_div = 4;
else if (rate < 1000)
combtxphy->rate_div = 2;
else
combtxphy->rate_div = 1;
break;
}
case PHY_MODE_VIDEO_GVI:
{
unsigned int i, delta_freq, best_delta_freq, fb_div;
unsigned int bus_width = rk628_combtxphy_get_bus_width(rk628);
unsigned long ref_clk;
unsigned long long pre_clk;
if (bus_width < 500000 || bus_width > 4000000)
return;
else if (bus_width < 1000000)
combtxphy->rate_div = 4;
else if (bus_width < 2000000)
combtxphy->rate_div = 2;
else
combtxphy->rate_div = 1;
fvco = bus_width * combtxphy->rate_div;
ref_clk = rk628_cru_clk_get_rate(rk628, CGU_SCLK_VOP) / 1000; /* khz */
if (combtxphy->division_mode)
ref_clk /= 2;
/*
* the reference clock at PFD(FPFD = ref_clk / ref_div) about
* 25MHz is recommende, FPFD must range from 16MHz to 35MHz,
* here to find the best rev_div.
*/
best_delta_freq = ref_clk;
for (i = 1; i <= 32; i++) {
fpfd = ref_clk / i;
delta_freq = abs(fpfd - 25000);
if (delta_freq < best_delta_freq) {
best_delta_freq = delta_freq;
combtxphy->ref_div = i;
}
}
/*
* ref_clk / ref_div * 8 * fb_div = FVCO
*/
pre_clk = (unsigned long long)fvco / 8 * combtxphy->ref_div * 1024;
do_div(pre_clk, ref_clk);
fb_div = pre_clk / 1024;
/*
* get the actually frequency
*/
bus_width = ref_clk / combtxphy->ref_div * 8;
bus_width *= fb_div;
bus_width /= combtxphy->rate_div;
combtxphy->frac_div = 0;
combtxphy->fb_div = fb_div;
combtxphy->bus_width = bus_width;
break;
}
default:
break;
}
combtxphy->mode = mode;
}

View File

@@ -0,0 +1,82 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#ifndef RK628_COMBTXPHY_H
#define RK628_COMBTXPHY_H
#include "rk628.h"
#define COMBTXPHY_BASE 0x90000
#define REG(x) ((x) + COMBTXPHY_BASE)
#define COMBTXPHY_CON0 REG(0x0000)
#define SW_TX_IDLE_MASK GENMASK(29, 20)
#define SW_TX_IDLE(x) UPDATE(x, 29, 20)
#define SW_TX_PD_MASK GENMASK(17, 8)
#define SW_TX_PD(x) UPDATE(x, 17, 8)
#define SW_BUS_WIDTH_MASK GENMASK(6, 5)
#define SW_BUS_WIDTH_7BIT UPDATE(0x3, 6, 5)
#define SW_BUS_WIDTH_8BIT UPDATE(0x2, 6, 5)
#define SW_BUS_WIDTH_9BIT UPDATE(0x1, 6, 5)
#define SW_BUS_WIDTH_10BIT UPDATE(0x0, 6, 5)
#define SW_PD_PLL_MASK BIT(4)
#define SW_PD_PLL BIT(4)
#define SW_GVI_LVDS_EN_MASK BIT(3)
#define SW_GVI_LVDS_EN BIT(3)
#define SW_MIPI_DSI_EN_MASK BIT(2)
#define SW_MIPI_DSI_EN BIT(2)
#define SW_MODULEB_EN_MASK BIT(1)
#define SW_MODULEB_EN BIT(1)
#define SW_MODULEA_EN_MASK BIT(0)
#define SW_MODULEA_EN BIT(0)
#define COMBTXPHY_CON1 REG(0x0004)
#define COMBTXPHY_CON2 REG(0x0008)
#define COMBTXPHY_CON3 REG(0x000c)
#define COMBTXPHY_CON4 REG(0x0010)
#define COMBTXPHY_CON5 REG(0x0014)
#define SW_RATE(x) UPDATE(x, 26, 24)
#define SW_REF_DIV(x) UPDATE(x, 20, 16)
#define SW_PLL_FB_DIV(x) UPDATE(x, 14, 10)
#define SW_PLL_FRAC_DIV(x) UPDATE(x, 9, 0)
#define COMBTXPHY_CON6 REG(0x0018)
#define COMBTXPHY_CON7 REG(0x001c)
#define SW_TX_RTERM_MASK GENMASK(22, 20)
#define SW_TX_RTERM(x) UPDATE(x, 22, 20)
#define SW_TX_MODE_MASK GENMASK(17, 16)
#define SW_TX_MODE(x) UPDATE(x, 17, 16)
#define SW_TX_CTL_CON5_MASK BIT(10)
#define SW_TX_CTL_CON5(x) UPDATE(x, 10, 10)
#define SW_TX_CTL_CON4_MASK GENMASK(9, 8)
#define SW_TX_CTL_CON4(x) UPDATE(x, 9, 8)
#define BYPASS_095V_LDO_MASK BIT(3)
#define BYPASS_095V_LDO(x) UPDATE(x, 3, 3)
#define TX_COM_VOLT_ADJ_MASK GENMASK(2, 0)
#define TX_COM_VOLT_ADJ(x) UPDATE(x, 2, 0)
#define COMBTXPHY_CON8 REG(0x0020)
#define COMBTXPHY_CON9 REG(0x0024)
#define SW_DSI_FSET_EN_MASK BIT(29)
#define SW_DSI_FSET_EN BIT(29)
#define SW_DSI_RCAL_EN_MASK BIT(28)
#define SW_DSI_RCAL_EN BIT(28)
#define COMBTXPHY_CON10 REG(0x0028)
#define TX9_CKDRV_EN BIT(9)
#define TX8_CKDRV_EN BIT(8)
#define TX7_CKDRV_EN BIT(7)
#define TX6_CKDRV_EN BIT(6)
#define TX5_CKDRV_EN BIT(5)
#define TX4_CKDRV_EN BIT(4)
#define TX3_CKDRV_EN BIT(3)
#define TX2_CKDRV_EN BIT(2)
#define TX1_CKDRV_EN BIT(1)
#define TX0_CKDRV_EN BIT(0)
void rk628_combtxphy_set_gvi_division_mode(struct rk628 *rk628, bool division);
void rk628_combtxphy_set_mode(struct rk628 *rk628, enum phy_mode mode);
void rk628_combtxphy_set_bus_width(struct rk628 *rk628, uint32_t bus_width);
uint32_t rk628_combtxphy_get_bus_width(struct rk628 *rk628);
void rk628_combtxphy_power_on(struct rk628 *rk628);
void rk628_combtxphy_power_off(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,52 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include "rk628_config.h"
struct rk628_display_mode *rk628_display_get_src_mode(struct rk628 *rk628)
{
return &rk628->src_mode;
}
struct rk628_display_mode *rk628_display_get_dst_mode(struct rk628 *rk628)
{
return &rk628->dst_mode;
}
void rk628_mode_copy(struct rk628_display_mode *to, struct rk628_display_mode *from)
{
to->clock = from->clock;
to->hdisplay = from->hdisplay;
to->hsync_start = from->hsync_start;
to->hsync_end = from->hsync_end;
to->htotal = from->htotal;
to->vdisplay = from->vdisplay;
to->vsync_start = from->vsync_start;
to->vsync_end = from->vsync_end;
to->vtotal = from->vtotal;
to->flags = from->flags;
}
void rk628_set_input_bus_format(struct rk628 *rk628, enum bus_format format)
{
rk628->input_fmt = format;
}
enum bus_format rk628_get_input_bus_format(struct rk628 *rk628)
{
return rk628->input_fmt;
}
void rk628_set_output_bus_format(struct rk628 *rk628, enum bus_format format)
{
rk628->output_fmt = format;
}
enum bus_format rk628_get_output_bus_format(struct rk628 *rk628)
{
return rk628->output_fmt;
}

View File

@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#ifndef CONFIG_H
#define CONFIG_H
#include "rk628.h"
struct rk628_display_mode *rk628_display_get_src_mode(struct rk628 *rk628);
struct rk628_display_mode *rk628_display_get_dst_mode(struct rk628 *rk628);
void rk628_mode_copy(struct rk628_display_mode *to, struct rk628_display_mode *from);
void rk628_set_input_bus_format(struct rk628 *rk628, enum bus_format format);
enum bus_format rk628_get_input_bus_format(struct rk628 *rk628);
void rk628_set_output_bus_format(struct rk628 *rk628, enum bus_format format);
enum bus_format rk628_get_output_bus_format(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,472 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#include "rk628.h"
#include "rk628_cru.h"
#define REFCLK_RATE 24000000UL
#define MIN_FREF_RATE 10000000UL
#define MAX_FREF_RATE 800000000UL
#define MIN_FREFDIV_RATE 1000000UL
#define MAX_FREFDIV_RATE 100000000UL
#define MIN_FVCO_RATE 600000000UL
#define MAX_FVCO_RATE 1600000000UL
#define MIN_FOUTPOSTDIV_RATE 12000000UL
#define MAX_FOUTPOSTDIV_RATE 1600000000UL
static void rational_best_approximation(unsigned long given_numerator,
unsigned long given_denominator,
unsigned long max_numerator,
unsigned long max_denominator,
unsigned long *best_numerator,
unsigned long *best_denominator)
{
unsigned long n, d, n0, d0, n1, d1;
n = given_numerator;
d = given_denominator;
n0 = d1 = 0;
n1 = d0 = 1;
for (;;) {
unsigned long t, a;
if ((n1 > max_numerator) || (d1 > max_denominator)) {
n1 = n0;
d1 = d0;
break;
}
if (d == 0)
break;
t = d;
a = n / d;
d = n % d;
n = t;
t = n0 + a * n1;
n0 = n1;
n1 = t;
t = d0 + a * d1;
d0 = d1;
d1 = t;
}
*best_numerator = n1;
*best_denominator = d1;
}
static unsigned long rk628_cru_clk_get_rate_pll(struct rk628 *rk628,
unsigned int id)
{
unsigned long parent_rate = REFCLK_RATE;
u32 postdiv1, fbdiv, dsmpd, postdiv2, refdiv, frac, bypass;
u32 con0, con1, con2;
u64 foutvco, foutpostdiv;
u32 offset, val;
rk628_i2c_read(rk628, CRU_MODE_CON00, &val);
if (id == CGU_CLK_CPLL) {
val &= CLK_CPLL_MODE_MASK;
val >>= CLK_CPLL_MODE_SHIFT;
if (val == CLK_CPLL_MODE_OSC)
return parent_rate;
offset = 0x00;
} else {
val &= CLK_GPLL_MODE_MASK;
val >>= CLK_GPLL_MODE_SHIFT;
if (val == CLK_GPLL_MODE_OSC)
return parent_rate;
offset = 0x20;
}
rk628_i2c_read(rk628, offset + CRU_CPLL_CON0, &con0);
rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &con1);
rk628_i2c_read(rk628, offset + CRU_CPLL_CON2, &con2);
bypass = (con0 & PLL_BYPASS_MASK) >> PLL_BYPASS_SHIFT;
postdiv1 = (con0 & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
fbdiv = (con0 & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
dsmpd = (con1 & PLL_DSMPD_MASK) >> PLL_DSMPD_SHIFT;
postdiv2 = (con1 & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
refdiv = (con1 & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
frac = (con2 & PLL_FRAC_MASK) >> PLL_FRAC_SHIFT;
if (bypass)
return parent_rate;
foutvco = parent_rate * fbdiv;
do_div(foutvco, refdiv);
if (!dsmpd) {
u64 frac_rate = (u64)parent_rate * frac;
do_div(frac_rate, refdiv);
foutvco += frac_rate >> 24;
}
foutpostdiv = foutvco;
do_div(foutpostdiv, postdiv1);
do_div(foutpostdiv, postdiv2);
return foutpostdiv;
}
static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
unsigned int id,
unsigned long rate)
{
unsigned long fin = REFCLK_RATE, fout = rate;
u8 min_refdiv, max_refdiv, postdiv;
u8 dsmpd = 1, postdiv1 = 0, postdiv2 = 0, refdiv = 0;
u16 fbdiv = 0;
u32 frac = 0;
u64 foutvco, foutpostdiv;
u32 offset, val;
/*
* FREF : 10MHz ~ 800MHz
* FREFDIV : 1MHz ~ 40MHz
* FOUTVCO : 400MHz ~ 1.6GHz
* FOUTPOSTDIV : 8MHz ~ 1.6GHz
*/
if (fin < MIN_FREF_RATE || fin > MAX_FREF_RATE)
return 0;
if (fout < MIN_FOUTPOSTDIV_RATE || fout > MAX_FOUTPOSTDIV_RATE)
return 0;
if (id == CGU_CLK_CPLL)
offset = 0x00;
else
offset = 0x20;
rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(1));
if (fin == fout) {
rk628_i2c_write(rk628, offset + CRU_CPLL_CON0, PLL_BYPASS(1));
rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(0));
while (1) {
rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &val);
if (val & PLL_LOCK)
break;
}
return fin;
}
min_refdiv = fin / MAX_FREFDIV_RATE + 1;
max_refdiv = fin / MIN_FREFDIV_RATE;
if (max_refdiv > 64)
max_refdiv = 64;
if (fout < MIN_FVCO_RATE) {
postdiv = MIN_FVCO_RATE / fout + 1;
for (postdiv2 = 1; postdiv2 < 8; postdiv2++) {
if (postdiv % postdiv2)
continue;
postdiv1 = postdiv / postdiv2;
if (postdiv1 > 0 && postdiv1 < 8)
break;
}
if (postdiv2 > 7)
return 0;
fout *= postdiv1 * postdiv2;
} else {
postdiv1 = 1;
postdiv2 = 1;
}
for (refdiv = min_refdiv; refdiv <= max_refdiv; refdiv++) {
u64 tmp, frac_rate;
if (fin % refdiv)
continue;
tmp = (u64)fout * refdiv;
do_div(tmp, fin);
fbdiv = tmp;
if (fbdiv < 10 || fbdiv > 1600)
continue;
tmp = (u64)fbdiv * fin;
do_div(tmp, refdiv);
if (fout < MIN_FVCO_RATE || fout > MAX_FVCO_RATE)
continue;
frac_rate = fout - tmp;
if (frac_rate) {
tmp = (u64)frac_rate * refdiv;
tmp <<= 24;
do_div(tmp, fin);
frac = tmp;
dsmpd = 0;
}
break;
}
/*
* If DSMPD = 1 (DSM is disabled, "integer mode")
* FOUTVCO = FREF / REFDIV * FBDIV
* FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
*
* If DSMPD = 0 (DSM is enabled, "fractional mode")
* FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 2^24)
* FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
*/
foutvco = fin * fbdiv;
do_div(foutvco, refdiv);
if (!dsmpd) {
u64 frac_rate = (u64)fin * frac;
do_div(frac_rate, refdiv);
foutvco += frac_rate >> 24;
}
foutpostdiv = foutvco;
do_div(foutpostdiv, postdiv1);
do_div(foutpostdiv, postdiv2);
rk628_i2c_write(rk628, offset + CRU_CPLL_CON0,
PLL_BYPASS(0) | PLL_POSTDIV1(postdiv1) |
PLL_FBDIV(fbdiv));
rk628_i2c_write(rk628, offset + CRU_CPLL_CON1,
PLL_DSMPD(dsmpd) | PLL_POSTDIV2(postdiv2) |
PLL_REFDIV(refdiv));
rk628_i2c_write(rk628, offset + CRU_CPLL_CON2, PLL_FRAC(frac));
rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(0));
while (1) {
rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &val);
if (val & PLL_LOCK)
break;
}
return (unsigned long)foutpostdiv;
}
static unsigned long rk628_cru_clk_set_rate_sclk_vop(struct rk628 *rk628,
unsigned long rate)
{
unsigned long m, n, parent_rate;
u32 val;
rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &val);
val &= SCLK_VOP_SEL_MASK;
val >>= SCLK_VOP_SEL_SHIFT;
if (val == SCLK_VOP_SEL_GPLL)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
else
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
rational_best_approximation(rate, parent_rate,
GENMASK(15, 0), GENMASK(15, 0),
&m, &n);
rk628_i2c_write(rk628, CRU_CLKSEL_CON13, m << 16 | n);
return rate;
}
static unsigned long rk628_cru_clk_get_rate_sclk_vop(struct rk628 *rk628)
{
unsigned long rate, parent_rate, m, n;
u32 mux, div;
rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &mux);
mux &= CLK_UART_SRC_SEL_MASK;
mux >>= SCLK_VOP_SEL_SHIFT;
if (mux == SCLK_VOP_SEL_GPLL)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
else
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
rk628_i2c_read(rk628, CRU_CLKSEL_CON13, &div);
m = div >> 16 & 0xffff;
n = div & 0xffff;
rate = parent_rate * m / n;
return rate;
}
static unsigned long rk628_cru_clk_set_rate_rx_read(struct rk628 *rk628,
unsigned long rate)
{
unsigned long m, n, parent_rate;
u32 val;
rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &val);
val &= CLK_RX_READ_SEL_MASK;
val >>= CLK_RX_READ_SEL_SHIFT;
if (val == CLK_RX_READ_SEL_GPLL)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
else
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
rational_best_approximation(rate, parent_rate,
GENMASK(15, 0), GENMASK(15, 0),
&m, &n);
rk628_i2c_write(rk628, CRU_CLKSEL_CON14, m << 16 | n);
return rate;
}
static unsigned long rk628_cru_clk_get_rate_uart_src(struct rk628 *rk628)
{
unsigned long rate, parent_rate;
u32 mux, div;
rk628_i2c_read(rk628, CRU_CLKSEL_CON21, &mux);
mux &= SCLK_VOP_SEL_MASK;
if (mux == CLK_UART_SRC_SEL_GPLL)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
else
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
rk628_i2c_read(rk628, CRU_CLKSEL_CON21, &div);
div &= CLK_UART_SRC_DIV_MASK;
div >>= CLK_UART_SRC_DIV_SHIFT;
rate = parent_rate / (div + 1);
return rate;
}
static unsigned long rk628_cru_clk_set_rate_sclk_uart(struct rk628 *rk628,
unsigned long rate)
{
unsigned long m, n, parent_rate;
parent_rate = rk628_cru_clk_get_rate_uart_src(rk628);
if (rate == REFCLK_RATE) {
rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
SCLK_UART_SEL(SCLK_UART_SEL_OSC));
return rate;
} else if (rate == parent_rate) {
rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
SCLK_UART_SEL(SCLK_UART_SEL_UART_SRC));
return rate;
}
rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
SCLK_UART_SEL(SCLK_UART_SEL_UART_FRAC));
rational_best_approximation(rate, parent_rate,
GENMASK(15, 0), GENMASK(15, 0),
&m, &n);
rk628_i2c_write(rk628, CRU_CLKSEL_CON20, m << 16 | n);
return rate;
}
static unsigned long
rk628_cru_clk_get_rate_bt1120_dec_parent(struct rk628 *rk628)
{
unsigned long parent_rate;
u32 mux;
rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &mux);
mux &= CLK_BT1120DEC_SEL_MASK;
if (mux == CLK_BT1120DEC_SEL_GPLL)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
else
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
return parent_rate;
}
static unsigned long rk628_cru_clk_set_rate_bt1120_dec(struct rk628 *rk628,
unsigned long rate)
{
unsigned long parent_rate;
u32 div;
parent_rate = rk628_cru_clk_get_rate_bt1120_dec_parent(rk628);
div = DIV_ROUND_UP(parent_rate, rate);
rk628_i2c_write(rk628, CRU_CLKSEL_CON02, CLK_BT1120DEC_DIV(div-1));
return parent_rate / div;
}
int rk628_cru_clk_set_rate(struct rk628 *rk628, unsigned int id,
unsigned long rate)
{
switch (id) {
case CGU_CLK_CPLL:
case CGU_CLK_GPLL:
rk628_cru_clk_set_rate_pll(rk628, id, rate);
break;
case CGU_CLK_RX_READ:
rk628_cru_clk_set_rate_rx_read(rk628, rate);
break;
case CGU_SCLK_VOP:
rk628_cru_clk_set_rate_sclk_vop(rk628, rate);
break;
case CGU_SCLK_UART:
rk628_cru_clk_set_rate_sclk_uart(rk628, rate);
break;
case CGU_BT1120DEC:
rk628_cru_clk_set_rate_bt1120_dec(rk628, rate);
break;
default:
return -1;
}
return 0;
}
unsigned long rk628_cru_clk_get_rate(struct rk628 *rk628, unsigned int id)
{
unsigned long rate;
switch (id) {
case CGU_CLK_CPLL:
case CGU_CLK_GPLL:
rate = rk628_cru_clk_get_rate_pll(rk628, id);
break;
case CGU_SCLK_VOP:
rate = rk628_cru_clk_get_rate_sclk_vop(rk628);
break;
default:
return 0;
}
return rate;
}
void rk628_cru_init(struct rk628 *rk628)
{
u32 val;
u8 mcu_mode;
rk628_i2c_read(rk628, GRF_SYSTEM_STATUS0, &val);
mcu_mode = (val & I2C_ONLY_FLAG) ? 0 : 1;
if (mcu_mode)
return;
rk628_i2c_write(rk628, CRU_GPLL_CON0, 0xffff701d);
mdelay(1);
rk628_i2c_write(rk628, CRU_MODE_CON00, 0xffff0004);
mdelay(1);
rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0080);
rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0083);
rk628_i2c_write(rk628, CRU_CPLL_CON0, 0xffff3063);
mdelay(1);
rk628_i2c_write(rk628, CRU_MODE_CON00, 0xffff0005);
rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0003);
rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff000b);
rk628_i2c_write(rk628, CRU_GPLL_CON0, 0xffff1028);
mdelay(1);
rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff008b);
rk628_i2c_write(rk628, CRU_CPLL_CON0, 0xffff1063);
mdelay(1);
rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff000b);
}

View File

@@ -0,0 +1,159 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#ifndef RK628_CRU_H
#define RK628_CRU_H
#include "rk628.h"
#define CRU_REG(x) ((x) + 0xc0000)
#define CRU_CPLL_CON0 CRU_REG(0x0000)
#define PLL_BYPASS_MASK BIT(15)
#define PLL_BYPASS(x) HIWORD_UPDATE(x, 15, 15)
#define PLL_BYPASS_SHIFT 15
#define PLL_POSTDIV1_MASK GENMASK(14, 12)
#define PLL_POSTDIV1(x) HIWORD_UPDATE(x, 14, 12)
#define PLL_POSTDIV1_SHIFT 12
#define PLL_FBDIV_MASK GENMASK(11, 0)
#define PLL_FBDIV(x) HIWORD_UPDATE(x, 11, 0)
#define PLL_FBDIV_SHIFT 0
#define CRU_CPLL_CON1 CRU_REG(0x0004)
#define PLL_PD_MASK BIT(13)
#define PLL_PD(x) HIWORD_UPDATE(x, 13, 13)
#define PLL_DSMPD_MASK BIT(12)
#define PLL_DSMPD(x) HIWORD_UPDATE(x, 12, 12)
#define PLL_DSMPD_SHIFT 12
#define PLL_LOCK BIT(10)
#define PLL_POSTDIV2_MASK GENMASK(8, 6)
#define PLL_POSTDIV2(x) HIWORD_UPDATE(x, 8, 6)
#define PLL_POSTDIV2_SHIFT 6
#define PLL_REFDIV_MASK GENMASK(5, 0)
#define PLL_REFDIV(x) HIWORD_UPDATE(x, 5, 0)
#define PLL_REFDIV_SHIFT 0
#define CRU_CPLL_CON2 CRU_REG(0x0008)
#define PLL_FRAC_MASK GENMASK(23, 0)
#define PLL_FRAC(x) ((x) << 0)
#define PLL_FRAC_SHIFT 0
#define CRU_CPLL_CON3 CRU_REG(0x000c)
#define CRU_CPLL_CON4 CRU_REG(0x0010)
#define CRU_GPLL_CON0 CRU_REG(0x0020)
#define CRU_GPLL_CON1 CRU_REG(0x0024)
#define CRU_GPLL_CON2 CRU_REG(0x0028)
#define CRU_GPLL_CON3 CRU_REG(0x002c)
#define CRU_GPLL_CON4 CRU_REG(0x0030)
#define CRU_MODE_CON00 CRU_REG(0x0060)
#define CLK_GPLL_MODE_MASK BIT(2)
#define CLK_GPLL_MODE_SHIFT 2
#define CLK_GPLL_MODE_GPLL 1
#define CLK_GPLL_MODE_OSC 0
#define CLK_CPLL_MODE_MASK BIT(0)
#define CLK_CPLL_MODE_SHIFT 0
#define CLK_CPLL_MODE_CPLL 1
#define CLK_CPLL_MODE_OSC 0
#define CRU_CLKSEL_CON00 CRU_REG(0x0080)
#define CRU_CLKSEL_CON01 CRU_REG(0x0084)
#define CRU_CLKSEL_CON02 CRU_REG(0x0088)
#define SCLK_VOP_SEL_MASK BIT(9)
#define SCLK_VOP_SEL_SHIFT 9
#define SCLK_VOP_SEL_GPLL 1
#define SCLK_VOP_SEL_CPLL 0
#define CLK_RX_READ_SEL_MASK BIT(8)
#define CLK_RX_READ_SEL_SHIFT 8
#define CLK_RX_READ_SEL_GPLL 1
#define CLK_RX_READ_SEL_CPLL 0
#define CLK_BT1120DEC_SEL_MASK BIT(7)
#define CLK_BT1120DEC_SEL_SHIFT 7
#define CLK_BT1120DEC_SEL_GPLL 1
#define CLK_BT1120DEC_SEL_CPLL 0
#define CLK_BT1120DEC_DIV(x) HIWORD_UPDATE(x, 4, 0)
#define CRU_CLKSEL_CON03 CRU_REG(0x008c)
#define CRU_CLKSEL_CON04 CRU_REG(0x0090)
#define CRU_CLKSEL_CON05 CRU_REG(0x0094)
#define CRU_CLKSEL_CON06 CRU_REG(0x0098)
#define SCLK_UART_SEL(x) HIWORD_UPDATE(x, 15, 14)
#define SCLK_UART_SEL_MASK GENMASK(15, 14)
#define SCLK_UART_SEL_SHIFT 14
#define SCLK_UART_SEL_OSC 2
#define SCLK_UART_SEL_UART_FRAC 1
#define SCLK_UART_SEL_UART_SRC 0
#define CRU_CLKSEL_CON07 CRU_REG(0x009c)
#define CRU_CLKSEL_CON08 CRU_REG(0x00a0)
#define CRU_CLKSEL_CON09 CRU_REG(0x00a4)
#define CRU_CLKSEL_CON10 CRU_REG(0x00a8)
#define CRU_CLKSEL_CON11 CRU_REG(0x00ac)
#define CRU_CLKSEL_CON12 CRU_REG(0x00b0)
#define CRU_CLKSEL_CON13 CRU_REG(0x00b4)
#define CRU_CLKSEL_CON14 CRU_REG(0x00b8)
#define CRU_CLKSEL_CON15 CRU_REG(0x00bc)
#define CRU_CLKSEL_CON16 CRU_REG(0x00c0)
#define CRU_CLKSEL_CON17 CRU_REG(0x00c4)
#define CRU_CLKSEL_CON18 CRU_REG(0x00c8)
#define CRU_CLKSEL_CON20 CRU_REG(0x00d0)
#define CRU_CLKSEL_CON21 CRU_REG(0x00d4)
#define CLK_UART_SRC_SEL_MASK BIT(15)
#define CLK_UART_SRC_SEL_GPLL (1 << 15)
#define CLK_UART_SRC_SEL_CPLL (0 << 15)
#define CLK_UART_SRC_DIV_MASK GENMASK(12, 8)
#define CLK_UART_SRC_DIV_SHIFT 8
#define CRU_GATE_CON00 CRU_REG(0x0180)
#define CRU_GATE_CON01 CRU_REG(0x0184)
#define CRU_GATE_CON02 CRU_REG(0x0188)
#define CRU_GATE_CON03 CRU_REG(0x018c)
#define CRU_GATE_CON04 CRU_REG(0x0190)
#define CRU_GATE_CON05 CRU_REG(0x0194)
#define CRU_SOFTRST_CON00 CRU_REG(0x0200)
#define CRU_SOFTRST_CON01 CRU_REG(0x0204)
#define CRU_SOFTRST_CON02 CRU_REG(0x0208)
#define CRU_SOFTRST_CON04 CRU_REG(0x0210)
#define CRU_MAX_REGISTER CRU_SOFTRST_CON04
#define CGU_CLK_CPLL 1
#define CGU_CLK_GPLL 2
#define CGU_CLK_CPLL_MUX 3
#define CGU_CLK_GPLL_MUX 4
#define CGU_PCLK_GPIO0 5
#define CGU_PCLK_GPIO1 6
#define CGU_PCLK_GPIO2 7
#define CGU_PCLK_GPIO3 8
#define CGU_PCLK_TXPHY_CON 9
#define CGU_PCLK_EFUSE 10
#define CGU_PCLK_DSI0 11
#define CGU_PCLK_DSI1 12
#define CGU_PCLK_CSI 13
#define CGU_PCLK_HDMITX 14
#define CGU_PCLK_RXPHY 15
#define CGU_PCLK_HDMIRX 16
#define CGU_PCLK_DPRX 17
#define CGU_PCLK_GVIHOST 18
#define CGU_CLK_CFG_DPHY0 19
#define CGU_CLK_CFG_DPHY1 20
#define CGU_CLK_TXESC 21
#define CGU_CLK_DPRX_VID 22
#define CGU_CLK_IMODET 23
#define CGU_CLK_HDMIRX_AUD 24
#define CGU_CLK_HDMIRX_CEC 25
#define CGU_CLK_RX_READ 26
#define CGU_SCLK_VOP 27
#define CGU_PCLK_LOGIC 28
#define CGU_CLK_GPIO_DB0 29
#define CGU_CLK_GPIO_DB1 30
#define CGU_CLK_GPIO_DB2 31
#define CGU_CLK_GPIO_DB3 32
#define CGU_CLK_I2S_8CH_SRC 33
#define CGU_CLK_I2S_8CH_FRAC 34
#define CGU_MCLK_I2S_8CH 35
#define CGU_I2S_MCLKOUT 36
#define CGU_BT1120DEC 37
#define CGU_SCLK_UART 38
unsigned long rk628_cru_clk_get_rate(struct rk628 *rk628, unsigned int id);
int rk628_cru_clk_set_rate(struct rk628 *rk628, unsigned int id,
unsigned long rate);
void rk628_cru_init(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,434 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Shunqing Chen <csq@rock-chisp.com>
*/
#include "rk628.h"
#include "rk628_combtxphy.h"
#include "rk628_config.h"
#include "rk628_csi.h"
#define CSITX_ERR_RETRY_TIMES 3
#define MIPI_DATARATE_MBPS_LOW 750
#define MIPI_DATARATE_MBPS_HIGH 1250
#define USE_4_LANES 4
#define YUV422_8BIT 0x1e
/* Test Code: 0x44 (HS RX Control of Lane 0) */
#define HSFREQRANGE(x) UPDATE(x, 6, 1)
struct rk628_csi {
struct rk628_display_mode mode;
bool txphy_pwron;
u64 lane_mbps;
};
static inline void testif_testclk_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTCLK, PHY_TESTCLK);
udelay(1);
}
static inline void testif_testclk_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTCLK, 0);
udelay(1);
}
static inline void testif_testclr_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTCLR, PHY_TESTCLR);
udelay(1);
}
static inline void testif_testclr_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTCLR, 0);
udelay(1);
}
static inline void testif_testen_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTEN, PHY_TESTEN);
udelay(1);
}
static inline void testif_testen_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTEN, 0);
udelay(1);
}
static inline void testif_set_data(struct rk628 *rk628, u8 data)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTDIN_MASK, PHY_TESTDIN(data));
udelay(1);
}
static inline u8 testif_get_data(struct rk628 *rk628)
{
u32 data = 0;
rk628_i2c_read(rk628, GRF_DPHY0_STATUS, &data);
return data >> PHY_TESTDOUT_SHIFT;
}
static void testif_test_code_write(struct rk628 *rk628, u8 test_code)
{
testif_testclk_assert(rk628);
testif_set_data(rk628, test_code);
testif_testen_assert(rk628);
testif_testclk_deassert(rk628);
testif_testen_deassert(rk628);
}
static void testif_test_data_write(struct rk628 *rk628, u8 test_data)
{
testif_testclk_deassert(rk628);
testif_set_data(rk628, test_data);
testif_testclk_assert(rk628);
}
static u8 testif_write(struct rk628 *rk628, u8 test_code, u8 test_data)
{
u8 monitor_data;
testif_test_code_write(rk628, test_code);
testif_test_data_write(rk628, test_data);
monitor_data = testif_get_data(rk628);
dev_info(rk628->dev, "test_code=0x%02x, ", test_code);
dev_info(rk628->dev, "test_data=0x%02x, ", test_data);
dev_info(rk628->dev, "monitor_data=0x%02x\n", monitor_data);
return monitor_data;
}
static void rk628_csi_get_detected_timings(struct rk628 *rk628)
{
struct rk628_display_mode *src, *dst;
struct rk628_csi *csi = rk628->csi;
if (!csi)
return;
src = rk628_display_get_src_mode(rk628);
dst = rk628_display_get_dst_mode(rk628);
rk628_set_output_bus_format(rk628, BUS_FMT_YUV422);
rk628_mode_copy(dst, src);
rk628_mode_copy(&csi->mode, dst);
}
static inline u8 testif_read(struct rk628 *rk628, u8 test_code)
{
u8 test_data;
testif_test_code_write(rk628, test_code);
test_data = testif_get_data(rk628);
testif_test_data_write(rk628, test_data);
return test_data;
}
static inline void mipi_dphy_enableclk_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, CSITX_DPHY_CTRL, DPHY_ENABLECLK,
DPHY_ENABLECLK);
udelay(1);
}
static inline void mipi_dphy_enableclk_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, CSITX_DPHY_CTRL, DPHY_ENABLECLK, 0);
udelay(1);
}
static inline void mipi_dphy_shutdownz_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYSHUTDOWNZ, 0);
udelay(1);
}
static inline void mipi_dphy_shutdownz_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYSHUTDOWNZ,
CSI_PHYSHUTDOWNZ);
udelay(1);
}
static inline void mipi_dphy_rstz_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYRSTZ, 0);
udelay(1);
}
static inline void mipi_dphy_rstz_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYRSTZ,
CSI_PHYRSTZ);
udelay(1);
}
static void mipi_dphy_init_hsfreqrange(struct rk628 *rk628)
{
const struct {
unsigned long max_lane_mbps;
u8 hsfreqrange;
} hsfreqrange_table[] = {
{ 90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
{ 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
{ 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
{ 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
{ 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
{ 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
{ 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
};
u8 hsfreqrange;
unsigned int index;
struct rk628_csi *csi = rk628->csi;
if (!csi)
return;
for (index = 0; index < ARRAY_SIZE(hsfreqrange_table); index++)
if (csi->lane_mbps <= hsfreqrange_table[index].max_lane_mbps)
break;
if (index == ARRAY_SIZE(hsfreqrange_table))
--index;
hsfreqrange = hsfreqrange_table[index].hsfreqrange;
testif_write(rk628, 0x44, HSFREQRANGE(hsfreqrange));
}
static int mipi_dphy_reset(struct rk628 *rk628)
{
u32 val;
int ret;
mipi_dphy_enableclk_deassert(rk628);
mipi_dphy_shutdownz_assert(rk628);
mipi_dphy_rstz_assert(rk628);
testif_testclr_assert(rk628);
/* Set all REQUEST inputs to zero */
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
FORCETXSTOPMODE_MASK | FORCERXMODE_MASK,
FORCETXSTOPMODE(0) | FORCERXMODE(0));
udelay(1);
testif_testclr_deassert(rk628);
mipi_dphy_enableclk_assert(rk628);
mipi_dphy_shutdownz_deassert(rk628);
mipi_dphy_rstz_deassert(rk628);
usleep_range(1500, 2000);
ret = rk628_i2c_read(rk628, CSITX_CSITX_STATUS1, &val);
if (ret < 0) {
dev_info(rk628->dev, "lane module is not in stop state\n");
return ret;
}
return 0;
}
static int mipi_dphy_power_on(struct rk628 *rk628)
{
unsigned int val;
u32 bus_width, mask;
struct rk628_csi *csi = rk628->csi;
if (!csi)
return -1;
if ((csi->mode.hdisplay == 3840) &&
(csi->mode.vdisplay == 2160)) {
csi->lane_mbps = MIPI_DATARATE_MBPS_HIGH;
} else {
csi->lane_mbps = MIPI_DATARATE_MBPS_LOW;
}
bus_width = csi->lane_mbps << 8;
bus_width |= COMBTXPHY_MODULEA_EN;
dev_info(rk628->dev, "%s mipi bitrate:%llu mbps\n", __func__, csi->lane_mbps);
rk628_combtxphy_set_bus_width(rk628, bus_width);
rk628_combtxphy_set_mode(rk628, PHY_MODE_VIDEO_MIPI);
mipi_dphy_init_hsfreqrange(rk628);
usleep_range(1500, 2000);
rk628_combtxphy_power_on(rk628);
usleep_range(1500, 2000);
mask = DPHY_PLL_LOCK;
rk628_i2c_read(rk628, CSITX_CSITX_STATUS1, &val);
if ((val & mask) != mask) {
dev_info(rk628->dev, "PHY is not locked\n");
return -1;
}
udelay(10);
return 0;
}
static void mipi_dphy_power_off(struct rk628 *rk628)
{
rk628_combtxphy_power_off(rk628);
}
static void rk62_csi_reset(struct rk628 *rk628)
{
rk628_i2c_write(rk628, CSITX_SYS_CTRL0_IMD, 0x1);
usleep_range(1000, 1100);
rk628_i2c_write(rk628, CSITX_SYS_CTRL0_IMD, 0x0);
}
static void rk628_csi_set_csi(struct rk628 *rk628)
{
u8 lanes = USE_4_LANES;
u8 lane_num;
u8 dphy_lane_en;
u32 wc_usrdef;
struct rk628_csi *csi;
if (!rk628->csi) {
csi = devm_kzalloc(rk628->dev, sizeof(*csi), GFP_KERNEL);
if (!csi)
return;
rk628->csi = csi;
} else {
csi = rk628->csi;
}
lane_num = lanes - 1;
dphy_lane_en = (1 << (lanes + 1)) - 1;
wc_usrdef = csi->mode.hdisplay * 2;
rk62_csi_reset(rk628);
if (csi->txphy_pwron) {
dev_info(rk628->dev, "%s: txphy already power on, power off\n",
__func__);
mipi_dphy_power_off(rk628);
csi->txphy_pwron = false;
}
mipi_dphy_power_on(rk628);
csi->txphy_pwron = true;
dev_info(rk628->dev, "%s: txphy power on!\n", __func__);
usleep_range(1000, 1500);
rk628_i2c_update_bits(rk628, CSITX_CSITX_EN,
VOP_UV_SWAP_MASK |
VOP_YUV422_EN_MASK |
VOP_P2_EN_MASK |
LANE_NUM_MASK |
DPHY_EN_MASK |
CSITX_EN_MASK,
VOP_UV_SWAP(1) |
VOP_YUV422_EN(1) |
VOP_P2_EN(1) |
LANE_NUM(lane_num) |
DPHY_EN(0) |
CSITX_EN(0));
rk628_i2c_update_bits(rk628, CSITX_SYS_CTRL1,
BYPASS_SELECT_MASK,
BYPASS_SELECT(1));
rk628_i2c_write(rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD);
rk628_i2c_write(rk628, CSITX_SYS_CTRL2, VOP_WHOLE_FRM_EN | VSYNC_ENABLE);
rk628_i2c_update_bits(rk628, CSITX_SYS_CTRL3_IMD,
CONT_MODE_CLK_CLR_MASK |
CONT_MODE_CLK_SET_MASK |
NON_CONTINOUS_MODE_MASK,
CONT_MODE_CLK_CLR(0) |
CONT_MODE_CLK_SET(0) |
NON_CONTINOUS_MODE(1));
rk628_i2c_write(rk628, CSITX_VOP_PATH_CTRL,
VOP_WC_USERDEFINE(wc_usrdef) |
VOP_DT_USERDEFINE(YUV422_8BIT) |
VOP_PIXEL_FORMAT(0) |
VOP_WC_USERDEFINE_EN(1) |
VOP_DT_USERDEFINE_EN(1) |
VOP_PATH_EN(1));
rk628_i2c_update_bits(rk628, CSITX_DPHY_CTRL,
CSI_DPHY_EN_MASK,
CSI_DPHY_EN(dphy_lane_en));
rk628_i2c_write(rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD);
dev_info(rk628->dev, "%s csi cofig done\n", __func__);
}
static void enable_csitx(struct rk628 *rk628)
{
u32 i, ret, val;
for (i = 0; i < CSITX_ERR_RETRY_TIMES; i++) {
rk628_csi_set_csi(rk628);
rk628_i2c_update_bits(rk628, CSITX_CSITX_EN,
DPHY_EN_MASK |
CSITX_EN_MASK,
DPHY_EN(1) |
CSITX_EN(1));
rk628_i2c_write(rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD);
msleep(40);
rk628_i2c_write(rk628, CSITX_ERR_INTR_CLR_IMD, 0xffffffff);
rk628_i2c_update_bits(rk628, CSITX_SYS_CTRL1,
BYPASS_SELECT_MASK, BYPASS_SELECT(0));
rk628_i2c_write(rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD);
msleep(40);
ret = rk628_i2c_read(rk628, CSITX_ERR_INTR_RAW_STATUS_IMD, &val);
if (!ret && !val)
break;
dev_info(rk628->dev, "%s csitx err, retry:%d, err status:%#x, ret:%d\n",
__func__, i, val, ret);
}
}
static void enable_stream(struct rk628 *rk628, bool en)
{
dev_info(rk628->dev, "%s: %sable\n", __func__, en ? "en" : "dis");
if (en) {
enable_csitx(rk628);
} else {
rk628_i2c_update_bits(rk628, CSITX_CSITX_EN,
DPHY_EN_MASK |
CSITX_EN_MASK,
DPHY_EN(0) |
CSITX_EN(0));
rk628_i2c_write(rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD);
}
}
void rk628_csi_init(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_OUTPUT_MODE_MASK, SW_OUTPUT_MODE(OUTPUT_MODE_CSI));
rk628_csi_get_detected_timings(rk628);
mipi_dphy_reset(rk628);
}
void rk628_csi_enable(struct rk628 *rk628)
{
rk628_csi_get_detected_timings(rk628);
return enable_stream(rk628, true);
}
void rk628_csi_disable(struct rk628 *rk628)
{
return enable_stream(rk628, false);
}

View File

@@ -0,0 +1,86 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Chen Shunqing <csq@rock-chips.com>
*/
#ifndef RK628_CSI_H
#define RK628_CSI_H
#include "rk628.h"
#define CSI_REG(x) ((x) + 0x40000)
#define CSITX_CONFIG_DONE CSI_REG(0x0000)
#define CONFIG_DONE_IMD BIT(4)
#define CONFIG_DONE BIT(0)
#define CSITX_CSITX_EN CSI_REG(0x0004)
#define VOP_YU_SWAP_MASK BIT(14)
#define VOP_YU_SWAP(x) UPDATE(x, 14, 14)
#define VOP_UV_SWAP_MASK BIT(13)
#define VOP_UV_SWAP(x) UPDATE(x, 13, 13)
#define VOP_YUV422_EN_MASK BIT(12)
#define VOP_YUV422_EN(x) UPDATE(x, 12, 12)
#define VOP_P2_EN_MASK BIT(8)
#define VOP_P2_EN(x) UPDATE(x, 8, 8)
#define LANE_NUM_MASK GENMASK(5, 4)
#define LANE_NUM(x) UPDATE(x, 5, 4)
#define DPHY_EN_MASK BIT(2)
#define DPHY_EN(x) UPDATE(x, 2, 2)
#define CSITX_EN_MASK BIT(0)
#define CSITX_EN(x) UPDATE(x, 0, 0)
#define CSITX_CSITX_VERSION CSI_REG(0x0008)
#define CSITX_SYS_CTRL0_IMD CSI_REG(0x0010)
#define CSITX_SYS_CTRL1 CSI_REG(0x0014)
#define BYPASS_SELECT_MASK BIT(0)
#define BYPASS_SELECT(x) UPDATE(x, 0, 0)
#define CSITX_SYS_CTRL2 CSI_REG(0x0018)
#define VOP_WHOLE_FRM_EN BIT(5)
#define VSYNC_ENABLE BIT(0)
#define CSITX_SYS_CTRL3_IMD CSI_REG(0x001c)
#define CONT_MODE_CLK_CLR_MASK BIT(8)
#define CONT_MODE_CLK_CLR(x) UPDATE(x, 8, 8)
#define CONT_MODE_CLK_SET_MASK BIT(4)
#define CONT_MODE_CLK_SET(x) UPDATE(x, 4, 4)
#define NON_CONTINOUS_MODE_MASK BIT(0)
#define NON_CONTINOUS_MODE(x) UPDATE(x, 0, 0)
#define CSITX_TIMING_HPW_PADDING_NUM CSI_REG(0x0030)
#define CSITX_VOP_PATH_CTRL CSI_REG(0x0040)
#define VOP_WC_USERDEFINE_MASK GENMASK(31, 16)
#define VOP_WC_USERDEFINE(x) UPDATE(x, 31, 16)
#define VOP_DT_USERDEFINE_MASK GENMASK(13, 8)
#define VOP_DT_USERDEFINE(x) UPDATE(x, 13, 8)
#define VOP_PIXEL_FORMAT_MASK GENMASK(7, 4)
#define VOP_PIXEL_FORMAT(x) UPDATE(x, 7, 4)
#define VOP_WC_USERDEFINE_EN_MASK BIT(3)
#define VOP_WC_USERDEFINE_EN(x) UPDATE(x, 3, 3)
#define VOP_DT_USERDEFINE_EN_MASK BIT(1)
#define VOP_DT_USERDEFINE_EN(x) UPDATE(x, 1, 1)
#define VOP_PATH_EN_MASK BIT(0)
#define VOP_PATH_EN(x) UPDATE(x, 0, 0)
#define CSITX_VOP_PATH_PKT_CTRL CSI_REG(0x0050)
#define CSITX_CSITX_STATUS0 CSI_REG(0x0070)
#define CSITX_CSITX_STATUS1 CSI_REG(0x0074)
#define STOPSTATE_LANE3 BIT(7)
#define STOPSTATE_LANE2 BIT(6)
#define STOPSTATE_LANE1 BIT(5)
#define STOPSTATE_LANE0 BIT(4)
#define STOPSTATE_CLK BIT(1)
#define DPHY_PLL_LOCK BIT(0)
#define CSITX_ERR_INTR_EN_IMD CSI_REG(0x0090)
#define CSITX_ERR_INTR_CLR_IMD CSI_REG(0x0094)
#define CSITX_ERR_INTR_STATUS_IMD CSI_REG(0x0098)
#define CSITX_ERR_INTR_RAW_STATUS_IMD CSI_REG(0x009c)
#define CSITX_LPDT_DATA_IMD CSI_REG(0x00a8)
#define CSITX_DPHY_CTRL CSI_REG(0x00b0)
#define CSI_DPHY_EN_MASK GENMASK(7, 3)
#define CSI_DPHY_EN(x) UPDATE(x, 7, 3)
#define DPHY_ENABLECLK BIT(3)
#define CSI_MAX_REGISTER CSITX_DPHY_CTRL
void rk628_csi_init(struct rk628 *rk628);
void rk628_csi_enable(struct rk628 *rk628);
void rk628_csi_disable(struct rk628 *rk628);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,158 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#ifndef RK628_DSI_H
#define RK628_DSI_H
#include "rk628.h"
#define DSI0_BASE 0x50000
#define DSI1_BASE 0x60000
#define DSI_VERSION 0x0000
#define DSI_PWR_UP 0x0004
#define RESET 0
#define POWER_UP BIT(0)
#define DSI_CLKMGR_CFG 0x0008
#define TO_CLK_DIVISION(x) UPDATE(x, 15, 8)
#define TX_ESC_CLK_DIVISION(x) UPDATE(x, 7, 0)
#define DSI_DPI_VCID 0x000c
#define DPI_VID(x) UPDATE(x, 1, 0)
#define DSI_DPI_COLOR_CODING 0x0010
#define LOOSELY18_EN BIT(8)
#define DPI_COLOR_CODING(x) UPDATE(x, 3, 0)
#define DSI_DPI_CFG_POL 0x0014
#define COLORM_ACTIVE_LOW BIT(4)
#define SHUTD_ACTIVE_LOW BIT(3)
#define HSYNC_ACTIVE_LOW BIT(2)
#define VSYNC_ACTIVE_LOW BIT(1)
#define DATAEN_ACTIVE_LOW BIT(0)
#define DSI_DPI_LP_CMD_TIM 0x0018
#define OUTVACT_LPCMD_TIME(x) UPDATE(x, 23, 16)
#define INVACT_LPCMD_TIME(x) UPDATE(x, 7, 0)
#define DSI_PCKHDL_CFG 0x002c
#define CRC_RX_EN BIT(4)
#define ECC_RX_EN BIT(3)
#define BTA_EN BIT(2)
#define EOTP_RX_EN BIT(1)
#define EOTP_TX_EN BIT(0)
#define DSI_GEN_VCID 0x0030
#define DSI_MODE_CFG 0x0034
#define CMD_VIDEO_MODE(x) UPDATE(x, 0, 0)
#define DSI_VID_MODE_CFG 0x0038
#define VPG_EN BIT(16)
#define LP_CMD_EN BIT(15)
#define FRAME_BTA_ACK_EN BIT(14)
#define LP_HFP_EN BIT(13)
#define LP_HBP_EN BIT(12)
#define LP_VACT_EN BIT(11)
#define LP_VFP_EN BIT(10)
#define LP_VBP_EN BIT(9)
#define LP_VSA_EN BIT(8)
#define VID_MODE_TYPE(x) UPDATE(x, 1, 0)
#define DSI_VID_PKT_SIZE 0x003c
#define VID_PKT_SIZE(x) UPDATE(x, 13, 0)
#define DSI_VID_NUM_CHUNKS 0x0040
#define DSI_VID_NULL_SIZE 0x0044
#define DSI_VID_HSA_TIME 0x0048
#define VID_HSA_TIME(x) UPDATE(x, 11, 0)
#define DSI_VID_HBP_TIME 0x004c
#define VID_HBP_TIME(x) UPDATE(x, 11, 0)
#define DSI_VID_HLINE_TIME 0x0050
#define VID_HLINE_TIME(x) UPDATE(x, 14, 0)
#define DSI_VID_VSA_LINES 0x0054
#define VSA_LINES(x) UPDATE(x, 9, 0)
#define DSI_VID_VBP_LINES 0x0058
#define VBP_LINES(x) UPDATE(x, 9, 0)
#define DSI_VID_VFP_LINES 0x005c
#define VFP_LINES(x) UPDATE(x, 9, 0)
#define DSI_VID_VACTIVE_LINES 0x0060
#define V_ACTIVE_LINES(x) UPDATE(x, 13, 0)
#define DSI_EDPI_CMD_SIZE 0x0064
#define EDPI_ALLOWED_CMD_SIZE(x) UPDATE(x, 15, 0)
#define DSI_CMD_MODE_CFG 0x0068
#define MAX_RD_PKT_SIZE BIT(24)
#define DCS_LW_TX BIT(19)
#define DCS_SR_0P_TX BIT(18)
#define DCS_SW_1P_TX BIT(17)
#define DCS_SW_0P_TX BIT(16)
#define GEN_LW_TX BIT(14)
#define GEN_SR_2P_TX BIT(13)
#define GEN_SR_1P_TX BIT(12)
#define GEN_SR_0P_TX BIT(11)
#define GEN_SW_2P_TX BIT(10)
#define GEN_SW_1P_TX BIT(9)
#define GEN_SW_0P_TX BIT(8)
#define ACK_RQST_EN BIT(1)
#define TEAR_FX_EN BIT(0)
#define DSI_GEN_HDR 0x006c
#define GEN_WC_MSBYTE(x) UPDATE(x, 23, 16)
#define GEN_WC_LSBYTE(x) UPDATE(x, 15, 8)
#define GEN_VC(x) UPDATE(x, 7, 6)
#define GEN_DT(x) UPDATE(x, 5, 0)
#define DSI_GEN_PLD_DATA 0x0070
#define DSI_CMD_PKT_STATUS 0x0074
#define GEN_RD_CMD_BUSY BIT(6)
#define GEN_PLD_R_FULL BIT(5)
#define GEN_PLD_R_EMPTY BIT(4)
#define GEN_PLD_W_FULL BIT(3)
#define GEN_PLD_W_EMPTY BIT(2)
#define GEN_CMD_FULL BIT(1)
#define GEN_CMD_EMPTY BIT(0)
#define DSI_TO_CNT_CFG 0x0078
#define HSTX_TO_CNT(x) UPDATE(x, 31, 16)
#define LPRX_TO_CNT(x) UPDATE(x, 15, 0)
#define DSI_HS_RD_TO_CNT 0x007c
#define HS_RD_TO_CNT(x) UPDATE(x, 15, 0)
#define DSI_LP_RD_TO_CNT 0x0080
#define LP_RD_TO_CNT(x) UPDATE(x, 15, 0)
#define DSI_HS_WR_TO_CNT 0x0084
#define HS_WR_TO_CNT(x) UPDATE(x, 15, 0)
#define DSI_LP_WR_TO_CNT 0x0088
#define LP_WR_TO_CNT(x) UPDATE(x, 15, 0)
#define DSI_BTA_TO_CNT 0x008c
#define BTA_TO_CNT(x) UPDATE(x, 15, 0)
#define DSI_SDF_3D 0x0090
#define DSI_LPCLK_CTRL 0x0094
#define AUTO_CLKLANE_CTRL BIT(1)
#define PHY_TXREQUESTCLKHS BIT(0)
#define DSI_PHY_TMR_LPCLK_CFG 0x0098
#define PHY_CLKHS2LP_TIME(x) UPDATE(x, 25, 16)
#define PHY_CLKLP2HS_TIME(x) UPDATE(x, 9, 0)
#define DSI_PHY_TMR_CFG 0x009c
#define PHY_HS2LP_TIME(x) UPDATE(x, 31, 24)
#define PHY_LP2HS_TIME(x) UPDATE(x, 23, 16)
#define MAX_RD_TIME(x) UPDATE(x, 14, 0)
#define DSI_PHY_RSTZ 0x00a0
#define PHY_FORCEPLL BIT(3)
#define PHY_ENABLECLK BIT(2)
#define PHY_RSTZ BIT(1)
#define PHY_SHUTDOWNZ BIT(0)
#define DSI_PHY_IF_CFG 0x00a4
#define PHY_STOP_WAIT_TIME(x) UPDATE(x, 15, 8)
#define N_LANES(x) UPDATE(x, 1, 0)
#define DSI_PHY_STATUS 0x00b0
#define PHY_STOPSTATE3LANE BIT(11)
#define PHY_STOPSTATE2LANE BIT(9)
#define PHY_STOPSTATE1LANE BIT(7)
#define PHY_STOPSTATE0LANE BIT(4)
#define PHY_STOPSTATECLKLANE BIT(2)
#define PHY_LOCK BIT(0)
#define PHY_STOPSTATELANE (PHY_STOPSTATE0LANE | \
PHY_STOPSTATECLKLANE)
#define DSI_INT_ST0 0x00bc
#define DSI_INT_ST1 0x00c0
#define DSI_INT_MSK0 0x00c4
#define DSI_INT_MSK1 0x00c8
#define DSI_INT_FORCE0 0x00d8
#define DSI_INT_FORCE1 0x00dc
#define DSI_MAX_REGISTER DSI_INT_FORCE1
int rk628_dsi_parse(struct rk628 *rk628, struct device_node *dsi_np);
void rk628_mipi_dsi_pre_enable(struct rk628 *rk628);
void rk628_mipi_dsi_enable(struct rk628 *rk628);
void rk628_dsi_disable(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,296 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#ifndef RK628_GPIO_H
#define RK628_GPIO_H
#define RK628_GPIO0_BASE 0x000D0000
#define RK628_GPIO1_BASE 0x000E0000
#define RK628_GPIO2_BASE 0x000F0000
#define RK628_GPIO3_BASE 0x00100000
#define RK628_GPIO_MAX_REGISTER (RK628_GPIO3_BASE + GPIO_VER_ID)
/* GPIO control registers */
#define GPIO_SWPORT_DR_L 0x00
#define GPIO_SWPORT_DR_H 0x04
#define GPIO_SWPORT_DDR_L 0x08
#define GPIO_SWPORT_DDR_H 0x0c
#define GPIO_INTEN_L 0x10
#define GPIO_INTEN_H 0x14
#define GPIO_INTMASK_L 0x18
#define GPIO_INTMASK_H 0x1c
#define GPIO_INTTYPE_L 0x20
#define GPIO_INTTYPE_H 0x24
#define GPIO_INT_POLARITY_L 0x28
#define GPIO_INT_POLARITY_H 0x2c
#define GPIO_INT_BOTHEDGE_L 0x30
#define GPIO_INT_BOTHEDGE_H 0x34
#define GPIO_DEBOUNCE_L 0x38
#define GPIO_DEBOUNCE_H 0x3c
#define GPIO_DBCLK_DIV_EN_L 0x40
#define GPIO_DBCLK_DIV_EN_H 0x44
#define GPIO_INT_STATUS 0x50
#define GPIO_INT_RAWSTATUS 0x58
#define GPIO_PORTS_EOI_L 0x60
#define GPIO_PORTS_EOI_H 0x64
#define GPIO_EXT_PORT 0x70
#define GPIO_VER_ID 0x78
#define GPIO_REG_LOW 0x0
#define GPIO_REG_HIGH 0x1
/* GPIO control registers */
#define GPIO_INTMASK 0x34
#define GPIO_PORTS_EOI 0x4c
#define BANK_OFFSET 32
#define GPIO_DIRECTION_OUT 1
#define GPIO_DIRECTION_IN 0
enum {
GPIO_HIGH_Z,
GPIO_PULL_UP,
GPIO_PULL_DOWN,
};
enum {
GPIO_BANK0 = 0,
GPIO_BANK1,
GPIO_BANK2,
GPIO_BANK3,
GPIO_BANKX = 9,
};
enum {
GPIO0_A0 = BANK_OFFSET * 0,
GPIO0_A1,
GPIO0_A2,
GPIO0_A3,
GPIO0_A4,
GPIO0_A5,
GPIO0_A6,
GPIO0_A7,
GPIO0_B0,
GPIO0_B1,
GPIO0_B2,
GPIO0_B3,
GPIO1_A0 = BANK_OFFSET * 1,
GPIO1_A1,
GPIO1_A2,
GPIO1_A3,
GPIO1_A4,
GPIO1_A5,
GPIO1_A6,
GPIO1_A7,
GPIO1_B0,
GPIO1_B1,
GPIO1_B2,
GPIO1_B3,
GPIO1_B4,
GPIO1_B5,
GPIO2_A0 = BANK_OFFSET * 2,
GPIO2_A1,
GPIO2_A2,
GPIO2_A3,
GPIO2_A4,
GPIO2_A5,
GPIO2_A6,
GPIO2_A7,
GPIO2_B0,
GPIO2_B1,
GPIO2_B2,
GPIO2_B3,
GPIO2_B4,
GPIO2_B5,
GPIO2_B6,
GPIO2_B7,
GPIO2_C0,
GPIO2_C1,
GPIO2_C2,
GPIO2_C3,
GPIO2_C4,
GPIO2_C5,
GPIO2_C6,
GPIO2_C7,
GPIO3_A0 = BANK_OFFSET * 3,
GPIO3_A1,
GPIO3_A2,
GPIO3_A3,
GPIO3_A4,
GPIO3_A5,
GPIO3_A6,
GPIO3_A7,
GPIO3_B0,
GPIO3_B1,
GPIO3_B2,
GPIO3_B3,
GPIO3_B4,
PIN_I2SM_SCK = BANK_OFFSET * 4 + 2,
PIN_I2SM_D,
PIN_I2SM_LR,
PIN_RXDDC_SCL,
PIN_RXDDC_SDA,
PIN_HDMIRX_CE,
PIN_JTAG_EN,
PIN_UART_SEL,
PIN_UART_RTS_EN,
PIN_UART_CTS_EN,
PIN_MUX,
};
struct rk628_pin_iomux_group {
unsigned int pins;
int bank;
int mux;
int iomux_base;
int gpio_base;
int pull_reg;
};
#define PINCTRL_GROUP(a, b, c, d, e, f) \
{.pins = a, .bank = b, .mux = c, .iomux_base = d, .gpio_base = e, .pull_reg = f}
static const struct rk628_pin_iomux_group rk628_pin_iomux_groups[] = {
PINCTRL_GROUP(GPIO0_A0, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON,
RK628_GPIO0_BASE, GRF_GPIO0A_P_CON),
PINCTRL_GROUP(GPIO0_A1, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON,
RK628_GPIO0_BASE, GRF_GPIO0A_P_CON),
PINCTRL_GROUP(GPIO0_A2, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON, RK628_GPIO0_BASE, 0),
PINCTRL_GROUP(GPIO0_A3, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON,
RK628_GPIO0_BASE, GRF_GPIO0A_P_CON),
PINCTRL_GROUP(GPIO0_A4, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON,
RK628_GPIO0_BASE, GRF_GPIO0A_P_CON),
PINCTRL_GROUP(GPIO0_A5, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON,
RK628_GPIO0_BASE, GRF_GPIO0A_P_CON),
PINCTRL_GROUP(GPIO0_A6, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON,
RK628_GPIO0_BASE, GRF_GPIO0A_P_CON),
PINCTRL_GROUP(GPIO0_A7, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON,
RK628_GPIO0_BASE, GRF_GPIO0A_P_CON),
PINCTRL_GROUP(GPIO0_B0, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON, RK628_GPIO0_BASE, 0),
PINCTRL_GROUP(GPIO0_B1, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON, RK628_GPIO0_BASE, 0),
PINCTRL_GROUP(GPIO0_B2, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON, RK628_GPIO0_BASE, 0),
PINCTRL_GROUP(GPIO0_B3, GPIO_BANK0, 1, GRF_GPIO0AB_SEL_CON, RK628_GPIO0_BASE, 0),
PINCTRL_GROUP(GPIO1_A0, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON,
RK628_GPIO1_BASE, GRF_GPIO1A_P_CON),
PINCTRL_GROUP(GPIO1_A1, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON,
RK628_GPIO1_BASE, GRF_GPIO1A_P_CON),
PINCTRL_GROUP(GPIO1_A2, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON,
RK628_GPIO1_BASE, GRF_GPIO1A_P_CON),
PINCTRL_GROUP(GPIO1_A3, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON,
RK628_GPIO1_BASE, GRF_GPIO1A_P_CON),
PINCTRL_GROUP(GPIO1_A4, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON,
RK628_GPIO1_BASE, GRF_GPIO1A_P_CON),
PINCTRL_GROUP(GPIO1_A5, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON,
RK628_GPIO1_BASE, GRF_GPIO1A_P_CON),
PINCTRL_GROUP(GPIO1_A6, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON,
RK628_GPIO1_BASE, GRF_GPIO1A_P_CON),
PINCTRL_GROUP(GPIO1_A7, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON,
RK628_GPIO1_BASE, GRF_GPIO1A_P_CON),
PINCTRL_GROUP(GPIO1_B0, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON, RK628_GPIO1_BASE, 0),
PINCTRL_GROUP(GPIO1_B1, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON, RK628_GPIO1_BASE, 0),
PINCTRL_GROUP(GPIO1_B2, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON, RK628_GPIO1_BASE, 0),
PINCTRL_GROUP(GPIO1_B3, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON, RK628_GPIO1_BASE, 0),
PINCTRL_GROUP(GPIO1_B4, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON, RK628_GPIO1_BASE, 0),
PINCTRL_GROUP(GPIO1_B5, GPIO_BANK1, 1, GRF_GPIO1AB_SEL_CON, RK628_GPIO1_BASE, 0),
PINCTRL_GROUP(GPIO2_A0, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2A_P_CON),
PINCTRL_GROUP(GPIO2_A1, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2A_P_CON),
PINCTRL_GROUP(GPIO2_A2, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2A_P_CON),
PINCTRL_GROUP(GPIO2_A3, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2A_P_CON),
PINCTRL_GROUP(GPIO2_A4, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2A_P_CON),
PINCTRL_GROUP(GPIO2_A5, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2A_P_CON),
PINCTRL_GROUP(GPIO2_A6, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2A_P_CON),
PINCTRL_GROUP(GPIO2_A7, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2A_P_CON),
PINCTRL_GROUP(GPIO2_B0, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2B_P_CON),
PINCTRL_GROUP(GPIO2_B1, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2B_P_CON),
PINCTRL_GROUP(GPIO2_B2, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2B_P_CON),
PINCTRL_GROUP(GPIO2_B3, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2B_P_CON),
PINCTRL_GROUP(GPIO2_B4, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2B_P_CON),
PINCTRL_GROUP(GPIO2_B5, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2B_P_CON),
PINCTRL_GROUP(GPIO2_B6, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2B_P_CON),
PINCTRL_GROUP(GPIO2_B7, GPIO_BANK2, 1, GRF_GPIO2AB_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2B_P_CON),
PINCTRL_GROUP(GPIO2_C0, GPIO_BANK2, 1, GRF_GPIO2C_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2C_P_CON),
PINCTRL_GROUP(GPIO2_C1, GPIO_BANK2, 1, GRF_GPIO2C_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2C_P_CON),
PINCTRL_GROUP(GPIO2_C2, GPIO_BANK2, 1, GRF_GPIO2C_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2C_P_CON),
PINCTRL_GROUP(GPIO2_C3, GPIO_BANK2, 1, GRF_GPIO2C_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2C_P_CON),
PINCTRL_GROUP(GPIO2_C4, GPIO_BANK2, 1, GRF_GPIO2C_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2C_P_CON),
PINCTRL_GROUP(GPIO2_C5, GPIO_BANK2, 1, GRF_GPIO2C_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2C_P_CON),
PINCTRL_GROUP(GPIO2_C6, GPIO_BANK2, 1, GRF_GPIO2C_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2C_P_CON),
PINCTRL_GROUP(GPIO2_C7, GPIO_BANK2, 1, GRF_GPIO2C_SEL_CON,
RK628_GPIO2_BASE, GRF_GPIO2C_P_CON),
PINCTRL_GROUP(GPIO3_A0, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3A_P_CON),
PINCTRL_GROUP(GPIO3_A1, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3A_P_CON),
PINCTRL_GROUP(GPIO3_A2, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3A_P_CON),
PINCTRL_GROUP(GPIO3_A3, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3A_P_CON),
PINCTRL_GROUP(GPIO3_A4, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, 0),
PINCTRL_GROUP(GPIO3_A5, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, 0),
PINCTRL_GROUP(GPIO3_A6, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, 0),
PINCTRL_GROUP(GPIO3_A7, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, 0),
PINCTRL_GROUP(GPIO3_B0, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3B_P_CON),
PINCTRL_GROUP(GPIO3_B1, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3B_P_CON),
PINCTRL_GROUP(GPIO3_B2, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3B_P_CON),
PINCTRL_GROUP(GPIO3_B3, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3B_P_CON),
PINCTRL_GROUP(GPIO3_B4, GPIO_BANK3, 1, GRF_GPIO3AB_SEL_CON,
RK628_GPIO3_BASE, GRF_GPIO3B_P_CON),
PINCTRL_GROUP(PIN_I2SM_SCK, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_I2SM_D, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_I2SM_LR, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_RXDDC_SCL, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_RXDDC_SDA, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_HDMIRX_CE, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_JTAG_EN, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_UART_SEL, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_UART_RTS_EN, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
PINCTRL_GROUP(PIN_UART_CTS_EN, GPIO_BANKX, 1, GRF_SYSTEM_CON3, 0, 0),
};
#endif // RK628_GPIO_H

View File

@@ -0,0 +1,263 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#ifndef RK628_GRF_H
#define RK628_GRF_H
#define GPIO_FUNC 0
#define MUX_FUNC1 1
#define MUX_FUNC2 2
#define MUX_FUNC3 3
/* GRF_SYSTEM_CON3 */
#define UART_CTS_DISABLE 0xB0
#define UART_CTS_ENABLE 0xB1
#define UART_RTS_DISABLE 0xA0
#define UART_RTS_ENABLE 0xA1
#define UART_IOMUX_DISABLE 0x90
#define UART_IOMUX_ENABLE 0x91
#define JTAG_DISABLE 0x80
#define JTAG_ENABLE 0x81
#define HDMIRX_CEC0 0x70
#define HDMIRX_CEC1 0x71
#define SELECT_RXDDC_SDA0 0x60
#define SELECT_RXDDC_SDA1 0x61
#define SELECT_RXDDC_SCL0 0x50
#define SELECT_RXDDC_SCL1 0x51
#define SELECT_I2S_LRM0 0x40
#define SELECT_I2S_LRM1 0x41
#define SELECT_I2S_DM0 0x30
#define SELECT_I2S_DM1 0x31
#define SELECT_I2S_SCKM0 0x20
#define SELECT_I2S_SCKM1 0x21
/* GPIO0_A */
#define GPIO_0A2 0x0a20
#define I2S_SCKM0 0x0a21
#define GPIO0A3 0x0a30
#define I2SLR_M0 0x0a31
#define GPIO0A4 0x0a40
#define I2SM0D0 0x0a41
#define UART_TXM1 0x0a42
#define GPIO0A5 0x0a50
#define I2SM0D1 0x0a51
#define UART_RXM1 0x0a52
#define GPIO0A6 0x0a60
#define I2SM0D2 0x0a61
#define UART_CTSNM1 0x0a62
#define GPIO0A7 0x0a70
#define I2SM0D3 0x0a71
#define UART_RTSNM1 0x0a72
/* GPIO0_B */
#define GPIO0B0 0x0b00
#define HPDIN 0x0b01
#define GPIO0B1 0x0b10
#define DDCSDATX 0x0b11
#define GPIO0B2 0x0b20
#define DDCSCLTX 0x0b21
#define GPIO0B3 0x0b30
#define CECTX 0x0b31
/* GPIO1_A */
#define GPIO1A0 0x1a00
#define TESTCLKOUT 0x1a01
#define GPIO1A1 0x1a10
#define XIPSFC_SCLK 0x1a11
#define GPIO1A2 0x1a20
#define I2SSCKM1 0x1a21
#define GPIO1A3 0x1a30
#define I2SM1LR 0x1a31
#define GPIO1A4 0x1a40
#define I2SM1D0 0x1a41
#define GPIO1A5 0x1a50
#define I2SM1D1 0x1a51
#define GPIO1A6 0x1a60
#define I2SM1D2 0x1a61
#define GPIO1A7 0x1a70
#define I2SM1D3 0x1a71
/* GPIO1_B */
#define GPIO1B0 0x1b00
#define HPDM0OUT 0x1b01
#define GPIO1B1 0x1b10
#define DDCM0SDARX 0x1b11
#define GPIO1B2 0x1b20
#define DDCM0SCLRX 0x1b21
#define GPIO1B3 0x1b30
#define CECM0RX 0x1b31
#define GPIO1B4 0x1b40
#define I2CS_SCL 0x1b41
#define I2CM_SCL 0x1b42
#define GPIO1B5 0x1b50
#define I2CS_SDA 0x1b51
#define I2CM_SDA 0x1b52
/* GPIO2_A */
#define GPIO2A0 0x2a00
#define VOPD0 0x2a01
#define GPIO2A1 0x2a10
#define VOPD1 0x2a11
#define GPIO2A2 0x2a20
#define VOPD2 0x2a21
#define GPIO2A3 0x2a30
#define VOPD3 0x2a31
#define GPIO2A4 0x2a40
#define VOPD4 0x2a41
#define GPIO2A5 0x2a50
#define VOPD5 0x2a51
#define GPIO2A6 0x2a60
#define VOPD6 0x2a61
#define GPIO2A7 0x2a70
#define VOPD7 0x2a71
/* GPIO2_B */
#define GPIO2B0 0x2b00
#define VOPD8 0x2b01
#define GPIO2B1 0x2b10
#define VOPD9 0x2b11
#define GPIO2B2 0x2b20
#define VOPD10 0x2b21
#define GPIO2B3 0x2b30
#define VOPD11 0x2b31
#define GPIO2B4 0x2b40
#define VOPD12 0x2b41
#define GPIO2B5 0x2b50
#define VOPD13 0x2b51
#define GPIO2B6 0x2b60
#define VOPD14 0x2b61
#define GPIO2B7 0x2b70
#define VOPD15 0x2b71
/* GPIO2_C */
#define GPIO2C0 0x2c00
#define VOPD16 0x2c01
#define XIPSFC_CSN 0x2c02
#define GPIO2C1 0x2c10
#define VOPD17 0x2c11
#define XIPSFC_MISO 0x2c12
#define GPIO2C2 0x2c20
#define VOPD18 0x2c21
#define XIPSFC_MOSI 0x2c22
#define GPIO2C3 0x2c30
#define VOPD19 0x2c31
#define RISVJTAG_TDO 0x2c32
#define UART_TXM0 0x2c33
#define GPIO2C4 0x2c40
#define VOPD20 0x2c41
#define RISVJTAG_TDI 0x2c42
#define UART_RXM0 0x2c43
#define GPIO2C5 0x2c50
#define VOPD21 0x2c51
#define RISVJTAG_TMS 0x2c52
#define UART_CTSNM0 0x2c53
#define GPIO2C6 0x2c60
#define VOPD22 0x2c61
#define RISVJTAG_TCK 0x2c62
#define UART_RTSNM0 0x2c63
#define GPIO2C7 0x2c70
#define VOPD23 0x2c71
#define RISVJTAG_TRSTN 0x2c72
/* GPIO3_A */
#define GPIO3A0 0x3a00
#define VOPDEN 0x3a01
#define GPIO3A1 0x3a10
#define VOPHSYNC 0x3a11
#define GPIO3A3 0x3a30
#define VOPVSYNC 0x3a31
#define GPIO3A4 0x3a40
#define HPDM1OUT 0x3a41
#define GPIO3A5 0x3a50
#define DDCM1SDARX 0x3a51
#define GPIO3A6 0x3a60
#define DDCM1SCLRX 0x3a61
#define GPIO3A7 0x3a70
#define CECM1RX 0x3a71
/* GPIO3_B */
#define GPIO3B0 0x3b00
#define VOPDCLK 0x3b01
#define GPIO3B1 0x3b10
#define GVIHPD 0x3b11
#define GPIO3B2 0x3b20
#define GVILOCK 0x3b21
#define GPIO3B4 0x3b40
#define SPIBOOT 0x3b41
#define INT 0x3b42
#endif // RK628_GRF_H

View File

@@ -0,0 +1,230 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include "linux/printk.h"
#include "rk628.h"
#include "rk628_config.h"
#include "rk628_combtxphy.h"
#include "rk628_gvi.h"
#include "panel.h"
int rk628_gvi_parse(struct rk628 *rk628, struct device_node *gvi_np)
{
const char *string;
u32 val;
int ret;
if (!of_device_is_available(gvi_np))
return -EINVAL;
rk628->output_mode = OUTPUT_MODE_GVI;
if (!of_property_read_u32(gvi_np, "gvi,lanes", &val))
rk628->gvi.lanes = val;
if (of_property_read_bool(gvi_np, "rockchip,division-mode"))
rk628->gvi.division_mode = true;
else
rk628->gvi.division_mode = false;
if (of_property_read_bool(gvi_np, "rockchip,gvi-frm-rst"))
rk628->gvi.frm_rst = true;
else
rk628->gvi.frm_rst = false;
if (!of_property_read_string(gvi_np, "bus-format", &string)) {
if (!strcmp(string, "rgb666"))
rk628->gvi.bus_format = GVI_MEDIA_BUS_FMT_RGB666_1X18;
else if (!strcmp(string, "rgb101010"))
rk628->gvi.bus_format = GVI_MEDIA_BUS_FMT_RGB101010_1X30;
else if (!strcmp(string, "yuyv8"))
rk628->gvi.bus_format = GVI_MEDIA_BUS_FMT_YUYV8_1X16;
else if (!strcmp(string, "yuyv10"))
rk628->gvi.bus_format = GVI_MEDIA_BUS_FMT_YUYV10_1X20;
else
rk628->gvi.bus_format = GVI_MEDIA_BUS_FMT_RGB888_1X24;
}
ret = rk628_panel_info_get(rk628, gvi_np);
if (ret)
return ret;
return 0;
}
static void rk628_gvi_get_info(struct rk628_gvi *gvi)
{
switch (gvi->bus_format) {
case GVI_MEDIA_BUS_FMT_RGB666_1X18:
gvi->byte_mode = 3;
gvi->color_depth = COLOR_DEPTH_RGB_YUV444_18BIT;
break;
case GVI_MEDIA_BUS_FMT_RGB888_1X24:
gvi->byte_mode = 4;
gvi->color_depth = COLOR_DEPTH_RGB_YUV444_24BIT;
break;
case GVI_MEDIA_BUS_FMT_RGB101010_1X30:
gvi->byte_mode = 4;
gvi->color_depth = COLOR_DEPTH_RGB_YUV444_30BIT;
break;
case GVI_MEDIA_BUS_FMT_YUYV8_1X16:
gvi->byte_mode = 3;
gvi->color_depth = COLOR_DEPTH_YUV422_16BIT;
break;
case GVI_MEDIA_BUS_FMT_YUYV10_1X20:
gvi->byte_mode = 3;
gvi->color_depth = COLOR_DEPTH_YUV422_20BIT;
break;
default:
gvi->byte_mode = 3;
gvi->color_depth = COLOR_DEPTH_RGB_YUV444_24BIT;
pr_err("unsupported bus_format: 0x%x\n", gvi->bus_format);
break;
}
}
static unsigned int rk628_gvi_get_lane_rate(struct rk628 *rk628)
{
const struct rk628_display_mode *mode = &rk628->dst_mode;
struct rk628_gvi *gvi = &rk628->gvi;
u32 lane_bit_rate, min_lane_rate = 500000, max_lane_rate = 4000000;
u64 total_bw;
/**
* [ENCODER TOTAL BIT-RATE](bps) = [byte mode](byte) x 10 / [pixel clock](HZ)
*
* lane_bit_rate = [total bit-rate](bps) / [lane number]
*
* 500Mbps <= lane_bit_rate <= 4Gbps
*/
total_bw = (u64)gvi->byte_mode * 10 * mode->clock;/* Kbps */
do_div(total_bw, gvi->lanes);
lane_bit_rate = total_bw;
if (lane_bit_rate < min_lane_rate)
lane_bit_rate = min_lane_rate;
if (lane_bit_rate > max_lane_rate)
lane_bit_rate = max_lane_rate;
return lane_bit_rate;
}
static void rk628_gvi_pre_enable(struct rk628 *rk628, struct rk628_gvi *gvi)
{
/* gvi reset */
rk628_i2c_update_bits(rk628, GVI_SYS_RST, SYS_RST_SOFT_RST,
SYS_RST_SOFT_RST);
udelay(10);
rk628_i2c_update_bits(rk628, GVI_SYS_RST, SYS_RST_SOFT_RST, 0);
udelay(10);
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, SYS_CTRL0_LANE_NUM_MASK,
SYS_CTRL0_LANE_NUM(gvi->lanes - 1));
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, SYS_CTRL0_BYTE_MODE_MASK,
SYS_CTRL0_BYTE_MODE(gvi->byte_mode ==
3 ? 0 : (gvi->byte_mode == 4 ? 1 : 2)));
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, SYS_CTRL0_SECTION_NUM_MASK,
SYS_CTRL0_SECTION_NUM(gvi->division_mode));
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, SW_SPLIT_EN,
gvi->division_mode ? SW_SPLIT_EN : 0);
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL1, SYS_CTRL1_DUAL_PIXEL_EN,
gvi->division_mode ? SYS_CTRL1_DUAL_PIXEL_EN : 0);
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, SYS_CTRL0_FRM_RST_EN,
gvi->frm_rst ? SYS_CTRL0_FRM_RST_EN : 0);
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL1, SYS_CTRL1_LANE_ALIGN_EN, 0);
}
static void rk628_gvi_enable_color_bar(struct rk628 *rk628,
struct rk628_gvi *gvi)
{
const struct rk628_display_mode *mode = &rk628->dst_mode;
u16 vm_hactive, vm_hback_porch, vm_hsync_len;
u16 vm_vactive, vm_vback_porch, vm_vsync_len;
u16 hsync_len, hact_st, hact_end, htotal;
u16 vsync_len, vact_st, vact_end, vtotal;
vm_hactive = mode->hdisplay;
vm_hsync_len = mode->hsync_end - mode->hsync_start;
vm_hback_porch = mode->htotal - mode->hsync_end;
vm_vactive = mode->vdisplay;
vm_vsync_len = mode->vsync_end - mode->vsync_start;
vm_vback_porch = mode->vtotal - mode->vsync_end;
if (gvi->division_mode) {
hsync_len = vm_hsync_len / 2;
hact_st = (vm_hsync_len + vm_hback_porch) / 2;
hact_end = (vm_hsync_len + vm_hback_porch + vm_hactive) / 2;
htotal = mode->htotal / 2;
} else {
hsync_len = vm_hsync_len;
hact_st = vm_hsync_len + vm_hback_porch;
hact_end = vm_hsync_len + vm_hback_porch + vm_hactive;
htotal = mode->htotal;
}
vsync_len = vm_vsync_len;
vact_st = vsync_len + vm_vback_porch;
vact_end = vact_st + vm_vactive;
vtotal = mode->vtotal;
rk628_i2c_write(rk628, GVI_COLOR_BAR_HTIMING0,
hact_st << 16 | hsync_len);
rk628_i2c_write(rk628, GVI_COLOR_BAR_HTIMING1,
(htotal - 1) << 16 | hact_end);
rk628_i2c_write(rk628, GVI_COLOR_BAR_VTIMING0,
vact_st << 16 | vsync_len);
rk628_i2c_write(rk628, GVI_COLOR_BAR_VTIMING1,
(vtotal - 1) << 16 | vact_end);
rk628_i2c_update_bits(rk628, GVI_COLOR_BAR_CTRL, COLOR_BAR_EN, 0);
}
static void rk628_gvi_post_enable(struct rk628 *rk628, struct rk628_gvi *gvi)
{
u32 val;
val = SYS_CTRL0_GVI_EN | SYS_CTRL0_AUTO_GATING;
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, val, 3);
}
void rk628_gvi_enable(struct rk628 *rk628)
{
struct rk628_gvi *gvi = &rk628->gvi;
unsigned int rate;
rk628_gvi_get_info(gvi);
rate = rk628_gvi_get_lane_rate(rk628);
/* set gvi_hpd and gvi_lock mux */
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x06000600);
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_GVI));
rk628_combtxphy_set_bus_width(rk628, rate);
rk628_combtxphy_set_gvi_division_mode(rk628, gvi->division_mode);
rk628_combtxphy_set_mode(rk628, PHY_MODE_VIDEO_GVI);
rate = rk628_combtxphy_get_bus_width(rk628);
rk628_combtxphy_power_on(rk628);
rk628_gvi_pre_enable(rk628, gvi);
rk628_panel_prepare(rk628);
rk628_gvi_enable_color_bar(rk628, gvi);
rk628_gvi_post_enable(rk628, gvi);
rk628_panel_enable(rk628);
dev_info(rk628->dev,
"GVI-Link bandwidth: %d x %d Mbps, Byte mode: %d, Color Depty: %d, %s division mode\n",
rate, gvi->lanes, gvi->byte_mode, gvi->color_depth,
gvi->division_mode ? "two" : "one");
}
void rk628_gvi_disable(struct rk628 *rk628)
{
rk628_panel_disable(rk628);
rk628_panel_unprepare(rk628);
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, SYS_CTRL0_GVI_EN, 0);
rk628_combtxphy_power_off(rk628);
}

View File

@@ -0,0 +1,218 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#ifndef RK628_GVI_H
#define RK628_GVI_H
#include "rk628.h"
#define GVI_BASE 0x80000
#define HOSTREG(x) ((x) + GVI_BASE)
#define GVI_SYS_CTRL0 HOSTREG(0x0000)
#define GVI_SYS_CTRL1 HOSTREG(0x0004)
#define GVI_SYS_CTRL2 HOSTREG(0x0008)
#define GVI_SYS_CTRL3 HOSTREG(0x000c)
#define GVI_VERSION HOSTREG(0x0010)
#define GVI_SYS_RST HOSTREG(0x0014)
#define GVI_LINE_FLAG HOSTREG(0x0018)
#define GVI_STATUS HOSTREG(0x001c)
#define GVI_PLL_LOCK_TIMEOUT HOSTREG(0x0030)
#define GVI_HTPDN_TIMEOUT HOSTREG(0x0034)
#define GVI_LOCKN_TIMEOUT HOSTREG(0x0038)
#define GVI_WAIT_LOCKN HOSTREG(0x003C)
#define GVI_WAIT_HTPDN HOSTREG(0x0040)
#define GVI_INTR_EN HOSTREG(0x0050)
#define GVI_INTR_CLR HOSTREG(0x0054)
#define GVI_INTR_RAW_STATUS HOSTREG(0x0058)
#define GVI_INTR_STATUS HOSTREG(0x005c)
#define GVI_COLOR_BAR_CTRL HOSTREG(0x0060)
#define GVI_COLOR_BAR_HTIMING0 HOSTREG(0x0070)
#define GVI_COLOR_BAR_HTIMING1 HOSTREG(0x0074)
#define GVI_COLOR_BAR_VTIMING0 HOSTREG(0x0078)
#define GVI_COLOR_BAR_VTIMING1 HOSTREG(0x007c)
/* SYS_CTRL0 */
#define SYS_CTRL0_GVI_EN BIT(0)
#define SYS_CTRL0_AUTO_GATING BIT(1)
#define SYS_CTRL0_FRM_RST_EN BIT(2)
#define SYS_CTRL0_FRM_RST_MODE BIT(3)
#define SYS_CTRL0_LANE_NUM_MASK GENMASK(7, 4)
#define SYS_CTRL0_LANE_NUM(x) UPDATE(x, 7, 4)
#define SYS_CTRL0_BYTE_MODE_MASK GENMASK(9, 8)
#define SYS_CTRL0_BYTE_MODE(x) UPDATE(x, 9, 8)
#define SYS_CTRL0_SECTION_NUM_MASK GENMASK(11, 10)
#define SYS_CTRL0_SECTION_NUM(x) UPDATE(x, 11, 10)
#define SYS_CTRL0_CDR_ENDIAN_SWAP BIT(12)
#define SYS_CTRL0_PACK_BYTE_SWAP BIT(13)
#define SYS_CTRL0_PACK_ENDIAN_SWAP BIT(14)
#define SYS_CTRL0_ENC8B10B_ENDIAN_SWAP BIT(15)
#define SYS_CTRL0_CDR_EN BIT(16)
#define SYS_CTRL0_ALN_EN BIT(17)
#define SYS_CTRL0_NOR_EN BIT(18)
#define SYS_CTRL0_ALN_NOR_MODE BIT(19)
#define SYS_CTRL0_GVI_MASK GENMASK(19, 16)
#define SYS_CTRL0_GVI_GN_EN(x) UPDATE(x, 19, 16)
#define SYS_CTRL0_SCRAMBLER_EN BIT(20)
#define SYS_CTRL0_ENCODE8B10B_EN BIT(21)
#define SYS_CTRL0_INIT_RD_EN BIT(22)
#define SYS_CTRL0_INIT_RD_VALUE BIT(23)
#define SYS_CTRL0_FORCE_HTPDN_EN BIT(24)
#define SYS_CTRL0_FORCE_HTPDN_VALUE BIT(25)
#define SYS_CTRL0_FORCE_PLL_EN BIT(26)
#define SYS_CTRL0_FORCE_PLL_VALUE BIT(27)
#define SYS_CTRL0_FORCE_LOCKN_EN BIT(28)
#define SYS_CTRL0_FORCE_LOCKN_VALUE BIT(29)
/* SYS_CTRL1 */
#define SYS_CTRL1_COLOR_DEPTH_MASK GENMASK(3, 0)
#define SYS_CTRL1_COLOR_DEPTH(x) UPDATE(x, 3, 0)
#define SYS_CTRL1_DUAL_PIXEL_EN BIT(4)
#define SYS_CTRL1_TIMING_ALIGN_EN BIT(8)
#define SYS_CTRL1_LANE_ALIGN_EN BIT(9)
#define SYS_CTRL1_DUAL_PIXEL_SWAP BIT(12)
#define SYS_CTRL1_RB_SWAP BIT(13)
#define SYS_CTRL1_YC_SWAP BIT(14)
#define SYS_CTRL1_WHOLE_FRM_EN BIT(16)
#define SYS_CTRL1_NOR_PROTECT BIT(17)
#define SYS_CTRL1_RD_WCNT_UPDATE BIT(31)
/* SYS_CTRL2 */
#define SYS_CTRL2_AFIFO_READ_THOLD_MASK GENMASK(7, 0)
#define SYS_CTRL2_AFIFO_READ_THOLD(x) UPDATE(x, 7, 0)
#define SYS_CTRL2_AFIFO_ALMOST_FULL_THOLD_MASK GENMASK(23, 16)
#define SYS_CTRL2_AFIFO_ALMOST_FULL_THOLD(x) UPDATE(x, 23, 16)
#define SYS_CTRL2_AFIFO_ALMOST_EMPTY_THOLD_MASK GENMASK(31, 24)
#define SYS_CTRL2_AFIFO_ALMOST_EMPTY_THOLD(x) UPDATE(x, 31, 24)
/* SYS_CTRL3 */
#define SYS_CTRL3_LANE0_SEL_MASK GENMASK(2, 0)
#define SYS_CTRL3_LANE0_SEL(x) UPDATE(x, 2, 0)
#define SYS_CTRL3_LANE1_SEL_MASK GENMASK(6, 4)
#define SYS_CTRL3_LANE1_SEL(x) UPDATE(x, 6, 4)
#define SYS_CTRL3_LANE2_SEL_MASK GENMASK(10, 8)
#define SYS_CTRL3_LANE2_SEL(x) UPDATE(x, 10, 8)
#define SYS_CTRL3_LANE3_SEL_MASK GENMASK(14, 12)
#define SYS_CTRL3_LANE3_SEL(x) UPDATE(x, 14, 12)
#define SYS_CTRL3_LANE4_SEL_MASK GENMASK(18, 16)
#define SYS_CTRL3_LANE4_SEL(x) UPDATE(x, 18, 16)
#define SYS_CTRL3_LANE5_SEL_MASK GENMASK(22, 20)
#define SYS_CTRL3_LANE5_SEL(x) UPDATE(x, 22, 20)
#define SYS_CTRL3_LANE6_SEL_MASK GENMASK(26, 24)
#define SYS_CTRL3_LANE6_SEL(x) UPDATE(x, 26, 24)
#define SYS_CTRL3_LANE7_SEL_MASK GENMASK(30, 28)
#define SYS_CTRL3_LANE7_SEL(x) UPDATE(x, 30, 28)
/* VERSIION */
#define VERSION_VERSION(x) UPDATE(x, 31, 0)
/* SYS_RESET*/
#define SYS_RST_SOFT_RST BIT(0)
/* LINE_FLAG */
#define LINE_FLAG_LANE_FLAG0_MASK GENMASK(15, 0)
#define LINE_FLAG_LANE_FLAG0(x) UPDATE(x, 15, 0)
#define LINE_FLAG_LANE_FLAG1_MASK GENMASK(31, 16)
#define LINE_FLAG_LANE_FLAG1(x) UPDATE(x, 31, 16)
/* STATUS */
#define STATUS_HTDPN BIT(4)
#define STATUS_LOCKN BIT(5)
#define STATUS_PLL_LOCKN BIT(6)
#define STATUS_AFIFO0_WCNT_MASK GENMASK(23, 16)
#define STATUS_AFIFO0_WCNT(x) UPDATE(x, 23, 16)
#define STATUS_AFIFO1_WCNT_MASK GENMASK(31, 24)
#define STATUS_AFIFO1_WCNT(x) UPDATE(x, 31, 24)
/* PLL_LTIMEOUT */
#define PLL_LOCK_TIMEOUT_PLL_LOCK_TIME_OUT_MASK GENMASK(31, 0)
#define PLL_LOCK_TIMEOUT_PLL_LOCK_TIME_OUT(x) UPDATE(x, 31, 0)
/* HTPDNEOUT */
#define HTPDN_TIMEOUT_HTPDN_TIME_OUT_MASK GENMASK(31, 0)
#define HTPDN_TIMEOUT_HTPDN_TIME_OUT(x) UPDATE(x, 31, 0)
/* LOCKNEOUT */
#define LOCKN_TIMEOUT_LOCKN_TIME_OUT_MASK GENMASK(31, 0)
#define LOCKN_TIMEOUT_LOCKN_TIME_OUT(x) UPDATE(x, 31, 0)
/* WAIT_LOCKN */
#define WAIT_LOCKN_WAIT_LOCKN_TIME_MASK GENMASK(30, 0)
#define WAIT_LOCKN_WAIT_LOCKN_TIME(x) UPDATE(x, 30, 0)
#define WAIT_LOCKN_WAIT_LOCKN_TIME_EN BIT(31)
/* WAIT_HTPDN */
#define WAIT_HTPDN_WAIT_HTPDN_TIME_MASK GENMASK(30, 0)
#define WAIT_HTPDN_WAIT_HTPDN_TIME(x) UPDATE(x, 30, 0)
#define WAIT_HTPDN_WAIT_HTPDN_EN BIT(31)
/* INTR_EN */
#define INTR_EN_INTR_FRM_ST_EN BIT(0)
#define INTR_EN_INTR_PLL_LOCK_EN BIT(1)
#define INTR_EN_INTR_HTPDN_EN BIT(2)
#define INTR_EN_INTR_LOCKN_EN BIT(3)
#define INTR_EN_INTR_PLL_TIMEOUT_EN BIT(4)
#define INTR_EN_INTR_HTPDN_TIMEOUT_EN BIT(5)
#define INTR_EN_INTR_LOCKN_TIMEOUT_EN BIT(6)
#define INTR_EN_INTR_LINE_FLAG0_EN BIT(8)
#define INTR_EN_INTR_LINE_FLAG1_EN BIT(9)
#define INTR_EN_INTR_AFIFO_OVERFLOW_EN BIT(10)
#define INTR_EN_INTR_AFIFO_UNDERFLOW_EN BIT(11)
#define INTR_EN_INTR_PLL_ERR_EN BIT(12)
#define INTR_EN_INTR_HTPDN_ERR_EN BIT(13)
#define INTR_EN_INTR_LOCKN_ERR_EN BIT(14)
/* INTR_CLR*/
#define INTR_CLR_INTR_FRM_ST_CLR BIT(0)
#define INTR_CLR_INTR_PLL_LOCK_CLR BIT(1)
#define INTR_CLR_INTR_HTPDN_CLR BIT(2)
#define INTR_CLR_INTR_LOCKN_CLR BIT(3)
#define INTR_CLR_INTR_PLL_TIMEOUT_CLR BIT(4)
#define INTR_CLR_INTR_HTPDN_TIMEOUT_CLR BIT(5)
#define INTR_CLR_INTR_LOCKN_TIMEOUT_CLR BIT(6)
#define INTR_CLR_INTR_LINE_FLAG0_CLR BIT(8)
#define INTR_CLR_INTR_LINE_FLAG1_CLR BIT(9)
#define INTR_CLR_INTR_AFIFO_OVERFLOW_CLR BIT(10)
#define INTR_CLR_INTR_AFIFO_UNDERFLOW_CLR BIT(11)
#define INTR_CLR_INTR_PLL_ERR_CLR BIT(12)
#define INTR_CLR_INTR_HTPDN_ERR_CLR BIT(13)
#define INTR_CLR_INTR_LOCKN_ERR_CLR BIT(14)
/* INTR_RAW_STATUS */
#define INTR_RAW_STATUS_RAW_INTR_FRM_ST BIT(0)
#define INTR_RAW_STATUS_RAW_INTR_PLL_LOCK BIT(1)
#define INTR_RAW_STATUS_RAW_INTR_HTPDN BIT(2)
#define INTR_RAW_STATUS_RAW_INTR_LOCKN BIT(3)
#define INTR_RAW_STATUS_RAW_INTR_PLL_TIMEOUT BIT(4)
#define INTR_RAW_STATUS_RAW_INTR_HTPDN_TIMEOUT BIT(5)
#define INTR_RAW_STATUS_RAW_INTR_LOCKN_TIMEOUT BIT(6)
#define INTR_RAW_STATUS_RAW_INTR_LINE_FLAG0 BIT(8)
#define INTR_RAW_STATUS_RAW_INTR_LINE_FLAG1 BIT(9)
#define INTR_RAW_STATUS_RAW_INTR_AFIFO_OVERFLOW BIT(10)
#define INTR_RAW_STATUS_RAW_INTR_AFIFO_UNDERFLOW BIT(11)
#define INTR_RAW_STATUS_RAW_INTR_PLL_ERR BIT(12)
#define INTR_RAW_STATUS_RAW_INTR_HTPDN_ERR BIT(13)
#define INTR_RAW_STATUS_RAW_INTR_LOCKN_ERR BIT(14)
/* INTR_STATUS */
#define INTR_STATUS_INTR_FRM_ST BIT(0)
#define INTR_STATUS_INTR_PLL_LOCK BIT(1)
#define INTR_STATUS_INTR_HTPDN BIT(2)
#define INTR_STATUS_INTR_LOCKN BIT(3)
#define INTR_STATUS_INTR_PLL_TIMEOUT BIT(4)
#define INTR_STATUS_INTR_HTPDN_TIMEOUT BIT(5)
#define INTR_STATUS_INTR_LOCKN_TIMEOUT BIT(6)
#define INTR_STATUS_INTR_LINE_FLAG0 BIT(8)
#define INTR_STATUS_INTR_LINE_FLAG1 BIT(9)
#define INTR_STATUS_INTR_AFIFO_OVERFLOW BIT(10)
#define INTR_STATUS_INTR_AFIFO_UNDERFLOW BIT(11)
#define INTR_STATUS_INTR_PLL_ERR BIT(12)
#define INTR_STATUS_INTR_HTPDN_ERR BIT(13)
#define INTR_STATUS_INTR_LOCKN_ERR BIT(14)
/* COLOR_BAR_CTRL */
#define COLOR_BAR_EN BIT(0)
#define COLOR_DEPTH_RGB_YUV444_18BIT 0
#define COLOR_DEPTH_RGB_YUV444_24BIT 1
#define COLOR_DEPTH_RGB_YUV444_30BIT 2
#define COLOR_DEPTH_YUV422_16BIT 8
#define COLOR_DEPTH_YUV422_20BIT 9
int rk628_gvi_parse(struct rk628 *rk628, struct device_node *gvi_np);
void rk628_gvi_enable(struct rk628 *rk628);
void rk628_gvi_disable(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,777 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Chen Shunqing <csq@rock-chips.com>
*/
#include <linux/gpio/consumer.h>
#include <linux/of_device.h>
#include "rk628.h"
#include "rk628_combrxphy.h"
#include "rk628_config.h"
#include "rk628_hdmirx.h"
#define POLL_INTERVAL_MS 1000
#define MODETCLK_CNT_NUM 1000
#define MODETCLK_HZ 49500000
#define RXPHY_CFG_MAX_TIMES 1
static u8 debug;
static u8 edid_init_data[] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x49, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x12, 0x1E, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78,
0x0A, 0x0D, 0xC9, 0xA0, 0x57, 0x47, 0x98, 0x27,
0x12, 0x48, 0x4C, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A,
0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
0x45, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E,
0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x50,
0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x6F, 0x72,
0x0A, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFD,
0x00, 0x14, 0x78, 0x01, 0xFF, 0x1D, 0x00, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x18,
0x02, 0x03, 0x13, 0x71, 0x40, 0x23, 0x09, 0x07,
0x01, 0x83, 0x01, 0x00, 0x00, 0x65, 0x03, 0x0C,
0x00, 0x10, 0x00, 0x02, 0x3A, 0x80, 0x18, 0x71,
0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45, 0x00, 0x20,
0xC2, 0x31, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17,
};
struct rk628_hdmi_mode {
u32 hdisplay;
u32 hstart;
u32 hend;
u32 htotal;
u32 vdisplay;
u32 vstart;
u32 vend;
u32 vtotal;
u32 clock;
unsigned int flags;
};
struct rk628_hdmirx {
bool plugin;
bool res_change;
struct rk628_hdmi_mode mode;
u32 input_format;
u32 fs_audio;
bool audio_present;
bool hpd_output_inverted;
bool src_mode_4K_yuv420;
bool phy_lock;
};
static void rk628_hdmirx_ctrl_enable(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_INPUT_MODE_MASK,
SW_INPUT_MODE(INPUT_MODE_HDMI));
rk628_i2c_write(rk628, HDMI_RX_HDMI20_CONTROL, 0x10001f10);
rk628_i2c_write(rk628, HDMI_RX_HDMI_MODE_RECOVER, 0x00000021);
rk628_i2c_write(rk628, HDMI_RX_PDEC_CTRL, 0xbfff8011);
rk628_i2c_write(rk628, HDMI_RX_PDEC_ASP_CTRL, 0x00000040);
rk628_i2c_write(rk628, HDMI_RX_HDMI_RESMPL_CTRL, 0x00000001);
rk628_i2c_write(rk628, HDMI_RX_HDMI_SYNC_CTRL, 0x00000014);
rk628_i2c_write(rk628, HDMI_RX_PDEC_ERR_FILTER, 0x00000008);
rk628_i2c_write(rk628, HDMI_RX_SCDC_I2CCONFIG, 0x01000000);
rk628_i2c_write(rk628, HDMI_RX_SCDC_CONFIG, 0x00000001);
rk628_i2c_write(rk628, HDMI_RX_SCDC_WRDATA0, 0xabcdef01);
rk628_i2c_write(rk628, HDMI_RX_CHLOCK_CONFIG, 0x0030c15c);
rk628_i2c_write(rk628, HDMI_RX_HDMI_ERROR_PROTECT, 0x000d0c98);
rk628_i2c_write(rk628, HDMI_RX_MD_HCTRL1, 0x00000010);
rk628_i2c_write(rk628, HDMI_RX_MD_HCTRL2, 0x00001738);
rk628_i2c_write(rk628, HDMI_RX_MD_VCTRL, 0x00000002);
rk628_i2c_write(rk628, HDMI_RX_MD_VTH, 0x0000073a);
rk628_i2c_write(rk628, HDMI_RX_MD_IL_POL, 0x00000004);
rk628_i2c_write(rk628, HDMI_RX_PDEC_ACRM_CTRL, 0x00000000);
rk628_i2c_write(rk628, HDMI_RX_HDMI_DCM_CTRL, 0x00040414);
rk628_i2c_write(rk628, HDMI_RX_HDMI_CKM_EVLTM, 0x00103e70);
rk628_i2c_write(rk628, HDMI_RX_HDMI_CKM_F, 0x0c1c0b54);
rk628_i2c_write(rk628, HDMI_RX_HDMI_RESMPL_CTRL, 0x00000001);
rk628_i2c_update_bits(rk628, HDMI_RX_HDCP_SETTINGS,
HDMI_RESERVED_MASK |
FAST_I2C_MASK |
ONE_DOT_ONE_MASK |
FAST_REAUTH_MASK,
HDMI_RESERVED(1) |
FAST_I2C(0) |
ONE_DOT_ONE(1) |
FAST_REAUTH(1));
}
static void rk628_hdmirx_video_unmute(struct rk628 *rk628, u8 unmute)
{
rk628_i2c_update_bits(rk628, HDMI_RX_DMI_DISABLE_IF, VID_ENABLE_MASK, VID_ENABLE(unmute));
}
static void rk628_hdmirx_hpd_ctrl(struct rk628 *rk628, bool en)
{
u8 en_level, set_level;
struct rk628_hdmirx *hdmirx = rk628->hdmirx;
dev_dbg(rk628->dev, "%s: %sable, hpd invert:%d\n", __func__,
en ? "en" : "dis", hdmirx->hpd_output_inverted);
en_level = hdmirx->hpd_output_inverted ? 0 : 1;
set_level = en ? en_level : !en_level;
rk628_i2c_update_bits(rk628, HDMI_RX_HDMI_SETUP_CTRL,
HOT_PLUG_DETECT_MASK, HOT_PLUG_DETECT(set_level));
}
static void rk628_hdmirx_disable_edid(struct rk628 *rk628)
{
rk628_hdmirx_hpd_ctrl(rk628, false);
rk628_hdmirx_video_unmute(rk628, 0);
}
static void rk628_hdmirx_enable_edid(struct rk628 *rk628)
{
rk628_hdmirx_hpd_ctrl(rk628, true);
}
static int tx_5v_power_present(struct rk628 *rk628)
{
bool ret;
int val, i, cnt;
/* Direct Mode */
if (!rk628->plugin_det_gpio)
return 1;
cnt = 0;
for (i = 0; i < 5; i++) {
val = gpiod_get_value(rk628->plugin_det_gpio);
if (val > 0)
cnt++;
usleep_range(500, 600);
}
ret = (cnt >= 3) ? 1 : 0;
dev_dbg(rk628->dev, "%s: %d\n", __func__, ret);
return ret;
}
static int rk628_hdmirx_init_edid(struct rk628 *rk628)
{
struct rk628_display_mode *src_mode;
struct rk628_hdmirx *hdmirx = rk628->hdmirx;
u32 val;
u8 csum = 0;
int i, base, j;
src_mode = rk628_display_get_src_mode(rk628);
for (j = 0, base = 0x36; j < 2; j++) {
csum = 0;
/* clock-frequency */
edid_init_data[base + 1] = ((src_mode->clock / 10) & 0xff00) >> 8;
edid_init_data[base] = (src_mode->clock / 10) & 0xff;
/* hactive low 8 bits */
edid_init_data[base + 2] = src_mode->hdisplay & 0xff;
/* hblanking low 8 bits */
val = src_mode->htotal - src_mode->hdisplay;
edid_init_data[base + 3] = val & 0xff;
/* hactive high 4 bits & hblanking low 4 bits */
edid_init_data[base + 4] =
((src_mode->hdisplay & 0xf00) >> 4) + ((val & 0xf00) >> 8);
/* vactive low 8 bits */
edid_init_data[base + 5] = src_mode->vdisplay & 0xff;
/* vblanking low 8 bits */
val = src_mode->vtotal - src_mode->vdisplay;
edid_init_data[base + 6] = val & 0xff;
/* vactive high 4 bits & vblanking low 4 bits */
edid_init_data[base + 7] =
((src_mode->vdisplay & 0xf00) >> 4) + ((val & 0xf00) >> 8);
/* hsync pulse offset low 8 bits */
val = src_mode->hsync_start - src_mode->hdisplay;
edid_init_data[base + 8] = val & 0xff;
/* hsync pulse width low 8 bits */
val = src_mode->hsync_end - src_mode->hsync_start;
edid_init_data[base + 9] = val & 0xff;
/* vsync pulse offset low 4 bits & vsync pulse width low 4 bits */
val = ((src_mode->vsync_start - src_mode->vdisplay) & 0xf) << 4;
edid_init_data[base + 10] = val;
edid_init_data[base + 10] += (src_mode->vsync_end - src_mode->vsync_start) & 0xf;
/* 6~7bits:hsync pulse offset;
* 4~6bits:hsync pulse width;
* 2~3bits:vsync pulse offset;
* 0~1bits:vsync pulse width
*/
edid_init_data[base + 11] =
((src_mode->hsync_start - src_mode->hdisplay) & 0x300) >> 2;
edid_init_data[base + 11] +=
((src_mode->hsync_end - src_mode->hsync_start) & 0x700) >> 4;
edid_init_data[base + 11] +=
((src_mode->vsync_start - src_mode->vdisplay) & 0x30) >> 2;
edid_init_data[base + 11] +=
((src_mode->vsync_end - src_mode->vsync_start) & 0x30) >> 4;
edid_init_data[base + 17] = 0x18;
if (src_mode->flags & DRM_MODE_FLAG_PHSYNC)
edid_init_data[base + 17] |= 0x2;
if (src_mode->flags & DRM_MODE_FLAG_PVSYNC)
edid_init_data[base + 17] |= 0x4;
if (hdmirx->src_mode_4K_yuv420 && src_mode->clock == 594000) {
edid_init_data[0x80 + 0x2] = 0x16;
edid_init_data[0x80 + 0x13] = 0xe2;
edid_init_data[0x80 + 0x14] = 0x0E;
edid_init_data[0x80 + 0x15] = 0x61;
base += (0x5d + 0x3);
} else {
base += 0x5d;
}
for (i = 0; i < 127; i++)
csum += edid_init_data[i + j * 128];
edid_init_data[127 + j * 128] = (u8)0 - csum;
}
return 0;
}
static int rk628_hdmirx_set_edid(struct rk628 *rk628)
{
int i;
u32 val;
u16 edid_len;
rk628_hdmirx_disable_edid(rk628);
if (!rk628->plugin_det_gpio)
return 0;
/* edid access by apb when write, i2c slave addr: 0x0 */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_ADAPTER_I2CSLADR_MASK |
SW_EDID_MODE_MASK,
SW_ADAPTER_I2CSLADR(0) |
SW_EDID_MODE(1));
rk628_hdmirx_init_edid(rk628);
edid_len = ARRAY_SIZE(edid_init_data);
for (i = 0; i < edid_len; i++)
rk628_i2c_write(rk628, EDID_BASE + i * 4, edid_init_data[i]);
/* read out for debug */
if (debug >= 3) {
pr_info("====== Read EDID: ======\n");
for (i = 0; i < edid_len; i++) {
rk628_i2c_read(rk628, EDID_BASE + i * 4, &val);
pr_info("0x%02x ", val);
if ((i + 1) % 8 == 0)
pr_info("\n");
}
pr_info("============\n");
}
/* edid access by RX's i2c, i2c slave addr: 0x0 */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_ADAPTER_I2CSLADR_MASK |
SW_EDID_MODE_MASK,
SW_ADAPTER_I2CSLADR(0) |
SW_EDID_MODE(0));
mdelay(1);
return 0;
}
static int rk628_hdmirx_phy_power_on(struct rk628 *rk628, int f)
{
int ret;
bool rxphy_pwron = false;
if (rxphy_pwron) {
dev_info(rk628->dev, "rxphy already power on, power off!\n");
ret = rk628_combrxphy_power_off(rk628);
if (ret)
dev_info(rk628->dev, "hdmi rxphy power off failed!\n");
else
rxphy_pwron = false;
}
udelay(1000);
if (rxphy_pwron == false) {
ret = rk628_combrxphy_power_on(rk628, f);
if (ret) {
rxphy_pwron = false;
dev_info(rk628->dev, "hdmi rxphy power on failed\n");
} else {
rxphy_pwron = true;
dev_info(rk628->dev, "hdmi rxphy power on success\n");
}
}
dev_info(rk628->dev, "%s:rxphy_pwron=%d\n", __func__, rxphy_pwron);
return ret;
}
static void rk628_hdmirx_get_timing(struct rk628 *rk628)
{
u32 hact, vact, htotal, vtotal, fps, status;
u32 val;
u32 modetclk_cnt_hs, modetclk_cnt_vs, hs, vs;
u32 hofs_pix, hbp, hfp, vbp, vfp;
u32 tmds_clk, tmdsclk_cnt;
u64 tmp_data;
u32 interlaced;
u32 hfrontporch, hsync, hbackporch, vfrontporch, vsync, vbackporch;
unsigned long long pixelclock;
unsigned long flags = 0;
struct rk628_hdmirx *hdmirx = rk628->hdmirx;
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS1, &val);
status = val;
rk628_i2c_read(rk628, HDMI_RX_MD_STS, &val);
interlaced = val & ILACE_STS ? 1 : 0;
rk628_i2c_read(rk628, HDMI_RX_MD_HACT_PX, &val);
hact = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VAL, &val);
vact = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val);
htotal = (val >> 16) & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VTL, &val);
vtotal = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val);
hofs_pix = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VOL, &val);
vbp = (val & 0xffff) + 1;
rk628_i2c_read(rk628, HDMI_RX_HDMI_CKM_RESULT, &val);
tmdsclk_cnt = val & 0xffff;
tmp_data = tmdsclk_cnt;
tmp_data = ((tmp_data * MODETCLK_HZ) + MODETCLK_CNT_NUM / 2);
do_div(tmp_data, MODETCLK_CNT_NUM);
tmds_clk = tmp_data;
if (!(htotal && vtotal)) {
dev_info(rk628->dev, "timing err, htotal:%d, vtotal:%d\n", htotal, vtotal);
return;
}
fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal);
rk628_i2c_read(rk628, HDMI_RX_MD_HT0, &val);
modetclk_cnt_hs = val & 0xffff;
hs = (tmdsclk_cnt * modetclk_cnt_hs + MODETCLK_CNT_NUM / 2) /
MODETCLK_CNT_NUM;
rk628_i2c_read(rk628, HDMI_RX_MD_VSC, &val);
modetclk_cnt_vs = val & 0xffff;
vs = (tmdsclk_cnt * modetclk_cnt_vs + MODETCLK_CNT_NUM / 2) /
MODETCLK_CNT_NUM;
vs = (vs + htotal / 2) / htotal;
rk628_i2c_read(rk628, HDMI_RX_HDMI_STS, &val);
if (val & BIT(8))
flags |= DRM_MODE_FLAG_PHSYNC;
else
flags |= DRM_MODE_FLAG_NHSYNC;
if (val & BIT(9))
flags |= DRM_MODE_FLAG_PVSYNC;
else
flags |= DRM_MODE_FLAG_NVSYNC;
if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) ||
(vtotal < (vact + vs + vbp))) {
dev_info(rk628->dev,
"timing err, total:%dx%d, act:%dx%d, hofs:%d, hs:%d, vs:%d, vbp:%d\n",
htotal, vtotal, hact, vact, hofs_pix, hs, vs, vbp);
return;
}
hbp = hofs_pix - hs;
hfp = htotal - hact - hofs_pix;
vfp = vtotal - vact - vs - vbp;
dev_info(rk628->dev, "cnt_num:%d, tmds_cnt:%d, hs_cnt:%d, vs_cnt:%d, hofs:%d\n",
MODETCLK_CNT_NUM, tmdsclk_cnt, modetclk_cnt_hs, modetclk_cnt_vs, hofs_pix);
hfrontporch = hfp;
hsync = hs;
hbackporch = hbp;
vfrontporch = vfp;
vsync = vs;
vbackporch = vbp;
pixelclock = htotal * vtotal * fps;
if (interlaced == 1) {
vsync = vsync + 1;
pixelclock /= 2;
}
hdmirx->mode.clock = pixelclock / 1000;
hdmirx->mode.hdisplay = hact;
hdmirx->mode.hstart = hdmirx->mode.hdisplay + hfrontporch;
hdmirx->mode.hend = hdmirx->mode.hstart + hsync;
hdmirx->mode.htotal = hdmirx->mode.hend + hbackporch;
hdmirx->mode.vdisplay = vact;
hdmirx->mode.vstart = hdmirx->mode.vdisplay + vfrontporch;
hdmirx->mode.vend = hdmirx->mode.vstart + vsync;
hdmirx->mode.vtotal = hdmirx->mode.vend + vbackporch;
hdmirx->mode.flags = flags;
dev_info(rk628->dev, "SCDC_REGS1:%#x, act:%dx%d, total:%dx%d, fps:%d, pixclk:%llu\n",
status, hact, vact, htotal, vtotal, fps, pixelclock);
dev_info(rk628->dev, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d, interlace:%d\n",
hfrontporch, hsync, hbackporch, vfrontporch, vsync, vbackporch, interlaced);
}
static int rk628_hdmirx_phy_setup(struct rk628 *rk628)
{
u32 i, cnt, val;
u32 width, height, frame_width, frame_height, status;
struct rk628_display_mode *src_mode;
struct rk628_hdmirx *hdmirx = rk628->hdmirx;
int f;
struct rk628_display_mode *dst_mode;
/* Bit31 is used to distinguish HDMI cable mode and direct connection
* mode in the rk628_combrxphy driver.
* Bit31: 0 -direct connection mode;
* 1 -cable mode;
* The cable mode is to know the input clock frequency through cdr_mode
* in the rk628_combrxphy driver, and the cable mode supports up to
* 297M, so 297M is passed uniformly here.
*/
f = (297000 | BIT(31));
dst_mode = rk628_display_get_dst_mode(rk628);
/*
* force 594m mode to yuv420 format.
* bit30 is used to indicate whether it is yuv420 format.
*/
if (hdmirx->src_mode_4K_yuv420 && dst_mode->clock == 594000)
f |= BIT(30);
for (i = 0; i < RXPHY_CFG_MAX_TIMES; i++) {
rk628_hdmirx_phy_power_on(rk628, f);
cnt = 0;
do {
cnt++;
udelay(2000);
rk628_i2c_read(rk628, HDMI_RX_MD_HACT_PX, &val);
width = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val);
frame_width = (val >> 16) & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VAL, &val);
height = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VTL, &val);
frame_height = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS1, &val);
status = val;
dev_info(rk628->dev,
"%s read wxh:%dx%d, total:%dx%d, SCDC_REGS1:%#x, cnt:%d\n",
__func__, width, height, frame_width,
frame_height, status, cnt);
if (cnt >= 15)
break;
} while ((status & 0xfff) != 0xf00);
if ((status & 0xfff) != 0xf00) {
dev_info(rk628->dev, "%s hdmi rxphy lock failed, retry:%d\n",
__func__, i);
continue;
} else {
rk628_hdmirx_get_timing(rk628);
src_mode = rk628_display_get_src_mode(rk628);
src_mode->clock = hdmirx->mode.clock;
src_mode->hdisplay = hdmirx->mode.hdisplay;
src_mode->hsync_start = hdmirx->mode.hstart;
src_mode->hsync_end = hdmirx->mode.hend;
src_mode->htotal = hdmirx->mode.htotal;
src_mode->vdisplay = hdmirx->mode.vdisplay;
src_mode->vsync_start = hdmirx->mode.vstart;
src_mode->vsync_end = hdmirx->mode.vend;
src_mode->vtotal = hdmirx->mode.vtotal;
src_mode->flags = hdmirx->mode.flags;
if (hdmirx->src_mode_4K_yuv420 && dst_mode->clock == 594000) {
rk628_mode_copy(src_mode, dst_mode);
src_mode->flags = DRM_MODE_FLAG_PHSYNC|DRM_MODE_FLAG_PVSYNC;
}
break;
}
}
if (i == RXPHY_CFG_MAX_TIMES) {
hdmirx->phy_lock = false;
return -1;
}
hdmirx->phy_lock = true;
return 0;
}
static u32 rk628_hdmirx_get_input_format(struct rk628 *rk628)
{
u32 val, format, avi_pb = 0;
u8 i;
u8 cnt = 0, max_cnt = 2;
struct rk628_hdmirx *hdmirx = rk628->hdmirx;
rk628_i2c_read(rk628, HDMI_RX_PDEC_ISTS, &val);
if (val & AVI_RCV_ISTS) {
for (i = 0; i < 100; i++) {
rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &format);
dev_dbg(rk628->dev, "%s PDEC_AVI_PB:%#x\n", __func__, format);
if (format && format == avi_pb) {
if (++cnt >= max_cnt)
break;
} else {
cnt = 0;
avi_pb = format;
}
msleep(30);
}
format = (avi_pb & VIDEO_FORMAT) >> 5;
switch (format) {
case 0:
hdmirx->input_format = BUS_FMT_RGB;
break;
case 1:
hdmirx->input_format = BUS_FMT_YUV422;
break;
case 2:
hdmirx->input_format = BUS_FMT_YUV444;
break;
case 3:
hdmirx->input_format = BUS_FMT_YUV420;
break;
default:
hdmirx->input_format = BUS_FMT_RGB;
break;
}
rk628_i2c_write(rk628, HDMI_RX_PDEC_ICLR, AVI_RCV_ISTS);
}
return hdmirx->input_format;
}
static int rk628_check_signal(struct rk628 *rk628)
{
u32 hact, vact, val;
rk628_i2c_read(rk628, HDMI_RX_MD_HACT_PX, &val);
hact = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VAL, &val);
vact = val & 0xffff;
if (!hact || !vact) {
dev_info(rk628->dev, "no signal\n");
return 0;
}
return 1;
}
static bool rk628_hdmirx_status_change(struct rk628 *rk628)
{
u32 hact, vact, val;
struct rk628_hdmirx *hdmirx = rk628->hdmirx;
rk628_i2c_read(rk628, HDMI_RX_MD_HACT_PX, &val);
hact = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VAL, &val);
vact = val & 0xffff;
if (!rk628->plugin_det_gpio && !hact && !vact)
return true;
if (hact != hdmirx->mode.hdisplay || vact != hdmirx->mode.vdisplay) {
dev_info(rk628->dev, "new: hdisplay=%d, vdisplay=%d\n", hact, vact);
dev_info(rk628->dev, "old: hdisplay=%d, vdisplay=%d\n",
hdmirx->mode.hdisplay, hdmirx->mode.vdisplay);
return true;
}
rk628_hdmirx_get_input_format(rk628);
if (hdmirx->input_format != rk628_get_input_bus_format(rk628))
return true;
return false;
}
static int rk628_hdmirx_init(struct rk628 *rk628)
{
struct rk628_hdmirx *hdmirx;
struct device *dev = rk628->dev;
hdmirx = devm_kzalloc(rk628->dev, sizeof(*hdmirx), GFP_KERNEL);
if (!hdmirx)
return -ENOMEM;
rk628->hdmirx = hdmirx;
hdmirx->hpd_output_inverted = of_property_read_bool(dev->of_node,
"hpd-output-inverted");
hdmirx->src_mode_4K_yuv420 = of_property_read_bool(dev->of_node,
"src-mode-4k-yuv420");
/* HDMIRX IOMUX */
rk628_i2c_write(rk628, GRF_GPIO1AB_SEL_CON, HIWORD_UPDATE(0x7, 10, 8));
//i2s pinctrl
rk628_i2c_write(rk628, GRF_GPIO0AB_SEL_CON, 0x155c155c);
/* if GVI and HDMITX OUT, HDMIRX missing signal */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_OUTPUT_MODE_MASK, SW_OUTPUT_MODE(OUTPUT_MODE_RGB));
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_INPUT_MODE_MASK, SW_INPUT_MODE(INPUT_MODE_HDMI));
rk628_hdmirx_set_edid(rk628);
/* clear avi rcv interrupt */
rk628_i2c_write(rk628, HDMI_RX_PDEC_ICLR, AVI_RCV_ISTS);
dev_info(rk628->dev, "hdmirx driver version: %s\n", DRIVER_VERSION);
return 0;
}
void rk628_hdmirx_enable_interrupts(struct rk628 *rk628, bool en)
{
u32 pdec_ien, md_ien;
u32 md_mask = 0;
md_mask = VACT_LIN_ENSET | HACT_PIX_ENSET | HS_CLK_ENSET;
dev_dbg(rk628->dev, "%s: %sable\n", __func__, en ? "en" : "dis");
/* clr irq */
rk628_i2c_write(rk628, HDMI_RX_MD_ICLR, md_mask);
if (en) {
rk628_i2c_write(rk628, HDMI_RX_MD_IEN_SET, md_mask);
} else {
rk628_i2c_write(rk628, HDMI_RX_MD_IEN_CLR, md_mask);
rk628_i2c_write(rk628, HDMI_RX_AUD_FIFO_IEN_CLR, 0x1f);
}
usleep_range(5000, 5000);
rk628_i2c_read(rk628, HDMI_RX_MD_IEN, &md_ien);
rk628_i2c_read(rk628, HDMI_RX_PDEC_IEN, &pdec_ien);
dev_dbg(rk628->dev, "%s MD_IEN:%#x, PDEC_IEN:%#x\n", __func__, md_ien, pdec_ien);
}
int rk628_hdmirx_enable(struct rk628 *rk628)
{
int ret;
struct rk628_hdmirx *hdmirx;
if (!rk628->hdmirx) {
ret = rk628_hdmirx_init(rk628);
if (ret < 0)
return HDMIRX_PLUGOUT;
}
hdmirx = rk628->hdmirx;
if (tx_5v_power_present(rk628)) {
hdmirx->plugin = true;
rk628_hdmirx_enable_edid(rk628);
rk628_hdmirx_ctrl_enable(rk628);
rk628_hdmirx_phy_setup(rk628);
rk628_hdmirx_get_input_format(rk628);
rk628_set_input_bus_format(rk628, hdmirx->input_format);
dev_info(rk628->dev, "hdmirx plug in\n");
dev_info(rk628->dev, "input: %d, output: %d\n", hdmirx->input_format,
rk628_get_output_bus_format(rk628));
if (!rk628_check_signal(rk628))
return HDMIRX_PLUGIN | HDMIRX_NOSIGNAL;
rk628_hdmirx_video_unmute(rk628, 1);
return HDMIRX_PLUGIN;
}
hdmirx->plugin = false;
rk628_hdmirx_disable_edid(rk628);
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_I2S_DATA_OEN_MASK, SW_I2S_DATA_OEN(1));
return HDMIRX_PLUGOUT;
}
void rk628_hdmirx_disable(struct rk628 *rk628)
{
int ret;
struct rk628_hdmirx *hdmirx;
if (!rk628->hdmirx) {
ret = rk628_hdmirx_init(rk628);
if (ret < 0)
return;
}
hdmirx = rk628->hdmirx;
if (!tx_5v_power_present(rk628)) {
hdmirx->plugin = false;
rk628_hdmirx_disable_edid(rk628);
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_I2S_DATA_OEN_MASK,
SW_I2S_DATA_OEN(1));
dev_info(rk628->dev, "hdmirx plug out\n");
}
}
int rk628_hdmirx_detect(struct rk628 *rk628)
{
int ret = 0;
struct rk628_hdmirx *hdmirx;
if (!rk628->hdmirx) {
ret = rk628_hdmirx_init(rk628);
if (ret < 0 || !rk628->hdmirx)
return HDMIRX_PLUGOUT;
}
hdmirx = rk628->hdmirx;
if (tx_5v_power_present(rk628)) {
ret |= HDMIRX_PLUGIN;
if (!hdmirx->plugin)
ret |= HDMIRX_CHANGED;
if (rk628_hdmirx_status_change(rk628))
ret |= HDMIRX_CHANGED;
if (!hdmirx->phy_lock)
ret |= HDMIRX_NOLOCK;
hdmirx->plugin = true;
} else {
ret |= HDMIRX_PLUGOUT;
if (hdmirx->plugin)
ret |= HDMIRX_CHANGED;
hdmirx->plugin = false;
}
return ret;
}

View File

@@ -0,0 +1,633 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Chen Shunqing <csq@rock-chips.com>
*/
#ifndef HDMIRX_H
#define HDMIRX_H
#include "rk628.h"
#define HDMIRX_REG(x) ((x) + 0x30000)
/* --------- EDID and HDCP KEY ------- */
#define EDID_BASE 0x000a0000
#define HDCP_KEY_BASE 0x000a8000
#define KEY_MAX_REGISTER 0x000a8490
#define HDMI_RX_HDMI_SETUP_CTRL HDMIRX_REG(0x0000)
#define HOT_PLUG_DETECT_MASK BIT(0)
#define HOT_PLUG_DETECT(x) UPDATE(x, 0, 0)
#define HDMI_RX_HDMI_OVR_CTRL HDMIRX_REG(0x0004)
#define HDMI_RX_HDMI_TIMER_CTRL HDMIRX_REG(0x0008)
#define HDMI_RX_HDMI_RES_OVR HDMIRX_REG(0x0010)
#define HDMI_RX_HDMI_RES_STS HDMIRX_REG(0x0014)
#define HDMI_RX_HDMI_PLL_CTRL HDMIRX_REG(0x0018)
#define HDMI_RX_HDMI_PLL_FRQSET1 HDMIRX_REG(0x001c)
#define HDMI_RX_HDMI_PLL_FRQSET2 HDMIRX_REG(0x0020)
#define HDMI_RX_HDMI_PLL_PAR1 HDMIRX_REG(0x0024)
#define HDMI_RX_HDMI_PLL_PAR2 HDMIRX_REG(0x0028)
#define HDMI_RX_HDMI_PLL_PAR3 HDMIRX_REG(0x002c)
#define HDMI_RX_HDMI_PLL_LCK_STS HDMIRX_REG(0x0030)
#define HDMI_RX_HDMI_CLK_CTRL HDMIRX_REG(0x0034)
#define HDMI_RX_HDMI_PCB_CTRL HDMIRX_REG(0x0038)
#define SEL_PIXCLKSRC_MASK GENMASK(19, 18)
#define SEL_PIXCLKSRC(x) UPDATE(x, 19, 18)
#define HDMI_RX_HDMI_PHS_CTR HDMIRX_REG(0x0040)
#define HDMI_RX_HDMI_PHS_USED HDMIRX_REG(0x0044)
#define HDMI_RX_HDMI_MISC_CTRL HDMIRX_REG(0x0048)
#define HDMI_RX_HDMI_EQOFF_CTRL HDMIRX_REG(0x004c)
#define HDMI_RX_HDMI_EQGAIN_CTRL HDMIRX_REG(0x0050)
#define HDMI_RX_HDMI_EQCAL_STS HDMIRX_REG(0x0054)
#define HDMI_RX_HDMI_EQRESULT HDMIRX_REG(0x0058)
#define HDMI_RX_HDMI_EQ_MEAS_CTRL HDMIRX_REG(0x005c)
#define HDMI_RX_HDMI_WR_CFG HDMIRX_REG(0x0060)
#define HDMI_RX_HDMI_CTRL HDMIRX_REG(0x0064)
#define HDMI_RX_HDMI_MODE_RECOVER HDMIRX_REG(0x0080)
#define PREAMBLE_CNT_LIMIT_MASK GENMASK(31, 27)
#define PREAMBLE_CNT_LIMIT(x) UPDATE(x, 31, 27)
#define OESSCTL3_THR_MASK GENMASK(20, 19)
#define OESSCTL3_THR(x) UPDATE(x, 20, 19)
#define SPIKE_FILTER_EN_MASK BIT(18)
#define SPIKE_FILTER_EN(x) UPDATE(x, 18, 18)
#define DVI_MODE_HYST_MASK GENMASK(17, 13)
#define DVI_MODE_HYST(x) UPDATE(x, 17, 13)
#define HDMI_MODE_HYST_MASK GENMASK(12, 8)
#define HDMI_MODE_HYST(x) UPDATE(x, 12, 8)
#define HDMI_MODE_MASK GENMASK(7, 6)
#define HDMI_MODE(x) UPDATE(x, 7, 6)
#define GB_DET_MASK GENMASK(5, 4)
#define GB_DET(x) UPDATE(x, 5, 4)
#define EESS_OESS_MASK GENMASK(3, 2)
#define EESS_OESS(x) UPDATE(x, 3, 2)
#define SEL_CTL01_MASK GENMASK(1, 0)
#define SEL_CTL01(x) UPDATE(x, 1, 0)
#define HDMI_RX_HDMI_ERROR_PROTECT HDMIRX_REG(0x0084)
#define RG_BLOCK_OFF_MASK BIT(20)
#define RG_BLOCK_OFF(x) UPDATE(x, 20, 20)
#define BLOCK_OFF_MASK BIT(19)
#define BLOCK_OFF(x) UPDATE(x, 19, 19)
#define VALID_MODE_MASK GENMASK(18, 16)
#define VALID_MODE(x) UPDATE(x, 18, 16)
#define CTRL_FILT_SEN_MASK GENMASK(13, 12)
#define CTRL_FILT_SEN(x) UPDATE(x, 13, 12)
#define VS_FILT_SENS_MASK GENMASK(11, 10)
#define VS_FILT_SENS(x) UPDATE(x, 11, 10)
#define HS_FILT_SENS_MASK GENMASK(9, 8)
#define HS_FILT_SENS(x) UPDATE(x, 9, 8)
#define DE_MEASURE_MODE_MASK GENMASK(7, 6)
#define DE_MEASURE_MODE(x) UPDATE(x, 7, 6)
#define DE_REGEN_MASK BIT(5)
#define DE_REGEN(x) UPDATE(x, 5, 5)
#define DE_FILTER_SENS_MASK GENMASK(4, 3)
#define DE_FILTER_SENS(x) UPDATE(x, 4, 3)
#define HDMI_RX_HDMI_ERD_STS HDMIRX_REG(0x0088)
#define HDMI_RX_HDMI_SYNC_CTRL HDMIRX_REG(0x0090)
#define VS_POL_ADJ_MODE_MASK GENMASK(4, 3)
#define VS_POL_ADJ_MODE(x) UPDATE(x, 4, 3)
#define HS_POL_ADJ_MODE_MASK GENMASK(2, 1)
#define HS_POL_ADJ_MODE(x) UPDATE(x, 2, 1)
#define HDMI_RX_HDMI_CKM_EVLTM HDMIRX_REG(0x0094)
#define LOCK_HYST_MASK GENMASK(21, 20)
#define LOCK_HYST(x) UPDATE(x, 21, 20)
#define CLK_HYST_MASK GENMASK(18, 16)
#define CLK_HYST(x) UPDATE(x, 18, 16)
#define EVAL_TIME_MASK GENMASK(15, 4)
#define EVAL_TIME(x) UPDATE(x, 15, 4)
#define HDMI_RX_HDMI_CKM_F HDMIRX_REG(0x0098)
#define HDMIRX_MAXFREQ_MASK GENMASK(31, 16)
#define HDMIRX_MAXFREQ(x) UPDATE(x, 31, 16)
#define MINFREQ_MASK GENMASK(15, 0)
#define MINFREQ(x) UPDATE(x, 15, 0)
#define HDMI_RX_HDMI_CKM_RESULT HDMIRX_REG(0x009c)
#define HDMI_RX_HDMI_PVO_CONFIG HDMIRX_REG(0x00a0)
#define HDMI_RX_HDMI_RESMPL_CTRL HDMIRX_REG(0x00a4)
#define MAN_VID_DEREPEAT_MASK GENMASK(4, 1)
#define MAN_VID_DEREPEAT(x) UPDATE(x, 4, 1)
#define AUTO_DEREPEAT_MASK BIT(0)
#define AUTO_DEREPEAT(x) UPDATE(x, 0, 0)
#define HDMI_RX_HDMI_DCM_CTRL HDMIRX_REG(0x00a8)
#define DCM_DEFAULT_PHASE_MASK BIT(18)
#define DCM_DEFAULT_PHASE(x) UPDATE(x, 18, 18)
#define DCM_COLOUR_DEPTH_SEL_MASK BIT(12)
#define DCM_COLOUR_DEPTH_SEL(x) UPDATE(x, 12, 12)
#define DCM_COLOUR_DEPTH_MASK GENMASK(11, 8)
#define DCM_COLOUR_DEPTH(x) UPDATE(x, 11, 8)
#define DCM_GCP_ZERO_FIELDS_MASK GENMASK(5, 2)
#define DCM_GCP_ZERO_FIELDS(x) UPDATE(x, 5, 2)
#define HDMI_RX_HDMI_VM_CFG_CH_0_1 HDMIRX_REG(0x00b0)
#define HDMI_RX_HDMI_VM_CFG_CH2 HDMIRX_REG(0x00b4)
#define HDMI_RX_HDMI_SPARE HDMIRX_REG(0x00b8)
#define HDMI_RX_HDMI_STS HDMIRX_REG(0x00bc)
#define HDMI_RX_HDCP_CTRL HDMIRX_REG(0x00c0)
#define HDCP_ENABLE_MASK BIT(24)
#define HDCP_ENABLE(x) UPDATE(x, 24, 24)
#define FREEZE_HDCP_FSM_MASK BIT(21)
#define FREEZE_HDCP_FSM(x) UPDATE(x, 21, 21)
#define FREEZE_HDCP_STATE_MASK GENMASK(20, 15)
#define FREEZE_HDCP_STATE(x) UPDATE(x, 20, 15)
#define HDCP_CTL_MASK GENMASK(9, 8)
#define HDCP_CTL(x) UPDATE(x, 9, 8)
#define HDCP_RI_RATE_MASK GENMASK(7, 6)
#define HDCP_RI_RATE(x) UPDATE(x, 7, 6)
#define KEY_DECRYPT_ENABLE_MASK BIT(1)
#define KEY_DECRYPT_ENABLE(x) UPDATE(x, 1, 1)
#define HDCP_ENC_EN_MASK BIT(0)
#define HDCP_ENC_EN(x) UPDATE(x, 0, 0)
#define HDMI_RX_HDCP_SETTINGS HDMIRX_REG(0x00c4)
#define HDMI_RESERVED(x) UPDATE(x, 13, 13)
#define HDMI_RESERVED_MASK BIT(13)
#define FAST_I2C(x) UPDATE(x, 12, 12)
#define FAST_I2C_MASK BIT(12)
#define ONE_DOT_ONE(x) UPDATE(x, 9, 9)
#define ONE_DOT_ONE_MASK BIT(9)
#define FAST_REAUTH(x) UPDATE(x, 8, 8)
#define FAST_REAUTH_MASK BIT(8)
#define HDMI_RX_HDCP_SEED HDMIRX_REG(0x00c8)
#define HDMI_RX_HDCP_BKSV1 HDMIRX_REG(0x00cc)
#define HDMI_RX_HDCP_BKSV0 HDMIRX_REG(0x00d0)
#define HDMI_RX_HDCP_KIDX HDMIRX_REG(0x00d4)
#define HDMI_RX_HDCP_KEY1 HDMIRX_REG(0x00d8)
#define HDMI_RX_HDCP_KEY0 HDMIRX_REG(0x00dc)
#define HDMI_RX_HDCP_DBG HDMIRX_REG(0x00e0)
#define HDMI_RX_HDCP_AKSV1 HDMIRX_REG(0x00e4)
#define HDMI_RX_HDCP_AKSV0 HDMIRX_REG(0x00e8)
#define HDMI_RX_HDCP_AN1 HDMIRX_REG(0x00ec)
#define HDMI_RX_HDCP_AN0 HDMIRX_REG(0x00f0)
#define HDMI_RX_HDCP_EESS_WOO HDMIRX_REG(0x00f4)
#define HDMI_RX_HDCP_I2C_TIMEOUT HDMIRX_REG(0x00f8)
#define HDMI_RX_HDCP_STS HDMIRX_REG(0x00fc)
#define HDMI_RX_MD_HCTRL1 HDMIRX_REG(0x0140)
#define HACT_PIX_ITH_MASK GENMASK(10, 8)
#define HACT_PIX_ITH(x) UPDATE(x, 10, 8)
#define HACT_PIX_SRC_MASK BIT(5)
#define HACT_PIX_SRC(x) UPDATE(x, 5, 5)
#define HTOT_PIX_SRC_MASK BIT(4)
#define HTOT_PIX_SRC(x) UPDATE(x, 4, 4)
#define HDMI_RX_MD_HCTRL2 HDMIRX_REG(0x0144)
#define HS_CLK_ITH_MASK GENMASK(14, 12)
#define HS_CLK_ITH(x) UPDATE(x, 14, 12)
#define HTOT32_CLK_ITH_MASK GENMASK(9, 8)
#define HTOT32_CLK_ITH(x) UPDATE(x, 9, 8)
#define VS_ACT_TIME_MASK BIT(5)
#define VS_ACT_TIME(x) UPDATE(x, 5, 5)
#define HS_ACT_TIME_MASK GENMASK(4, 3)
#define HS_ACT_TIME(x) UPDATE(x, 4, 3)
#define H_START_POS_MASK GENMASK(1, 0)
#define H_START_POS(x) UPDATE(x, 1, 0)
#define HDMI_RX_MD_HT0 HDMIRX_REG(0x0148)
#define HDMI_RX_MD_HT1 HDMIRX_REG(0x014c)
#define HDMI_RX_MD_HACT_PX HDMIRX_REG(0x0150)
#define HDMI_RX_MD_HACT_RSV HDMIRX_REG(0x0154)
#define HDMI_RX_MD_VCTRL HDMIRX_REG(0x0158)
#define V_OFFS_LIN_MODE_MASK BIT(4)
#define V_OFFS_LIN_MODE(x) UPDATE(x, 4, 4)
#define V_EDGE_MASK BIT(1)
#define V_EDGE(x) UPDATE(x, 1, 1)
#define V_MODE_MASK BIT(0)
#define V_MODE(x) UPDATE(x, 0, 0)
#define HDMI_RX_MD_VSC HDMIRX_REG(0x015c)
#define HDMI_RX_MD_VTC HDMIRX_REG(0x0160)
#define HDMI_RX_MD_VOL HDMIRX_REG(0x0164)
#define HDMI_RX_MD_VAL HDMIRX_REG(0x0168)
#define HDMI_RX_MD_VTH HDMIRX_REG(0x016c)
#define VOFS_LIN_ITH_MASK GENMASK(11, 10)
#define VOFS_LIN_ITH(x) UPDATE(x, 11, 10)
#define VACT_LIN_ITH_MASK GENMASK(9, 8)
#define VACT_LIN_ITH(x) UPDATE(x, 9, 8)
#define VTOT_LIN_ITH_MASK GENMASK(7, 6)
#define VTOT_LIN_ITH(x) UPDATE(x, 7, 6)
#define VS_CLK_ITH_MASK GENMASK(5, 3)
#define VS_CLK_ITH(x) UPDATE(x, 5, 3)
#define VTOT_CLK_ITH_MASK GENMASK(2, 0)
#define VTOT_CLK_ITH(x) UPDATE(x, 2, 0)
#define HDMI_RX_MD_VTL HDMIRX_REG(0x0170)
#define HDMI_RX_MD_IL_CTRL HDMIRX_REG(0x0174)
#define HDMI_RX_MD_IL_SKEW HDMIRX_REG(0x0178)
#define HDMI_RX_MD_IL_POL HDMIRX_REG(0x017c)
#define FAFIELDDET_EN_MASK BIT(2)
#define FAFIELDDET_EN(x) UPDATE(x, 2, 2)
#define FIELD_POL_MODE_MASK GENMASK(1, 0)
#define FIELD_POL_MODE(x) UPDATE(x, 1, 0)
#define HDMI_RX_MD_STS HDMIRX_REG(0x0180)
#define ILACE_STS BIT(3)
#define HDMI_RX_AUD_CTRL HDMIRX_REG(0x0200)
#define HDMI_RX_AUD_PLL_CTRL HDMIRX_REG(0x0208)
#define PLL_LOCK_TOGGLE_DIV_MASK GENMASK(27, 24)
#define PLL_LOCK_TOGGLE_DIV(x) UPDATE(x, 27, 24)
#define HDMI_RX_AUD_CLK_CTRL HDMIRX_REG(0x0214)
#define CTS_N_REF_MASK BIT(4)
#define CTS_N_REF(x) UPDATE(x, 4, 4)
#define HDMI_RX_AUD_CLK_STS HDMIRX_REG(0x023c)
#define HDMI_RX_AUD_FIFO_CTRL HDMIRX_REG(0x0240)
#define AFIF_SUBPACKET_DESEL_MASK GENMASK(27, 24)
#define AFIF_SUBPACKET_DESEL(x) UPDATE(x, 27, 24)
#define AFIF_SUBPACKETS_MASK BIT(16)
#define AFIF_SUBPACKETS(x) UPDATE(x, 16, 16)
#define MSA_CHANNEL_DESELECT BIT(24)
#define HDMI_RX_AUD_FIFO_TH HDMIRX_REG(0x0244)
#define AFIF_TH_START_MASK GENMASK(26, 18)
#define AFIF_TH_START(x) UPDATE(x, 26, 18)
#define AFIF_TH_MAX_MASK GENMASK(17, 9)
#define AFIF_TH_MAX(x) UPDATE(x, 17, 9)
#define AFIF_TH_MIN_MASK GENMASK(8, 0)
#define AFIF_TH_MIN(x) UPDATE(x, 8, 0)
#define HDMI_RX_AUD_FIFO_FILL_S HDMIRX_REG(0x0248)
#define HDMI_RX_AUD_FIFO_CLR_MM HDMIRX_REG(0x024c)
#define HDMI_RX_AUD_FIFO_FILLSTS HDMIRX_REG(0x0250)
#define HDMI_RX_AUD_CHEXTR_CTRL HDMIRX_REG(0x0254)
#define AUD_LAYOUT_CTRL(x) UPDATE(x, 1, 0)
#define HDMI_RX_AUD_MUTE_CTRL HDMIRX_REG(0x0258)
#define APPLY_INT_MUTE_MASK BIT(31)
#define APPLY_INT_MUTE(x) UPDATE(x, 31, 31)
#define APORT_SHDW_CTRL_MASK GENMASK(22, 21)
#define APORT_SHDW_CTRL(x) UPDATE(x, 22, 21)
#define AUTO_ACLK_MUTE_MASK GENMASK(20, 19)
#define AUTO_ACLK_MUTE(x) UPDATE(x, 20, 19)
#define AUD_MUTE_SPEED_MASK GENMASK(16, 10)
#define AUD_MUTE_SPEED(x) UPDATE(x, 16, 10)
#define AUD_AVMUTE_EN_MASK BIT(7)
#define AUD_AVMUTE_EN(x) UPDATE(x, 7, 7)
#define AUD_MUTE_SEL_MASK GENMASK(6, 5)
#define AUD_MUTE_SEL(x) UPDATE(x, 6, 5)
#define AUD_MUTE_MODE_MASK GENMASK(4, 3)
#define AUD_MUTE_MODE(x) UPDATE(x, 4, 3)
#define HDMI_RX_AUD_FIFO_FILLSTS1 HDMIRX_REG(0x025c)
#define HDMI_RX_AUD_SAO_CTRL HDMIRX_REG(0x0260)
#define I2S_LPCM_BPCUV_MASK BIT(11)
#define I2S_LPCM_BPCUV(x) UPDATE(x, 11, 11)
#define I2S_32_16_MASK BIT(0)
#define I2S_32_16(x) UPDATE(x, 0, 0)
#define HDMI_RX_AUD_PAO_CTRL HDMIRX_REG(0x0264)
#define PAO_RATE_MASK GENMASK(17, 16)
#define PAO_RATE(x) UPDATE(x, 17, 16)
#define HDMI_RX_AUD_SPARE HDMIRX_REG(0x0268)
#define HDMI_RX_AUD_FIFO_STS HDMIRX_REG(0x027c)
#define HDMI_RX_AUDPLL_GEN_CTS HDMIRX_REG(0x0280)
#define AUDPLL_CTS_MANUAL(x) UPDATE(x, 19, 0)
#define HDMI_RX_AUDPLL_GEN_N HDMIRX_REG(0x0284)
#define AUDPLL_N_MANUAL(x) UPDATE(x, 19, 0)
#define HDMI_RX_AUDPLL_GEN_CTRL_RW1 HDMIRX_REG(0x0288)
#define HDMI_RX_AUDPLL_GEN_CTRL_RW2 HDMIRX_REG(0x028c)
#define HDMI_RX_AUDPLL_GEN_CTRL_W1 HDMIRX_REG(0x0298)
#define HDMI_RX_AUDPLL_GEN_STS_RO1 HDMIRX_REG(0x02a0)
#define HDMI_RX_AUDPLL_GEN_STS_RO2 HDMIRX_REG(0x02a4)
#define HDMI_RX_AUDPLL_SC_NDIVCTSTH HDMIRX_REG(0x02a8)
#define HDMI_RX_AUDPLL_SC_CTS HDMIRX_REG(0x02ac)
#define HDMI_RX_AUDPLL_SC_N HDMIRX_REG(0x02b0)
#define HDMI_RX_AUDPLL_SC_CTRL HDMIRX_REG(0x02b4)
#define HDMI_RX_AUDPLL_SC_STS1 HDMIRX_REG(0x02b8)
#define HDMI_RX_AUDPLL_SC_STS2 HDMIRX_REG(0x02bc)
#define HDMI_RX_SNPS_PHYG3_CTRL HDMIRX_REG(0x02c0)
#define PORTSELECT_MASK GENMASK(3, 2)
#define PORTSELECT(x) UPDATE(x, 3, 2)
#define HDMI_RX_I2CM_PHYG3_SLAVE HDMIRX_REG(0x02c4)
#define HDMI_RX_I2CM_PHYG3_ADDRESS HDMIRX_REG(0x02c8)
#define HDMI_RX_I2CM_PHYG3_DATAO HDMIRX_REG(0x02cc)
#define HDMI_RX_I2CM_PHYG3_DATAI HDMIRX_REG(0x02d0)
#define HDMI_RX_I2CM_PHYG3_OPERATION HDMIRX_REG(0x02d4)
#define HDMI_RX_I2CM_PHYG3_MODE HDMIRX_REG(0x02d8)
#define HDMI_RX_I2CM_PHYG3_SOFTRST HDMIRX_REG(0x02dc)
#define HDMI_RX_I2CM_PHYG3_SS_CNTS HDMIRX_REG(0x02e0)
#define HDMI_RX_I2CM_PHYG3_FS_HCNT HDMIRX_REG(0x02e4)
#define HDMI_RX_JTAG_CONF HDMIRX_REG(0x02ec)
#define HDMI_RX_JTAG_TAP_TCLK HDMIRX_REG(0x02f0)
#define HDMI_RX_JTAG_TAP_IN HDMIRX_REG(0x02f4)
#define HDMI_RX_JTAG_TAP_OUT HDMIRX_REG(0x02f8)
#define HDMI_RX_JTAG_ADDR HDMIRX_REG(0x02fc)
#define HDMI_RX_PDEC_CTRL HDMIRX_REG(0x0300)
#define PFIFO_SCORE_FILTER_EN BIT(31)
#define PFIFO_SCORE_HDP_IF BIT(29)
#define PFIFO_SCORE_AMP_IF BIT(28)
#define PFIFO_SCORE_NTSCVBI_IF BIT(27)
#define PFIFO_SCORE_MPEGS_IF BIT(26)
#define PFIFO_SCORE_AUD_IF BIT(25)
#define PFIFO_SCORE_SPD_IF BIT(24)
#define PFIFO_SCORE_AVI_IF BIT(23)
#define PFIFO_SCORE_VS_IF BIT(22)
#define PFIFO_SCORE_GMTP BIT(21)
#define PFIFO_SCORE_ISRC2 BIT(20)
#define PFIFO_SCORE_ISRC1 BIT(19)
#define PFIFO_SCORE_ACP BIT(18)
#define PFIFO_SCORE_GCP BIT(17)
#define PFIFO_SCORE_ACR BIT(16)
#define GCP_GLOBAVMUTE BIT(15)
#define PD_FIFO_WE BIT(4)
#define PDEC_BCH_EN BIT(0)
#define HDMI_RX_PDEC_FIFO_CFG HDMIRX_REG(0x0304)
#define PD_FIFO_TH_START_MASK GENMASK(29, 20)
#define PD_FIFO_TH_START(x) UPDATE(x, 29, 20)
#define PD_FIFO_TH_MAX_MASK GENMASK(19, 10)
#define PD_FIFO_TH_MAX(x) UPDATE(x, 19, 10)
#define PD_FIFO_TH_MIN_MASK GENMASK(9, 0)
#define PD_FIFO_TH_MIN(x) UPDATE(x, 9, 0)
#define HDMI_RX_PDEC_FIFO_STS HDMIRX_REG(0x0308)
#define HDMI_RX_PDEC_FIFO_DATA HDMIRX_REG(0x030c)
#define HDMI_RX_PDEC_AUDIODET_CTRL HDMIRX_REG(0x0310)
#define AUDIODET_THRESHOLD_MASK GENMASK(13, 9)
#define AUDIODET_THRESHOLD(x) UPDATE(x, 13, 9)
#define HDMI_RX_PDEC_DBG_ACP HDMIRX_REG(0x031c)
#define HDMI_RX_PDEC_DBG_ERR_CORR HDMIRX_REG(0x0320)
#define HDMI_RX_PDEC_FIFO_STS1 HDMIRX_REG(0x0324)
#define HDMI_RX_PDEC_ACRM_CTRL HDMIRX_REG(0x0330)
#define DELTACTS_IRQTRIG_MASK GENMASK(4, 2)
#define DELTACTS_IRQTRIG(x) UPDATE(x, 4, 2)
#define HDMI_RX_PDEC_ACRM_MAX HDMIRX_REG(0x0334)
#define HDMI_RX_PDEC_ACRM_MIN HDMIRX_REG(0x0338)
#define HDMI_RX_PDEC_ERR_FILTER HDMIRX_REG(0x033c)
#define HDMI_RX_PDEC_ASP_CTRL HDMIRX_REG(0x0340)
#define HDMI_RX_PDEC_ASP_ERR HDMIRX_REG(0x0344)
#define HDMI_RX_PDEC_STS HDMIRX_REG(0x0360)
#define HDMI_RX_PDEC_AUD_STS HDMIRX_REG(0x0364)
#define HDMI_RX_PDEC_VSI_PAYLOAD0 HDMIRX_REG(0x0368)
#define HDMI_RX_PDEC_VSI_PAYLOAD1 HDMIRX_REG(0x036c)
#define HDMI_RX_PDEC_VSI_PAYLOAD2 HDMIRX_REG(0x0370)
#define HDMI_RX_PDEC_VSI_PAYLOAD3 HDMIRX_REG(0x0374)
#define HDMI_RX_PDEC_VSI_PAYLOAD4 HDMIRX_REG(0x0378)
#define HDMI_RX_PDEC_VSI_PAYLOAD5 HDMIRX_REG(0x037c)
#define HDMI_RX_PDEC_GCP_AVMUTE HDMIRX_REG(0x0380)
#define PKTDEC_GCP_CD_MASK GENMASK(7, 4)
#define HDMI_RX_PDEC_ACR_CTS HDMIRX_REG(0x0390)
#define HDMI_RX_PDEC_ACR_N HDMIRX_REG(0x0394)
#define HDMI_RX_PDEC_AVI_HB HDMIRX_REG(0x03a0)
#define HDMI_RX_PDEC_AVI_PB HDMIRX_REG(0x03a4)
#define VID_IDENT_CODE_VIC7 BIT(31)
#define VID_IDENT_CODE GENMASK(30, 24)
#define VIDEO_FORMAT GENMASK(6, 5)
#define HDMI_RX_PDEC_AVI_TBB HDMIRX_REG(0x03a8)
#define HDMI_RX_PDEC_AVI_LRB HDMIRX_REG(0x03ac)
#define HDMI_RX_PDEC_AIF_CTRL HDMIRX_REG(0x03c0)
#define FC_LFE_EXCHG BIT(18)
#define HDMI_RX_PDEC_AIF_HB HDMIRX_REG(0x03c4)
#define HDMI_RX_PDEC_AIF_PB0 HDMIRX_REG(0x03c8)
#define HDMI_RX_PDEC_AIF_PB1 HDMIRX_REG(0x03cc)
#define HDMI_RX_PDEC_GMD_HB HDMIRX_REG(0x03d0)
#define HDMI_RX_PDEC_GMD_PB HDMIRX_REG(0x03d4)
#define HDMI_RX_PDEC_VSI_ST0 HDMIRX_REG(0x03e0)
#define HDMI_RX_PDEC_VSI_ST1 HDMIRX_REG(0x03e4)
#define HDMI_RX_PDEC_VSI_PB0 HDMIRX_REG(0x03e8)
#define HDMI_RX_PDEC_VSI_PB1 HDMIRX_REG(0x03ec)
#define HDMI_RX_PDEC_VSI_PB2 HDMIRX_REG(0x03f0)
#define HDMI_RX_PDEC_VSI_PB3 HDMIRX_REG(0x03f4)
#define HDMI_RX_PDEC_VSI_PB4 HDMIRX_REG(0x03f8)
#define HDMI_RX_PDEC_VSI_PB5 HDMIRX_REG(0x03fc)
#define HDMI_RX_CEAVID_CONFIG HDMIRX_REG(0x0400)
#define HDMI_RX_CEAVID_3DCONFIG HDMIRX_REG(0x0404)
#define HDMI_RX_CEAVID_HCONFIG_LO HDMIRX_REG(0x0408)
#define HDMI_RX_CEAVID_HCONFIG_HI HDMIRX_REG(0x040c)
#define HDMI_RX_CEAVID_VCONFIG_LO HDMIRX_REG(0x0410)
#define HDMI_RX_CEAVID_VCONFIG_HI HDMIRX_REG(0x0414)
#define HDMI_RX_CEAVID_STATUS HDMIRX_REG(0x0418)
#define HDMI_RX_PDEC_AMP_HB HDMIRX_REG(0x0480)
#define HDMI_RX_PDEC_AMP_PAYLOAD0 HDMIRX_REG(0x0484)
#define HDMI_RX_PDEC_AMP_PAYLOAD1 HDMIRX_REG(0x0488)
#define HDMI_RX_PDEC_AMP_PAYLOAD2 HDMIRX_REG(0x048c)
#define HDMI_RX_PDEC_AMP_PAYLOAD3 HDMIRX_REG(0x0490)
#define HDMI_RX_PDEC_AMP_PAYLOAD4 HDMIRX_REG(0x0494)
#define HDMI_RX_PDEC_AMP_PAYLOAD5 HDMIRX_REG(0x0498)
#define HDMI_RX_PDEC_AMP_PAYLOAD6 HDMIRX_REG(0x049c)
#define HDMI_RX_PDEC_NTSCVBI_HB HDMIRX_REG(0x04a0)
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD0 HDMIRX_REG(0x04a4)
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD1 HDMIRX_REG(0x04a8)
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD2 HDMIRX_REG(0x04ac)
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD3 HDMIRX_REG(0x04b0)
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD4 HDMIRX_REG(0x04b4)
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD5 HDMIRX_REG(0x04b8)
#define HDMI_RX_PDEC_NTSCVBI_PAYLOAD6 HDMIRX_REG(0x04bc)
#define HDMI_RX_PDEC_DRM_HB HDMIRX_REG(0x04c0)
#define HDMI_RX_PDEC_DRM_PAYLOAD0 HDMIRX_REG(0x04c4)
#define HDMI_RX_PDEC_DRM_PAYLOAD1 HDMIRX_REG(0x04c8)
#define HDMI_RX_PDEC_DRM_PAYLOAD2 HDMIRX_REG(0x04cc)
#define HDMI_RX_PDEC_DRM_PAYLOAD3 HDMIRX_REG(0x04d0)
#define HDMI_RX_PDEC_DRM_PAYLOAD4 HDMIRX_REG(0x04d4)
#define HDMI_RX_PDEC_DRM_PAYLOAD5 HDMIRX_REG(0x04d8)
#define HDMI_RX_PDEC_DRM_PAYLOAD6 HDMIRX_REG(0x04dc)
#define HDMI_RX_MHLMODE_CTRL HDMIRX_REG(0x0500)
#define HDMI_RX_CDSENSE_STATUS HDMIRX_REG(0x0504)
#define HDMI_RX_DESERFIFO_CTRL HDMIRX_REG(0x0508)
#define HDMI_RX_DESER_INTTRSHCTRL HDMIRX_REG(0x050c)
#define HDMI_RX_DESER_INTCNTCTRL HDMIRX_REG(0x0510)
#define HDMI_RX_DESER_INTCNT HDMIRX_REG(0x0514)
#define HDMI_RX_HDCP_RPT_CTRL HDMIRX_REG(0x0600)
#define HDMI_RX_HDCP_RPT_BSTATUS HDMIRX_REG(0x0604)
#define HDMI_RX_HDCP_RPT_KSVFIFO_CTRL HDMIRX_REG(0x0608)
#define HDMI_RX_HDCP_RPT_KSVFIFO1 HDMIRX_REG(0x060c)
#define HDMI_RX_HDCP_RPT_KSVFIFO0 HDMIRX_REG(0x0610)
#define HDMI_RX_HDMI20_CONTROL HDMIRX_REG(0x0800)
#define HDMI_RX_SCDC_I2CCONFIG HDMIRX_REG(0x0804)
#define I2CSPIKESUPPR_MASK GENMASK(25, 24)
#define I2CSPIKESUPPR(x) UPDATE(x, 25, 24)
#define HDMI_RX_SCDC_CONFIG HDMIRX_REG(0x0808)
#define HDMI_RX_CHLOCK_CONFIG HDMIRX_REG(0x080c)
#define CHLOCKMAXER_MASK GENMASK(29, 20)
#define CHLOCKMAXER(x) UPDATE(x, 29, 20)
#define MILISECTIMERLIMIT_MASK GENMASK(15, 0)
#define MILISECTIMERLIMIT(x) UPDATE(x, 15, 0)
#define HDMI_RX_HDCP22_CONTROL HDMIRX_REG(0x081c)
#define HDMI_RX_SCDC_REGS0 HDMIRX_REG(0x0820)
#define HDMI_RX_SCDC_REGS1 HDMIRX_REG(0x0824)
#define HDMI_RX_SCDC_REGS2 HDMIRX_REG(0x0828)
#define HDMI_RX_SCDC_REGS3 HDMIRX_REG(0x082c)
#define HDMI_RX_SCDC_MANSPEC0 HDMIRX_REG(0x0840)
#define HDMI_RX_SCDC_MANSPEC1 HDMIRX_REG(0x0844)
#define HDMI_RX_SCDC_MANSPEC2 HDMIRX_REG(0x0848)
#define HDMI_RX_SCDC_MANSPEC3 HDMIRX_REG(0x084c)
#define HDMI_RX_SCDC_MANSPEC4 HDMIRX_REG(0x0850)
#define HDMI_RX_SCDC_WRDATA0 HDMIRX_REG(0x0860)
#define MANUFACTUREROUI_MASK GENMASK(31, 8)
#define MANUFACTUREROUI(x) UPDATE(x, 31, 8)
#define SINKVERSION_MASK GENMASK(7, 0)
#define SINKVERSION(x) UPDATE(x, 7, 0)
#define HDMI_RX_SCDC_WRDATA1 HDMIRX_REG(0x0864)
#define HDMI_RX_SCDC_WRDATA2 HDMIRX_REG(0x0868)
#define HDMI_RX_SCDC_WRDATA3 HDMIRX_REG(0x086c)
#define HDMI_RX_SCDC_WRDATA4 HDMIRX_REG(0x0870)
#define HDMI_RX_SCDC_WRDATA5 HDMIRX_REG(0x0874)
#define HDMI_RX_SCDC_WRDATA6 HDMIRX_REG(0x0878)
#define HDMI_RX_SCDC_WRDATA7 HDMIRX_REG(0x087c)
#define HDMI_RX_HDMI20_STATUS HDMIRX_REG(0x08e0)
#define HDMI_RX_HDCP2_ESM_GLOBAL_GPIO_IN HDMIRX_REG(0x08e8)
#define HDMI_RX_HDCP2_ESM_GLOBAL_GPIO_OUT HDMIRX_REG(0x08ec)
#define HDMI_RX_HDCP2_ESM_P0_GPIO_IN HDMIRX_REG(0x08f0)
#define HDMI_RX_HDCP2_ESM_P0_GPIO_OUT HDMIRX_REG(0x08f4)
#define HDMI_RX_HDCP22_STATUS HDMIRX_REG(0x08fc)
#define HDMI_RX_HDMI2_IEN_CLR HDMIRX_REG(0x0f60)
#define HDMI_RX_HDMI2_IEN_SET HDMIRX_REG(0x0f64)
#define HDMI_RX_HDMI2_ISTS HDMIRX_REG(0x0f68)
#define HDMI_RX_HDMI2_IEN HDMIRX_REG(0x0f6c)
#define HDMI_RX_HDMI2_ICLR HDMIRX_REG(0x0f70)
#define HDMI_RX_HDMI2_ISET HDMIRX_REG(0x0f74)
#define HDMI_RX_PDEC_IEN_CLR HDMIRX_REG(0x0f78)
#define HDMI_RX_PDEC_IEN_SET HDMIRX_REG(0x0f7c)
#define ACR_N_CHG_IEN BIT(23)
#define ACR_CTS_CHG_IEN BIT(22)
#define GCP_AV_MUTE_CHG_ENSET BIT(21)
#define AIF_RCV_ENSET BIT(19)
#define AVI_RCV_ENSET BIT(18)
#define GCP_RCV_ENSET BIT(16)
#define AMP_RCV_ENSET BIT(14)
#define HDMI_RX_PDEC_ISTS HDMIRX_REG(0x0f80)
#define AVI_RCV_ISTS BIT(18)
#define HDMI_RX_PDEC_IEN HDMIRX_REG(0x0f84)
#define HDMI_RX_PDEC_ICLR HDMIRX_REG(0x0f88)
#define AVI_RCV_ICLR BIT(18)
#define HDMI_RX_PDEC_ISET HDMIRX_REG(0x0f8c)
#define HDMI_RX_AUD_CEC_IEN_CLR HDMIRX_REG(0x0f90)
#define HDMI_RX_AUD_CEC_IEN_SET HDMIRX_REG(0x0f94)
#define HDMI_RX_AUD_CEC_ISTS HDMIRX_REG(0x0f98)
#define HDMI_RX_AUD_CEC_IEN HDMIRX_REG(0x0f9c)
#define HDMI_RX_AUD_CEC_ICLR HDMIRX_REG(0x0fa0)
#define HDMI_RX_AUD_CEC_ISET HDMIRX_REG(0x0fa4)
#define HDMI_RX_AUD_FIFO_IEN_CLR HDMIRX_REG(0x0fa8)
#define HDMI_RX_AUD_FIFO_IEN_SET HDMIRX_REG(0x0fac)
#define HDMI_RX_AUD_FIFO_ISTS HDMIRX_REG(0x0fb0)
#define HDMI_RX_AUD_FIFO_IEN HDMIRX_REG(0x0fb4)
#define HDMI_RX_AUD_FIFO_ICLR HDMIRX_REG(0x0fb8)
#define HDMI_RX_AUD_FIFO_ISET HDMIRX_REG(0x0fbc)
#define HDMI_RX_MD_IEN_CLR HDMIRX_REG(0x0fc0)
#define HDMI_RX_MD_IEN_SET HDMIRX_REG(0x0fc4)
#define VACT_LIN_ENSET BIT(9)
#define HACT_PIX_ENSET BIT(6)
#define HS_CLK_ENSET BIT(5)
#define DE_ACTIVITY_ENSET BIT(2)
#define VS_ACT_ENSET BIT(1)
#define HS_ACT_ENSET BIT(0)
#define HDMI_RX_MD_ISTS HDMIRX_REG(0x0fc8)
#define HDMI_RX_MD_IEN HDMIRX_REG(0x0fcc)
#define HDMI_RX_MD_ICLR HDMIRX_REG(0x0fd0)
#define HDMI_RX_MD_ISET HDMIRX_REG(0x0fd4)
#define HDMI_RX_HDMI_IEN_CLR HDMIRX_REG(0x0fd8)
#define HDMI_RX_HDMI_IEN_SET HDMIRX_REG(0x0fdc)
#define HDCP_DKSET_DONE_ENCLR_MASK BIT(31)
#define HDCP_DKSET_DONE_ENCLR(x) UPDATE(x, 31, 31)
#define HDMI_RX_HDMI_ISTS HDMIRX_REG(0x0fe0)
#define HDMI_RX_HDMI_IEN HDMIRX_REG(0x0fe4)
#define HDMI_RX_HDMI_ICLR HDMIRX_REG(0x0fe8)
#define HDMI_RX_HDMI_ISET HDMIRX_REG(0x0fec)
#define HDMI_RX_DMI_SW_RST HDMIRX_REG(0x0ff0)
#define HDMI_RX_DMI_DISABLE_IF HDMIRX_REG(0x0ff4)
#define MAIN_ENABLE BIT(0)
#define MODET_ENABLE BIT(1)
#define HDMI_ENABLE BIT(2)
#define BUS_ENABLE BIT(3)
#define AUD_ENABLE BIT(4)
#define CEC_ENABLE BIT(5)
#define PIXEL_ENABLE BIT(6)
#define VID_ENABLE_MASK BIT(7)
#define VID_ENABLE(x) UPDATE(x, 7, 7)
#define TMDS_ENABLE_MASK BIT(16)
#define TMDS_ENABLE(x) UPDATE(x, 16, 16)
#define HDMI_RX_DMI_MODULE_ID_EXT HDMIRX_REG(0x0ff8)
#define HDMI_RX_DMI_MODULE_ID HDMIRX_REG(0x0ffc)
#define HDMI_RX_CEC_CTRL HDMIRX_REG(0x1f00)
#define HDMI_RX_CEC_MASK HDMIRX_REG(0x1f08)
#define HDMI_RX_CEC_ADDR_L HDMIRX_REG(0x1f14)
#define HDMI_RX_CEC_ADDR_H HDMIRX_REG(0x1f18)
#define HDMI_RX_CEC_TX_CNT HDMIRX_REG(0x1f1c)
#define HDMI_RX_CEC_RX_CNT HDMIRX_REG(0x1f20)
#define HDMI_RX_CEC_TX_DATA_0 HDMIRX_REG(0x1f40)
#define HDMI_RX_CEC_TX_DATA_1 HDMIRX_REG(0x1f44)
#define HDMI_RX_CEC_TX_DATA_2 HDMIRX_REG(0x1f48)
#define HDMI_RX_CEC_TX_DATA_3 HDMIRX_REG(0x1f4c)
#define HDMI_RX_CEC_TX_DATA_4 HDMIRX_REG(0x1f50)
#define HDMI_RX_CEC_TX_DATA_5 HDMIRX_REG(0x1f54)
#define HDMI_RX_CEC_TX_DATA_6 HDMIRX_REG(0x1f58)
#define HDMI_RX_CEC_TX_DATA_7 HDMIRX_REG(0x1f5c)
#define HDMI_RX_CEC_TX_DATA_8 HDMIRX_REG(0x1f60)
#define HDMI_RX_CEC_TX_DATA_9 HDMIRX_REG(0x1f64)
#define HDMI_RX_CEC_TX_DATA_10 HDMIRX_REG(0x1f68)
#define HDMI_RX_CEC_TX_DATA_11 HDMIRX_REG(0x1f6c)
#define HDMI_RX_CEC_TX_DATA_12 HDMIRX_REG(0x1f70)
#define HDMI_RX_CEC_TX_DATA_13 HDMIRX_REG(0x1f74)
#define HDMI_RX_CEC_TX_DATA_14 HDMIRX_REG(0x1f78)
#define HDMI_RX_CEC_TX_DATA_15 HDMIRX_REG(0x1f7c)
#define HDMI_RX_CEC_RX_DATA_0 HDMIRX_REG(0x1f80)
#define HDMI_RX_CEC_RX_DATA_1 HDMIRX_REG(0x1f84)
#define HDMI_RX_CEC_RX_DATA_2 HDMIRX_REG(0x1f88)
#define HDMI_RX_CEC_RX_DATA_3 HDMIRX_REG(0x1f8c)
#define HDMI_RX_CEC_RX_DATA_4 HDMIRX_REG(0x1f90)
#define HDMI_RX_CEC_RX_DATA_5 HDMIRX_REG(0x1f94)
#define HDMI_RX_CEC_RX_DATA_6 HDMIRX_REG(0x1f98)
#define HDMI_RX_CEC_RX_DATA_7 HDMIRX_REG(0x1f9c)
#define HDMI_RX_CEC_RX_DATA_8 HDMIRX_REG(0x1fa0)
#define HDMI_RX_CEC_RX_DATA_9 HDMIRX_REG(0x1fa4)
#define HDMI_RX_CEC_RX_DATA_10 HDMIRX_REG(0x1fa8)
#define HDMI_RX_CEC_RX_DATA_11 HDMIRX_REG(0x1fac)
#define HDMI_RX_CEC_RX_DATA_12 HDMIRX_REG(0x1fb0)
#define HDMI_RX_CEC_RX_DATA_13 HDMIRX_REG(0x1fb4)
#define HDMI_RX_CEC_RX_DATA_14 HDMIRX_REG(0x1fb8)
#define HDMI_RX_CEC_RX_DATA_15 HDMIRX_REG(0x1fbc)
#define HDMI_RX_CEC_LOCK HDMIRX_REG(0x1fc0)
#define HDMI_RX_CEC_WAKEUPCTRL HDMIRX_REG(0x1fc4)
#define HDMI_RX_CBUSSWRESETREQ HDMIRX_REG(0x3000)
#define HDMI_RX_CBUSENABLEIF HDMIRX_REG(0x3004)
#define HDMI_RX_CB_LOCKONCLOCK_STS HDMIRX_REG(0x3010)
#define HDMI_RX_CB_LOCKONCLOCKCLR HDMIRX_REG(0x3014)
#define HDMI_RX_CBUSIOCTRL HDMIRX_REG(0x3020)
#define HDMI_RX_DD_CTRL HDMIRX_REG(0x3040)
#define HDMI_RX_DD_OP_CTRL HDMIRX_REG(0x3044)
#define HDMI_RX_DD_STS HDMIRX_REG(0x3048)
#define HDMI_RX_DD_BYPASS_EN HDMIRX_REG(0x304c)
#define HDMI_RX_DD_BYPASS_CTRL HDMIRX_REG(0x3050)
#define HDMI_RX_DD_BYPASS_CBUS HDMIRX_REG(0x3054)
#define HDMI_RX_LL_TXPCKFIFO HDMIRX_REG(0x3080)
#define HDMI_RX_LL_RXPCKFIFO_RD_CLR HDMIRX_REG(0x3084)
#define HDMI_RX_LL_RXPCKFIFO_A HDMIRX_REG(0x3088)
#define HDMI_RX_LL_RXPCKFIFO_B HDMIRX_REG(0x308c)
#define HDMI_RX_LL_TXPCKCTRL_0 HDMIRX_REG(0x3090)
#define HDMI_RX_LL_TXPCKCTRL_1 HDMIRX_REG(0x3094)
#define HDMI_RX_LL_PCKFIFO_STS HDMIRX_REG(0x309c)
#define HDMI_RX_LL_RXPCKCTRL_0 HDMIRX_REG(0x30a0)
#define HDMI_RX_LL_RXPCKCTRL_1 HDMIRX_REG(0x30a4)
#define HDMI_RX_LL_INTTRSHLDCTRL HDMIRX_REG(0x30b0)
#define HDMI_RX_LL_INTCNTCTRL HDMIRX_REG(0x30b4)
#define HDMI_RX_LL_INTCNT_0 HDMIRX_REG(0x30b8)
#define HDMI_RX_LL_INTCNT_1 HDMIRX_REG(0x30bc)
#define HDMI_RX_CBHDCP_OPCTRL HDMIRX_REG(0x3100)
#define HDMI_RX_CBHDCP_WDATA_0 HDMIRX_REG(0x3104)
#define HDMI_RX_CBHDCP_WDATA_1 HDMIRX_REG(0x3108)
#define HDMI_RX_CBHDCP_RDATA_0 HDMIRX_REG(0x310c)
#define HDMI_RX_CBHDCP_RDATA_1 HDMIRX_REG(0x3110)
#define HDMI_RX_CBHDCP_STATUS HDMIRX_REG(0x3114)
#define HDMI_RX_CBHDCP_DDC_REPORT HDMIRX_REG(0x3118)
#define HDMI_RX_ISTAT_CB_DD HDMIRX_REG(0x3200)
#define HDMI_RX_IMASK_CB_DD HDMIRX_REG(0x3204)
#define HDMI_RX_IFORCE_CB_DD HDMIRX_REG(0x3208)
#define HDMI_RX_ICLEAR_CB_DD HDMIRX_REG(0x320c)
#define HDMI_RX_IMUTE_CB_DD HDMIRX_REG(0x3210)
#define HDMI_RX_ISTAT_CB_LL HDMIRX_REG(0x3220)
#define HDMI_RX_IMASK_CB_LL HDMIRX_REG(0x3224)
#define HDMI_RX_IFORCE_CB_LL HDMIRX_REG(0x3228)
#define HDMI_RX_ICLEAR_CB_LL HDMIRX_REG(0x322c)
#define HDMI_RX_IMUTE_CB_LL HDMIRX_REG(0x3230)
#define HDMI_RX_ISTAT_CB_HDCP HDMIRX_REG(0x3240)
#define HDMI_RX_IMASK_CB_HDCP HDMIRX_REG(0x3244)
#define HDMI_RX_IFORCE_CB_HDCP HDMIRX_REG(0x3248)
#define HDMI_RX_ICLEAR_CB_HDCP HDMIRX_REG(0x324c)
#define HDMI_RX_IMUTE_CB_HDCP HDMIRX_REG(0x3250)
#define HDMI_RX_ISTAT_CB_MCTRL HDMIRX_REG(0x3260)
#define HDMI_RX_IMASK_CB_MCTRL HDMIRX_REG(0x3264)
#define HDMI_RX_IFORCE_CB_MCTRL HDMIRX_REG(0x3268)
#define HDMI_RX_ICLEAR_CB_MCTRL HDMIRX_REG(0x326c)
#define HDMI_RX_IMUTE_CB_MCTRL HDMIRX_REG(0x3270)
#define HDMI_RX_IMASTER_MUTE_CB HDMIRX_REG(0x32e0)
#define HDMI_RX_IVECTOR_INDEX_CB HDMIRX_REG(0x32e4)
#define HDMI_RX_MAX_REGISTER HDMI_RX_IVECTOR_INDEX_CB
#define EDID_NUM_BLOCKS_MAX 2
#define EDID_BLOCK_SIZE 128
#define HDMIRX_PLUGIN BIT(0)
#define HDMIRX_PLUGOUT BIT(1)
#define HDMIRX_CHANGED BIT(2)
#define HDMIRX_NOSIGNAL BIT(3)
#define HDMIRX_NOLOCK BIT(4)
void rk628_hdmirx_enable_interrupts(struct rk628 *rk628, bool en);
int rk628_hdmirx_enable(struct rk628 *rk628);
void rk628_hdmirx_disable(struct rk628 *rk628);
int rk628_hdmirx_detect(struct rk628 *rk628);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,350 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Chen Shunqing <csq@rock-chips.com>
*/
#ifndef HDMITX_H
#define HDMITX_H
#include "rk628.h"
#define HDMI_BASE 0x70000
#define HDMI_REG_STRIDE 4
#define HDMITX_REG(x) ((x * HDMI_REG_STRIDE) + HDMI_BASE)
#define DDC_SEGMENT_ADDR 0x30
enum PWR_MODE {
NORMAL,
LOWER_PWR,
};
#define HDMI_SCL_RATE (100 * 1000)
#define DDC_BUS_FREQ_L HDMITX_REG(0x4b)
#define DDC_BUS_FREQ_H HDMITX_REG(0x4c)
#define HDMI_SYS_CTRL HDMITX_REG(0x00)
#define RST_ANALOG_MASK BIT(6)
#define NOT_RST_ANALOG(x) UPDATE(x, 6, 6)
#define RST_DIGITAL_MASK BIT(5)
#define NOT_RST_DIGITAL(x) UPDATE(x, 5, 5)
#define REG_CLK_INV_MASK BIT(4)
#define REG_CLK_INV(x) UPDATE(x, 4, 4)
#define VCLK_INV_MASK BIT(3)
#define VCLK_INV(x) UPDATE(x, 3, 3)
#define REG_CLK_SOURCE_MASK BIT(2)
#define REG_CLK_SOURCE(x) UPDATE(x, 2, 2)
#define POWER_MASK BIT(1)
#define PWR_OFF(x) UPDATE(x, 1, 1)
#define INT_POL_MASK BIT(0)
#define INT_POL(x) UPDATE(x, 0, 0)
#define HDMI_VIDEO_CONTROL1 HDMITX_REG(0x01)
#define VIDEO_INPUT_FORMAT_MASK GENMASK(3, 1)
#define VIDEO_INPUT_SDR_RGB444 UPDATE(0x0, 3, 1)
#define VIDEO_INPUT_DDR_RGB444 UPDATE(0x5, 3, 1)
#define VIDEO_INPUT_DDR_YCBCR422 UPDATE(0x6, 3, 1)
#define DE_SOURCE_MASK BIT(0)
#define DE_SOURCE(x) UPDATE(x, 0, 0)
#define HDMI_VIDEO_CONTROL2 HDMITX_REG(0x02)
#define VIDEO_OUTPUT_COLOR_MASK GENMASK(7, 6)
#define VIDEO_OUTPUT_RRGB444 UPDATE(0x0, 7, 6)
#define VIDEO_OUTPUT_YCBCR444 UPDATE(0x1, 7, 6)
#define VIDEO_OUTPUT_YCBCR422 UPDATE(0x2, 7, 6)
#define VIDEO_INPUT_BITS_MASK GENMASK(5, 4)
#define VIDEO_INPUT_12BITS UPDATE(0x0, 5, 4)
#define VIDEO_INPUT_10BITS UPDATE(0x1, 5, 4)
#define VIDEO_INPUT_REVERT UPDATE(0x2, 5, 4)
#define VIDEO_INPUT_8BITS UPDATE(0x3, 5, 4)
#define VIDEO_INPUT_CSP_MASK BIT(1)
#define VIDEO_INPUT_CSP(x) UPDATE(x, 0, 0)
#define HDMI_VIDEO_CONTROL HDMITX_REG(0x03)
#define VIDEO_AUTO_CSC_MASK BIT(7)
#define VIDEO_AUTO_CSC(x) UPDATE(x, 7, 7)
#define VIDEO_C0_C2_SWAP_MASK BIT(0)
#define VIDEO_C0_C2_SWAP(x) UPDATE(x, 0, 0)
enum {
C0_C2_CHANGE_ENABLE = 0,
C0_C2_CHANGE_DISABLE = 1,
AUTO_CSC_DISABLE = 0,
AUTO_CSC_ENABLE = 1,
};
#define HDMI_VIDEO_CONTROL3 HDMITX_REG(0x04)
#define COLOR_DEPTH_NOT_INDICATED_MASK BIT(4)
#define COLOR_DEPTH_NOT_INDICATED(x) UPDATE(x, 4, 4)
#define SOF_MASK BIT(3)
#define SOF_DISABLE(x) UPDATE(x, 3, 3)
#define CSC_MASK BIT(0)
#define CSC_ENABLE(x) UPDATE(x, 0, 0)
#define HDMI_AV_MUTE HDMITX_REG(0x05)
#define AVMUTE_CLEAR_MASK BIT(7)
#define AVMUTE_CLEAR(x) UPDATE(x, 7, 7)
#define AVMUTE_ENABLE_MASK BIT(6)
#define AVMUTE_ENABLE(x) UPDATE(x, 6, 6)
#define AUDIO_PD_MASK BIT(2)
#define AUDIO_PD(x) UPDATE(x, 2, 2)
#define AUDIO_MUTE_MASK BIT(1)
#define AUDIO_MUTE(x) UPDATE(x, 1, 1)
#define VIDEO_BLACK_MASK BIT(0)
#define VIDEO_MUTE(x) UPDATE(x, 0, 0)
#define HDMI_VIDEO_TIMING_CTL HDMITX_REG(0x08)
#define HSYNC_POLARITY(x) UPDATE(x, 3, 3)
#define VSYNC_POLARITY(x) UPDATE(x, 2, 2)
#define INETLACE(x) UPDATE(x, 1, 1)
#define EXTERANL_VIDEO(x) UPDATE(x, 0, 0)
#define HDMI_VIDEO_EXT_HTOTAL_L HDMITX_REG(0x09)
#define HDMI_VIDEO_EXT_HTOTAL_H HDMITX_REG(0x0a)
#define HDMI_VIDEO_EXT_HBLANK_L HDMITX_REG(0x0b)
#define HDMI_VIDEO_EXT_HBLANK_H HDMITX_REG(0x0c)
#define HDMI_VIDEO_EXT_HDELAY_L HDMITX_REG(0x0d)
#define HDMI_VIDEO_EXT_HDELAY_H HDMITX_REG(0x0e)
#define HDMI_VIDEO_EXT_HDURATION_L HDMITX_REG(0x0f)
#define HDMI_VIDEO_EXT_HDURATION_H HDMITX_REG(0x10)
#define HDMI_VIDEO_EXT_VTOTAL_L HDMITX_REG(0x11)
#define HDMI_VIDEO_EXT_VTOTAL_H HDMITX_REG(0x12)
#define HDMI_VIDEO_EXT_VBLANK HDMITX_REG(0x13)
#define HDMI_VIDEO_EXT_VDELAY HDMITX_REG(0x14)
#define HDMI_VIDEO_EXT_VDURATION HDMITX_REG(0x15)
#define HDMI_VIDEO_CSC_COEF HDMITX_REG(0x18)
#define HDMI_AUDIO_CTRL1 HDMITX_REG(0x35)
enum {
CTS_SOURCE_INTERNAL = 0,
CTS_SOURCE_EXTERNAL = 1,
};
#define CTS_SOURCE(x) UPDATE(x, 7, 7)
enum {
DOWNSAMPLE_DISABLE = 0,
DOWNSAMPLE_1_2 = 1,
DOWNSAMPLE_1_4 = 2,
};
#define DOWN_SAMPLE(x) UPDATE(x, 6, 5)
enum {
AUDIO_SOURCE_IIS = 0,
AUDIO_SOURCE_SPDIF = 1,
};
#define AUDIO_SOURCE(x) UPDATE(x, 4, 3)
#define MCLK_ENABLE(x) UPDATE(x, 2, 2)
enum {
MCLK_128FS = 0,
MCLK_256FS = 1,
MCLK_384FS = 2,
MCLK_512FS = 3,
};
#define MCLK_RATIO(x) UPDATE(x, 1, 0)
#define AUDIO_SAMPLE_RATE HDMITX_REG(0x37)
enum {
AUDIO_32K = 0x3,
AUDIO_441K = 0x0,
AUDIO_48K = 0x2,
AUDIO_882K = 0x8,
AUDIO_96K = 0xa,
AUDIO_1764K = 0xc,
AUDIO_192K = 0xe,
};
#define AUDIO_I2S_MODE HDMITX_REG(0x38)
enum {
I2S_CHANNEL_1_2 = 1,
I2S_CHANNEL_3_4 = 3,
I2S_CHANNEL_5_6 = 7,
I2S_CHANNEL_7_8 = 0xf
};
#define I2S_CHANNEL(x) UPDATE(x, 5, 2)
enum {
I2S_STANDARD = 0,
I2S_LEFT_JUSTIFIED = 1,
I2S_RIGHT_JUSTIFIED = 2,
};
#define I2S_MODE(x) UPDATE(x, 1, 0)
#define AUDIO_I2S_MAP HDMITX_REG(0x39)
#define AUDIO_I2S_SWAPS_SPDIF HDMITX_REG(0x3a)
#define N_32K 0x1000
#define N_441K 0x1880
#define N_882K 0x3100
#define N_1764K 0x6200
#define N_48K 0x1800
#define N_96K 0x3000
#define N_192K 0x6000
#define HDMI_AUDIO_CHANNEL_STATUS HDMITX_REG(0x3e)
#define AUDIO_STATUS_NLPCM_MASK BIT(7)
#define AUDIO_STATUS_NLPCM(x) UPDATE(x, 7, 7)
#define AUDIO_STATUS_USE_MASK BIT(6)
#define AUDIO_STATUS_COPYRIGHT_MASK BIT(5)
#define AUDIO_STATUS_ADDITION_MASK GENMASK(3, 2)
#define AUDIO_STATUS_CLK_ACCURACY_MASK GENMASK(1, 1)
#define AUDIO_N_H HDMITX_REG(0x3f)
#define AUDIO_N_M HDMITX_REG(0x40)
#define AUDIO_N_L HDMITX_REG(0x41)
#define HDMI_AUDIO_CTS_H HDMITX_REG(0x45)
#define HDMI_AUDIO_CTS_M HDMITX_REG(0x46)
#define HDMI_AUDIO_CTS_L HDMITX_REG(0x47)
#define HDMI_DDC_CLK_L HDMITX_REG(0x4b)
#define HDMI_DDC_CLK_H HDMITX_REG(0x4c)
#define HDMI_EDID_SEGMENT_POINTER HDMITX_REG(0x4d)
#define HDMI_EDID_WORD_ADDR HDMITX_REG(0x4e)
#define HDMI_EDID_FIFO_OFFSET HDMITX_REG(0x4f)
#define HDMI_EDID_FIFO_ADDR HDMITX_REG(0x50)
#define HDMI_PACKET_SEND_MANUAL HDMITX_REG(0x9c)
#define HDMI_PACKET_SEND_AUTO HDMITX_REG(0x9d)
#define PACKET_GCP_EN_MASK BIT(7)
#define PACKET_GCP_EN(x) UPDATE(x, 7, 7)
#define PACKET_MSI_EN_MASK BIT(6)
#define PACKET_MSI_EN(x) UPDATE(x, 6, 6)
#define PACKET_SDI_EN_MASK BIT(5)
#define PACKET_SDI_EN(x) UPDATE(x, 5, 5)
#define PACKET_VSI_EN_MASK BIT(4)
#define PACKET_VSI_EN(x) UPDATE(x, 4, 4)
#define HDMI_CONTROL_PACKET_BUF_INDEX HDMITX_REG(0x9f)
enum {
INFOFRAME_VSI = 0x05,
INFOFRAME_AVI = 0x06,
INFOFRAME_AAI = 0x08,
};
#define HDMI_CONTROL_PACKET_ADDR HDMITX_REG(0xa0)
#define HDMI_MAXIMUM_INFO_FRAME_SIZE 0x11
enum {
AVI_COLOR_MODE_RGB = 0,
AVI_COLOR_MODE_YCBCR422 = 1,
AVI_COLOR_MODE_YCBCR444 = 2,
AVI_COLORIMETRY_NO_DATA = 0,
AVI_COLORIMETRY_SMPTE_170M = 1,
AVI_COLORIMETRY_ITU709 = 2,
AVI_COLORIMETRY_EXTENDED = 3,
AVI_CODED_FRAME_ASPECT_NO_DATA = 0,
AVI_CODED_FRAME_ASPECT_4_3 = 1,
AVI_CODED_FRAME_ASPECT_16_9 = 2,
ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
ACTIVE_ASPECT_RATE_4_3 = 0x09,
ACTIVE_ASPECT_RATE_16_9 = 0x0A,
ACTIVE_ASPECT_RATE_14_9 = 0x0B,
};
#define HDMI_HDCP_CTRL HDMITX_REG(0x52)
#define HDMI_DVI_MASK BIT(1)
#define HDMI_DVI(x) UPDATE(x, 1, 1)
#define HDMI_INTERRUPT_MASK1 HDMITX_REG(0xc0)
#define INT_EDID_READY_MASK BIT(2)
#define HDMI_INTERRUPT_STATUS1 HDMITX_REG(0xc1)
#define INT_ACTIVE_VSYNC_MASK BIT(5)
#define INT_EDID_READY BIT(2)
#define HDMI_INTERRUPT_MASK2 HDMITX_REG(0xc2)
#define HDMI_INTERRUPT_STATUS2 HDMITX_REG(0xc3)
#define INT_HDCP_ERR BIT(7)
#define INT_BKSV_FLAG BIT(6)
#define INT_HDCP_OK BIT(4)
#define HDMI_STATUS HDMITX_REG(0xc8)
#define HOTPLUG_STATUS BIT(7)
#define MASK_INT_HOTPLUG_MASK BIT(5)
#define MASK_INT_HOTPLUG(x) UPDATE(x, 5, 5)
#define INT_HOTPLUG BIT(1)
#define HDMI_COLORBAR HDMITX_REG(0xc9)
#define HDMI_PHY_SYNC HDMITX_REG(0xce)
#define HDMI_PHY_SYS_CTL HDMITX_REG(0xe0)
#define TMDS_CLK_SOURCE_MASK BIT(5)
#define TMDS_CLK_SOURCE(x) UPDATE(x, 5, 5)
#define PHASE_CLK_MASK BIT(4)
#define PHASE_CLK(x) UPDATE(x, 4, 4)
#define TMDS_PHASE_SEL_MASK BIT(3)
#define TMDS_PHASE_SEL(x) UPDATE(x, 3, 3)
#define BANDGAP_PWR_MASK BIT(2)
#define BANDGAP_PWR(x) UPDATE(x, 2, 2)
#define PLL_PWR_DOWN_MASK BIT(1)
#define PLL_PWR_DOWN(x) UPDATE(x, 1, 1)
#define TMDS_CHG_PWR_DOWN_MASK BIT(0)
#define TMDS_CHG_PWR_DOWN(x) UPDATE(x, 0, 0)
#define HDMI_PHY_CHG_PWR HDMITX_REG(0xe1)
#define CLK_CHG_PWR(x) UPDATE(x, 3, 3)
#define DATA_CHG_PWR(x) UPDATE(x, 2, 0)
#define HDMI_PHY_DRIVER HDMITX_REG(0xe2)
#define CLK_MAIN_DRIVER(x) UPDATE(x, 7, 4)
#define DATA_MAIN_DRIVER(x) UPDATE(x, 3, 0)
#define HDMI_PHY_PRE_EMPHASIS HDMITX_REG(0xe3)
#define PRE_EMPHASIS(x) UPDATE(x, 6, 4)
#define CLK_PRE_DRIVER(x) UPDATE(x, 3, 2)
#define DATA_PRE_DRIVER(x) UPDATE(x, 1, 0)
#define PHY_FEEDBACK_DIV_RATIO_LOW HDMITX_REG(0xe7)
#define FEEDBACK_DIV_LOW(x) UPDATE(x, 7, 0)
#define PHY_FEEDBACK_DIV_RATIO_HIGH HDMITX_REG(0xe8)
#define FEEDBACK_DIV_HIGH(x) UPDATE(x, 0, 0)
#define HDMI_PHY_PRE_DIV_RATIO HDMITX_REG(0xed)
#define PRE_DIV_RATIO(x) UPDATE(x, 4, 0)
#define HDMI_CEC_CTRL HDMITX_REG(0xd0)
#define ADJUST_FOR_HISENSE_MASK BIT(6)
#define REJECT_RX_BROADCAST_MASK BIT(5)
#define BUSFREETIME_ENABLE_MASK BIT(2)
#define REJECT_RX_MASK BIT(1)
#define START_TX_MASK BIT(0)
#define HDMI_CEC_DATA HDMITX_REG(0xd1)
#define HDMI_CEC_TX_OFFSET HDMITX_REG(0xd2)
#define HDMI_CEC_RX_OFFSET HDMITX_REG(0xd3)
#define HDMI_CEC_CLK_H HDMITX_REG(0xd4)
#define HDMI_CEC_CLK_L HDMITX_REG(0xd5)
#define HDMI_CEC_TX_LENGTH HDMITX_REG(0xd6)
#define HDMI_CEC_RX_LENGTH HDMITX_REG(0xd7)
#define HDMI_CEC_TX_INT_MASK HDMITX_REG(0xd8)
#define TX_DONE_MASK BIT(3)
#define TX_NOACK_MASK BIT(2)
#define TX_BROADCAST_REJ_MASK BIT(1)
#define TX_BUSNOTFREE_MASK BIT(0)
#define HDMI_CEC_RX_INT_MASK HDMITX_REG(0xd9)
#define RX_LA_ERR_MASK BIT(4)
#define RX_GLITCH_MASK BIT(3)
#define RX_DONE_MASK BIT(0)
#define HDMI_CEC_TX_INT HDMITX_REG(0xda)
#define HDMI_CEC_RX_INT HDMITX_REG(0xdb)
#define HDMI_CEC_BUSFREETIME_L HDMITX_REG(0xdc)
#define HDMI_CEC_BUSFREETIME_H HDMITX_REG(0xdd)
#define HDMI_CEC_LOGICADDR HDMITX_REG(0xde)
#define HDMI_MAX_REG HDMITX_REG(0xed)
int rk628_hdmitx_enable(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,126 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include "rk628.h"
#include "rk628_combtxphy.h"
#include "rk628_config.h"
#include "panel.h"
static inline void lvds_write(struct rk628 *rk628, u32 reg, u32 val)
{
rk628_i2c_write(rk628, reg, val);
}
static inline void lvds_update_bits(struct rk628 *rk628, u32 reg,
u32 mask, u32 val)
{
rk628_i2c_update_bits(rk628, reg, mask, val);
}
int rk628_lvds_parse(struct rk628 *rk628, struct device_node *lvds_np)
{
const char *string;
int ret;
if (!of_device_is_available(lvds_np))
return -EINVAL;
rk628->output_mode = OUTPUT_MODE_LVDS;
if (!of_property_read_string(lvds_np, "bus-format", &string)) {
if (!strcmp(string, "jeida_24"))
rk628->lvds.format = LVDS_FORMAT_JEIDA_24BIT;
else if (!strcmp(string, "jeida_18"))
rk628->lvds.format = LVDS_FORMAT_JEIDA_18BIT;
else if (!strcmp(string, "vesa_18"))
rk628->lvds.format = LVDS_FORMAT_VESA_18BIT;
else
rk628->lvds.format = LVDS_FORMAT_VESA_24BIT;
}
if (!of_property_read_string(lvds_np, "link-type", &string)) {
if (!strcmp(string, "dual_link_odd_even_pixels"))
rk628->lvds.link_type = LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
else if (!strcmp(string, "dual_link_even_odd_pixels"))
rk628->lvds.link_type = LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
else if (!strcmp(string, "dual_link_left_right_pixels"))
rk628->lvds.link_type = LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS;
else if (!strcmp(string, "dual_link_right_left_pixels"))
rk628->lvds.link_type = LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS;
else
rk628->lvds.link_type = LVDS_SINGLE_LINK;
}
ret = rk628_panel_info_get(rk628, lvds_np);
if (ret)
return ret;
return 0;
}
void rk628_lvds_enable(struct rk628 *rk628)
{
enum lvds_link_type link_type = rk628->lvds.link_type;
enum lvds_format format = rk628->lvds.format;
const struct rk628_display_mode *mode = &rk628->dst_mode;
u32 val, bus_width;
lvds_update_bits(rk628, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_LVDS));
switch (link_type) {
case LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(0) |
SW_LVDS_CON_DUAL_SEL(0);
bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
break;
case LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(1) |
SW_LVDS_CON_DUAL_SEL(0);
bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
break;
case LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS:
val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(0) |
SW_LVDS_CON_DUAL_SEL(1);
lvds_update_bits(rk628, GRF_POST_PROC_CON,
SW_SPLIT_EN, SW_SPLIT_EN);
bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
break;
case LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS:
val = SW_LVDS_CON_CHASEL(1) | SW_LVDS_CON_STARTSEL(1) |
SW_LVDS_CON_DUAL_SEL(1);
lvds_update_bits(rk628, GRF_POST_PROC_CON,
SW_SPLIT_EN, SW_SPLIT_EN);
bus_width = COMBTXPHY_MODULEA_EN | COMBTXPHY_MODULEB_EN;
break;
case LVDS_SINGLE_LINK:
default:
val = SW_LVDS_CON_CHASEL(0) | SW_LVDS_CON_STARTSEL(0) |
SW_LVDS_CON_DUAL_SEL(0);
bus_width = COMBTXPHY_MODULEA_EN;
break;
}
val |= SW_LVDS_CON_SELECT(format) | SW_LVDS_CON_MSBSEL(0) |
SW_LVDS_CON_CLKINV(0);
lvds_write(rk628, GRF_LVDS_TX_CON, val);
bus_width |= (mode->clock / 1000) << 8;
rk628_combtxphy_set_bus_width(rk628, bus_width);
rk628_combtxphy_set_mode(rk628, PHY_MODE_VIDEO_LVDS);
rk628_combtxphy_power_on(rk628);
rk628_panel_prepare(rk628);
rk628_panel_enable(rk628);
}
void rk628_lvds_disable(struct rk628 *rk628)
{
rk628_panel_disable(rk628);
rk628_panel_unprepare(rk628);
rk628_combtxphy_power_off(rk628);
}

View File

@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#ifndef RK628_LVDS_H
#define RK628_LVDS_H
int rk628_lvds_parse(struct rk628 *rk628, struct device_node *lvds_np);
void rk628_lvds_enable(struct rk628 *rk628);
void rk628_lvds_disable(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,326 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#include "rk628.h"
static int rk628_calc_mux_offset(struct rk628 *rk628, int mux, int reg, int offset)
{
int val = 0, orig;
switch (reg) {
case GRF_SYSTEM_CON3:
rk628_i2c_read(rk628, reg, &orig);
if (mux)
val = BIT(offset) | orig;
else
val = ~BIT(offset) & orig;
break;
case GRF_GPIO0AB_SEL_CON:
if (offset >= 4 && offset < 8) {
offset += offset - 4;
val = 0x3 << (offset + 16) | (mux << offset);
} else if (offset > 7) {
offset += 4;
val = BIT(offset + 16) | (mux << offset);
} else {
val = BIT(offset + 16) | (mux << offset);
}
break;
case GRF_GPIO1AB_SEL_CON:
if (offset == 13)
offset++;
if (offset > 11)
val = 0x3 << (offset + 16) | (mux << offset);
else
val = BIT(offset + 16) | (mux << offset);
break;
case GRF_GPIO2AB_SEL_CON:
val = BIT(offset + 16) | (mux << offset);
break;
case GRF_GPIO2C_SEL_CON:
offset -= 16;
val = 0x3 << ((offset*2) + 16) | (mux << (offset*2));
break;
case GRF_GPIO3AB_SEL_CON:
if (offset > 11)
val = 0x3 << (offset + 16) | (mux << offset);
else
val = BIT(offset + 16) | (mux << offset);
break;
default:
break;
}
return val;
}
int rk628_misc_pinctrl_set_mux(struct rk628 *rk628, int gpio, int mux)
{
int i, iomux_base, offset, val;
mux &= 0x3;
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
if (rk628_pin_iomux_groups[i].pins == gpio) {
iomux_base = rk628_pin_iomux_groups[i].iomux_base;
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
break;
}
}
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!iomux_base)) {
pr_info("%s invalid gpio or iomux_base\n", __func__);
return -1;
}
val = rk628_calc_mux_offset(rk628, mux, iomux_base, offset);
rk628_i2c_write(rk628, iomux_base, val);
return 0;
}
/* generic gpio chip */
int rk628_misc_gpio_get_value(struct rk628 *rk628, int gpio)
{
int i, data_reg, offset, val;
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
if (rk628_pin_iomux_groups[i].pins == gpio) {
data_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_EXT_PORT;
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
break;
}
}
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!data_reg)) {
pr_info("%s invalid gpio or data_reg\n", __func__);
return -1;
}
rk628_i2c_read(rk628, data_reg, &val);
val >>= offset;
val &= 1;
return val;
}
int rk628_misc_gpio_set_value(struct rk628 *rk628, int gpio, int value)
{
int i, data_reg, offset, val;
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
if (rk628_pin_iomux_groups[i].pins == gpio) {
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
if (offset >= 16) {
data_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_SWPORT_DR_H;
offset -= 16;
} else {
data_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_SWPORT_DR_L;
}
break;
}
}
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!data_reg)) {
pr_info("%s invalid gpio or data_reg\n", __func__);
return -1;
}
if (value)
val = BIT(offset + 16) | BIT(offset);
else
val = BIT(offset + 16) | (0xffff & ~BIT(offset));
rk628_i2c_write(rk628, data_reg, val);
return 0;
}
int rk628_misc_gpio_set_direction(struct rk628 *rk628, int gpio, int direction)
{
int i, dir_reg, offset, val;
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
if (rk628_pin_iomux_groups[i].pins == gpio) {
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
if (offset >= 16) {
dir_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_SWPORT_DDR_H;
offset -= 16;
} else {
dir_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_SWPORT_DDR_L;
}
break;
}
}
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!dir_reg)) {
pr_info("%s invalid gpio or dir_reg\n", __func__);
return -1;
}
if (!direction)
val = BIT(offset + 16) | (0xffff & ~BIT(offset));
else
val = BIT(offset + 16) | BIT(offset);
rk628_i2c_write(rk628, dir_reg, val);
return 0;
}
int rk628_misc_iomux_init(struct rk628 *rk628)
{
int i, iomux_base, offset, val, mux;
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
mux = rk628_pin_iomux_groups[i].mux;
iomux_base = rk628_pin_iomux_groups[i].iomux_base;
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
if (iomux_base) {
val = rk628_calc_mux_offset(rk628, mux, iomux_base, offset);
rk628_i2c_write(rk628, iomux_base, val);
}
}
return 0;
}
int rk628_misc_gpio_direction_input(struct rk628 *rk628, int gpio)
{
rk628_misc_pinctrl_set_mux(rk628, gpio, GPIO_FUNC);
rk628_misc_gpio_set_direction(rk628, gpio, GPIO_DIRECTION_IN);
return 0;
}
int rk628_misc_gpio_direction_output(struct rk628 *rk628, int gpio, int value)
{
rk628_misc_pinctrl_set_mux(rk628, gpio, GPIO_FUNC);
rk628_misc_gpio_set_value(rk628, gpio, value);
rk628_misc_gpio_set_direction(rk628, gpio, GPIO_DIRECTION_OUT);
return 0;
}
int rk628_misc_gpio_set_pull_highz_up_down(struct rk628 *rk628, int gpio, int pull)
{
int i, bank, pull_reg = 0, offset, val = 0;
int valid_pinnum[] = { 8, 8, 24, 13 };
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
if (rk628_pin_iomux_groups[i].pins == gpio) {
bank = rk628_pin_iomux_groups[i].bank;
pull_reg = rk628_pin_iomux_groups[i].pull_reg;
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
break;
}
}
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!pull_reg)) {
pr_info("rk628_gpio_pull_highz_up_down invalid gpio or pull_reg\n");
return -1;
}
switch (bank) {
case GPIO_BANK0:
if (pull == GPIO_PULL_UP)
return -1;
if (offset == 2)
return -1;
if (offset < valid_pinnum[bank])
val = 0x3 << (2 * offset + 16) | pull << (2 * offset);
break;
case GPIO_BANK1:
if (pull == GPIO_PULL_UP)
return -1;
if (offset == 2)
return -1;
if (offset < valid_pinnum[bank])
val = 0x3 << (2 * offset + 16) | pull << (2 * offset);
break;
case GPIO_BANK2:
if (pull == GPIO_PULL_UP)
pull = GPIO_PULL_DOWN;
else if (pull == GPIO_PULL_DOWN)
pull = GPIO_PULL_UP;
if (offset < valid_pinnum[bank]) {
offset = offset % 8;
val = 0x3 << (2 * offset + 16) | pull << (2 * offset);
}
break;
case GPIO_BANK3:
if (pull == GPIO_PULL_UP && (offset == 2 || offset == 11 || offset == 12))
return -1;
else if (pull == GPIO_PULL_DOWN && (offset == 9 || offset == 10))
return -1;
if (offset == 0 || offset == 1 || offset == 3 || offset == 8) {
if (pull == GPIO_PULL_UP)
pull = GPIO_PULL_DOWN;
else if (pull == GPIO_PULL_DOWN)
pull = GPIO_PULL_UP;
}
if ((offset > 7 && offset < valid_pinnum[bank]) || offset < 4) {
offset = offset % 8;
val = 0x3 << (2 * offset + 16) | pull << (2 * offset);
}
break;
default:
break;
}
rk628_i2c_write(rk628, pull_reg, val);
return 0;
}
int rk628_misc_gpio_test_all(struct rk628 *rk628)
{
int i;
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
if (rk628_pin_iomux_groups[i].pins && (rk628_pin_iomux_groups[i].pins != GPIO1_A1)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C0)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C1)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C2)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C3)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C4))
rk628_misc_gpio_direction_output(rk628, rk628_pin_iomux_groups[i].pins, 1);
}
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
if (rk628_pin_iomux_groups[i].pins && (rk628_pin_iomux_groups[i].pins != GPIO1_A1)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C0)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C1)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C2)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C3)
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C4))
rk628_misc_gpio_direction_output(rk628, rk628_pin_iomux_groups[i].pins, 0);
}
return 0;
}

View File

@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#ifndef RK628_PINCTRL_H
#define RK628_PINCTRL_H
int rk628_misc_pinctrl_set_mux(struct rk628 *rk628, int gpio, int mux);
int rk628_misc_gpio_get_value(struct rk628 *rk628, int gpio);
int rk628_misc_gpio_set_value(struct rk628 *rk628, int gpio, int value);
int rk628_misc_gpio_set_direction(struct rk628 *rk628, int gpio, int direction);
int rk628_misc_gpio_direction_input(struct rk628 *rk628, int gpio);
int rk628_misc_gpio_direction_output(struct rk628 *rk628, int gpio, int value);
int rk628_misc_gpio_set_pull_highz_up_down(struct rk628 *rk628, int gpio, int pull);
#endif // RK628_PINCTRL_H

View File

@@ -0,0 +1,268 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#include "rk628.h"
#include "rk628_config.h"
#include "rk628_cru.h"
static void calc_dsp_frm_hst_vst(const struct rk628_display_mode *src,
const struct rk628_display_mode *dst,
u32 *dsp_frame_hst,
u32 *dsp_frame_vst)
{
u32 bp_in, bp_out;
u32 v_scale_ratio;
u64 t_frm_st;
u64 t_bp_in, t_bp_out, t_delta, tin;
u32 src_pixclock, dst_pixclock;
u32 dst_htotal, dst_hsync_len, dst_hback_porch;
u32 dst_vsync_len, dst_vback_porch, dst_vactive;
u32 src_htotal, src_hsync_len, src_hback_porch;
u32 src_vtotal, src_vsync_len, src_vback_porch, src_vactive;
u32 rem;
u32 x;
src_pixclock = div_u64(1000000000llu, src->clock);
dst_pixclock = div_u64(1000000000llu, dst->clock);
src_hsync_len = src->hsync_end - src->hsync_start;
src_hback_porch = src->htotal - src->hsync_end;
src_htotal = src->htotal;
src_vsync_len = src->vsync_end - src->vsync_start;
src_vback_porch = src->vtotal - src->vsync_end;
src_vactive = src->vdisplay;
src_vtotal = src->vtotal;
dst_hsync_len = dst->hsync_end - dst->hsync_start;
dst_hback_porch = dst->htotal - dst->hsync_end;
dst_htotal = dst->htotal;
dst_vsync_len = dst->vsync_end - dst->vsync_start;
dst_vback_porch = dst->vtotal - dst->vsync_end;
dst_vactive = dst->vdisplay;
bp_in = (src_vback_porch + src_vsync_len) * src_htotal +
src_hsync_len + src_hback_porch;
bp_out = (dst_vback_porch + dst_vsync_len) * dst_htotal +
dst_hsync_len + dst_hback_porch;
t_bp_in = bp_in * src_pixclock;
t_bp_out = bp_out * dst_pixclock;
tin = src_vtotal * src_htotal * src_pixclock;
v_scale_ratio = src_vactive / dst_vactive;
x = 5;
__retry:
if (v_scale_ratio <= 2)
t_delta = x * src_htotal * src_pixclock;
else
t_delta = 12 * src_htotal * src_pixclock;
if (t_bp_in + t_delta > t_bp_out)
t_frm_st = (t_bp_in + t_delta - t_bp_out);
else
t_frm_st = tin - (t_bp_out - (t_bp_in + t_delta));
do_div(t_frm_st, src_pixclock);
rem = do_div(t_frm_st, src_htotal);
if ((t_frm_st < 2 || t_frm_st > 14) && x < 12) {
x++;
goto __retry;
}
if (t_frm_st < 2 || t_frm_st > 14)
t_frm_st = 4;
*dsp_frame_hst = rem;
*dsp_frame_vst = t_frm_st;
}
static void rk628_post_process_scaler_init(struct rk628 *rk628,
struct rk628_display_mode *src,
const struct rk628_display_mode *dst)
{
u32 dsp_frame_hst, dsp_frame_vst;
u32 scl_hor_mode, scl_ver_mode;
u32 scl_v_factor, scl_h_factor;
u32 dsp_htotal, dsp_hs_end, dsp_hact_st, dsp_hact_end;
u32 dsp_vtotal, dsp_vs_end, dsp_vact_st, dsp_vact_end;
u32 dsp_hbor_end, dsp_hbor_st, dsp_vbor_end, dsp_vbor_st;
u16 bor_right = 0, bor_left = 0, bor_up = 0, bor_down = 0;
u8 hor_down_mode = 0, ver_down_mode = 0;
u32 dst_hsync_len, dst_hback_porch, dst_hfront_porch, dst_hactive;
u32 dst_vsync_len, dst_vback_porch, dst_vfront_porch, dst_vactive;
u32 src_hactive;
u32 src_vactive;
src_hactive = src->hdisplay;
src_vactive = src->vdisplay;
dst_hactive = dst->hdisplay;
dst_hsync_len = dst->hsync_end - dst->hsync_start;
dst_hback_porch = dst->htotal - dst->hsync_end;
dst_hfront_porch = dst->hsync_start - dst->hdisplay;
dst_vsync_len = dst->vsync_end - dst->vsync_start;
dst_vback_porch = dst->vtotal - dst->vsync_end;
dst_vfront_porch = dst->vsync_start - dst->vdisplay;
dst_vactive = dst->vdisplay;
dsp_htotal = dst_hsync_len + dst_hback_porch +
dst_hactive + dst_hfront_porch;
dsp_vtotal = dst_vsync_len + dst_vback_porch +
dst_vactive + dst_vfront_porch;
dsp_hs_end = dst_hsync_len;
dsp_vs_end = dst_vsync_len;
dsp_hbor_end = dst_hsync_len + dst_hback_porch + dst_hactive;
dsp_hbor_st = dst_hsync_len + dst_hback_porch;
dsp_vbor_end = dst_vsync_len + dst_vback_porch + dst_vactive;
dsp_vbor_st = dst_vsync_len + dst_vback_porch;
dsp_hact_st = dsp_hbor_st + bor_left;
dsp_hact_end = dsp_hbor_end - bor_right;
dsp_vact_st = dsp_vbor_st + bor_up;
dsp_vact_end = dsp_vbor_end - bor_down;
calc_dsp_frm_hst_vst(src, dst, &dsp_frame_hst, &dsp_frame_vst);
dev_info(rk628->dev, "dsp_frame_vst:%d dsp_frame_hst:%d\n",
dsp_frame_vst, dsp_frame_hst);
if (src_hactive > dst_hactive) {
scl_hor_mode = 2;
if (hor_down_mode == 0) {
if ((src_hactive - 1) / (dst_hactive - 1) > 2)
scl_h_factor = ((src_hactive - 1) << 14) /
(dst_hactive - 1);
else
scl_h_factor = ((src_hactive - 2) << 14) /
(dst_hactive - 1);
} else {
scl_h_factor = (dst_hactive << 16) / (src_hactive - 1);
}
} else if (src_hactive == dst_hactive) {
scl_hor_mode = 0;
scl_h_factor = 0;
} else {
scl_hor_mode = 1;
scl_h_factor = ((src_hactive - 1) << 16) / (dst_hactive - 1);
}
if (src_vactive > dst_vactive) {
scl_ver_mode = 2;
if (ver_down_mode == 0) {
if ((src_vactive - 1) / (dst_vactive - 1) > 2)
scl_v_factor = ((src_vactive - 1) << 14) /
(dst_vactive - 1);
else
scl_v_factor = ((src_vactive - 2) << 14) /
(dst_vactive - 1);
} else {
scl_v_factor = (dst_vactive << 16) / (src_vactive - 1);
}
} else if (src_vactive == dst_vactive) {
scl_ver_mode = 0;
scl_v_factor = 0;
} else {
scl_ver_mode = 1;
scl_v_factor = ((src_vactive - 1) << 16) / (dst_vactive - 1);
}
rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON0, SW_HRES_MASK,
SW_HRES(src_hactive));
rk628_i2c_write(rk628, GRF_SCALER_CON0, SCL_VER_DOWN_MODE(ver_down_mode) |
SCL_HOR_DOWN_MODE(hor_down_mode) |
SCL_VER_MODE(scl_ver_mode) |
SCL_HOR_MODE(scl_hor_mode));
rk628_i2c_write(rk628, GRF_SCALER_CON1, SCL_V_FACTOR(scl_v_factor) |
SCL_H_FACTOR(scl_h_factor));
rk628_i2c_write(rk628, GRF_SCALER_CON2, DSP_FRAME_VST(dsp_frame_vst) |
DSP_FRAME_HST(dsp_frame_hst));
rk628_i2c_write(rk628, GRF_SCALER_CON3, DSP_HS_END(dsp_hs_end) |
DSP_HTOTAL(dsp_htotal));
rk628_i2c_write(rk628, GRF_SCALER_CON4, DSP_HACT_END(dsp_hact_end) |
DSP_HACT_ST(dsp_hact_st));
rk628_i2c_write(rk628, GRF_SCALER_CON5, DSP_VS_END(dsp_vs_end) |
DSP_VTOTAL(dsp_vtotal));
rk628_i2c_write(rk628, GRF_SCALER_CON6, DSP_VACT_END(dsp_vact_end) |
DSP_VACT_ST(dsp_vact_st));
rk628_i2c_write(rk628, GRF_SCALER_CON7, DSP_HBOR_END(dsp_hbor_end) |
DSP_HBOR_ST(dsp_hbor_st));
rk628_i2c_write(rk628, GRF_SCALER_CON8, DSP_VBOR_END(dsp_vbor_end) |
DSP_VBOR_ST(dsp_vbor_st));
}
void rk628_post_process_init(struct rk628 *rk628)
{
struct rk628_display_mode *src = &rk628->src_mode;
const struct rk628_display_mode *dst = &rk628->dst_mode;
u64 dst_rate, src_rate;
src_rate = src->clock * 1000;
dst_rate = src_rate * dst->vdisplay * dst->htotal;
do_div(dst_rate, (src->vdisplay * src->htotal));
do_div(dst_rate, 1000);
dev_info(rk628->dev, "src %dx%d clock:%d\n",
src->hdisplay, src->vdisplay, src->clock);
dev_info(rk628->dev, "dst %dx%d clock:%llu\n",
dst->hdisplay, dst->vdisplay, dst_rate);
rk628_cru_clk_set_rate(rk628, CGU_CLK_RX_READ, src->clock * 1000);
rk628_cru_clk_set_rate(rk628, CGU_SCLK_VOP, dst_rate * 1000);
if (rk628->output_mode == OUTPUT_MODE_HDMI) {
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_VSYNC_POL_MASK,
SW_VSYNC_POL(rk628->sync_pol));
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_HSYNC_POL_MASK,
SW_HSYNC_POL(rk628->sync_pol));
} else {
if (src->flags & DRM_MODE_FLAG_PVSYNC)
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_VSYNC_POL_MASK, SW_VSYNC_POL(1));
if (src->flags & DRM_MODE_FLAG_PHSYNC)
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_HSYNC_POL_MASK,
SW_HSYNC_POL(1));
}
rk628_post_process_scaler_init(rk628, src, dst);
}
static void rk628_post_process_csc(struct rk628 *rk628)
{
enum bus_format in_fmt, out_fmt;
in_fmt = rk628_get_input_bus_format(rk628);
out_fmt = rk628_get_output_bus_format(rk628);
if (in_fmt == out_fmt) {
if (out_fmt == BUS_FMT_YUV422) {
rk628_i2c_write(rk628, GRF_CSC_CTRL_CON,
SW_YUV2VYU_SWP(1) |
SW_R2Y_EN(0));
return;
}
rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_R2Y_EN(0));
rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_Y2R_EN(0));
return;
}
if (in_fmt == BUS_FMT_RGB)
rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_R2Y_EN(1));
else if (out_fmt == BUS_FMT_RGB)
rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_Y2R_EN(1));
}
void rk628_post_process_enable(struct rk628 *rk628)
{
rk628_post_process_csc(rk628);
rk628_i2c_write(rk628, GRF_SCALER_CON0, SCL_EN(1));
}
void rk628_post_process_disable(struct rk628 *rk628)
{
rk628_i2c_write(rk628, GRF_SCALER_CON0, SCL_EN(0));
}

View File

@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#ifndef POST_PROCESS_H
#define POST_PROCESS_H
void rk628_post_process_init(struct rk628 *rk628);
void rk628_post_process_enable(struct rk628 *rk628);
void rk628_post_process_disable(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,166 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include "rk628.h"
#include "rk628_cru.h"
#include "rk628_config.h"
#include "panel.h"
void rk628_rgb_decoder_enable(struct rk628 *rk628)
{
/* config sw_input_mode RGB */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_INPUT_MODE_MASK,
SW_INPUT_MODE(INPUT_MODE_RGB));
/* pinctrl for vop pin */
rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff);
rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555);
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b);
/* rk628: modify IO drive strength for RGB */
rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, 0xffff1011);
rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, 0x10001);
}
void rk628_rgb_encoder_enable(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_BT_DATA_OEN_MASK | SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_RGB));
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, SW_DCLK_OUT_INV_EN,
SW_DCLK_OUT_INV_EN);
}
void rk628_rgb_encoder_disable(struct rk628 *rk628)
{
rk628_panel_disable(rk628);
rk628_panel_unprepare(rk628);
}
void rk628_rgb_rx_enable(struct rk628 *rk628)
{
rk628_rgb_decoder_enable(rk628);
}
void rk628_rgb_tx_enable(struct rk628 *rk628)
{
rk628_rgb_encoder_enable(rk628);
rk628_panel_prepare(rk628);
rk628_panel_enable(rk628);
}
void rk628_rgb_tx_disable(struct rk628 *rk628)
{
rk628_panel_disable(rk628);
}
void rk628_bt1120_decoder_enable(struct rk628 *rk628)
{
struct rk628_display_mode *mode = rk628_display_get_src_mode(rk628);
/* pinctrl for vop pin */
rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff);
rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555);
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b);
/* rk628: modify IO drive strength for RGB */
rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, 0xffff1011);
rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, 0x10001);
/* config sw_input_mode bt1120 */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_INPUT_MODE_MASK,
SW_INPUT_MODE(INPUT_MODE_BT1120));
/* operation resetn_bt1120dec */
rk628_i2c_write(rk628, CRU_SOFTRST_CON00, 0x10001000);
rk628_i2c_write(rk628, CRU_SOFTRST_CON00, 0x10000000);
rk628_cru_clk_set_rate(rk628, CGU_BT1120DEC, mode->clock * 1000);
#ifdef BT1120_DUAL_EDGE
rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON0,
DEC_DUALEDGE_EN, DEC_DUALEDGE_EN);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0);
#endif
rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON1, SW_SET_X_MASK,
SW_SET_X(mode->hdisplay));
rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON2, SW_SET_Y_MASK,
SW_SET_Y(mode->vdisplay));
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_BT_DATA_OEN_MASK | SW_INPUT_MODE_MASK,
SW_BT_DATA_OEN | SW_INPUT_MODE(INPUT_MODE_BT1120));
rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_Y2R_EN(1));
rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON0,
SW_CAP_EN_PSYNC | SW_CAP_EN_ASYNC | SW_PROGRESS_EN,
SW_CAP_EN_PSYNC | SW_CAP_EN_ASYNC | SW_PROGRESS_EN);
}
void rk628_bt1120_encoder_enable(struct rk628 *rk628)
{
u32 val = 0;
/* pinctrl for vop pin */
rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff);
rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555);
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b);
/* rk628: modify IO drive strength for RGB */
rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, 0xffff1011);
rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, 0x10001);
/* config sw_input_mode bt1120 */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_BT_DATA_OEN_MASK | SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_BT1120));
rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_R2Y_EN(1));
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN);
#ifdef BT1120_DUAL_EDGE
val |= ENC_DUALEDGE_EN(1);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0);
#endif
val |= BT1120_UV_SWAP(1);
rk628_i2c_write(rk628, GRF_RGB_ENC_CON, val);
}
void rk628_bt1120_rx_enable(struct rk628 *rk628)
{
rk628_bt1120_decoder_enable(rk628);
}
void rk628_bt1120_tx_enable(struct rk628 *rk628)
{
rk628_bt1120_encoder_enable(rk628);
}

View File

@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#ifndef RK628_RGB_H
#define RK628_RGB_H
#include "rk628.h"
void rk628_rgb_rx_enable(struct rk628 *rk628);
void rk628_rgb_tx_enable(struct rk628 *rk628);
void rk628_rgb_tx_disable(struct rk628 *rk628);
void rk628_bt1120_rx_enable(struct rk628 *rk628);
void rk628_bt1120_tx_enable(struct rk628 *rk628);
#endif