xref: /linux/drivers/media/platform/verisilicon/hantro_jpeg.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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 
28 static 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  */
43 static 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  */
162 static_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  */
170 static_assert(IS_ALIGNED(sizeof(hantro_jpeg_header), 8),
171 	      "Hantro JPEG header size needs to be 8-byte aligned.");
172 
jpeg_scale_qp(const unsigned char qp,int scale)173 static 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 
186 static void
jpeg_scale_quant_table(unsigned char * file_q_tab,unsigned char * reordered_q_tab,const unsigned char * tab,int scale)187 jpeg_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 
jpeg_set_quality(struct hantro_jpeg_ctx * ctx)202 static 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 
hantro_jpeg_header_assemble(struct hantro_jpeg_ctx * ctx)227 void 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 }
246