1 /*
2 * Copyright (c) 2021 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_jpeg_drv.h"
9
10 #define HPM_JPEG_DEFAULT_MAX_OT (2)
11
12 const jpeg_sampling_t jpeg_supported_sampling[5] = {
13 {2, 2, 1, 1}, /* 420 */
14 {2, 1, 1, 1}, /* 422H */
15 {1, 2, 1, 1}, /* 422V */
16 {1, 1, 1, 1}, /* 444 */
17 {1, 1, 0, 0}, /* 400 */
18 };
19
20 const jpeg_pixel_t jpeg_supported_pixel_format[6] = {
21 {4, 1, 1, true}, /* JPEG_PIXEL_FORMAT_ARGB8888 */
22 {2, 2, 2, true}, /* JPEG_PIXEL_FORMAT_RGB565 */
23 {2, 3, 0, false}, /* JPEG_PIXEL_FORMAT_YUV422H1P */
24 {1, 0, 0, false}, /* JPEG_PIXEL_FORMAT_YUV422H2P */
25 {1, 0, 0, false}, /* JPEG_PIXEL_FORMAT_YUV420 */
26 {1, 0, 0, false}, /* JPEG_PIXEL_FORMAT_Y8 */
27 };
28
jpeg_disable_irq(JPEG_Type * ptr,uint32_t mask)29 void jpeg_disable_irq(JPEG_Type *ptr, uint32_t mask)
30 {
31 if (mask & JPEG_EVENT_IN_DMA_FINISH) {
32 ptr->INDMA_MISC &= ~(JPEG_INDMA_MISC_IN_DMA_DONE_IRQ_EN_MASK
33 | JPEG_INDMA_MISC_IRQ_EN_MASK);
34 }
35 if (mask & JPEG_EVENT_OUT_DMA_FINISH) {
36 ptr->OUTDMA_MISC &= ~(JPEG_OUTDMA_MISC_OUT_DMA_DONE_IRQ_EN_MASK
37 | JPEG_OUTDMA_MISC_IRQ_EN_MASK);
38 }
39 if (mask & JPEG_EVENT_ERROR) {
40 ptr->CFG &= ~(JPEG_CFG_CODEC_RESTART_ERR_IRQ_EN_MASK);
41 }
42 }
43
jpeg_enable_irq(JPEG_Type * ptr,uint32_t mask)44 void jpeg_enable_irq(JPEG_Type *ptr, uint32_t mask)
45 {
46 if (mask & JPEG_EVENT_IN_DMA_FINISH) {
47 ptr->INDMA_MISC |= JPEG_INDMA_MISC_IN_DMA_DONE_IRQ_EN_MASK
48 | JPEG_INDMA_MISC_IRQ_EN_MASK;
49 }
50 if (mask & JPEG_EVENT_OUT_DMA_FINISH) {
51 ptr->OUTDMA_MISC |= JPEG_OUTDMA_MISC_OUT_DMA_DONE_IRQ_EN_MASK
52 | JPEG_OUTDMA_MISC_IRQ_EN_MASK;
53 }
54 if (mask & JPEG_EVENT_ERROR) {
55 ptr->CFG |= JPEG_CFG_CODEC_RESTART_ERR_IRQ_EN_MASK;
56 }
57 }
58
jpeg_reset(JPEG_Type * ptr)59 void jpeg_reset(JPEG_Type *ptr)
60 {
61 jpeg_stop(ptr);
62 jpeg_software_reset(ptr);
63 ptr->STAT = 0xFFFFFFFFUL;
64
65 }
66
jpeg_init(JPEG_Type * ptr)67 void jpeg_init(JPEG_Type *ptr)
68 {
69 jpeg_reset(ptr);
70 jpeg_clear_cfg(ptr);
71 }
72
jpeg_need_csc(jpeg_pixel_format_t in,jpeg_pixel_format_t out)73 static bool jpeg_need_csc(jpeg_pixel_format_t in, jpeg_pixel_format_t out)
74 {
75 return (jpeg_supported_pixel_format[in].is_rgb != jpeg_supported_pixel_format[out].is_rgb);
76 }
77
jpeg_is_valid_size(uint8_t format,uint32_t width,uint32_t height)78 static bool jpeg_is_valid_size(uint8_t format, uint32_t width, uint32_t height)
79 {
80 uint32_t align;
81 if (format > ARRAY_SIZE(jpeg_supported_sampling)) {
82 return false;
83 }
84 align = jpeg_supported_sampling[format].hy * 8;
85 if (width % align) {
86 return false;
87 }
88 align = jpeg_supported_sampling[format].vy * 8;
89 if (height % align) {
90 return false;
91 }
92 return true;
93 }
94
95 #define JPEG_HY(x) ((x)->hy)
96 #define JPEG_VY(x) ((x)->vy)
97 #define JPEG_HC(x) ((x)->hc)
98 #define JPEG_VC(x) ((x)->vc)
99
jpeg_calculate_macro_block_count(uint32_t width,uint32_t height,jpeg_sampling_t * sampling)100 static uint32_t jpeg_calculate_macro_block_count(uint32_t width, uint32_t height, jpeg_sampling_t *sampling)
101 {
102 return (width / (JPEG_HY(sampling) << 3)) * (height / (JPEG_VY(sampling) << 3));
103 }
104
jpeg_config_interal_regs(JPEG_Type * ptr,bool decoding,uint32_t macro_block_count,uint8_t format)105 static void jpeg_config_interal_regs(JPEG_Type *ptr,
106 bool decoding,
107 uint32_t macro_block_count,
108 uint8_t format)
109 {
110 (void) decoding;
111 uint8_t hy, vy, hc, vc;
112 hy = JPEG_HY(&jpeg_supported_sampling[format]);
113 vy = JPEG_VY(&jpeg_supported_sampling[format]);
114 hc = JPEG_HC(&jpeg_supported_sampling[format]);
115 vc = JPEG_VC(&jpeg_supported_sampling[format]);
116
117 if (format != JPEG_SUPPORTED_FORMAT_400) {
118 ptr->IMGREG1 = JPEG_IMGREG1_NCOL_SET(2);
119 } else {
120 ptr->IMGREG1 = 8;
121 }
122 ptr->IMGREG2 = JPEG_IMGREG2_NMCU_SET(macro_block_count - 1);
123 ptr->IMGREG3 = 0;
124 ptr->IMGREG[0] = JPEG_IMGREG_NBLOCK_SET(hy * vy - 1);
125 if (format == JPEG_SUPPORTED_FORMAT_400) {
126 ptr->IMGREG[1] = 0;
127 ptr->IMGREG[2] = 0;
128 } else {
129 ptr->IMGREG[1] = JPEG_IMGREG_NBLOCK_SET(hc * vc - 1)
130 | JPEG_IMGREG_QT_SET(1)
131 | JPEG_IMGREG_HA_SET(1)
132 | JPEG_IMGREG_HD_SET(1);
133 ptr->IMGREG[2] = JPEG_IMGREG_NBLOCK_SET(hc * vc - 1)
134 | JPEG_IMGREG_QT_SET(1)
135 | JPEG_IMGREG_HA_SET(1)
136 | JPEG_IMGREG_HD_SET(1);
137 }
138 ptr->IMGREG[3] = 0;
139 }
140
jpeg_start_encode(JPEG_Type * ptr,jpeg_job_config_t * config)141 hpm_stat_t jpeg_start_encode(JPEG_Type *ptr, jpeg_job_config_t *config)
142 {
143 uint32_t macro_block_count;
144 uint32_t macro_block_bytes;
145 uint32_t total_bytes;
146 jpeg_sampling_t *sampling;
147
148 if (!jpeg_is_valid_size(config->jpeg_format, config->width_in_pixel, config->height_in_pixel)) {
149 return status_invalid_argument;
150 }
151
152 jpeg_disable(ptr);
153 jpeg_software_reset(ptr);
154
155 sampling = (jpeg_sampling_t *)&jpeg_supported_sampling[config->jpeg_format];
156 macro_block_count = jpeg_calculate_macro_block_count(config->width_in_pixel, config->height_in_pixel, sampling);
157 macro_block_bytes = (JPEG_HY(sampling) * JPEG_VY(sampling)
158 + 2 * JPEG_HC(sampling) * JPEG_VC(sampling)) << 6;
159 total_bytes = macro_block_count * macro_block_bytes;
160
161 /* input DMA setting */
162 ptr->INDMA_MISC = JPEG_INDMA_MISC_IN_DMA_ID_SET(0)
163 | JPEG_INDMA_MISC_MAX_OT_SET(HPM_JPEG_DEFAULT_MAX_OT)
164 | JPEG_INDMA_MISC_INDMA2D_MASK
165 | JPEG_INDMA_MISC_IN_DMA_REQ_MASK
166 | JPEG_INDMA_MISC_PACK_DIR_SET(config->in_byte_order);
167 ptr->INDMABASE = JPEG_INDMABASE_ADDR_SET(config->in_buffer);
168 ptr->INDMA_CTRL0 = JPEG_INDMA_CTRL0_TTLEN_SET(total_bytes)
169 | JPEG_INDMA_CTRL0_PITCH_SET(config->width_in_pixel * jpeg_supported_pixel_format[config->in_pixel_format].pixel_width);
170 ptr->INDMA_CTRL1 = JPEG_INDMA_CTRL1_ROWLEN_SET(total_bytes >> 16);
171
172 ptr->INXT_CMD = JPEG_INXT_CMD_ADDR_SET(5) | JPEG_INXT_CMD_OP_VALID_MASK;
173
174 /* output DMA setting */
175 ptr->OUTDMA_MISC = JPEG_OUTDMA_MISC_EN_OUTCNT_MASK
176 | JPEG_OUTDMA_MISC_INI_OUTCNT_MASK
177 | JPEG_OUTDMA_MISC_OUT_DMA_ID_SET(1)
178 | JPEG_OUTDMA_MISC_OUT_DMA_REQ_MASK
179 | JPEG_OUTDMA_MISC_ADD_ODMA_ENDINGS_MASK
180 | JPEG_OUTDMA_MISC_PACK_DIR_SET(config->out_byte_order);
181 ptr->OUTDMABASE = JPEG_OUTDMABASE_ADDR_SET(config->out_buffer);
182 ptr->OUTDMA_CTRL0 = JPEG_OUTDMA_CTRL0_TTLEN_SET(total_bytes);
183 ptr->OUTDMA_CTRL1 = JPEG_OUTDMA_CTRL1_ROWLEN_SET(total_bytes >> 16);
184
185 ptr->ONXT_CMD = JPEG_ONXT_CMD_ADDR_SET(5) | JPEG_ONXT_CMD_OP_VALID_MASK;
186
187 jpeg_config_interal_regs(ptr, false, macro_block_count, config->jpeg_format);
188
189 ptr->WIDTH = config->width_in_pixel - 1;
190 ptr->HEIGHT = config->height_in_pixel - 1;
191
192 if (jpeg_need_csc(config->in_pixel_format, config->out_pixel_format)) {
193 if (config->enable_ycbcr) {
194 ptr->RGB2YUV_COEF0 = JPEG_RGB2YUV_COEF0_C0_SET(0x42)
195 | JPEG_RGB2YUV_COEF0_UV_OFFSET_SET(0x80)
196 | JPEG_RGB2YUV_COEF0_Y_OFFSET_SET(0x10)
197 | JPEG_RGB2YUV_COEF0_ENABLE_MASK
198 | JPEG_RGB2YUV_COEF0_YCBCR_MODE_MASK;
199 ptr->RGB2YUV_COEF1 = JPEG_RGB2YUV_COEF1_C1_SET(0x81)
200 | JPEG_RGB2YUV_COEF1_C4_SET(0x7B5);
201 ptr->RGB2YUV_COEF2 = JPEG_RGB2YUV_COEF2_C2_SET(0x19)
202 | JPEG_RGB2YUV_COEF2_C3_SET(0x7DA);
203 ptr->RGB2YUV_COEF3 = JPEG_RGB2YUV_COEF3_C6_SET(0x70)
204 | JPEG_RGB2YUV_COEF3_C5_SET(0x70);
205 ptr->RGB2YUV_COEF4 = JPEG_RGB2YUV_COEF4_C8_SET(0x7EE)
206 | JPEG_RGB2YUV_COEF4_C7_SET(0x7A2);
207 } else {
208 ptr->RGB2YUV_COEF0 = JPEG_RGB2YUV_COEF0_C0_SET(0x4D)
209 | JPEG_RGB2YUV_COEF0_UV_OFFSET_SET(0)
210 | JPEG_RGB2YUV_COEF0_Y_OFFSET_SET(0x0)
211 | JPEG_RGB2YUV_COEF0_ENABLE_MASK;
212 ptr->RGB2YUV_COEF1 = JPEG_RGB2YUV_COEF1_C1_SET(0x96)
213 | JPEG_RGB2YUV_COEF1_C4_SET(0x7B6);
214 ptr->RGB2YUV_COEF2 = JPEG_RGB2YUV_COEF2_C2_SET(0x1D)
215 | JPEG_RGB2YUV_COEF2_C3_SET(0x7DA);
216 ptr->RGB2YUV_COEF3 = JPEG_RGB2YUV_COEF3_C6_SET(0x9D)
217 | JPEG_RGB2YUV_COEF3_C5_SET(0x70);
218 ptr->RGB2YUV_COEF4 = JPEG_RGB2YUV_COEF4_C8_SET(0x7E6)
219 | JPEG_RGB2YUV_COEF4_C7_SET(0x77C);
220 }
221 } else {
222 ptr->RGB2YUV_COEF0 = 0x04030000;
223 }
224
225 ptr->CFG = JPEG_CFG_CFG_IPATH_SEL_SET(jpeg_supported_pixel_format[config->in_pixel_format].ipath)
226 | JPEG_CFG_CFG_OPATH_SEL_SET(jpeg_supported_pixel_format[config->out_pixel_format].opath)
227 | JPEG_CFG_CLKGATE_MASK
228 | JPEG_CFG_JDATA_FORMAT_SET(config->jpeg_format)
229 | JPEG_CFG_JPEG_EN_MASK
230 | JPEG_CFG_START_MASK;
231
232 return status_success;
233 }
234
235
jpeg_start_decode(JPEG_Type * ptr,jpeg_job_config_t * config,uint32_t length)236 hpm_stat_t jpeg_start_decode(JPEG_Type *ptr,
237 jpeg_job_config_t *config,
238 uint32_t length)
239 {
240 uint32_t macro_block_count;
241 uint32_t macro_block_bytes;
242 uint32_t total_bytes;
243 jpeg_sampling_t *sampling;
244
245 if (!jpeg_is_valid_size(config->jpeg_format, config->width_in_pixel, config->height_in_pixel)) {
246 return status_invalid_argument;
247 }
248
249 jpeg_disable(ptr);
250 jpeg_software_reset(ptr);
251
252 sampling = (jpeg_sampling_t *)&jpeg_supported_sampling[config->jpeg_format];
253 macro_block_count = jpeg_calculate_macro_block_count(config->width_in_pixel, config->height_in_pixel, sampling);
254 macro_block_bytes = (JPEG_HY(sampling) * JPEG_VY(sampling)
255 + 2 * JPEG_HC(sampling) * JPEG_VC(sampling)) << 6;
256 total_bytes = macro_block_count * macro_block_bytes;
257
258 /* input DMA setting */
259 ptr->INDMA_MISC = JPEG_INDMA_MISC_IN_DMA_ID_SET(1)
260 | JPEG_INDMA_MISC_IN_DMA_REQ_MASK
261 | JPEG_INDMA_MISC_MAX_OT_SET(2)
262 | JPEG_INDMA_MISC_PACK_DIR_SET(config->in_byte_order);
263 ptr->INDMABASE = JPEG_INDMABASE_ADDR_SET(config->in_buffer);
264 /* TODO: check if it has to use the compressed length */
265 ptr->INDMA_CTRL0 = JPEG_INDMA_CTRL0_TTLEN_SET(length);
266 ptr->INDMA_CTRL1 = JPEG_INDMA_CTRL1_ROWLEN_SET(length >> 16);
267 ptr->INXT_CMD = JPEG_INXT_CMD_ADDR_SET(5) | JPEG_INXT_CMD_OP_VALID_MASK;
268
269 /* output DMA setting */
270 ptr->OUTDMA_MISC = JPEG_OUTDMA_MISC_EN_OUTCNT_MASK
271 | JPEG_OUTDMA_MISC_OUT_DMA_ID_SET(0)
272 | JPEG_OUTDMA_MISC_INI_OUTCNT_MASK
273 | JPEG_OUTDMA_MISC_OUT_DMA_REQ_MASK
274 | JPEG_OUTDMA_MISC_OUTDMA2D_MASK
275 | JPEG_OUTDMA_MISC_PACK_DIR_SET(config->out_byte_order);
276 ptr->OUTDMABASE = JPEG_OUTDMABASE_ADDR_SET(config->out_buffer);
277 ptr->OUTDMA_CTRL0 = JPEG_OUTDMA_CTRL0_TTLEN_SET(total_bytes)
278 | JPEG_OUTDMA_CTRL0_PITCH_SET(config->width_in_pixel * jpeg_supported_pixel_format[config->out_pixel_format].pixel_width);
279 ptr->OUTDMA_CTRL1 = JPEG_OUTDMA_CTRL1_ROWLEN_SET(total_bytes >> 16);
280 ptr->ONXT_CMD = JPEG_ONXT_CMD_ADDR_SET(5) | JPEG_ONXT_CMD_OP_VALID_MASK;
281
282 jpeg_config_interal_regs(ptr, true, macro_block_count, config->jpeg_format);
283
284 ptr->WIDTH = config->width_in_pixel - 1;
285 ptr->HEIGHT = config->height_in_pixel - 1;
286
287 ptr->CSC_COEF0 = 0x4ab01f0
288 | JPEG_CSC_COEF0_YCBCR_MODE_SET(config->enable_ycbcr)
289 | JPEG_CSC_COEF0_ENABLE_SET(jpeg_need_csc(config->in_pixel_format, config->out_pixel_format));
290 ptr->CSC_COEF1 = 0x01980204;
291 ptr->CSC_COEF2 = 0x0730079C;
292
293 ptr->CFG = JPEG_CFG_CFG_OPATH_SEL_SET(jpeg_supported_pixel_format[config->out_pixel_format].opath)
294 | JPEG_CFG_JDATA_FORMAT_SET(config->jpeg_format)
295 | JPEG_CFG_JPEG_EN_MASK
296 | JPEG_CFG_START_MASK
297 | JPEG_CFG_CLKGATE_MASK
298 | JPEG_CFG_MODE_MASK;
299 return status_success;
300 }
301
302 #define JPEG_TABLE_WIDTH(x) (((x) & 0xF00000UL) >> 20)
303 #define JPEG_TABLE_LENGTH(x) (((x) & 0xFFFF0UL) >> 4)
304 #define JPEG_TABLE_TYPE(x) (((x) & 0xFUL))
305 #define JPEG_TABLE_VALUE_MASK(x) (((x) == 4) ? (0xFFFFFFFFUL) : (uint32_t) ((1 << ((x) << 3)) - 1))
306
jpeg_fill_table(JPEG_Type * ptr,jpeg_table_t table,uint8_t * data,uint32_t count)307 hpm_stat_t jpeg_fill_table(JPEG_Type *ptr, jpeg_table_t table, uint8_t *data, uint32_t count)
308 {
309 uint32_t i = 0;
310 uint32_t width = JPEG_TABLE_WIDTH(table);
311 uint32_t length = JPEG_TABLE_LENGTH(table);
312 uint32_t type = JPEG_TABLE_TYPE(table);
313 uint32_t *p;
314
315 if (length != count) {
316 return status_invalid_argument;
317 }
318
319 ptr->BUFADDR = type << 28;
320 for (i = 0; i < count; i++) {
321 p = (uint32_t *) &data[i * width];
322 ptr->BUFDATA = JPEG_BUFADDR_ADDR_SET(*p & JPEG_TABLE_VALUE_MASK(width));
323 }
324 return status_success;
325 }
326
327