Tag branch

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQRSrcquik9wuZrNjXJrQl33mxwedgUCY2U2ZQAKCRBrQl33mxwe
 dhaLAP4t7vpFHF6UwPKhUsnBjykDE9cqX5tFY5hV/P4B3dhm3wEAmJFEi38QFQlb
 gkISSnYIx5DZGP2iBXT96ftGlPI7qgg=
 =wwvs
 -----END PGP SIGNATURE-----

Merge tag 'br-v6.2e' of git://linuxtv.org/hverkuil/media_tree into media_stage

Tag branch

* tag 'br-v6.2e' of git://linuxtv.org/hverkuil/media_tree: (29 commits)
  media: davinci/vpbe: Fix a typo ("defualt_mode")
  media: sun6i-csi: Remove unnecessary print function dev_err()
  media: Documentation: Drop deprecated bytesused == 0
  media: platform: exynos4-is: fix return value check in fimc_md_probe()
  media: dvb-core: remove variable n, turn for-loop to while-loop
  media: vivid: fix compose size exceed boundary
  media: rkisp1: make const arrays ae_wnd_num and hist_wnd_num static
  media: dvb-core: Fix UAF due to refcount races at releasing
  media: rkvdec: Add required padding
  media: aspeed: Extend debug message
  media: aspeed: Support aspeed mode to reduce compressed data
  media: Documentation: aspeed-video: Add user documentation for the aspeed-video driver
  media: v4l2-ctrls: Reserve controls for ASPEED
  media: v4l: Add definition for the Aspeed JPEG format
  staging: media: tegra-video: fix device_node use after free
  staging: media: tegra-video: fix chan->mipi value on error
  media: cedrus: initialize controls a bit later
  media: cedrus: prefer untiled capture format
  media: cedrus: Remove cedrus_codec enum
  media: cedrus: set codec ops immediately
  ...
This commit is contained in:
Mauro Carvalho Chehab 2022-11-15 11:55:54 +00:00
commit a7bab6f8b7
34 changed files with 642 additions and 301 deletions

View File

@ -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.

View File

@ -31,6 +31,7 @@ For more details see the file COPYING in the source distribution of Linux.
:maxdepth: 5 :maxdepth: 5
:numbered: :numbered:
aspeed-video
ccs ccs
cx2341x-uapi cx2341x-uapi
dw100 dw100

View File

@ -187,10 +187,8 @@ struct v4l2_buffer
on the negotiated data format and may change with each buffer for on the negotiated data format and may change with each buffer for
compressed variable size data like JPEG images. Drivers must set compressed variable size data like JPEG images. Drivers must set
this field when ``type`` refers to a capture stream, applications this field when ``type`` refers to a capture stream, applications
when it refers to an output stream. If the application sets this when it refers to an output stream. For multiplanar formats this field
to 0 for an output stream, then ``bytesused`` will be set to the is ignored and the
size of the buffer (see the ``length`` field of this struct) by
the driver. For multiplanar formats this field is ignored and the
``planes`` pointer is used instead. ``planes`` pointer is used instead.
* - __u32 * - __u32
- ``flags`` - ``flags``
@ -327,10 +325,7 @@ struct v4l2_plane
- ``bytesused`` - ``bytesused``
- The number of bytes occupied by data in the plane (its payload). - The number of bytes occupied by data in the plane (its payload).
Drivers must set this field when ``type`` refers to a capture Drivers must set this field when ``type`` refers to a capture
stream, applications when it refers to an output stream. If the stream, applications when it refers to an output stream.
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.
.. note:: .. note::

View File

@ -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 and it is used by various multimedia hardware blocks like GPU, display
controllers, ISP and video accelerators. controllers, ISP and video accelerators.
It contains four planes for progressive video. 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 .. raw:: latex
\normalsize \normalsize

View File

