summaryrefslogtreecommitdiff
path: root/drivers/media/platform
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@kernel.org>2022-03-07 16:24:56 +0100
committerMauro Carvalho Chehab <mchehab@kernel.org>2022-03-07 16:25:17 +0100
commit8268d067508b0fb9988b5423a8539a21caba5f44 (patch)
tree8f4f14c72770488b070d2b62ed37d01d07c36c4c /drivers/media/platform
parent8bd4aaf438e39f88e4321e0cad2d42284c2269af (diff)
parentd8ebe298d008ccbae3011cbeb139707f01a730c8 (diff)
Merge tag 'br-v5.18l' of git://linuxtv.org/hverkuil/media_tree into media_stage
Tag branch * tag 'br-v5.18l' of git://linuxtv.org/hverkuil/media_tree: (39 commits) media: imx-jpeg: Set V4L2_BUF_FLAG_LAST at eos media: meson-ir-tx: remove incorrect doc comment media: vivid: use time_is_after_jiffies() instead of open coding it media: wl128x: use time_is_before_jiffies() instead of open coding it media: tda8083: use time_is_after_jiffies() instead of open coding it media: stv0299: use time_is_before_jiffies() instead of open coding it media: si21xx: use time_is_before_jiffies() instead of open coding it media: cedrus: h264: Fix neighbour info buffer size media: cx88-mpeg: clear interrupt status register before streaming video media: cedrus: H265: Fix neighbour info buffer size media: fsl-viu: use GFP_KERNEL media: cx18: use GFP_KERNEL drivers: meson: vdec: add VP9 support to GXM stkwebcam: add new Asus laptop to upside_down table media: imx-jpeg: fix a bug of accessing array out of bounds media: sun6i-csi: fix colorspace in sun6i_video_try_fmt() media: usb: go7007: s2250-board: fix leak in probe() media: cedrus: Add watchdog for job completion pixfmt-yuv-planar.rst: fix typo: 'Cr, Cr' -> 'Cr, Cb' media: imx-jpeg: Remove unnecessary print function dev_err() ... Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/aspeed-video.c86
-rw-r--r--drivers/media/platform/fsl-viu.c2
-rw-r--r--drivers/media/platform/imx-jpeg/mxc-jpeg.c43
-rw-r--r--drivers/media/platform/imx-jpeg/mxc-jpeg.h1
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c27
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c2
-rw-r--r--drivers/media/platform/rcar-vin/rcar-core.c387
-rw-r--r--drivers/media/platform/rcar-vin/rcar-csi2.c57
-rw-r--r--drivers/media/platform/rcar-vin/rcar-dma.c2
-rw-r--r--drivers/media/platform/rcar-vin/rcar-vin.h18
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c6
12 files changed, 305 insertions, 328 deletions
diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
index 51fb18453b81..b937dbcbe9e0 100644
--- a/drivers/media/platform/aspeed-video.c
+++ b/drivers/media/platform/aspeed-video.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
@@ -32,7 +33,8 @@
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-dma-contig.h>
-#include <linux/videodev2.h>
+
+#define ASPEED_VIDEO_V4L2_MIN_BUF_REQ 3
#define DEVICE_NAME "aspeed-video"
@@ -86,8 +88,6 @@
#define VE_CTRL_SOURCE BIT(2)
#define VE_CTRL_INT_DE BIT(4)
#define VE_CTRL_DIRECT_FETCH BIT(5)
-#define VE_CTRL_YUV BIT(6)
-#define VE_CTRL_RGB BIT(7)
#define VE_CTRL_CAPTURE_FMT GENMASK(7, 6)
#define VE_CTRL_AUTO_OR_CURSOR BIT(8)
#define VE_CTRL_CLK_INVERSE BIT(11)
@@ -153,9 +153,14 @@
#define VE_MODE_DETECT_STATUS 0x098
#define VE_MODE_DETECT_H_PERIOD GENMASK(11, 0)
+#define VE_MODE_DETECT_EXTSRC_ADC BIT(12)
+#define VE_MODE_DETECT_H_STABLE BIT(13)
+#define VE_MODE_DETECT_V_STABLE BIT(14)
#define VE_MODE_DETECT_V_LINES GENMASK(27, 16)
#define VE_MODE_DETECT_STATUS_VSYNC BIT(28)
#define VE_MODE_DETECT_STATUS_HSYNC BIT(29)
+#define VE_MODE_DETECT_VSYNC_RDY BIT(30)
+#define VE_MODE_DETECT_HSYNC_RDY BIT(31)
#define VE_SYNC_STATUS 0x09c
#define VE_SYNC_STATUS_HSYNC GENMASK(11, 0)
@@ -178,9 +183,24 @@
#define VE_INTERRUPT_VSYNC_DESC BIT(11)
#define VE_MODE_DETECT 0x30c
+#define VE_MODE_DT_HOR_TOLER GENMASK(31, 28)
+#define VE_MODE_DT_VER_TOLER GENMASK(27, 24)
+#define VE_MODE_DT_HOR_STABLE GENMASK(23, 20)
+#define VE_MODE_DT_VER_STABLE GENMASK(19, 16)
+#define VE_MODE_DT_EDG_THROD GENMASK(15, 8)
+
#define VE_MEM_RESTRICT_START 0x310
#define VE_MEM_RESTRICT_END 0x314
+/*
+ * VIDEO_MODE_DETECT_DONE: a flag raised if signal lock
+ * VIDEO_RES_CHANGE: a flag raised if res_change work on-going
+ * VIDEO_RES_DETECT: a flag raised if res. detection on-going
+ * VIDEO_STREAMING: a flag raised if user requires stream-on
+ * VIDEO_FRAME_INPRG: a flag raised if hw working on a frame
+ * VIDEO_STOPPED: a flag raised if device release
+ * VIDEO_CLOCKS_ON: a flag raised if clk is on
+ */
enum {
VIDEO_MODE_DETECT_DONE,
VIDEO_RES_CHANGE,
@@ -191,6 +211,15 @@ enum {
VIDEO_CLOCKS_ON,
};
+// for VE_CTRL_CAPTURE_FMT
+enum aspeed_video_capture_format {
+ VIDEO_CAP_FMT_YUV_STUDIO_SWING = 0,
+ VIDEO_CAP_FMT_YUV_FULL_SWING,
+ VIDEO_CAP_FMT_RGB,
+ VIDEO_CAP_FMT_GRAY,
+ VIDEO_CAP_FMT_MAX
+};
+
struct aspeed_video_addr {
unsigned int size;
dma_addr_t dma;
@@ -213,6 +242,25 @@ struct aspeed_video_perf {
#define to_aspeed_video_buffer(x) \
container_of((x), struct aspeed_video_buffer, vb)
+/*
+ * struct aspeed_video - driver data
+ *
+ * res_work: holds the delayed_work for res-detection if unlock
+ * buffers: holds the list of buffer queued from user
+ * flags: holds the state of video
+ * sequence: holds the last number of frame completed
+ * max_compressed_size: holds max compressed stream's size
+ * srcs: holds the buffer information for srcs
+ * jpeg: holds the buffer information for jpeg header
+ * yuv420: a flag raised if JPEG subsampling is 420
+ * frame_rate: holds the frame_rate
+ * jpeg_quality: holds jpeq's quality (0~11)
+ * frame_bottom: end position of video data in vertical direction
+ * frame_left: start position of video data in horizontal direction
+ * frame_right: end position of video data in horizontal direction
+ * frame_top: start position of video data in vertical direction
+ * perf: holds the statistics primary for debugfs
+ */
struct aspeed_video {
void __iomem *base;
struct clk *eclk;
@@ -903,6 +951,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
bool invalid_resolution = true;
int rc;
int tries = 0;
+ u32 mds;
u32 src_lr_edge;
u32 src_tb_edge;
struct v4l2_bt_timings *det = &video->detected_timings;
@@ -933,6 +982,13 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
return;
}
+ mds = aspeed_video_read(video, VE_MODE_DETECT_STATUS);
+ // try detection again if current signal isn't stable
+ if (!(mds & VE_MODE_DETECT_H_STABLE) ||
+ !(mds & VE_MODE_DETECT_V_STABLE) ||
+ (mds & VE_MODE_DETECT_EXTSRC_ADC))
+ continue;
+
aspeed_video_check_and_set_polarity(video);
aspeed_video_enable_mode_detect(video);
@@ -1070,7 +1126,8 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
u32 comp_ctrl = VE_COMP_CTRL_RSVD |
FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
- u32 ctrl = VE_CTRL_AUTO_OR_CURSOR;
+ u32 ctrl = VE_CTRL_AUTO_OR_CURSOR |
+ FIELD_PREP(VE_CTRL_CAPTURE_FMT, VIDEO_CAP_FMT_YUV_FULL_SWING);
u32 seq_ctrl = video->jpeg_mode;
if (video->frame_rate)
@@ -1105,7 +1162,12 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
aspeed_video_write(video, VE_SCALING_FILTER3, 0x00200000);
/* Set mode detection defaults */
- aspeed_video_write(video, VE_MODE_DETECT, 0x22666500);
+ aspeed_video_write(video, VE_MODE_DETECT,
+ FIELD_PREP(VE_MODE_DT_HOR_TOLER, 2) |
+ FIELD_PREP(VE_MODE_DT_VER_TOLER, 2) |
+ FIELD_PREP(VE_MODE_DT_HOR_STABLE, 6) |
+ FIELD_PREP(VE_MODE_DT_VER_STABLE, 6) |
+ FIELD_PREP(VE_MODE_DT_EDG_THROD, 0x65));
}
static void aspeed_video_start(struct aspeed_video *video)
@@ -1212,7 +1274,7 @@ static int aspeed_video_get_parm(struct file *file, void *fh,
struct aspeed_video *video = video_drvdata(file);
a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- a->parm.capture.readbuffers = 3;
+ a->parm.capture.readbuffers = ASPEED_VIDEO_V4L2_MIN_BUF_REQ;
a->parm.capture.timeperframe.numerator = 1;
if (!video->frame_rate)
a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE;
@@ -1229,7 +1291,7 @@ static int aspeed_video_set_parm(struct file *file, void *fh,
struct aspeed_video *video = video_drvdata(file);
a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- a->parm.capture.readbuffers = 3;
+ a->parm.capture.readbuffers = ASPEED_VIDEO_V4L2_MIN_BUF_REQ;
if (a->parm.capture.timeperframe.numerator)
frame_rate = a->parm.capture.timeperframe.denominator /
@@ -1781,7 +1843,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
vbq->drv_priv = video;
vbq->buf_struct_size = sizeof(struct aspeed_video_buffer);
vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vbq->min_buffers_needed = 3;
+ vbq->min_buffers_needed = ASPEED_VIDEO_V4L2_MIN_BUF_REQ;
rc = vb2_queue_init(vbq);
if (rc) {
@@ -1899,7 +1961,6 @@ MODULE_DEVICE_TABLE(of, aspeed_video_of_match);
static int aspeed_video_probe(struct platform_device *pdev)
{
const struct aspeed_video_config *config;
- const struct of_device_id *match;
struct aspeed_video *video;
int rc;
@@ -1911,11 +1972,10 @@ static int aspeed_video_probe(struct platform_device *pdev)
if (IS_ERR(video->base))
return PTR_ERR(video->base);
- match = of_match_node(aspeed_video_of_match, pdev->dev.of_node);
- if (!match)
- return -EINVAL;
+ config = of_device_get_match_data(&pdev->dev);
+ if (!config)
+ return -ENODEV;
- config = match->data;
video->jpeg_mode = config->jpeg_mode;
video->comp_size_read = config->comp_size_read;
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index a4bfa70b49b2..afc96f6db2a1 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -1407,7 +1407,7 @@ static int viu_of_probe(struct platform_device *op)
}
/* Prepare our private structure */
- viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC);
+ viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_KERNEL);
if (!viu_dev) {
dev_err(&op->dev, "Can't allocate private structure\n");
ret = -ENOMEM;
diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c
index fed762491379..3b892c5792b4 100644
--- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c
@@ -954,7 +954,6 @@ static void mxc_jpeg_device_run(void *priv)
jpeg_src_buf->jpeg_parse_error = true;
}
if (jpeg_src_buf->jpeg_parse_error) {
- jpeg->slot_data[ctx->slot].used = false;
v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
@@ -998,6 +997,20 @@ end:
spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
}
+static void mxc_jpeg_set_last_buffer_dequeued(struct mxc_jpeg_ctx *ctx)
+{
+ struct vb2_queue *q;
+
+ ctx->stopped = 1;
+ q = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx);
+ if (!list_empty(&q->done_list))
+ return;
+
+ q->last_buffer_dequeued = true;
+ wake_up(&q->done_wq);
+ ctx->stopped = 0;
+}
+
static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
struct v4l2_decoder_cmd *cmd)
{
@@ -1015,6 +1028,7 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) {
/* No more src bufs, notify app EOS */
notify_eos(ctx);
+ mxc_jpeg_set_last_buffer_dequeued(ctx);
} else {
/* will send EOS later*/
ctx->stopping = 1;
@@ -1041,6 +1055,7 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv,
if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) {
/* No more src bufs, notify app EOS */
notify_eos(ctx);
+ mxc_jpeg_set_last_buffer_dequeued(ctx);
} else {
/* will send EOS later*/
ctx->stopping = 1;
@@ -1117,6 +1132,10 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q)
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
}
pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev);
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ ctx->stopping = 0;
+ ctx->stopped = 0;
+ }
}
static int mxc_jpeg_valid_comp_id(struct device *dev,
@@ -1408,12 +1427,29 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
return 0;
}
+static void mxc_jpeg_buf_finish(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_queue *q = vb->vb2_queue;
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->type))
+ return;
+ if (!ctx->stopped)
+ return;
+ if (list_empty(&q->done_list)) {
+ vbuf->flags |= V4L2_BUF_FLAG_LAST;
+ ctx->stopped = 0;
+ }
+}
+
static const struct vb2_ops mxc_jpeg_qops = {
.queue_setup = mxc_jpeg_queue_setup,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.buf_out_validate = mxc_jpeg_buf_out_validate,
.buf_prepare = mxc_jpeg_buf_prepare,
+ .buf_finish = mxc_jpeg_buf_finish,
.start_streaming = mxc_jpeg_start_streaming,
.stop_streaming = mxc_jpeg_stop_streaming,
.buf_queue = mxc_jpeg_buf_queue,
@@ -1849,14 +1885,14 @@ static int mxc_jpeg_dqbuf(struct file *file, void *priv,
int ret;
dev_dbg(dev, "DQBUF type=%d, index=%d", buf->type, buf->index);
- if (ctx->stopping == 1 && num_src_ready == 0) {
+ if (ctx->stopping == 1 && num_src_ready == 0) {
/* No more src bufs, notify app EOS */
notify_eos(ctx);
ctx->stopping = 0;
+ mxc_jpeg_set_last_buffer_dequeued(ctx);
}
ret = v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf);
-
return ret;
}
@@ -2022,7 +2058,6 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
for (slot = 0; slot < MXC_MAX_SLOTS; slot++) {
dec_irq = platform_get_irq(pdev, slot);
if (dec_irq < 0) {
- dev_err(&pdev->dev, "Failed to get irq %d\n", dec_irq);
ret = dec_irq;
goto err_irq;
}
diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/imx-jpeg/mxc-jpeg.h
index 9fb2a5aaa941..f53f004ba851 100644
--- a/drivers/media/platform/imx-jpeg/mxc-jpeg.h
+++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.h
@@ -91,6 +91,7 @@ struct mxc_jpeg_ctx {
struct v4l2_fh fh;
enum mxc_jpeg_enc_state enc_state;
unsigned int stopping;
+ unsigned int stopped;
unsigned int slot;
};
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
index d532f86e826e..ab5485dfc20c 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
@@ -680,7 +680,7 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
{
struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct mtk_jpeg_q_data *q_data = NULL;
- struct v4l2_plane_pix_format plane_fmt = {};
+ struct v4l2_plane_pix_format plane_fmt;
int i;
q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index 8d11510e441e..48dad9bb13d2 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -374,7 +374,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
if (IS_ERR((__force void *)dev->m2m_dev_dec)) {
mtk_v4l2_err("Failed to init mem2mem dec device");
ret = PTR_ERR((__force void *)dev->m2m_dev_dec);
- goto err_dec_mem_init;
+ goto err_dec_alloc;
}
dev->decode_workqueue =
@@ -391,10 +391,16 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
&pdev->dev);
if (ret) {
mtk_v4l2_err("Main device of_platform_populate failed.");
- goto err_event_workq;
+ goto err_reg_cont;
}
}
+ ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ mtk_v4l2_err("Failed to register video device");
+ goto err_reg_cont;
+ }
+
if (dev->vdec_pdata->uses_stateless_api) {
dev->mdev_dec.dev = &pdev->dev;
strscpy(dev->mdev_dec.model, MTK_VCODEC_DEC_NAME,
@@ -408,7 +414,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
MEDIA_ENT_F_PROC_VIDEO_DECODER);
if (ret) {
mtk_v4l2_err("Failed to register media controller");
- goto err_reg_cont;
+ goto err_dec_mem_init;
}
ret = media_device_register(&dev->mdev_dec);
@@ -419,30 +425,21 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
mtk_v4l2_debug(0, "media registered as /dev/media%d", vfd_dec->minor);
}
- ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, 0);
- if (ret) {
- mtk_v4l2_err("Failed to register video device");
- goto err_dec_reg;
- }
mtk_v4l2_debug(0, "decoder registered as /dev/video%d", vfd_dec->minor);
return 0;
-err_dec_reg:
- if (dev->vdec_pdata->uses_stateless_api)
- media_device_unregister(&dev->mdev_dec);
err_media_reg:
- if (dev->vdec_pdata->uses_stateless_api)
- v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec);
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec);
+err_dec_mem_init:
+ video_unregister_device(vfd_dec);
err_reg_cont:
if (dev->vdec_pdata->uses_stateless_api)
media_device_cleanup(&dev->mdev_dec);
destroy_workqueue(dev->decode_workqueue);
err_event_workq:
v4l2_m2m_release(dev->m2m_dev_dec);
-err_dec_mem_init:
- video_unregister_device(vfd_dec);
err_dec_alloc:
v4l2_device_unregister(&dev->v4l2_dev);
err_core_workq:
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
index 326ee151298c..5172cfe0db4a 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -349,7 +349,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
- ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, 1);
+ ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, -1);
if (ret) {
mtk_v4l2_err("Failed to register video device");
goto err_enc_reg;
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 0186ae235113..58b002693b7d 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -743,27 +743,6 @@ static int rvin_parallel_init(struct rvin_dev *vin)
* CSI-2
*/
-static unsigned int rvin_csi2_get_mask(struct rvin_dev *vin,
- enum rvin_csi_id csi_id,
- unsigned char channel)
-{
- const struct rvin_group_route *route;
- unsigned int mask = 0;
-
- for (route = vin->info->routes; route->mask; route++) {
- if (route->vin == vin->id &&
- route->csi == csi_id &&
- route->channel == channel) {
- vin_dbg(vin,
- "Adding route: vin: %d csi: %d channel: %d\n",
- route->vin, route->csi, route->channel);
- mask |= route->mask;
- }
- }
-
- return mask;
-}
-
/*
* Link setup for the links between a VIN and a CSI-2 receiver is a bit
* complex. The reason for this is that the register controlling routing
@@ -793,12 +772,10 @@ static int rvin_csi2_link_notify(struct media_link *link, u32 flags,
{
struct rvin_group *group = container_of(link->graph_obj.mdev,
struct rvin_group, mdev);
- unsigned int master_id, channel, mask_new, i;
- unsigned int mask = ~0;
struct media_entity *entity;
struct video_device *vdev;
- struct media_pad *csi_pad;
- struct rvin_dev *vin = NULL;
+ struct rvin_dev *vin;
+ unsigned int i;
int csi_id, ret;
ret = v4l2_pipeline_link_notify(link, flags, notification);
@@ -819,38 +796,13 @@ static int rvin_csi2_link_notify(struct media_link *link, u32 flags,
if (entity->stream_count)
return -EBUSY;
- mutex_lock(&group->lock);
-
/* Find the master VIN that controls the routes. */
vdev = media_entity_to_video_device(link->sink->entity);
vin = container_of(vdev, struct rvin_dev, vdev);
- master_id = rvin_group_id_to_master(vin->id);
- if (WARN_ON(!group->vin[master_id])) {
- ret = -ENODEV;
- goto out;
- }
-
- /* Build a mask for already enabled links. */
- for (i = master_id; i < master_id + 4; i++) {
- if (!group->vin[i])
- continue;
-
- /* Get remote CSI-2, if any. */
- csi_pad = media_entity_remote_pad(
- &group->vin[i]->vdev.entity.pads[0]);
- if (!csi_pad)
- continue;
-
- csi_id = rvin_group_entity_to_remote_id(group, csi_pad->entity);
- channel = rvin_group_csi_pad_to_channel(csi_pad->index);
-
- mask &= rvin_csi2_get_mask(group->vin[i], csi_id, channel);
- }
+ mutex_lock(&group->lock);
- /* Add the new link to the existing mask and check if it works. */
csi_id = rvin_group_entity_to_remote_id(group, link->source->entity);
-
if (csi_id == -ENODEV) {
struct v4l2_subdev *sd;
@@ -875,25 +827,58 @@ static int rvin_csi2_link_notify(struct media_link *link, u32 flags,
vin_err(vin, "Subdevice %s not registered to any VIN\n",
link->source->entity->name);
ret = -ENODEV;
- goto out;
- }
+ } else {
+ const struct rvin_group_route *route;
+ unsigned int chsel = UINT_MAX;
+ unsigned int master_id;
- channel = rvin_group_csi_pad_to_channel(link->source->index);
- mask_new = mask & rvin_csi2_get_mask(vin, csi_id, channel);
- vin_dbg(vin, "Try link change mask: 0x%x new: 0x%x\n", mask, mask_new);
+ master_id = rvin_group_id_to_master(vin->id);
- if (!mask_new) {
- ret = -EMLINK;
- goto out;
- }
+ if (WARN_ON(!group->vin[master_id])) {
+ ret = -ENODEV;
+ goto out;
+ }
- /* New valid CHSEL found, set the new value. */
- ret = rvin_set_channel_routing(group->vin[master_id], __ffs(mask_new));
- if (ret)
- goto out;
+ /* Make sure group is connected to same CSI-2 */
+ for (i = master_id; i < master_id + 4; i++) {
+ struct media_pad *csi_pad;
+
+ if (!group->vin[i])
+ continue;
+
+ /* Get remote CSI-2, if any. */
+ csi_pad = media_entity_remote_pad(
+ &group->vin[i]->vdev.entity.pads[0]);
+ if (!csi_pad)
+ continue;
+
+ if (csi_pad->entity != link->source->entity) {
+ vin_dbg(vin, "Already attached to %s\n",
+ csi_pad->entity->name);
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+
+ for (route = vin->info->routes; route->chsel; route++) {
+ if (route->master == master_id && route->csi == csi_id) {
+ chsel = route->chsel;
+ break;
+ }
+ }
- vin->is_csi = true;
+ if (chsel == UINT_MAX) {
+ vin_err(vin, "No CHSEL value found\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = rvin_set_channel_routing(group->vin[master_id], chsel);
+ if (ret)
+ goto out;
+ vin->is_csi = true;
+ }
out:
mutex_unlock(&group->lock);
@@ -904,48 +889,60 @@ static const struct media_device_ops rvin_csi2_media_ops = {
.link_notify = rvin_csi2_link_notify,
};
+static int rvin_csi2_create_link(struct rvin_group *group, unsigned int id,
+ const struct rvin_group_route *route)
+
+{
+ struct media_entity *source = &group->remotes[route->csi].subdev->entity;
+ struct media_entity *sink = &group->vin[id]->vdev.entity;
+ struct media_pad *sink_pad = &sink->pads[0];
+ unsigned int channel;
+ int ret;
+
+ for (channel = 0; channel < 4; channel++) {
+ unsigned int source_idx = rvin_group_csi_channel_to_pad(channel);
+ struct media_pad *source_pad = &source->pads[source_idx];
+
+ /* Skip if link already exists. */
+ if (media_entity_find_link(source_pad, sink_pad))
+ continue;
+
+ ret = media_create_pad_link(source, source_idx, sink, 0, 0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int rvin_csi2_setup_links(struct rvin_dev *vin)
{
const struct rvin_group_route *route;
+ unsigned int id;
int ret = -EINVAL;
/* Create all media device links between VINs and CSI-2's. */
mutex_lock(&vin->group->lock);
- for (route = vin->info->routes; route->mask; route++) {
- struct media_pad *source_pad, *sink_pad;
- struct media_entity *source, *sink;
- unsigned int source_idx;
-
- /* Check that VIN is part of the group. */
- if (!vin->group->vin[route->vin])
- continue;
-
+ for (route = vin->info->routes; route->chsel; route++) {
/* Check that VIN' master is part of the group. */
- if (!vin->group->vin[rvin_group_id_to_master(route->vin)])
+ if (!vin->group->vin[route->master])
continue;
/* Check that CSI-2 is part of the group. */
if (!vin->group->remotes[route->csi].subdev)
continue;
- source = &vin->group->remotes[route->csi].subdev->entity;
- source_idx = rvin_group_csi_channel_to_pad(route->channel);
- source_pad = &source->pads[source_idx];
-
- sink = &vin->group->vin[route->vin]->vdev.entity;
- sink_pad = &sink->pads[0];
-
- /* Skip if link already exists. */
- if (media_entity_find_link(source_pad, sink_pad))
- continue;
+ for (id = route->master; id < route->master + 4; id++) {
+ /* Check that VIN is part of the group. */
+ if (!vin->group->vin[id])
+ continue;
- ret = media_create_pad_link(source, source_idx, sink, 0, 0);
- if (ret) {
- vin_err(vin, "Error adding link from %s to %s\n",
- source->name, sink->name);
- break;
+ ret = rvin_csi2_create_link(vin->group, id, route);
+ if (ret)
+ goto out;
}
}
+out:
mutex_unlock(&vin->group->lock);
return ret;
@@ -1155,30 +1152,9 @@ static const struct rvin_info rcar_info_gen2 = {
};
static const struct rvin_group_route rcar_info_r8a774e1_routes[] = {
- { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
+ { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
+ { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 },
{ /* Sentinel */ }
};
@@ -1191,38 +1167,10 @@ static const struct rvin_info rcar_info_r8a774e1 = {
};
static const struct rvin_group_route rcar_info_r8a7795_routes[] = {
- { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
- { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
- { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
- { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
- { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
+ { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
+ { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 4, .csi = RVIN_CSI41, .chsel = 0x03 },
{ /* Sentinel */ }
};
@@ -1236,48 +1184,12 @@ static const struct rvin_info rcar_info_r8a7795 = {
};
static const struct rvin_group_route rcar_info_r8a7795es1_routes[] = {
- { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI21, .channel = 0, .vin = 0, .mask = BIT(2) | BIT(5) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
- { .csi = RVIN_CSI21, .channel = 0, .vin = 1, .mask = BIT(1) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
- { .csi = RVIN_CSI21, .channel = 1, .vin = 1, .mask = BIT(5) },
- { .csi = RVIN_CSI21, .channel = 0, .vin = 2, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
- { .csi = RVIN_CSI21, .channel = 2, .vin = 2, .mask = BIT(5) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) },
- { .csi = RVIN_CSI21, .channel = 1, .vin = 3, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
- { .csi = RVIN_CSI21, .channel = 3, .vin = 3, .mask = BIT(5) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI21, .channel = 0, .vin = 4, .mask = BIT(2) | BIT(5) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
- { .csi = RVIN_CSI21, .channel = 0, .vin = 5, .mask = BIT(1) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
- { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
- { .csi = RVIN_CSI21, .channel = 1, .vin = 5, .mask = BIT(5) },
- { .csi = RVIN_CSI21, .channel = 0, .vin = 6, .mask = BIT(0) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
- { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
- { .csi = RVIN_CSI21, .channel = 2, .vin = 6, .mask = BIT(5) },
- { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) },
- { .csi = RVIN_CSI21, .channel = 1, .vin = 7, .mask = BIT(2) },
- { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
- { .csi = RVIN_CSI21, .channel = 3, .vin = 7, .mask = BIT(5) },
+ { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 0, .csi = RVIN_CSI21, .chsel = 0x05 },
+ { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
+ { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 4, .csi = RVIN_CSI21, .chsel = 0x05 },
+ { .master = 4, .csi = RVIN_CSI41, .chsel = 0x03 },
{ /* Sentinel */ }
};
@@ -1290,34 +1202,10 @@ static const struct rvin_info rcar_info_r8a7795es1 = {
};
static const struct rvin_group_route rcar_info_r8a7796_routes[] = {
- { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 6, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 6, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 7, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 7, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
+ { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
+ { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 4, .csi = RVIN_CSI40, .chsel = 0x03 },
{ /* Sentinel */ }
};
@@ -1331,38 +1219,10 @@ static const struct rvin_info rcar_info_r8a7796 = {
};
static const struct rvin_group_route rcar_info_r8a77965_routes[] = {
- { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 4, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 6, .mask = BIT(1) },
- { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 6, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 7, .mask = BIT(0) },
- { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 7, .mask = BIT(3) },
- { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
+ { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
+ { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 },
+ { .master = 4, .csi = RVIN_CSI40, .chsel = 0x03 },
{ /* Sentinel */ }
};
@@ -1376,13 +1236,7 @@ static const struct rvin_info rcar_info_r8a77965 = {
};
static const struct rvin_group_route rcar_info_r8a77970_routes[] = {
- { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
+ { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
{ /* Sentinel */ }
};
@@ -1395,22 +1249,8 @@ static const struct rvin_info rcar_info_r8a77970 = {
};
static const struct rvin_group_route rcar_info_r8a77980_routes[] = {
- { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
- { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
- { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
- { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
- { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
- { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
- { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
- { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
+ { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
+ { .master = 4, .csi = RVIN_CSI41, .chsel = 0x03 },
{ /* Sentinel */ }
};
@@ -1424,10 +1264,7 @@ static const struct rvin_info rcar_info_r8a77980 = {
};
static const struct rvin_group_route rcar_info_r8a77990_routes[] = {
- { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
- { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 4, .mask = BIT(2) },
- { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
+ { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
{ /* Sentinel */ }
};
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index 2f097792525f..2fe179e389d2 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -503,6 +503,8 @@ struct rcar_csi2 {
struct v4l2_subdev *remote;
unsigned int remote_pad;
+ int channel_vc[4];
+
struct mutex lock; /* Protects mf and stream_count. */
struct v4l2_mbus_framefmt mf;
int stream_count;
@@ -700,8 +702,11 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
for (i = 0; i < priv->info->num_channels; i++) {
u32 vcdt_part;
- vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON |
- VCDT_SEL_DT(format->datatype);
+ if (priv->channel_vc[i] < 0)
+ continue;
+
+ vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) | VCDT_VCDTN_EN |
+ VCDT_SEL_DTN_ON | VCDT_SEL_DT(format->datatype);
/* Store in correct reg and offset. */
if (i < 2)
@@ -1283,7 +1288,52 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
* Platform Device Driver.
*/
+static int rcsi2_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct rcar_csi2 *priv = sd_to_csi2(sd);
+ struct video_device *vdev;
+ int channel, vc;
+ u32 id;
+
+ if (!is_media_entity_v4l2_video_device(remote->entity)) {
+ dev_err(priv->dev, "Remote is not a video device\n");
+ return -EINVAL;
+ }
+
+ vdev = media_entity_to_video_device(remote->entity);
+
+ if (of_property_read_u32(vdev->dev_parent->of_node, "renesas,id", &id)) {
+ dev_err(priv->dev, "No renesas,id, can't configure routing\n");
+ return -EINVAL;
+ }
+
+ channel = id % 4;
+
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (media_entity_remote_pad(local)) {
+ dev_dbg(priv->dev,
+ "Each VC can only be routed to one output channel\n");
+ return -EINVAL;
+ }
+
+ vc = local->index - 1;
+
+ dev_dbg(priv->dev, "Route VC%d to VIN%u on output channel %d\n",
+ vc, id, channel);
+ } else {
+ vc = -1;
+ }
+
+ priv->channel_vc[channel] = vc;
+
+ return 0;
+}
+
static const struct media_entity_operations rcar_csi2_entity_ops = {
+ .link_setup = rcsi2_link_setup,
.link_validate = v4l2_subdev_link_validate,
};
@@ -1502,6 +1552,9 @@ static int rcsi2_probe(struct platform_device *pdev)
if (ret)
goto error_async;
+ for (i = 0; i < ARRAY_SIZE(priv->channel_vc); i++)
+ priv->channel_vc[i] = -1;
+
pm_runtime_enable(&pdev->dev);
ret = v4l2_async_register_subdev(&priv->subdev);
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 8136bc75e7c4..2272f1c96aaf 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -1507,7 +1507,7 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
* register. IFMD_DES1 controls data expansion mode for CSI20/21,
* IFMD_DES0 controls data expansion mode for CSI40/41.
*/
- for (route = vin->info->routes; route->mask; route++) {
+ for (route = vin->info->routes; route->chsel; route++) {
if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21)
ifmd |= VNCSI_IFMD_DES1;
else
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index 7e86e35ca42b..1f94589d9ef1 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -128,11 +128,9 @@ struct rvin_parallel_entity {
* struct rvin_group_route - describes a route from a channel of a
* CSI-2 receiver to a VIN
*
+ * @master: VIN group master ID.
* @csi: CSI-2 receiver ID.
- * @channel: Output channel of the CSI-2 receiver.
- * @vin: VIN ID.
- * @mask: Bitmask of the different CHSEL register values that
- * allow for a route from @csi + @chan to @vin.
+ * @chsel: CHSEL register values that connects VIN group to CSI-2.
*
* .. note::
* Each R-Car CSI-2 receiver has four output channels facing the VIN
@@ -140,19 +138,11 @@ struct rvin_parallel_entity {
* There is no correlation between channel number and CSI-2 VC. It's
* up to the CSI-2 receiver driver to configure which VC is output
* on which channel, the VIN devices only care about output channels.
- *
- * There are in some cases multiple CHSEL register settings which would
- * allow for the same route from @csi + @channel to @vin. For example
- * on R-Car H3 both the CHSEL values 0 and 3 allow for a route from
- * CSI40/VC0 to VIN0. All possible CHSEL values for a route need to be
- * recorded as a bitmask in @mask, in this example bit 0 and 3 should
- * be set.
*/
struct rvin_group_route {
+ unsigned int master;
enum rvin_csi_id csi;
- unsigned int channel;
- unsigned int vin;
- unsigned int mask;
+ unsigned int chsel;
};
/**
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
index 607a8d39fbe2..682c26536034 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
@@ -368,7 +368,11 @@ static int sun6i_video_try_fmt(struct sun6i_video *video,
if (pixfmt->field == V4L2_FIELD_ANY)
pixfmt->field = V4L2_FIELD_NONE;
- pixfmt->colorspace = V4L2_COLORSPACE_RAW;
+ if (pixfmt->pixelformat == V4L2_PIX_FMT_JPEG)
+ pixfmt->colorspace = V4L2_COLORSPACE_JPEG;
+ else
+ pixfmt->colorspace = V4L2_COLORSPACE_SRGB;
+
pixfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
pixfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
pixfmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;