File Index
Files and directories
Sign in
FILE

hantro_jpeg.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/verisilicon/hantro_jpeg.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) Collabora, Ltd.
  4 *
  5 * Based on GSPCA and CODA drivers:
  6 * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr)
  7 * Copyright (C) 2014 Philipp Zabel, Pengutronix
  8 */
  9
 10#include <linux/align.h>
 11#include <linux/build_bug.h>
 12#include <linux/kernel.h>
 13#include <linux/string.h>
 14#include <media/v4l2-jpeg.h>
 15#include "hantro_jpeg.h"
 16#include "hantro.h"
 17
 18#define LUMA_QUANT_OFF		25
 19#define CHROMA_QUANT_OFF	90
 20#define HEIGHT_OFF		159
 21#define WIDTH_OFF		161
 22
 23#define HUFF_LUMA_DC_OFF	178
 24#define HUFF_LUMA_AC_OFF	211
 25#define HUFF_CHROMA_DC_OFF	394
 26#define HUFF_CHROMA_AC_OFF	427
 27
 28static const u32 hw_reorder[] = {
 29	 0,  8, 16, 24,  1,  9, 17, 25,
 30	32, 40, 48, 56, 33, 41, 49, 57,
 31	 2, 10, 18, 26,  3, 11, 19, 27,
 32	34, 42, 50, 58, 35, 43, 51, 59,
 33	 4, 12, 20, 28,  5, 13, 21, 29,
 34	36, 44, 52, 60, 37, 45, 53, 61,
 35	 6, 14, 22, 30,  7, 15, 23, 31,
 36	38, 46, 54, 62, 39, 47, 55, 63
 37};
 38
 39/* For simplicity, we keep a pre-formatted JPEG header,
 40 * and we'll use fixed offsets to change the width, height
 41 * quantization tables, etc.
 42 */
 43static const unsigned char hantro_jpeg_header[] = {
 44	/* SOI */
 45	0xff, 0xd8,
 46
 47	/* JFIF-APP0 */
 48	0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46,
 49	0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01,
 50	0x00, 0x00,
 51
 52	/* DQT */
 53	0xff, 0xdb, 0x00, 0x84,
 54
 55	0x00,
 56	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 57	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 58	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 59	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 60	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 61	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 62	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 63	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 64
 65	0x01,
 66	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 67	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 68	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 69	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 70	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 71	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 72	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 73	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 74
 75	/* SOF */
 76	0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01,
 77	0x40, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01,
 78	0x03, 0x11, 0x01,
 79
 80	/* DHT */
 81	0xff, 0xc4, 0x00, 0x1f, 0x00,
 82
 83	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 84	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 85	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 86	0x00, 0x00, 0x00, 0x00,
 87
 88	/* DHT */
 89	0xff, 0xc4, 0x00, 0xb5, 0x10,
 90
 91	0x00, 0x00,
 92	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 93	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 94	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 95	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 96	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 97	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 98	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 99	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114
115	/* DHT */
116	0xff, 0xc4, 0x00, 0x1f, 0x01,
117
118	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121	0x00, 0x00, 0x00, 0x00,
122
123	/* DHT */
124	0xff, 0xc4, 0x00, 0xb5, 0x11,
125
126	0x00, 0x00,
127	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149
150	/* COM */
151	0xff, 0xfe, 0x00, 0x03, 0x00,
152
153	/* SOS */
154	0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
155	0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
156};
157
158/*
159 * JPEG_HEADER_SIZE is used in other parts of the driver in lieu of
160 * "sizeof(hantro_jpeg_header)". The two must be equal.
161 */
162static_assert(sizeof(hantro_jpeg_header) == JPEG_HEADER_SIZE);
163
164/*
165 * hantro_jpeg_header is padded with a COM segment, so that the payload
166 * of the SOS segment (the entropy-encoded image scan), which should
167 * trail the whole header, is 8-byte aligned for the hardware to write
168 * to directly.
169 */
170static_assert(IS_ALIGNED(sizeof(hantro_jpeg_header), 8),
171	      "Hantro JPEG header size needs to be 8-byte aligned.");
172
173static unsigned char jpeg_scale_qp(const unsigned char qp, int scale)
174{
175	unsigned int temp;
176
177	temp = DIV_ROUND_CLOSEST((unsigned int)qp * scale, 100);
178	if (temp <= 0)
179		temp = 1;
180	if (temp > 255)
181		temp = 255;
182
183	return (unsigned char)temp;
184}
185
186static void
187jpeg_scale_quant_table(unsigned char *file_q_tab,
188		       unsigned char *reordered_q_tab,
189		       const unsigned char *tab, int scale)
190{
191	int i;
192
193	BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_zigzag_scan_index) != JPEG_QUANT_SIZE);
194	BUILD_BUG_ON(ARRAY_SIZE(hw_reorder) != JPEG_QUANT_SIZE);
195
196	for (i = 0; i < JPEG_QUANT_SIZE; i++) {
197		file_q_tab[i] = jpeg_scale_qp(tab[v4l2_jpeg_zigzag_scan_index[i]], scale);
198		reordered_q_tab[i] = jpeg_scale_qp(tab[hw_reorder[i]], scale);
199	}
200}
201
202static void jpeg_set_quality(struct hantro_jpeg_ctx *ctx)
203{
204	int scale;
205	/*
206	 * Non-linear scaling factor:
207	 * [5,50] -> [1000..100], [51,100] -> [98..0]
208	 */
209	if (ctx->quality < 50)
210		scale = 5000 / ctx->quality;
211	else
212		scale = 200 - 2 * ctx->quality;
213
214	BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_ref_table_luma_qt) != JPEG_QUANT_SIZE);
215	BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_ref_table_chroma_qt) != JPEG_QUANT_SIZE);
216	BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_luma_qtable) != JPEG_QUANT_SIZE);
217	BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_chroma_qtable) != JPEG_QUANT_SIZE);
218
219	jpeg_scale_quant_table(ctx->buffer + LUMA_QUANT_OFF,
220			       ctx->hw_luma_qtable,
221			       (const unsigned char *)v4l2_jpeg_ref_table_luma_qt, scale);
222	jpeg_scale_quant_table(ctx->buffer + CHROMA_QUANT_OFF,
223			       ctx->hw_chroma_qtable,
224			       (const unsigned char *)v4l2_jpeg_ref_table_chroma_qt, scale);
225}
226
227void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
228{
229	char *buf = ctx->buffer;
230
231	memcpy(buf, hantro_jpeg_header,
232	       sizeof(hantro_jpeg_header));
233
234	buf[HEIGHT_OFF + 0] = ctx->height >> 8;
235	buf[HEIGHT_OFF + 1] = ctx->height;
236	buf[WIDTH_OFF + 0] = ctx->width >> 8;
237	buf[WIDTH_OFF + 1] = ctx->width;
238
239	memcpy(buf + HUFF_LUMA_DC_OFF, v4l2_jpeg_ref_table_luma_dc_ht, V4L2_JPEG_REF_HT_DC_LEN);
240	memcpy(buf + HUFF_LUMA_AC_OFF, v4l2_jpeg_ref_table_luma_ac_ht, V4L2_JPEG_REF_HT_AC_LEN);
241	memcpy(buf + HUFF_CHROMA_DC_OFF, v4l2_jpeg_ref_table_chroma_dc_ht, V4L2_JPEG_REF_HT_DC_LEN);
242	memcpy(buf + HUFF_CHROMA_AC_OFF, v4l2_jpeg_ref_table_chroma_ac_ht, V4L2_JPEG_REF_HT_AC_LEN);
243
244	jpeg_set_quality(ctx);
245}
~/ Read-only file preview.