]> Git Repo - J-linux.git/blob - drivers/media/platform/verisilicon/hantro_jpeg.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / media / platform / verisilicon / 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 <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
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
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
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
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 }
This page took 0.041957 seconds and 4 git commands to generate.