@ -790,6 +790,11 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
if (mutex_lock_interruptible(&dmxdev->mutex)) if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (dmxdev->exit) {
mutex_unlock(&dmxdev->mutex);
return -ENODEV;
}
for (i = 0; i < dmxdev->filternum; i++) for (i = 0; i < dmxdev->filternum; i++)
if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
break; break;
@ -1448,7 +1453,10 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
void dvb_dmxdev_release(struct dmxdev *dmxdev) void dvb_dmxdev_release(struct dmxdev *dmxdev)
{ {
mutex_lock(&dmxdev->mutex);
dmxdev->exit = 1; dmxdev->exit = 1;
mutex_unlock(&dmxdev->mutex);
if (dmxdev->dvbdev->users > 1) { if (dmxdev->dvbdev->users > 1) {
wait_event(dmxdev->dvbdev->wait_queue, wait_event(dmxdev->dvbdev->wait_queue,
dmxdev->dvbdev->users == 1); dmxdev->dvbdev->users == 1);

View File

@ -233,7 +233,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
{ {
struct dvb_demux *demux = feed->demux; struct dvb_demux *demux = feed->demux;
struct dmx_section_feed *sec = &feed->feed.sec; struct dmx_section_feed *sec = &feed->feed.sec;
u16 limit, seclen, n; u16 limit, seclen;
if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
return 0; 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 */ /* to be sure always set secbuf */
sec->secbuf = sec->secbuf_base + sec->secbufp; 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); seclen = section_length(sec->secbuf);
if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
|| seclen + sec->secbufp > limit) || seclen + sec->secbufp > limit)

View File

@ -33,6 +33,7 @@
#include <media/v4l2-event.h> #include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/videobuf2-dma-contig.h> #include <media/videobuf2-dma-contig.h>
#include <uapi/linux/aspeed-video.h>
#define ASPEED_VIDEO_V4L2_MIN_BUF_REQ 3 #define ASPEED_VIDEO_V4L2_MIN_BUF_REQ 3
@ -59,6 +60,7 @@
#define VE_MAX_SRC_BUFFER_SIZE 0x8ca000 /* 1920 * 1200, 32bpp */ #define VE_MAX_SRC_BUFFER_SIZE 0x8ca000 /* 1920 * 1200, 32bpp */
#define VE_JPEG_HEADER_SIZE 0x006000 /* 512 * 12 * 4 */ #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 0x000
#define VE_PROTECTION_KEY_UNLOCK 0x1a038aa8 #define VE_PROTECTION_KEY_UNLOCK 0x1a038aa8
@ -107,6 +109,13 @@
#define VE_SCALING_FILTER2 0x020 #define VE_SCALING_FILTER2 0x020
#define VE_SCALING_FILTER3 0x024 #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_CAP_WINDOW 0x030
#define VE_COMP_WINDOW 0x034 #define VE_COMP_WINDOW 0x034
#define VE_COMP_PROC_OFFSET 0x038 #define VE_COMP_PROC_OFFSET 0x038
@ -115,6 +124,7 @@
#define VE_SRC0_ADDR 0x044 #define VE_SRC0_ADDR 0x044
#define VE_SRC_SCANLINE_OFFSET 0x048 #define VE_SRC_SCANLINE_OFFSET 0x048
#define VE_SRC1_ADDR 0x04c #define VE_SRC1_ADDR 0x04c
#define VE_BCD_ADDR 0x050
#define VE_COMP_ADDR 0x054 #define VE_COMP_ADDR 0x054
#define VE_STREAM_BUF_SIZE 0x058 #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_CHR GENMASK(26, 22)
#define VE_COMP_CTRL_HQ_DCT_LUM GENMASK(31, 27) #define VE_COMP_CTRL_HQ_DCT_LUM GENMASK(31, 27)
#define VE_CB_ADDR 0x06C
#define AST2400_VE_COMP_SIZE_READ_BACK 0x078 #define AST2400_VE_COMP_SIZE_READ_BACK 0x078
#define AST2600_VE_COMP_SIZE_READ_BACK 0x084 #define AST2600_VE_COMP_SIZE_READ_BACK 0x084
@ -211,6 +223,12 @@ enum {
VIDEO_CLOCKS_ON, 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 // for VE_CTRL_CAPTURE_FMT
enum aspeed_video_capture_format { enum aspeed_video_capture_format {
VIDEO_CAP_FMT_YUV_STUDIO_SWING = 0, VIDEO_CAP_FMT_YUV_STUDIO_SWING = 0,
@ -245,16 +263,20 @@ struct aspeed_video_perf {
/* /*
* struct aspeed_video - driver data * struct aspeed_video - driver data
* *
* res_work: holds the delayed_work for res-detection if unlock * res_work: holds the delayed_work for res-detection if unlock
* buffers: holds the list of buffer queued from user * buffers: holds the list of buffer queued from user
* flags: holds the state of video * flags: holds the state of video
* sequence: holds the last number of frame completed * sequence: holds the last number of frame completed
* max_compressed_size: holds max compressed stream's size * max_compressed_size: holds max compressed stream's size
* srcs: holds the buffer information for srcs * srcs: holds the buffer information for srcs
* jpeg: holds the buffer information for jpeg header * 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 * 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 * frame_rate: holds the frame_rate
* jpeg_quality: holds jpeq's quality (0~11) * 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_bottom: end position of video data in vertical direction
* frame_left: start position of video data in horizontal direction * frame_left: start position of video data in horizontal direction
* frame_right: end 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; unsigned int max_compressed_size;
struct aspeed_video_addr srcs[2]; struct aspeed_video_addr srcs[2];
struct aspeed_video_addr jpeg; struct aspeed_video_addr jpeg;
struct aspeed_video_addr bcd;
bool yuv420; bool yuv420;
enum aspeed_video_format format;
bool hq_mode;
unsigned int frame_rate; unsigned int frame_rate;
unsigned int jpeg_quality; unsigned int jpeg_quality;
unsigned int jpeg_hq_quality;
unsigned int frame_bottom; unsigned int frame_bottom;
unsigned int frame_left; 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 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) static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420)
{ {
int i; int i;
@ -547,6 +583,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video)
unsigned long flags; unsigned long flags;
struct aspeed_video_buffer *buf; struct aspeed_video_buffer *buf;
u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL); u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL);
bool bcd_buf_need = (video->format != VIDEO_FMT_STANDARD);
if (video->v4l2_input_status) { if (video->v4l2_input_status) {
v4l2_warn(&video->v4l2_dev, "No signal; don't start frame\n"); 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; 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); spin_lock_irqsave(&video->lock, flags);
buf = list_first_entry_or_null(&video->buffers, buf = list_first_entry_or_null(&video->buffers,
struct aspeed_video_buffer, link); 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); 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) static irqreturn_t aspeed_video_irq(int irq, void *arg)
{ {
struct aspeed_video *video = 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) { if (sts & VE_INTERRUPT_COMP_COMPLETE) {
struct aspeed_video_buffer *buf; struct aspeed_video_buffer *buf;
bool empty = true;
u32 frame_size = aspeed_video_read(video, u32 frame_size = aspeed_video_read(video,
video->comp_size_read); video->comp_size_read);
@ -718,13 +788,23 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
if (buf) { if (buf) {
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size); 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.vb2_buf.timestamp = ktime_get_ns();
buf->vb.sequence = video->sequence++; buf->vb.sequence = video->sequence++;
buf->vb.field = V4L2_FIELD_NONE; buf->vb.field = V4L2_FIELD_NONE;
vb2_buffer_done(&buf->vb.vb2_buf, vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_DONE); VB2_BUF_STATE_DONE);
list_del(&buf->link); list_del(&buf->link);
empty = list_empty(&video->buffers);
} }
} }
spin_unlock(&video->lock); 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, aspeed_video_write(video, VE_INTERRUPT_STATUS,
VE_INTERRUPT_COMP_COMPLETE); VE_INTERRUPT_COMP_COMPLETE);
sts &= ~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); 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_FIRST, video->frame_top) |
FIELD_PREP(VE_TGS_LAST, FIELD_PREP(VE_TGS_LAST,
video->frame_bottom + 1)); 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 { } else {
v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n"); 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; size *= 4;
@ -1121,21 +1208,65 @@ err_mem:
aspeed_video_free_buf(video, &video->srcs[0]); 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 | u8 jpeg_hq_quality = clamp((int)video->jpeg_hq_quality - 1, 0,
FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) | ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1);
FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10); u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
u32 ctrl = VE_CTRL_AUTO_OR_CURSOR | FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10) |
FIELD_PREP(VE_CTRL_CAPTURE_FMT, VIDEO_CAP_FMT_YUV_FULL_SWING); FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode) |
u32 seq_ctrl = video->jpeg_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) if (video->frame_rate)
ctrl |= FIELD_PREP(VE_CTRL_FRC, 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) if (video->yuv420)
seq_ctrl |= VE_SEQ_CTRL_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 */ /* Unlock VE registers */
aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_UNLOCK); 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); aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma);
/* Set control registers */ /* Set control registers */
aspeed_video_write(video, VE_SEQ_CTRL, seq_ctrl);
aspeed_video_write(video, VE_CTRL, 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 */ /* Don't downscale */
aspeed_video_write(video, VE_SCALING_FACTOR, 0x10001000); 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_HOR_STABLE, 6) |
FIELD_PREP(VE_MODE_DT_VER_STABLE, 6) | FIELD_PREP(VE_MODE_DT_VER_STABLE, 6) |
FIELD_PREP(VE_MODE_DT_EDG_THROD, 0x65)); 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) 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) if (video->srcs[1].size)
aspeed_video_free_buf(video, &video->srcs[1]); 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->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
video->flags = 0; 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, static int aspeed_video_enum_format(struct file *file, void *fh,
struct v4l2_fmtdesc *f) struct v4l2_fmtdesc *f)
{ {
struct aspeed_video *video = video_drvdata(file);
if (f->index) if (f->index)
return -EINVAL; return -EINVAL;
f->pixelformat = V4L2_PIX_FMT_JPEG; f->pixelformat = video->pix_fmt.pixelformat;
return 0; return 0;
} }
@ -1237,6 +1374,29 @@ static int aspeed_video_get_format(struct file *file, void *fh,
return 0; 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, static int aspeed_video_enum_input(struct file *file, void *fh,
struct v4l2_input *inp) 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_enum_fmt_vid_cap = aspeed_video_enum_format,
.vidioc_g_fmt_vid_cap = aspeed_video_get_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_try_fmt_vid_cap = aspeed_video_get_format,
.vidioc_reqbufs = vb2_ioctl_reqbufs, .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, .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) static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
{ {
struct aspeed_video *video = container_of(ctrl->handler, 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) { switch (ctrl->id) {
case V4L2_CID_JPEG_COMPRESSION_QUALITY: case V4L2_CID_JPEG_COMPRESSION_QUALITY:
video->jpeg_quality = ctrl->val; video->jpeg_quality = ctrl->val;
aspeed_video_update_jpeg_quality(video); if (test_bit(VIDEO_STREAMING, &video->flags))
aspeed_video_update_regs(video);
break; break;
case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
if (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420) { video->yuv420 = (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420);
video->yuv420 = true; if (test_bit(VIDEO_STREAMING, &video->flags))
aspeed_video_update_subsampling(video); aspeed_video_update_regs(video);
} else { break;
video->yuv420 = false; case V4L2_CID_ASPEED_HQ_MODE:
aspeed_video_update_subsampling(video); 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; break;
default: default:
return -EINVAL; return -EINVAL;
@ -1538,6 +1684,28 @@ static const struct v4l2_ctrl_ops aspeed_video_ctrl_ops = {
.s_ctrl = aspeed_video_set_ctrl, .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) static void aspeed_video_resolution_work(struct work_struct *work)
{ {
struct delayed_work *dwork = to_delayed_work(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_init_regs(video);
aspeed_video_update_regs(video);
aspeed_video_get_resolution(video); aspeed_video_get_resolution(video);
if (video->detected_timings.width != video->active_timings.width || 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_max = 0;
video->perf.duration_min = 0xffffffff; video->perf.duration_min = 0xffffffff;
aspeed_video_update_regs(video);
rc = aspeed_video_start_frame(video); rc = aspeed_video_start_frame(video);
if (rc) { if (rc) {
aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED); 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) static int aspeed_video_debugfs_show(struct seq_file *s, void *data)
{ {
struct aspeed_video *v = s->private; struct aspeed_video *v = s->private;
u32 val08;
seq_puts(s, "\n"); 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", seq_printf(s, " %-20s:\t%s\n", "Signal",
v->v4l2_input_status ? "Unlock" : "Lock"); v->v4l2_input_status ? "Unlock" : "Lock");
seq_printf(s, " %-20s:\t%d\n", "Width", v->pix_fmt.width); 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, "\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_puts(s, "Performance:\n");
seq_printf(s, " %-20s:\t%d\n", "Frame#", v->sequence); seq_printf(s, " %-20s:\t%d\n", "Frame#", v->sequence);
seq_printf(s, " %-20s:\n", "Frame Duration(ms)"); 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", "Now", v->perf.duration);
seq_printf(s, " %-18s:\t%d\n", "Min", v->perf.duration_min); 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, " %-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; 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 v4l2_device *v4l2_dev = &video->v4l2_dev;
struct vb2_queue *vbq = &video->queue; struct vb2_queue *vbq = &video->queue;
struct video_device *vdev = &video->vdev; struct video_device *vdev = &video->vdev;
struct v4l2_ctrl_handler *hdl = &video->ctrl_handler;
int rc; int rc;
video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG; video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG;
@ -1814,16 +2023,18 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
return rc; return rc;
} }
v4l2_ctrl_handler_init(&video->ctrl_handler, 2); v4l2_ctrl_handler_init(hdl, 4);
v4l2_ctrl_new_std(&video->ctrl_handler, &aspeed_video_ctrl_ops, v4l2_ctrl_new_std(hdl, &aspeed_video_ctrl_ops,
V4L2_CID_JPEG_COMPRESSION_QUALITY, 0, V4L2_CID_JPEG_COMPRESSION_QUALITY, 0,
ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1, 1, 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_CID_JPEG_CHROMA_SUBSAMPLING,
V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask, V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask,
V4L2_JPEG_CHROMA_SUBSAMPLING_444); 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) { if (rc) {
v4l2_ctrl_handler_free(&video->ctrl_handler); v4l2_ctrl_handler_free(&video->ctrl_handler);
v4l2_device_unregister(v4l2_dev); v4l2_device_unregister(v4l2_dev);
@ -1832,7 +2043,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
return rc; return rc;
} }
v4l2_dev->ctrl_handler = &video->ctrl_handler; v4l2_dev->ctrl_handler = hdl;
vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; 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->comp_size_read = config->comp_size_read;
video->frame_rate = 30; video->frame_rate = 30;
video->jpeg_hq_quality = 1;
video->dev = &pdev->dev; video->dev = &pdev->dev;
spin_lock_init(&video->lock); spin_lock_init(&video->lock);
mutex_init(&video->video_lock); mutex_init(&video->video_lock);

View File

@ -51,14 +51,14 @@ struct img_sw_addr {
struct img_plane_format { struct img_plane_format {
u32 size; u32 size;
u16 stride; u32 stride;
} __packed; } __packed;
struct img_pix_format { struct img_pix_format {
u16 width; u32 width;
u16 height; u32 height;
u32 colorformat; /* enum mdp_color */ 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]; struct img_plane_format plane_fmt[IMG_MAX_PLANES];
} __packed; } __packed;
@ -72,10 +72,10 @@ struct img_image_buffer {
#define IMG_SUBPIXEL_SHIFT 20 #define IMG_SUBPIXEL_SHIFT 20
struct img_crop { struct img_crop {
s16 left; s32 left;
s16 top; s32 top;
u16 width; u32 width;
u16 height; u32 height;
u32 left_subpix; u32 left_subpix;
u32 top_subpix; u32 top_subpix;
u32 width_subpix; u32 width_subpix;
@ -90,24 +90,24 @@ struct img_crop {
struct img_input { struct img_input {
struct img_image_buffer buffer; struct img_image_buffer buffer;
u16 flags; /* HDR, DRE, dither */ u32 flags; /* HDR, DRE, dither */
} __packed; } __packed;
struct img_output { struct img_output {
struct img_image_buffer buffer; struct img_image_buffer buffer;
struct img_crop crop; struct img_crop crop;
s16 rotation; s32 rotation;
u16 flags; /* H-flip, sharpness, dither */ u32 flags; /* H-flip, sharpness, dither */
} __packed; } __packed;
struct img_ipi_frameparam { struct img_ipi_frameparam {
u32 index; u32 index;
u32 frame_no; u32 frame_no;
struct img_timeval timestamp; struct img_timeval timestamp;
u8 type; /* enum mdp_stream_type */ u32 type; /* enum mdp_stream_type */
u8 state; u32 state;
u8 num_inputs; u32 num_inputs;
u8 num_outputs; u32 num_outputs;
u64 drv_data; u64 drv_data;
struct img_input inputs[IMG_MAX_HW_INPUTS]; struct img_input inputs[IMG_MAX_HW_INPUTS];
struct img_output outputs[IMG_MAX_HW_OUTPUTS]; struct img_output outputs[IMG_MAX_HW_OUTPUTS];
@ -123,51 +123,51 @@ struct img_sw_buffer {
} __packed; } __packed;
struct img_ipi_param { struct img_ipi_param {
u8 usage; u32 usage;
struct img_sw_buffer frm_param; struct img_sw_buffer frm_param;
} __packed; } __packed;
struct img_frameparam { struct img_frameparam {
struct list_head list_entry; struct list_head list_entry;
struct img_ipi_frameparam frameparam; struct img_ipi_frameparam frameparam;
}; } __packed;
/* ISP-MDP generic output information */ /* ISP-MDP generic output information */
struct img_comp_frame { struct img_comp_frame {
u32 output_disable:1; u32 output_disable;
u32 bypass:1; u32 bypass;
u16 in_width; u32 in_width;
u16 in_height; u32 in_height;
u16 out_width; u32 out_width;
u16 out_height; u32 out_height;
struct img_crop crop; struct img_crop crop;
u16 in_total_width; u32 in_total_width;
u16 out_total_width; u32 out_total_width;
} __packed; } __packed;
struct img_region { struct img_region {
s16 left; s32 left;
s16 right; s32 right;
s16 top; s32 top;
s16 bottom; s32 bottom;
} __packed; } __packed;
struct img_offset { struct img_offset {
s16 left; s32 left;
s16 top; s32 top;
u32 left_subpix; u32 left_subpix;
u32 top_subpix; u32 top_subpix;
} __packed; } __packed;
struct img_comp_subfrm { struct img_comp_subfrm {
u32 tile_disable:1; u32 tile_disable;
struct img_region in; struct img_region in;
struct img_region out; struct img_region out;
struct img_offset luma; struct img_offset luma;
struct img_offset chroma; struct img_offset chroma;
s16 out_vertical; /* Output vertical index */ s32 out_vertical; /* Output vertical index */
s16 out_horizontal; /* Output horizontal index */ s32 out_horizontal; /* Output horizontal index */
} __packed; } __packed;
#define IMG_MAX_SUBFRAMES 14 #define IMG_MAX_SUBFRAMES 14
@ -250,8 +250,8 @@ struct isp_data {
} __packed; } __packed;
struct img_compparam { struct img_compparam {
u16 type; /* enum mdp_comp_type */ u32 type; /* enum mdp_comp_id */
u16 id; /* enum mtk_mdp_comp_id */ u32 id; /* engine alias_id */
u32 input; u32 input;
u32 outputs[IMG_MAX_HW_OUTPUTS]; u32 outputs[IMG_MAX_HW_OUTPUTS];
u32 num_outputs; u32 num_outputs;
@ -273,12 +273,12 @@ struct img_mux {
u32 reg; u32 reg;
u32 value; u32 value;
u32 subsys_id; u32 subsys_id;
}; } __packed;
struct img_mmsys_ctrl { struct img_mmsys_ctrl {
struct img_mux sets[IMG_MAX_COMPONENTS * 2]; struct img_mux sets[IMG_MAX_COMPONENTS * 2];
u32 num_sets; u32 num_sets;
}; } __packed;
struct img_config { struct img_config {
struct img_compparam components[IMG_MAX_COMPONENTS]; struct img_compparam components[IMG_MAX_COMPONENTS];

View File

@ -252,10 +252,9 @@ static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
dma_addr_t dma_addr; dma_addr_t dma_addr;
pkt->va_base = kzalloc(size, GFP_KERNEL); pkt->va_base = kzalloc(size, GFP_KERNEL);
if (!pkt->va_base) { if (!pkt->va_base)
kfree(pkt);
return -ENOMEM; return -ENOMEM;
}
pkt->buf_size = size; pkt->buf_size = size;
pkt->cl = (void *)client; 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); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) { if (!cmd) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_cmdq_data; goto err_cancel_job;
} }
if (mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K)) { ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K);
ret = -ENOMEM; if (ret)
goto err_cmdq_data; goto err_free_cmd;
}
comps = kcalloc(param->config->num_components, sizeof(*comps), comps = kcalloc(param->config->num_components, sizeof(*comps),
GFP_KERNEL); GFP_KERNEL);
if (!comps) { if (!comps) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_cmdq_data; goto err_destroy_pkt;
} }
path = kzalloc(sizeof(*path), GFP_KERNEL); path = kzalloc(sizeof(*path), GFP_KERNEL);
if (!path) { if (!path) {
ret = -ENOMEM; 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; 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); ret = mdp_path_ctx_init(mdp, path);
if (ret) { if (ret) {
dev_err(dev, "mdp_path_ctx_init error\n"); 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); ret = mdp_path_config(mdp, cmd, path);
if (ret) { if (ret) {
dev_err(dev, "mdp_path_config error\n"); dev_err(dev, "mdp_path_config error\n");
goto err_cmdq_data; goto err_free_path;
} }
cmdq_pkt_finalize(&cmd->pkt); 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; cmd->mdp_ctx = param->mdp_ctx;
ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps); ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps);
if (ret) { if (ret)
dev_err(dev, "comp %d failed to enable clock!\n", ret); goto err_free_path;
goto err_clock_off;
}
dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev, dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev,
cmd->pkt.pa_base, cmd->pkt.cmd_buf_size, 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; return 0;
err_clock_off: err_clock_off:
mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps); cmd->num_comps);
err_cmdq_data: err_free_path:
mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
kfree(path); kfree(path);
atomic_dec(&mdp->job_count); err_free_comps:
wake_up(&mdp->callback_wq);
if (cmd && cmd->pkt.buf_size > 0)
mdp_cmdq_pkt_destroy(&cmd->pkt);
kfree(comps); kfree(comps);
err_destroy_pkt:
mdp_cmdq_pkt_destroy(&cmd->pkt);
err_free_cmd:
kfree(cmd); kfree(cmd);
err_cancel_job:
atomic_dec(&mdp->job_count);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(mdp_cmdq_send); EXPORT_SYMBOL_GPL(mdp_cmdq_send);

View File

@ -699,12 +699,22 @@ int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp)
dev_err(dev, dev_err(dev,
"Failed to enable clk %d. type:%d id:%d\n", "Failed to enable clk %d. type:%d id:%d\n",
i, comp->type, comp->id); i, comp->type, comp->id);
pm_runtime_put(comp->comp_dev); goto err_revert;
return ret;
} }
} }
return 0; 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) 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 mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num)
{ {
int i; int i, ret;
for (i = 0; i < num; i++) for (i = 0; i < num; i++) {
if (mdp_comp_clock_on(dev, &comps[i]) != 0) ret = mdp_comp_clock_on(dev, &comps[i]);
return ++i; if (ret)
return ret;
}
return 0; return 0;
} }

