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(tab[zigzag[i]], scale);
300		reordered_q_tab[i] = jpeg_scale_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(ctx->buffer + LUMA_QUANT_OFF,
323			       ctx->hw_luma_qtable, luma_q_table, scale);
324	jpeg_scale_quant_table(ctx->buffer + CHROMA_QUANT_OFF,
325			       ctx->hw_chroma_qtable, 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