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