View File

@ -196,27 +196,27 @@ static int mdp_probe(struct platform_device *pdev)
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS); mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS);
if (!mm_pdev) { if (!mm_pdev) {
ret = -ENODEV; ret = -ENODEV;
goto err_return; goto err_destroy_device;
} }
mdp->mdp_mmsys = &mm_pdev->dev; mdp->mdp_mmsys = &mm_pdev->dev;
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX); mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX);
if (WARN_ON(!mm_pdev)) { if (WARN_ON(!mm_pdev)) {
ret = -ENODEV; ret = -ENODEV;
goto err_return; goto err_destroy_device;
} }
for (i = 0; i < MDP_PIPE_MAX; i++) { for (i = 0; i < MDP_PIPE_MAX; i++) {
mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev); mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev);
if (!mdp->mdp_mutex[i]) { if (!mdp->mdp_mutex[i]) {
ret = -ENODEV; ret = -ENODEV;
goto err_return; goto err_free_mutex;
} }
} }
ret = mdp_comp_config(mdp); ret = mdp_comp_config(mdp);
if (ret) { if (ret) {
dev_err(dev, "Failed to config mdp components\n"); 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); mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);
@ -287,11 +287,12 @@ err_destroy_job_wq:
destroy_workqueue(mdp->job_wq); destroy_workqueue(mdp->job_wq);
err_deinit_comp: err_deinit_comp:
mdp_comp_destroy(mdp); mdp_comp_destroy(mdp);
err_return: err_free_mutex:
for (i = 0; i < MDP_PIPE_MAX; i++) 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); kfree(mdp);
err_return:
dev_dbg(dev, "Errno %d\n", ret); dev_dbg(dev, "Errno %d\n", ret);
return ret; return ret;
} }

