1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) Collabora, Ltd.
5 * Based on GSPCA and CODA drivers:
6 * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr)
7 * Copyright (C) 2014 Philipp Zabel, Pengutronix
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"
18 #define LUMA_QUANT_OFF 25
19 #define CHROMA_QUANT_OFF 90
20 #define HEIGHT_OFF 159
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
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
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.
43 static const unsigned char hantro_jpeg_header[] = {
48 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46,
49 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01,
53 0xff, 0xdb, 0x00, 0x84,
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,
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,
76 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01,
77 0x40, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01,
81 0xff, 0xc4, 0x00, 0x1f, 0x00,
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,
89 0xff, 0xc4, 0x00, 0xb5, 0x10,
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,
116 0xff, 0xc4, 0x00, 0x1f, 0x01,
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,
124 0xff, 0xc4, 0x00, 0xb5, 0x11,
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,
151 0xff, 0xfe, 0x00, 0x03, 0x00,
154 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
155 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
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.
162 static_assert(sizeof(hantro_jpeg_header) == JPEG_HEADER_SIZE);
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
170 static_assert(IS_ALIGNED(sizeof(hantro_jpeg_header), 8),
171 "Hantro JPEG header size needs to be 8-byte aligned.");
173 static unsigned char jpeg_scale_qp(const unsigned char qp, int scale)
177 temp = DIV_ROUND_CLOSEST((unsigned int)qp * scale, 100);
183 return (unsigned char)temp;
187 jpeg_scale_quant_table(unsigned char *file_q_tab,
188 unsigned char *reordered_q_tab,
189 const unsigned char *tab, int scale)
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);
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);
202 static void jpeg_set_quality(struct hantro_jpeg_ctx *ctx)
206 * Non-linear scaling factor:
207 * [5,50] -> [1000..100], [51,100] -> [98..0]
209 if (ctx->quality < 50)
210 scale = 5000 / ctx->quality;
212 scale = 200 - 2 * ctx->quality;
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);
219 jpeg_scale_quant_table(ctx->buffer + LUMA_QUANT_OFF,
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);
227 void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
229 char *buf = ctx->buffer;
231 memcpy(buf, hantro_jpeg_header,
232 sizeof(hantro_jpeg_header));
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;
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);
244 jpeg_set_quality(ctx);