• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <linux/dma-mapping.h>
10 #include <linux/kernel.h>
11 #include <linux/string.h>
12 #include "hantro_jpeg.h"
13 #include "hantro.h"
14 
15 #define LUMA_QUANT_OFF		7
16 #define CHROMA_QUANT_OFF	72
17 #define HEIGHT_OFF		141
18 #define WIDTH_OFF		143
19 
20 #define HUFF_LUMA_DC_OFF	160
21 #define HUFF_LUMA_AC_OFF	193
22 #define HUFF_CHROMA_DC_OFF	376
23 #define HUFF_CHROMA_AC_OFF	409
24 
25 /* Default tables from JPEG ITU-T.81
26  * (ISO/IEC 10918-1) Annex K.3, I
27  */
28 static const unsigned char luma_q_table[] = {
29 	0x10, 0x0b, 0x0a, 0x10, 0x7c, 0x8c, 0x97, 0xa1,
30 	0x0c, 0x0c, 0x0e, 0x13, 0x7e, 0x9e, 0xa0, 0x9b,
31 	0x0e, 0x0d, 0x10, 0x18, 0x8c, 0x9d, 0xa9, 0x9c,
32 	0x0e, 0x11, 0x16, 0x1d, 0x97, 0xbb, 0xb4, 0xa2,
33 	0x12, 0x16, 0x25, 0x38, 0xa8, 0x6d, 0x67, 0xb1,
34 	0x18, 0x23, 0x37, 0x40, 0xb5, 0x68, 0x71, 0xc0,
35 	0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65,
36 	0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0xc7,
37 };
38 
39 static const unsigned char chroma_q_table[] = {
40 	0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63,
41 	0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63,
42 	0x18, 0x1a, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63,
43 	0x2f, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
44 	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
45 	0x63, 0x63, 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 };
49 
50 /* Huffman tables are shared with CODA */
51 static const unsigned char luma_dc_table[] = {
52 	0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
53 	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
55 	0x08, 0x09, 0x0a, 0x0b,
56 };
57 
58 static const unsigned char chroma_dc_table[] = {
59 	0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
60 	0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
61 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
62 	0x08, 0x09, 0x0a, 0x0b,
63 };
64 
65 static const unsigned char luma_ac_table[] = {
66 	0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
67 	0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
68 	0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
69 	0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
70 	0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
71 	0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
72 	0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
73 	0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
74 	0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
75 	0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
76 	0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
77 	0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
78 	0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
79 	0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
80 	0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
81 	0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
82 	0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
83 	0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
84 	0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
85 	0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
86 	0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
87 	0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
88 	0xf9, 0xfa,
89 };
90 
91 static const unsigned char chroma_ac_table[] = {
92 	0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
93 	0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
94 	0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
95 	0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
96 	0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
97 	0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
98 	0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
99 	0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
100 	0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
101 	0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
102 	0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
103 	0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
104 	0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
105 	0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
106 	0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
107 	0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
108 	0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
109 	0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
110 	0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
111 	0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
112 	0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
113 	0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
114 	0xf9, 0xfa,
115 };
116 
117 /* For simplicity, we keep a pre-formatted JPEG header,
118  * and we'll use fixed offsets to change the width, height
119  * quantization tables, etc.
120  */
121 static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = {
122 	/* SOI */
123 	0xff, 0xd8,
124 
125 	/* DQT */
126 	0xff, 0xdb, 0x00, 0x84,
127 
128 	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 
138 	0x01,
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 
148 	/* SOF */
149 	0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01,
150 	0x40, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01,
151 	0x03, 0x11, 0x01,
152 
153 	/* DHT */
154 	0xff, 0xc4, 0x00, 0x1f, 0x00,
155 
156 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 	0x00, 0x00, 0x00, 0x00,
160 
161 	/* DHT */
162 	0xff, 0xc4, 0x00, 0xb5, 0x10,
163 
164 	0x00, 0x00,
165 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 
188 	/* DHT */
189 	0xff, 0xc4, 0x00, 0x1f, 0x01,
190 
191 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194 	0x00, 0x00, 0x00, 0x00,
195 
196 	/* DHT */
197 	0xff, 0xc4, 0x00, 0xb5, 0x11,
198 
199 	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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 
223 	/* SOS */
224 	0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
225 	0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
226 };
227 
228 static void
jpeg_scale_quant_table(unsigned char * q_tab,const unsigned char * tab,int scale)229 jpeg_scale_quant_table(unsigned char *q_tab,
230 		       const unsigned char *tab, int scale)
231 {
232 	unsigned int temp;
233 	int i;
234 
235 	for (i = 0; i < 64; i++) {
236 		temp = DIV_ROUND_CLOSEST((unsigned int)tab[i] * scale, 100);
237 		if (temp <= 0)
238 			temp = 1;
239 		if (temp > 255)
240 			temp = 255;
241 		q_tab[i] = (unsigned char)temp;
242 	}
243 }
244 
jpeg_set_quality(unsigned char * buffer,int quality)245 static void jpeg_set_quality(unsigned char *buffer, int quality)
246 {
247 	int scale;
248 
249 	/*
250 	 * Non-linear scaling factor:
251 	 * [5,50] -> [1000..100], [51,100] -> [98..0]
252 	 */
253 	if (quality < 50)
254 		scale = 5000 / quality;
255 	else
256 		scale = 200 - 2 * quality;
257 
258 	jpeg_scale_quant_table(buffer + LUMA_QUANT_OFF,
259 			       luma_q_table, scale);
260 	jpeg_scale_quant_table(buffer + CHROMA_QUANT_OFF,
261 			       chroma_q_table, scale);
262 }
263 
264 unsigned char *
hantro_jpeg_get_qtable(struct hantro_jpeg_ctx * ctx,int index)265 hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index)
266 {
267 	if (index == 0)
268 		return ctx->buffer + LUMA_QUANT_OFF;
269 	return ctx->buffer + CHROMA_QUANT_OFF;
270 }
271 
hantro_jpeg_header_assemble(struct hantro_jpeg_ctx * ctx)272 void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
273 {
274 	char *buf = ctx->buffer;
275 
276 	memcpy(buf, hantro_jpeg_header,
277 	       sizeof(hantro_jpeg_header));
278 
279 	buf[HEIGHT_OFF + 0] = ctx->height >> 8;
280 	buf[HEIGHT_OFF + 1] = ctx->height;
281 	buf[WIDTH_OFF + 0] = ctx->width >> 8;
282 	buf[WIDTH_OFF + 1] = ctx->width;
283 
284 	memcpy(buf + HUFF_LUMA_DC_OFF, luma_dc_table, sizeof(luma_dc_table));
285 	memcpy(buf + HUFF_LUMA_AC_OFF, luma_ac_table, sizeof(luma_ac_table));
286 	memcpy(buf + HUFF_CHROMA_DC_OFF, chroma_dc_table,
287 	       sizeof(chroma_dc_table));
288 	memcpy(buf + HUFF_CHROMA_AC_OFF, chroma_ac_table,
289 	       sizeof(chroma_ac_table));
290 
291 	jpeg_set_quality(buf, ctx->quality);
292 }
293 
hantro_jpeg_enc_init(struct hantro_ctx * ctx)294 int hantro_jpeg_enc_init(struct hantro_ctx *ctx)
295 {
296 	ctx->jpeg_enc.bounce_buffer.size =
297 		ctx->dst_fmt.plane_fmt[0].sizeimage -
298 		ctx->vpu_dst_fmt->header_size;
299 
300 	ctx->jpeg_enc.bounce_buffer.cpu =
301 		dma_alloc_attrs(ctx->dev->dev,
302 				ctx->jpeg_enc.bounce_buffer.size,
303 				&ctx->jpeg_enc.bounce_buffer.dma,
304 				GFP_KERNEL,
305 				DMA_ATTR_ALLOC_SINGLE_PAGES);
306 	if (!ctx->jpeg_enc.bounce_buffer.cpu)
307 		return -ENOMEM;
308 
309 	return 0;
310 }
311 
hantro_jpeg_enc_exit(struct hantro_ctx * ctx)312 void hantro_jpeg_enc_exit(struct hantro_ctx *ctx)
313 {
314 	dma_free_attrs(ctx->dev->dev,
315 		       ctx->jpeg_enc.bounce_buffer.size,
316 		       ctx->jpeg_enc.bounce_buffer.cpu,
317 		       ctx->jpeg_enc.bounce_buffer.dma,
318 		       DMA_ATTR_ALLOC_SINGLE_PAGES);
319 }
320