View File

@ -715,7 +715,7 @@ static void rkisp1_aec_config_v12(struct rkisp1_params *params,
u32 exp_ctrl; u32 exp_ctrl;
u32 block_hsize, block_vsize; u32 block_hsize, block_vsize;
u32 wnd_num_idx = 1; 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 */ /* avoid to override the old enable value */
exp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL); 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 block_hsize, block_vsize;
u32 wnd_num_idx, hist_weight_num, hist_ctrl, value; u32 wnd_num_idx, hist_weight_num, hist_ctrl, value;
u8 weight15x15[RKISP1_CIF_ISP_HIST_WEIGHT_REG_SIZE_V12]; 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 */ /* now we just support 9x9 window */
wnd_num_idx = 1; wnd_num_idx = 1;

View File

@ -1472,7 +1472,7 @@ static int fimc_md_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get(dev); pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(pinctrl)) { if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl); ret = PTR_ERR(pinctrl);
if (ret != EPROBE_DEFER) if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get pinctrl: %d\n", ret); dev_err(dev, "Failed to get pinctrl: %d\n", ret);
goto err_clk; goto err_clk;
} }

View File

@ -913,7 +913,6 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev,
irq = platform_get_irq(platform_dev, 0); irq = platform_get_irq(platform_dev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(dev, "failed to get interrupt\n");
ret = -ENXIO; ret = -ENXIO;
goto error_clock_rate_exclusive; goto error_clock_rate_exclusive;
} }

