mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 13:41:51 +00:00
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:
commit
a7bab6f8b7
65
Documentation/userspace-api/media/drivers/aspeed-video.rst
Normal file
65
Documentation/userspace-api/media/drivers/aspeed-video.rst
Normal 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.
|
@ -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
|
||||||
|
@ -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::
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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];
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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. */
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
14
include/uapi/linux/aspeed-video.h
Normal file
14
include/uapi/linux/aspeed-video.h
Normal 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 */
|
@ -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 */
|
||||||
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user