summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/userspace-api/media/drivers/aspeed-video.rst65
-rw-r--r--Documentation/userspace-api/media/drivers/index.rst1
-rw-r--r--Documentation/userspace-api/media/v4l/buffer.rst11
-rw-r--r--Documentation/userspace-api/media/v4l/pixfmt-reserved.rst17
-rw-r--r--drivers/media/dvb-core/dmxdev.c8
-rw-r--r--drivers/media/dvb-core/dvb_demux.c4
-rw-r--r--drivers/media/platform/aspeed/aspeed-video.c316
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h76
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c51
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c24
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c15
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-params.c4
-rw-r--r--drivers/media/platform/samsung/exynos4-is/media-dev.c2
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c1
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c1
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c1
-rw-r--r--drivers/staging/media/rkvdec/rkvdec-vp9.c3
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.c81
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.h19
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.c4
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h264.c2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h265.c2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.c18
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.h2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.c178
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.h2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_vp8.c2
-rw-r--r--drivers/staging/media/tegra-video/csi.c4
-rw-r--r--drivers/staging/media/tegra-video/csi.h2
-rw-r--r--include/media/davinci/vpbe.h2
-rw-r--r--include/uapi/linux/aspeed-video.h14
-rw-r--r--include/uapi/linux/v4l2-controls.h6
-rw-r--r--include/uapi/linux/videodev2.h1
34 files changed, 641 insertions, 300 deletions
diff --git a/Documentation/userspace-api/media/drivers/aspeed-video.rst b/Documentation/userspace-api/media/drivers/aspeed-video.rst
new file mode 100644
index 000000000000..1b0cb1e3eba8
--- /dev/null
+++ b/Documentation/userspace-api/media/drivers/aspeed-video.rst
@@ -0,0 +1,65 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: <isonum.txt>
+
+ASPEED video driver
+===================
+
+ASPEED Video Engine found on AST2400/2500/2600 SoC supports high performance
+video compressions with a wide range of video quality and compression ratio
+options. The adopted compressing algorithm is a modified JPEG algorithm.
+
+There are 2 types of compressions in this IP.
+
+* JPEG JFIF standard mode: for single frame and management compression
+* ASPEED proprietary mode: for multi-frame and differential compression.
+ Support 2-pass (high quality) video compression scheme (Patent pending by
+ ASPEED). Provide visually lossless video compression quality or to reduce
+ the network average loading under intranet KVM applications.
+
+VIDIOC_S_FMT can be used to choose which format you want. V4L2_PIX_FMT_JPEG
+stands for JPEG JFIF standard mode; V4L2_PIX_FMT_AJPG stands for ASPEED
+proprietary mode.
+
+More details on the ASPEED video hardware operations can be found in
+*chapter 6.2.16 KVM Video Driver* of SDK_User_Guide which available on
+AspeedTech-BMC/openbmc/releases.
+
+The ASPEED video driver implements the following driver-specific control:
+
+``V4L2_CID_ASPEED_HQ_MODE``
+---------------------------
+ Enable/Disable ASPEED's High quality mode. This is a private control
+ that can be used to enable high quality for aspeed proprietary mode.
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 4
+
+ * - ``(0)``
+ - ASPEED HQ mode is disabled.
+ * - ``(1)``
+ - ASPEED HQ mode is enabled.
+
+``V4L2_CID_ASPEED_HQ_JPEG_QUALITY``
+-----------------------------------
+ Define the quality of ASPEED's High quality mode. This is a private control
+ that can be used to decide compression quality if High quality mode enabled
+ . Higher the value, better the quality and bigger the size.
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 4
+
+ * - ``(1)``
+ - minimum
+ * - ``(12)``
+ - maximum
+ * - ``(1)``
+ - step
+ * - ``(1)``
+ - default
+
+**Copyright** |copy| 2022 ASPEED Technology Inc.
diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst
index 32f82aed47d9..46a494e00b72 100644
--- a/Documentation/userspace-api/media/drivers/index.rst
+++ b/Documentation/userspace-api/media/drivers/index.rst
@@ -31,6 +31,7 @@ For more details see the file COPYING in the source distribution of Linux.
:maxdepth: 5
:numbered:
+ aspeed-video
ccs
cx2341x-uapi
dw100
diff --git a/Documentation/userspace-api/media/v4l/buffer.rst b/Documentation/userspace-api/media/v4l/buffer.rst
index 4638ec64db00..04dec3e570ed 100644
--- a/Documentation/userspace-api/media/v4l/buffer.rst
+++ b/Documentation/userspace-api/media/v4l/buffer.rst
@@ -187,10 +187,8 @@ struct v4l2_buffer
on the negotiated data format and may change with each buffer for
compressed variable size data like JPEG images. Drivers must set
this field when ``type`` refers to a capture stream, applications
- when it refers to an output stream. If the application sets this
- to 0 for an output stream, then ``bytesused`` will be set to the
- size of the buffer (see the ``length`` field of this struct) by
- the driver. For multiplanar formats this field is ignored and the
+ when it refers to an output stream. For multiplanar formats this field
+ is ignored and the
``planes`` pointer is used instead.
* - __u32
- ``flags``
@@ -327,10 +325,7 @@ struct v4l2_plane
- ``bytesused``
- The number of bytes occupied by data in the plane (its payload).
Drivers must set this field when ``type`` refers to a capture
- stream, applications when it refers to an output stream. If the
- application sets this to 0 for an output stream, then
- ``bytesused`` will be set to the size of the plane (see the
- ``length`` field of this struct) by the driver.
+ stream, applications when it refers to an output stream.
.. note::
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
index 0ff68cd8cf62..73cd99828010 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
@@ -258,6 +258,23 @@ please make a proposal on the linux-media mailing list.
and it is used by various multimedia hardware blocks like GPU, display
controllers, ISP and video accelerators.
It contains four planes for progressive video.
+ * .. _V4L2-PIX-FMT-AJPG:
+
+ - ``V4L2_PIX_FMT_AJPG``
+ - 'AJPG'
+ - ASPEED JPEG format used by the aspeed-video driver on Aspeed platforms,
+ which is generally adapted for remote KVM.
+ On each frame compression, I will compare the new frame with previous
+ one to decide which macroblock's data is changed, and only the changed
+ macroblocks will be compressed.
+
+ The implementation is based on AST2600 A3 datasheet, revision 0.9, which
+ is not publicly available. Or you can reference Video stream data format
+ – ASPEED mode compression of SDK_User_Guide which available on
+ AspeedTech-BMC/openbmc/releases.
+
+ Decoder's implementation can be found here,
+ `aspeed_codec <https://github.com/AspeedTech-BMC/aspeed_codec/>`__
.. raw:: latex
\normalsize
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index f6ee678107d3..9ce5f010de3f 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -790,6 +790,11 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
for (i = 0; i < dmxdev->filternum; i++)
if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
break;
@@ -1448,7 +1453,10 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
+ mutex_lock(&dmxdev->mutex);
dmxdev->exit = 1;
+ mutex_unlock(&dmxdev->mutex);
+
if (dmxdev->dvbdev->users > 1) {
wait_event(dmxdev->dvbdev->wait_queue,
dmxdev->dvbdev->users == 1);
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index 83cc32ad7e12..398c86279b5b 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -233,7 +233,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
{
struct dvb_demux *demux = feed->demux;
struct dmx_section_feed *sec = &feed->feed.sec;
- u16 limit, seclen, n;
+ u16 limit, seclen;
if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
return 0;
@@ -262,7 +262,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
/* to be sure always set secbuf */
sec->secbuf = sec->secbuf_base + sec->secbufp;
- for (n = 0; sec->secbufp + 2 < limit; n++) {
+ while (sec->secbufp + 2 < limit) {
seclen = section_length(sec->secbuf);
if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
|| seclen + sec->secbufp > limit)
diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c
index 20f795ccc11b..f08b7884424f 100644
--- a/drivers/media/platform/aspeed/aspeed-video.c
+++ b/drivers/media/platform/aspeed/aspeed-video.c
@@ -33,6 +33,7 @@
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-dma-contig.h>
+#include <uapi/linux/aspeed-video.h>
#define ASPEED_VIDEO_V4L2_MIN_BUF_REQ 3
@@ -59,6 +60,7 @@
#define VE_MAX_SRC_BUFFER_SIZE 0x8ca000 /* 1920 * 1200, 32bpp */
#define VE_JPEG_HEADER_SIZE 0x006000 /* 512 * 12 * 4 */
+#define VE_BCD_BUFF_SIZE 0x9000 /* (1920/8) * (1200/8) */
#define VE_PROTECTION_KEY 0x000
#define VE_PROTECTION_KEY_UNLOCK 0x1a038aa8
@@ -107,6 +109,13 @@
#define VE_SCALING_FILTER2 0x020
#define VE_SCALING_FILTER3 0x024
+#define VE_BCD_CTRL 0x02C
+#define VE_BCD_CTRL_EN_BCD BIT(0)
+#define VE_BCD_CTRL_EN_ABCD BIT(1)
+#define VE_BCD_CTRL_EN_CB BIT(2)
+#define VE_BCD_CTRL_THR GENMASK(23, 16)
+#define VE_BCD_CTRL_ABCD_THR GENMASK(31, 24)
+
#define VE_CAP_WINDOW 0x030
#define VE_COMP_WINDOW 0x034
#define VE_COMP_PROC_OFFSET 0x038
@@ -115,6 +124,7 @@
#define VE_SRC0_ADDR 0x044
#define VE_SRC_SCANLINE_OFFSET 0x048
#define VE_SRC1_ADDR 0x04c
+#define VE_BCD_ADDR 0x050
#define VE_COMP_ADDR 0x054
#define VE_STREAM_BUF_SIZE 0x058
@@ -135,6 +145,8 @@
#define VE_COMP_CTRL_HQ_DCT_CHR GENMASK(26, 22)
#define VE_COMP_CTRL_HQ_DCT_LUM GENMASK(31, 27)
+#define VE_CB_ADDR 0x06C
+
#define AST2400_VE_COMP_SIZE_READ_BACK 0x078
#define AST2600_VE_COMP_SIZE_READ_BACK 0x084
@@ -211,6 +223,12 @@ enum {
VIDEO_CLOCKS_ON,
};
+enum aspeed_video_format {
+ VIDEO_FMT_STANDARD = 0,
+ VIDEO_FMT_ASPEED,
+ VIDEO_FMT_MAX = VIDEO_FMT_ASPEED
+};
+
// for VE_CTRL_CAPTURE_FMT
enum aspeed_video_capture_format {
VIDEO_CAP_FMT_YUV_STUDIO_SWING = 0,
@@ -245,16 +263,20 @@ struct aspeed_video_perf {
/*
* 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
+ * 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
+ * bcd: holds the buffer information for bcd work
* yuv420: a flag raised if JPEG subsampling is 420
+ * format: holds the video format
+ * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED
* frame_rate: holds the frame_rate
* jpeg_quality: holds jpeq's quality (0~11)
+ * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled
* 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
@@ -290,10 +312,14 @@ struct aspeed_video {
unsigned int max_compressed_size;
struct aspeed_video_addr srcs[2];
struct aspeed_video_addr jpeg;
+ struct aspeed_video_addr bcd;
bool yuv420;
+ enum aspeed_video_format format;
+ bool hq_mode;
unsigned int frame_rate;
unsigned int jpeg_quality;
+ unsigned int jpeg_hq_quality;
unsigned int frame_bottom;
unsigned int frame_left;
@@ -458,8 +484,18 @@ static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = {
},
};
+static const char * const format_str[] = {"Standard JPEG",
+ "Aspeed JPEG"};
+
static unsigned int debug;
+static bool aspeed_video_alloc_buf(struct aspeed_video *video,
+ struct aspeed_video_addr *addr,
+ unsigned int size);
+
+static void aspeed_video_free_buf(struct aspeed_video *video,
+ struct aspeed_video_addr *addr);
+
static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420)
{
int i;
@@ -547,6 +583,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video)
unsigned long flags;
struct aspeed_video_buffer *buf;
u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL);
+ bool bcd_buf_need = (video->format != VIDEO_FMT_STANDARD);
if (video->v4l2_input_status) {
v4l2_warn(&video->v4l2_dev, "No signal; don't start frame\n");
@@ -559,6 +596,20 @@ static int aspeed_video_start_frame(struct aspeed_video *video)
return -EBUSY;
}
+ if (bcd_buf_need && !video->bcd.size) {
+ if (!aspeed_video_alloc_buf(video, &video->bcd,
+ VE_BCD_BUFF_SIZE)) {
+ dev_err(video->dev, "Failed to allocate BCD buffer\n");
+ dev_err(video->dev, "don't start frame\n");
+ return -ENOMEM;
+ }
+ aspeed_video_write(video, VE_BCD_ADDR, video->bcd.dma);
+ v4l2_dbg(1, debug, &video->v4l2_dev, "bcd addr(%pad) size(%d)\n",
+ &video->bcd.dma, video->bcd.size);
+ } else if (!bcd_buf_need && video->bcd.size) {
+ aspeed_video_free_buf(video, &video->bcd);
+ }
+
spin_lock_irqsave(&video->lock, flags);
buf = list_first_entry_or_null(&video->buffers,
struct aspeed_video_buffer, link);
@@ -657,6 +708,24 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay)
schedule_delayed_work(&video->res_work, delay);
}
+static void aspeed_video_swap_src_buf(struct aspeed_video *v)
+{
+ if (v->format == VIDEO_FMT_STANDARD)
+ return;
+
+ /* Reset bcd buffer to have a full frame update every 8 frames. */
+ if (IS_ALIGNED(v->sequence, 8))
+ memset((u8 *)v->bcd.virt, 0x00, VE_BCD_BUFF_SIZE);
+
+ if (v->sequence & 0x01) {
+ aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[1].dma);
+ aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[0].dma);
+ } else {
+ aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[0].dma);
+ aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[1].dma);
+ }
+}
+
static irqreturn_t aspeed_video_irq(int irq, void *arg)
{
struct aspeed_video *video = arg;
@@ -705,6 +774,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
if (sts & VE_INTERRUPT_COMP_COMPLETE) {
struct aspeed_video_buffer *buf;
+ bool empty = true;
u32 frame_size = aspeed_video_read(video,
video->comp_size_read);
@@ -718,13 +788,23 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
if (buf) {
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size);
- if (!list_is_last(&buf->link, &video->buffers)) {
+ /*
+ * aspeed_jpeg requires continuous update.
+ * On the contrary, standard jpeg can keep last buffer
+ * to always have the latest result.
+ */
+ if (video->format == VIDEO_FMT_STANDARD &&
+ list_is_last(&buf->link, &video->buffers)) {
+ empty = false;
+ v4l2_warn(&video->v4l2_dev, "skip to keep last frame updated\n");
+ } else {
buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.sequence = video->sequence++;
buf->vb.field = V4L2_FIELD_NONE;
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_DONE);
list_del(&buf->link);
+ empty = list_empty(&video->buffers);
}
}
spin_unlock(&video->lock);
@@ -738,7 +818,10 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
aspeed_video_write(video, VE_INTERRUPT_STATUS,
VE_INTERRUPT_COMP_COMPLETE);
sts &= ~VE_INTERRUPT_COMP_COMPLETE;
- if (test_bit(VIDEO_STREAMING, &video->flags) && buf)
+
+ aspeed_video_swap_src_buf(video);
+
+ if (test_bit(VIDEO_STREAMING, &video->flags) && !empty)
aspeed_video_start_frame(video);
}
@@ -1085,10 +1168,14 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
FIELD_PREP(VE_TGS_FIRST, video->frame_top) |
FIELD_PREP(VE_TGS_LAST,
video->frame_bottom + 1));
- aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_INT_DE);
+ aspeed_video_update(video, VE_CTRL,
+ VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH,
+ VE_CTRL_INT_DE);
} else {
v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n");
- aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH);
+ aspeed_video_update(video, VE_CTRL,
+ VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH,
+ VE_CTRL_DIRECT_FETCH);
}
size *= 4;
@@ -1121,21 +1208,65 @@ err_mem:
aspeed_video_free_buf(video, &video->srcs[0]);
}
-static void aspeed_video_init_regs(struct aspeed_video *video)
+static void aspeed_video_update_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 |
- FIELD_PREP(VE_CTRL_CAPTURE_FMT, VIDEO_CAP_FMT_YUV_FULL_SWING);
- u32 seq_ctrl = video->jpeg_mode;
+ u8 jpeg_hq_quality = clamp((int)video->jpeg_hq_quality - 1, 0,
+ ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1);
+ u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
+ FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10) |
+ FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode) |
+ FIELD_PREP(VE_COMP_CTRL_HQ_DCT_LUM, jpeg_hq_quality) |
+ FIELD_PREP(VE_COMP_CTRL_HQ_DCT_CHR, jpeg_hq_quality | 0x10);
+ u32 ctrl = 0;
+ u32 seq_ctrl = 0;
+
+ v4l2_dbg(1, debug, &video->v4l2_dev, "framerate(%d)\n",
+ video->frame_rate);
+ v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg format(%s) subsample(%s)\n",
+ format_str[video->format],
+ video->yuv420 ? "420" : "444");
+ v4l2_dbg(1, debug, &video->v4l2_dev, "compression quality(%d)\n",
+ video->jpeg_quality);
+ v4l2_dbg(1, debug, &video->v4l2_dev, "hq_mode(%s) hq_quality(%d)\n",
+ video->hq_mode ? "on" : "off", video->jpeg_hq_quality);
+
+ if (video->format == VIDEO_FMT_ASPEED)
+ aspeed_video_update(video, VE_BCD_CTRL, 0, VE_BCD_CTRL_EN_BCD);
+ else
+ aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0);
if (video->frame_rate)
ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate);
+ if (video->format == VIDEO_FMT_STANDARD) {
+ comp_ctrl &= ~FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode);
+ seq_ctrl |= video->jpeg_mode;
+ }
+
if (video->yuv420)
seq_ctrl |= VE_SEQ_CTRL_YUV420;
+ if (video->jpeg.virt)
+ aspeed_video_update_jpeg_table(video->jpeg.virt, video->yuv420);
+
+ /* Set control registers */
+ aspeed_video_update(video, VE_SEQ_CTRL,
+ video->jpeg_mode | VE_SEQ_CTRL_YUV420,
+ seq_ctrl);
+ aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC, ctrl);
+ aspeed_video_update(video, VE_COMP_CTRL,
+ VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR |
+ VE_COMP_CTRL_EN_HQ | VE_COMP_CTRL_HQ_DCT_LUM |
+ VE_COMP_CTRL_HQ_DCT_CHR | VE_COMP_CTRL_VQ_4COLOR |
+ VE_COMP_CTRL_VQ_DCT_ONLY,
+ comp_ctrl);
+}
+
+static void aspeed_video_init_regs(struct aspeed_video *video)
+{
+ u32 ctrl = VE_CTRL_AUTO_OR_CURSOR |
+ FIELD_PREP(VE_CTRL_CAPTURE_FMT, VIDEO_CAP_FMT_YUV_FULL_SWING);
+
/* Unlock VE registers */
aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_UNLOCK);
@@ -1150,9 +1281,8 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma);
/* Set control registers */
- aspeed_video_write(video, VE_SEQ_CTRL, seq_ctrl);
aspeed_video_write(video, VE_CTRL, ctrl);
- aspeed_video_write(video, VE_COMP_CTRL, comp_ctrl);
+ aspeed_video_write(video, VE_COMP_CTRL, VE_COMP_CTRL_RSVD);
/* Don't downscale */
aspeed_video_write(video, VE_SCALING_FACTOR, 0x10001000);
@@ -1168,6 +1298,8 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
FIELD_PREP(VE_MODE_DT_HOR_STABLE, 6) |
FIELD_PREP(VE_MODE_DT_VER_STABLE, 6) |
FIELD_PREP(VE_MODE_DT_EDG_THROD, 0x65));
+
+ aspeed_video_write(video, VE_BCD_CTRL, 0);
}
static void aspeed_video_start(struct aspeed_video *video)
@@ -1201,6 +1333,9 @@ static void aspeed_video_stop(struct aspeed_video *video)
if (video->srcs[1].size)
aspeed_video_free_buf(video, &video->srcs[1]);
+ if (video->bcd.size)
+ aspeed_video_free_buf(video, &video->bcd);
+
video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
video->flags = 0;
}
@@ -1219,10 +1354,12 @@ static int aspeed_video_querycap(struct file *file, void *fh,
static int aspeed_video_enum_format(struct file *file, void *fh,
struct v4l2_fmtdesc *f)
{
+ struct aspeed_video *video = video_drvdata(file);
+
if (f->index)
return -EINVAL;
- f->pixelformat = V4L2_PIX_FMT_JPEG;
+ f->pixelformat = video->pix_fmt.pixelformat;
return 0;
}
@@ -1237,6 +1374,29 @@ static int aspeed_video_get_format(struct file *file, void *fh,
return 0;
}
+static int aspeed_video_set_format(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct aspeed_video *video = video_drvdata(file);
+
+ if (vb2_is_busy(&video->queue))
+ return -EBUSY;
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_JPEG:
+ video->format = VIDEO_FMT_STANDARD;
+ break;
+ case V4L2_PIX_FMT_AJPG:
+ video->format = VIDEO_FMT_ASPEED;
+ break;
+ default:
+ return -EINVAL;
+ }
+ video->pix_fmt.pixelformat = f->fmt.pix.pixelformat;
+
+ return 0;
+}
+
static int aspeed_video_enum_input(struct file *file, void *fh,
struct v4l2_input *inp)
{
@@ -1454,7 +1614,7 @@ static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = {
.vidioc_enum_fmt_vid_cap = aspeed_video_enum_format,
.vidioc_g_fmt_vid_cap = aspeed_video_get_format,
- .vidioc_s_fmt_vid_cap = aspeed_video_get_format,
+ .vidioc_s_fmt_vid_cap = aspeed_video_set_format,
.vidioc_try_fmt_vid_cap = aspeed_video_get_format,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
@@ -1486,27 +1646,6 @@ static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
-static void aspeed_video_update_jpeg_quality(struct aspeed_video *video)
-{
- u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
- FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
-
- aspeed_video_update(video, VE_COMP_CTRL,
- VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR,
- comp_ctrl);
-}
-
-static void aspeed_video_update_subsampling(struct aspeed_video *video)
-{
- if (video->jpeg.virt)
- aspeed_video_update_jpeg_table(video->jpeg.virt, video->yuv420);
-
- if (video->yuv420)
- aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420);
- else
- aspeed_video_update(video, VE_SEQ_CTRL, VE_SEQ_CTRL_YUV420, 0);
-}
-
static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct aspeed_video *video = container_of(ctrl->handler,
@@ -1516,16 +1655,23 @@ static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_JPEG_COMPRESSION_QUALITY:
video->jpeg_quality = ctrl->val;
- aspeed_video_update_jpeg_quality(video);
+ if (test_bit(VIDEO_STREAMING, &video->flags))
+ aspeed_video_update_regs(video);
break;
case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
- if (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420) {
- video->yuv420 = true;
- aspeed_video_update_subsampling(video);
- } else {
- video->yuv420 = false;
- aspeed_video_update_subsampling(video);
- }
+ video->yuv420 = (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420);
+ if (test_bit(VIDEO_STREAMING, &video->flags))
+ aspeed_video_update_regs(video);
+ break;
+ case V4L2_CID_ASPEED_HQ_MODE:
+ video->hq_mode = ctrl->val;
+ if (test_bit(VIDEO_STREAMING, &video->flags))
+ aspeed_video_update_regs(video);
+ break;
+ case V4L2_CID_ASPEED_HQ_JPEG_QUALITY:
+ video->jpeg_hq_quality = ctrl->val;
+ if (test_bit(VIDEO_STREAMING, &video->flags))
+ aspeed_video_update_regs(video);
break;
default:
return -EINVAL;
@@ -1538,6 +1684,28 @@ static const struct v4l2_ctrl_ops aspeed_video_ctrl_ops = {
.s_ctrl = aspeed_video_set_ctrl,
};
+static const struct v4l2_ctrl_config aspeed_ctrl_HQ_mode = {
+ .ops = &aspeed_video_ctrl_ops,
+ .id = V4L2_CID_ASPEED_HQ_MODE,
+ .name = "Aspeed HQ Mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = false,
+};
+
+static const struct v4l2_ctrl_config aspeed_ctrl_HQ_jpeg_quality = {
+ .ops = &aspeed_video_ctrl_ops,
+ .id = V4L2_CID_ASPEED_HQ_JPEG_QUALITY,
+ .name = "Aspeed HQ Quality",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = ASPEED_VIDEO_JPEG_NUM_QUALITIES,
+ .step = 1,
+ .def = 1,
+};
+
static void aspeed_video_resolution_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -1552,6 +1720,8 @@ static void aspeed_video_resolution_work(struct work_struct *work)
aspeed_video_init_regs(video);
+ aspeed_video_update_regs(video);
+
aspeed_video_get_resolution(video);
if (video->detected_timings.width != video->active_timings.width ||
@@ -1662,6 +1832,8 @@ static int aspeed_video_start_streaming(struct vb2_queue *q,
video->perf.duration_max = 0;
video->perf.duration_min = 0xffffffff;
+ aspeed_video_update_regs(video);
+
rc = aspeed_video_start_frame(video);
if (rc) {
aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED);
@@ -1732,9 +1904,29 @@ static const struct vb2_ops aspeed_video_vb2_ops = {
static int aspeed_video_debugfs_show(struct seq_file *s, void *data)
{
struct aspeed_video *v = s->private;
+ u32 val08;
seq_puts(s, "\n");
+ seq_puts(s, "Capture:\n");
+ val08 = aspeed_video_read(v, VE_CTRL);
+ if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) {
+ seq_printf(s, " %-20s:\tDirect fetch\n", "Mode");
+ seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode",
+ FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32");
+ } else {
+ seq_printf(s, " %-20s:\tSync\n", "Mode");
+ seq_printf(s, " %-20s:\t%s\n", "Video source",
+ FIELD_GET(VE_CTRL_SOURCE, val08) ?
+ "external" : "internal");
+ seq_printf(s, " %-20s:\t%s\n", "DE source",
+ FIELD_GET(VE_CTRL_INT_DE, val08) ?
+ "internal" : "external");
+ seq_printf(s, " %-20s:\t%s\n", "Cursor overlay",
+ FIELD_GET(VE_CTRL_AUTO_OR_CURSOR, val08) ?
+ "Without" : "With");
+ }
+
seq_printf(s, " %-20s:\t%s\n", "Signal",
v->v4l2_input_status ? "Unlock" : "Lock");
seq_printf(s, " %-20s:\t%d\n", "Width", v->pix_fmt.width);
@@ -1743,13 +1935,29 @@ static int aspeed_video_debugfs_show(struct seq_file *s, void *data)
seq_puts(s, "\n");
+ seq_puts(s, "Compression:\n");
+ seq_printf(s, " %-20s:\t%s\n", "Format", format_str[v->format]);
+ seq_printf(s, " %-20s:\t%s\n", "Subsampling",
+ v->yuv420 ? "420" : "444");
+ seq_printf(s, " %-20s:\t%d\n", "Quality", v->jpeg_quality);
+ if (v->format == VIDEO_FMT_ASPEED) {
+ seq_printf(s, " %-20s:\t%s\n", "HQ Mode",
+ v->hq_mode ? "on" : "off");
+ seq_printf(s, " %-20s:\t%d\n", "HQ Quality",
+ v->hq_mode ? v->jpeg_hq_quality : 0);
+ }
+
+ seq_puts(s, "\n");
+
seq_puts(s, "Performance:\n");
seq_printf(s, " %-20s:\t%d\n", "Frame#", v->sequence);
seq_printf(s, " %-20s:\n", "Frame Duration(ms)");
seq_printf(s, " %-18s:\t%d\n", "Now", v->perf.duration);
seq_printf(s, " %-18s:\t%d\n", "Min", v->perf.duration_min);
seq_printf(s, " %-18s:\t%d\n", "Max", v->perf.duration_max);
- seq_printf(s, " %-20s:\t%d\n", "FPS", 1000 / (v->perf.totaltime / v->sequence));
+ seq_printf(s, " %-20s:\t%d\n", "FPS",
+ (v->perf.totaltime && v->sequence) ?
+ 1000 / (v->perf.totaltime / v->sequence) : 0);
return 0;
}
@@ -1800,6 +2008,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
struct v4l2_device *v4l2_dev = &video->v4l2_dev;
struct vb2_queue *vbq = &video->queue;
struct video_device *vdev = &video->vdev;
+ struct v4l2_ctrl_handler *hdl = &video->ctrl_handler;
int rc;
video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG;
@@ -1814,16 +2023,18 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
return rc;
}
- v4l2_ctrl_handler_init(&video->ctrl_handler, 2);
- v4l2_ctrl_new_std(&video->ctrl_handler, &aspeed_video_ctrl_ops,
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &aspeed_video_ctrl_ops,
V4L2_CID_JPEG_COMPRESSION_QUALITY, 0,
ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1, 1, 0);
- v4l2_ctrl_new_std_menu(&video->ctrl_handler, &aspeed_video_ctrl_ops,
+ v4l2_ctrl_new_std_menu(hdl, &aspeed_video_ctrl_ops,
V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask,
V4L2_JPEG_CHROMA_SUBSAMPLING_444);
+ v4l2_ctrl_new_custom(hdl, &aspeed_ctrl_HQ_mode, NULL);
+ v4l2_ctrl_new_custom(hdl, &aspeed_ctrl_HQ_jpeg_quality, NULL);
- rc = video->ctrl_handler.error;
+ rc = hdl->error;
if (rc) {
v4l2_ctrl_handler_free(&video->ctrl_handler);
v4l2_device_unregister(v4l2_dev);
@@ -1832,7 +2043,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
return rc;
}
- v4l2_dev->ctrl_handler = &video->ctrl_handler;
+ v4l2_dev->ctrl_handler = hdl;
vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
@@ -1980,6 +2191,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
video->comp_size_read = config->comp_size_read;
video->frame_rate = 30;
+ video->jpeg_hq_quality = 1;
video->dev = &pdev->dev;
spin_lock_init(&video->lock);
mutex_init(&video->video_lock);
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
index 3e66ebaee2da..c7f231f8ea3e 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
@@ -51,14 +51,14 @@ struct img_sw_addr {
struct img_plane_format {
u32 size;
- u16 stride;
+ u32 stride;
} __packed;
struct img_pix_format {
- u16 width;
- u16 height;
+ u32 width;
+ u32 height;
u32 colorformat; /* enum mdp_color */
- u16 ycbcr_prof; /* enum mdp_ycbcr_profile */
+ u32 ycbcr_prof; /* enum mdp_ycbcr_profile */
struct img_plane_format plane_fmt[IMG_MAX_PLANES];
} __packed;
@@ -72,10 +72,10 @@ struct img_image_buffer {
#define IMG_SUBPIXEL_SHIFT 20
struct img_crop {
- s16 left;
- s16 top;
- u16 width;
- u16 height;
+ s32 left;
+ s32 top;
+ u32 width;
+ u32 height;
u32 left_subpix;
u32 top_subpix;
u32 width_subpix;
@@ -90,24 +90,24 @@ struct img_crop {
struct img_input {
struct img_image_buffer buffer;
- u16 flags; /* HDR, DRE, dither */
+ u32 flags; /* HDR, DRE, dither */
} __packed;
struct img_output {
struct img_image_buffer buffer;
struct img_crop crop;
- s16 rotation;
- u16 flags; /* H-flip, sharpness, dither */
+ s32 rotation;
+ u32 flags; /* H-flip, sharpness, dither */
} __packed;
struct img_ipi_frameparam {
u32 index;
u32 frame_no;
struct img_timeval timestamp;
- u8 type; /* enum mdp_stream_type */
- u8 state;
- u8 num_inputs;
- u8 num_outputs;
+ u32 type; /* enum mdp_stream_type */
+ u32 state;
+ u32 num_inputs;
+ u32 num_outputs;
u64 drv_data;
struct img_input inputs[IMG_MAX_HW_INPUTS];
struct img_output outputs[IMG_MAX_HW_OUTPUTS];
@@ -123,51 +123,51 @@ struct img_sw_buffer {
} __packed;
struct img_ipi_param {
- u8 usage;
+ u32 usage;
struct img_sw_buffer frm_param;
} __packed;
struct img_frameparam {
struct list_head list_entry;
struct img_ipi_frameparam frameparam;
-};
+} __packed;
/* ISP-MDP generic output information */
struct img_comp_frame {
- u32 output_disable:1;
- u32 bypass:1;
- u16 in_width;
- u16 in_height;
- u16 out_width;
- u16 out_height;
+ u32 output_disable;
+ u32 bypass;
+ u32 in_width;
+ u32 in_height;
+ u32 out_width;
+ u32 out_height;
struct img_crop crop;
- u16 in_total_width;
- u16 out_total_width;
+ u32 in_total_width;
+ u32 out_total_width;
} __packed;
struct img_region {
- s16 left;
- s16 right;
- s16 top;
- s16 bottom;
+ s32 left;
+ s32 right;
+ s32 top;
+ s32 bottom;
} __packed;
struct img_offset {
- s16 left;
- s16 top;
+ s32 left;
+ s32 top;
u32 left_subpix;
u32 top_subpix;
} __packed;
struct img_comp_subfrm {
- u32 tile_disable:1;
+ u32 tile_disable;
struct img_region in;
struct img_region out;
struct img_offset luma;
struct img_offset chroma;
- s16 out_vertical; /* Output vertical index */
- s16 out_horizontal; /* Output horizontal index */
+ s32 out_vertical; /* Output vertical index */
+ s32 out_horizontal; /* Output horizontal index */
} __packed;
#define IMG_MAX_SUBFRAMES 14
@@ -250,8 +250,8 @@ struct isp_data {
} __packed;
struct img_compparam {
- u16 type; /* enum mdp_comp_type */
- u16 id; /* enum mtk_mdp_comp_id */
+ u32 type; /* enum mdp_comp_id */
+ u32 id; /* engine alias_id */
u32 input;
u32 outputs[IMG_MAX_HW_OUTPUTS];
u32 num_outputs;
@@ -273,12 +273,12 @@ struct img_mux {
u32 reg;
u32 value;
u32 subsys_id;
-};
+} __packed;
struct img_mmsys_ctrl {
struct img_mux sets[IMG_MAX_COMPONENTS * 2];
u32 num_sets;
-};
+} __packed;
struct img_config {
struct img_compparam components[IMG_MAX_COMPONENTS];
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
index 86c054600a08..124c1b96e96b 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
@@ -252,10 +252,9 @@ static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
dma_addr_t dma_addr;
pkt->va_base = kzalloc(size, GFP_KERNEL);
- if (!pkt->va_base) {
- kfree(pkt);
+ if (!pkt->va_base)
return -ENOMEM;
- }
+
pkt->buf_size = size;
pkt->cl = (void *)client;
@@ -368,25 +367,30 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
- goto err_cmdq_data;
+ goto err_cancel_job;
}
- if (mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K)) {
- ret = -ENOMEM;
- goto err_cmdq_data;
- }
+ ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K);
+ if (ret)
+ goto err_free_cmd;
comps = kcalloc(param->config->num_components, sizeof(*comps),
GFP_KERNEL);
if (!comps) {
ret = -ENOMEM;
- goto err_cmdq_data;
+ goto err_destroy_pkt;
}
path = kzalloc(sizeof(*path), GFP_KERNEL);
if (!path) {
ret = -ENOMEM;
- goto err_cmdq_data;
+ goto err_free_comps;
+ }
+
+ ret = mtk_mutex_prepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
+ if (ret) {
+ dev_err(dev, "Fail to enable mutex clk\n");
+ goto err_free_path;
}
path->mdp_dev = mdp;
@@ -406,15 +410,13 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
ret = mdp_path_ctx_init(mdp, path);
if (ret) {
dev_err(dev, "mdp_path_ctx_init error\n");
- goto err_cmdq_data;
+ goto err_free_path;
}
- mtk_mutex_prepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
-
ret = mdp_path_config(mdp, cmd, path);
if (ret) {
dev_err(dev, "mdp_path_config error\n");
- goto err_cmdq_data;
+ goto err_free_path;
}
cmdq_pkt_finalize(&cmd->pkt);
@@ -431,10 +433,8 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
cmd->mdp_ctx = param->mdp_ctx;
ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps);
- if (ret) {
- dev_err(dev, "comp %d failed to enable clock!\n", ret);
- goto err_clock_off;
- }
+ if (ret)
+ goto err_free_path;
dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev,
cmd->pkt.pa_base, cmd->pkt.cmd_buf_size,
@@ -450,17 +450,20 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
return 0;
err_clock_off:
- mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps);
-err_cmdq_data:
+err_free_path:
+ mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
kfree(path);
- atomic_dec(&mdp->job_count);
- wake_up(&mdp->callback_wq);
- if (cmd && cmd->pkt.buf_size > 0)
- mdp_cmdq_pkt_destroy(&cmd->pkt);
+err_free_comps:
kfree(comps);
+err_destroy_pkt:
+ mdp_cmdq_pkt_destroy(&cmd->pkt);
+err_free_cmd:
kfree(cmd);
+err_cancel_job:
+ atomic_dec(&mdp->job_count);
+
return ret;
}
EXPORT_SYMBOL_GPL(mdp_cmdq_send);
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
index d3eaf8884412..7bc05f42a23c 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
@@ -699,12 +699,22 @@ int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp)
dev_err(dev,
"Failed to enable clk %d. type:%d id:%d\n",
i, comp->type, comp->id);
- pm_runtime_put(comp->comp_dev);
- return ret;
+ goto err_revert;
}
}
return 0;
+
+err_revert:
+ while (--i >= 0) {
+ if (IS_ERR_OR_NULL(comp->clks[i]))
+ continue;
+ clk_disable_unprepare(comp->clks[i]);
+ }
+ if (comp->comp_dev)
+ pm_runtime_put_sync(comp->comp_dev);
+
+ return ret;
}
void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp)
@@ -723,11 +733,13 @@ void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp)
int mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num)
{
- int i;
+ int i, ret;
- for (i = 0; i < num; i++)
- if (mdp_comp_clock_on(dev, &comps[i]) != 0)
- return ++i;
+ for (i = 0; i < num; i++) {
+ ret = mdp_comp_clock_on(dev, &comps[i]);
+ if (ret)
+ return ret;
+ }
return 0;
}
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
index c413e59d4286..2d1f6ae9f080 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
@@ -196,27 +196,27 @@ static int mdp_probe(struct platform_device *pdev)
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS);
if (!mm_pdev) {
ret = -ENODEV;
- goto err_return;
+ goto err_destroy_device;
}
mdp->mdp_mmsys = &mm_pdev->dev;
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX);
if (WARN_ON(!mm_pdev)) {
ret = -ENODEV;
- goto err_return;
+ goto err_destroy_device;
}
for (i = 0; i < MDP_PIPE_MAX; i++) {
mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev);
if (!mdp->mdp_mutex[i]) {
ret = -ENODEV;
- goto err_return;
+ goto err_free_mutex;
}
}
ret = mdp_comp_config(mdp);
if (ret) {
dev_err(dev, "Failed to config mdp components\n");
- goto err_return;
+ goto err_free_mutex;
}
mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);
@@ -287,11 +287,12 @@ err_destroy_job_wq:
destroy_workqueue(mdp->job_wq);
err_deinit_comp:
mdp_comp_destroy(mdp);
-err_return:
+err_free_mutex:
for (i = 0; i < MDP_PIPE_MAX; i++)
- if (mdp)
- mtk_mutex_put(mdp->mdp_mutex[i]);
+ mtk_mutex_put(mdp->mdp_mutex[i]);
+err_destroy_device:
kfree(mdp);
+err_return:
dev_dbg(dev, "Errno %d\n", ret);
return ret;
}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
index d8731ebbf479..3482f7d707b7 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
@@ -715,7 +715,7 @@ static void rkisp1_aec_config_v12(struct rkisp1_params *params,
u32 exp_ctrl;
u32 block_hsize, block_vsize;
u32 wnd_num_idx = 1;
- const u32 ae_wnd_num[] = { 5, 9, 15, 15 };
+ static const u32 ae_wnd_num[] = { 5, 9, 15, 15 };
/* avoid to override the old enable value */
exp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL);
@@ -822,7 +822,7 @@ static void rkisp1_hst_config_v12(struct rkisp1_params *params,
u32 block_hsize, block_vsize;
u32 wnd_num_idx, hist_weight_num, hist_ctrl, value;
u8 weight15x15[RKISP1_CIF_ISP_HIST_WEIGHT_REG_SIZE_V12];
- const u32 hist_wnd_num[] = { 5, 9, 15, 15 };
+ static const u32 hist_wnd_num[] = { 5, 9, 15, 15 };
/* now we just support 9x9 window */
wnd_num_idx = 1;
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c
index 412213b0c384..383a1e0ab912 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.c
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c
@@ -1472,7 +1472,7 @@ static int fimc_md_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl);
- if (ret != EPROBE_DEFER)
+ if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get pinctrl: %d\n", ret);
goto err_clk;
}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 8b99c17e8403..9119f5e0e05e 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -913,7 +913,6 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev,
irq = platform_get_irq(platform_dev, 0);
if (irq < 0) {
- dev_err(dev, "failed to get interrupt\n");
ret = -ENXIO;
goto error_clock_rate_exclusive;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index 11620eaf941e..c0999581c599 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -973,6 +973,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
if (dev->has_compose_cap) {
v4l2_rect_set_min_size(compose, &min_rect);
v4l2_rect_set_max_size(compose, &max_rect);
+ v4l2_rect_map_inside(compose, &fmt);
}
dev->fmt_cap_rect = fmt;
tpg_s_buf_height(&dev->tpg, fmt.height);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index fddba75d9074..8cb4b976064e 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1497,6 +1497,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break;
case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break;
case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break;
+ case V4L2_PIX_FMT_AJPG: descr = "Aspeed JPEG"; break;
default:
if (fmt->description[0])
return;
diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c
index d8c1c0db15c7..cfae99b40ccb 100644
--- a/drivers/staging/media/rkvdec/rkvdec-vp9.c
+++ b/drivers/staging/media/rkvdec/rkvdec-vp9.c
@@ -84,6 +84,8 @@ struct rkvdec_vp9_probs {
struct rkvdec_vp9_inter_frame_probs inter;
struct rkvdec_vp9_intra_only_frame_probs intra_only;
};
+ /* 128 bit alignment */
+ u8 padding1[11];
};
/* Data structure describing auxiliary buffer format. */
@@ -1006,6 +1008,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
ctx->priv = vp9_ctx;
+ BUILD_BUG_ON(sizeof(priv_tbl->probs) % 16); /* ensure probs size is 128-bit aligned */
priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
&vp9_ctx->priv_tbl.dma, GFP_KERNEL);
if (!priv_tbl) {
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index 55c54dfdc585..6a2c08928613 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -77,56 +77,56 @@ static const struct cedrus_control cedrus_controls[] = {
.cfg = {
.id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
},
- .codec = CEDRUS_CODEC_MPEG2,
+ .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_MPEG2_PICTURE,
},
- .codec = CEDRUS_CODEC_MPEG2,
+ .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
},
- .codec = CEDRUS_CODEC_MPEG2,
+ .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SLICE_PARAMS,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SPS,
.ops = &cedrus_ctrl_ops,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_PPS,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
@@ -134,7 +134,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
.def = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
@@ -142,7 +142,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_H264_START_CODE_NONE,
.def = V4L2_STATELESS_H264_START_CODE_NONE,
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
/*
* We only expose supported profiles information,
@@ -160,20 +160,20 @@ static const struct cedrus_control cedrus_controls[] = {
.menu_skip_mask =
BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
},
- .codec = CEDRUS_CODEC_H264,
+ .capabilities = CEDRUS_CAPABILITY_H264_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_SPS,
.ops = &cedrus_ctrl_ops,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_PPS,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
@@ -181,13 +181,13 @@ static const struct cedrus_control cedrus_controls[] = {
/* The driver can only handle 1 entry per slice for now */
.dims = { 1 },
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
@@ -197,7 +197,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = 0xffffffff,
.step = 1,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
@@ -205,7 +205,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
.def = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
@@ -213,19 +213,19 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_HEVC_START_CODE_NONE,
.def = V4L2_STATELESS_HEVC_START_CODE_NONE,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_VP8_FRAME,
},
- .codec = CEDRUS_CODEC_VP8,
+ .capabilities = CEDRUS_CAPABILITY_VP8_DEC,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
},
- .codec = CEDRUS_CODEC_H265,
+ .capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
};
@@ -258,7 +258,7 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
struct v4l2_ctrl_handler *hdl = &ctx->hdl;
struct v4l2_ctrl *ctrl;
unsigned int ctrl_size;
- unsigned int i;
+ unsigned int i, j;
v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
if (hdl->error) {
@@ -274,7 +274,11 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
if (!ctx->ctrls)
return -ENOMEM;
+ j = 0;
for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
+ if (!cedrus_is_capable(ctx, cedrus_controls[i].capabilities))
+ continue;
+
ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg,
NULL);
if (hdl->error) {
@@ -289,7 +293,7 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
return hdl->error;
}
- ctx->ctrls[i] = ctrl;
+ ctx->ctrls[j++] = ctrl;
}
ctx->fh.ctrl_handler = hdl;
@@ -351,26 +355,18 @@ static int cedrus_open(struct file *file)
file->private_data = &ctx->fh;
ctx->dev = dev;
- ret = cedrus_init_ctrls(dev, ctx);
- if (ret)
- goto err_free;
-
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
&cedrus_queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
- goto err_ctrls;
+ goto err_free;
}
- ctx->dst_fmt.pixelformat = V4L2_PIX_FMT_NV12_32L32;
- cedrus_prepare_format(&ctx->dst_fmt);
- ctx->src_fmt.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE;
- /*
- * TILED_NV12 has more strict requirements, so copy the width and
- * height to src_fmt to ensure that is matches the dst_fmt resolution.
- */
- ctx->src_fmt.width = ctx->dst_fmt.width;
- ctx->src_fmt.height = ctx->dst_fmt.height;
- cedrus_prepare_format(&ctx->src_fmt);
+
+ cedrus_reset_out_format(ctx);
+
+ ret = cedrus_init_ctrls(dev, ctx);
+ if (ret)
+ goto err_m2m_release;
v4l2_fh_add(&ctx->fh);
@@ -378,8 +374,8 @@ static int cedrus_open(struct file *file)
return 0;
-err_ctrls:
- v4l2_ctrl_handler_free(&ctx->hdl);
+err_m2m_release:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
err_free:
kfree(ctx);
mutex_unlock(&dev->dev_mutex);
@@ -460,11 +456,6 @@ static int cedrus_probe(struct platform_device *pdev)
return ret;
}
- dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
- dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
- dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265;
- dev->dec_ops[CEDRUS_CODEC_VP8] = &cedrus_dec_ops_vp8;
-
mutex_init(&dev->dev_mutex);
INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 93a2196006f7..a6a649bacc95 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -35,14 +35,6 @@
#define CEDRUS_CAPABILITY_VP8_DEC BIT(4)
#define CEDRUS_CAPABILITY_H265_10_DEC BIT(5)
-enum cedrus_codec {
- CEDRUS_CODEC_MPEG2,
- CEDRUS_CODEC_H264,
- CEDRUS_CODEC_H265,
- CEDRUS_CODEC_VP8,
- CEDRUS_CODEC_LAST,
-};
-
enum cedrus_irq_status {
CEDRUS_IRQ_NONE,
CEDRUS_IRQ_ERROR,
@@ -57,7 +49,7 @@ enum cedrus_h264_pic_type {
struct cedrus_control {
struct v4l2_ctrl_config cfg;
- enum cedrus_codec codec;
+ unsigned int capabilities;
};
struct cedrus_h264_run {
@@ -118,7 +110,7 @@ struct cedrus_ctx {
struct v4l2_pix_format src_fmt;
struct v4l2_pix_format dst_fmt;
- enum cedrus_codec current_codec;
+ struct cedrus_dec_ops *current_codec;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl **ctrls;
@@ -185,7 +177,6 @@ struct cedrus_dev {
struct platform_device *pdev;
struct device *dev;
struct v4l2_m2m_dev *m2m_dev;
- struct cedrus_dec_ops *dec_ops[CEDRUS_CODEC_LAST];
/* Device file mutex */
struct mutex dev_mutex;
@@ -268,6 +259,12 @@ vb2_to_cedrus_buffer(const struct vb2_buffer *p)
return vb2_v4l2_to_cedrus_buffer(to_vb2_v4l2_buffer(p));
}
+static inline bool
+cedrus_is_capable(struct cedrus_ctx *ctx, unsigned int capabilities)
+{
+ return (ctx->dev->capabilities & capabilities) == capabilities;
+}
+
void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
index e7f7602a5ab4..fbbf9e6f0f50 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -94,7 +94,7 @@ void cedrus_device_run(void *priv)
cedrus_dst_format_set(dev, &ctx->dst_fmt);
- error = dev->dec_ops[ctx->current_codec]->setup(ctx, &run);
+ error = ctx->current_codec->setup(ctx, &run);
if (error)
v4l2_err(&ctx->dev->v4l2_dev,
"Failed to setup decoding job: %d\n", error);
@@ -110,7 +110,7 @@ void cedrus_device_run(void *priv)
schedule_delayed_work(&dev->watchdog_work,
msecs_to_jiffies(2000));
- dev->dec_ops[ctx->current_codec]->trigger(ctx);
+ ctx->current_codec->trigger(ctx);
} else {
v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev,
ctx->fh.m2m_ctx,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index a8b236cd3800..c139a37a567c 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -497,7 +497,7 @@ static int cedrus_h264_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
{
struct cedrus_dev *dev = ctx->dev;
- cedrus_engine_enable(ctx, CEDRUS_CODEC_H264);
+ cedrus_engine_enable(ctx);
cedrus_write(dev, VE_H264_SDROT_CTRL, 0);
cedrus_write(dev, VE_H264_EXTRA_BUFFER1,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 4952fc17f3e6..3f2946c8f174 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -463,7 +463,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
}
/* Activate H265 engine. */
- cedrus_engine_enable(ctx, CEDRUS_CODEC_H265);
+ cedrus_engine_enable(ctx);
/* Source offset and length in bits. */
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
index a6470a89851e..fa86a658fdc6 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -31,7 +31,7 @@
#include "cedrus_hw.h"
#include "cedrus_regs.h"
-int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec)
+int cedrus_engine_enable(struct cedrus_ctx *ctx)
{
u32 reg = 0;
@@ -42,18 +42,18 @@ int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec)
reg |= VE_MODE_REC_WR_MODE_2MB;
reg |= VE_MODE_DDR_MODE_BW_128;
- switch (codec) {
- case CEDRUS_CODEC_MPEG2:
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_MPEG2_SLICE:
reg |= VE_MODE_DEC_MPEG;
break;
/* H.264 and VP8 both use the same decoding mode bit. */
- case CEDRUS_CODEC_H264:
- case CEDRUS_CODEC_VP8:
+ case V4L2_PIX_FMT_H264_SLICE:
+ case V4L2_PIX_FMT_VP8_FRAME:
reg |= VE_MODE_DEC_H264;
break;
- case CEDRUS_CODEC_H265:
+ case V4L2_PIX_FMT_HEVC_SLICE:
reg |= VE_MODE_DEC_H265;
break;
@@ -132,12 +132,12 @@ static irqreturn_t cedrus_irq(int irq, void *data)
return IRQ_NONE;
}
- status = dev->dec_ops[ctx->current_codec]->irq_status(ctx);
+ status = ctx->current_codec->irq_status(ctx);
if (status == CEDRUS_IRQ_NONE)
return IRQ_NONE;
- dev->dec_ops[ctx->current_codec]->irq_disable(ctx);
- dev->dec_ops[ctx->current_codec]->irq_clear(ctx);
+ ctx->current_codec->irq_disable(ctx);
+ ctx->current_codec->irq_clear(ctx);
if (status == CEDRUS_IRQ_ERROR)
state = VB2_BUF_STATE_ERROR;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
index 7c92f00e36da..6f1e701b1ea8 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
@@ -16,7 +16,7 @@
#ifndef _CEDRUS_HW_H_
#define _CEDRUS_HW_H_
-int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec);
+int cedrus_engine_enable(struct cedrus_ctx *ctx);
void cedrus_engine_disable(struct cedrus_dev *dev);
void cedrus_dst_format_set(struct cedrus_dev *dev,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
index c1128d2cd555..10e98f08aafc 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
@@ -66,7 +66,7 @@ static int cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
quantisation = run->mpeg2.quantisation;
/* Activate MPEG engine. */
- cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2);
+ cedrus_engine_enable(ctx);
/* Set intra quantisation matrix. */
matrix = quantisation->intra_quantiser_matrix;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index 66714609b577..e6909be282d3 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -56,13 +56,13 @@ static struct cedrus_format cedrus_formats[] = {
.capabilities = CEDRUS_CAPABILITY_VP8_DEC,
},
{
- .pixelformat = V4L2_PIX_FMT_NV12_32L32,
+ .pixelformat = V4L2_PIX_FMT_NV12,
.directions = CEDRUS_DECODE_DST,
+ .capabilities = CEDRUS_CAPABILITY_UNTILED,
},
{
- .pixelformat = V4L2_PIX_FMT_NV12,
+ .pixelformat = V4L2_PIX_FMT_NV12_32L32,
.directions = CEDRUS_DECODE_DST,
- .capabilities = CEDRUS_CAPABILITY_UNTILED,
},
};
@@ -73,8 +73,8 @@ static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file)
return container_of(file->private_data, struct cedrus_ctx, fh);
}
-static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions,
- unsigned int capabilities)
+static struct cedrus_format *cedrus_find_format(struct cedrus_ctx *ctx,
+ u32 pixelformat, u32 directions)
{
struct cedrus_format *first_valid_fmt = NULL;
struct cedrus_format *fmt;
@@ -83,7 +83,7 @@ static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions,
for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
fmt = &cedrus_formats[i];
- if ((fmt->capabilities & capabilities) != fmt->capabilities ||
+ if (!cedrus_is_capable(ctx, fmt->capabilities) ||
!(fmt->directions & directions))
continue;
@@ -177,19 +177,13 @@ static int cedrus_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
u32 direction)
{
struct cedrus_ctx *ctx = cedrus_file2ctx(file);
- struct cedrus_dev *dev = ctx->dev;
- unsigned int capabilities = dev->capabilities;
- struct cedrus_format *fmt;
unsigned int i, index;
/* Index among formats that match the requested direction. */
index = 0;
for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
- fmt = &cedrus_formats[i];
-
- if (fmt->capabilities && (fmt->capabilities & capabilities) !=
- fmt->capabilities)
+ if (!cedrus_is_capable(ctx, cedrus_formats[i].capabilities))
continue;
if (!(cedrus_formats[i].directions & direction))
@@ -241,15 +235,12 @@ static int cedrus_g_fmt_vid_out(struct file *file, void *priv,
return 0;
}
-static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int cedrus_try_fmt_vid_cap_p(struct cedrus_ctx *ctx,
+ struct v4l2_pix_format *pix_fmt)
{
- struct cedrus_ctx *ctx = cedrus_file2ctx(file);
- struct cedrus_dev *dev = ctx->dev;
- struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
struct cedrus_format *fmt =
- cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST,
- dev->capabilities);
+ cedrus_find_format(ctx, pix_fmt->pixelformat,
+ CEDRUS_DECODE_DST);
if (!fmt)
return -EINVAL;
@@ -262,15 +253,18 @@ static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
+static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cedrus_ctx *ctx = cedrus_file2ctx(file);
- struct cedrus_dev *dev = ctx->dev;
- struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
+ return cedrus_try_fmt_vid_cap_p(cedrus_file2ctx(file), &f->fmt.pix);
+}
+
+static int cedrus_try_fmt_vid_out_p(struct cedrus_ctx *ctx,
+ struct v4l2_pix_format *pix_fmt)
+{
struct cedrus_format *fmt =
- cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC,
- dev->capabilities);
+ cedrus_find_format(ctx, pix_fmt->pixelformat,
+ CEDRUS_DECODE_SRC);
if (!fmt)
return -EINVAL;
@@ -281,6 +275,12 @@ static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
return 0;
}
+static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return cedrus_try_fmt_vid_out_p(cedrus_file2ctx(file), &f->fmt.pix);
+}
+
static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -301,18 +301,76 @@ static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
+void cedrus_reset_cap_format(struct cedrus_ctx *ctx)
+{
+ ctx->dst_fmt.pixelformat = 0;
+ cedrus_try_fmt_vid_cap_p(ctx, &ctx->dst_fmt);
+}
+
+static int cedrus_s_fmt_vid_out_p(struct cedrus_ctx *ctx,
+ struct v4l2_pix_format *pix_fmt)
{
- struct cedrus_ctx *ctx = cedrus_file2ctx(file);
struct vb2_queue *vq;
- struct vb2_queue *peer_vq;
int ret;
- ret = cedrus_try_fmt_vid_out(file, priv, f);
+ ret = cedrus_try_fmt_vid_out_p(ctx, pix_fmt);
if (ret)
return ret;
+ ctx->src_fmt = *pix_fmt;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_H264_SLICE:
+ case V4L2_PIX_FMT_HEVC_SLICE:
+ vq->subsystem_flags |=
+ VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
+ break;
+ default:
+ vq->subsystem_flags &=
+ ~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
+ break;
+ }
+
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_MPEG2_SLICE:
+ ctx->current_codec = &cedrus_dec_ops_mpeg2;
+ break;
+ case V4L2_PIX_FMT_H264_SLICE:
+ ctx->current_codec = &cedrus_dec_ops_h264;
+ break;
+ case V4L2_PIX_FMT_HEVC_SLICE:
+ ctx->current_codec = &cedrus_dec_ops_h265;
+ break;
+ case V4L2_PIX_FMT_VP8_FRAME:
+ ctx->current_codec = &cedrus_dec_ops_vp8;
+ break;
+ }
+
+ /* Propagate format information to capture. */
+ ctx->dst_fmt.colorspace = pix_fmt->colorspace;
+ ctx->dst_fmt.xfer_func = pix_fmt->xfer_func;
+ ctx->dst_fmt.ycbcr_enc = pix_fmt->ycbcr_enc;
+ ctx->dst_fmt.quantization = pix_fmt->quantization;
+ cedrus_reset_cap_format(ctx);
+
+ return 0;
+}
+
+void cedrus_reset_out_format(struct cedrus_ctx *ctx)
+{
+ ctx->src_fmt.pixelformat = 0;
+ cedrus_s_fmt_vid_out_p(ctx, &ctx->src_fmt);
+}
+
+static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+ struct vb2_queue *vq;
+ struct vb2_queue *peer_vq;
+
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
/*
* In order to support dynamic resolution change,
@@ -332,34 +390,7 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
if (vb2_is_busy(peer_vq))
return -EBUSY;
- ret = cedrus_try_fmt_vid_out(file, priv, f);
- if (ret)
- return ret;
-
- ctx->src_fmt = f->fmt.pix;
-
- switch (ctx->src_fmt.pixelformat) {
- case V4L2_PIX_FMT_H264_SLICE:
- case V4L2_PIX_FMT_HEVC_SLICE:
- vq->subsystem_flags |=
- VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
- break;
- default:
- vq->subsystem_flags &=
- ~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
- break;
- }
-
- /* Propagate format information to capture. */
- ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
- ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
- ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
- ctx->dst_fmt.quantization = f->fmt.pix.quantization;
- ctx->dst_fmt.width = ctx->src_fmt.width;
- ctx->dst_fmt.height = ctx->src_fmt.height;
- cedrus_prepare_format(&ctx->dst_fmt);
-
- return 0;
+ return cedrus_s_fmt_vid_out_p(cedrus_file2ctx(file), &f->fmt.pix);
}
const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
@@ -475,34 +506,13 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
struct cedrus_dev *dev = ctx->dev;
int ret = 0;
- switch (ctx->src_fmt.pixelformat) {
- case V4L2_PIX_FMT_MPEG2_SLICE:
- ctx->current_codec = CEDRUS_CODEC_MPEG2;
- break;
-
- case V4L2_PIX_FMT_H264_SLICE:
- ctx->current_codec = CEDRUS_CODEC_H264;
- break;
-
- case V4L2_PIX_FMT_HEVC_SLICE:
- ctx->current_codec = CEDRUS_CODEC_H265;
- break;
-
- case V4L2_PIX_FMT_VP8_FRAME:
- ctx->current_codec = CEDRUS_CODEC_VP8;
- break;
-
- default:
- return -EINVAL;
- }
-
if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
ret = pm_runtime_resume_and_get(dev->dev);
if (ret < 0)
goto err_cleanup;
- if (dev->dec_ops[ctx->current_codec]->start) {
- ret = dev->dec_ops[ctx->current_codec]->start(ctx);
+ if (ctx->current_codec->start) {
+ ret = ctx->current_codec->start(ctx);
if (ret)
goto err_pm;
}
@@ -524,8 +534,8 @@ static void cedrus_stop_streaming(struct vb2_queue *vq)
struct cedrus_dev *dev = ctx->dev;
if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
- if (dev->dec_ops[ctx->current_codec]->stop)
- dev->dec_ops[ctx->current_codec]->stop(ctx);
+ if (ctx->current_codec->stop)
+ ctx->current_codec->stop(ctx);
pm_runtime_put(dev->dev);
}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.h b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
index 05050c0a0921..8e1afc16a6a1 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
@@ -27,5 +27,7 @@ extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq);
void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt);
+void cedrus_reset_cap_format(struct cedrus_ctx *ctx);
+void cedrus_reset_out_format(struct cedrus_ctx *ctx);
#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
index f7714baae37d..969677a3bbf9 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
@@ -662,7 +662,7 @@ static int cedrus_vp8_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
int header_size;
u32 reg;
- cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8);
+ cedrus_engine_enable(ctx);
cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8);
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index b26e44adb2be..426e653bd55d 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -433,7 +433,7 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
for (i = 0; i < chan->numgangports; i++)
chan->csi_port_nums[i] = port_num + i * CSI_PORTS_PER_BRICK;
- chan->of_node = node;
+ chan->of_node = of_node_get(node);
chan->numpads = num_pads;
if (num_pads & 0x2) {
chan->pads[0].flags = MEDIA_PAD_FL_SINK;
@@ -448,6 +448,7 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
chan->mipi = tegra_mipi_request(csi->dev, node);
if (IS_ERR(chan->mipi)) {
ret = PTR_ERR(chan->mipi);
+ chan->mipi = NULL;
dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
}
@@ -640,6 +641,7 @@ static void tegra_csi_channels_cleanup(struct tegra_csi *csi)
media_entity_cleanup(&subdev->entity);
}
+ of_node_put(chan->of_node);
list_del(&chan->list);
kfree(chan);
}
diff --git a/drivers/staging/media/tegra-video/csi.h b/drivers/staging/media/tegra-video/csi.h
index 4ee05a1785cf..6960ea2e3d36 100644
--- a/drivers/staging/media/tegra-video/csi.h
+++ b/drivers/staging/media/tegra-video/csi.h
@@ -56,7 +56,7 @@ struct tegra_csi;
* @framerate: active framerate for TPG
* @h_blank: horizontal blanking for TPG active format
* @v_blank: vertical blanking for TPG active format
- * @mipi: mipi device for corresponding csi channel pads
+ * @mipi: mipi device for corresponding csi channel pads, or NULL if not applicable (TPG, error)
* @pixel_rate: active pixel rate from the sensor on this channel
*/
struct tegra_csi_channel {
diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h
index e74a93475d21..646c4b48b29d 100644
--- a/include/media/davinci/vpbe.h
+++ b/include/media/davinci/vpbe.h
@@ -28,7 +28,7 @@ struct vpbe_output {
*/
char *subdev_name;
/*
- * defualt_mode identifies the default timings set at the venc or
+ * default_mode identifies the default timings set at the venc or
* external encoder.
*/
char *default_mode;
diff --git a/include/uapi/linux/aspeed-video.h b/include/uapi/linux/aspeed-video.h
new file mode 100644
index 000000000000..6586a65548c4
--- /dev/null
+++ b/include/uapi/linux/aspeed-video.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Copyright (C) 2021 ASPEED Technology Inc.
+ */
+
+#ifndef _UAPI_LINUX_ASPEED_VIDEO_H
+#define _UAPI_LINUX_ASPEED_VIDEO_H
+
+#include <linux/v4l2-controls.h>
+
+#define V4L2_CID_ASPEED_HQ_MODE (V4L2_CID_USER_ASPEED_BASE + 1)
+#define V4L2_CID_ASPEED_HQ_JPEG_QUALITY (V4L2_CID_USER_ASPEED_BASE + 2)
+
+#endif /* _UAPI_LINUX_ASPEED_VIDEO_H */
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index d27e255ed33b..410d778c1243 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -231,6 +231,12 @@ enum v4l2_colorfx {
*/
#define V4L2_CID_USER_DW100_BASE (V4L2_CID_USER_BASE + 0x1190)
+/*
+ * The base for Aspeed driver controls.
+ * We reserve 16 controls for this driver.
+ */
+#define V4L2_CID_USER_ASPEED_BASE (V4L2_CID_USER_BASE + 0x11a0)
+
/* MPEG-class control IDs */
/* The MPEG controls are applicable to all codec controls
* and the 'MPEG' part of the define is historical */
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 29da1f4b4578..f91260e79ddc 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -775,6 +775,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* BTTV 8-bit dithered RGB */
#define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') /* Qualcomm 8-bit compressed */
#define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */
+#define V4L2_PIX_FMT_AJPG v4l2_fourcc('A', 'J', 'P', 'G') /* Aspeed JPEG */
/* 10bit raw packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */
#define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */