GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / staging / media / hantro / hantro_jpeg.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 "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  */
30 static 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
41 static 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
52 static 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
63 static 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 */
75 static 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
82 static 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
89 static 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
115 static 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  */
145 static 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  */
264 static_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  */
272 static_assert(IS_ALIGNED(sizeof(hantro_jpeg_header), 8),
273               "Hantro JPEG header size needs to be 8-byte aligned.");
274
275 static 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
288 static void
289 jpeg_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
304 static 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
328 void 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 }