diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 468f90b3a1b8..b9162f87f54e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1043,12 +1043,15 @@ static inline void vop2_mask_write(struct vop2 *vop2, uint32_t offset, { uint32_t cached_val; - if (!mask) + if (!mask || !vop2 || !vop2->regs) return; if (write_mask) { v = ((v & mask) << shift) | (mask << (shift + 16)); } else { + if (!vop2->regsbak) + return; + cached_val = vop2->regsbak[offset >> 2]; v = (cached_val & ~(mask << shift)) | ((v & mask) << shift); @@ -3966,6 +3969,10 @@ static void vop2_power_domain_off_by_disabled_vp(struct vop2_power_domain *pd) phys_id = ffs(pd->data->module_id_mask) - 1; win = vop2_find_win_by_phys_id(vop2, phys_id); vp_id = ffs(win->vp_mask) - 1; + if (vp_id >= ROCKCHIP_MAX_CRTC) { + DRM_DEV_ERROR(vop2->dev, "unexpected vp%d\n", vp_id); + return; + } vp = &vop2->vps[vp_id]; } else { DRM_DEV_ERROR(vop2->dev, "unexpected power on pd%d\n", ffs(pd->data->id) - 1); @@ -4102,7 +4109,7 @@ static int vop2_extend_clk_init(struct vop2 *vop2) extend_pll->clk = clk; extend_pll->vp_mask = 0; - strncpy(extend_pll->clk_name, extend_clk_name[i], sizeof(extend_pll->clk_name)); + strscpy_pad(extend_pll->clk_name, extend_clk_name[i], sizeof(extend_pll->clk_name)); list_add_tail(&extend_pll->list, &vop2->extend_clk_list_head); } @@ -9473,7 +9480,7 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat struct drm_plane *plane; struct vop2_plane_state *vpstate; struct vop2_zpos *vop2_zpos; - struct vop2_zpos *vop2_zpos_splice; + struct vop2_zpos *vop2_zpos_splice = NULL; struct vop2_cluster cluster; uint8_t nr_layers = 0; uint8_t splice_nr_layers = 0; @@ -9545,7 +9552,7 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat rockchip_drm_dbg(vop2->dev, VOP_DEBUG_OVERLAY, "%s active zpos:%d for vp%d from vp%d\n", win->name, vpstate->zpos, vp->id, old_vp->id); /* left and right win may have different number */ - if (vcstate->splice_mode) { + if (vcstate->splice_mode && vop2_zpos_splice) { splice_win = vop2_find_win_by_phys_id(vop2, win->splice_win_id); splice_win->splice_mode_right = true; splice_win->left_win = win; diff --git a/drivers/media/i2c/rk628/rk628.h b/drivers/media/i2c/rk628/rk628.h index 6ea3ad0d6437..eb9dcc39987d 100644 --- a/drivers/media/i2c/rk628/rk628.h +++ b/drivers/media/i2c/rk628/rk628.h @@ -294,6 +294,7 @@ struct rk628 { struct mutex rst_lock; int tx_mode; struct dentry *debug_dir; + struct gpio_desc *hdmirx_det_gpio; }; int rk628_media_i2c_write(struct rk628 *rk628, u32 reg, u32 val); diff --git a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c index 875d7998442a..1c9d8655398e 100644 --- a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c @@ -234,7 +234,7 @@ static int rk628_bt1120_s_edid(struct v4l2_subdev *sd, static int rk628_hdmirx_inno_phy_power_on(struct v4l2_subdev *sd); static int rk628_hdmirx_inno_phy_power_off(struct v4l2_subdev *sd); static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd); -static void rk628_bt1120_format_change(struct v4l2_subdev *sd); +static int 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); @@ -248,22 +248,9 @@ static inline struct rk628_bt1120 *to_bt1120(struct v4l2_subdev *sd) static bool tx_5v_power_present(struct v4l2_subdev *sd) { bool ret; - int val, i, cnt; struct rk628_bt1120 *bt1120 = to_bt1120(sd); - /* Direct Mode */ - if (!bt1120->plugin_det_gpio) - return true; - - cnt = 0; - for (i = 0; i < 5; i++) { - val = gpiod_get_value(bt1120->plugin_det_gpio); - if (val > 0) - cnt++; - usleep_range(500, 600); - } - - ret = (cnt >= 3) ? true : false; + ret = rk628_hdmirx_tx_5v_power_detect(bt1120->plugin_det_gpio); v4l2_dbg(1, debug, sd, "%s: %d\n", __func__, ret); return ret; @@ -355,9 +342,11 @@ static void rk628_hdmirx_config_all(struct v4l2_subdev *sd) ret = rk628_hdmirx_phy_setup(sd); if (ret >= 0 && !rk628_hdmirx_scdc_ced_err(bt1120->rk628)) { - rk628_bt1120_format_change(sd); - bt1120->nosignal = false; - return; + ret = rk628_bt1120_format_change(sd); + if (!ret) { + bt1120->nosignal = false; + return; + } } if (ret < 0 || rk628_hdmirx_scdc_ced_err(bt1120->rk628)) { @@ -889,7 +878,7 @@ static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd) schedule_delayed_work(&bt1120->delayed_work_enable_hotplug, 4000); } -static void rk628_bt1120_format_change(struct v4l2_subdev *sd) +static int rk628_bt1120_format_change(struct v4l2_subdev *sd) { struct rk628_bt1120 *bt1120 = to_bt1120(sd); struct v4l2_dv_timings timings; @@ -897,8 +886,13 @@ static void rk628_bt1120_format_change(struct v4l2_subdev *sd) .type = V4L2_EVENT_SOURCE_CHANGE, .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, }; + int ret; - rk628_bt1120_get_detected_timings(sd, &timings); + ret = rk628_bt1120_get_detected_timings(sd, &timings); + if (ret) { + v4l2_dbg(1, debug, sd, "%s: get timing fail\n", __func__); + return ret; + } if (!v4l2_match_dv_timings(&bt1120->timings, &timings, 0, false)) { /* automatically set timing rather than set by userspace */ rk628_bt1120_s_dv_timings(sd, &timings); @@ -909,6 +903,8 @@ static void rk628_bt1120_format_change(struct v4l2_subdev *sd) if (sd->devnode) v4l2_subdev_notify_event(sd, &rk628_bt1120_ev_fmt); + + return 0; } static void rk628_bt1120_enable_interrupts(struct v4l2_subdev *sd, bool en) @@ -1736,6 +1732,7 @@ static int rk628_bt1120_probe_of(struct rk628_bt1120 *bt1120) ret = PTR_ERR(bt1120->plugin_det_gpio); goto clk_put; } + bt1120->rk628->hdmirx_det_gpio = bt1120->plugin_det_gpio; if (bt1120->enable_gpio) { gpiod_set_value(bt1120->enable_gpio, 1); diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 3bda56eecf29..dd96d6d2ded4 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -105,6 +105,7 @@ struct rk628_csi { u32 stream_state; int hdmirx_irq; int plugin_irq; + int avi_rdy; bool nosignal; bool rxphy_pwron; bool txphy_pwron; @@ -116,6 +117,7 @@ struct rk628_csi { bool continues_clk; bool cec_enable; struct rk628_hdmirx_cec *cec; + bool is_dvi; struct rk628_hdcp hdcp; bool i2s_enable_default; HAUDINFO audio_info; @@ -342,7 +344,7 @@ static void mipi_dphy_power_off(struct rk628_csi *csi); static int rk628_hdmirx_inno_phy_power_on(struct v4l2_subdev *sd); static int rk628_hdmirx_inno_phy_power_off(struct v4l2_subdev *sd); static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd); -static void rk628_csi_format_change(struct v4l2_subdev *sd); +static int rk628_csi_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_csi_set_csi(struct v4l2_subdev *sd); @@ -361,22 +363,9 @@ static inline struct rk628_csi *to_csi(struct v4l2_subdev *sd) static bool tx_5v_power_present(struct v4l2_subdev *sd) { bool ret; - int val, i, cnt; struct rk628_csi *csi = to_csi(sd); - /* Direct Mode */ - if (!csi->plugin_det_gpio) - return true; - - cnt = 0; - for (i = 0; i < 5; i++) { - val = gpiod_get_value(csi->plugin_det_gpio); - if (val > 0) - cnt++; - usleep_range(500, 600); - } - - ret = (cnt >= 3) ? true : false; + ret = rk628_hdmirx_tx_5v_power_detect(csi->plugin_det_gpio); v4l2_dbg(1, debug, sd, "%s: %d\n", __func__, ret); return ret; @@ -479,9 +468,11 @@ static void rk628_hdmirx_config_all(struct v4l2_subdev *sd) ret = rk628_hdmirx_phy_setup(sd); if (ret >= 0 && !rk628_hdmirx_scdc_ced_err(csi->rk628)) { - rk628_csi_format_change(sd); - csi->nosignal = false; - return; + ret = rk628_csi_format_change(sd); + if (!ret) { + csi->nosignal = false; + return; + } } if (ret < 0 || rk628_hdmirx_scdc_ced_err(csi->rk628)) { @@ -730,10 +721,9 @@ static void rk628_dsi_set_scs(struct rk628_csi *csi) { u8 video_fmt; u32 val; - int avi_rdy; mutex_lock(&csi->confctl_mutex); - avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); + csi->avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); mutex_unlock(&csi->confctl_mutex); rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_AVI_PB, &val); @@ -762,7 +752,7 @@ static void rk628_dsi_set_scs(struct rk628_csi *csi) } /* if avi packet is not stable, reset ctrl*/ - if (!avi_rdy) { + if (!csi->avi_rdy) { csi->nosignal = true; schedule_delayed_work(&csi->delayed_work_enable_hotplug, HZ / 20); } @@ -930,7 +920,6 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) u8 lanes = csi->csi_lanes_in_use; u8 lane_num; u32 wc_usrdef, val; - int avi_rdy; lane_num = lanes - 1; csi->rk628->dphy_lane_en = (1 << (lanes + 1)) - 1; @@ -1088,7 +1077,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) } mutex_lock(&csi->confctl_mutex); - avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); + csi->avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); mutex_unlock(&csi->confctl_mutex); rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_AVI_PB, &val); @@ -1112,7 +1101,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_post_process_csc_en(csi->rk628); } /* if avi packet is not stable, reset ctrl*/ - if (!avi_rdy) { + if (!csi->avi_rdy) { csi->nosignal = true; schedule_delayed_work(&csi->delayed_work_enable_hotplug, HZ / 20); } @@ -1253,8 +1242,12 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd) __func__, width, height, frame_width, frame_height, status, cnt); rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_STS, &val); - if (csi->rk628->version < RK628F_VERSION && (val & DVI_DET)) + if (csi->rk628->version < RK628F_VERSION && (val & DVI_DET)) { + csi->is_dvi = true; dev_info(csi->dev, "DVI mode detected\n"); + } else { + csi->is_dvi = false; + } if (!tx_5v_power_present(sd)) { v4l2_info(sd, "HDMI pull out, return!\n"); @@ -1371,7 +1364,7 @@ static void rk628_csi_initial_setup(struct v4l2_subdev *sd) schedule_delayed_work(&csi->delayed_work_enable_hotplug, msecs_to_jiffies(4000)); } -static void rk628_csi_format_change(struct v4l2_subdev *sd) +static int rk628_csi_format_change(struct v4l2_subdev *sd) { struct rk628_csi *csi = to_csi(sd); struct v4l2_dv_timings timings; @@ -1379,8 +1372,13 @@ static void rk628_csi_format_change(struct v4l2_subdev *sd) .type = V4L2_EVENT_SOURCE_CHANGE, .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, }; + int ret; - rk628_csi_get_detected_timings(sd, &timings); + ret = rk628_csi_get_detected_timings(sd, &timings); + if (ret) { + v4l2_dbg(1, debug, sd, "%s: get timing fail\n", __func__); + return ret; + } if (!v4l2_match_dv_timings(&csi->timings, &timings, 0, false)) { /* automatically set timing rather than set by userspace */ rk628_csi_s_dv_timings(sd, &timings); @@ -1391,6 +1389,8 @@ static void rk628_csi_format_change(struct v4l2_subdev *sd) if (sd->devnode) v4l2_subdev_notify_event(sd, &rk628_csi_ev_fmt); + + return 0; } static void rk628_csi_enable_csi_interrupts(struct v4l2_subdev *sd, bool en) @@ -2213,6 +2213,32 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) else *(int *)arg = RKMODULE_CSI_INPUT; break; + case RK_HDMIRX_CMD_GET_FPS: + *(int *)arg = fps_calc(&csi->timings.bt); + break; + case RK_HDMIRX_CMD_GET_HDCP_ENC_STATUS: + *(int *)arg = rk628_hdmirx_get_hdcp_enc_status(csi->rk628); + break; + case RK_HDMIRX_CMD_GET_INPUT_MODE: + *(int *)arg = csi->is_dvi; + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = csi->avi_rdy; + break; + case RK_HDMIRX_CMD_GET_SCAN_MODE: + if (csi->timings.bt.interlaced == V4L2_DV_INTERLACED) + *(int *)arg = HDMIRX_INTERLACED; + else + *(int *)arg = HDMIRX_PROGRESSIVE; + break; + case RK_HDMIRX_CMD_GET_EDID_MODE: + *(int *)arg = HDMIRX_EDID_4K60HZ_YUV444; + break; + case RK_HDMIRX_CMD_SET_EDID_MODE: + break; + case RK_HDMIRX_CMD_GET_COLOR_RANGE: + *(int *)arg = rk628_hdmirx_get_range(csi->rk628); + break; default: ret = -ENOIOCTLCMD; break; @@ -2385,6 +2411,118 @@ static long rk628_csi_compat_ioctl32(struct v4l2_subdev *sd, } kfree(seq); break; + case RK_HDMIRX_CMD_GET_FPS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_HDCP_ENC_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_INPUT_MODE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SCAN_MODE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_EDID_MODE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_SET_EDID_MODE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_COLOR_RANGE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; @@ -2537,6 +2675,7 @@ static int rk628_csi_probe_of(struct rk628_csi *csi) ret = PTR_ERR(csi->plugin_det_gpio); goto clk_put; } + csi->rk628->hdmirx_det_gpio = csi->plugin_det_gpio; if (csi->enable_gpio) { gpiod_set_value(csi->enable_gpio, 1); diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index b9daaf5e7628..8348067ebc68 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -213,6 +213,17 @@ void rk628_hdmirx_controller_setup(struct rk628 *rk628) } EXPORT_SYMBOL(rk628_hdmirx_controller_setup); +int rk628_hdmirx_get_hdcp_enc_status(struct rk628 *rk628) +{ + u32 val; + + rk628_i2c_read(rk628, HDMI_RX_HDCP_STS, &val); + val &= HDCP_ENC_STATE; + + return val ? 1 : 0; +} +EXPORT_SYMBOL(rk628_hdmirx_get_hdcp_enc_status); + static bool is_validfs(int fs) { int i = 0; @@ -1375,6 +1386,29 @@ TIMING_ERR: return -ENOLCK; } +bool rk628_hdmirx_tx_5v_power_detect(struct gpio_desc *det_gpio) +{ + bool ret; + int val, i, cnt; + + /* Direct Mode */ + if (!det_gpio) + return true; + + cnt = 0; + for (i = 0; i < 5; i++) { + val = gpiod_get_value(det_gpio); + if (val > 0) + cnt++; + usleep_range(500, 600); + } + + ret = (cnt >= 3) ? true : false; + + return ret; +} +EXPORT_SYMBOL(rk628_hdmirx_tx_5v_power_detect); + static int rk628_hdmirx_try_to_get_timing(struct rk628 *rk628, struct v4l2_dv_timings *timings) { @@ -1404,6 +1438,11 @@ int rk628_hdmirx_get_timings(struct rk628 *rk628, last_fmt = BUS_FMT_RGB; for (i = 0; i < HDMIRX_GET_TIMING_CNT; i++) { + if (!rk628_hdmirx_tx_5v_power_detect(rk628->hdmirx_det_gpio)) { + dev_info(rk628->dev, "%s: hdmi plug out!\n", __func__); + return -EINVAL; + } + ret = rk628_hdmirx_try_to_get_timing(rk628, timings); if ((last_w == 0) && (last_h == 0)) { last_w = bt->width; @@ -1411,6 +1450,9 @@ int rk628_hdmirx_get_timings(struct rk628 *rk628, last_fmt = rk628_hdmirx_get_format(rk628); } + if (ret && i > 2) + return -EINVAL; + if (ret || (last_w != bt->width) || (last_h != bt->height) || (last_fmt != rk628_hdmirx_get_format(rk628))) cnt = 0; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index 43b159e387e0..774b72caf4f0 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -8,9 +8,11 @@ #ifndef __RK628_HDMIRX_H #define __RK628_HDMIRX_H +#include #include #include #include + #include "rk628.h" /* --------- EDID and HDCP KEY ------- */ @@ -119,6 +121,7 @@ #define HDMI_RX_HDCP_DBG (HDMI_RX_BASE + 0x00e0) #define HDMI_RX_HDCP_AN0 (HDMI_RX_BASE + 0x00f0) #define HDMI_RX_HDCP_STS (HDMI_RX_BASE + 0x00fc) +#define HDCP_ENC_STATE BIT(9) #define HDMI_RX_MD_HCTRL1 (HDMI_RX_BASE + 0x0140) #define HACT_PIX_ITH(x) UPDATE(x, 10, 8) #define HACT_PIX_SRC(x) UPDATE(x, 5, 5) @@ -438,7 +441,7 @@ #define MIPI_DATARATE_MBPS_HIGH 1300 #define POLL_INTERVAL_MS 1000 -#define RXPHY_CFG_MAX_TIMES 10 +#define RXPHY_CFG_MAX_TIMES 5 #define CSITX_ERR_RETRY_TIMES 3 #define USE_4_LANES 4 @@ -509,10 +512,12 @@ void rk628_hdmirx_phy_prepclk_cfg(struct rk628 *rk628); int rk628_hdmirx_verisyno_phy_init(struct rk628 *rk628); u8 rk628_hdmirx_get_format(struct rk628 *rk628); void rk628_set_bg_enable(struct rk628 *rk628, bool en); +bool rk628_hdmirx_tx_5v_power_detect(struct gpio_desc *det_gpio); 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); +int rk628_hdmirx_get_hdcp_enc_status(struct rk628 *rk628); void rk628_hdmirx_controller_reset(struct rk628 *rk628); bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628); bool rk628_hdmirx_is_signal_change_ists(struct rk628 *rk628); diff --git a/drivers/mfd/display-serdes/core.h b/drivers/mfd/display-serdes/core.h index 941f448adcac..e74f4436beef 100644 --- a/drivers/mfd/display-serdes/core.h +++ b/drivers/mfd/display-serdes/core.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -351,6 +352,7 @@ struct serdes { struct mutex io_lock; struct mutex irq_lock; struct mutex wq_lock; + struct mutex reg_check_lock; struct device *dev; enum serdes_type type; struct regmap *regmap; @@ -377,6 +379,10 @@ struct serdes { bool route_enable; bool use_delay_work; + struct kthread_worker *kworker; + struct kthread_delayed_work reg_check_work; + bool use_reg_check_work; + bool split_mode_enable; unsigned int reg_hw; unsigned int reg_use; @@ -391,6 +397,7 @@ struct serdes { struct pinctrl_state *pins_sleep; struct serdes_init_seq *serdes_init_seq; + struct serdes_init_seq *serdes_backup_seq; struct serdes_bridge *serdes_bridge; struct serdes_bridge_split *serdes_bridge_split; struct serdes_panel *serdes_panel; diff --git a/drivers/mfd/display-serdes/serdes-i2c.c b/drivers/mfd/display-serdes/serdes-i2c.c index 951d40d3db50..b02a64b04291 100644 --- a/drivers/mfd/display-serdes/serdes-i2c.c +++ b/drivers/mfd/display-serdes/serdes-i2c.c @@ -14,7 +14,7 @@ static struct serdes *g_serdes_ser_split[MAX_NUM_SERDES_SPLIT]; int serdes_i2c_set_sequence(struct serdes *serdes) { struct device *dev = serdes->dev; - int i, ret = 0; + int i, num = 0, ret = 0; unsigned int def = 0; for (i = 0; i < serdes->serdes_init_seq->reg_seq_cnt; i++) { @@ -30,9 +30,9 @@ int serdes_i2c_set_sequence(struct serdes *serdes) serdes->serdes_init_seq->reg_sequence[i].def); if (ret < 0) { - dev_err(serdes->dev, - "failed to write register %04x, ret %d, write again now\n", - serdes->serdes_init_seq->reg_sequence[i].reg, ret); + SERDES_DBG_MFD("%s failed to write reg %04x, ret %d, again now\n", + serdes->dev, + serdes->serdes_init_seq->reg_sequence[i].reg, ret); ret = serdes_reg_write(serdes, serdes->serdes_init_seq->reg_sequence[i].reg, serdes->serdes_init_seq->reg_sequence[i].def); @@ -40,9 +40,10 @@ int serdes_i2c_set_sequence(struct serdes *serdes) serdes_reg_read(serdes, serdes->serdes_init_seq->reg_sequence[i].reg, &def); if ((def != serdes->serdes_init_seq->reg_sequence[i].def) || (ret < 0)) { /* if read value != write value then write again */ - dev_err(dev, "read %04x %04x != %04x\n", - serdes->serdes_init_seq->reg_sequence[i].reg, - def, serdes->serdes_init_seq->reg_sequence[i].def); + if (num++ < 1) + dev_err(dev, "read %04x %04x != %04x\n", + serdes->serdes_init_seq->reg_sequence[i].reg, + def, serdes->serdes_init_seq->reg_sequence[i].def); serdes_reg_write(serdes, serdes->serdes_init_seq->reg_sequence[i].reg, serdes->serdes_init_seq->reg_sequence[i].def); @@ -91,6 +92,133 @@ static int serdes_set_i2c_address(struct serdes *serdes, u32 reg_hw, u32 reg_use return ret; } +static int serdes_i2c_set_sequence_backup(struct serdes *serdes) +{ + struct device *dev = serdes->dev; + int i, num = 0, ret = 0; + unsigned int def = 0; + + for (i = 0; i < serdes->serdes_backup_seq->reg_seq_cnt; i++) { + if (serdes->serdes_backup_seq->reg_sequence[i].reg == 0xffff) { + SERDES_DBG_MFD("%s: delay 0x%04x us\n", __func__, + serdes->serdes_backup_seq->reg_sequence[i].def); + udelay(serdes->serdes_backup_seq->reg_sequence[i].def); + continue; + } + + ret = serdes_reg_write(serdes, + serdes->serdes_backup_seq->reg_sequence[i].reg, + serdes->serdes_backup_seq->reg_sequence[i].def); + if (ret < 0) { + SERDES_DBG_MFD("%s failed to write reg %04x, ret %d, again now\n", + serdes->dev, + serdes->serdes_backup_seq->reg_sequence[i].reg, ret); + ret = serdes_reg_write(serdes, + serdes->serdes_backup_seq->reg_sequence[i].reg, + serdes->serdes_backup_seq->reg_sequence[i].def); + } + serdes_reg_read(serdes, serdes->serdes_backup_seq->reg_sequence[i].reg, &def); + if ((def != serdes->serdes_backup_seq->reg_sequence[i].def) || (ret < 0)) { + /* if read value != write value then write again */ + if (num++ < 1) + dev_err(dev, "%s read %04x %04x != %04x\n", __func__, + serdes->serdes_backup_seq->reg_sequence[i].reg, + def, serdes->serdes_backup_seq->reg_sequence[i].def); + serdes_reg_write(serdes, + serdes->serdes_backup_seq->reg_sequence[i].reg, + serdes->serdes_backup_seq->reg_sequence[i].def); + } + } + + return ret; +} + +static int serdes_i2c_backup_register(struct serdes *serdes) +{ + int i, ret = 0; + + for (i = 0; i < serdes->serdes_backup_seq->reg_seq_cnt; i++) { + if (serdes->serdes_backup_seq->reg_sequence[i].reg == 0xffff) + continue; + serdes_reg_read(serdes, serdes->serdes_backup_seq->reg_sequence[i].reg, + &serdes->serdes_backup_seq->reg_sequence[i].def); + } + + return ret; +} + +static int serdes_i2c_check_register(struct serdes *serdes, int *flag) +{ + struct device *dev = serdes->dev; + int ret = 0; + unsigned int def = 0; + unsigned int num = 0; + + get_random_bytes(&num, 1); + if (num > serdes->serdes_backup_seq->reg_seq_cnt - 1) + num = 0; + + if (serdes->serdes_backup_seq->reg_sequence[num].reg == 0xffff) + return 0; + + ret = serdes_reg_read(serdes, serdes->serdes_backup_seq->reg_sequence[num].reg, &def); + if ((def != serdes->serdes_backup_seq->reg_sequence[num].def) || (ret < 0)) { + /* if read value != write value then write again */ + dev_err(dev, "%s read %04x %04x != %04x\n", __func__, + serdes->serdes_backup_seq->reg_sequence[num].reg, + def, serdes->serdes_backup_seq->reg_sequence[num].def); + *flag = 1; + return ret; + } + + return ret; +} + +static void serdes_reg_check_work(struct kthread_work *work) +{ + int flag = 0; + struct serdes *serdes = container_of(work, struct serdes, + reg_check_work.work); + + if (atomic_read(&serdes->flag_ser_init)) { + serdes_i2c_backup_register(serdes); + atomic_set(&serdes->flag_ser_init, 0); + } + + serdes_i2c_check_register(serdes, &flag); + if (flag) { + if (serdes->chip_data->chip_init) + serdes->chip_data->chip_init(serdes); + serdes_i2c_set_sequence_backup(serdes); + msleep(500); + SERDES_DBG_MFD("%s %s\n", __func__, serdes->chip_data->name); + } + kthread_queue_delayed_work(serdes->kworker, &serdes->reg_check_work, + msecs_to_jiffies(2000)); +} + +static int serdes_reg_check_work_setup(struct serdes *serdes) +{ + kthread_init_delayed_work(&serdes->reg_check_work, + serdes_reg_check_work); + + serdes->kworker = kthread_create_worker(0, "%s", dev_name(serdes->dev)); + if (IS_ERR(serdes->kworker)) + return PTR_ERR(serdes->kworker); + mutex_init(&serdes->reg_check_lock); + atomic_set(&serdes->flag_ser_init, 1); + kthread_queue_delayed_work(serdes->kworker, &serdes->reg_check_work, + msecs_to_jiffies(20000)); + + return 0; +} + +static void serdes_reg_check_work_free(struct serdes *serdes) +{ + kthread_cancel_delayed_work_sync(&serdes->reg_check_work); + kthread_destroy_worker(serdes->kworker); +} + static void serdes_mfd_work(struct work_struct *work) { struct serdes *serdes = container_of(work, struct serdes, mfd_delay_work.work); @@ -161,6 +289,17 @@ static int serdes_get_init_seq(struct serdes *serdes) return err; } + serdes->serdes_backup_seq = devm_kzalloc(dev, sizeof(*serdes->serdes_backup_seq), + GFP_KERNEL); + if (!serdes->serdes_backup_seq) + return -ENOMEM; + + err = serdes_parse_init_seq(dev, data, len, serdes->serdes_backup_seq); + if (err) { + dev_err(dev, "failed to parse serdes-init-sequence\n"); + return err; + } + /* init ser register(not des register) more early if uboot logo disabled */ serdes->route_enable = of_property_read_bool(dev->of_node, "route-enable"); if ((!serdes->route_enable) && (serdes->chip_data->serdes_type == TYPE_SER)) { @@ -284,6 +423,13 @@ static int serdes_i2c_probe(struct i2c_client *client, SERDES_DBG_MFD("%s: use_delay_work=%d\n", __func__, serdes->use_delay_work); } + serdes->use_reg_check_work = of_property_read_bool(dev->of_node, "use-reg-check-work"); + if (serdes->use_reg_check_work) { + serdes_reg_check_work_setup(serdes); + + SERDES_DBG_MFD("%s: use_reg_check_work=%d\n", __func__, serdes->use_reg_check_work); + } + dev_info(dev, "serdes %s serdes_i2c_probe successful version %s\n", serdes->chip_data->name, MFD_SERDES_DISPLAY_VERSION); @@ -298,6 +444,20 @@ static void serdes_i2c_shutdown(struct i2c_client *client) serdes_device_shutdown(serdes); } +static void serdes_i2c_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct serdes *serdes = dev_get_drvdata(dev); + + if (serdes->use_reg_check_work) + serdes_reg_check_work_free(serdes); + + if (serdes->use_delay_work) { + cancel_delayed_work_sync(&serdes->mfd_delay_work); + destroy_workqueue(serdes->mfd_wq); + } +} + static int serdes_i2c_prepare(struct device *dev) { return 0; @@ -394,6 +554,7 @@ static struct i2c_driver serdes_i2c_driver = { }, .probe = serdes_i2c_probe, .shutdown = serdes_i2c_shutdown, + .remove = (void *)serdes_i2c_remove, }; static int __init serdes_i2c_init(void) diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index cdad58d1c45f..57350db360e2 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -27,9 +27,15 @@ /* System control */ #define SFC_CTRL 0x0 #define SFC_CTRL_PHASE_SEL_NEGETIVE BIT(1) +#define SFC_CTRL_DTR_MODE BIT(2) #define SFC_CTRL_CMD_BITS_SHIFT 8 #define SFC_CTRL_ADDR_BITS_SHIFT 10 #define SFC_CTRL_DATA_BITS_SHIFT 12 +#define SFC_CTRL_DTR_MODE_BY_DEVICE BIT(17) +#define SFC_CTRL_CMD_STR_SHIFT 19 +#define SFC_CTRL_ADDR_STR_SHIFT 20 +#define SFC_CTRL_CMD_CTRL_CMD_EXT (2 << 27) +#define SFC_CTRL_WPEN BIT(29) /* Interrupt mask */ #define SFC_IMR 0x4 @@ -87,7 +93,7 @@ #define SFC_FSR_TX_IS_EMPTY BIT(1) #define SFC_FSR_RX_IS_EMPTY BIT(2) #define SFC_FSR_RX_IS_FULL BIT(3) -#define SFC_FSR_TXLV_MASK GENMASK(12, 8) +#define SFC_FSR_TXLV_MASK GENMASK(13, 8) #define SFC_FSR_TXLV_SHIFT 8 #define SFC_FSR_RXLV_MASK GENMASK(20, 16) #define SFC_FSR_RXLV_SHIFT 16 @@ -122,6 +128,14 @@ #define SFC_DLL_CTRL0_DLL_MAX_VER4 0xFFU #define SFC_DLL_CTRL0_DLL_MAX_VER5 0x1FFU +/* Dummy Cycle Control Register */ +#define SFC_DUMM_CTRL 0x74 +#define SFC_DUMMY_CTRL_SEL BIT(0) +#define SFC_DUMMY_CTRL_EXT_SHIFT 1 + +/* Command Extend Register */ +#define SFC_CMD_EXT 0x78 + /* Master trigger */ #define SFC_DMA_TRIGGER 0x80 #define SFC_DMA_TRIGGER_START 1 @@ -222,21 +236,20 @@ static u16 rockchip_sfc_get_version(struct rockchip_sfc *sfc) static u32 rockchip_sfc_get_max_iosize(struct rockchip_sfc *sfc) { + if (sfc->version >= SFC_VER_4) + return SFC_MAX_IOSIZE_VER4; + return SFC_MAX_IOSIZE_VER3; } static u32 rockchip_sfc_get_max_dll_cells(struct rockchip_sfc *sfc) { - switch (rockchip_sfc_get_version(sfc)) { - case SFC_VER_8: - case SFC_VER_6: - case SFC_VER_5: + if (sfc->version > SFC_VER_4) return SFC_DLL_CTRL0_DLL_MAX_VER5; - case SFC_VER_4: + else if (sfc->version == SFC_VER_4) return SFC_DLL_CTRL0_DLL_MAX_VER4; - default: + else return 0; - } } static void rockchip_sfc_set_delay_lines(struct rockchip_sfc *sfc, u16 cells, u8 cs) @@ -310,7 +323,8 @@ static int rockchip_sfc_wait_rxfifo_ready(struct rockchip_sfc *sfc, u32 timeout_ status & SFC_FSR_RXLV_MASK, 0, timeout_us); if (ret) { - dev_dbg(sfc->dev, "sfc wait rx fifo timeout\n"); + print_hex_dump(KERN_WARNING, "sfc", DUMP_PREFIX_OFFSET, 4, 4, sfc->regbase, 0x104, 0); + dev_err(sfc->dev, "sfc wait rx fifo timeout\n"); return -ETIMEDOUT; } @@ -338,12 +352,19 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc, const struct spi_mem_op *op, u32 len) { - u32 ctrl = 0, cmd = 0; + u32 ctrl = 0, cmd = 0, cmd_ext = 0, dummy_ext = 0; u8 cs = mem->spi->chip_select; /* set CMD */ - cmd = op->cmd.opcode; - ctrl |= ((op->cmd.buswidth >> 1) << SFC_CTRL_CMD_BITS_SHIFT); + if (op->cmd.nbytes == 2) { + cmd_ext = op->cmd.opcode; + ctrl |= SFC_CTRL_CMD_CTRL_CMD_EXT; + } else { + cmd = op->cmd.opcode; + } + + ctrl |= (find_first_bit((unsigned long *)&op->cmd.buswidth, 8) << SFC_CTRL_CMD_BITS_SHIFT); + ctrl |= (!op->cmd.dtr) << SFC_CTRL_CMD_STR_SHIFT; /* set ADDR */ if (op->addr.nbytes) { @@ -354,14 +375,18 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc, } else { cmd |= SFC_CMD_ADDR_XBITS << SFC_CMD_ADDR_SHIFT; writel(op->addr.nbytes * 8 - 1, sfc->regbase + cs * SFC_CS1_REG_OFFSET + SFC_ABIT); + dev_dbg(sfc->dev, "sfc addrxbits=%d\n", op->addr.nbytes * 8 - 1); } - ctrl |= ((op->addr.buswidth >> 1) << SFC_CTRL_ADDR_BITS_SHIFT); + ctrl |= (find_first_bit((unsigned long *)&op->addr.buswidth, 8) << SFC_CTRL_ADDR_BITS_SHIFT); } + ctrl |= (!op->addr.dtr) << SFC_CTRL_ADDR_STR_SHIFT; /* set DUMMY */ if (op->dummy.nbytes) { - if (op->dummy.buswidth == 4) + if (op->dummy.buswidth == 8) + dummy_ext |= ((op->dummy.nbytes / 2) << SFC_DUMMY_CTRL_EXT_SHIFT | SFC_DUMMY_CTRL_SEL); /* dtr */ + else if (op->dummy.buswidth == 4) cmd |= op->dummy.nbytes * 2 << SFC_CMD_DUMMY_SHIFT; else if (op->dummy.buswidth == 2) cmd |= op->dummy.nbytes * 4 << SFC_CMD_DUMMY_SHIFT; @@ -374,25 +399,34 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc, writel(len, sfc->regbase + SFC_LEN_EXT); else cmd |= len << SFC_CMD_TRAN_BYTES_SHIFT; - if (len) { - if (op->data.dir == SPI_MEM_DATA_OUT) - cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT; - ctrl |= ((op->data.buswidth >> 1) << SFC_CTRL_DATA_BITS_SHIFT); - } - if (!len && op->addr.nbytes) + if ((len && op->data.dir == SPI_MEM_DATA_OUT) || (!len && op->addr.nbytes)) cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT; + if (len) + ctrl |= (find_first_bit((unsigned long *)&op->data.buswidth, 8) << SFC_CTRL_DATA_BITS_SHIFT); /* set the Controller */ - ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE; - cmd |= mem->spi->chip_select << SFC_CMD_CS_SHIFT; + ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE | SFC_CTRL_WPEN; + if (op->cmd.buswidth > 1) + ctrl |= SFC_CTRL_WPEN; - dev_dbg(sfc->dev, "sfc addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n", + /* Workaround, binding dqs with buswidth 8 */ + if (op->cmd.buswidth == 8) + ctrl |= (SFC_CTRL_DTR_MODE | SFC_CTRL_DTR_MODE_BY_DEVICE); + + cmd |= cs << SFC_CMD_CS_SHIFT; + + dev_dbg(sfc->dev, "sfc cmd.nbytes=%x(x%d) addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n", + op->cmd.nbytes, op->cmd.buswidth, op->addr.nbytes, op->addr.buswidth, op->dummy.nbytes, op->dummy.buswidth); - dev_dbg(sfc->dev, "sfc ctrl=%x cmd=%x addr=%llx len=%x\n", - ctrl, cmd, op->addr.val, len); + dev_dbg(sfc->dev, "sfc ctrl=%x cmd=%x cmd_ext=%x addr=%llx dummy_ext=%x len=%x\n", + ctrl, cmd, cmd_ext, op->addr.val, cmd_ext, len); + if (cmd_ext) + writel(cmd_ext, sfc->regbase + SFC_CMD_EXT); + if (sfc->version >= SFC_VER_8) + writel(dummy_ext, sfc->regbase + SFC_DUMM_CTRL); writel(ctrl, sfc->regbase + cs * SFC_CS1_REG_OFFSET + SFC_CTRL); writel(cmd, sfc->regbase + SFC_CMD); if (op->addr.nbytes) @@ -678,7 +712,7 @@ static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op if (ret != len) { dev_err(sfc->dev, "xfer data failed ret %d dir %d\n", ret, op->data.dir); - + rockchip_sfc_reset(sfc); ret = -EIO; goto out; } @@ -701,9 +735,21 @@ static int rockchip_sfc_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *o return 0; } +static bool rockchip_sfc_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + /* + * The number of address bytes should be equal to or less than 4 bytes. + */ + if (op->addr.nbytes > 4) + return false; + + return true; +} + static const struct spi_controller_mem_ops rockchip_sfc_mem_ops = { .exec_op = rockchip_sfc_exec_mem_op, .adjust_op_size = rockchip_sfc_adjust_op_size, + .supports_op = rockchip_sfc_supports_op, }; static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id) @@ -741,7 +787,6 @@ static int rockchip_sfc_probe(struct platform_device *pdev) master->flags = SPI_MASTER_HALF_DUPLEX; master->mem_ops = &rockchip_sfc_mem_ops; master->dev.of_node = pdev->dev.of_node; - master->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL; master->max_speed_hz = SFC_MAX_SPEED; master->num_chipselect = SFC_MAX_CHIPSELECT_NUM; @@ -837,6 +882,10 @@ static int rockchip_sfc_probe(struct platform_device *pdev) sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc); sfc->version = rockchip_sfc_get_version(sfc); + master->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL; + if (sfc->version >= SFC_VER_8) + master->mode_bits |= SPI_TX_OCTAL | SPI_RX_OCTAL; + pm_runtime_set_autosuspend_delay(dev, ROCKCHIP_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(dev); pm_runtime_set_active(dev); diff --git a/drivers/video/rockchip/vehicle/vehicle_cfg.h b/drivers/video/rockchip/vehicle/vehicle_cfg.h index 96241b7b5128..7702edd187ec 100644 --- a/drivers/video/rockchip/vehicle/vehicle_cfg.h +++ b/drivers/video/rockchip/vehicle/vehicle_cfg.h @@ -15,7 +15,7 @@ static int vehicle_debug; #define VEHICLE_DG(format, ...) do { \ if (vehicle_debug) \ - pr_info("%s %s(%d): " format, __func__, __LINE__, ## __VA_ARGS__); \ + pr_info("%s(%d): " format, __func__, __LINE__, ## __VA_ARGS__); \ } while (0) #define VEHICLE_DGERR(format, ...) \ @@ -43,6 +43,29 @@ enum { CIF_OUTPUT_FORMAT_420 = 1, }; +/* Serial flags */ +/* CSI-2 D-PHY number of data lanes. */ +#define V4L2_MBUS_CSI2_1_LANE BIT(0) +#define V4L2_MBUS_CSI2_2_LANE BIT(1) +#define V4L2_MBUS_CSI2_3_LANE BIT(2) +#define V4L2_MBUS_CSI2_4_LANE BIT(3) +/* CSI-2 Virtual Channel identifiers. */ +#define V4L2_MBUS_CSI2_CHANNEL_0 BIT(4) +#define V4L2_MBUS_CSI2_CHANNEL_1 BIT(5) +#define V4L2_MBUS_CSI2_CHANNEL_2 BIT(6) +#define V4L2_MBUS_CSI2_CHANNEL_3 BIT(7) +/* Clock non-continuous mode support. */ +#define V4L2_MBUS_CSI2_CONTINUOUS_CLOCK BIT(8) + +#define V4L2_MBUS_CSI2_LANES (V4L2_MBUS_CSI2_1_LANE | \ + V4L2_MBUS_CSI2_2_LANE | \ + V4L2_MBUS_CSI2_3_LANE | \ + V4L2_MBUS_CSI2_4_LANE) +#define V4L2_MBUS_CSI2_CHANNELS (V4L2_MBUS_CSI2_CHANNEL_0 | \ + V4L2_MBUS_CSI2_CHANNEL_1 | \ + V4L2_MBUS_CSI2_CHANNEL_2 | \ + V4L2_MBUS_CSI2_CHANNEL_3) + struct vehicle_cfg { /* output */ int width; diff --git a/drivers/video/rockchip/vehicle/vehicle_cif.c b/drivers/video/rockchip/vehicle/vehicle_cif.c index 2671d9bc1394..22defc8e7204 100644 --- a/drivers/video/rockchip/vehicle/vehicle_cif.c +++ b/drivers/video/rockchip/vehicle/vehicle_cif.c @@ -4515,7 +4515,7 @@ static void vehicle_csi2_err_print_work(struct work_struct *work) pr_err("mipi_csi2: ERR%d:0x%x %s\n", err_state->err_num, err_state->err_val, err_state->err_str); if (err_state->err_num == 1) - pr_info("mipi_csi2: err_stat:0x%x\n", err_state->err_stat); + pr_info("mipi_csi2: err_stat:0x%lx\n", err_state->err_stat); } static irqreturn_t vehicle_csirx_irq1(int irq, void *data) diff --git a/drivers/video/rockchip/vehicle/vehicle_flinger.c b/drivers/video/rockchip/vehicle/vehicle_flinger.c index e2c0e676ba85..f645bfa9346d 100644 --- a/drivers/video/rockchip/vehicle/vehicle_flinger.c +++ b/drivers/video/rockchip/vehicle/vehicle_flinger.c @@ -724,7 +724,6 @@ static int rk_flinger_rga_scaler(struct flinger *flinger, if (!file_ready) { int frame_len = src_buffer->src.w * src_buffer->src.h * 3 / 2; char path[128] = {0}; - mm_segment_t fs; VEHICLE_DG("save vop frame(%d) frame_len(%d)\n", frame_count++, frame_len); @@ -735,13 +734,8 @@ static int rk_flinger_rga_scaler(struct flinger *flinger, VEHICLE_DGERR(" %s filp_open failed!\n", path); file_ready = false; } else { - fs = get_fs(); - set_fs(KERNEL_DS); - vfs_write(filep, - (unsigned char __user *)(src_buffer->vir_addr), - frame_len, &pos); + kernel_write(filep, src_buffer->vir_addr, frame_len, &pos); filp_close(filep, NULL); - set_fs(fs); VEHICLE_INFO(" %s file saved ok!\n", path); file_ready = true; } @@ -761,7 +755,6 @@ static int rk_flinger_rga_scaler(struct flinger *flinger, /* NV12 */ int frame_len = dst_buffer->src.w * dst_buffer->src.h * 3 / 2; char path[128] = {0}; - mm_segment_t fs; VEHICLE_DG("save vop frame(%d) frame_len(%d)\n", frame_count++, frame_len); @@ -772,13 +765,8 @@ static int rk_flinger_rga_scaler(struct flinger *flinger, VEHICLE_DGERR(" %s filp_open failed!\n", path); file_ready = false; } else { - fs = get_fs(); - set_fs(KERNEL_DS); - vfs_write(filep, - (unsigned char __user *)(dst_buffer->vir_addr), - frame_len, &pos); + kernel_write(filep, dst_buffer->vir_addr, frame_len, &pos); filp_close(filep, NULL); - set_fs(fs); VEHICLE_INFO(" %s file saved ok!\n", path); file_ready = true; } @@ -1006,7 +994,6 @@ static int rk_flinger_rga_render(struct flinger *flinger, if (!file_ready) { int frame_len = dst_buffer->src.w * dst_buffer->src.h * 3 / 2;//NV12 char path[128] = {0}; - mm_segment_t fs; VEHICLE_DG("save vop frame(%d) frame_len(%d)\n", frame_count++, frame_len); @@ -1017,13 +1004,8 @@ static int rk_flinger_rga_render(struct flinger *flinger, VEHICLE_DGERR(" %s filp_open failed!\n", path); file_ready = false; } else { - fs = get_fs(); - set_fs(KERNEL_DS); - vfs_write(filep, - (unsigned char __user *)(dst_buffer->vir_addr), - frame_len, &pos); + kernel_write(filep, dst_buffer->vir_addr, frame_len, &pos); filp_close(filep, NULL); - set_fs(fs); VEHICLE_INFO(" %s file saved ok!\n", path); file_ready = true; } @@ -1075,7 +1057,6 @@ static void rk_drm_vehicle_commit(struct flinger *flinger, struct graphic_buffer int frame_len = buffer->drm_buffer->width * buffer->drm_buffer->height * 3 / 2;//NV12 char path[128] = {0}; - mm_segment_t fs; VEHICLE_DG("save vop frame(%d) frame_len(%d)\n", frame_count++, frame_len); @@ -1087,13 +1068,9 @@ static void rk_drm_vehicle_commit(struct flinger *flinger, struct graphic_buffer VEHICLE_DGERR(" %s filp_open failed!\n", path); file_ready = false; } else { - fs = get_fs(); - set_fs(KERNEL_DS); - vfs_write(filep, - (unsigned char __user *)(buffer->drm_buffer->vir_addr[0]), - frame_len, &pos); + kernel_write(filep, + buffer->drm_buffer->vir_addr[0], frame_len, &pos); filp_close(filep, NULL); - set_fs(fs); VEHICLE_INFO(" %s file saved ok!\n", path); file_ready = true; } @@ -1149,7 +1126,6 @@ static int rk_flinger_vop_show(struct flinger *flinger, if (!file_ready) { int frame_len = buffer->src.w * buffer->src.h * 3 / 2;//NV12 char path[128] = {0}; - mm_segment_t fs; VEHICLE_DG("save vop frame(%d) frame_len(%d)\n", frame_count++, frame_len); @@ -1160,13 +1136,8 @@ static int rk_flinger_vop_show(struct flinger *flinger, VEHICLE_DGERR(" %s filp_open failed!\n", path); file_ready = false; } else { - fs = get_fs(); - set_fs(KERNEL_DS); - vfs_write(filep, - (unsigned char __user *)(buffer->vir_addr), - frame_len, &pos); + kernel_write(filep, buffer->vir_addr, frame_len, &pos); filp_close(filep, NULL); - set_fs(fs); VEHICLE_INFO(" %s file saved ok!\n", path); file_ready = true; } @@ -1275,7 +1246,6 @@ try_again: //nv12 frame_len=w*h*3/2 int frame_len = src_buffer->src.w * src_buffer->src.h * 3 / 2; char path[128] = {0}; - mm_segment_t fs; VEHICLE_DG("save vop frame(%d) frame_len(%d)\n", frame_count++, frame_len); @@ -1286,11 +1256,8 @@ try_again: VEHICLE_DGERR(" %s filp_open failed!\n", path); file_ready = false; } else { - fs = get_fs(); - set_fs(KERNEL_DS); - vfs_write(filep, src_buffer->vir_addr, frame_len, &pos); + kernel_write(filep, src_buffer->vir_addr, frame_len, &pos); filp_close(filep, NULL); - set_fs(fs); VEHICLE_INFO(" %s file saved ok!\n", path); file_ready = true; } diff --git a/include/uapi/linux/rk_hdmirx_config.h b/include/uapi/linux/rk_hdmirx_config.h index 26dcea790013..afa7b2104a81 100644 --- a/include/uapi/linux/rk_hdmirx_config.h +++ b/include/uapi/linux/rk_hdmirx_config.h @@ -44,6 +44,19 @@ enum hdmirx_color_space { HDMIRX_BT2020_RGB_OR_YCC = 6, }; +/* hdmirx scan mode */ +enum hdmirx_scan_mode { + HDMIRX_PROGRESSIVE = 0, + HDMIRX_INTERLACED = 1, +}; + +enum hdmirx_edid_mode { + HDMIRX_EDID_2K60HZ_YUV444, + HDMIRX_EDID_4K30HZ_YUV444, + HDMIRX_EDID_4K60HZ_YUV444, + HDMIRX_EDID_4K60HZ_YUV420, +}; + /* Private v4l2 ioctl */ #define RK_HDMIRX_CMD_GET_FPS \ _IOR('V', BASE_VIDIOC_PRIVATE + 0, int) @@ -78,6 +91,18 @@ enum hdmirx_color_space { #define RK_HDMIRX_CMD_GET_COLOR_SPACE \ _IOR('V', BASE_VIDIOC_PRIVATE + 10, int) +#define RK_HDMIRX_CMD_GET_SCAN_MODE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 11, __u8) + +#define RK_HDMIRX_CMD_GET_EDID_MODE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 12, __u8) + +#define RK_HDMIRX_CMD_SET_EDID_MODE \ + _IOW('V', BASE_VIDIOC_PRIVATE + 13, __u8) + +#define RK_HDMIRX_CMD_GET_HDCP_ENC_STATUS \ + _IOR('V', BASE_VIDIOC_PRIVATE + 14, __u8) + /* Private v4l2 event */ #define RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST \ (V4L2_EVENT_PRIVATE_START + 1)