View File

@ -973,6 +973,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
if (dev->has_compose_cap) { if (dev->has_compose_cap) {
v4l2_rect_set_min_size(compose, &min_rect); v4l2_rect_set_min_size(compose, &min_rect);
v4l2_rect_set_max_size(compose, &max_rect); v4l2_rect_set_max_size(compose, &max_rect);
v4l2_rect_map_inside(compose, &fmt);
} }
dev->fmt_cap_rect = fmt; dev->fmt_cap_rect = fmt;
tpg_s_buf_height(&dev->tpg, fmt.height); tpg_s_buf_height(&dev->tpg, fmt.height);

View File

@ -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_MT21C: descr = "Mediatek Compressed Format"; break;
case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit 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_QC10C: descr = "QCOM Compressed 10-bit Format"; break;
case V4L2_PIX_FMT_AJPG: descr = "Aspeed JPEG"; break;
default: default:
if (fmt->description[0]) if (fmt->description[0])
return; return;

View File

@ -84,6 +84,8 @@ struct rkvdec_vp9_probs {
struct rkvdec_vp9_inter_frame_probs inter; struct rkvdec_vp9_inter_frame_probs inter;
struct rkvdec_vp9_intra_only_frame_probs intra_only; struct rkvdec_vp9_intra_only_frame_probs intra_only;
}; };
/* 128 bit alignment */
u8 padding1[11];
}; };
/* Data structure describing auxiliary buffer format. */ /* Data structure describing auxiliary buffer format. */
@ -1006,6 +1008,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
ctx->priv = vp9_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), priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
&vp9_ctx->priv_tbl.dma, GFP_KERNEL); &vp9_ctx->priv_tbl.dma, GFP_KERNEL);
if (!priv_tbl) { if (!priv_tbl) {

View File

@ -77,56 +77,56 @@ static const struct cedrus_control cedrus_controls[] = {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_MPEG2_SEQUENCE, .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
}, },
.codec = CEDRUS_CODEC_MPEG2, .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_MPEG2_PICTURE, .id = V4L2_CID_STATELESS_MPEG2_PICTURE,
}, },
.codec = CEDRUS_CODEC_MPEG2, .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_MPEG2_QUANTISATION, .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
}, },
.codec = CEDRUS_CODEC_MPEG2, .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
}, },
.codec = CEDRUS_CODEC_H264, .capabilities = CEDRUS_CAPABILITY_H264_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_H264_SLICE_PARAMS, .id = V4L2_CID_STATELESS_H264_SLICE_PARAMS,
}, },
.codec = CEDRUS_CODEC_H264, .capabilities = CEDRUS_CAPABILITY_H264_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_H264_SPS, .id = V4L2_CID_STATELESS_H264_SPS,
.ops = &cedrus_ctrl_ops, .ops = &cedrus_ctrl_ops,
}, },
.codec = CEDRUS_CODEC_H264, .capabilities = CEDRUS_CAPABILITY_H264_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_H264_PPS, .id = V4L2_CID_STATELESS_H264_PPS,
}, },
.codec = CEDRUS_CODEC_H264, .capabilities = CEDRUS_CAPABILITY_H264_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
}, },
.codec = CEDRUS_CODEC_H264, .capabilities = CEDRUS_CAPABILITY_H264_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS, .id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS,
}, },
.codec = CEDRUS_CODEC_H264, .capabilities = CEDRUS_CAPABILITY_H264_DEC,
}, },
{ {
.cfg = { .cfg = {
@ -134,7 +134,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED, .max = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
.def = 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 = { .cfg = {
@ -142,7 +142,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_H264_START_CODE_NONE, .max = V4L2_STATELESS_H264_START_CODE_NONE,
.def = 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, * We only expose supported profiles information,
@ -160,20 +160,20 @@ static const struct cedrus_control cedrus_controls[] = {
.menu_skip_mask = .menu_skip_mask =
BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
}, },
.codec = CEDRUS_CODEC_H264, .capabilities = CEDRUS_CAPABILITY_H264_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_HEVC_SPS, .id = V4L2_CID_STATELESS_HEVC_SPS,
.ops = &cedrus_ctrl_ops, .ops = &cedrus_ctrl_ops,
}, },
.codec = CEDRUS_CODEC_H265, .capabilities = CEDRUS_CAPABILITY_H265_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_HEVC_PPS, .id = V4L2_CID_STATELESS_HEVC_PPS,
}, },
.codec = CEDRUS_CODEC_H265, .capabilities = CEDRUS_CAPABILITY_H265_DEC,
}, },
{ {
.cfg = { .cfg = {
@ -181,13 +181,13 @@ static const struct cedrus_control cedrus_controls[] = {
/* The driver can only handle 1 entry per slice for now */ /* The driver can only handle 1 entry per slice for now */
.dims = { 1 }, .dims = { 1 },
}, },
.codec = CEDRUS_CODEC_H265, .capabilities = CEDRUS_CAPABILITY_H265_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
}, },
.codec = CEDRUS_CODEC_H265, .capabilities = CEDRUS_CAPABILITY_H265_DEC,
}, },
{ {
.cfg = { .cfg = {
@ -197,7 +197,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = 0xffffffff, .max = 0xffffffff,
.step = 1, .step = 1,
}, },
.codec = CEDRUS_CODEC_H265, .capabilities = CEDRUS_CAPABILITY_H265_DEC,
}, },
{ {
.cfg = { .cfg = {
@ -205,7 +205,7 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, .max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
.def = 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 = { .cfg = {
@ -213,19 +213,19 @@ static const struct cedrus_control cedrus_controls[] = {
.max = V4L2_STATELESS_HEVC_START_CODE_NONE, .max = V4L2_STATELESS_HEVC_START_CODE_NONE,
.def = V4L2_STATELESS_HEVC_START_CODE_NONE, .def = V4L2_STATELESS_HEVC_START_CODE_NONE,
}, },
.codec = CEDRUS_CODEC_H265, .capabilities = CEDRUS_CAPABILITY_H265_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_VP8_FRAME, .id = V4L2_CID_STATELESS_VP8_FRAME,
}, },
.codec = CEDRUS_CODEC_VP8, .capabilities = CEDRUS_CAPABILITY_VP8_DEC,
}, },
{ {
.cfg = { .cfg = {
.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, .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_handler *hdl = &ctx->hdl;
struct v4l2_ctrl *ctrl; struct v4l2_ctrl *ctrl;
unsigned int ctrl_size; unsigned int ctrl_size;
unsigned int i; unsigned int i, j;
v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT); v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
if (hdl->error) { if (hdl->error) {
@ -274,7 +274,11 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
if (!ctx->ctrls) if (!ctx->ctrls)
return -ENOMEM; return -ENOMEM;
j = 0;
for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) { 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, ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg,
NULL); NULL);
if (hdl->error) { if (hdl->error) {
@ -289,7 +293,7 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
return hdl->error; return hdl->error;
} }
ctx->ctrls[i] = ctrl; ctx->ctrls[j++] = ctrl;
} }
ctx->fh.ctrl_handler = hdl; ctx->fh.ctrl_handler = hdl;
@ -351,26 +355,18 @@ static int cedrus_open(struct file *file)
file->private_data = &ctx->fh; file->private_data = &ctx->fh;
ctx->dev = dev; 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, ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
&cedrus_queue_init); &cedrus_queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) { if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_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); cedrus_reset_out_format(ctx);
ctx->src_fmt.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE;
/* ret = cedrus_init_ctrls(dev, ctx);
* TILED_NV12 has more strict requirements, so copy the width and if (ret)
* height to src_fmt to ensure that is matches the dst_fmt resolution. goto err_m2m_release;
*/
ctx->src_fmt.width = ctx->dst_fmt.width;
ctx->src_fmt.height = ctx->dst_fmt.height;
cedrus_prepare_format(&ctx->src_fmt);
v4l2_fh_add(&ctx->fh); v4l2_fh_add(&ctx->fh);
@ -378,8 +374,8 @@ static int cedrus_open(struct file *file)
return 0; return 0;
err_ctrls: err_m2m_release:
v4l2_ctrl_handler_free(&ctx->hdl); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
err_free: err_free:
kfree(ctx); kfree(ctx);
mutex_unlock(&dev->dev_mutex); mutex_unlock(&dev->dev_mutex);
@ -460,11 +456,6 @@ static int cedrus_probe(struct platform_device *pdev)
return ret; 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); mutex_init(&dev->dev_mutex);
INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog); INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog);

