mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-24 19:40:21 +09:00
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:
@@ -5,6 +5,8 @@
|
||||
|
||||
menu "Misc devices"
|
||||
|
||||
source "drivers/misc/rk628/Kconfig"
|
||||
|
||||
config RK803
|
||||
tristate "RK803"
|
||||
default n
|
||||
|
||||
@@ -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
|
||||
|
||||
27
drivers/misc/rk628/Kconfig
Normal file
27
drivers/misc/rk628/Kconfig
Normal 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
|
||||
10
drivers/misc/rk628/Makefile
Normal file
10
drivers/misc/rk628/Makefile
Normal 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
245
drivers/misc/rk628/panel.c
Normal 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);
|
||||
|
||||
}
|
||||
18
drivers/misc/rk628/panel.h
Normal file
18
drivers/misc/rk628/panel.h
Normal 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
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
484
drivers/misc/rk628/rk628.h
Normal 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
|
||||
567
drivers/misc/rk628/rk628_combrxphy.c
Normal file
567
drivers/misc/rk628/rk628_combrxphy.c
Normal 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 1’b0.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=32’h25c3f8)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
16
drivers/misc/rk628/rk628_combrxphy.h
Normal file
16
drivers/misc/rk628/rk628_combrxphy.h
Normal 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
|
||||
309
drivers/misc/rk628/rk628_combtxphy.c
Normal file
309
drivers/misc/rk628/rk628_combtxphy.c
Normal 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;
|
||||
}
|
||||
82
drivers/misc/rk628/rk628_combtxphy.h
Normal file
82
drivers/misc/rk628/rk628_combtxphy.h
Normal 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
|
||||
52
drivers/misc/rk628/rk628_config.c
Normal file
52
drivers/misc/rk628/rk628_config.c
Normal 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;
|
||||
}
|
||||
24
drivers/misc/rk628/rk628_config.h
Normal file
24
drivers/misc/rk628/rk628_config.h
Normal 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
|
||||
|
||||
472
drivers/misc/rk628/rk628_cru.c
Normal file
472
drivers/misc/rk628/rk628_cru.c
Normal 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);
|
||||
}
|
||||
159
drivers/misc/rk628/rk628_cru.h
Normal file
159
drivers/misc/rk628/rk628_cru.h
Normal 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
|
||||
434
drivers/misc/rk628/rk628_csi.c
Normal file
434
drivers/misc/rk628/rk628_csi.c
Normal 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);
|
||||
}
|
||||
86
drivers/misc/rk628/rk628_csi.h
Normal file
86
drivers/misc/rk628/rk628_csi.h
Normal 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
|
||||
1310
drivers/misc/rk628/rk628_dsi.c
Normal file
1310
drivers/misc/rk628/rk628_dsi.c
Normal file
File diff suppressed because it is too large
Load Diff
158
drivers/misc/rk628/rk628_dsi.h
Normal file
158
drivers/misc/rk628/rk628_dsi.h
Normal 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
|
||||
296
drivers/misc/rk628/rk628_gpio.h
Normal file
296
drivers/misc/rk628/rk628_gpio.h
Normal 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
|
||||
|
||||
|
||||
263
drivers/misc/rk628/rk628_grf.h
Normal file
263
drivers/misc/rk628/rk628_grf.h
Normal 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
|
||||
|
||||
|
||||
230
drivers/misc/rk628/rk628_gvi.c
Normal file
230
drivers/misc/rk628/rk628_gvi.c
Normal 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);
|
||||
}
|
||||
|
||||
218
drivers/misc/rk628/rk628_gvi.h
Normal file
218
drivers/misc/rk628/rk628_gvi.h
Normal 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
|
||||
777
drivers/misc/rk628/rk628_hdmirx.c
Normal file
777
drivers/misc/rk628/rk628_hdmirx.c
Normal 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;
|
||||
}
|
||||
633
drivers/misc/rk628/rk628_hdmirx.h
Normal file
633
drivers/misc/rk628/rk628_hdmirx.h
Normal 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
|
||||
1198
drivers/misc/rk628/rk628_hdmitx.c
Normal file
1198
drivers/misc/rk628/rk628_hdmitx.c
Normal file
File diff suppressed because it is too large
Load Diff
350
drivers/misc/rk628/rk628_hdmitx.h
Normal file
350
drivers/misc/rk628/rk628_hdmitx.h
Normal 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
|
||||
126
drivers/misc/rk628/rk628_lvds.c
Normal file
126
drivers/misc/rk628/rk628_lvds.c
Normal 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);
|
||||
}
|
||||
15
drivers/misc/rk628/rk628_lvds.h
Normal file
15
drivers/misc/rk628/rk628_lvds.h
Normal 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
|
||||
326
drivers/misc/rk628/rk628_pinctrl.c
Normal file
326
drivers/misc/rk628/rk628_pinctrl.c
Normal 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;
|
||||
}
|
||||
|
||||
19
drivers/misc/rk628/rk628_pinctrl.h
Normal file
19
drivers/misc/rk628/rk628_pinctrl.h
Normal 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
|
||||
268
drivers/misc/rk628/rk628_post_process.c
Normal file
268
drivers/misc/rk628/rk628_post_process.c
Normal 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));
|
||||
}
|
||||
15
drivers/misc/rk628/rk628_post_process.h
Normal file
15
drivers/misc/rk628/rk628_post_process.h
Normal 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
|
||||
166
drivers/misc/rk628/rk628_rgb.c
Normal file
166
drivers/misc/rk628/rk628_rgb.c
Normal 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);
|
||||
}
|
||||
|
||||
17
drivers/misc/rk628/rk628_rgb.h
Normal file
17
drivers/misc/rk628/rk628_rgb.h
Normal 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
|
||||
Reference in New Issue
Block a user