mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 04:48:04 +09:00
Merge commit 'f9ab55a3df38ca2ed7f70739aa37c051bf214768'
* commit 'f9ab55a3df38ca2ed7f70739aa37c051bf214768': spi: rockchip-sfc: Compatible with OSPI DTR mode media: i2c: rk628: add private interface, compatible with hdmirx. media: i2c: rk628: fix display error caused by read resolution error media: i2c: rk628: fix display error in plugout drm/rockchip: vop2: fix some compiled warning mfd: display-serdes: add error detection and recovery function video: rockchip: vehicle: adapt driver to kernel-6.1 Change-Id: I90311e32211d064602e769bd497f08920a6b3647
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#ifndef __RK628_HDMIRX_H
|
||||
#define __RK628_HDMIRX_H
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <media/cec.h>
|
||||
#include <media/cec-notifier.h>
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user