From 223293205a7265c8b02882461ba8996650048ade Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 11 Dec 2023 06:33:33 +0000
Subject: [PATCH] audio ok
---
kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c | 487 ++++++++++++++++++++++++++++-------------------------
1 files changed, 259 insertions(+), 228 deletions(-)
diff --git a/kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c b/kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c
index f06a238..c0e5999 100644
--- a/kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c
+++ b/kernel/drivers/media/platform/rockchip/cif/mipi-csi2.c
@@ -15,157 +15,19 @@
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-fwnode.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-event.h>
#include <linux/rk-camera-module.h>
#include <media/v4l2-ioctl.h>
#include "mipi-csi2.h"
+#include <linux/rkcif-config.h>
+#include <linux/regulator/consumer.h>
static int csi2_debug;
module_param_named(debug_csi2, csi2_debug, int, 0644);
MODULE_PARM_DESC(debug_csi2, "Debug level (0-1)");
-/*
- * there must be 5 pads: 1 input pad from sensor, and
- * the 4 virtual channel output pads
- */
-#define CSI2_SINK_PAD 0
-#define CSI2_NUM_SINK_PADS 1
-#define CSI2_NUM_SRC_PADS 4
-#define CSI2_NUM_PADS 5
-#define CSI2_NUM_PADS_SINGLE_LINK 2
-#define MAX_CSI2_SENSORS 2
-
-#define RKCIF_DEFAULT_WIDTH 640
-#define RKCIF_DEFAULT_HEIGHT 480
-
-/*
- * The default maximum bit-rate per lane in Mbps, if the
- * source subdev does not provide V4L2_CID_LINK_FREQ.
- */
-#define CSI2_DEFAULT_MAX_MBPS 849
-
-#define IMX_MEDIA_GRP_ID_CSI2 BIT(8)
-#define CSIHOST_MAX_ERRINT_COUNT 10
-
-/*
- * add new chip id in tail in time order
- * by increasing to distinguish csi2 host version
- */
-enum rkcsi2_chip_id {
- CHIP_PX30_CSI2,
- CHIP_RK1808_CSI2,
- CHIP_RK3128_CSI2,
- CHIP_RK3288_CSI2,
- CHIP_RV1126_CSI2,
- CHIP_RK3568_CSI2,
-};
-
-enum csi2_pads {
- RK_CSI2_PAD_SINK = 0,
- RK_CSI2X_PAD_SOURCE0,
- RK_CSI2X_PAD_SOURCE1,
- RK_CSI2X_PAD_SOURCE2,
- RK_CSI2X_PAD_SOURCE3
-};
-
-enum csi2_err {
- RK_CSI2_ERR_SOTSYN = 0x0,
- RK_CSI2_ERR_FS_FE_MIS,
- RK_CSI2_ERR_FRM_SEQ_ERR,
- RK_CSI2_ERR_CRC_ONCE,
- RK_CSI2_ERR_CRC,
- RK_CSI2_ERR_ALL,
- RK_CSI2_ERR_MAX
-};
-
-enum host_type_t {
- RK_CSI_RXHOST,
- RK_DSI_RXHOST
-};
-
-struct csi2_match_data {
- int chip_id;
- int num_pads;
-};
-
-struct csi2_sensor {
- struct v4l2_subdev *sd;
- struct v4l2_mbus_config mbus;
- int lanes;
-};
-
-struct csi2_err_stats {
- unsigned int cnt;
-};
-
-struct csi2_dev {
- struct device *dev;
- struct v4l2_subdev sd;
- struct media_pad pad[CSI2_NUM_PADS];
- struct clk_bulk_data *clks_bulk;
- int clks_num;
- struct reset_control *rsts_bulk;
-
- void __iomem *base;
- struct v4l2_async_notifier notifier;
- struct v4l2_fwnode_bus_mipi_csi2 bus;
-
- /* lock to protect all members below */
- struct mutex lock;
-
- struct v4l2_mbus_framefmt format_mbus;
- struct v4l2_rect crop;
- int stream_count;
- struct v4l2_subdev *src_sd;
- bool sink_linked[CSI2_NUM_SRC_PADS];
- struct csi2_sensor sensors[MAX_CSI2_SENSORS];
- const struct csi2_match_data *match_data;
- int num_sensors;
- atomic_t frm_sync_seq;
- struct csi2_err_stats err_list[RK_CSI2_ERR_MAX];
- int dsi_input_en;
-};
-
-#define DEVICE_NAME "rockchip-mipi-csi2"
-
-/* CSI Host Registers Define */
-#define CSIHOST_N_LANES 0x04
-#define CSIHOST_DPHY_SHUTDOWNZ 0x08
-#define CSIHOST_PHY_RSTZ 0x0c
-#define CSIHOST_RESETN 0x10
-#define CSIHOST_PHY_STATE 0x14
-#define CSIHOST_ERR1 0x20
-#define CSIHOST_ERR2 0x24
-#define CSIHOST_MSK1 0x28
-#define CSIHOST_MSK2 0x2c
-#define CSIHOST_CONTROL 0x40
-
-#define CSIHOST_ERR1_PHYERR_SPTSYNCHS 0x0000000f
-#define CSIHOST_ERR1_ERR_BNDRY_MATCH 0x000000f0
-#define CSIHOST_ERR1_ERR_SEQ 0x00000f00
-#define CSIHOST_ERR1_ERR_FRM_DATA 0x0000f000
-#define CSIHOST_ERR1_ERR_CRC 0x1f000000
-
-#define CSIHOST_ERR2_PHYERR_ESC 0x0000000f
-#define CSIHOST_ERR2_PHYERR_SOTHS 0x000000f0
-#define CSIHOST_ERR2_ECC_CORRECTED 0x00000f00
-#define CSIHOST_ERR2_ERR_ID 0x0000f000
-#define CSIHOST_ERR2_PHYERR_CODEHS 0x01000000
-
-#define SW_CPHY_EN(x) ((x) << 0)
-#define SW_DSI_EN(x) ((x) << 4)
-#define SW_DATATYPE_FS(x) ((x) << 8)
-#define SW_DATATYPE_FE(x) ((x) << 14)
-#define SW_DATATYPE_LS(x) ((x) << 20)
-#define SW_DATATYPE_LE(x) ((x) << 26)
-
#define write_csihost_reg(base, addr, val) writel(val, (addr) + (base))
#define read_csihost_reg(base, addr) readl((addr) + (base))
-static struct csi2_dev *g_csi2_dev;
static ATOMIC_NOTIFIER_HEAD(g_csi_host_chain);
int rkcif_csi2_register_notifier(struct notifier_block *nb)
@@ -183,7 +45,7 @@
return container_of(sdev, struct csi2_dev, sd);
}
-static struct csi2_sensor *sd_to_sensor(struct csi2_dev *csi2,
+static struct csi2_sensor_info *sd_to_sensor(struct csi2_dev *csi2,
struct v4l2_subdev *sd)
{
int i;
@@ -227,6 +89,7 @@
*sensor_sd = NULL;
return;
}
+
media_graph_walk_start(&graph, entity);
while ((entity = media_graph_walk_next(&graph))) {
if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
@@ -234,6 +97,7 @@
}
mutex_unlock(&mdev->graph_mutex);
media_graph_walk_cleanup(&graph);
+
if (entity)
*sensor_sd = media_entity_to_v4l2_subdev(entity);
else
@@ -242,24 +106,25 @@
static void csi2_update_sensor_info(struct csi2_dev *csi2)
{
- struct csi2_sensor *sensor = &csi2->sensors[0];
struct v4l2_subdev *terminal_sensor_sd = NULL;
+ struct csi2_sensor_info *sensor = &csi2->sensors[0];
struct v4l2_mbus_config mbus;
int ret = 0;
- ret = v4l2_subdev_call(sensor->sd, video, g_mbus_config, &mbus);
+ ret = v4l2_subdev_call(sensor->sd, pad, get_mbus_config, 0, &mbus);
if (ret) {
v4l2_err(&csi2->sd, "update sensor info failed!\n");
return;
}
get_remote_terminal_sensor(&csi2->sd, &terminal_sensor_sd);
- if (terminal_sensor_sd) {
- ret = v4l2_subdev_call(terminal_sensor_sd, core, ioctl,
- RKMODULE_GET_CSI_DSI_INFO, &csi2->dsi_input_en);
- if (ret)
- csi2->dsi_input_en = 0;
+ ret = v4l2_subdev_call(terminal_sensor_sd, core, ioctl,
+ RKMODULE_GET_CSI_DSI_INFO, &csi2->dsi_input_en);
+ if (ret) {
+ v4l2_dbg(1, csi2_debug, &csi2->sd, "get CSI/DSI sel failed, default csi!\n");
+ csi2->dsi_input_en = 0;
}
+
csi2->bus.flags = mbus.flags;
switch (csi2->bus.flags & V4L2_MBUS_CSI2_LANES) {
case V4L2_MBUS_CSI2_1_LANE:
@@ -316,27 +181,41 @@
write_csihost_reg(base, CSIHOST_MSK2, 0xffffffff);
}
+static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
+ struct v4l2_mbus_config *mbus);
+
static void csi2_enable(struct csi2_dev *csi2,
enum host_type_t host_type)
{
void __iomem *base = csi2->base;
int lanes = csi2->bus.num_data_lanes;
+ struct v4l2_mbus_config mbus;
+ u32 val = 0;
+
+ csi2_g_mbus_config(&csi2->sd, 0, &mbus);
+ if (mbus.type == V4L2_MBUS_CSI2_DPHY)
+ val = SW_CPHY_EN(0);
+ else if (mbus.type == V4L2_MBUS_CSI2_CPHY)
+ val = SW_CPHY_EN(1);
write_csihost_reg(base, CSIHOST_N_LANES, lanes - 1);
if (host_type == RK_DSI_RXHOST) {
- write_csihost_reg(base, CSIHOST_CONTROL,
- SW_CPHY_EN(0) | SW_DSI_EN(1) |
- SW_DATATYPE_FS(0x01) | SW_DATATYPE_FE(0x11) |
- SW_DATATYPE_LS(0x21) | SW_DATATYPE_LE(0x31));
+ val |= SW_DSI_EN(1) | SW_DATATYPE_FS(0x01) |
+ SW_DATATYPE_FE(0x11) | SW_DATATYPE_LS(0x21) |
+ SW_DATATYPE_LE(0x31);
+ write_csihost_reg(base, CSIHOST_CONTROL, val);
/* Disable some error interrupt when HOST work on DSI RX mode */
write_csihost_reg(base, CSIHOST_MSK1, 0xe00000f0);
write_csihost_reg(base, CSIHOST_MSK2, 0xff00);
} else {
- write_csihost_reg(base, CSIHOST_CONTROL,
- SW_CPHY_EN(0) | SW_DSI_EN(0));
- write_csihost_reg(base, CSIHOST_MSK1, 0);
+ val |= SW_DSI_EN(0) | SW_DATATYPE_FS(0x0) |
+ SW_DATATYPE_FE(0x01) | SW_DATATYPE_LS(0x02) |
+ SW_DATATYPE_LE(0x03);
+ write_csihost_reg(base, CSIHOST_CONTROL, val);
+ write_csihost_reg(base, CSIHOST_MSK1, 0x0);
write_csihost_reg(base, CSIHOST_MSK2, 0xf000);
+ csi2->is_check_sot_sync = true;
}
write_csihost_reg(base, CSIHOST_RESETN, 1);
@@ -500,6 +379,7 @@
csi2->crop.left = 0;
csi2->crop.width = RKCIF_DEFAULT_WIDTH;
csi2->crop.height = RKCIF_DEFAULT_HEIGHT;
+ csi2->csi_idx = 0;
return media_entity_pads_init(&sd->entity, num_pads, csi2->pad);
}
@@ -556,10 +436,12 @@
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sel->pad = 0;
ret = v4l2_subdev_call(sensor, pad, get_selection,
cfg, sel);
if (ret) {
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.pad = 0;
ret = v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt);
if (!ret) {
csi2->format_mbus = fmt.format;
@@ -608,16 +490,16 @@
return ret;
}
-static int csi2_g_mbus_config(struct v4l2_subdev *sd,
+static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
struct v4l2_mbus_config *mbus)
{
struct csi2_dev *csi2 = sd_to_dev(sd);
struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
int ret;
- ret = v4l2_subdev_call(sensor_sd, video, g_mbus_config, mbus);
+ ret = v4l2_subdev_call(sensor_sd, pad, get_mbus_config, 0, mbus);
if (ret) {
- mbus->type = V4L2_MBUS_CSI2;
+ mbus->type = V4L2_MBUS_CSI2_DPHY;
mbus->flags = csi2->bus.flags;
mbus->flags |= BIT(csi2->bus.num_data_lanes - 1);
}
@@ -630,50 +512,110 @@
.link_validate = v4l2_subdev_link_validate,
};
-void rkcif_csi2_event_inc_sof(void)
+void rkcif_csi2_event_reset_pipe(struct csi2_dev *csi2_dev, int reset_src)
{
- if (g_csi2_dev) {
+ if (csi2_dev) {
struct v4l2_event event = {
- .type = V4L2_EVENT_FRAME_SYNC,
- .u.frame_sync.frame_sequence =
- atomic_inc_return(&g_csi2_dev->frm_sync_seq) - 1,
+ .type = V4L2_EVENT_RESET_DEV,
+ .reserved[0] = reset_src,
};
- v4l2_event_queue(g_csi2_dev->sd.devnode, &event);
+ v4l2_event_queue(csi2_dev->sd.devnode, &event);
}
}
-u32 rkcif_csi2_get_sof(void)
+void rkcif_csi2_event_inc_sof(struct csi2_dev *csi2_dev)
{
- if (g_csi2_dev) {
- return atomic_read(&g_csi2_dev->frm_sync_seq) - 1;
+ if (csi2_dev) {
+ struct v4l2_event event = {
+ .type = V4L2_EVENT_FRAME_SYNC,
+ .u.frame_sync.frame_sequence =
+ atomic_inc_return(&csi2_dev->frm_sync_seq) - 1,
+ };
+ v4l2_event_queue(csi2_dev->sd.devnode, &event);
}
+}
+
+u32 rkcif_csi2_get_sof(struct csi2_dev *csi2_dev)
+{
+ if (csi2_dev)
+ return atomic_read(&csi2_dev->frm_sync_seq) - 1;
return 0;
}
-void rkcif_csi2_set_sof(u32 seq)
+void rkcif_csi2_set_sof(struct csi2_dev *csi2_dev, u32 seq)
{
- if (g_csi2_dev) {
- atomic_set(&g_csi2_dev->frm_sync_seq, seq);
- }
+ if (csi2_dev)
+ atomic_set(&csi2_dev->frm_sync_seq, seq);
}
static int rkcif_csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub)
{
- if (sub->type != V4L2_EVENT_FRAME_SYNC)
+ if (sub->type == V4L2_EVENT_FRAME_SYNC ||
+ sub->type == V4L2_EVENT_RESET_DEV)
+ return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL);
+ else
return -EINVAL;
-
- return v4l2_event_subscribe(fh, sub, 0, NULL);
}
+
+static int rkcif_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+ return 0;
+}
+
+static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct csi2_dev *csi2 = sd_to_dev(sd);
+ long ret = 0;
+
+ switch (cmd) {
+ case RKCIF_CMD_SET_CSI_IDX:
+ csi2->csi_idx = *((u32 *)arg);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *up = compat_ptr(arg);
+ u32 csi_idx = 0;
+ long ret;
+
+ switch (cmd) {
+ case RKCIF_CMD_SET_CSI_IDX:
+ if (copy_from_user(&csi_idx, up, sizeof(u32)))
+ return -EFAULT;
+
+ ret = rkcif_csi2_ioctl(sd, cmd, &csi_idx);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+#endif
static const struct v4l2_subdev_core_ops csi2_core_ops = {
.subscribe_event = rkcif_csi2_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+ .s_power = rkcif_csi2_s_power,
+ .ioctl = rkcif_csi2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = rkcif_csi2_compat_ioctl32,
+#endif
};
static const struct v4l2_subdev_video_ops csi2_video_ops = {
- .g_mbus_config = csi2_g_mbus_config,
.s_stream = csi2_s_stream,
};
@@ -682,6 +624,7 @@
.set_fmt = csi2_get_set_fmt,
.get_selection = csi2_get_selection,
.set_selection = csi2_set_selection,
+ .get_mbus_config = csi2_g_mbus_config,
};
static const struct v4l2_subdev_ops csi2_subdev_ops = {
@@ -716,7 +659,7 @@
struct csi2_dev *csi2 = container_of(notifier,
struct csi2_dev,
notifier);
- struct csi2_sensor *sensor;
+ struct csi2_sensor_info *sensor;
struct media_link *link;
unsigned int pad, ret;
@@ -772,10 +715,10 @@
struct csi2_dev *csi2 = container_of(notifier,
struct csi2_dev,
notifier);
- struct csi2_sensor *sensor = sd_to_sensor(csi2, sd);
+ struct csi2_sensor_info *sensor = sd_to_sensor(csi2, sd);
- sensor->sd = NULL;
-
+ if (sensor)
+ sensor->sd = NULL;
}
static const struct
@@ -784,6 +727,25 @@
.unbind = csi2_notifier_unbind,
};
+static void csi2_find_err_vc(int val, char *vc_info)
+{
+ int i;
+ char cur_str[CSI_VCINFO_LEN] = {0};
+
+ memset(vc_info, 0, sizeof(*vc_info));
+ for (i = 0; i < 4; i++) {
+ if ((val >> i) & 0x1) {
+ snprintf(cur_str, CSI_VCINFO_LEN, " %d", i);
+ if (strlen(vc_info) + strlen(cur_str) < CSI_VCINFO_LEN)
+ strncat(vc_info, cur_str, strlen(cur_str));
+ }
+ }
+}
+
+#define csi2_err_strncat(dst_str, src_str) {\
+ if (strlen(dst_str) + strlen(src_str) < CSI_ERRSTR_LEN)\
+ strncat(dst_str, src_str, strlen(src_str)); }
+
static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
{
struct device *dev = ctx;
@@ -791,58 +753,96 @@
struct csi2_err_stats *err_list = NULL;
unsigned long err_stat = 0;
u32 val;
+ char err_str[CSI_ERRSTR_LEN] = {0};
+ char cur_str[CSI_ERRSTR_LEN] = {0};
+ char vc_info[CSI_VCINFO_LEN] = {0};
+ bool is_add_cnt = false;
val = read_csihost_reg(csi2->base, CSIHOST_ERR1);
if (val) {
- write_csihost_reg(csi2->base,
- CSIHOST_ERR1, 0x0);
-
if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) {
err_list = &csi2->err_list[RK_CSI2_ERR_SOTSYN];
err_list->cnt++;
- v4l2_err(&csi2->sd,
- "ERR1: start of transmission error(no synchronization achieved), reg: 0x%x,cnt:%d\n",
- val, err_list->cnt);
+ if (csi2->match_data->chip_id == CHIP_RK3588_CSI2) {
+ if (err_list->cnt > 3 &&
+ csi2->err_list[RK_CSI2_ERR_ALL].cnt <= err_list->cnt) {
+ csi2->is_check_sot_sync = false;
+ write_csihost_reg(csi2->base, CSIHOST_MSK1, 0xf);
+ }
+ if (csi2->is_check_sot_sync) {
+ csi2_find_err_vc(val & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ } else {
+ csi2_find_err_vc(val & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ is_add_cnt = true;
+ }
}
if (val & CSIHOST_ERR1_ERR_BNDRY_MATCH) {
err_list = &csi2->err_list[RK_CSI2_ERR_FS_FE_MIS];
err_list->cnt++;
- v4l2_err(&csi2->sd,
- "ERR1: error matching frame start with frame end, reg: 0x%x,cnt:%d\n",
- val, err_list->cnt);
+ csi2_find_err_vc((val >> 4) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(fs/fe mis,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ if (csi2->match_data->chip_id < CHIP_RK3588_CSI2)
+ is_add_cnt = true;
}
if (val & CSIHOST_ERR1_ERR_SEQ) {
err_list = &csi2->err_list[RK_CSI2_ERR_FRM_SEQ_ERR];
err_list->cnt++;
- v4l2_err(&csi2->sd,
- "ERR1: incorrect frame sequence detected, reg: 0x%x,cnt:%d\n",
- val, err_list->cnt);
+ csi2_find_err_vc((val >> 8) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(f_seq,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
}
if (val & CSIHOST_ERR1_ERR_FRM_DATA) {
err_list = &csi2->err_list[RK_CSI2_ERR_CRC_ONCE];
+ is_add_cnt = true;
err_list->cnt++;
- v4l2_dbg(1, csi2_debug, &csi2->sd,
- "ERR1: at least one crc error, reg: 0x%x\n,cnt:%d", val, err_list->cnt);
+ csi2_find_err_vc((val >> 12) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(err_data,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
}
if (val & CSIHOST_ERR1_ERR_CRC) {
err_list = &csi2->err_list[RK_CSI2_ERR_CRC];
err_list->cnt++;
- v4l2_err(&csi2->sd,
- "ERR1: crc errors, reg: 0x%x, cnt:%d\n",
- val, err_list->cnt);
+ is_add_cnt = true;
+ csi2_find_err_vc((val >> 24) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(crc,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
}
- csi2->err_list[RK_CSI2_ERR_ALL].cnt++;
- err_stat = ((csi2->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) |
- ((csi2->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff);
+ if (val & CSIHOST_ERR1_ERR_ECC2) {
+ err_list = &csi2->err_list[RK_CSI2_ERR_CRC];
+ err_list->cnt++;
+ is_add_cnt = true;
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc2) ");
+ csi2_err_strncat(err_str, cur_str);
+ }
- atomic_notifier_call_chain(&g_csi_host_chain,
- err_stat,
- NULL);
+ if (val & CSIHOST_ERR1_ERR_CTRL) {
+ csi2_find_err_vc((val >> 16) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(ctrl,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+
+ pr_err("%s ERR1:0x%x %s\n", csi2->dev_name, val, err_str);
+
+ if (is_add_cnt) {
+ csi2->err_list[RK_CSI2_ERR_ALL].cnt++;
+ err_stat = ((csi2->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) |
+ ((csi2->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff);
+
+ atomic_notifier_call_chain(&g_csi_host_chain,
+ err_stat,
+ &csi2->csi_idx);
+ }
}
@@ -854,25 +854,38 @@
struct device *dev = ctx;
struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev));
u32 val;
+ char cur_str[CSI_ERRSTR_LEN] = {0};
+ char err_str[CSI_ERRSTR_LEN] = {0};
+ char vc_info[CSI_VCINFO_LEN] = {0};
val = read_csihost_reg(csi2->base, CSIHOST_ERR2);
if (val) {
- if (val & CSIHOST_ERR2_PHYERR_ESC)
- v4l2_err(&csi2->sd, "ERR2: escape entry error(ULPM), reg: 0x%x\n", val);
- if (val & CSIHOST_ERR2_PHYERR_SOTHS)
- v4l2_err(&csi2->sd,
- "ERR2: start of transmission error(synchronization can still be achieved), reg: 0x%x\n",
- val);
- if (val & CSIHOST_ERR2_ECC_CORRECTED)
- v4l2_dbg(1, csi2_debug, &csi2->sd,
- "ERR2: header error detected and corrected, reg: 0x%x\n",
- val);
- if (val & CSIHOST_ERR2_ERR_ID)
- v4l2_err(&csi2->sd,
- "ERR2: unrecognized or unimplemented data type detected, reg: 0x%x\n",
- val);
- if (val & CSIHOST_ERR2_PHYERR_CODEHS)
- v4l2_err(&csi2->sd, "ERR2: receiv error code, reg: 0x%x\n", val);
+ if (val & CSIHOST_ERR2_PHYERR_ESC) {
+ csi2_find_err_vc(val & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(ULPM,lane:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ if (val & CSIHOST_ERR2_PHYERR_SOTHS) {
+ csi2_find_err_vc((val >> 4) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(sot,lane:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ if (val & CSIHOST_ERR2_ECC_CORRECTED) {
+ csi2_find_err_vc((val >> 8) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ if (val & CSIHOST_ERR2_ERR_ID) {
+ csi2_find_err_vc((val >> 12) & 0xf, vc_info);
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(err id,vc:%s) ", vc_info);
+ csi2_err_strncat(err_str, cur_str);
+ }
+ if (val & CSIHOST_ERR2_PHYERR_CODEHS) {
+ snprintf(cur_str, CSI_ERRSTR_LEN, "(err code) ");
+ csi2_err_strncat(err_str, cur_str);
+ }
+
+ pr_err("%s ERR2:0x%x %s\n", csi2->dev_name, val, err_str);
}
return IRQ_HANDLED;
@@ -883,15 +896,14 @@
struct v4l2_async_notifier *ntf = &csi2->notifier;
int ret;
+ v4l2_async_notifier_init(ntf);
+
ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(csi2->dev,
&csi2->notifier,
sizeof(struct v4l2_async_subdev), 0,
csi2_parse_endpoint);
if (ret < 0)
return ret;
-
- if (!ntf->num_subdevs)
- return -ENODEV; /* no endpoint */
csi2->sd.subdev_notifier = &csi2->notifier;
csi2->notifier.ops = &csi2_async_ops;
@@ -929,6 +941,16 @@
.num_pads = CSI2_NUM_PADS,
};
+static const struct csi2_match_data rk3588_csi2_match_data = {
+ .chip_id = CHIP_RK3588_CSI2,
+ .num_pads = CSI2_NUM_PADS_MAX,
+};
+
+static const struct csi2_match_data rk3562_csi2_match_data = {
+ .chip_id = CHIP_RK3562_CSI2,
+ .num_pads = CSI2_NUM_PADS_MAX,
+};
+
static const struct of_device_id csi2_dt_ids[] = {
{
.compatible = "rockchip,rk1808-mipi-csi2",
@@ -945,6 +967,14 @@
{
.compatible = "rockchip,rv1126-mipi-csi2",
.data = &rv1126_csi2_match_data,
+ },
+ {
+ .compatible = "rockchip,rk3588-mipi-csi2",
+ .data = &rk3588_csi2_match_data,
+ },
+ {
+ .compatible = "rockchip,rk3562-mipi-csi2",
+ .data = &rk3562_csi2_match_data,
},
{ /* sentinel */ }
};
@@ -972,6 +1002,7 @@
csi2->dev = &pdev->dev;
csi2->match_data = data;
+ csi2->dev_name = node->name;
v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops);
v4l2_set_subdevdata(&csi2->sd, &pdev->dev);
csi2->sd.entity.ops = &csi2_entity_ops;
@@ -984,14 +1015,16 @@
platform_set_drvdata(pdev, &csi2->sd);
csi2->clks_num = devm_clk_bulk_get_all(dev, &csi2->clks_bulk);
- if (csi2->clks_num < 0)
+ if (csi2->clks_num < 0) {
+ csi2->clks_num = 0;
dev_err(dev, "failed to get csi2 clks\n");
+ }
csi2->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev);
if (IS_ERR(csi2->rsts_bulk)) {
if (PTR_ERR(csi2->rsts_bulk) != -EPROBE_DEFER)
dev_err(dev, "failed to get csi2 reset\n");
- return PTR_ERR(csi2->rsts_bulk);
+ csi2->rsts_bulk = NULL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1019,6 +1052,7 @@
if (ret < 0)
v4l2_err(&csi2->sd, "request csi-intr1 irq failed: %d\n",
ret);
+ csi2->irq1 = irq;
} else {
v4l2_err(&csi2->sd, "No found irq csi-intr1\n");
}
@@ -1032,6 +1066,7 @@
if (ret < 0)
v4l2_err(&csi2->sd, "request csi-intr2 failed: %d\n",
ret);
+ csi2->irq2 = irq;
} else {
v4l2_err(&csi2->sd, "No found irq csi-intr2\n");
}
@@ -1044,10 +1079,6 @@
ret = csi2_notifier(csi2);
if (ret)
goto rmmutex;
-
- csi2_hw_do_reset(csi2);
-
- g_csi2_dev = csi2;
v4l2_info(&csi2->sd, "probe success, v4l2_dev:%s!\n", csi2->sd.v4l2_dev->name);
@@ -1079,7 +1110,7 @@
.remove = csi2_remove,
};
-int __init rkcif_csi2_plat_drv_init(void)
+int rkcif_csi2_plat_drv_init(void)
{
return platform_driver_register(&csi2_driver);
}
--
Gitblit v1.6.2