View File

@ -35,14 +35,6 @@
#define CEDRUS_CAPABILITY_VP8_DEC BIT(4) #define CEDRUS_CAPABILITY_VP8_DEC BIT(4)
#define CEDRUS_CAPABILITY_H265_10_DEC BIT(5) #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 { enum cedrus_irq_status {
CEDRUS_IRQ_NONE, CEDRUS_IRQ_NONE,
CEDRUS_IRQ_ERROR, CEDRUS_IRQ_ERROR,
@ -57,7 +49,7 @@ enum cedrus_h264_pic_type {
struct cedrus_control { struct cedrus_control {
struct v4l2_ctrl_config cfg; struct v4l2_ctrl_config cfg;
enum cedrus_codec codec; unsigned int capabilities;
}; };
struct cedrus_h264_run { struct cedrus_h264_run {
@ -118,7 +110,7 @@ struct cedrus_ctx {
struct v4l2_pix_format src_fmt; struct v4l2_pix_format src_fmt;
struct v4l2_pix_format dst_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_handler hdl;
struct v4l2_ctrl **ctrls; struct v4l2_ctrl **ctrls;
@ -185,7 +177,6 @@ struct cedrus_dev {
struct platform_device *pdev; struct platform_device *pdev;
struct device *dev; struct device *dev;
struct v4l2_m2m_dev *m2m_dev; struct v4l2_m2m_dev *m2m_dev;
struct cedrus_dec_ops *dec_ops[CEDRUS_CODEC_LAST];
/* Device file mutex */ /* Device file mutex */
struct mutex dev_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)); 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); void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id); u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id);

