[PATCH v9 3/4] media: aspeed: Support aspeed mode to reduce compressed data
Jammy Huang
jammy_huang at aspeedtech.com
Thu Oct 20 18:25:26 AEDT 2022
Hi Nocolas,
On 2022/10/18 下午 11:20, Nicolas Dufresne wrote:
> Hi,
>
> Le mercredi 21 septembre 2022 à 10:51 +0800, Jammy Huang a écrit :
>> aspeed supports differential jpeg format which only compress the parts
>> which are changed. In this way, it reduces both the amount of data to be
>> transferred by network and those to be decoded on the client side.
>>
>> 2 new ctrls are added:
>> * Aspeed HQ Mode: to control aspeed's high quality(2-pass) compression mode
>> This only works with yuv444 subsampling.
>> * Aspeed HQ Quality: to control the quality of aspeed's HQ mode
>> only useful if Aspeed HQ mode is enabled
>>
>> Aspeed JPEG Format requires an additional buffer, called bcd, to store
>> the information about which macro block in the new frame is different
>> from the previous one.
>>
>> To have bcd correctly working, we need to swap the buffers for src0/1 to
>> make src1 refer to previous frame and src0 to the coming new frame.
>>
>> Signed-off-by: Jammy Huang <jammy_huang at aspeedtech.com>
>> ---
>> drivers/media/platform/aspeed/aspeed-video.c | 281 +++++++++++++++----
>> include/uapi/linux/aspeed-video.h | 15 +
>> 2 files changed, 245 insertions(+), 51 deletions(-)
>> create mode 100644 include/uapi/linux/aspeed-video.h
>>
>> diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c
>> index 20f795ccc11b..739288026418 100644
>> --- a/drivers/media/platform/aspeed/aspeed-video.c
>> +++ b/drivers/media/platform/aspeed/aspeed-video.c
>> @@ -33,6 +33,7 @@
>> #include <media/v4l2-event.h>
>> #include <media/v4l2-ioctl.h>
>> #include <media/videobuf2-dma-contig.h>
>> +#include <uapi/linux/aspeed-video.h>
>>
>> #define ASPEED_VIDEO_V4L2_MIN_BUF_REQ 3
>>
>> @@ -59,6 +60,7 @@
>>
>> #define VE_MAX_SRC_BUFFER_SIZE 0x8ca000 /* 1920 * 1200, 32bpp */
>> #define VE_JPEG_HEADER_SIZE 0x006000 /* 512 * 12 * 4 */
>> +#define VE_BCD_BUFF_SIZE 0x9000 /* (1920/8) * (1200/8) */
>>
>> #define VE_PROTECTION_KEY 0x000
>> #define VE_PROTECTION_KEY_UNLOCK 0x1a038aa8
>> @@ -107,6 +109,13 @@
>> #define VE_SCALING_FILTER2 0x020
>> #define VE_SCALING_FILTER3 0x024
>>
>> +#define VE_BCD_CTRL 0x02C
>> +#define VE_BCD_CTRL_EN_BCD BIT(0)
>> +#define VE_BCD_CTRL_EN_ABCD BIT(1)
>> +#define VE_BCD_CTRL_EN_CB BIT(2)
>> +#define VE_BCD_CTRL_THR GENMASK(23, 16)
>> +#define VE_BCD_CTRL_ABCD_THR GENMASK(31, 24)
>> +
>> #define VE_CAP_WINDOW 0x030
>> #define VE_COMP_WINDOW 0x034
>> #define VE_COMP_PROC_OFFSET 0x038
>> @@ -115,6 +124,7 @@
>> #define VE_SRC0_ADDR 0x044
>> #define VE_SRC_SCANLINE_OFFSET 0x048
>> #define VE_SRC1_ADDR 0x04c
>> +#define VE_BCD_ADDR 0x050
>> #define VE_COMP_ADDR 0x054
>>
>> #define VE_STREAM_BUF_SIZE 0x058
>> @@ -135,6 +145,8 @@
>> #define VE_COMP_CTRL_HQ_DCT_CHR GENMASK(26, 22)
>> #define VE_COMP_CTRL_HQ_DCT_LUM GENMASK(31, 27)
>>
>> +#define VE_CB_ADDR 0x06C
>> +
>> #define AST2400_VE_COMP_SIZE_READ_BACK 0x078
>> #define AST2600_VE_COMP_SIZE_READ_BACK 0x084
>>
>> @@ -211,6 +223,12 @@ enum {
>> VIDEO_CLOCKS_ON,
>> };
>>
>> +enum aspeed_video_format {
>> + VIDEO_FMT_STANDARD = 0,
>> + VIDEO_FMT_ASPEED,
>> + VIDEO_FMT_MAX = VIDEO_FMT_ASPEED
>> +};
>> +
>> // for VE_CTRL_CAPTURE_FMT
>> enum aspeed_video_capture_format {
>> VIDEO_CAP_FMT_YUV_STUDIO_SWING = 0,
>> @@ -245,16 +263,20 @@ struct aspeed_video_perf {
>> /*
>> * struct aspeed_video - driver data
>> *
>> - * res_work: holds the delayed_work for res-detection if unlock
>> - * buffers: holds the list of buffer queued from user
>> + * res_work: holds the delayed_work for res-detection if unlock
>> + * buffers: holds the list of buffer queued from user
>> * flags: holds the state of video
>> * sequence: holds the last number of frame completed
>> * max_compressed_size: holds max compressed stream's size
>> * srcs: holds the buffer information for srcs
>> * jpeg: holds the buffer information for jpeg header
>> + * bcd: holds the buffer information for bcd work
>> * yuv420: a flag raised if JPEG subsampling is 420
>> + * format: holds the video format
>> + * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED
>> * frame_rate: holds the frame_rate
>> * jpeg_quality: holds jpeq's quality (0~11)
>> + * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled
>> * frame_bottom: end position of video data in vertical direction
>> * frame_left: start position of video data in horizontal direction
>> * frame_right: end position of video data in horizontal direction
>> @@ -290,10 +312,14 @@ struct aspeed_video {
>> unsigned int max_compressed_size;
>> struct aspeed_video_addr srcs[2];
>> struct aspeed_video_addr jpeg;
>> + struct aspeed_video_addr bcd;
>>
>> bool yuv420;
>> + enum aspeed_video_format format;
>> + bool hq_mode;
>> unsigned int frame_rate;
>> unsigned int jpeg_quality;
>> + unsigned int jpeg_hq_quality;
>>
>> unsigned int frame_bottom;
>> unsigned int frame_left;
>> @@ -458,8 +484,20 @@ static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = {
>> },
>> };
>>
>> +static const char * const compress_scheme_str[] = {"DCT Only",
>> + "DCT VQ mix 2-color", "DCT VQ mix 4-color"};
>> +static const char * const format_str[] = {"Standard JPEG",
>> + "Aspeed JPEG"};
>> +
>> static unsigned int debug;
>>
>> +static bool aspeed_video_alloc_buf(struct aspeed_video *video,
>> + struct aspeed_video_addr *addr,
>> + unsigned int size);
>> +
>> +static void aspeed_video_free_buf(struct aspeed_video *video,
>> + struct aspeed_video_addr *addr);
>> +
>> static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420)
>> {
>> int i;
>> @@ -547,6 +585,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video)
>> unsigned long flags;
>> struct aspeed_video_buffer *buf;
>> u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL);
>> + bool bcd_buf_need = (video->format != VIDEO_FMT_STANDARD);
>>
>> if (video->v4l2_input_status) {
>> v4l2_warn(&video->v4l2_dev, "No signal; don't start frame\n");
>> @@ -559,6 +598,20 @@ static int aspeed_video_start_frame(struct aspeed_video *video)
>> return -EBUSY;
>> }
>>
>> + if (bcd_buf_need && !video->bcd.size) {
>> + if (!aspeed_video_alloc_buf(video, &video->bcd,
>> + VE_BCD_BUFF_SIZE)) {
>> + dev_err(video->dev, "Failed to allocate BCD buffer\n");
>> + dev_err(video->dev, "don't start frame\n");
>> + return -ENOMEM;
>> + }
>> + aspeed_video_write(video, VE_BCD_ADDR, video->bcd.dma);
>> + v4l2_dbg(1, debug, &video->v4l2_dev, "bcd addr(%#x) size(%d)\n",
>> + video->bcd.dma, video->bcd.size);
>> + } else if (!bcd_buf_need && video->bcd.size) {
>> + aspeed_video_free_buf(video, &video->bcd);
>> + }
>> +
>> spin_lock_irqsave(&video->lock, flags);
>> buf = list_first_entry_or_null(&video->buffers,
>> struct aspeed_video_buffer, link);
>> @@ -657,6 +710,24 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay)
>> schedule_delayed_work(&video->res_work, delay);
>> }
>>
>> +static void aspeed_video_swap_src_buf(struct aspeed_video *v)
>> +{
>> + if (v->format == VIDEO_FMT_STANDARD)
>> + return;
>> +
>> + /* Reset bcd buffer to have a full frame update every 8 frames. */
>> + if (IS_ALIGNED(v->sequence, 8))
>> + memset((u8 *)v->bcd.virt, 0x00, VE_BCD_BUFF_SIZE);
>> +
>> + if (v->sequence & 0x01) {
>> + aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[1].dma);
>> + aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[0].dma);
>> + } else {
>> + aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[0].dma);
>> + aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[1].dma);
>> + }
>> +}
>> +
>> static irqreturn_t aspeed_video_irq(int irq, void *arg)
>> {
>> struct aspeed_video *video = arg;
>> @@ -705,6 +776,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
>>
>> if (sts & VE_INTERRUPT_COMP_COMPLETE) {
>> struct aspeed_video_buffer *buf;
>> + bool empty = true;
>> u32 frame_size = aspeed_video_read(video,
>> video->comp_size_read);
>>
>> @@ -718,13 +790,23 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
>> if (buf) {
>> vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size);
>>
>> - if (!list_is_last(&buf->link, &video->buffers)) {
>> + /*
>> + * aspeed_jpeg requires continuous update.
>> + * On the contrary, standard jpeg can keep last buffer
>> + * to always have the latest result.
>> + */
>> + if (video->format == VIDEO_FMT_STANDARD &&
>> + list_is_last(&buf->link, &video->buffers)) {
>> + empty = false;
>> + v4l2_warn(&video->v4l2_dev, "skip to keep last frame updated\n");
>> + } else {
>> buf->vb.vb2_buf.timestamp = ktime_get_ns();
>> buf->vb.sequence = video->sequence++;
>> buf->vb.field = V4L2_FIELD_NONE;
>> vb2_buffer_done(&buf->vb.vb2_buf,
>> VB2_BUF_STATE_DONE);
>> list_del(&buf->link);
>> + empty = list_empty(&video->buffers);
>> }
>> }
>> spin_unlock(&video->lock);
>> @@ -738,7 +820,10 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
>> aspeed_video_write(video, VE_INTERRUPT_STATUS,
>> VE_INTERRUPT_COMP_COMPLETE);
>> sts &= ~VE_INTERRUPT_COMP_COMPLETE;
>> - if (test_bit(VIDEO_STREAMING, &video->flags) && buf)
>> +
>> + aspeed_video_swap_src_buf(video);
>> +
>> + if (test_bit(VIDEO_STREAMING, &video->flags) && !empty)
>> aspeed_video_start_frame(video);
>> }
>>
>> @@ -1085,10 +1170,14 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
>> FIELD_PREP(VE_TGS_FIRST, video->frame_top) |
>> FIELD_PREP(VE_TGS_LAST,
>> video->frame_bottom + 1));
>> - aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_INT_DE);
>> + aspeed_video_update(video, VE_CTRL,
>> + VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH,
>> + VE_CTRL_INT_DE);
>> } else {
>> v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n");
>> - aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH);
>> + aspeed_video_update(video, VE_CTRL,
>> + VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH,
>> + VE_CTRL_DIRECT_FETCH);
>> }
>>
>> size *= 4;
>> @@ -1121,21 +1210,66 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
>> aspeed_video_free_buf(video, &video->srcs[0]);
>> }
>>
>> -static void aspeed_video_init_regs(struct aspeed_video *video)
>> +static void aspeed_video_update_regs(struct aspeed_video *video)
>> {
>> - u32 comp_ctrl = VE_COMP_CTRL_RSVD |
>> - FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
>> - FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
>> - u32 ctrl = VE_CTRL_AUTO_OR_CURSOR |
>> - FIELD_PREP(VE_CTRL_CAPTURE_FMT, VIDEO_CAP_FMT_YUV_FULL_SWING);
>> - u32 seq_ctrl = video->jpeg_mode;
>> + u8 jpeg_hq_quality = clamp((int)video->jpeg_hq_quality - 1, 0,
>> + ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1);
>> + u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
>> + FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10) |
>> + FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode) |
>> + FIELD_PREP(VE_COMP_CTRL_HQ_DCT_LUM, jpeg_hq_quality) |
>> + FIELD_PREP(VE_COMP_CTRL_HQ_DCT_CHR, jpeg_hq_quality | 0x10);
>> + u32 ctrl = 0;
>> + u32 seq_ctrl = 0;
>> +
>> + v4l2_dbg(1, debug, &video->v4l2_dev, "framerate(%d)\n",
>> + video->frame_rate);
>> + v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg format(%s) subsample(%s)\n",
>> + format_str[video->format],
>> + video->yuv420 ? "420" : "444");
>> + v4l2_dbg(1, debug, &video->v4l2_dev, "compression quality(%d)\n",
>> + video->jpeg_quality);
>> + v4l2_dbg(1, debug, &video->v4l2_dev, "hq_mode(%s) hq_quality(%d)\n",
>> + video->hq_mode ? "on" : "off", video->jpeg_hq_quality);
>> +
>> + if (video->format == VIDEO_FMT_ASPEED)
>> + aspeed_video_update(video, VE_BCD_CTRL, 0, VE_BCD_CTRL_EN_BCD);
>> + else
>> + aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0);
>>
>> if (video->frame_rate)
>> ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate);
>>
>> + if (video->format == VIDEO_FMT_STANDARD) {
>> + comp_ctrl &= ~FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode);
>> + seq_ctrl |= video->jpeg_mode;
>> + }
>> +
>> if (video->yuv420)
>> seq_ctrl |= VE_SEQ_CTRL_YUV420;
>>
>> + if (video->jpeg.virt)
>> + aspeed_video_update_jpeg_table(video->jpeg.virt, video->yuv420);
>> +
>> +
>> + /* Set control registers */
>> + aspeed_video_update(video, VE_SEQ_CTRL,
>> + video->jpeg_mode | VE_SEQ_CTRL_YUV420,
>> + seq_ctrl);
>> + aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC, ctrl);
>> + aspeed_video_update(video, VE_COMP_CTRL,
>> + VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR |
>> + VE_COMP_CTRL_EN_HQ | VE_COMP_CTRL_HQ_DCT_LUM |
>> + VE_COMP_CTRL_HQ_DCT_CHR | VE_COMP_CTRL_VQ_4COLOR |
>> + VE_COMP_CTRL_VQ_DCT_ONLY,
>> + comp_ctrl);
>> +}
>> +
>> +static void aspeed_video_init_regs(struct aspeed_video *video)
>> +{
>> + u32 ctrl = VE_CTRL_AUTO_OR_CURSOR |
>> + FIELD_PREP(VE_CTRL_CAPTURE_FMT, VIDEO_CAP_FMT_YUV_FULL_SWING);
>> +
>> /* Unlock VE registers */
>> aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_UNLOCK);
>>
>> @@ -1150,9 +1284,8 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
>> aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma);
>>
>> /* Set control registers */
>> - aspeed_video_write(video, VE_SEQ_CTRL, seq_ctrl);
>> aspeed_video_write(video, VE_CTRL, ctrl);
>> - aspeed_video_write(video, VE_COMP_CTRL, comp_ctrl);
>> + aspeed_video_write(video, VE_COMP_CTRL, VE_COMP_CTRL_RSVD);
>>
>> /* Don't downscale */
>> aspeed_video_write(video, VE_SCALING_FACTOR, 0x10001000);
>> @@ -1168,6 +1301,8 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
>> FIELD_PREP(VE_MODE_DT_HOR_STABLE, 6) |
>> FIELD_PREP(VE_MODE_DT_VER_STABLE, 6) |
>> FIELD_PREP(VE_MODE_DT_EDG_THROD, 0x65));
>> +
>> + aspeed_video_write(video, VE_BCD_CTRL, 0);
>> }
>>
>> static void aspeed_video_start(struct aspeed_video *video)
>> @@ -1201,6 +1336,9 @@ static void aspeed_video_stop(struct aspeed_video *video)
>> if (video->srcs[1].size)
>> aspeed_video_free_buf(video, &video->srcs[1]);
>>
>> + if (video->bcd.size)
>> + aspeed_video_free_buf(video, &video->bcd);
>> +
>> video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
>> video->flags = 0;
>> }
>> @@ -1219,10 +1357,12 @@ static int aspeed_video_querycap(struct file *file, void *fh,
>> static int aspeed_video_enum_format(struct file *file, void *fh,
>> struct v4l2_fmtdesc *f)
>> {
>> + struct aspeed_video *video = video_drvdata(file);
>> +
>> if (f->index)
>> return -EINVAL;
>>
>> - f->pixelformat = V4L2_PIX_FMT_JPEG;
>> + f->pixelformat = video->pix_fmt.pixelformat;
>>
>> return 0;
>> }
>> @@ -1237,6 +1377,29 @@ static int aspeed_video_get_format(struct file *file, void *fh,
>> return 0;
>> }
>>
>> +static int aspeed_video_set_format(struct file *file, void *fh,
>> + struct v4l2_format *f)
>> +{
>> + struct aspeed_video *video = video_drvdata(file);
>> +
>> + if (vb2_is_busy(&video->queue))
>> + return -EBUSY;
>> +
>> + switch (f->fmt.pix.pixelformat) {
>> + case V4L2_PIX_FMT_JPEG:
>> + video->format = VIDEO_FMT_STANDARD;
>> + break;
>> + case V4L2_PIX_FMT_AJPG:
>> + video->format = VIDEO_FMT_ASPEED;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> + video->pix_fmt.pixelformat = f->fmt.pix.pixelformat;
>> +
>> + return 0;
>> +}
>> +
>> static int aspeed_video_enum_input(struct file *file, void *fh,
>> struct v4l2_input *inp)
>> {
>> @@ -1454,7 +1617,7 @@ static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = {
>>
>> .vidioc_enum_fmt_vid_cap = aspeed_video_enum_format,
>> .vidioc_g_fmt_vid_cap = aspeed_video_get_format,
>> - .vidioc_s_fmt_vid_cap = aspeed_video_get_format,
>> + .vidioc_s_fmt_vid_cap = aspeed_video_set_format,
>> .vidioc_try_fmt_vid_cap = aspeed_video_get_format,
>>
>> .vidioc_reqbufs = vb2_ioctl_reqbufs,
>> @@ -1486,27 +1649,6 @@ static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = {
>> .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
>> };
>>
>> -static void aspeed_video_update_jpeg_quality(struct aspeed_video *video)
>> -{
>> - u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
>> - FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
>> -
>> - aspeed_video_update(video, VE_COMP_CTRL,
>> - VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR,
>> - comp_ctrl);
>> -}
>> -
>> -static void aspeed_video_update_subsampling(struct aspeed_video *video)
>> -{
>> - if (video->jpeg.virt)
>> - aspeed_video_update_jpeg_table(video->jpeg.virt, video->yuv420);
>> -
>> - if (video->yuv420)
>> - aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420);
>> - else
>> - aspeed_video_update(video, VE_SEQ_CTRL, VE_SEQ_CTRL_YUV420, 0);
>> -}
>> -
>> static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
>> {
>> struct aspeed_video *video = container_of(ctrl->handler,
>> @@ -1516,16 +1658,23 @@ static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
>> switch (ctrl->id) {
>> case V4L2_CID_JPEG_COMPRESSION_QUALITY:
>> video->jpeg_quality = ctrl->val;
>> - aspeed_video_update_jpeg_quality(video);
>> + if (test_bit(VIDEO_STREAMING, &video->flags))
>> + aspeed_video_update_regs(video);
>> break;
>> case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
>> - if (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420) {
>> - video->yuv420 = true;
>> - aspeed_video_update_subsampling(video);
>> - } else {
>> - video->yuv420 = false;
>> - aspeed_video_update_subsampling(video);
>> - }
>> + video->yuv420 = (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420);
>> + if (test_bit(VIDEO_STREAMING, &video->flags))
>> + aspeed_video_update_regs(video);
>> + break;
>> + case V4L2_CID_ASPEED_HQ_MODE:
>> + video->hq_mode = ctrl->val;
>> + if (test_bit(VIDEO_STREAMING, &video->flags))
>> + aspeed_video_update_regs(video);
>> + break;
>> + case V4L2_CID_ASPEED_HQ_JPEG_QUALITY:
>> + video->jpeg_hq_quality = ctrl->val;
>> + if (test_bit(VIDEO_STREAMING, &video->flags))
>> + aspeed_video_update_regs(video);
>> break;
>> default:
>> return -EINVAL;
>> @@ -1538,6 +1687,28 @@ static const struct v4l2_ctrl_ops aspeed_video_ctrl_ops = {
>> .s_ctrl = aspeed_video_set_ctrl,
>> };
>>
>> +static const struct v4l2_ctrl_config aspeed_ctrl_HQ_mode = {
>> + .ops = &aspeed_video_ctrl_ops,
>> + .id = V4L2_CID_ASPEED_HQ_MODE,
>> + .name = "Aspeed HQ Mode",
>> + .type = V4L2_CTRL_TYPE_BOOLEAN,
>> + .min = false,
>> + .max = true,
>> + .step = 1,
>> + .def = false,
>> +};
>> +
>> +static const struct v4l2_ctrl_config aspeed_ctrl_HQ_jpeg_quality = {
>> + .ops = &aspeed_video_ctrl_ops,
>> + .id = V4L2_CID_ASPEED_HQ_JPEG_QUALITY,
>> + .name = "Aspeed HQ Quality",
>> + .type = V4L2_CTRL_TYPE_INTEGER,
>> + .min = 1,
>> + .max = ASPEED_VIDEO_JPEG_NUM_QUALITIES,
>> + .step = 1,
>> + .def = 1,
>> +};
>> +
>> static void aspeed_video_resolution_work(struct work_struct *work)
>> {
>> struct delayed_work *dwork = to_delayed_work(work);
>> @@ -1552,6 +1723,8 @@ static void aspeed_video_resolution_work(struct work_struct *work)
>>
>> aspeed_video_init_regs(video);
>>
>> + aspeed_video_update_regs(video);
>> +
>> aspeed_video_get_resolution(video);
>>
>> if (video->detected_timings.width != video->active_timings.width ||
>> @@ -1662,6 +1835,8 @@ static int aspeed_video_start_streaming(struct vb2_queue *q,
>> video->perf.duration_max = 0;
>> video->perf.duration_min = 0xffffffff;
>>
>> + aspeed_video_update_regs(video);
>> +
>> rc = aspeed_video_start_frame(video);
>> if (rc) {
>> aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED);
>> @@ -1800,6 +1975,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
>> struct v4l2_device *v4l2_dev = &video->v4l2_dev;
>> struct vb2_queue *vbq = &video->queue;
>> struct video_device *vdev = &video->vdev;
>> + struct v4l2_ctrl_handler *hdl = &video->ctrl_handler;
>> int rc;
>>
>> video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG;
>> @@ -1814,16 +1990,18 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
>> return rc;
>> }
>>
>> - v4l2_ctrl_handler_init(&video->ctrl_handler, 2);
>> - v4l2_ctrl_new_std(&video->ctrl_handler, &aspeed_video_ctrl_ops,
>> + v4l2_ctrl_handler_init(hdl, 4);
>> + v4l2_ctrl_new_std(hdl, &aspeed_video_ctrl_ops,
>> V4L2_CID_JPEG_COMPRESSION_QUALITY, 0,
>> ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1, 1, 0);
>> - v4l2_ctrl_new_std_menu(&video->ctrl_handler, &aspeed_video_ctrl_ops,
>> + v4l2_ctrl_new_std_menu(hdl, &aspeed_video_ctrl_ops,
>> V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
>> V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask,
>> V4L2_JPEG_CHROMA_SUBSAMPLING_444);
>> + v4l2_ctrl_new_custom(hdl, &aspeed_ctrl_HQ_mode, NULL);
>> + v4l2_ctrl_new_custom(hdl, &aspeed_ctrl_HQ_jpeg_quality, NULL);
>>
>> - rc = video->ctrl_handler.error;
>> + rc = hdl->error;
>> if (rc) {
>> v4l2_ctrl_handler_free(&video->ctrl_handler);
>> v4l2_device_unregister(v4l2_dev);
>> @@ -1832,7 +2010,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
>> return rc;
>> }
>>
>> - v4l2_dev->ctrl_handler = &video->ctrl_handler;
>> + v4l2_dev->ctrl_handler = hdl;
>>
>> vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
>> @@ -1980,6 +2158,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
>> video->comp_size_read = config->comp_size_read;
>>
>> video->frame_rate = 30;
>> + video->jpeg_hq_quality = 1;
>> video->dev = &pdev->dev;
>> spin_lock_init(&video->lock);
>> mutex_init(&video->video_lock);
>> diff --git a/include/uapi/linux/aspeed-video.h b/include/uapi/linux/aspeed-video.h
>> new file mode 100644
>> index 000000000000..63f0432192a5
>> --- /dev/null
>> +++ b/include/uapi/linux/aspeed-video.h
>> @@ -0,0 +1,15 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * 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_COMPRESSION_SCHEME (V4L2_CID_USER_ASPEED_BASE + 1)
>> +#define V4L2_CID_ASPEED_HQ_MODE (V4L2_CID_USER_ASPEED_BASE + 2)
>> +#define V4L2_CID_ASPEED_HQ_JPEG_QUALITY (V4L2_CID_USER_ASPEED_BASE + 3)
> I believe you are missing documentation for these. Even vendor CID get to be
> documented in the RST doc, it also helps us reviewer to judge if these are
> trully vendor controls or should be generalized, its not currently possible to
> make an opinion.
OK, I will add aspeed.rst to disclose related information.
>> +
>> +#endif /* _UAPI_LINUX_ASPEED_VIDEO_H */
--
Best Regards
Jammy
More information about the Linux-aspeed
mailing list