mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 11:26:02 +09:00
media: i2c: rk628: fix display error
1. fix black screen when plugout/plugin. 2. fix abnormal display when resolution change. Change-Id: Iecc06805fa1d4f7abbc5d496200ad411185eecd7 Signed-off-by: Chen Shunqing <csq@rock-chips.com>
This commit is contained in:
@@ -52,7 +52,7 @@ static const struct regmap_range rk628_hdmirx_readable_ranges[] = {
|
||||
regmap_reg_range(HDMI_RX_HDMI_MODE_RECOVER, HDMI_RX_HDMI_ERROR_PROTECT),
|
||||
regmap_reg_range(HDMI_RX_HDMI_SYNC_CTRL, HDMI_RX_HDMI_CKM_RESULT),
|
||||
regmap_reg_range(HDMI_RX_HDMI_RESMPL_CTRL, HDMI_RX_HDMI_RESMPL_CTRL),
|
||||
regmap_reg_range(HDMI_VM_CFG_CH2, HDMI_VM_CFG_CH2),
|
||||
regmap_reg_range(HDMI_VM_CFG_CH0_1, HDMI_VM_CFG_CH2),
|
||||
regmap_reg_range(HDMI_RX_HDCP_CTRL, HDMI_RX_HDCP_SETTINGS),
|
||||
regmap_reg_range(HDMI_RX_HDCP_KIDX, HDMI_RX_HDCP_KIDX),
|
||||
regmap_reg_range(HDMI_RX_HDCP_DBG, HDMI_RX_HDCP_AN0),
|
||||
|
||||
@@ -47,22 +47,6 @@ MODULE_PARM_DESC(debug, "debug level (0-3)");
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x1, 0x0)
|
||||
#define RK628_BT1120_NAME "rk628-bt1120"
|
||||
|
||||
#define EDID_NUM_BLOCKS_MAX 2
|
||||
#define EDID_BLOCK_SIZE 128
|
||||
|
||||
#define RK628_CSI_LINK_FREQ_LOW 350000000
|
||||
#define RK628_CSI_LINK_FREQ_HIGH 400000000
|
||||
#define RK628_CSI_PIXEL_RATE_LOW 400000000
|
||||
#define RK628_CSI_PIXEL_RATE_HIGH 600000000
|
||||
#define MIPI_DATARATE_MBPS_LOW 750
|
||||
#define MIPI_DATARATE_MBPS_HIGH 1250
|
||||
|
||||
#define POLL_INTERVAL_MS 1000
|
||||
#define RXPHY_CFG_MAX_TIMES 15
|
||||
#define CSITX_ERR_RETRY_TIMES 3
|
||||
|
||||
#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)
|
||||
|
||||
@@ -251,7 +235,6 @@ static void rk628_bt1120_format_change(struct v4l2_subdev *sd);
|
||||
static void enable_stream(struct v4l2_subdev *sd, bool enable);
|
||||
static void rk628_hdmirx_vid_enable(struct v4l2_subdev *sd, bool en);
|
||||
static void rk628_hdmirx_hpd_ctrl(struct v4l2_subdev *sd, bool en);
|
||||
static void rk628_hdmirx_controller_reset(struct v4l2_subdev *sd);
|
||||
static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd);
|
||||
|
||||
static inline struct rk628_bt1120 *to_bt1120(struct v4l2_subdev *sd)
|
||||
@@ -348,17 +331,37 @@ static int rk628_bt1120_get_detected_timings(struct v4l2_subdev *sd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_plugout(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
|
||||
|
||||
enable_stream(sd, false);
|
||||
bt1120->nosignal = true;
|
||||
rk628_bt1120_enable_interrupts(sd, false);
|
||||
cancel_delayed_work(&bt1120->delayed_work_res_change);
|
||||
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
|
||||
rk628_hdmirx_hpd_ctrl(sd, false);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
rk628_hdmirx_controller_reset(bt1120->rk628);
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_config_all(struct v4l2_subdev *sd)
|
||||
{
|
||||
int ret;
|
||||
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
|
||||
|
||||
rk628_hdmirx_controller_setup(bt1120->rk628);
|
||||
ret = rk628_hdmirx_phy_setup(sd);
|
||||
if (ret >= 0) {
|
||||
if (ret >= 0 && !rk628_hdmirx_scdc_ced_err(bt1120->rk628)) {
|
||||
rk628_bt1120_format_change(sd);
|
||||
bt1120->nosignal = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret < 0 || rk628_hdmirx_scdc_ced_err(bt1120->rk628)) {
|
||||
rk628_hdmirx_plugout(sd);
|
||||
schedule_delayed_work(&bt1120->delayed_work_enable_hotplug,
|
||||
msecs_to_jiffies(800));
|
||||
}
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_reset_regfile(struct v4l2_subdev *sd)
|
||||
@@ -411,21 +414,15 @@ static void rk628_bt1120_delayed_work_enable_hotplug(struct work_struct *work)
|
||||
rk628_bt1120_enable_interrupts(sd, false);
|
||||
rk628_hdmirx_audio_setup(bt1120->audio_info);
|
||||
rk628_hdmirx_set_hdcp(bt1120->rk628, &bt1120->hdcp, bt1120->enable_hdcp);
|
||||
rk628_hdmirx_controller_setup(bt1120->rk628);
|
||||
rk628_hdmirx_hpd_ctrl(sd, true);
|
||||
rk628_hdmirx_config_all(sd);
|
||||
rk628_bt1120_enable_interrupts(sd, true);
|
||||
rk628_i2c_update_bits(bt1120->rk628, GRF_SYSTEM_CON0,
|
||||
SW_I2S_DATA_OEN_MASK, SW_I2S_DATA_OEN(0));
|
||||
} else {
|
||||
rk628_bt1120_enable_interrupts(sd, false);
|
||||
enable_stream(sd, false);
|
||||
cancel_delayed_work(&bt1120->delayed_work_res_change);
|
||||
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
|
||||
rk628_hdmirx_hpd_ctrl(sd, false);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
if (bt1120->rk628->version < RK628F_VERSION)
|
||||
rk628_hdmirx_controller_reset(sd);
|
||||
bt1120->nosignal = true;
|
||||
rk628_hdmirx_plugout(sd);
|
||||
rk628_set_io_func_to_gpio(bt1120->rk628);
|
||||
}
|
||||
mutex_unlock(&bt1120->confctl_mutex);
|
||||
@@ -468,7 +465,8 @@ static void rk628_delayed_work_res_change(struct work_struct *work)
|
||||
bool plugin;
|
||||
|
||||
mutex_lock(&bt1120->confctl_mutex);
|
||||
rk628_set_bg_enable(bt1120->rk628, false);
|
||||
enable_stream(sd, false);
|
||||
bt1120->nosignal = true;
|
||||
bt1120->avi_rcv_rdy = false;
|
||||
plugin = tx_5v_power_present(sd);
|
||||
v4l2_dbg(1, debug, sd, "%s: 5v_det:%d\n", __func__, plugin);
|
||||
@@ -476,19 +474,28 @@ static void rk628_delayed_work_res_change(struct work_struct *work)
|
||||
if (rk628_check_resulotion_change(sd)) {
|
||||
v4l2_dbg(1, debug, sd, "res change, recfg ctrler and phy!\n");
|
||||
|
||||
rk628_bt1120_enable_interrupts(sd, false);
|
||||
enable_stream(sd, false);
|
||||
cancel_delayed_work(&bt1120->delayed_work_res_change);
|
||||
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
|
||||
rk628_hdmirx_hpd_ctrl(sd, false);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
if (bt1120->rk628->version < RK628F_VERSION)
|
||||
rk628_hdmirx_controller_reset(sd);
|
||||
bt1120->nosignal = true;
|
||||
rk628_hdmirx_reset_regfile(sd);
|
||||
if (bt1120->rk628->version >= RK628F_VERSION) {
|
||||
rk628_bt1120_enable_interrupts(sd, false);
|
||||
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
|
||||
rk628_hdmirx_hpd_ctrl(sd, false);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
rk628_hdmirx_controller_reset(bt1120->rk628);
|
||||
schedule_delayed_work(&bt1120->delayed_work_enable_hotplug,
|
||||
msecs_to_jiffies(800));
|
||||
} else {
|
||||
rk628_bt1120_enable_interrupts(sd, false);
|
||||
enable_stream(sd, false);
|
||||
cancel_delayed_work(&bt1120->delayed_work_res_change);
|
||||
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
|
||||
rk628_hdmirx_controller_setup(bt1120->rk628);
|
||||
rk628_hdmirx_hpd_ctrl(sd, false);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
rk628_hdmirx_controller_reset(bt1120->rk628);
|
||||
bt1120->nosignal = true;
|
||||
rk628_hdmirx_reset_regfile(sd);
|
||||
}
|
||||
} else {
|
||||
rk628_bt1120_format_change(sd);
|
||||
bt1120->nosignal = false;
|
||||
rk628_bt1120_enable_interrupts(sd, true);
|
||||
}
|
||||
}
|
||||
@@ -591,9 +598,19 @@ static void enable_bt1120tx(struct v4l2_subdev *sd)
|
||||
static void enable_stream(struct v4l2_subdev *sd, bool en)
|
||||
{
|
||||
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
|
||||
u32 val;
|
||||
|
||||
v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, en ? "en" : "dis");
|
||||
if (en) {
|
||||
if (bt1120->rk628->version >= RK628F_VERSION) {
|
||||
rk628_i2c_read(bt1120->rk628, HDMI_RX_SCDC_REGS2, &val);
|
||||
if (rk628_hdmirx_scdc_ced_err(bt1120->rk628)) {
|
||||
rk628_hdmirx_plugout(sd);
|
||||
schedule_delayed_work(&bt1120->delayed_work_enable_hotplug,
|
||||
msecs_to_jiffies(800));
|
||||
return;
|
||||
}
|
||||
}
|
||||
rk628_hdmirx_vid_enable(sd, true);
|
||||
enable_bt1120tx(sd);
|
||||
} else {
|
||||
@@ -719,20 +736,6 @@ static void rk628_hdmirx_vid_enable(struct v4l2_subdev *sd, bool en)
|
||||
}
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_controller_reset(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
|
||||
|
||||
rk628_control_assert(bt1120->rk628, RGU_HDMIRX_PON);
|
||||
udelay(10);
|
||||
rk628_control_deassert(bt1120->rk628, RGU_HDMIRX_PON);
|
||||
udelay(10);
|
||||
rk628_i2c_write(bt1120->rk628, HDMI_RX_DMI_SW_RST, 0x000101ff);
|
||||
rk628_i2c_write(bt1120->rk628, HDMI_RX_DMI_DISABLE_IF, 0x00000000);
|
||||
rk628_i2c_write(bt1120->rk628, HDMI_RX_DMI_DISABLE_IF, 0x0000017f);
|
||||
rk628_i2c_write(bt1120->rk628, HDMI_RX_DMI_DISABLE_IF, 0x0001017f);
|
||||
}
|
||||
|
||||
static bool rk628_rcv_supported_res(struct v4l2_subdev *sd, u32 width,
|
||||
u32 height)
|
||||
{
|
||||
@@ -802,10 +805,10 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd)
|
||||
|
||||
if (cnt >= 15)
|
||||
break;
|
||||
} while (((status & 0xfff) != 0xf00) ||
|
||||
} while (((status & 0xfff) < 0xf00) ||
|
||||
(!rk628_rcv_supported_res(sd, width, height)));
|
||||
|
||||
if (((status & 0xfff) != 0xf00) ||
|
||||
if (((status & 0xfff) < 0xf00) ||
|
||||
(!rk628_rcv_supported_res(sd, width, height))) {
|
||||
v4l2_err(sd, "%s hdmi rxphy lock failed, retry:%d\n",
|
||||
__func__, i);
|
||||
@@ -865,7 +868,7 @@ static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd)
|
||||
SW_EFUSE_HDCP_EN(0) |
|
||||
SW_HSYNC_POL(1) |
|
||||
SW_VSYNC_POL(1));
|
||||
rk628_hdmirx_controller_reset(sd);
|
||||
rk628_hdmirx_controller_reset(bt1120->rk628);
|
||||
|
||||
def_edid.pad = 0;
|
||||
def_edid.start_block = 0;
|
||||
|
||||
@@ -52,22 +52,6 @@ MODULE_PARM_DESC(debug, "debug level (0-3)");
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x1, 0x0)
|
||||
#define RK628_CSI_NAME "rk628-csi"
|
||||
|
||||
#define EDID_NUM_BLOCKS_MAX 2
|
||||
#define EDID_BLOCK_SIZE 128
|
||||
|
||||
#define RK628_CSI_LINK_FREQ_LOW 350000000
|
||||
#define RK628_CSI_LINK_FREQ_HIGH 650000000
|
||||
#define RK628_CSI_PIXEL_RATE_LOW 400000000
|
||||
#define RK628_CSI_PIXEL_RATE_HIGH 600000000
|
||||
#define MIPI_DATARATE_MBPS_LOW 700
|
||||
#define MIPI_DATARATE_MBPS_HIGH 1300
|
||||
|
||||
#define POLL_INTERVAL_MS 1000
|
||||
#define RXPHY_CFG_MAX_TIMES 15
|
||||
#define CSITX_ERR_RETRY_TIMES 3
|
||||
|
||||
#define YUV422_8BIT 0x1e
|
||||
|
||||
enum tx_mode_type {
|
||||
CSI_MODE,
|
||||
DSI_MODE,
|
||||
@@ -350,7 +334,6 @@ static void enable_stream(struct v4l2_subdev *sd, bool enable);
|
||||
static void rk628_hdmirx_vid_enable(struct v4l2_subdev *sd, bool en);
|
||||
static void rk628_csi_set_csi(struct v4l2_subdev *sd);
|
||||
static void rk628_hdmirx_hpd_ctrl(struct v4l2_subdev *sd, bool en);
|
||||
static void rk628_hdmirx_controller_reset(struct v4l2_subdev *sd);
|
||||
static bool rk628_rcv_supported_res(struct v4l2_subdev *sd, u32 width,
|
||||
u32 height);
|
||||
static void rk628_dsi_set_scs(struct rk628_csi *csi);
|
||||
@@ -461,16 +444,36 @@ static int rk628_csi_get_detected_timings(struct v4l2_subdev *sd,
|
||||
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_plugout(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct rk628_csi *csi = to_csi(sd);
|
||||
|
||||
enable_stream(sd, false);
|
||||
csi->nosignal = true;
|
||||
rk628_csi_enable_interrupts(sd, false);
|
||||
cancel_delayed_work(&csi->delayed_work_res_change);
|
||||
rk628_hdmirx_audio_cancel_work_audio(csi->audio_info, true);
|
||||
rk628_hdmirx_hpd_ctrl(sd, false);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
rk628_hdmirx_controller_reset(csi->rk628);
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_config_all(struct v4l2_subdev *sd)
|
||||
{
|
||||
int ret;
|
||||
struct rk628_csi *csi = to_csi(sd);
|
||||
|
||||
rk628_hdmirx_controller_setup(csi->rk628);
|
||||
ret = rk628_hdmirx_phy_setup(sd);
|
||||
if (ret >= 0) {
|
||||
if (ret >= 0 && !rk628_hdmirx_scdc_ced_err(csi->rk628)) {
|
||||
rk628_csi_format_change(sd);
|
||||
csi->nosignal = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret < 0 || rk628_hdmirx_scdc_ced_err(csi->rk628)) {
|
||||
rk628_hdmirx_plugout(sd);
|
||||
schedule_delayed_work(&csi->delayed_work_enable_hotplug,
|
||||
msecs_to_jiffies(800));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,21 +495,14 @@ static void rk628_csi_delayed_work_enable_hotplug(struct work_struct *work)
|
||||
rk628_csi_enable_interrupts(sd, false);
|
||||
rk628_hdmirx_audio_setup(csi->audio_info);
|
||||
rk628_hdmirx_set_hdcp(csi->rk628, &csi->hdcp, csi->enable_hdcp);
|
||||
rk628_hdmirx_controller_setup(csi->rk628);
|
||||
rk628_hdmirx_hpd_ctrl(sd, true);
|
||||
rk628_hdmirx_config_all(sd);
|
||||
rk628_csi_enable_interrupts(sd, true);
|
||||
rk628_i2c_update_bits(csi->rk628, GRF_SYSTEM_CON0,
|
||||
SW_I2S_DATA_OEN_MASK, SW_I2S_DATA_OEN(0));
|
||||
} else {
|
||||
rk628_csi_enable_interrupts(sd, false);
|
||||
enable_stream(sd, false);
|
||||
cancel_delayed_work(&csi->delayed_work_res_change);
|
||||
rk628_hdmirx_audio_cancel_work_audio(csi->audio_info, true);
|
||||
rk628_hdmirx_hpd_ctrl(sd, false);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
if (csi->rk628->version < RK628F_VERSION)
|
||||
rk628_hdmirx_controller_reset(sd);
|
||||
csi->nosignal = true;
|
||||
rk628_hdmirx_plugout(sd);
|
||||
}
|
||||
mutex_unlock(&csi->confctl_mutex);
|
||||
if (csi->plat_data->tx_mode == DSI_MODE && plugin)
|
||||
@@ -550,28 +546,38 @@ static void rk628_delayed_work_res_change(struct work_struct *work)
|
||||
bool plugin;
|
||||
|
||||
mutex_lock(&csi->confctl_mutex);
|
||||
rk628_set_bg_enable(csi->rk628, false);
|
||||
enable_stream(sd, false);
|
||||
csi->nosignal = true;
|
||||
csi->avi_rcv_rdy = false;
|
||||
plugin = tx_5v_power_present(sd);
|
||||
v4l2_dbg(1, debug, sd, "%s: 5v_det:%d\n", __func__, plugin);
|
||||
if (plugin) {
|
||||
if (rk628_check_resulotion_change(sd)) {
|
||||
v4l2_dbg(1, debug, sd, "res change, recfg ctrler and phy!\n");
|
||||
rk628_hdmirx_audio_cancel_work_audio(csi->audio_info, true);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
if (csi->rk628->version < RK628F_VERSION)
|
||||
rk628_hdmirx_controller_reset(sd);
|
||||
rk628_hdmirx_audio_setup(csi->audio_info);
|
||||
rk628_hdmirx_set_hdcp(csi->rk628, &csi->hdcp, csi->enable_hdcp);
|
||||
rk628_hdmirx_hpd_ctrl(sd, true);
|
||||
rk628_hdmirx_config_all(sd);
|
||||
rk628_csi_enable_interrupts(sd, true);
|
||||
rk628_i2c_update_bits(csi->rk628, GRF_SYSTEM_CON0,
|
||||
SW_I2S_DATA_OEN_MASK,
|
||||
SW_I2S_DATA_OEN(0));
|
||||
if (csi->rk628->version >= RK628F_VERSION) {
|
||||
rk628_csi_enable_interrupts(sd, false);
|
||||
rk628_hdmirx_audio_cancel_work_audio(csi->audio_info, true);
|
||||
rk628_hdmirx_hpd_ctrl(sd, false);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
rk628_hdmirx_controller_reset(csi->rk628);
|
||||
schedule_delayed_work(&csi->delayed_work_enable_hotplug,
|
||||
msecs_to_jiffies(800));
|
||||
} else {
|
||||
rk628_hdmirx_audio_cancel_work_audio(csi->audio_info, true);
|
||||
rk628_hdmirx_inno_phy_power_off(sd);
|
||||
rk628_hdmirx_controller_reset(csi->rk628);
|
||||
rk628_hdmirx_audio_setup(csi->audio_info);
|
||||
rk628_hdmirx_set_hdcp(csi->rk628, &csi->hdcp, csi->enable_hdcp);
|
||||
rk628_hdmirx_controller_setup(csi->rk628);
|
||||
rk628_hdmirx_hpd_ctrl(sd, true);
|
||||
rk628_hdmirx_config_all(sd);
|
||||
rk628_csi_enable_interrupts(sd, true);
|
||||
rk628_i2c_update_bits(csi->rk628, GRF_SYSTEM_CON0,
|
||||
SW_I2S_DATA_OEN_MASK,
|
||||
SW_I2S_DATA_OEN(0));
|
||||
}
|
||||
} else {
|
||||
rk628_csi_format_change(sd);
|
||||
csi->nosignal = false;
|
||||
rk628_csi_enable_interrupts(sd, true);
|
||||
}
|
||||
}
|
||||
@@ -843,6 +849,13 @@ static void enable_stream(struct v4l2_subdev *sd, bool en)
|
||||
|
||||
v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, en ? "en" : "dis");
|
||||
if (en) {
|
||||
if (rk628_hdmirx_scdc_ced_err(csi->rk628)) {
|
||||
rk628_hdmirx_plugout(sd);
|
||||
schedule_delayed_work(&csi->delayed_work_enable_hotplug,
|
||||
msecs_to_jiffies(800));
|
||||
return;
|
||||
}
|
||||
|
||||
rk628_hdmirx_vid_enable(sd, true);
|
||||
if (csi->plat_data->tx_mode == DSI_MODE)
|
||||
enable_dsitx(sd);
|
||||
@@ -1170,21 +1183,6 @@ static void rk628_hdmirx_vid_enable(struct v4l2_subdev *sd, bool en)
|
||||
}
|
||||
}
|
||||
|
||||
static void rk628_hdmirx_controller_reset(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct rk628_csi *csi = to_csi(sd);
|
||||
|
||||
v4l2_dbg(1, debug, sd, "%s reset hdmirx_controller\n", __func__);
|
||||
rk628_control_assert(csi->rk628, RGU_HDMIRX_PON);
|
||||
udelay(10);
|
||||
rk628_control_deassert(csi->rk628, RGU_HDMIRX_PON);
|
||||
udelay(10);
|
||||
rk628_i2c_write(csi->rk628, HDMI_RX_DMI_SW_RST, 0x000101ff);
|
||||
rk628_i2c_write(csi->rk628, HDMI_RX_DMI_DISABLE_IF, 0x00000000);
|
||||
rk628_i2c_write(csi->rk628, HDMI_RX_DMI_DISABLE_IF, 0x0000017f);
|
||||
rk628_i2c_write(csi->rk628, HDMI_RX_DMI_DISABLE_IF, 0x0001017f);
|
||||
}
|
||||
|
||||
static bool rk628_rcv_supported_res(struct v4l2_subdev *sd, u32 width,
|
||||
u32 height)
|
||||
{
|
||||
@@ -1254,10 +1252,10 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd)
|
||||
|
||||
if (cnt >= 15)
|
||||
break;
|
||||
} while (((status & 0xfff) != 0xf00) ||
|
||||
} while (((status & 0xfff) < 0xf00) ||
|
||||
(!rk628_rcv_supported_res(sd, width, height)));
|
||||
|
||||
if (((status & 0xfff) != 0xf00) ||
|
||||
if (((status & 0xfff) < 0xf00) ||
|
||||
(!rk628_rcv_supported_res(sd, width, height))) {
|
||||
v4l2_err(sd, "%s hdmi rxphy lock failed, retry:%d\n",
|
||||
__func__, i);
|
||||
@@ -1326,7 +1324,7 @@ static void rk628_csi_initial_setup(struct v4l2_subdev *sd)
|
||||
SW_EFUSE_HDCP_EN(0) |
|
||||
SW_HSYNC_POL(1) |
|
||||
SW_VSYNC_POL(1));
|
||||
rk628_hdmirx_controller_reset(sd);
|
||||
rk628_hdmirx_controller_reset(csi->rk628);
|
||||
|
||||
def_edid.pad = 0;
|
||||
def_edid.start_block = 0;
|
||||
@@ -1467,7 +1465,7 @@ static int rk628_csi_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
|
||||
enable_stream(sd, false);
|
||||
csi->nosignal = true;
|
||||
}
|
||||
schedule_delayed_work(&csi->delayed_work_res_change, HZ / 2);
|
||||
schedule_delayed_work(&csi->delayed_work_res_change, msecs_to_jiffies(100));
|
||||
|
||||
v4l2_dbg(1, debug, sd, "%s: hact/vact change, md_ints: %#x\n",
|
||||
__func__, (u32)(md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS)));
|
||||
|
||||
@@ -175,7 +175,7 @@ EXPORT_SYMBOL(rk628_hdmirx_set_hdcp);
|
||||
|
||||
void rk628_hdmirx_controller_setup(struct rk628 *rk628)
|
||||
{
|
||||
rk628_i2c_write(rk628, HDMI_RX_HDMI20_CONTROL, 0x10000f10);
|
||||
rk628_i2c_write(rk628, HDMI_RX_HDMI20_CONTROL, 0x10000f11);
|
||||
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);
|
||||
@@ -188,7 +188,7 @@ void rk628_hdmirx_controller_setup(struct rk628 *rk628)
|
||||
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_HCTRL2, 0x0000173a);
|
||||
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);
|
||||
@@ -880,6 +880,19 @@ u8 rk628_hdmirx_get_format(struct rk628 *rk628)
|
||||
video_fmt = BUS_FMT_UNKNOWN;
|
||||
dev_info(rk628->dev, "%s: format = %s\n", __func__, bus_format_str[video_fmt]);
|
||||
|
||||
/*
|
||||
* set avmute value to black
|
||||
* RGB: R: CH2[15:0], G:CH0_1[31:16], B: CH0_1[15:0]
|
||||
* YUV: Cr:CH2[15:0], Y:CH0_1[31:16], Cb:CH0_1[15:0]
|
||||
*/
|
||||
if (video_fmt == BUS_FMT_RGB) {
|
||||
rk628_i2c_write(rk628, HDMI_VM_CFG_CH0_1, 0x0);
|
||||
rk628_i2c_write(rk628, HDMI_VM_CFG_CH2, 0x0);
|
||||
} else {
|
||||
rk628_i2c_write(rk628, HDMI_VM_CFG_CH0_1, 0x00008000);
|
||||
rk628_i2c_write(rk628, HDMI_VM_CFG_CH2, 0x8000);
|
||||
}
|
||||
|
||||
return video_fmt;
|
||||
}
|
||||
EXPORT_SYMBOL(rk628_hdmirx_get_format);
|
||||
@@ -1119,3 +1132,37 @@ u8 rk628_hdmirx_get_range(struct rk628 *rk628)
|
||||
return color_range;
|
||||
}
|
||||
EXPORT_SYMBOL(rk628_hdmirx_get_range);
|
||||
|
||||
void rk628_hdmirx_controller_reset(struct rk628 *rk628)
|
||||
{
|
||||
rk628_control_assert(rk628, RGU_HDMIRX);
|
||||
rk628_control_assert(rk628, RGU_HDMIRX_PON);
|
||||
udelay(10);
|
||||
rk628_control_deassert(rk628, RGU_HDMIRX);
|
||||
rk628_control_deassert(rk628, RGU_HDMIRX_PON);
|
||||
udelay(10);
|
||||
rk628_i2c_write(rk628, HDMI_RX_DMI_SW_RST, 0x000101ff);
|
||||
rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x00000000);
|
||||
rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x0000017f);
|
||||
rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x0001017f);
|
||||
}
|
||||
EXPORT_SYMBOL(rk628_hdmirx_controller_reset);
|
||||
|
||||
bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628)
|
||||
{
|
||||
u32 val, val1;
|
||||
|
||||
if (rk628->version < RK628F_VERSION)
|
||||
return false;
|
||||
|
||||
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS1, &val);
|
||||
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS2, &val1);
|
||||
if (((val >> 15) & SCDC_ERRDET_MASK) < SCDC_CED_ERR_CNT &&
|
||||
((val1 >> 15) & SCDC_ERRDET_MASK) < SCDC_CED_ERR_CNT &&
|
||||
(val1 & SCDC_ERRDET_MASK) < SCDC_CED_ERR_CNT)
|
||||
return false;
|
||||
|
||||
dev_info(rk628->dev, "%s: Character Error(0x%x 0x%x)!\n", __func__, val, val1);
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(rk628_hdmirx_scdc_ced_err);
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
#define DCM_COLOUR_DEPTH_SEL(x) UPDATE(x, 12, 12)
|
||||
#define DCM_COLOUR_DEPTH(x) UPDATE(x, 11, 8)
|
||||
#define DCM_GCP_ZERO_FIELDS(x) UPDATE(x, 5, 2)
|
||||
#define HDMI_VM_CFG_CH0_1 (HDMI_RX_BASE + 0x00b0)
|
||||
#define HDMI_VM_CFG_CH2 (HDMI_RX_BASE + 0x00b4)
|
||||
#define HDMI_RX_HDCP_CTRL (HDMI_RX_BASE + 0x00c0)
|
||||
#define HDCP_ENABLE_MASK BIT(24)
|
||||
@@ -278,6 +279,7 @@
|
||||
#define SCDC_TMDSBITCLKRATIO BIT(17)
|
||||
#define HDMI_RX_SCDC_REGS1 (HDMI_RX_BASE + 0x0824)
|
||||
#define HDMI_RX_SCDC_REGS2 (HDMI_RX_BASE + 0x0828)
|
||||
#define SCDC_ERRDET_MASK GENMASK(14, 0)
|
||||
#define HDMI_RX_SCDC_REGS3 (HDMI_RX_BASE + 0x082c)
|
||||
#define HDMI_RX_SCDC_WRDATA0 (HDMI_RX_BASE + 0x0860)
|
||||
#define MANUFACTUREROUI(x) UPDATE(x, 31, 8)
|
||||
@@ -380,6 +382,25 @@
|
||||
#define HDMIRX_MODETCLK_CNT_NUM 1000
|
||||
#define HDMIRX_MODETCLK_HZ 49500000
|
||||
|
||||
#define EDID_NUM_BLOCKS_MAX 2
|
||||
#define EDID_BLOCK_SIZE 128
|
||||
|
||||
#define RK628_CSI_LINK_FREQ_LOW 350000000
|
||||
#define RK628_CSI_LINK_FREQ_HIGH 650000000
|
||||
#define RK628_CSI_PIXEL_RATE_LOW 400000000
|
||||
#define RK628_CSI_PIXEL_RATE_HIGH 600000000
|
||||
#define MIPI_DATARATE_MBPS_LOW 700
|
||||
#define MIPI_DATARATE_MBPS_HIGH 1300
|
||||
|
||||
#define POLL_INTERVAL_MS 1000
|
||||
#define RXPHY_CFG_MAX_TIMES 10
|
||||
#define CSITX_ERR_RETRY_TIMES 3
|
||||
|
||||
#define USE_4_LANES 4
|
||||
#define YUV422_8BIT 0x1e
|
||||
|
||||
#define SCDC_CED_ERR_CNT 0xfff
|
||||
|
||||
enum color_range {
|
||||
CSC_LIMIT_RANGE,
|
||||
CSC_FULL_RANGE,
|
||||
@@ -435,5 +456,7 @@ u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628);
|
||||
int rk628_hdmirx_get_timings(struct rk628 *rk628,
|
||||
struct v4l2_dv_timings *timings);
|
||||
u8 rk628_hdmirx_get_range(struct rk628 *rk628);
|
||||
void rk628_hdmirx_controller_reset(struct rk628 *rk628);
|
||||
bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user