View File

@ -94,7 +94,7 @@ void cedrus_device_run(void *priv)
cedrus_dst_format_set(dev, &ctx->dst_fmt); 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) if (error)
v4l2_err(&ctx->dev->v4l2_dev, v4l2_err(&ctx->dev->v4l2_dev,
"Failed to setup decoding job: %d\n", error); "Failed to setup decoding job: %d\n", error);
@ -110,7 +110,7 @@ void cedrus_device_run(void *priv)
schedule_delayed_work(&dev->watchdog_work, schedule_delayed_work(&dev->watchdog_work,
msecs_to_jiffies(2000)); msecs_to_jiffies(2000));
dev->dec_ops[ctx->current_codec]->trigger(ctx); ctx->current_codec->trigger(ctx);
} else { } else {
v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev,
ctx->fh.m2m_ctx, ctx->fh.m2m_ctx,

View File

@ -497,7 +497,7 @@ static int cedrus_h264_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
{ {
struct cedrus_dev *dev = ctx->dev; 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_SDROT_CTRL, 0);
cedrus_write(dev, VE_H264_EXTRA_BUFFER1, cedrus_write(dev, VE_H264_EXTRA_BUFFER1,

View File

@ -463,7 +463,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
} }
/* Activate H265 engine. */ /* Activate H265 engine. */
cedrus_engine_enable(ctx, CEDRUS_CODEC_H265); cedrus_engine_enable(ctx);
/* Source offset and length in bits. */ /* Source offset and length in bits. */

View File

@ -31,7 +31,7 @@
#include "cedrus_hw.h" #include "cedrus_hw.h"
#include "cedrus_regs.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; 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_REC_WR_MODE_2MB;
reg |= VE_MODE_DDR_MODE_BW_128; reg |= VE_MODE_DDR_MODE_BW_128;
switch (codec) { switch (ctx->src_fmt.pixelformat) {
case CEDRUS_CODEC_MPEG2: case V4L2_PIX_FMT_MPEG2_SLICE:
reg |= VE_MODE_DEC_MPEG; reg |= VE_MODE_DEC_MPEG;
break; break;
/* H.264 and VP8 both use the same decoding mode bit. */ /* H.264 and VP8 both use the same decoding mode bit. */
case CEDRUS_CODEC_H264: case V4L2_PIX_FMT_H264_SLICE:
case CEDRUS_CODEC_VP8: case V4L2_PIX_FMT_VP8_FRAME:
reg |= VE_MODE_DEC_H264; reg |= VE_MODE_DEC_H264;
break; break;
case CEDRUS_CODEC_H265: case V4L2_PIX_FMT_HEVC_SLICE:
reg |= VE_MODE_DEC_H265; reg |= VE_MODE_DEC_H265;
break; break;
@ -132,12 +132,12 @@ static irqreturn_t cedrus_irq(int irq, void *data)
return IRQ_NONE; 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) if (status == CEDRUS_IRQ_NONE)
return IRQ_NONE; return IRQ_NONE;
dev->dec_ops[ctx->current_codec]->irq_disable(ctx); ctx->current_codec->irq_disable(ctx);
dev->dec_ops[ctx->current_codec]->irq_clear(ctx); ctx->current_codec->irq_clear(ctx);
if (status == CEDRUS_IRQ_ERROR) if (status == CEDRUS_IRQ_ERROR)
state = VB2_BUF_STATE_ERROR; state = VB2_BUF_STATE_ERROR;

View File

@ -16,7 +16,7 @@
#ifndef _CEDRUS_HW_H_ #ifndef _CEDRUS_HW_H_
#define _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_engine_disable(struct cedrus_dev *dev);
void cedrus_dst_format_set(struct cedrus_dev *dev, void cedrus_dst_format_set(struct cedrus_dev *dev,

View File

@ -66,7 +66,7 @@ static int cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
quantisation = run->mpeg2.quantisation; quantisation = run->mpeg2.quantisation;
/* Activate MPEG engine. */ /* Activate MPEG engine. */
cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2); cedrus_engine_enable(ctx);
/* Set intra quantisation matrix. */ /* Set intra quantisation matrix. */
matrix = quantisation->intra_quantiser_matrix; matrix = quantisation->intra_quantiser_matrix;

View File

@ -55,15 +55,15 @@ static struct cedrus_format cedrus_formats[] = {
.directions = CEDRUS_DECODE_SRC, .directions = CEDRUS_DECODE_SRC,
.capabilities = CEDRUS_CAPABILITY_VP8_DEC, .capabilities = CEDRUS_CAPABILITY_VP8_DEC,
}, },
{
.pixelformat = V4L2_PIX_FMT_NV12_32L32,
.directions = CEDRUS_DECODE_DST,
},
{ {
.pixelformat = V4L2_PIX_FMT_NV12, .pixelformat = V4L2_PIX_FMT_NV12,
.directions = CEDRUS_DECODE_DST, .directions = CEDRUS_DECODE_DST,
.capabilities = CEDRUS_CAPABILITY_UNTILED, .capabilities = CEDRUS_CAPABILITY_UNTILED,
}, },
{
.pixelformat = V4L2_PIX_FMT_NV12_32L32,
.directions = CEDRUS_DECODE_DST,
},
}; };
#define CEDRUS_FORMATS_COUNT ARRAY_SIZE(cedrus_formats) #define CEDRUS_FORMATS_COUNT ARRAY_SIZE(cedrus_formats)
@ -73,8 +73,8 @@ static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file)
return container_of(file->private_data, struct cedrus_ctx, fh); return container_of(file->private_data, struct cedrus_ctx, fh);
} }
static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions, static struct cedrus_format *cedrus_find_format(struct cedrus_ctx *ctx,
unsigned int capabilities) u32 pixelformat, u32 directions)
{ {
struct cedrus_format *first_valid_fmt = NULL; struct cedrus_format *first_valid_fmt = NULL;
struct cedrus_format *fmt; 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++) { for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
fmt = &cedrus_formats[i]; fmt = &cedrus_formats[i];
if ((fmt->capabilities & capabilities) != fmt->capabilities || if (!cedrus_is_capable(ctx, fmt->capabilities) ||
!(fmt->directions & directions)) !(fmt->directions & directions))
continue; continue;
@ -177,19 +177,13 @@ static int cedrus_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
u32 direction) u32 direction)
{ {
struct cedrus_ctx *ctx = cedrus_file2ctx(file); 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; unsigned int i, index;
/* Index among formats that match the requested direction. */ /* Index among formats that match the requested direction. */
index = 0; index = 0;
for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) { for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
fmt = &cedrus_formats[i]; if (!cedrus_is_capable(ctx, cedrus_formats[i].capabilities))
if (fmt->capabilities && (fmt->capabilities & capabilities) !=
fmt->capabilities)
continue; continue;
if (!(cedrus_formats[i].directions & direction)) if (!(cedrus_formats[i].directions & direction))
@ -241,15 +235,12 @@ static int cedrus_g_fmt_vid_out(struct file *file, void *priv,
return 0; return 0;
} }
static int cedrus_try_fmt_vid_cap(struct file *file, void *priv, static int cedrus_try_fmt_vid_cap_p(struct cedrus_ctx *ctx,
struct v4l2_format *f) 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 = struct cedrus_format *fmt =
cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST, cedrus_find_format(ctx, pix_fmt->pixelformat,
dev->capabilities); CEDRUS_DECODE_DST);
if (!fmt) if (!fmt)
return -EINVAL; return -EINVAL;
@ -262,15 +253,18 @@ static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
return 0; 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 v4l2_format *f)
{ {
struct cedrus_ctx *ctx = cedrus_file2ctx(file); return cedrus_try_fmt_vid_cap_p(cedrus_file2ctx(file), &f->fmt.pix);
struct cedrus_dev *dev = ctx->dev; }
struct v4l2_pix_format *pix_fmt = &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 = struct cedrus_format *fmt =
cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC, cedrus_find_format(ctx, pix_fmt->pixelformat,
dev->capabilities); CEDRUS_DECODE_SRC);
if (!fmt) if (!fmt)
return -EINVAL; return -EINVAL;
@ -281,6 +275,12 @@ static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
return 0; 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, static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
@ -301,17 +301,75 @@ static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
return 0; return 0;
} }
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 vb2_queue *vq;
int ret;
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, static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct cedrus_ctx *ctx = cedrus_file2ctx(file); struct cedrus_ctx *ctx = cedrus_file2ctx(file);
struct vb2_queue *vq; struct vb2_queue *vq;
struct vb2_queue *peer_vq; struct vb2_queue *peer_vq;
int ret;
ret = cedrus_try_fmt_vid_out(file, priv, f);
if (ret)
return ret;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
/* /*
@ -332,34 +390,7 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
if (vb2_is_busy(peer_vq)) if (vb2_is_busy(peer_vq))
return -EBUSY; return -EBUSY;
ret = cedrus_try_fmt_vid_out(file, priv, f); return cedrus_s_fmt_vid_out_p(cedrus_file2ctx(file), &f->fmt.pix);
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;
} }
const struct v4l2_ioctl_ops cedrus_ioctl_ops = { 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; struct cedrus_dev *dev = ctx->dev;
int ret = 0; 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)) { if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
ret = pm_runtime_resume_and_get(dev->dev); ret = pm_runtime_resume_and_get(dev->dev);
if (ret < 0) if (ret < 0)
goto err_cleanup; goto err_cleanup;
if (dev->dec_ops[ctx->current_codec]->start) { if (ctx->current_codec->start) {
ret = dev->dec_ops[ctx->current_codec]->start(ctx); ret = ctx->current_codec->start(ctx);
if (ret) if (ret)
goto err_pm; goto err_pm;
} }
@ -524,8 +534,8 @@ static void cedrus_stop_streaming(struct vb2_queue *vq)
struct cedrus_dev *dev = ctx->dev; struct cedrus_dev *dev = ctx->dev;
if (V4L2_TYPE_IS_OUTPUT(vq->type)) { if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
if (dev->dec_ops[ctx->current_codec]->stop) if (ctx->current_codec->stop)
dev->dec_ops[ctx->current_codec]->stop(ctx); ctx->current_codec->stop(ctx);
pm_runtime_put(dev->dev); pm_runtime_put(dev->dev);
} }

View File

@ -27,5 +27,7 @@ extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq); struct vb2_queue *dst_vq);
void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt); 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 #endif

View File

@ -662,7 +662,7 @@ static int cedrus_vp8_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
int header_size; int header_size;
u32 reg; u32 reg;
cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8); cedrus_engine_enable(ctx);
cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8); cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8);

View File

@ -433,7 +433,7 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
for (i = 0; i < chan->numgangports; i++) for (i = 0; i < chan->numgangports; i++)
chan->csi_port_nums[i] = port_num + i * CSI_PORTS_PER_BRICK; 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; chan->numpads = num_pads;
if (num_pads & 0x2) { if (num_pads & 0x2) {
chan->pads[0].flags = MEDIA_PAD_FL_SINK; 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); chan->mipi = tegra_mipi_request(csi->dev, node);
if (IS_ERR(chan->mipi)) { if (IS_ERR(chan->mipi)) {
ret = PTR_ERR(chan->mipi); ret = PTR_ERR(chan->mipi);
chan->mipi = NULL;
dev_err(csi->dev, "failed to get mipi device: %d\n", ret); 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); media_entity_cleanup(&subdev->entity);
} }
of_node_put(chan->of_node);
list_del(&chan->list); list_del(&chan->list);
kfree(chan); kfree(chan);
} }

View File

@ -56,7 +56,7 @@ struct tegra_csi;
* @framerate: active framerate for TPG * @framerate: active framerate for TPG
* @h_blank: horizontal blanking for TPG active format * @h_blank: horizontal blanking for TPG active format
* @v_blank: vertical 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 * @pixel_rate: active pixel rate from the sensor on this channel
*/ */
struct tegra_csi_channel { struct tegra_csi_channel {

View File

@ -28,7 +28,7 @@ struct vpbe_output {
*/ */
char *subdev_name; 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. * external encoder.
*/ */
char *default_mode; char *default_mode;

View File

@ -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 */

View File

@ -231,6 +231,12 @@ enum v4l2_colorfx {
*/ */
#define V4L2_CID_USER_DW100_BASE (V4L2_CID_USER_BASE + 0x1190) #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 */ /* MPEG-class control IDs */
/* The MPEG controls are applicable to all codec controls /* The MPEG controls are applicable to all codec controls
* and the 'MPEG' part of the define is historical */ * and the 'MPEG' part of the define is historical */

View File

@ -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_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_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_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 */ /* 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 */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */