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 "hantro_jpeg.h"
15#include "hantro.h"
16
17#define LUMA_QUANT_OFF 25
18#define CHROMA_QUANT_OFF 90
19#define HEIGHT_OFF 159
20#define WIDTH_OFF 161
21
22#define HUFF_LUMA_DC_OFF 178
23#define HUFF_LUMA_AC_OFF 211
24#define HUFF_CHROMA_DC_OFF 394
25#define HUFF_CHROMA_AC_OFF 427
26
27/* Default tables from JPEG ITU-T.81
28 * (ISO/IEC 10918-1) Annex K, tables K.1 and K.2
29 */
30static const unsigned char luma_q_table[] = {
31 0x10, 0x0b, 0x0a, 0x10, 0x18, 0x28, 0x33, 0x3d,
32 0x0c, 0x0c, 0x0e, 0x13, 0x1a, 0x3a, 0x3c, 0x37,
33 0x0e, 0x0d, 0x10, 0x18, 0x28, 0x39, 0x45, 0x38,
34 0x0e, 0x11, 0x16, 0x1d, 0x33, 0x57, 0x50, 0x3e,
35 0x12, 0x16, 0x25, 0x38, 0x44, 0x6d, 0x67, 0x4d,
36 0x18, 0x23, 0x37, 0x40, 0x51, 0x68, 0x71, 0x5c,
37 0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65,
38 0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0x63
39};
40
41static const unsigned char chroma_q_table[] = {
42 0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63,
43 0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63,
44 0x18, 0x1a, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63,
45 0x2f, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
46 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
47 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
48 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
49 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
50};
51
52static const unsigned char zigzag[] = {
53 0, 1, 8, 16, 9, 2, 3, 10,
54 17, 24, 32, 25, 18, 11, 4, 5,
55 12, 19, 26, 33, 40, 48, 41, 34,
56 27, 20, 13, 6, 7, 14, 21, 28,
57 35, 42, 49, 56, 57, 50, 43, 36,
58 29, 22, 15, 23, 30, 37, 44, 51,
59 58, 59, 52, 45, 38, 31, 39, 46,
60 53, 60, 61, 54, 47, 55, 62, 63
61};
62
63static const u32 hw_reorder[] = {
64 0, 8, 16, 24, 1, 9, 17, 25,
65 32, 40, 48, 56, 33, 41, 49, 57,
66 2, 10, 18, 26, 3, 11, 19, 27,
67 34, 42, 50, 58, 35, 43, 51, 59,
68 4, 12, 20, 28, 5, 13, 21, 29,
69 36, 44, 52, 60, 37, 45, 53, 61,
70 6, 14, 22, 30, 7, 15, 23, 31,
71 38, 46, 54, 62, 39, 47, 55, 63
72};
73
74/* Huffman tables are shared with CODA */
75static const unsigned char luma_dc_table[] = {
76 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
77 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
79 0x08, 0x09, 0x0a, 0x0b,
80};
81
82static const unsigned char chroma_dc_table[] = {
83 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
84 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
86 0x08, 0x09, 0x0a, 0x0b,
87};
88
89static const unsigned char luma_ac_table[] = {
90 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
91 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
92 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
93 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
94 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
95 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
96 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
97 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
98 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
99 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
100 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
101 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
102 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
103 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
104 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
105 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
106 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
107 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
108 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
109 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
110 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
111 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
112 0xf9, 0xfa,
113};
114
115static const unsigned char chroma_ac_table[] = {
116 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
117 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
118 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
119 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
120 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
121 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
122 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
123 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
124 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
125 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
126 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
127 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
128 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
129 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
130 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
131 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
132 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
133 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
134 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
135 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
136 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
137 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
138 0xf9, 0xfa,
139};
140
141/* For simplicity, we keep a pre-formatted JPEG header,
142 * and we'll use fixed offsets to change the width, height
143 * quantization tables, etc.
144 */
145static const unsigned char hantro_jpeg_header[] = {
146 /* SOI */
147 0xff, 0xd8,
148
149 /* JFIF-APP0 */
150 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46,
151 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01,
152 0x00, 0x00,
153
154 /* DQT */
155 0xff, 0xdb, 0x00, 0x84,
156
157 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166
167 0x01,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176
177 /* SOF */
178 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01,
179 0x40, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01,
180 0x03, 0x11, 0x01,
181
182 /* DHT */
183 0xff, 0xc4, 0x00, 0x1f, 0x00,
184
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x00,
189
190 /* DHT */
191 0xff, 0xc4, 0x00, 0xb5, 0x10,
192
193 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216
217 /* DHT */
218 0xff, 0xc4, 0x00, 0x1f, 0x01,
219
220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x00, 0x00,
224
225 /* DHT */
226 0xff, 0xc4, 0x00, 0xb5, 0x11,
227
228 0x00, 0x00,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251
252 /* COM */
253 0xff, 0xfe, 0x00, 0x03, 0x00,
254
255 /* SOS */
256 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
257 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
258};
259
260/*
261 * JPEG_HEADER_SIZE is used in other parts of the driver in lieu of
262 * "sizeof(hantro_jpeg_header)". The two must be equal.
263 */
264static_assert(sizeof(hantro_jpeg_header) == JPEG_HEADER_SIZE);
265
266/*
267 * hantro_jpeg_header is padded with a COM segment, so that the payload
268 * of the SOS segment (the entropy-encoded image scan), which should
269 * trail the whole header, is 8-byte aligned for the hardware to write
270 * to directly.
271 */
272static_assert(IS_ALIGNED(sizeof(hantro_jpeg_header), 8),
273 "Hantro JPEG header size needs to be 8-byte aligned.");
274
275static unsigned char jpeg_scale_qp(const unsigned char qp, int scale)
276{
277 unsigned int temp;
278
279 temp = DIV_ROUND_CLOSEST((unsigned int)qp * scale, 100);
280 if (temp <= 0)
281 temp = 1;
282 if (temp > 255)
283 temp = 255;
284
285 return (unsigned char)temp;
286}
287
288static void
289jpeg_scale_quant_table(unsigned char *file_q_tab,
290 unsigned char *reordered_q_tab,
291 const unsigned char *tab, int scale)
292{
293 int i;
294
295 BUILD_BUG_ON(ARRAY_SIZE(zigzag) != JPEG_QUANT_SIZE);
296 BUILD_BUG_ON(ARRAY_SIZE(hw_reorder) != JPEG_QUANT_SIZE);
297
298 for (i = 0; i < JPEG_QUANT_SIZE; i++) {
299 file_q_tab[i] = jpeg_scale_qp(qp: tab[zigzag[i]], scale);
300 reordered_q_tab[i] = jpeg_scale_qp(qp: tab[hw_reorder[i]], scale);
301 }
302}
303
304static void jpeg_set_quality(struct hantro_jpeg_ctx *ctx)
305{
306 int scale;
307
308 /*
309 * Non-linear scaling factor:
310 * [5,50] -> [1000..100], [51,100] -> [98..0]
311 */
312 if (ctx->quality < 50)
313 scale = 5000 / ctx->quality;
314 else
315 scale = 200 - 2 * ctx->quality;
316
317 BUILD_BUG_ON(ARRAY_SIZE(luma_q_table) != JPEG_QUANT_SIZE);
318 BUILD_BUG_ON(ARRAY_SIZE(chroma_q_table) != JPEG_QUANT_SIZE);
319 BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_luma_qtable) != JPEG_QUANT_SIZE);
320 BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_chroma_qtable) != JPEG_QUANT_SIZE);
321
322 jpeg_scale_quant_table(file_q_tab: ctx->buffer + LUMA_QUANT_OFF,
323 reordered_q_tab: ctx->hw_luma_qtable, tab: luma_q_table, scale);
324 jpeg_scale_quant_table(file_q_tab: ctx->buffer + CHROMA_QUANT_OFF,
325 reordered_q_tab: ctx->hw_chroma_qtable, tab: chroma_q_table, scale);
326}
327
328void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
329{
330 char *buf = ctx->buffer;
331
332 memcpy(buf, hantro_jpeg_header,
333 sizeof(hantro_jpeg_header));
334
335 buf[HEIGHT_OFF + 0] = ctx->height >> 8;
336 buf[HEIGHT_OFF + 1] = ctx->height;
337 buf[WIDTH_OFF + 0] = ctx->width >> 8;
338 buf[WIDTH_OFF + 1] = ctx->width;
339
340 memcpy(buf + HUFF_LUMA_DC_OFF, luma_dc_table, sizeof(luma_dc_table));
341 memcpy(buf + HUFF_LUMA_AC_OFF, luma_ac_table, sizeof(luma_ac_table));
342 memcpy(buf + HUFF_CHROMA_DC_OFF, chroma_dc_table,
343 sizeof(chroma_dc_table));
344 memcpy(buf + HUFF_CHROMA_AC_OFF, chroma_ac_table,
345 sizeof(chroma_ac_table));
346
347 jpeg_set_quality(ctx);
348}
349

source code of linux/drivers/media/platform/verisilicon/hantro_jpeg.c