summaryrefslogtreecommitdiff
path: root/drivers/media/platform/nxp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/nxp')
-rw-r--r--drivers/media/platform/nxp/dw100/dw100.c7
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c45
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c353
-rw-r--r--drivers/media/platform/nxp/imx-pxp.c7
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c8
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h14
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c2
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c292
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c2
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c156
-rw-r--r--drivers/media/platform/nxp/mx2_emmaprp.c24
11 files changed, 471 insertions, 439 deletions
diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c
index 3d1db1121bf9..97744c7b7c03 100644
--- a/drivers/media/platform/nxp/dw100/dw100.c
+++ b/drivers/media/platform/nxp/dw100/dw100.c
@@ -266,7 +266,7 @@ static inline int dw100_dump_regs(struct seq_file *m)
static inline struct dw100_ctx *dw100_file2ctx(struct file *file)
{
- return container_of(file->private_data, struct dw100_ctx, fh);
+ return container_of(file_to_v4l2_fh(file), struct dw100_ctx, fh);
}
static struct dw100_q_data *dw100_get_q_data(struct dw100_ctx *ctx,
@@ -607,7 +607,6 @@ static int dw100_open(struct file *file)
mutex_init(&ctx->vq_mutex);
v4l2_fh_init(&ctx->fh, video_devdata(file));
- file->private_data = &ctx->fh;
ctx->dw_dev = dw_dev;
ctx->q_data[DW100_QUEUE_SRC].fmt = &formats[0];
@@ -651,7 +650,7 @@ static int dw100_open(struct file *file)
goto err;
}
- v4l2_fh_add(&ctx->fh);
+ v4l2_fh_add(&ctx->fh, file);
return 0;
@@ -668,7 +667,7 @@ static int dw100_release(struct file *file)
{
struct dw100_ctx *ctx = dw100_file2ctx(file);
- v4l2_fh_del(&ctx->fh);
+ v4l2_fh_del(&ctx->fh, file);
v4l2_fh_exit(&ctx->fh);
v4l2_ctrl_handler_free(&ctx->hdl);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index 8681dd193033..df3ccdf767ba 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -644,9 +644,9 @@ static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf,
}
}
-static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh)
+static inline struct mxc_jpeg_ctx *mxc_jpeg_file_to_ctx(struct file *filp)
{
- return container_of(fh, struct mxc_jpeg_ctx, fh);
+ return container_of(file_to_v4l2_fh(filp), struct mxc_jpeg_ctx, fh);
}
static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n,
@@ -1604,8 +1604,8 @@ end:
static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
struct v4l2_decoder_cmd *cmd)
{
- struct v4l2_fh *fh = file->private_data;
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct v4l2_fh *fh = file_to_v4l2_fh(file);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
unsigned long flags;
int ret;
@@ -1637,8 +1637,8 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
static int mxc_jpeg_encoder_cmd(struct file *file, void *priv,
struct v4l2_encoder_cmd *cmd)
{
- struct v4l2_fh *fh = file->private_data;
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct v4l2_fh *fh = file_to_v4l2_fh(file);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
unsigned long flags;
int ret;
@@ -2200,8 +2200,7 @@ static int mxc_jpeg_open(struct file *file)
}
v4l2_fh_init(&ctx->fh, mxc_vfd);
- file->private_data = &ctx->fh;
- v4l2_fh_add(&ctx->fh);
+ v4l2_fh_add(&ctx->fh, file);
ctx->mxc_jpeg = mxc_jpeg;
@@ -2234,7 +2233,7 @@ static int mxc_jpeg_open(struct file *file)
err_ctrls_setup:
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
error:
- v4l2_fh_del(&ctx->fh);
+ v4l2_fh_del(&ctx->fh, file);
v4l2_fh_exit(&ctx->fh);
mutex_unlock(&mxc_jpeg->lock);
free:
@@ -2256,7 +2255,7 @@ static int mxc_jpeg_querycap(struct file *file, void *priv,
static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type);
if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) {
@@ -2296,7 +2295,7 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
u32 type = ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? MXC_JPEG_FMT_TYPE_ENC :
MXC_JPEG_FMT_TYPE_RAW;
int ret;
@@ -2437,7 +2436,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f,
static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
struct mxc_jpeg_q_data tmp_q;
@@ -2456,7 +2455,7 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
struct mxc_jpeg_q_data tmp_q;
@@ -2508,20 +2507,20 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
+ return mxc_jpeg_s_fmt(mxc_jpeg_file_to_ctx(file), f);
}
static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
int ret;
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct vb2_queue *dst_vq;
struct mxc_jpeg_q_data *q_data_cap;
enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
struct v4l2_format fc;
- ret = mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
+ ret = mxc_jpeg_s_fmt(ctx, f);
if (ret)
return ret;
@@ -2550,7 +2549,7 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv,
static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
@@ -2588,7 +2587,7 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv,
static int mxc_jpeg_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct mxc_jpeg_q_data *q_data_cap;
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -2617,7 +2616,7 @@ static int mxc_jpeg_dec_g_selection(struct file *file, void *fh, struct v4l2_sel
static int mxc_jpeg_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct mxc_jpeg_q_data *q_data_out;
if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
@@ -2645,7 +2644,7 @@ static int mxc_jpeg_enc_g_selection(struct file *file, void *fh, struct v4l2_sel
static int mxc_jpeg_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE)
return mxc_jpeg_dec_g_selection(file, fh, s);
@@ -2655,7 +2654,7 @@ static int mxc_jpeg_g_selection(struct file *file, void *fh, struct v4l2_selecti
static int mxc_jpeg_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
{
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct mxc_jpeg_q_data *q_data_out;
if (ctx->mxc_jpeg->mode != MXC_JPEG_ENCODE)
@@ -2735,7 +2734,7 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = {
static int mxc_jpeg_release(struct file *file)
{
struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(file->private_data);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file);
struct device *dev = mxc_jpeg->dev;
mutex_lock(&mxc_jpeg->lock);
@@ -2747,7 +2746,7 @@ static int mxc_jpeg_release(struct file *file)
ctx->slot);
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
- v4l2_fh_del(&ctx->fh);
+ v4l2_fh_del(&ctx->fh, file);
v4l2_fh_exit(&ctx->fh);
kfree(ctx);
mutex_unlock(&mxc_jpeg->lock);
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 2beb5f43c2c0..d5de7854f579 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -54,23 +54,19 @@
/* CSIS common control */
#define MIPI_CSIS_CMN_CTRL 0x04
-#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW BIT(16)
-#define MIPI_CSIS_CMN_CTRL_INTER_MODE BIT(10)
+#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW(n) BIT((n) + 16)
+#define MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_DT BIT(10)
+#define MIPI_CSIS_CMN_CTRL_LANE_NUMBER(n) ((n) << 8)
+#define MIPI_CSIS_CMN_CTRL_LANE_NUMBER_MASK GENMASK(9, 8)
#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL BIT(2)
-#define MIPI_CSIS_CMN_CTRL_RESET BIT(1)
-#define MIPI_CSIS_CMN_CTRL_ENABLE BIT(0)
-
-#define MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET 8
-#define MIPI_CSIS_CMN_CTRL_LANE_NR_MASK (3 << 8)
+#define MIPI_CSIS_CMN_CTRL_SW_RESET BIT(1)
+#define MIPI_CSIS_CMN_CTRL_CSI_EN BIT(0)
/* CSIS clock control */
#define MIPI_CSIS_CLK_CTRL 0x08
-#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH3(x) ((x) << 28)
-#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH2(x) ((x) << 24)
-#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH1(x) ((x) << 20)
-#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(x) ((x) << 16)
-#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK (0xf << 4)
-#define MIPI_CSIS_CLK_CTRL_WCLK_SRC BIT(0)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(n, x) ((x) << ((n) * 4 + 16))
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MASK GENMASK(7, 4)
+#define MIPI_CSIS_CLK_CTRL_WCLK_SRC(n) BIT(n)
/* CSIS Interrupt mask */
#define MIPI_CSIS_INT_MSK 0x10
@@ -87,7 +83,7 @@
#define MIPI_CSIS_INT_MSK_ERR_WRONG_CFG BIT(3)
#define MIPI_CSIS_INT_MSK_ERR_ECC BIT(2)
#define MIPI_CSIS_INT_MSK_ERR_CRC BIT(1)
-#define MIPI_CSIS_INT_MSK_ERR_UNKNOWN BIT(0)
+#define MIPI_CSIS_INT_MSK_ERR_ID BIT(0)
/* CSIS Interrupt source */
#define MIPI_CSIS_INT_SRC 0x14
@@ -98,16 +94,16 @@
#define MIPI_CSIS_INT_SRC_ODD_AFTER BIT(28)
#define MIPI_CSIS_INT_SRC_ODD (0x3 << 28)
#define MIPI_CSIS_INT_SRC_NON_IMAGE_DATA (0xf << 28)
-#define MIPI_CSIS_INT_SRC_FRAME_START BIT(24)
-#define MIPI_CSIS_INT_SRC_FRAME_END BIT(20)
-#define MIPI_CSIS_INT_SRC_ERR_SOT_HS BIT(16)
-#define MIPI_CSIS_INT_SRC_ERR_LOST_FS BIT(12)
-#define MIPI_CSIS_INT_SRC_ERR_LOST_FE BIT(8)
-#define MIPI_CSIS_INT_SRC_ERR_OVER BIT(4)
+#define MIPI_CSIS_INT_SRC_FRAME_START(n) BIT((n) + 24)
+#define MIPI_CSIS_INT_SRC_FRAME_END(n) BIT((n) + 20)
+#define MIPI_CSIS_INT_SRC_ERR_SOT_HS(n) BIT((n) + 16)
+#define MIPI_CSIS_INT_SRC_ERR_LOST_FS(n) BIT((n) + 12)
+#define MIPI_CSIS_INT_SRC_ERR_LOST_FE(n) BIT((n) + 8)
+#define MIPI_CSIS_INT_SRC_ERR_OVER(n) BIT((n) + 4)
#define MIPI_CSIS_INT_SRC_ERR_WRONG_CFG BIT(3)
#define MIPI_CSIS_INT_SRC_ERR_ECC BIT(2)
#define MIPI_CSIS_INT_SRC_ERR_CRC BIT(1)
-#define MIPI_CSIS_INT_SRC_ERR_UNKNOWN BIT(0)
+#define MIPI_CSIS_INT_SRC_ERR_ID BIT(0)
#define MIPI_CSIS_INT_SRC_ERRORS 0xfffff
/* D-PHY status control */
@@ -123,8 +119,8 @@
#define MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE_MASK GENMASK(31, 24)
#define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(n) ((n) << 22)
#define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE_MASK GENMASK(23, 22)
-#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_CLK BIT(6)
-#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_DAT BIT(5)
+#define MIPI_CSIS_DPHY_CMN_CTRL_S_DPDN_SWAP_CLK BIT(6)
+#define MIPI_CSIS_DPHY_CMN_CTRL_S_DPDN_SWAP_DAT BIT(5)
#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_DAT BIT(1)
#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_CLK BIT(0)
#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE (0x1f << 0)
@@ -174,26 +170,28 @@
/* ISP Configuration register */
#define MIPI_CSIS_ISP_CONFIG_CH(n) (0x40 + (n) * 0x10)
-#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24)
+#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MASK GENMASK(31, 24)
#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) ((x) << 24)
#define MIPI_CSIS_ISPCFG_PIXEL_MODE_SINGLE (0 << 12)
#define MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL (1 << 12)
#define MIPI_CSIS_ISPCFG_PIXEL_MODE_QUAD (2 << 12) /* i.MX8M[MNP] only */
-#define MIPI_CSIS_ISPCFG_PIXEL_MASK (3 << 12)
-#define MIPI_CSIS_ISPCFG_ALIGN_32BIT BIT(11)
-#define MIPI_CSIS_ISPCFG_FMT(fmt) ((fmt) << 2)
-#define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2)
+#define MIPI_CSIS_ISPCFG_PIXEL_MODE_MASK GENMASK(13, 12)
+#define MIPI_CSIS_ISPCFG_PARALLEL BIT(11)
+#define MIPI_CSIS_ISPCFG_DATAFORMAT(fmt) ((fmt) << 2)
+#define MIPI_CSIS_ISPCFG_DATAFORMAT_MASK GENMASK(7, 2)
/* ISP Image Resolution register */
#define MIPI_CSIS_ISP_RESOL_CH(n) (0x44 + (n) * 0x10)
+#define MIPI_CSIS_ISP_RESOL_VRESOL(n) ((n) << 16)
+#define MIPI_CSIS_ISP_RESOL_HRESOL(n) ((n) << 0)
#define CSIS_MAX_PIX_WIDTH 0xffff
#define CSIS_MAX_PIX_HEIGHT 0xffff
/* ISP SYNC register */
#define MIPI_CSIS_ISP_SYNC_CH(n) (0x48 + (n) * 0x10)
-#define MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET 18
-#define MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET 12
-#define MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET 0
+#define MIPI_CSIS_ISP_SYNC_HSYNC_LINTV(n) ((n) << 18)
+#define MIPI_CSIS_ISP_SYNC_VSYNC_SINTV(n) ((n) << 12)
+#define MIPI_CSIS_ISP_SYNC_VSYNC_EINTV(n) ((n) << 0)
/* ISP shadow registers */
#define MIPI_CSIS_SDW_CONFIG_CH(n) (0x80 + (n) * 0x10)
@@ -203,23 +201,23 @@
/* Debug control register */
#define MIPI_CSIS_DBG_CTRL 0xc0
#define MIPI_CSIS_DBG_INTR_MSK 0xc4
-#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT BIT(25)
-#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE BIT(24)
-#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE BIT(20)
-#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME BIT(16)
-#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE BIT(12)
-#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS BIT(8)
-#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL BIT(4)
-#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE BIT(0)
+#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT BIT(25)
+#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE BIT(24)
+#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE(n) BIT((n) + 20)
+#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME(n) BIT((n) + 16)
+#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE(n) BIT((n) + 12)
+#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS(n) BIT((n) + 8)
+#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL(n) BIT((n) + 4)
+#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE(n) BIT((n) + 0)
#define MIPI_CSIS_DBG_INTR_SRC 0xc8
-#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT BIT(25)
-#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE BIT(24)
-#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE BIT(20)
-#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME BIT(16)
-#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE BIT(12)
-#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS BIT(8)
-#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL BIT(4)
-#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0)
+#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT BIT(25)
+#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE BIT(24)
+#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(n) BIT((n) + 20)
+#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(n) BIT((n) + 16)
+#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(n) BIT((n) + 12)
+#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(n) BIT((n) + 8)
+#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(n) BIT((n) + 4)
+#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(n) BIT((n) + 0)
#define MIPI_CSIS_FRAME_COUNTER_CH(n) (0x0100 + (n) * 4)
@@ -228,10 +226,11 @@
#define MIPI_CSIS_PKTDATA_EVEN 0x3000
#define MIPI_CSIS_PKTDATA_SIZE SZ_4K
-#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
+#define MIPI_CSIS_MAX_CHANNELS 4
struct mipi_csis_event {
bool debug;
+ unsigned int channel;
u32 mask;
const char * const name;
unsigned int counter;
@@ -239,33 +238,70 @@ struct mipi_csis_event {
static const struct mipi_csis_event mipi_csis_events[] = {
/* Errors */
- { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" },
- { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" },
- { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" },
- { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error" },
- { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" },
- { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End" },
- { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_SOT_HS(0), "SOT 0 Error" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_SOT_HS(1), "SOT 1 Error" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_SOT_HS(2), "SOT 2 Error" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_SOT_HS(3), "SOT 3 Error" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_LOST_FS(0), "Lost Frame Start Error 0" },
+ { false, 1, MIPI_CSIS_INT_SRC_ERR_LOST_FS(1), "Lost Frame Start Error 1" },
+ { false, 2, MIPI_CSIS_INT_SRC_ERR_LOST_FS(2), "Lost Frame Start Error 2" },
+ { false, 3, MIPI_CSIS_INT_SRC_ERR_LOST_FS(3), "Lost Frame Start Error 3" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_LOST_FE(0), "Lost Frame End Error 0" },
+ { false, 1, MIPI_CSIS_INT_SRC_ERR_LOST_FE(1), "Lost Frame End Error 1" },
+ { false, 2, MIPI_CSIS_INT_SRC_ERR_LOST_FE(2), "Lost Frame End Error 2" },
+ { false, 3, MIPI_CSIS_INT_SRC_ERR_LOST_FE(3), "Lost Frame End Error 3" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_OVER(0), "FIFO Overflow Error 0" },
+ { false, 1, MIPI_CSIS_INT_SRC_ERR_OVER(1), "FIFO Overflow Error 1" },
+ { false, 2, MIPI_CSIS_INT_SRC_ERR_OVER(2), "FIFO Overflow Error 2" },
+ { false, 3, MIPI_CSIS_INT_SRC_ERR_OVER(3), "FIFO Overflow Error 3" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" },
+ { false, 0, MIPI_CSIS_INT_SRC_ERR_ID, "Unknown ID Error" },
+ { true, 0, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" },
+ { true, 0, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" },
+ { true, 0, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(0), "Frame Size Error 0" },
+ { true, 1, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(1), "Frame Size Error 1" },
+ { true, 2, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(2), "Frame Size Error 2" },
+ { true, 3, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(3), "Frame Size Error 3" },
+ { true, 0, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(0), "Truncated Frame 0" },
+ { true, 1, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(1), "Truncated Frame 1" },
+ { true, 2, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(2), "Truncated Frame 2" },
+ { true, 3, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(3), "Truncated Frame 3" },
+ { true, 0, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(0), "Early Frame End 0" },
+ { true, 1, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(1), "Early Frame End 1" },
+ { true, 2, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(2), "Early Frame End 2" },
+ { true, 3, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(3), "Early Frame End 3" },
+ { true, 0, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(0), "Early Frame Start 0" },
+ { true, 1, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(1), "Early Frame Start 1" },
+ { true, 2, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(2), "Early Frame Start 2" },
+ { true, 3, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(3), "Early Frame Start 3" },
/* Non-image data receive events */
- { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" },
- { false, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" },
- { false, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" },
- { false, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" },
+ { false, 0, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" },
+ { false, 0, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" },
+ { false, 0, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" },
+ { false, 0, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" },
/* Frame start/end */
- { false, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" },
- { false, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" },
- { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge" },
- { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge" },
+ { false, 0, MIPI_CSIS_INT_SRC_FRAME_START(0), "Frame Start 0" },
+ { false, 1, MIPI_CSIS_INT_SRC_FRAME_START(1), "Frame Start 1" },
+ { false, 2, MIPI_CSIS_INT_SRC_FRAME_START(2), "Frame Start 2" },
+ { false, 3, MIPI_CSIS_INT_SRC_FRAME_START(3), "Frame Start 3" },
+ { false, 0, MIPI_CSIS_INT_SRC_FRAME_END(0), "Frame End 0" },
+ { false, 1, MIPI_CSIS_INT_SRC_FRAME_END(1), "Frame End 1" },
+ { false, 2, MIPI_CSIS_INT_SRC_FRAME_END(2), "Frame End 2" },
+ { false, 3, MIPI_CSIS_INT_SRC_FRAME_END(3), "Frame End 3" },
+ { true, 0, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(0), "VSYNC Falling Edge 0" },
+ { true, 1, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(1), "VSYNC Falling Edge 1" },
+ { true, 2, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(2), "VSYNC Falling Edge 2" },
+ { true, 3, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(3), "VSYNC Falling Edge 3" },
+ { true, 0, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(0), "VSYNC Rising Edge 0" },
+ { true, 1, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(1), "VSYNC Rising Edge 1" },
+ { true, 2, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(2), "VSYNC Rising Edge 2" },
+ { true, 3, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(3), "VSYNC Rising Edge 3" },
};
-#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
+#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
+#define MIPI_CSIS_NUM_ERROR_EVENTS 38
enum mipi_csis_clk {
MIPI_CSIS_CLK_PCLK,
@@ -297,7 +333,9 @@ struct mipi_csis_device {
struct clk_bulk_data *clks;
struct reset_control *mrst;
struct regulator *mipi_phy_regulator;
+
const struct mipi_csis_info *info;
+ unsigned int num_channels;
struct v4l2_subdev sd;
struct media_pad pads[CSIS_PADS_NUM];
@@ -517,7 +555,7 @@ static void mipi_csis_sw_reset(struct mipi_csis_device *csis)
u32 val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL,
- val | MIPI_CSIS_CMN_CTRL_RESET);
+ val | MIPI_CSIS_CMN_CTRL_SW_RESET);
usleep_range(10, 20);
}
@@ -527,9 +565,9 @@ static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on)
val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
if (on)
- val |= MIPI_CSIS_CMN_CTRL_ENABLE;
+ val |= MIPI_CSIS_CMN_CTRL_CSI_EN;
else
- val &= ~MIPI_CSIS_CMN_CTRL_ENABLE;
+ val &= ~MIPI_CSIS_CMN_CTRL_CSI_EN;
mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val);
val = mipi_csis_read(csis, MIPI_CSIS_DPHY_CMN_CTRL);
@@ -549,8 +587,8 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis,
/* Color format */
val = mipi_csis_read(csis, MIPI_CSIS_ISP_CONFIG_CH(0));
- val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK
- | MIPI_CSIS_ISPCFG_PIXEL_MASK);
+ val &= ~(MIPI_CSIS_ISPCFG_PARALLEL | MIPI_CSIS_ISPCFG_PIXEL_MODE_MASK |
+ MIPI_CSIS_ISPCFG_DATAFORMAT_MASK);
/*
* YUV 4:2:2 can be transferred with 8 or 16 bits per clock sample
@@ -568,24 +606,23 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis,
if (csis_fmt->data_type == MIPI_CSI2_DT_YUV422_8B)
val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL;
- val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type);
+ val |= MIPI_CSIS_ISPCFG_DATAFORMAT(csis_fmt->data_type);
mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val);
/* Pixel resolution */
- val = format->width | (format->height << 16);
- mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val);
+ mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0),
+ MIPI_CSIS_ISP_RESOL_VRESOL(format->height) |
+ MIPI_CSIS_ISP_RESOL_HRESOL(format->width));
}
static int mipi_csis_calculate_params(struct mipi_csis_device *csis,
const struct csis_pix_format *csis_fmt)
{
- struct media_pad *src_pad =
- &csis->source.sd->entity.pads[csis->source.pad->index];
s64 link_freq;
u32 lane_rate;
/* Calculate the line rate from the pixel rate. */
- link_freq = v4l2_get_link_freq(src_pad, csis_fmt->width,
+ link_freq = v4l2_get_link_freq(csis->source.pad, csis_fmt->width,
csis->bus.num_data_lanes * 2);
if (link_freq < 0) {
dev_err(csis->dev, "Unable to obtain link frequency: %d\n",
@@ -635,10 +672,10 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis,
u32 val;
val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
- val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK;
- val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET;
+ val &= ~MIPI_CSIS_CMN_CTRL_LANE_NUMBER_MASK;
+ val |= MIPI_CSIS_CMN_CTRL_LANE_NUMBER(lanes - 1);
if (csis->info->version == MIPI_CSIS_V3_3)
- val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
+ val |= MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_DT;
mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val);
__mipi_csis_set_format(csis, format, csis_fmt);
@@ -647,15 +684,15 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis,
MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) |
MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(csis->clk_settle));
- val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET)
- | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET)
- | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET);
- mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(0), val);
+ mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(0),
+ MIPI_CSIS_ISP_SYNC_HSYNC_LINTV(0) |
+ MIPI_CSIS_ISP_SYNC_VSYNC_SINTV(0) |
+ MIPI_CSIS_ISP_SYNC_VSYNC_EINTV(0));
val = mipi_csis_read(csis, MIPI_CSIS_CLK_CTRL);
- val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC;
- val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15);
- val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK;
+ val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC(0);
+ val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(0, 15);
+ val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MASK;
mipi_csis_write(csis, MIPI_CSIS_CLK_CTRL, val);
mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_L,
@@ -671,7 +708,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis,
/* Update the shadow register. */
val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL,
- val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW |
+ val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW(0) |
MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL);
}
@@ -704,12 +741,17 @@ static int mipi_csis_clk_get(struct mipi_csis_device *csis)
if (ret < 0)
return ret;
- /* Set clock rate */
- ret = clk_set_rate(csis->clks[MIPI_CSIS_CLK_WRAP].clk,
- csis->clk_frequency);
- if (ret < 0)
- dev_err(csis->dev, "set rate=%d failed: %d\n",
- csis->clk_frequency, ret);
+ if (csis->clk_frequency) {
+ /*
+ * Set the clock rate. This is deprecated, for backward
+ * compatibility with old device trees.
+ */
+ ret = clk_set_rate(csis->clks[MIPI_CSIS_CLK_WRAP].clk,
+ csis->clk_frequency);
+ if (ret < 0)
+ dev_err(csis->dev, "set rate=%d failed: %d\n",
+ csis->clk_frequency, ret);
+ }
return ret;
}
@@ -757,16 +799,19 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
/* Update the event/error counters */
if ((status & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) {
- for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
+ for (i = 0; i < ARRAY_SIZE(csis->events); i++) {
struct mipi_csis_event *event = &csis->events[i];
+ if (event->channel >= csis->num_channels)
+ continue;
+
if ((!event->debug && (status & event->mask)) ||
(event->debug && (dbg_status & event->mask)))
event->counter++;
}
}
- if (status & MIPI_CSIS_INT_SRC_FRAME_START)
+ if (status & MIPI_CSIS_INT_SRC_FRAME_START(0))
mipi_csis_queue_event_sof(csis);
spin_unlock_irqrestore(&csis->slock, flags);
@@ -843,7 +888,7 @@ static void mipi_csis_clear_counters(struct mipi_csis_device *csis)
static void mipi_csis_log_counters(struct mipi_csis_device *csis, bool non_errors)
{
unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS
- : MIPI_CSIS_NUM_EVENTS - 8;
+ : MIPI_CSIS_NUM_ERROR_EVENTS;
unsigned int counters[MIPI_CSIS_NUM_EVENTS];
unsigned long flags;
unsigned int i;
@@ -854,45 +899,67 @@ static void mipi_csis_log_counters(struct mipi_csis_device *csis, bool non_error
spin_unlock_irqrestore(&csis->slock, flags);
for (i = 0; i < num_events; ++i) {
+ const struct mipi_csis_event *event = &csis->events[i];
+
+ if (event->channel >= csis->num_channels)
+ continue;
+
if (counters[i] > 0 || csis->debug.enable)
dev_info(csis->dev, "%s events: %d\n",
- csis->events[i].name,
- counters[i]);
+ event->name, counters[i]);
}
}
+struct mipi_csis_reg_info {
+ u32 addr;
+ unsigned int offset;
+ const char * const name;
+};
+
+static void mipi_csis_dump_channel_reg(struct mipi_csis_device *csis,
+ const struct mipi_csis_reg_info *reg,
+ unsigned int channel)
+{
+ dev_info(csis->dev, "%16s%u: 0x%08x\n", reg->name, channel,
+ mipi_csis_read(csis, reg->addr + channel * reg->offset));
+}
+
static int mipi_csis_dump_regs(struct mipi_csis_device *csis)
{
- static const struct {
- u32 offset;
- const char * const name;
- } registers[] = {
- { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" },
- { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" },
- { MIPI_CSIS_INT_MSK, "INT_MSK" },
- { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" },
- { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" },
- { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" },
- { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" },
- { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" },
- { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" },
- { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" },
- { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" },
- { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" },
- { MIPI_CSIS_FRAME_COUNTER_CH(0), "FRAME_COUNTER_CH0" },
+ static const struct mipi_csis_reg_info common_registers[] = {
+ { MIPI_CSIS_CMN_CTRL, 0, "CMN_CTRL" },
+ { MIPI_CSIS_CLK_CTRL, 0, "CLK_CTRL" },
+ { MIPI_CSIS_INT_MSK, 0, "INT_MSK" },
+ { MIPI_CSIS_DPHY_STATUS, 0, "DPHY_STATUS" },
+ { MIPI_CSIS_DPHY_CMN_CTRL, 0, "DPHY_CMN_CTRL" },
+ { MIPI_CSIS_DPHY_SCTRL_L, 0, "DPHY_SCTRL_L" },
+ { MIPI_CSIS_DPHY_SCTRL_H, 0, "DPHY_SCTRL_H" },
+ { MIPI_CSIS_DBG_CTRL, 0, "DBG_CTRL" },
+ };
+ static const struct mipi_csis_reg_info channel_registers[] = {
+ { MIPI_CSIS_ISP_CONFIG_CH(0), 0x10, "ISP_CONFIG_CH" },
+ { MIPI_CSIS_ISP_RESOL_CH(0), 0x10, "ISP_RESOL_CH" },
+ { MIPI_CSIS_SDW_CONFIG_CH(0), 0x10, "SDW_CONFIG_CH" },
+ { MIPI_CSIS_SDW_RESOL_CH(0), 0x10, "SDW_RESOL_CH" },
+ { MIPI_CSIS_FRAME_COUNTER_CH(0), 4, "FRAME_COUNTER_CH" },
};
-
- unsigned int i;
- u32 cfg;
if (!pm_runtime_get_if_in_use(csis->dev))
return 0;
dev_info(csis->dev, "--- REGISTERS ---\n");
- for (i = 0; i < ARRAY_SIZE(registers); i++) {
- cfg = mipi_csis_read(csis, registers[i].offset);
- dev_info(csis->dev, "%14s: 0x%08x\n", registers[i].name, cfg);
+ for (unsigned int i = 0; i < ARRAY_SIZE(common_registers); i++) {
+ const struct mipi_csis_reg_info *reg = &common_registers[i];
+
+ dev_info(csis->dev, "%17s: 0x%08x\n", reg->name,
+ mipi_csis_read(csis, reg->addr));
+ }
+
+ for (unsigned int chan = 0; chan < csis->num_channels; chan++) {
+ for (unsigned int i = 0; i < ARRAY_SIZE(channel_registers); ++i)
+ mipi_csis_dump_channel_reg(csis, &channel_registers[i],
+ chan);
}
pm_runtime_put(csis->dev);
@@ -998,7 +1065,7 @@ err_unlock:
}
static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code)
{
/*
@@ -1011,7 +1078,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- fmt = v4l2_subdev_state_get_format(sd_state, code->pad);
+ fmt = v4l2_subdev_state_get_format(state, code->pad);
code->code = fmt->code;
return 0;
}
@@ -1028,10 +1095,10 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
}
static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *sdformat)
{
- struct csis_pix_format const *csis_fmt;
+ const struct csis_pix_format *csis_fmt;
struct v4l2_mbus_framefmt *fmt;
unsigned int align;
@@ -1040,7 +1107,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
* modified.
*/
if (sdformat->pad == CSIS_PAD_SOURCE)
- return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
+ return v4l2_subdev_get_fmt(sd, state, sdformat);
if (sdformat->pad != CSIS_PAD_SINK)
return -EINVAL;
@@ -1078,7 +1145,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
&sdformat->format.height, 1,
CSIS_MAX_PIX_HEIGHT, 0, 0);
- fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
+ fmt = v4l2_subdev_state_get_format(state, sdformat->pad);
fmt->code = csis_fmt->code;
fmt->width = sdformat->format.width;
@@ -1092,7 +1159,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
sdformat->format = *fmt;
/* Propagate the format from sink to source. */
- fmt = v4l2_subdev_state_get_format(sd_state, CSIS_PAD_SOURCE);
+ fmt = v4l2_subdev_state_get_format(state, CSIS_PAD_SOURCE);
*fmt = sdformat->format;
/* The format on the source pad might change due to unpacking. */
@@ -1132,7 +1199,7 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
}
static int mipi_csis_init_state(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_format fmt = {
.pad = CSIS_PAD_SINK,
@@ -1149,7 +1216,7 @@ static int mipi_csis_init_state(struct v4l2_subdev *sd,
V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt.format.colorspace,
fmt.format.ycbcr_enc);
- return mipi_csis_set_fmt(sd, sd_state, &fmt);
+ return mipi_csis_set_fmt(sd, state, &fmt);
}
static int mipi_csis_log_status(struct v4l2_subdev *sd)
@@ -1413,9 +1480,13 @@ static int mipi_csis_parse_dt(struct mipi_csis_device *csis)
{
struct device_node *node = csis->dev->of_node;
- if (of_property_read_u32(node, "clock-frequency",
- &csis->clk_frequency))
- csis->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+ of_property_read_u32(node, "clock-frequency", &csis->clk_frequency);
+
+ csis->num_channels = 1;
+ of_property_read_u32(node, "fsl,num-channels", &csis->num_channels);
+ if (csis->num_channels < 1 || csis->num_channels > MIPI_CSIS_MAX_CHANNELS)
+ return dev_err_probe(csis->dev, -EINVAL,
+ "Invalid fsl,num-channels value\n");
return 0;
}
@@ -1440,10 +1511,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
/* Parse DT properties. */
ret = mipi_csis_parse_dt(csis);
- if (ret < 0) {
- dev_err(dev, "Failed to parse device tree: %d\n", ret);
+ if (ret < 0)
return ret;
- }
/* Acquire resources. */
csis->regs = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c
index 7f8ffbac582f..6cc9b07ea53a 100644
--- a/drivers/media/platform/nxp/imx-pxp.c
+++ b/drivers/media/platform/nxp/imx-pxp.c
@@ -248,7 +248,7 @@ struct pxp_ctx {
static inline struct pxp_ctx *file2ctx(struct file *file)
{
- return container_of(file->private_data, struct pxp_ctx, fh);
+ return container_of(file_to_v4l2_fh(file), struct pxp_ctx, fh);
}
static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx,
@@ -1660,7 +1660,6 @@ static int pxp_open(struct file *file)
}
v4l2_fh_init(&ctx->fh, video_devdata(file));
- file->private_data = &ctx->fh;
ctx->dev = dev;
hdl = &ctx->hdl;
v4l2_ctrl_handler_init(hdl, 4);
@@ -1699,7 +1698,7 @@ static int pxp_open(struct file *file)
goto open_unlock;
}
- v4l2_fh_add(&ctx->fh);
+ v4l2_fh_add(&ctx->fh, file);
atomic_inc(&dev->num_inst);
dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
@@ -1717,7 +1716,7 @@ static int pxp_release(struct file *file)
dprintk(dev, "Releasing instance %p\n", ctx);
- v4l2_fh_del(&ctx->fh);
+ v4l2_fh_del(&ctx->fh, file);
v4l2_fh_exit(&ctx->fh);
v4l2_ctrl_handler_free(&ctx->hdl);
mutex_lock(&dev->dev_mutex);
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
index 981648a03113..adc8d9960bf0 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
@@ -374,6 +374,8 @@ static int mxc_isi_pm_suspend(struct device *dev)
mxc_isi_video_suspend(pipe);
}
+ mxc_isi_m2m_suspend(&isi->m2m);
+
return pm_runtime_force_suspend(dev);
}
@@ -403,6 +405,12 @@ static int mxc_isi_pm_resume(struct device *dev)
}
}
+ ret = mxc_isi_m2m_resume(&isi->m2m);
+ if (ret) {
+ dev_err(dev, "Failed to resume ISI (%d) for m2m\n", ret);
+ err = ret;
+ }
+
return err;
}
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
index 206995bedca4..e84af5127e4e 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
@@ -202,9 +202,8 @@ struct mxc_isi_video {
struct video_device vdev;
struct media_pad pad;
- /* Protects is_streaming, and the vdev and vb2_q operations */
+ /* Protects the vdev and vb2_q operations */
struct mutex lock;
- bool is_streaming;
struct v4l2_pix_format_mplane pix;
const struct mxc_isi_format_info *fmtinfo;
@@ -343,6 +342,8 @@ int mxc_isi_video_buffer_prepare(struct mxc_isi_dev *isi, struct vb2_buffer *vb2
#ifdef CONFIG_VIDEO_IMX8_ISI_M2M
int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev);
int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi);
+void mxc_isi_m2m_suspend(struct mxc_isi_m2m *m2m);
+int mxc_isi_m2m_resume(struct mxc_isi_m2m *m2m);
#else
static inline int mxc_isi_m2m_register(struct mxc_isi_dev *isi,
struct v4l2_device *v4l2_dev)
@@ -353,6 +354,13 @@ static inline int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi)
{
return 0;
}
+static inline void mxc_isi_m2m_suspend(struct mxc_isi_m2m *m2m)
+{
+}
+static inline int mxc_isi_m2m_resume(struct mxc_isi_m2m *m2m)
+{
+ return 0;
+}
#endif
int mxc_isi_channel_acquire(struct mxc_isi_pipe *pipe,
@@ -362,7 +370,7 @@ void mxc_isi_channel_get(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_put(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_enable(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_disable(struct mxc_isi_pipe *pipe);
-int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe, bool bypass);
+int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_unchain(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_config(struct mxc_isi_pipe *pipe,
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c
index 5623914f95e6..9225a7ac1c3e 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c
@@ -587,7 +587,7 @@ void mxc_isi_channel_release(struct mxc_isi_pipe *pipe)
*
* TODO: Support secondary line buffer for downscaling YUV420 images.
*/
-int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe, bool bypass)
+int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe)
{
/* Channel chaining requires both line and output buffer. */
const u8 resources = MXC_ISI_CHANNEL_RES_OUTPUT_BUF
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
index 22e49d3a1287..00afcbfbdde4 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
@@ -43,7 +43,6 @@ struct mxc_isi_m2m_ctx_queue_data {
struct v4l2_pix_format_mplane format;
const struct mxc_isi_format_info *info;
u32 sequence;
- bool streaming;
};
struct mxc_isi_m2m_ctx {
@@ -74,9 +73,9 @@ to_isi_m2m_buffer(struct vb2_v4l2_buffer *buf)
return container_of(buf, struct mxc_isi_m2m_buffer, buf.vb);
}
-static inline struct mxc_isi_m2m_ctx *to_isi_m2m_ctx(struct v4l2_fh *fh)
+static inline struct mxc_isi_m2m_ctx *file_to_isi_m2m_ctx(struct file *filp)
{
- return container_of(fh, struct mxc_isi_m2m_ctx, fh);
+ return container_of(file_to_v4l2_fh(filp), struct mxc_isi_m2m_ctx, fh);
}
static inline struct mxc_isi_m2m_ctx_queue_data *
@@ -236,6 +235,70 @@ static void mxc_isi_m2m_vb2_buffer_queue(struct vb2_buffer *vb2)
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
}
+static int mxc_isi_m2m_vb2_prepare_streaming(struct vb2_queue *q)
+{
+ struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
+ const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format;
+ const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format;
+ const struct mxc_isi_format_info *cap_info = ctx->queues.cap.info;
+ const struct mxc_isi_format_info *out_info = ctx->queues.out.info;
+ struct mxc_isi_m2m *m2m = ctx->m2m;
+ int ret;
+
+ guard(mutex)(&m2m->lock);
+
+ if (m2m->usage_count == INT_MAX)
+ return -EOVERFLOW;
+
+ ret = pm_runtime_resume_and_get(m2m->isi->dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Acquire the pipe and initialize the channel with the first user of
+ * the M2M device.
+ */
+ if (m2m->usage_count == 0) {
+ bool bypass = cap_pix->width == out_pix->width &&
+ cap_pix->height == out_pix->height &&
+ cap_info->encoding == out_info->encoding;
+
+ ret = mxc_isi_channel_acquire(m2m->pipe,
+ &mxc_isi_m2m_frame_write_done,
+ bypass);
+ if (ret)
+ goto err_pm;
+
+ mxc_isi_channel_get(m2m->pipe);
+ }
+
+ m2m->usage_count++;
+
+ /*
+ * Allocate resources for the channel, counting how many users require
+ * buffer chaining.
+ */
+ if (!ctx->chained && out_pix->width > MXC_ISI_MAX_WIDTH_UNCHAINED) {
+ ret = mxc_isi_channel_chain(m2m->pipe);
+ if (ret)
+ goto err_deinit;
+
+ m2m->chained_count++;
+ ctx->chained = true;
+ }
+
+ return 0;
+
+err_deinit:
+ if (--m2m->usage_count == 0) {
+ mxc_isi_channel_put(m2m->pipe);
+ mxc_isi_channel_release(m2m->pipe);
+ }
+err_pm:
+ pm_runtime_put(m2m->isi->dev);
+ return ret;
+}
+
static int mxc_isi_m2m_vb2_start_streaming(struct vb2_queue *q,
unsigned int count)
{
@@ -265,13 +328,46 @@ static void mxc_isi_m2m_vb2_stop_streaming(struct vb2_queue *q)
}
}
+static void mxc_isi_m2m_vb2_unprepare_streaming(struct vb2_queue *q)
+{
+ struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
+ struct mxc_isi_m2m *m2m = ctx->m2m;
+
+ guard(mutex)(&m2m->lock);
+
+ /*
+ * If the last context is this one, reset it to make sure the device
+ * will be reconfigured when streaming is restarted.
+ */
+ if (m2m->last_ctx == ctx)
+ m2m->last_ctx = NULL;
+
+ /* Free the channel resources if this is the last chained context. */
+ if (ctx->chained && --m2m->chained_count == 0)
+ mxc_isi_channel_unchain(m2m->pipe);
+ ctx->chained = false;
+
+ /* Turn off the light with the last user. */
+ if (--m2m->usage_count == 0) {
+ mxc_isi_channel_disable(m2m->pipe);
+ mxc_isi_channel_put(m2m->pipe);
+ mxc_isi_channel_release(m2m->pipe);
+ }
+
+ WARN_ON(m2m->usage_count < 0);
+
+ pm_runtime_put(m2m->isi->dev);
+}
+
static const struct vb2_ops mxc_isi_m2m_vb2_qops = {
.queue_setup = mxc_isi_m2m_vb2_queue_setup,
.buf_init = mxc_isi_m2m_vb2_buffer_init,
.buf_prepare = mxc_isi_m2m_vb2_buffer_prepare,
.buf_queue = mxc_isi_m2m_vb2_buffer_queue,
+ .prepare_streaming = mxc_isi_m2m_vb2_prepare_streaming,
.start_streaming = mxc_isi_m2m_vb2_start_streaming,
.stop_streaming = mxc_isi_m2m_vb2_stop_streaming,
+ .unprepare_streaming = mxc_isi_m2m_vb2_unprepare_streaming,
};
static int mxc_isi_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
@@ -427,7 +523,7 @@ static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh,
const enum mxc_isi_video_type type =
f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP;
- struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
+ struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file);
__mxc_isi_m2m_try_fmt_vid(ctx, &f->fmt.pix_mp, type);
@@ -437,7 +533,7 @@ static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh,
static int mxc_isi_m2m_g_fmt_vid(struct file *file, void *fh,
struct v4l2_format *f)
{
- struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
+ struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file);
const struct mxc_isi_m2m_ctx_queue_data *qdata =
mxc_isi_m2m_ctx_qdata(ctx, f->type);
@@ -452,7 +548,7 @@ static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh,
const enum mxc_isi_video_type type =
f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP;
- struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
+ struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file);
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
const struct mxc_isi_format_info *info;
struct vb2_queue *vq;
@@ -481,136 +577,6 @@ static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh,
return 0;
}
-static int mxc_isi_m2m_streamon(struct file *file, void *fh,
- enum v4l2_buf_type type)
-{
- struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
- struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type);
- const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format;
- const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format;
- const struct mxc_isi_format_info *cap_info = ctx->queues.cap.info;
- const struct mxc_isi_format_info *out_info = ctx->queues.out.info;
- struct mxc_isi_m2m *m2m = ctx->m2m;
- bool bypass;
- int ret;
-
- if (q->streaming)
- return 0;
-
- mutex_lock(&m2m->lock);
-
- if (m2m->usage_count == INT_MAX) {
- ret = -EOVERFLOW;
- goto unlock;
- }
-
- bypass = cap_pix->width == out_pix->width &&
- cap_pix->height == out_pix->height &&
- cap_info->encoding == out_info->encoding;
-
- /*
- * Acquire the pipe and initialize the channel with the first user of
- * the M2M device.
- */
- if (m2m->usage_count == 0) {
- ret = mxc_isi_channel_acquire(m2m->pipe,
- &mxc_isi_m2m_frame_write_done,
- bypass);
- if (ret)
- goto unlock;
-
- mxc_isi_channel_get(m2m->pipe);
- }
-
- m2m->usage_count++;
-
- /*
- * Allocate resources for the channel, counting how many users require
- * buffer chaining.
- */
- if (!ctx->chained && out_pix->width > MXC_ISI_MAX_WIDTH_UNCHAINED) {
- ret = mxc_isi_channel_chain(m2m->pipe, bypass);
- if (ret)
- goto deinit;
-
- m2m->chained_count++;
- ctx->chained = true;
- }
-
- /*
- * Drop the lock to start the stream, as the .device_run() operation
- * needs to acquire it.
- */
- mutex_unlock(&m2m->lock);
- ret = v4l2_m2m_ioctl_streamon(file, fh, type);
- if (ret) {
- /* Reacquire the lock for the cleanup path. */
- mutex_lock(&m2m->lock);
- goto unchain;
- }
-
- q->streaming = true;
-
- return 0;
-
-unchain:
- if (ctx->chained && --m2m->chained_count == 0)
- mxc_isi_channel_unchain(m2m->pipe);
- ctx->chained = false;
-
-deinit:
- if (--m2m->usage_count == 0) {
- mxc_isi_channel_put(m2m->pipe);
- mxc_isi_channel_release(m2m->pipe);
- }
-
-unlock:
- mutex_unlock(&m2m->lock);
- return ret;
-}
-
-static int mxc_isi_m2m_streamoff(struct file *file, void *fh,
- enum v4l2_buf_type type)
-{
- struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
- struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type);
- struct mxc_isi_m2m *m2m = ctx->m2m;
-
- v4l2_m2m_ioctl_streamoff(file, fh, type);
-
- if (!q->streaming)
- return 0;
-
- mutex_lock(&m2m->lock);
-
- /*
- * If the last context is this one, reset it to make sure the device
- * will be reconfigured when streaming is restarted.
- */
- if (m2m->last_ctx == ctx)
- m2m->last_ctx = NULL;
-
- /* Free the channel resources if this is the last chained context. */
- if (ctx->chained && --m2m->chained_count == 0)
- mxc_isi_channel_unchain(m2m->pipe);
- ctx->chained = false;
-
- /* Turn off the light with the last user. */
- if (--m2m->usage_count == 0) {
- mxc_isi_channel_disable(m2m->pipe);
- mxc_isi_channel_put(m2m->pipe);
- mxc_isi_channel_release(m2m->pipe);
- }
-
- WARN_ON(m2m->usage_count < 0);
-
- mutex_unlock(&m2m->lock);
-
- q->streaming = false;
-
- return 0;
-}
-
static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops = {
.vidioc_querycap = mxc_isi_m2m_querycap,
@@ -631,8 +597,8 @@ static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops = {
.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
- .vidioc_streamon = mxc_isi_m2m_streamon,
- .vidioc_streamoff = mxc_isi_m2m_streamoff,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
@@ -668,7 +634,6 @@ static int mxc_isi_m2m_open(struct file *file)
mutex_init(&ctx->vb2_lock);
v4l2_fh_init(&ctx->fh, vdev);
- file->private_data = &ctx->fh;
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(m2m->m2m_dev, ctx,
&mxc_isi_m2m_queue_init);
@@ -685,16 +650,10 @@ static int mxc_isi_m2m_open(struct file *file)
if (ret)
goto err_ctx;
- ret = pm_runtime_resume_and_get(m2m->isi->dev);
- if (ret)
- goto err_ctrls;
-
- v4l2_fh_add(&ctx->fh);
+ v4l2_fh_add(&ctx->fh, file);
return 0;
-err_ctrls:
- mxc_isi_m2m_ctx_ctrls_delete(ctx);
err_ctx:
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
err_fh:
@@ -706,20 +665,17 @@ err_fh:
static int mxc_isi_m2m_release(struct file *file)
{
- struct mxc_isi_m2m *m2m = video_drvdata(file);
- struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(file->private_data);
+ struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
mxc_isi_m2m_ctx_ctrls_delete(ctx);
- v4l2_fh_del(&ctx->fh);
+ v4l2_fh_del(&ctx->fh, file);
v4l2_fh_exit(&ctx->fh);
mutex_destroy(&ctx->vb2_lock);
kfree(ctx);
- pm_runtime_put(m2m->isi->dev);
-
return 0;
}
@@ -733,6 +689,40 @@ static const struct v4l2_file_operations mxc_isi_m2m_fops = {
};
/* -----------------------------------------------------------------------------
+ * Suspend & resume
+ */
+
+void mxc_isi_m2m_suspend(struct mxc_isi_m2m *m2m)
+{
+ if (m2m->usage_count == 0)
+ return;
+
+ v4l2_m2m_suspend(m2m->m2m_dev);
+
+ if (m2m->chained_count > 0)
+ mxc_isi_channel_unchain(m2m->pipe);
+
+ mxc_isi_channel_disable(m2m->pipe);
+ mxc_isi_channel_put(m2m->pipe);
+}
+
+int mxc_isi_m2m_resume(struct mxc_isi_m2m *m2m)
+{
+ if (m2m->usage_count == 0)
+ return 0;
+
+ mxc_isi_channel_get(m2m->pipe);
+
+ if (m2m->chained_count > 0)
+ mxc_isi_channel_chain(m2m->pipe);
+
+ m2m->last_ctx = NULL;
+ v4l2_m2m_resume(m2m->m2m_dev);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
* Registration
*/
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
index d76eb58deb09..a41c51dd9ce0 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
@@ -855,7 +855,7 @@ int mxc_isi_pipe_acquire(struct mxc_isi_pipe *pipe,
/* Chain the channel if needed for wide resolutions. */
if (sink_fmt->width > MXC_ISI_MAX_WIDTH_UNCHAINED) {
- ret = mxc_isi_channel_chain(pipe, bypass);
+ ret = mxc_isi_channel_chain(pipe);
if (ret)
mxc_isi_channel_release(pipe);
}
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
index 8654150728a8..13682bf6e9f8 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
@@ -937,6 +937,47 @@ static void mxc_isi_video_init_channel(struct mxc_isi_video *video)
mxc_isi_channel_set_output_format(pipe, video->fmtinfo, &video->pix);
}
+static int mxc_isi_vb2_prepare_streaming(struct vb2_queue *q)
+{
+ struct mxc_isi_video *video = vb2_get_drv_priv(q);
+ struct media_device *mdev = &video->pipe->isi->media_dev;
+ struct media_pipeline *pipe;
+ int ret;
+
+ /* Get a pipeline for the video node and start it. */
+ scoped_guard(mutex, &mdev->graph_mutex) {
+ ret = mxc_isi_pipe_acquire(video->pipe,
+ &mxc_isi_video_frame_write_done);
+ if (ret)
+ return ret;
+
+ pipe = media_entity_pipeline(&video->vdev.entity)
+ ? : &video->pipe->pipe;
+
+ ret = __video_device_pipeline_start(&video->vdev, pipe);
+ if (ret)
+ goto err_release;
+ }
+
+ /* Verify that the video format matches the output of the subdev. */
+ ret = mxc_isi_video_validate_format(video);
+ if (ret)
+ goto err_stop;
+
+ /* Allocate buffers for discard operation. */
+ ret = mxc_isi_video_alloc_discard_buffers(video);
+ if (ret)
+ goto err_stop;
+
+ return 0;
+
+err_stop:
+ video_device_pipeline_stop(&video->vdev);
+err_release:
+ mxc_isi_pipe_release(video->pipe);
+ return ret;
+}
+
static int mxc_isi_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct mxc_isi_video *video = vb2_get_drv_priv(q);
@@ -985,13 +1026,24 @@ static void mxc_isi_vb2_stop_streaming(struct vb2_queue *q)
mxc_isi_video_return_buffers(video, VB2_BUF_STATE_ERROR);
}
+static void mxc_isi_vb2_unprepare_streaming(struct vb2_queue *q)
+{
+ struct mxc_isi_video *video = vb2_get_drv_priv(q);
+
+ mxc_isi_video_free_discard_buffers(video);
+ video_device_pipeline_stop(&video->vdev);
+ mxc_isi_pipe_release(video->pipe);
+}
+
static const struct vb2_ops mxc_isi_vb2_qops = {
.queue_setup = mxc_isi_vb2_queue_setup,
.buf_init = mxc_isi_vb2_buffer_init,
.buf_prepare = mxc_isi_vb2_buffer_prepare,
.buf_queue = mxc_isi_vb2_buffer_queue,
+ .prepare_streaming = mxc_isi_vb2_prepare_streaming,
.start_streaming = mxc_isi_vb2_start_streaming,
.stop_streaming = mxc_isi_vb2_stop_streaming,
+ .unprepare_streaming = mxc_isi_vb2_unprepare_streaming,
};
/* -----------------------------------------------------------------------------
@@ -1145,97 +1197,6 @@ static int mxc_isi_video_s_fmt(struct file *file, void *priv,
return 0;
}
-static int mxc_isi_video_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct mxc_isi_video *video = video_drvdata(file);
- struct media_device *mdev = &video->pipe->isi->media_dev;
- struct media_pipeline *pipe;
- int ret;
-
- if (vb2_queue_is_busy(&video->vb2_q, file))
- return -EBUSY;
-
- /*
- * Get a pipeline for the video node and start it. This must be done
- * here and not in the queue .start_streaming() handler, so that
- * pipeline start errors can be reported from VIDIOC_STREAMON and not
- * delayed until subsequent VIDIOC_QBUF calls.
- */
- mutex_lock(&mdev->graph_mutex);
-
- ret = mxc_isi_pipe_acquire(video->pipe, &mxc_isi_video_frame_write_done);
- if (ret) {
- mutex_unlock(&mdev->graph_mutex);
- return ret;
- }
-
- pipe = media_entity_pipeline(&video->vdev.entity) ? : &video->pipe->pipe;
-
- ret = __video_device_pipeline_start(&video->vdev, pipe);
- if (ret) {
- mutex_unlock(&mdev->graph_mutex);
- goto err_release;
- }
-
- mutex_unlock(&mdev->graph_mutex);
-
- /* Verify that the video format matches the output of the subdev. */
- ret = mxc_isi_video_validate_format(video);
- if (ret)
- goto err_stop;
-
- /* Allocate buffers for discard operation. */
- ret = mxc_isi_video_alloc_discard_buffers(video);
- if (ret)
- goto err_stop;
-
- ret = vb2_streamon(&video->vb2_q, type);
- if (ret)
- goto err_free;
-
- video->is_streaming = true;
-
- return 0;
-
-err_free:
- mxc_isi_video_free_discard_buffers(video);
-err_stop:
- video_device_pipeline_stop(&video->vdev);
-err_release:
- mxc_isi_pipe_release(video->pipe);
- return ret;
-}
-
-static void mxc_isi_video_cleanup_streaming(struct mxc_isi_video *video)
-{
- lockdep_assert_held(&video->lock);
-
- if (!video->is_streaming)
- return;
-
- mxc_isi_video_free_discard_buffers(video);
- video_device_pipeline_stop(&video->vdev);
- mxc_isi_pipe_release(video->pipe);
-
- video->is_streaming = false;
-}
-
-static int mxc_isi_video_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct mxc_isi_video *video = video_drvdata(file);
- int ret;
-
- ret = vb2_ioctl_streamoff(file, priv, type);
- if (ret)
- return ret;
-
- mxc_isi_video_cleanup_streaming(video);
-
- return 0;
-}
-
static int mxc_isi_video_enum_framesizes(struct file *file, void *priv,
struct v4l2_frmsizeenum *fsize)
{
@@ -1291,9 +1252,8 @@ static const struct v4l2_ioctl_ops mxc_isi_video_ioctl_ops = {
.vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
-
- .vidioc_streamon = mxc_isi_video_streamon,
- .vidioc_streamoff = mxc_isi_video_streamoff,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_enum_framesizes = mxc_isi_video_enum_framesizes,
@@ -1332,10 +1292,6 @@ static int mxc_isi_video_release(struct file *file)
if (ret)
dev_err(video->pipe->isi->dev, "%s fail\n", __func__);
- mutex_lock(&video->lock);
- mxc_isi_video_cleanup_streaming(video);
- mutex_unlock(&video->lock);
-
pm_runtime_put(video->pipe->isi->dev);
return ret;
}
@@ -1357,7 +1313,7 @@ void mxc_isi_video_suspend(struct mxc_isi_pipe *pipe)
{
struct mxc_isi_video *video = &pipe->video;
- if (!video->is_streaming)
+ if (!vb2_is_streaming(&video->vb2_q))
return;
mxc_isi_pipe_disable(pipe);
@@ -1388,7 +1344,7 @@ int mxc_isi_video_resume(struct mxc_isi_pipe *pipe)
{
struct mxc_isi_video *video = &pipe->video;
- if (!video->is_streaming)
+ if (!vb2_is_streaming(&video->vb2_q))
return 0;
mxc_isi_video_init_channel(video);
diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c
index 0c6cc120fd2a..3aae8c0b690c 100644
--- a/drivers/media/platform/nxp/mx2_emmaprp.c
+++ b/drivers/media/platform/nxp/mx2_emmaprp.c
@@ -214,6 +214,11 @@ struct emmaprp_ctx {
struct emmaprp_q_data q_data[2];
};
+static inline struct emmaprp_ctx *file_to_emmaprp_ctx(struct file *filp)
+{
+ return container_of(file_to_v4l2_fh(filp), struct emmaprp_ctx, fh);
+}
+
static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx,
enum v4l2_buf_type type)
{
@@ -451,13 +456,13 @@ static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
- return vidioc_g_fmt(priv, f);
+ return vidioc_g_fmt(file_to_emmaprp_ctx(file), f);
}
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- return vidioc_g_fmt(priv, f);
+ return vidioc_g_fmt(file_to_emmaprp_ctx(file), f);
}
static int vidioc_try_fmt(struct v4l2_format *f)
@@ -497,8 +502,8 @@ static int vidioc_try_fmt(struct v4l2_format *f)
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
+ struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file);
struct emmaprp_fmt *fmt;
- struct emmaprp_ctx *ctx = priv;
fmt = find_format(f);
if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
@@ -514,8 +519,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
+ struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file);
struct emmaprp_fmt *fmt;
- struct emmaprp_ctx *ctx = priv;
fmt = find_format(f);
if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
@@ -575,7 +580,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
if (ret)
return ret;
- return vidioc_s_fmt(priv, f);
+ return vidioc_s_fmt(file_to_emmaprp_ctx(file), f);
}
static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
@@ -587,7 +592,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
if (ret)
return ret;
- return vidioc_s_fmt(priv, f);
+ return vidioc_s_fmt(file_to_emmaprp_ctx(file), f);
}
static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
@@ -725,7 +730,6 @@ static int emmaprp_open(struct file *file)
return -ENOMEM;
v4l2_fh_init(&ctx->fh, video_devdata(file));
- file->private_data = &ctx->fh;
ctx->dev = pcdev;
if (mutex_lock_interruptible(&pcdev->dev_mutex)) {
@@ -747,7 +751,7 @@ static int emmaprp_open(struct file *file)
clk_prepare_enable(pcdev->clk_emma_ahb);
ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
- v4l2_fh_add(&ctx->fh);
+ v4l2_fh_add(&ctx->fh, file);
mutex_unlock(&pcdev->dev_mutex);
dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx);
@@ -758,14 +762,14 @@ static int emmaprp_open(struct file *file)
static int emmaprp_release(struct file *file)
{
struct emmaprp_dev *pcdev = video_drvdata(file);
- struct emmaprp_ctx *ctx = file->private_data;
+ struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file);
dprintk(pcdev, "Releasing instance %p\n", ctx);
mutex_lock(&pcdev->dev_mutex);
clk_disable_unprepare(pcdev->clk_emma_ahb);
clk_disable_unprepare(pcdev->clk_emma_ipg);
- v4l2_fh_del(&ctx->fh);
+ v4l2_fh_del(&ctx->fh, file);
v4l2_fh_exit(&ctx->fh);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
mutex_unlock(&pcdev->dev_mutex);