From patchwork Wed Nov 13 15:05:37 2019
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Philipp Zabel
X-Patchwork-Id: 11242071
Return-Path:
Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org
[172.30.200.123])
by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9677C13B1
for ;
Wed, 13 Nov 2019 15:06:02 +0000 (UTC)
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
by mail.kernel.org (Postfix) with ESMTP id 6EE9422466
for ;
Wed, 13 Nov 2019 15:06:02 +0000 (UTC)
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1727884AbfKMPGC (ORCPT
);
Wed, 13 Nov 2019 10:06:02 -0500
Received: from metis.ext.pengutronix.de ([85.220.165.71]:38525 "EHLO
metis.ext.pengutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
with ESMTP id S1727820AbfKMPGB (ORCPT
);
Wed, 13 Nov 2019 10:06:01 -0500
Received: from dude02.hi.pengutronix.de ([2001:67c:670:100:1d::28]
helo=dude02.pengutronix.de.)
by metis.ext.pengutronix.de with esmtp (Exim 4.92)
(envelope-from )
id 1iUuDY-00064Z-4O; Wed, 13 Nov 2019 16:06:00 +0100
From: Philipp Zabel
To: linux-media@vger.kernel.org
Cc: Hans Verkuil ,
Mikhail Ulyanov ,
Andrzej Pietrasiewicz ,
Jacek Anaszewski ,
Sylwester Nawrocki ,
Rick Chang ,
Bin Liu ,
Ezequiel Garcia ,
Mirela Rabulea , kernel@pengutronix.de
Subject: [PATCH 4/5] media: s5p-jpeg: use v4l2 JPEG helpers
Date: Wed, 13 Nov 2019 16:05:37 +0100
Message-Id: <20191113150538.9807-5-p.zabel@pengutronix.de>
X-Mailer: git-send-email 2.20.1
In-Reply-To: <20191113150538.9807-1-p.zabel@pengutronix.de>
References: <20191113150538.9807-1-p.zabel@pengutronix.de>
MIME-Version: 1.0
X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::28
X-SA-Exim-Mail-From: p.zabel@pengutronix.de
X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de);
SAEximRunCond expanded to false
X-PTX-Original-Recipient: linux-media@vger.kernel.org
Sender: linux-media-owner@vger.kernel.org
Precedence: bulk
List-ID:
X-Mailing-List: linux-media@vger.kernel.org
Use the v4l2 JPEG helpers for header parsing.
Signed-off-by: Philipp Zabel
---
drivers/media/platform/Kconfig | 1 +
drivers/media/platform/s5p-jpeg/jpeg-core.c | 388 +++++---------------
drivers/media/platform/s5p-jpeg/jpeg-core.h | 14 +-
3 files changed, 105 insertions(+), 298 deletions(-)
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 34b634c5fcd2..9e338bd26df2 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -281,6 +281,7 @@ config VIDEO_SAMSUNG_S5P_JPEG
depends on VIDEO_DEV && VIDEO_V4L2
depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
+ select V4L2_JPEG_HELPER
select V4L2_MEM2MEM_DEV
help
This is a v4l2 driver for Samsung S5P, EXYNOS3250
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index ac2162235cef..773a396414c9 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -757,75 +758,59 @@ static inline int exynos4_huff_tbl_val(int class, int id)
return __exynos4_huff_tbl(class, id, false);
}
-static int get_byte(struct s5p_jpeg_buffer *buf);
-static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word);
-static void skip(struct s5p_jpeg_buffer *buf, long len);
-
static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
{
struct s5p_jpeg *jpeg = ctx->jpeg;
struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- struct s5p_jpeg_buffer jpeg_buffer;
- unsigned int word;
- int c, x, components;
-
- jpeg_buffer.size = 2; /* Ls */
- jpeg_buffer.data =
- (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2;
- jpeg_buffer.curr = 0;
-
- word = 0;
+ u8 *buffer = vb2_plane_vaddr(&vb->vb2_buf, 0);
+ struct v4l2_jpeg_scan_header scan_header;
+ int i, ret;
- if (get_word_be(&jpeg_buffer, &word))
+ ret = v4l2_jpeg_parse_scan_header(buffer + ctx->out_q.sos + 2,
+ ctx->out_q.sos_len, &scan_header);
+ if (ret < 0)
return;
- jpeg_buffer.size = (long)word - 2;
- jpeg_buffer.data += 2;
- jpeg_buffer.curr = 0;
- components = get_byte(&jpeg_buffer);
- if (components == -1)
- return;
- while (components--) {
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- return;
- x = get_byte(&jpeg_buffer);
- if (x == -1)
- return;
- exynos4_jpeg_select_dec_h_tbl(jpeg->regs, c,
- (((x >> 4) & 0x1) << 1) | (x & 0x1));
- }
+ for (i = 0; i < scan_header.num_components; i++) {
+ struct v4l2_jpeg_scan_component_spec *component;
+ component = &scan_header.component[i];
+ exynos4_jpeg_select_dec_h_tbl(jpeg->regs,
+ component->component_selector,
+ ((component->dc_entropy_coding_table_selector &
+ 0x1) << 1) |
+ (component->ac_entropy_coding_table_selector &
+ 0x1));
+ }
}
static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
{
struct s5p_jpeg *jpeg = ctx->jpeg;
struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- struct s5p_jpeg_buffer jpeg_buffer;
+ u8 *buffer = vb2_plane_vaddr(&vb->vb2_buf, 0);
+ struct v4l2_jpeg_reference huffman_tables[4] = { 0 };
unsigned int word;
int c, i, n, j;
+ int ret;
for (j = 0; j < ctx->out_q.dht.n; ++j) {
- jpeg_buffer.size = ctx->out_q.dht.len[j];
- jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) +
- ctx->out_q.dht.marker[j];
- jpeg_buffer.curr = 0;
+ ret = v4l2_jpeg_parse_huffman_tables(
+ buffer + ctx->out_q.dht.marker[j],
+ ctx->out_q.dht.len[j], huffman_tables);
+ if (ret < 0)
+ return;
+ }
- word = 0;
- while (jpeg_buffer.curr < jpeg_buffer.size) {
- char id, class;
-
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- return;
- id = c & 0xf;
- class = (c >> 4) & 0xf;
+ for (j = 0; j < ARRAY_SIZE(huffman_tables); ++j) {
+ if (huffman_tables[j].start) {
+ char class = (j >> 1) & 1;
+ char id = j & 1;
+
+ word = 0;
n = 0;
for (i = 0; i < 16; ++i) {
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- return;
+ c = huffman_tables[j].start[i];
word |= c << ((i % 4) * 8);
if ((i + 1) % 4 == 0) {
writel(word, jpeg->regs +
@@ -837,9 +822,7 @@ static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
}
word = 0;
for (i = 0; i < n; ++i) {
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- return;
+ c = huffman_tables[j].start[16 + i];
word |= c << ((i % 4) * 8);
if ((i + 1) % 4 == 0) {
writel(word, jpeg->regs +
@@ -852,7 +835,6 @@ static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
writel(word, jpeg->regs +
exynos4_huff_tbl_val(class, id) + (i / 4) * 4);
}
- word = 0;
}
}
}
@@ -861,30 +843,26 @@ static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx)
{
struct s5p_jpeg *jpeg = ctx->jpeg;
struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- struct s5p_jpeg_buffer jpeg_buffer;
- int c, x, components;
-
- jpeg_buffer.size = ctx->out_q.sof_len;
- jpeg_buffer.data =
- (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sof;
- jpeg_buffer.curr = 0;
+ u8 *buffer = vb2_plane_vaddr(&vb->vb2_buf, 0);
+ struct v4l2_jpeg_frame_header frame_header;
+ int i, ret;
- skip(&jpeg_buffer, 5); /* P, Y, X */
- components = get_byte(&jpeg_buffer);
- if (components == -1)
+ ret = v4l2_jpeg_parse_frame_header(buffer + ctx->out_q.sof,
+ ctx->out_q.sof_len + 2,
+ &frame_header);
+ if (ret < 0)
return;
- exynos4_jpeg_set_dec_components(jpeg->regs, components);
+ exynos4_jpeg_set_dec_components(jpeg->regs,
+ frame_header.num_components);
- while (components--) {
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- return;
- skip(&jpeg_buffer, 1);
- x = get_byte(&jpeg_buffer);
- if (x == -1)
- return;
- exynos4_jpeg_select_dec_q_tbl(jpeg->regs, c, x);
+ for (i = 0; i < frame_header.num_components; i++) {
+ struct v4l2_jpeg_frame_component_spec *component;
+
+ component = &frame_header.component[i];
+ exynos4_jpeg_select_dec_q_tbl(jpeg->regs,
+ component->component_identifier,
+ component->quantization_table_selector);
}
}
@@ -892,39 +870,33 @@ static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx)
{
struct s5p_jpeg *jpeg = ctx->jpeg;
struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- struct s5p_jpeg_buffer jpeg_buffer;
+ u8 *buffer = vb2_plane_vaddr(&vb->vb2_buf, 0);
+ struct v4l2_jpeg_reference quantization_tables[4] = { 0 };
unsigned int word;
int c, i, j;
+ int ret;
for (j = 0; j < ctx->out_q.dqt.n; ++j) {
- jpeg_buffer.size = ctx->out_q.dqt.len[j];
- jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) +
- ctx->out_q.dqt.marker[j];
- jpeg_buffer.curr = 0;
+ ret = v4l2_jpeg_parse_quantization_tables(buffer +
+ ctx->out_q.dqt.marker[j],
+ ctx->out_q.dqt.len[j], quantization_tables);
+ if (ret < 0)
+ return;
+ }
+
+ for (j = 0; j < 4; ++j) {
+ if (!quantization_tables[j].start)
+ continue;
word = 0;
- while (jpeg_buffer.size - jpeg_buffer.curr >= 65) {
- char id;
-
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- return;
- id = c & 0xf;
- /* nonzero means extended mode - not supported */
- if ((c >> 4) & 0xf)
- return;
- for (i = 0; i < 64; ++i) {
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- return;
- word |= c << ((i % 4) * 8);
- if ((i + 1) % 4 == 0) {
- writel(word, jpeg->regs +
- EXYNOS4_QTBL_CONTENT(id) + (i / 4) * 4);
- word = 0;
- }
+ for (i = 0; i < 64; ++i) {
+ c = quantization_tables[j].start[i];
+ word |= c << ((i % 4) * 8);
+ if ((i + 1) % 4 == 0) {
+ writel(word, jpeg->regs +
+ EXYNOS4_QTBL_CONTENT(j) + (i / 4) * 4);
+ word = 0;
}
- word = 0;
}
}
}
@@ -1036,206 +1008,50 @@ static const struct v4l2_file_operations s5p_jpeg_fops = {
* ============================================================================
*/
-static int get_byte(struct s5p_jpeg_buffer *buf)
-{
- if (buf->curr >= buf->size)
- return -1;
-
- return ((unsigned char *)buf->data)[buf->curr++];
-}
-
-static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
+static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
+ u8 *buffer, unsigned long size,
+ struct s5p_jpeg_ctx *ctx)
{
- unsigned int temp;
- int byte;
-
- byte = get_byte(buf);
- if (byte == -1)
- return -1;
- temp = byte << 8;
- byte = get_byte(buf);
- if (byte == -1)
- return -1;
- *word = (unsigned int)byte | temp;
- return 0;
-}
+ struct v4l2_jpeg_header header;
+ unsigned int subsampling;
+ int i, ret;
-static void skip(struct s5p_jpeg_buffer *buf, long len)
-{
- if (len <= 0)
- return;
+ memset(&header, 0, sizeof(header));
+ ret = v4l2_jpeg_parse_header(buffer, size, &header);
+ if (ret < 0)
+ return false;
- while (len--)
- get_byte(buf);
-}
+ subsampling = (header.frame.num_components == 1) ? 0x33 :
+ (header.frame.component[0].horizontal_sampling_factor << 4) |
+ header.frame.component[0].vertical_sampling_factor;
-static bool s5p_jpeg_subsampling_decode(struct s5p_jpeg_ctx *ctx,
- unsigned int subsampling)
-{
- unsigned int version;
+ /* 4:1:1 subsampling only supported by 3250, 5420, and 5433 variants */
+ if (header.frame.subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_411) {
+ unsigned int version = ctx->jpeg->variant->version;
- switch (subsampling) {
- case 0x11:
- ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
- break;
- case 0x21:
- ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
- break;
- case 0x22:
- ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
- break;
- case 0x33:
- ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
- break;
- case 0x41:
- /*
- * 4:1:1 subsampling only supported by 3250, 5420, and 5433
- * variants
- */
- version = ctx->jpeg->variant->version;
if (version != SJPEG_EXYNOS3250 &&
version != SJPEG_EXYNOS5420 &&
version != SJPEG_EXYNOS5433)
return false;
-
- ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_411;
- break;
- default:
- return false;
- }
-
- return true;
-}
-
-static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
- unsigned long buffer, unsigned long size,
- struct s5p_jpeg_ctx *ctx)
-{
- int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
- unsigned int height = 0, width = 0, word, subsampling = 0;
- unsigned int sos = 0, sof = 0, sof_len = 0;
- unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER];
- unsigned int dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
- long length;
- struct s5p_jpeg_buffer jpeg_buffer;
-
- jpeg_buffer.size = size;
- jpeg_buffer.data = buffer;
- jpeg_buffer.curr = 0;
-
- notfound = 1;
- while (notfound || !sos) {
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- return false;
- if (c != 0xff)
- continue;
- do
- c = get_byte(&jpeg_buffer);
- while (c == 0xff);
- if (c == -1)
- return false;
- if (c == 0)
- continue;
- length = 0;
- switch (c) {
- /* SOF0: baseline JPEG */
- case SOF0:
- if (get_word_be(&jpeg_buffer, &word))
- break;
- length = (long)word - 2;
- if (!length)
- return false;
- sof = jpeg_buffer.curr; /* after 0xffc0 */
- sof_len = length;
- if (get_byte(&jpeg_buffer) == -1)
- break;
- if (get_word_be(&jpeg_buffer, &height))
- break;
- if (get_word_be(&jpeg_buffer, &width))
- break;
- components = get_byte(&jpeg_buffer);
- if (components == -1)
- break;
-
- if (components == 1) {
- subsampling = 0x33;
- } else {
- skip(&jpeg_buffer, 1);
- subsampling = get_byte(&jpeg_buffer);
- skip(&jpeg_buffer, 1);
- }
- if (components > 3)
- return false;
- skip(&jpeg_buffer, components * 2);
- notfound = 0;
- break;
-
- case DQT:
- if (get_word_be(&jpeg_buffer, &word))
- break;
- length = (long)word - 2;
- if (!length)
- return false;
- if (n_dqt >= S5P_JPEG_MAX_MARKER)
- return false;
- dqt[n_dqt] = jpeg_buffer.curr; /* after 0xffdb */
- dqt_len[n_dqt++] = length;
- skip(&jpeg_buffer, length);
- break;
-
- case DHT:
- if (get_word_be(&jpeg_buffer, &word))
- break;
- length = (long)word - 2;
- if (!length)
- return false;
- if (n_dht >= S5P_JPEG_MAX_MARKER)
- return false;
- dht[n_dht] = jpeg_buffer.curr; /* after 0xffc4 */
- dht_len[n_dht++] = length;
- skip(&jpeg_buffer, length);
- break;
-
- case SOS:
- sos = jpeg_buffer.curr - 2; /* 0xffda */
- break;
-
- /* skip payload-less markers */
- case RST ... RST + 7:
- case SOI:
- case EOI:
- case TEM:
- break;
-
- /* skip uninteresting payload markers */
- default:
- if (get_word_be(&jpeg_buffer, &word))
- break;
- length = (long)word - 2;
- skip(&jpeg_buffer, length);
- break;
- }
}
+ ctx->subsampling = header.frame.subsampling;
- if (notfound || !sos || !s5p_jpeg_subsampling_decode(ctx, subsampling))
- return false;
-
- result->w = width;
- result->h = height;
- result->sos = sos;
- result->dht.n = n_dht;
- while (n_dht--) {
- result->dht.marker[n_dht] = dht[n_dht];
- result->dht.len[n_dht] = dht_len[n_dht];
+ result->w = header.frame.width;
+ result->h = header.frame.height;
+ result->sos = header.sos.start - buffer - 2;
+ result->sos_len = header.sos.length;
+ result->dht.n = header.num_dht;
+ for (i = 0; i < header.num_dht; i++) {
+ result->dht.marker[i] = header.dht[i].start - buffer;
+ result->dht.len[i] = header.dht[i].length;
}
- result->dqt.n = n_dqt;
- while (n_dqt--) {
- result->dqt.marker[n_dqt] = dqt[n_dqt];
- result->dqt.len[n_dqt] = dqt_len[n_dqt];
+ result->dqt.n = header.num_dqt;
+ for (i = 0; i < header.num_dqt; i++) {
+ result->dqt.marker[i] = header.dqt[i].start - buffer;
+ result->dqt.len[i] = header.dqt[i].length;
}
- result->sof = sof;
- result->sof_len = sof_len;
+ result->sof = header.sof.start - buffer;
+ result->sof_len = header.sof.length - 2;
return true;
}
@@ -2550,7 +2366,7 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
ori_h = ctx->out_q.h;
ctx->hdr_parsed = s5p_jpeg_parse_hdr(&ctx->out_q,
- (unsigned long)vb2_plane_vaddr(vb, 0),
+ (u8 *)vb2_plane_vaddr(vb, 0),
min((unsigned long)ctx->out_q.size,
vb2_get_plane_payload(vb, 0)), ctx);
if (!ctx->hdr_parsed) {
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 4407fe775afa..9254f1ef9dc4 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -186,6 +186,7 @@ struct s5p_jpeg_marker {
* @w: image width
* @h: image height
* @sos: SOS marker's position relative to the buffer beginning
+ * @sos_len: SOS marker's payload length (including length field)
* @dht: DHT markers' positions relative to the buffer beginning
* @dqt: DQT markers' positions relative to the buffer beginning
* @sof: SOF0 marker's position relative to the buffer beginning
@@ -197,6 +198,7 @@ struct s5p_jpeg_q_data {
u32 w;
u32 h;
u32 sos;
+ u32 sos_len;
struct s5p_jpeg_marker dht;
struct s5p_jpeg_marker dqt;
u32 sof;
@@ -238,18 +240,6 @@ struct s5p_jpeg_ctx {
enum s5p_jpeg_ctx_state state;
};
-/**
- * s5p_jpeg_buffer - description of memory containing input JPEG data
- * @size: buffer size
- * @curr: current position in the buffer
- * @data: pointer to the data
- */
-struct s5p_jpeg_buffer {
- unsigned long size;
- unsigned long curr;
- unsigned long data;
-};
-
/**
* struct s5p_jpeg_addr - JPEG converter physical address set for DMA
* @y: luminance plane physical address