summaryrefslogtreecommitdiff
path: root/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c')
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c1189
1 files changed, 576 insertions, 613 deletions
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index d596bc040005..2311672cedb1 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -9,11 +9,11 @@
*/
#include <linux/iopoll.h>
-#include <linux/phy/phy.h>
-#include <linux/phy/phy-mipi-dphy.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
+
#include <media/v4l2-event.h>
#include "rkisp1-common.h"
@@ -54,184 +54,113 @@
* +---------------------------------------------------------+
*/
-static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = {
- {
- .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .direction = RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10,
- .bayer_pat = RKISP1_RAW_RGGB,
- .bus_width = 10,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10,
- .bayer_pat = RKISP1_RAW_BGGR,
- .bus_width = 10,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10,
- .bayer_pat = RKISP1_RAW_GBRG,
- .bus_width = 10,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10,
- .bayer_pat = RKISP1_RAW_GRBG,
- .bus_width = 10,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12,
- .bayer_pat = RKISP1_RAW_RGGB,
- .bus_width = 12,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12,
- .bayer_pat = RKISP1_RAW_BGGR,
- .bus_width = 12,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12,
- .bayer_pat = RKISP1_RAW_GBRG,
- .bus_width = 12,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12,
- .bayer_pat = RKISP1_RAW_GRBG,
- .bus_width = 12,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8,
- .bayer_pat = RKISP1_RAW_RGGB,
- .bus_width = 8,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8,
- .bayer_pat = RKISP1_RAW_BGGR,
- .bus_width = 8,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8,
- .bayer_pat = RKISP1_RAW_GBRG,
- .bus_width = 8,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8,
- .bayer_pat = RKISP1_RAW_GRBG,
- .bus_width = 8,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b,
- .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR,
- .bus_width = 16,
- .direction = RKISP1_ISP_SD_SINK,
- }, {
- .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b,
- .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB,
- .bus_width = 16,
- .direction = RKISP1_ISP_SD_SINK,
- }, {
- .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b,
- .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY,
- .bus_width = 16,
- .direction = RKISP1_ISP_SD_SINK,
- }, {
- .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b,
- .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY,
- .bus_width = 16,
- .direction = RKISP1_ISP_SD_SINK,
- },
-};
-
-/* ----------------------------------------------------------------------------
- * Helpers
+/* -----------------------------------------------------------------------------
+ * Media block control (i.MX8MP only)
*/
-const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code)
+#define ISP_DEWARP_CONTROL 0x0138
+
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_HS_POLARITY BIT(22)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_RISING (0 << 20)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_NEGATIVE (1 << 20)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_POSITIVE (2 << 20)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_FALLING (3 << 20)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_MASK GENMASK(21, 20)
+#define ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE BIT(19)
+#define ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE(dt) ((dt) << 13)
+#define ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK GENMASK(18, 13)
+
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_HS_POLARITY BIT(12)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_RISING (0 << 10)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_NEGATIVE (1 << 10)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_POSITIVE (2 << 10)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_FALLING (3 << 10)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_MASK GENMASK(11, 10)
+#define ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE BIT(9)
+#define ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE(dt) ((dt) << 3)
+#define ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK GENMASK(8, 3)
+
+#define ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE BIT(1)
+#define ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE BIT(0)
+
+static int rkisp1_gasket_enable(struct rkisp1_device *rkisp1,
+ struct media_pad *source)
{
- unsigned int i;
+ struct v4l2_subdev *source_sd;
+ struct v4l2_mbus_frame_desc fd;
+ unsigned int dt;
+ u32 mask;
+ u32 val;
+ int ret;
- for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) {
- const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i];
+ /*
+ * Configure and enable the gasket with the CSI-2 data type. Set the
+ * vsync polarity as active high, as that is what the ISP is configured
+ * to expect in ISP_ACQ_PROP. Enable left justification, as the i.MX8MP
+ * ISP has a 16-bit wide input and expects data to be left-aligned.
+ */
- if (fmt->mbus_code == mbus_code)
- return fmt;
+ source_sd = media_entity_to_v4l2_subdev(source->entity);
+ ret = v4l2_subdev_call(source_sd, pad, get_frame_desc,
+ source->index, &fd);
+ if (ret) {
+ dev_err(rkisp1->dev,
+ "failed to get frame descriptor from '%s':%u: %d\n",
+ source_sd->name, 0, ret);
+ return ret;
}
- return NULL;
-}
+ if (fd.num_entries != 1) {
+ dev_err(rkisp1->dev, "invalid frame descriptor for '%s':%u\n",
+ source_sd->name, 0);
+ return -EINVAL;
+ }
-static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd)
-{
- struct media_pad *local, *remote;
- struct media_entity *sensor_me;
+ dt = fd.entry[0].bus.csi2.dt;
+
+ if (rkisp1->gasket_id == 0) {
+ mask = ISP_DEWARP_CONTROL_MIPI_CSI1_HS_POLARITY
+ | ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_MASK
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK
+ | ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE;
+ val = ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_POSITIVE
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE(dt);
+ } else {
+ mask = ISP_DEWARP_CONTROL_MIPI_CSI2_HS_POLARITY
+ | ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_MASK
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK
+ | ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE;
+ val = ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_POSITIVE
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE(dt);
+ }
- local = &sd->entity.pads[RKISP1_ISP_PAD_SINK_VIDEO];
- remote = media_entity_remote_pad(local);
- if (!remote)
- return NULL;
+ regmap_update_bits(rkisp1->gasket, ISP_DEWARP_CONTROL, mask, val);
- sensor_me = remote->entity;
- return media_entity_to_v4l2_subdev(sensor_me);
+ return 0;
}
-static struct v4l2_mbus_framefmt *
-rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, u32 which)
+static void rkisp1_gasket_disable(struct rkisp1_device *rkisp1)
{
- struct v4l2_subdev_state state = {
- .pads = isp->pad_cfg
- };
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&isp->sd, sd_state, pad);
- else
- return v4l2_subdev_get_try_format(&isp->sd, &state, pad);
-}
+ u32 mask;
+ u32 val;
-static struct v4l2_rect *
-rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, u32 which)
-{
- struct v4l2_subdev_state state = {
- .pads = isp->pad_cfg
- };
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&isp->sd, sd_state, pad);
- else
- return v4l2_subdev_get_try_crop(&isp->sd, &state, pad);
+ if (rkisp1->gasket_id == 1) {
+ mask = ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK
+ | ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE;
+ val = ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE;
+ } else {
+ mask = ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK
+ | ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE;
+ val = ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE;
+ }
+
+ regmap_update_bits(rkisp1->gasket, ISP_DEWARP_CONTROL, mask, val);
}
/* ----------------------------------------------------------------------------
@@ -243,73 +172,78 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp,
* This should only be called when configuring CIF
* or at the frame end interrupt
*/
-static void rkisp1_config_ism(struct rkisp1_device *rkisp1)
+static void rkisp1_config_ism(struct rkisp1_isp *isp,
+ const struct v4l2_subdev_state *sd_state)
{
- struct v4l2_rect *src_crop =
- rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL,
- RKISP1_ISP_PAD_SOURCE_VIDEO,
- V4L2_SUBDEV_FORMAT_ACTIVE);
+ const struct v4l2_rect *src_crop =
+ v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
u32 val;
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_RECENTER);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DX);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DY);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_DISPLACE);
- rkisp1_write(rkisp1, src_crop->left, RKISP1_CIF_ISP_IS_H_OFFS);
- rkisp1_write(rkisp1, src_crop->top, RKISP1_CIF_ISP_IS_V_OFFS);
- rkisp1_write(rkisp1, src_crop->width, RKISP1_CIF_ISP_IS_H_SIZE);
- rkisp1_write(rkisp1, src_crop->height, RKISP1_CIF_ISP_IS_V_SIZE);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_RECENTER, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DX, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DY, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_DISPLACE, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_OFFS, src_crop->left);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_OFFS, src_crop->top);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_SIZE, src_crop->width);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_SIZE, src_crop->height);
/* IS(Image Stabilization) is always on, working as output crop */
- rkisp1_write(rkisp1, 1, RKISP1_CIF_ISP_IS_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_CTRL, 1);
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD;
- rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
}
/*
* configure ISP blocks with input format, size......
*/
-static int rkisp1_config_isp(struct rkisp1_device *rkisp1)
+static int rkisp1_config_isp(struct rkisp1_isp *isp,
+ const struct v4l2_subdev_state *sd_state,
+ enum v4l2_mbus_type mbus_type, u32 mbus_flags)
{
- u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, signal = 0;
- const struct rkisp1_isp_mbus_info *src_fmt, *sink_fmt;
- struct rkisp1_sensor_async *sensor;
- struct v4l2_mbus_framefmt *sink_frm;
- struct v4l2_rect *sink_crop;
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
+ u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, acq_prop = 0;
+ const struct rkisp1_mbus_info *sink_fmt;
+ const struct rkisp1_mbus_info *src_fmt;
+ const struct v4l2_mbus_framefmt *src_frm;
+ const struct v4l2_mbus_framefmt *sink_frm;
+ const struct v4l2_rect *sink_crop;
+
+ sink_frm = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ src_frm = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
- sensor = rkisp1->active_sensor;
- sink_fmt = rkisp1->isp.sink_fmt;
- src_fmt = rkisp1->isp.src_fmt;
- sink_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL,
- RKISP1_ISP_PAD_SINK_VIDEO,
- V4L2_SUBDEV_FORMAT_ACTIVE);
- sink_crop = rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL,
- RKISP1_ISP_PAD_SINK_VIDEO,
- V4L2_SUBDEV_FORMAT_ACTIVE);
+ sink_fmt = rkisp1_mbus_info_get_by_code(sink_frm->code);
+ src_fmt = rkisp1_mbus_info_get_by_code(src_frm->code);
if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
acq_mult = 1;
if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
- if (sensor->mbus_type == V4L2_MBUS_BT656)
+ if (mbus_type == V4L2_MBUS_BT656)
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656;
else
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT;
} else {
- rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC_TH(0xc),
- RKISP1_CIF_ISP_DEMOSAIC);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC,
+ RKISP1_CIF_ISP_DEMOSAIC_TH(0xc));
- if (sensor->mbus_type == V4L2_MBUS_BT656)
+ if (mbus_type == V4L2_MBUS_BT656)
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656;
else
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601;
}
} else if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) {
acq_mult = 2;
- if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) {
+ if (mbus_type == V4L2_MBUS_CSI2_DPHY) {
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601;
} else {
- if (sensor->mbus_type == V4L2_MBUS_BT656)
+ if (mbus_type == V4L2_MBUS_BT656)
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656;
else
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601;
@@ -319,253 +253,225 @@ static int rkisp1_config_isp(struct rkisp1_device *rkisp1)
}
/* Set up input acquisition properties */
- if (sensor->mbus_type == V4L2_MBUS_BT656 ||
- sensor->mbus_type == V4L2_MBUS_PARALLEL) {
- if (sensor->mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- signal = RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE;
+ if (mbus_type == V4L2_MBUS_BT656 || mbus_type == V4L2_MBUS_PARALLEL) {
+ if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE;
+
+ switch (sink_fmt->bus_width) {
+ case 8:
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO;
+ break;
+ case 10:
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO;
+ break;
+ case 12:
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B;
+ break;
+ default:
+ dev_err(rkisp1->dev, "Invalid bus width %u\n",
+ sink_fmt->bus_width);
+ return -EINVAL;
+ }
}
- if (sensor->mbus_type == V4L2_MBUS_PARALLEL) {
- if (sensor->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- signal |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW;
+ if (mbus_type == V4L2_MBUS_PARALLEL) {
+ if (mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW;
- if (sensor->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- signal |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW;
+ if (mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW;
}
- rkisp1_write(rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL);
- rkisp1_write(rkisp1, signal | sink_fmt->yuv_seq |
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, isp_ctrl);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_PROP,
+ acq_prop | sink_fmt->yuv_seq |
RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(sink_fmt->bayer_pat) |
- RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL,
- RKISP1_CIF_ISP_ACQ_PROP);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_NR_FRAMES);
+ RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_NR_FRAMES, 0);
/* Acquisition Size */
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_H_OFFS);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_V_OFFS);
- rkisp1_write(rkisp1,
- acq_mult * sink_frm->width, RKISP1_CIF_ISP_ACQ_H_SIZE);
- rkisp1_write(rkisp1, sink_frm->height, RKISP1_CIF_ISP_ACQ_V_SIZE);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_H_OFFS, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_V_OFFS, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_H_SIZE,
+ acq_mult * sink_frm->width);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_V_SIZE, sink_frm->height);
/* ISP Out Area */
- rkisp1_write(rkisp1, sink_crop->left, RKISP1_CIF_ISP_OUT_H_OFFS);
- rkisp1_write(rkisp1, sink_crop->top, RKISP1_CIF_ISP_OUT_V_OFFS);
- rkisp1_write(rkisp1, sink_crop->width, RKISP1_CIF_ISP_OUT_H_SIZE);
- rkisp1_write(rkisp1, sink_crop->height, RKISP1_CIF_ISP_OUT_V_SIZE);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_H_OFFS, sink_crop->left);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_V_OFFS, sink_crop->top);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_H_SIZE, sink_crop->width);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_V_SIZE, sink_crop->height);
irq_mask |= RKISP1_CIF_ISP_FRAME | RKISP1_CIF_ISP_V_START |
RKISP1_CIF_ISP_PIC_SIZE_ERROR;
- rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, irq_mask);
if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
rkisp1_params_disable(&rkisp1->params);
} else {
- struct v4l2_mbus_framefmt *src_frm;
-
- src_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL,
- RKISP1_ISP_PAD_SINK_VIDEO,
- V4L2_SUBDEV_FORMAT_ACTIVE);
- rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat,
- src_frm->quantization);
- }
-
- return 0;
-}
-
-static int rkisp1_config_dvp(struct rkisp1_device *rkisp1)
-{
- const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt;
- u32 val, input_sel;
+ const struct v4l2_mbus_framefmt *src_frm;
- switch (sink_fmt->bus_width) {
- case 8:
- input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO;
- break;
- case 10:
- input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO;
- break;
- case 12:
- input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B;
- break;
- default:
- dev_err(rkisp1->dev, "Invalid bus width\n");
- return -EINVAL;
+ src_frm = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ rkisp1_params_pre_configure(&rkisp1->params, sink_fmt->bayer_pat,
+ src_frm->quantization,
+ src_frm->ycbcr_enc);
}
- val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ACQ_PROP);
- rkisp1_write(rkisp1, val | input_sel, RKISP1_CIF_ISP_ACQ_PROP);
-
- return 0;
-}
-
-static int rkisp1_config_mipi(struct rkisp1_device *rkisp1)
-{
- const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt;
- unsigned int lanes = rkisp1->active_sensor->lanes;
- u32 mipi_ctrl;
-
- if (lanes < 1 || lanes > 4)
- return -EINVAL;
-
- mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) |
- RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) |
- RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP |
- RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA;
-
- rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL);
-
- /* Configure Data Type and Virtual Channel */
- rkisp1_write(rkisp1,
- RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) |
- RKISP1_CIF_MIPI_DATA_SEL_VC(0),
- RKISP1_CIF_MIPI_IMG_DATA_SEL);
-
- /* Clear MIPI interrupts */
- rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR);
- /*
- * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for
- * isp bus may be dead when switch isp.
- */
- rkisp1_write(rkisp1,
- RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI |
- RKISP1_CIF_MIPI_ERR_DPHY |
- RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) |
- RKISP1_CIF_MIPI_ADD_DATA_OVFLW,
- RKISP1_CIF_MIPI_IMSC);
-
- dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n"
- " MIPI_IMG_DATA_SEL 0x%08x\n"
- " MIPI_STATUS 0x%08x\n"
- " MIPI_IMSC 0x%08x\n",
- rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL),
- rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL),
- rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS),
- rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC));
+ isp->sink_fmt = sink_fmt;
return 0;
}
/* Configure MUX */
-static int rkisp1_config_path(struct rkisp1_device *rkisp1)
+static void rkisp1_config_path(struct rkisp1_isp *isp,
+ enum v4l2_mbus_type mbus_type)
{
- struct rkisp1_sensor_async *sensor = rkisp1->active_sensor;
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
u32 dpcl = rkisp1_read(rkisp1, RKISP1_CIF_VI_DPCL);
- int ret = 0;
- if (sensor->mbus_type == V4L2_MBUS_BT656 ||
- sensor->mbus_type == V4L2_MBUS_PARALLEL) {
- ret = rkisp1_config_dvp(rkisp1);
+ if (mbus_type == V4L2_MBUS_BT656 || mbus_type == V4L2_MBUS_PARALLEL)
dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL;
- } else if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) {
- ret = rkisp1_config_mipi(rkisp1);
+ else if (mbus_type == V4L2_MBUS_CSI2_DPHY)
dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_MIPI;
- }
-
- rkisp1_write(rkisp1, dpcl, RKISP1_CIF_VI_DPCL);
- return ret;
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_DPCL, dpcl);
}
/* Hardware configure Entry */
-static int rkisp1_config_cif(struct rkisp1_device *rkisp1)
+static int rkisp1_config_cif(struct rkisp1_isp *isp,
+ struct v4l2_subdev_state *sd_state,
+ enum v4l2_mbus_type mbus_type, u32 mbus_flags)
{
- u32 cif_id;
int ret;
- cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID);
- dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id);
-
- ret = rkisp1_config_isp(rkisp1);
- if (ret)
- return ret;
- ret = rkisp1_config_path(rkisp1);
+ ret = rkisp1_config_isp(isp, sd_state, mbus_type, mbus_flags);
if (ret)
return ret;
- rkisp1_config_ism(rkisp1);
+
+ rkisp1_config_path(isp, mbus_type);
+ rkisp1_config_ism(isp, sd_state);
return 0;
}
-static void rkisp1_isp_stop(struct rkisp1_device *rkisp1)
+static void rkisp1_isp_stop(struct rkisp1_isp *isp)
{
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
u32 val;
/*
* ISP(mi) stop in mi frame end -> Stop ISP(mipi) ->
* Stop ISP(isp) ->wait for ISP isp off
*/
- /* stop and clear MI, MIPI, and ISP interrupts */
- rkisp1_write(rkisp1, 0, RKISP1_CIF_MIPI_IMSC);
- rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR);
-
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IMSC);
- rkisp1_write(rkisp1, ~0, RKISP1_CIF_ISP_ICR);
-
- rkisp1_write(rkisp1, 0, RKISP1_CIF_MI_IMSC);
- rkisp1_write(rkisp1, ~0, RKISP1_CIF_MI_ICR);
- val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
- rkisp1_write(rkisp1, val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA),
- RKISP1_CIF_MIPI_CTRL);
+
+ /* Mask MI and ISP interrupts */
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_IMSC, 0);
+
+ /* Flush posted writes */
+ rkisp1_read(rkisp1, RKISP1_CIF_MI_IMSC);
+
+ /*
+ * Wait until the IRQ handler has ended. The IRQ handler may get called
+ * even after this, but it will return immediately as the MI and ISP
+ * interrupts have been masked.
+ */
+ synchronize_irq(rkisp1->irqs[RKISP1_IRQ_ISP]);
+ if (rkisp1->irqs[RKISP1_IRQ_ISP] != rkisp1->irqs[RKISP1_IRQ_MI])
+ synchronize_irq(rkisp1->irqs[RKISP1_IRQ_MI]);
+
+ /* Clear MI and ISP interrupt status */
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, ~0);
+
/* stop ISP */
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
val &= ~(RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE |
RKISP1_CIF_ISP_CTRL_ISP_ENABLE);
- rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
- rkisp1_write(rkisp1, val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD,
- RKISP1_CIF_ISP_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL,
+ val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD);
readx_poll_timeout(readl, rkisp1->base_addr + RKISP1_CIF_ISP_RIS,
val, val & RKISP1_CIF_ISP_OFF, 20, 100);
- rkisp1_write(rkisp1,
- RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST,
- RKISP1_CIF_IRCL);
- rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL);
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL,
+ RKISP1_CIF_VI_IRCL_MIPI_SW_RST |
+ RKISP1_CIF_VI_IRCL_ISP_SW_RST);
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL, 0x0);
+
+ if (rkisp1->info->isp_ver == RKISP1_V_IMX8MP)
+ rkisp1_gasket_disable(rkisp1);
}
-static void rkisp1_config_clk(struct rkisp1_device *rkisp1)
+static void rkisp1_config_clk(struct rkisp1_isp *isp)
{
- u32 val = RKISP1_CIF_ICCL_ISP_CLK | RKISP1_CIF_ICCL_CP_CLK |
- RKISP1_CIF_ICCL_MRSZ_CLK | RKISP1_CIF_ICCL_SRSZ_CLK |
- RKISP1_CIF_ICCL_JPEG_CLK | RKISP1_CIF_ICCL_MI_CLK |
- RKISP1_CIF_ICCL_IE_CLK | RKISP1_CIF_ICCL_MIPI_CLK |
- RKISP1_CIF_ICCL_DCROP_CLK;
-
- rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL);
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
+
+ u32 val = RKISP1_CIF_VI_ICCL_ISP_CLK | RKISP1_CIF_VI_ICCL_CP_CLK |
+ RKISP1_CIF_VI_ICCL_MRSZ_CLK | RKISP1_CIF_VI_ICCL_SRSZ_CLK |
+ RKISP1_CIF_VI_ICCL_JPEG_CLK | RKISP1_CIF_VI_ICCL_MI_CLK |
+ RKISP1_CIF_VI_ICCL_IE_CLK | RKISP1_CIF_VI_ICCL_MIPI_CLK |
+ RKISP1_CIF_VI_ICCL_DCROP_CLK;
+
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_ICCL, val);
+
+ /* ensure sp and mp can run at the same time in V12 */
+ if (rkisp1->info->isp_ver == RKISP1_V12) {
+ val = RKISP1_CIF_CLK_CTRL_MI_Y12 | RKISP1_CIF_CLK_CTRL_MI_SP |
+ RKISP1_CIF_CLK_CTRL_MI_RAW0 | RKISP1_CIF_CLK_CTRL_MI_RAW1 |
+ RKISP1_CIF_CLK_CTRL_MI_READ | RKISP1_CIF_CLK_CTRL_MI_RAWRD |
+ RKISP1_CIF_CLK_CTRL_CP | RKISP1_CIF_CLK_CTRL_IE;
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_ISP_CLK_CTRL_V12, val);
+ }
}
-static void rkisp1_isp_start(struct rkisp1_device *rkisp1)
+static int rkisp1_isp_start(struct rkisp1_isp *isp,
+ const struct v4l2_subdev_state *sd_state,
+ struct media_pad *source)
{
- struct rkisp1_sensor_async *sensor = rkisp1->active_sensor;
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
+ const struct v4l2_mbus_framefmt *src_fmt;
+ const struct rkisp1_mbus_info *src_info;
u32 val;
+ int ret;
- rkisp1_config_clk(rkisp1);
+ rkisp1_config_clk(isp);
- /* Activate MIPI */
- if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) {
- val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
- rkisp1_write(rkisp1, val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA,
- RKISP1_CIF_MIPI_CTRL);
+ if (rkisp1->info->isp_ver == RKISP1_V_IMX8MP) {
+ ret = rkisp1_gasket_enable(rkisp1, source);
+ if (ret)
+ return ret;
}
+
/* Activate ISP */
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD |
RKISP1_CIF_ISP_CTRL_ISP_ENABLE |
RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE;
- rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
- /*
- * CIF spec says to wait for sufficient time after enabling
- * the MIPI interface and before starting the sensor output.
- */
- usleep_range(1000, 1200);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
+
+ if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER)
+ rkisp1_params_post_configure(&rkisp1->params);
+
+ return 0;
}
/* ----------------------------------------------------------------------------
* Subdev pad operations
*/
+static inline struct rkisp1_isp *to_rkisp1_isp(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct rkisp1_isp, sd);
+}
+
static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -584,11 +490,12 @@ static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
- if (code->index >= ARRAY_SIZE(rkisp1_isp_formats))
- return -EINVAL;
+ for (i = 0; ; i++) {
+ const struct rkisp1_mbus_info *fmt =
+ rkisp1_mbus_info_get_by_index(i);
- for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) {
- const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i];
+ if (!fmt)
+ return -EINVAL;
if (fmt->direction & dir)
pos++;
@@ -610,7 +517,8 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- const struct rkisp1_isp_mbus_info *mbus_info;
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
+ const struct rkisp1_mbus_info *mbus_info;
if (fse->pad == RKISP1_ISP_PAD_SINK_PARAMS ||
fse->pad == RKISP1_ISP_PAD_SOURCE_STATS)
@@ -619,7 +527,7 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index > 0)
return -EINVAL;
- mbus_info = rkisp1_isp_mbus_info_get(fse->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(fse->code);
if (!mbus_info)
return -EINVAL;
@@ -632,46 +540,56 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;
fse->min_width = RKISP1_ISP_MIN_WIDTH;
- fse->max_width = RKISP1_ISP_MAX_WIDTH;
+ fse->max_width = isp->rkisp1->info->max_width;
fse->min_height = RKISP1_ISP_MIN_HEIGHT;
- fse->max_height = RKISP1_ISP_MAX_HEIGHT;
+ fse->max_height = isp->rkisp1->info->max_height;
return 0;
}
-static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int rkisp1_isp_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
struct v4l2_rect *sink_crop, *src_crop;
- sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ /* Video. */
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
sink_fmt->width = RKISP1_DEFAULT_WIDTH;
sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
sink_fmt->field = V4L2_FIELD_NONE;
sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT;
+ sink_fmt->colorspace = V4L2_COLORSPACE_RAW;
+ sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+ sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
- sink_crop = v4l2_subdev_get_try_crop(sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
sink_crop->width = RKISP1_DEFAULT_WIDTH;
sink_crop->height = RKISP1_DEFAULT_HEIGHT;
sink_crop->left = 0;
sink_crop->top = 0;
- src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
*src_fmt = *sink_fmt;
src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
+ src_fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ src_fmt->xfer_func = V4L2_XFER_FUNC_SRGB;
+ src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
- src_crop = v4l2_subdev_get_try_crop(sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
*src_crop = *sink_crop;
- sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- RKISP1_ISP_PAD_SINK_PARAMS);
- src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_STATS);
+ /* Parameters and statistics. */
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_PARAMS);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_STATS);
sink_fmt->width = 0;
sink_fmt->height = 0;
sink_fmt->field = V4L2_FIELD_NONE;
@@ -683,59 +601,117 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
struct v4l2_subdev_state *sd_state,
- struct v4l2_mbus_framefmt *format,
- unsigned int which)
+ struct v4l2_mbus_framefmt *format)
{
- const struct rkisp1_isp_mbus_info *mbus_info;
+ const struct rkisp1_mbus_info *sink_info;
+ const struct rkisp1_mbus_info *src_info;
+ struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_mbus_framefmt *src_fmt;
const struct v4l2_rect *src_crop;
+ bool set_csc;
+
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
- src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO, which);
- src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO, which);
+ /*
+ * Media bus code. The ISP can operate in pass-through mode (Bayer in,
+ * Bayer out or YUV in, YUV out) or process Bayer data to YUV, but
+ * can't convert from YUV to Bayer.
+ */
+ sink_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
src_fmt->code = format->code;
- mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code);
- if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) {
+ src_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
+ if (!src_info || !(src_info->direction & RKISP1_ISP_SD_SRC)) {
src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
- mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code);
+ src_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
+ }
+
+ if (sink_info->pixel_enc == V4L2_PIXEL_ENC_YUV &&
+ src_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
+ src_fmt->code = sink_fmt->code;
+ src_info = sink_info;
}
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- isp->src_fmt = mbus_info;
+
+ /*
+ * The source width and height must be identical to the source crop
+ * size.
+ */
src_fmt->width = src_crop->width;
src_fmt->height = src_crop->height;
/*
- * The CSC API is used to allow userspace to force full
- * quantization on YUV formats.
+ * Copy the color space for the sink pad. When converting from Bayer to
+ * YUV, default to a limited quantization range.
*/
- if (format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC &&
- format->quantization == V4L2_QUANTIZATION_FULL_RANGE &&
- mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV)
- src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
- else if (mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV)
+ src_fmt->colorspace = sink_fmt->colorspace;
+ src_fmt->xfer_func = sink_fmt->xfer_func;
+ src_fmt->ycbcr_enc = sink_fmt->ycbcr_enc;
+
+ if (sink_info->pixel_enc == V4L2_PIXEL_ENC_BAYER &&
+ src_info->pixel_enc == V4L2_PIXEL_ENC_YUV)
src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
else
- src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ src_fmt->quantization = sink_fmt->quantization;
+
+ /*
+ * Allow setting the source color space fields when the SET_CSC flag is
+ * set and the source format is YUV. If the sink format is YUV, don't
+ * set the color primaries, transfer function or YCbCr encoding as the
+ * ISP is bypassed in that case and passes YUV data through without
+ * modifications.
+ *
+ * The color primaries and transfer function are configured through the
+ * cross-talk matrix and tone curve respectively. Settings for those
+ * hardware blocks are conveyed through the ISP parameters buffer, as
+ * they need to combine color space information with other image tuning
+ * characteristics and can't thus be computed by the kernel based on the
+ * color space. The source pad colorspace and xfer_func fields are thus
+ * ignored by the driver, but can be set by userspace to propagate
+ * accurate color space information down the pipeline.
+ */
+ set_csc = format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC;
+
+ if (set_csc && src_info->pixel_enc == V4L2_PIXEL_ENC_YUV) {
+ if (sink_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
+ if (format->colorspace != V4L2_COLORSPACE_DEFAULT)
+ src_fmt->colorspace = format->colorspace;
+ if (format->xfer_func != V4L2_XFER_FUNC_DEFAULT)
+ src_fmt->xfer_func = format->xfer_func;
+ if (format->ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT)
+ src_fmt->ycbcr_enc = format->ycbcr_enc;
+ }
+
+ if (format->quantization != V4L2_QUANTIZATION_DEFAULT)
+ src_fmt->quantization = format->quantization;
+ }
*format = *src_fmt;
+
+ /*
+ * Restore the SET_CSC flag if it was set to indicate support for the
+ * CSC setting API.
+ */
+ if (set_csc)
+ format->flags |= V4L2_MBUS_FRAMEFMT_SET_CSC;
}
static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
struct v4l2_subdev_state *sd_state,
- struct v4l2_rect *r, unsigned int which)
+ struct v4l2_rect *r)
{
struct v4l2_mbus_framefmt *src_fmt;
const struct v4l2_rect *sink_crop;
struct v4l2_rect *src_crop;
- src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO,
- which);
- sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO,
- which);
+ src_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
src_crop->left = ALIGN(r->left, 2);
src_crop->width = ALIGN(r->width, 2);
@@ -746,24 +722,22 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
*r = *src_crop;
/* Propagate to out format */
- src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO, which);
- rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt, which);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt);
}
static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
struct v4l2_subdev_state *sd_state,
- struct v4l2_rect *r, unsigned int which)
+ struct v4l2_rect *r)
{
struct v4l2_rect *sink_crop, *src_crop;
- struct v4l2_mbus_framefmt *sink_fmt;
+ const struct v4l2_mbus_framefmt *sink_fmt;
- sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO,
- which);
- sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO,
- which);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
sink_crop->left = ALIGN(r->left, 2);
sink_crop->width = ALIGN(r->width, 2);
@@ -774,79 +748,88 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
*r = *sink_crop;
/* Propagate to out crop */
- src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO, which);
- rkisp1_isp_set_src_crop(isp, sd_state, src_crop, which);
+ src_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ rkisp1_isp_set_src_crop(isp, sd_state, src_crop);
}
static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
struct v4l2_subdev_state *sd_state,
- struct v4l2_mbus_framefmt *format,
- unsigned int which)
+ struct v4l2_mbus_framefmt *format)
{
- const struct rkisp1_isp_mbus_info *mbus_info;
+ const struct rkisp1_mbus_info *mbus_info;
struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_rect *sink_crop;
+ bool is_yuv;
- sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO,
- which);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
sink_fmt->code = format->code;
- mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) {
sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT;
- mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
}
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- isp->sink_fmt = mbus_info;
sink_fmt->width = clamp_t(u32, format->width,
RKISP1_ISP_MIN_WIDTH,
- RKISP1_ISP_MAX_WIDTH);
+ isp->rkisp1->info->max_width);
sink_fmt->height = clamp_t(u32, format->height,
RKISP1_ISP_MIN_HEIGHT,
- RKISP1_ISP_MAX_HEIGHT);
+ isp->rkisp1->info->max_height);
+
+ /*
+ * Adjust the color space fields. Accept any color primaries and
+ * transfer function for both YUV and Bayer. For YUV any YCbCr encoding
+ * and quantization range is also accepted. For Bayer formats, the YCbCr
+ * encoding isn't applicable, and the quantization range can only be
+ * full.
+ */
+ is_yuv = mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV;
+
+ sink_fmt->colorspace = format->colorspace ? :
+ (is_yuv ? V4L2_COLORSPACE_SRGB :
+ V4L2_COLORSPACE_RAW);
+ sink_fmt->xfer_func = format->xfer_func ? :
+ V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace);
+ if (is_yuv) {
+ sink_fmt->ycbcr_enc = format->ycbcr_enc ? :
+ V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace);
+ sink_fmt->quantization = format->quantization ? :
+ V4L2_MAP_QUANTIZATION_DEFAULT(false, sink_fmt->colorspace,
+ sink_fmt->ycbcr_enc);
+ } else {
+ /*
+ * The YCbCr encoding isn't applicable for non-YUV formats, but
+ * V4L2 has no "no encoding" value. Hardcode it to Rec. 601, it
+ * should be ignored by userspace.
+ */
+ sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ }
*format = *sink_fmt;
/* Propagate to in crop */
- sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO,
- which);
- rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop, which);
-}
-
-static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
-
- mutex_lock(&isp->ops_lock);
- fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad,
- fmt->which);
- mutex_unlock(&isp->ops_lock);
- return 0;
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop);
}
static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
- mutex_lock(&isp->ops_lock);
if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO)
- rkisp1_isp_set_sink_fmt(isp, sd_state, &fmt->format,
- fmt->which);
+ rkisp1_isp_set_sink_fmt(isp, sd_state, &fmt->format);
else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
- rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format,
- fmt->which);
+ rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format);
else
- fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad,
- fmt->which);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
- mutex_unlock(&isp->ops_lock);
return 0;
}
@@ -854,39 +837,37 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
int ret = 0;
if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO &&
sel->pad != RKISP1_ISP_PAD_SINK_VIDEO)
return -EINVAL;
- mutex_lock(&isp->ops_lock);
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) {
struct v4l2_mbus_framefmt *fmt;
- fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, sel->pad,
- sel->which);
+ fmt = v4l2_subdev_state_get_format(sd_state, sel->pad);
sel->r.height = fmt->height;
sel->r.width = fmt->width;
sel->r.left = 0;
sel->r.top = 0;
} else {
- sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO,
- sel->which);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
}
break;
+
case V4L2_SEL_TGT_CROP:
- sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state, sel->pad,
- sel->which);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
break;
+
default:
ret = -EINVAL;
+ break;
}
- mutex_unlock(&isp->ops_lock);
+
return ret;
}
@@ -894,25 +875,22 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct rkisp1_device *rkisp1 =
- container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev);
- struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
int ret = 0;
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__,
+ dev_dbg(isp->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%ux%u\n", __func__,
sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
- mutex_lock(&isp->ops_lock);
+
if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO)
- rkisp1_isp_set_sink_crop(isp, sd_state, &sel->r, sel->which);
+ rkisp1_isp_set_sink_crop(isp, sd_state, &sel->r);
else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
- rkisp1_isp_set_src_crop(isp, sd_state, &sel->r, sel->which);
+ rkisp1_isp_set_src_crop(isp, sd_state, &sel->r);
else
ret = -EINVAL;
- mutex_unlock(&isp->ops_lock);
return ret;
}
@@ -929,8 +907,7 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = {
.enum_frame_size = rkisp1_isp_enum_frame_size,
.get_selection = rkisp1_isp_get_selection,
.set_selection = rkisp1_isp_set_selection,
- .init_cfg = rkisp1_isp_init_config,
- .get_fmt = rkisp1_isp_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = rkisp1_isp_set_fmt,
.link_validate = v4l2_subdev_link_validate_default,
};
@@ -939,80 +916,75 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = {
* Stream operations
*/
-static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp,
- struct rkisp1_sensor_async *sensor)
+static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct rkisp1_device *rkisp1 =
- container_of(isp->sd.v4l2_dev, struct rkisp1_device, v4l2_dev);
- union phy_configure_opts opts;
- struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
- s64 pixel_clock;
-
- if (!sensor->pixel_rate_ctrl) {
- dev_warn(rkisp1->dev, "No pixel rate control in sensor subdev\n");
- return -EPIPE;
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
+ struct v4l2_subdev_state *sd_state;
+ struct media_pad *source_pad;
+ struct media_pad *sink_pad;
+ enum v4l2_mbus_type mbus_type;
+ u32 mbus_flags;
+ int ret;
+
+ if (!enable) {
+ v4l2_subdev_call(rkisp1->source, video, s_stream, false);
+ rkisp1_isp_stop(isp);
+ return 0;
}
- pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl);
- if (!pixel_clock) {
- dev_err(rkisp1->dev, "Invalid pixel rate value\n");
- return -EINVAL;
+ sink_pad = &isp->pads[RKISP1_ISP_PAD_SINK_VIDEO];
+ source_pad = media_pad_remote_pad_unique(sink_pad);
+ if (IS_ERR(source_pad)) {
+ dev_dbg(rkisp1->dev, "Failed to get source for ISP: %pe\n",
+ source_pad);
+ return -EPIPE;
}
- phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width,
- sensor->lanes, cfg);
- phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY);
- phy_configure(sensor->dphy, &opts);
- phy_power_on(sensor->dphy);
+ rkisp1->source = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (!rkisp1->source) {
+ /* This should really not happen, so is not worth a message. */
+ return -EPIPE;
+ }
- return 0;
-}
+ if (rkisp1->source == &rkisp1->csi.sd) {
+ mbus_type = V4L2_MBUS_CSI2_DPHY;
+ mbus_flags = 0;
+ } else {
+ const struct rkisp1_sensor_async *asd;
+ struct v4l2_async_connection *asc;
-static void rkisp1_mipi_csi2_stop(struct rkisp1_sensor_async *sensor)
-{
- phy_power_off(sensor->dphy);
-}
+ asc = v4l2_async_connection_unique(rkisp1->source);
+ if (!asc)
+ return -EPIPE;
-static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct rkisp1_device *rkisp1 =
- container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev);
- struct rkisp1_isp *isp = &rkisp1->isp;
- struct v4l2_subdev *sensor_sd;
- int ret = 0;
+ asd = container_of(asc, struct rkisp1_sensor_async, asd);
- if (!enable) {
- rkisp1_isp_stop(rkisp1);
- rkisp1_mipi_csi2_stop(rkisp1->active_sensor);
- return 0;
+ mbus_type = asd->mbus_type;
+ mbus_flags = asd->mbus_flags;
}
- sensor_sd = rkisp1_get_remote_sensor(sd);
- if (!sensor_sd) {
- dev_warn(rkisp1->dev, "No link between isp and sensor\n");
- return -ENODEV;
- }
+ isp->frame_sequence = -1;
+ isp->frame_active = false;
- rkisp1->active_sensor = container_of(sensor_sd->asd,
- struct rkisp1_sensor_async, asd);
+ sd_state = v4l2_subdev_lock_and_get_active_state(sd);
- if (rkisp1->active_sensor->mbus_type != V4L2_MBUS_CSI2_DPHY)
- return -EINVAL;
-
- rkisp1->isp.frame_sequence = -1;
- mutex_lock(&isp->ops_lock);
- ret = rkisp1_config_cif(rkisp1);
+ ret = rkisp1_config_cif(isp, sd_state, mbus_type, mbus_flags);
if (ret)
- goto mutex_unlock;
+ goto out_unlock;
- ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor);
+ ret = rkisp1_isp_start(isp, sd_state, source_pad);
if (ret)
- goto mutex_unlock;
+ goto out_unlock;
- rkisp1_isp_start(rkisp1);
+ ret = v4l2_subdev_call(rkisp1->source, video, s_stream, true);
+ if (ret) {
+ rkisp1_isp_stop(isp);
+ goto out_unlock;
+ }
-mutex_unlock:
- mutex_unlock(&isp->ops_lock);
+out_unlock:
+ v4l2_subdev_unlock_state(sd_state);
return ret;
}
@@ -1048,17 +1020,21 @@ static const struct v4l2_subdev_ops rkisp1_isp_ops = {
.pad = &rkisp1_isp_pad_ops,
};
+static const struct v4l2_subdev_internal_ops rkisp1_isp_internal_ops = {
+ .init_state = rkisp1_isp_init_state,
+};
+
int rkisp1_isp_register(struct rkisp1_device *rkisp1)
{
- struct v4l2_subdev_state state = {
- .pads = rkisp1->isp.pad_cfg
- };
struct rkisp1_isp *isp = &rkisp1->isp;
struct media_pad *pads = isp->pads;
struct v4l2_subdev *sd = &isp->sd;
int ret;
+ isp->rkisp1 = rkisp1;
+
v4l2_subdev_init(sd, &rkisp1_isp_ops);
+ sd->internal_ops = &rkisp1_isp_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
sd->entity.ops = &rkisp1_isp_media_ops;
sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
@@ -1071,113 +1047,88 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1)
pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE;
pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE;
- isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT);
- isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT);
-
- mutex_init(&isp->ops_lock);
ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads);
if (ret)
- return ret;
+ goto err_entity_cleanup;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret)
+ goto err_subdev_cleanup;
ret = v4l2_device_register_subdev(&rkisp1->v4l2_dev, sd);
if (ret) {
dev_err(rkisp1->dev, "Failed to register isp subdev\n");
- goto err_cleanup_media_entity;
+ goto err_subdev_cleanup;
}
- rkisp1_isp_init_config(sd, &state);
return 0;
-err_cleanup_media_entity:
+err_subdev_cleanup:
+ v4l2_subdev_cleanup(sd);
+err_entity_cleanup:
media_entity_cleanup(&sd->entity);
-
+ isp->sd.v4l2_dev = NULL;
return ret;
}
void rkisp1_isp_unregister(struct rkisp1_device *rkisp1)
{
- struct v4l2_subdev *sd = &rkisp1->isp.sd;
+ struct rkisp1_isp *isp = &rkisp1->isp;
- v4l2_device_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
+ if (!isp->sd.v4l2_dev)
+ return;
+
+ v4l2_device_unregister_subdev(&isp->sd);
+ v4l2_subdev_cleanup(&isp->sd);
+ media_entity_cleanup(&isp->sd.entity);
}
/* ----------------------------------------------------------------------------
* Interrupt handlers
*/
-void rkisp1_mipi_isr(struct rkisp1_device *rkisp1)
-{
- u32 val, status;
-
- status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS);
- if (!status)
- return;
-
- rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR);
-
- /*
- * Disable DPHY errctrl interrupt, because this dphy
- * erctrl signal is asserted until the next changes
- * of line state. This time is may be too long and cpu
- * is hold in this interrupt.
- */
- if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) {
- val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
- rkisp1_write(rkisp1, val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f),
- RKISP1_CIF_MIPI_IMSC);
- rkisp1->isp.is_dphy_errctrl_disabled = true;
- }
-
- /*
- * Enable DPHY errctrl interrupt again, if mipi have receive
- * the whole frame without any error.
- */
- if (status == RKISP1_CIF_MIPI_FRAME_END) {
- /*
- * Enable DPHY errctrl interrupt again, if mipi have receive
- * the whole frame without any error.
- */
- if (rkisp1->isp.is_dphy_errctrl_disabled) {
- val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
- val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f);
- rkisp1_write(rkisp1, val, RKISP1_CIF_MIPI_IMSC);
- rkisp1->isp.is_dphy_errctrl_disabled = false;
- }
- } else {
- rkisp1->debug.mipi_error++;
- }
-}
-
-static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp)
+static void rkisp1_isp_sof(struct rkisp1_isp *isp)
{
struct v4l2_event event = {
.type = V4L2_EVENT_FRAME_SYNC,
};
- event.u.frame_sync.frame_sequence = isp->frame_sequence;
+ isp->frame_sequence++;
+ isp->frame_active = true;
+
+ event.u.frame_sync.frame_sequence = isp->frame_sequence;
v4l2_event_queue(isp->sd.devnode, &event);
}
-void rkisp1_isp_isr(struct rkisp1_device *rkisp1)
+irqreturn_t rkisp1_isp_isr(int irq, void *ctx)
{
+ struct device *dev = ctx;
+ struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
u32 status, isp_err;
+ if (!rkisp1->irqs_enabled)
+ return IRQ_NONE;
+
status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS);
if (!status)
- return;
+ return IRQ_NONE;
- rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, status);
- /* Vertical sync signal, starting generating new frame */
- if (status & RKISP1_CIF_ISP_V_START) {
- rkisp1->isp.frame_sequence++;
- rkisp1_isp_queue_event_sof(&rkisp1->isp);
+ /*
+ * Vertical sync signal, starting new frame. Defer handling of vsync
+ * after RKISP1_CIF_ISP_FRAME if the previous frame was not completed
+ * yet.
+ */
+ if (status & RKISP1_CIF_ISP_V_START && !rkisp1->isp.frame_active) {
+ status &= ~RKISP1_CIF_ISP_V_START;
+ rkisp1_isp_sof(&rkisp1->isp);
if (status & RKISP1_CIF_ISP_FRAME) {
WARN_ONCE(1, "irq delay is too long, buffers might not be in sync\n");
rkisp1->debug.irq_delay++;
}
}
+
if (status & RKISP1_CIF_ISP_PIC_SIZE_ERROR) {
/* Clear pic_size_error */
isp_err = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ERR);
@@ -1187,7 +1138,7 @@ void rkisp1_isp_isr(struct rkisp1_device *rkisp1)
rkisp1->debug.img_stabilization_size_error++;
if (isp_err & RKISP1_CIF_ISP_ERR_OUTFORM_SIZE)
rkisp1->debug.outform_size_error++;
- rkisp1_write(rkisp1, isp_err, RKISP1_CIF_ISP_ERR_CLR);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ERR_CLR, isp_err);
} else if (status & RKISP1_CIF_ISP_DATA_LOSS) {
/* keep track of data_loss in debugfs */
rkisp1->debug.data_loss++;
@@ -1196,6 +1147,9 @@ void rkisp1_isp_isr(struct rkisp1_device *rkisp1)
if (status & RKISP1_CIF_ISP_FRAME) {
u32 isp_ris;
+ rkisp1->isp.frame_active = false;
+ rkisp1->debug.complete_frames++;
+
/* New frame from the sensor received */
isp_ris = rkisp1_read(rkisp1, RKISP1_CIF_ISP_RIS);
if (isp_ris & RKISP1_STATS_MEAS_MASK)
@@ -1207,4 +1161,13 @@ void rkisp1_isp_isr(struct rkisp1_device *rkisp1)
*/
rkisp1_params_isr(rkisp1);
}
+
+ /*
+ * Deferred handling of vsync if RKISP1_CIF_ISP_V_START and
+ * RKISP1_CIF_ISP_FRAME occurred in the same irq.
+ */
+ if (status & RKISP1_CIF_ISP_V_START)
+ rkisp1_isp_sof(&rkisp1->isp);
+
+ return IRQ_HANDLED;
}