1 /*
2 * Copyright 2023 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_pngdec.h"
8
9 /*******************************************************************************
10 * Definitions
11 ******************************************************************************/
12
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.pngdec"
16 #endif
17
18 #define PNG_MARKER 0x89504e47UL
19 #define PNG_HEADER_MARKER 0x49484452UL
20 #define PNG_GET_U32(p) \
21 ((((uint32_t)(*(p))) << 24) + (((uint32_t)(*((p) + 1))) << 16) + (((uint32_t)(*((p) + 2))) << 8) + ((uint32_t)(*((p) + 3))))
22
23 /*******************************************************************************
24 * Prototypes
25 ******************************************************************************/
26 /*!
27 * @brief Get the PNGDEC instance from the peripheral base address.
28 *
29 * @param base PNGDEC peripheral base address.
30 * @return PNGDEC instance.
31 */
32 static uint32_t PNGDEC_GetInstance(PNGDEC_Type *base);
33
34 /*******************************************************************************
35 * Variables
36 ******************************************************************************/
37 /* Array of PNGDEC peripheral base address. */
38 static PNGDEC_Type *const s_pngdecBases[] = PNGDEC_BASE_PTRS;
39 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
40 /* Clock name of PNGDEC. */
41 static const clock_ip_name_t s_pngdecClock[] = PNGDEC_CLOCKS;
42 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
43 #if defined(PNGDEC_RSTS)
44 /* Reset array */
45 static const reset_ip_name_t s_pngdecResets[] = PNGDEC_RSTS;
46 #endif
47 /*******************************************************************************
48 * Codes
49 ******************************************************************************/
PNGDEC_GetInstance(PNGDEC_Type * base)50 static uint32_t PNGDEC_GetInstance(PNGDEC_Type *base)
51 {
52 uint32_t instance = 0U;
53
54 /* Find the instance index from base address mappings. */
55 for (instance = 0; instance < ARRAY_SIZE(s_pngdecBases); instance++)
56 {
57 if (MSDK_REG_SECURE_ADDR(s_pngdecBases[instance]) == MSDK_REG_SECURE_ADDR(base))
58 {
59 break;
60 }
61 }
62
63 assert(instance < ARRAY_SIZE(s_pngdecBases));
64
65 return instance;
66 }
67
68 /*!
69 * brief Initializes the PNGDEC.
70 *
71 * The default configuration can be got by calling PNGDEC_GetDefaultConfig().
72 *
73 * param base PNGDEC peripheral base address.
74 * param config Pointer to PNGDEC configuration structure.
75 */
PNGDEC_Init(PNGDEC_Type * base,const pngdec_config_t * config)76 void PNGDEC_Init(PNGDEC_Type *base, const pngdec_config_t *config)
77 {
78 assert(NULL != config);
79
80 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
81 /* Open clock gate. */
82 CLOCK_EnableClock(s_pngdecClock[PNGDEC_GetInstance(base)]);
83 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
84
85 #if defined(PNGDEC_RSTS)
86 RESET_ReleasePeripheralReset(s_pngdecResets[PNGDEC_GetInstance(base)]);
87 #endif
88
89 /* Reset the module before configuring it. */
90 PNGDEC_Reset(base);
91
92 base->GLB_CTRL = PNGDEC_GLB_CTRL_ANC_DROP_EN((uint32_t)config->enableAncillary) |
93 PNGDEC_GLB_CTRL_DEC_EN((uint32_t)config->enable);
94 }
95
96 /*!
97 * brief Deinitializes the PNGDEC.
98 *
99 * param base PNGDEC peripheral base address.
100 */
PNGDEC_Deinit(PNGDEC_Type * base)101 void PNGDEC_Deinit(PNGDEC_Type *base)
102 {
103 /* Disable the module. */
104 PNGDEC_Enable(base, false);
105
106 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
107 /* Disable clock gate. */
108 CLOCK_DisableClock(s_pngdecClock[PNGDEC_GetInstance(base)]);
109 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
110 }
111
112 /*!
113 * brief Gets the default configuration for PNGDEC.
114 *
115 * This function initializes the user configuration structure to default value. The default value are:
116 *
117 * Example:
118 code
119 config->enableAncillary = false;
120 config->enable = true;
121 endcode
122 *
123 * param config Pointer to PNGDEC configuration structure.
124 */
PNGDEC_GetDefaultConfig(pngdec_config_t * config)125 void PNGDEC_GetDefaultConfig(pngdec_config_t *config)
126 {
127 assert(NULL != config);
128
129 /* Initializes the configure structure to zero. */
130 (void)memset(config, 0, sizeof(*config));
131
132 /* Fill default configuration */
133 config->enableAncillary = false;
134 config->enable = true;
135 }
136
137 /*!
138 * brief Sets the address and length of the raw PNG image.
139 *
140 * param base PNGDEC peripheral base address.
141 * param data Start address of the buffer of the raw PNG image, shall be 8-byte aligned.
142 * param length Size of the buffer.
143 */
PNGDEC_SetPngBuffer(PNGDEC_Type * base,uint8_t * buffer,size_t length)144 void PNGDEC_SetPngBuffer(PNGDEC_Type *base, uint8_t *buffer, size_t length)
145 {
146 assert(((uint32_t)buffer & 0x7U) == 0U);
147 assert(length > 32U);
148
149 base->ENC_DATA_DMA_SRC_ADDR = (uint32_t)buffer;
150 base->ENC_DATA_DMA_SRC_LEN = length;
151 }
152
153 /*!
154 * brief Parses the PNG header and stores the info in the decoded image info structure.
155 *
156 * param image Pointer to PNGDEC decoded image info structure.
157 * param pngBuf Pointer to PNG file buffer.
158 * retval kStatus_Success Header parsing success.
159 * retval kStatus_Fail PNG header parsing failed due corrupted header.
160 * retval kStatus_PNGDEC_WidthTooLarge Header parsing failed due to the image width is larger than 1024.
161 * retval kStatus_PNGDEC_NotSupported Header parsing failed due to the image is interlaced or the bit depth is less
162 than 8.
163 */
PNGDEC_ParseHeader(pngdec_image_t * image,uint8_t * pngBuf)164 status_t PNGDEC_ParseHeader(pngdec_image_t *image, uint8_t *pngBuf)
165 {
166 assert(pngBuf != NULL);
167
168 /* Initializes the structure to zero. */
169 (void)memset(image, 0, sizeof(*image));
170
171 status_t result = kStatus_Success;
172 uint8_t bitDepth;
173 bool isInterlaced;
174 uint8_t colorType;
175
176 /* Check if the file is a PNG file and PNG header marker is there. */
177 if ((PNG_GET_U32(pngBuf) != PNG_MARKER) || (PNG_GET_U32(&pngBuf[12U]) != PNG_HEADER_MARKER))
178 {
179 return kStatus_Fail;
180 }
181
182 image->width = PNG_GET_U32(&pngBuf[16U]);
183
184 /* Check if the PNG width is larger than the max value supported. */
185 if (image->width > 1024U)
186 {
187 return kStatus_PNGDEC_WidthTooLarge;
188 }
189
190 image->height = PNG_GET_U32(&pngBuf[20U]);
191 bitDepth = pngBuf[24U];
192 isInterlaced = (bool)pngBuf[28U];
193 colorType = 0U;
194
195 /* Check whether the bit depth is less than 8 or the image is interlaced. */
196 if ((bitDepth < 8U) || (isInterlaced == true))
197 {
198 return kStatus_PNGDEC_NotSupported;
199 }
200
201 if ((bitDepth != 8U) && (bitDepth != 16U))
202 {
203 /* Corrupt header info, unrecognized bit depth. */
204 return kStatus_Fail;
205 }
206
207 switch (pngBuf[25U])
208 {
209 case 3U:
210 image->colorType = kPNGDEC_PixelFormatLUT8;
211 break;
212 case 4U:
213 colorType = 1U;
214 case 0U:
215 colorType += (uint8_t)kPNGDEC_PixelFormatY8;
216 image->colorType = (pngdec_color_type_t)colorType;
217 if (bitDepth != 8U)
218 {
219 result = kStatus_Fail;
220 }
221 break;
222 case 6U:
223 colorType = 1U;
224 case 2U:
225 if (bitDepth == 8U)
226 {
227 colorType += (uint8_t)kPNGDEC_PixelFormatRGB888;
228 }
229 else
230 {
231 colorType += (uint8_t)kPNGDEC_PixelFormatRGB16_16_16;
232 }
233 image->colorType = (pngdec_color_type_t)colorType;
234 break;
235 default:
236 /* Corrupt header info, unrecognized image type. */
237 result = kStatus_Fail;
238 break;
239 }
240
241 return result;
242 }
243
244 /*!
245 * brief Decodes the PNG image.
246 *
247 * This function performs the PNG decoding in blocking way and stores the decoded info in decoded image info structure.
248 *
249 * param base PNGDEC peripheral base address.
250 * param image Pointer to PNGDEC decoded image info structure.
251 * param status Pointer to decoded status. When retval is kStatus_Fail, Checksum/Crc/Header/Btype/ZlibHeader error may
252 occur due to PNG file corruption, user can check which error(s) occured if necessary.
253 * retval kStatus_Success PNG decoding success.
254 * retval kStatus_Fail PNG decoding failed due to CRC/header/B type/Alder error or invalid PNG file.
255 * retval kStatus_PNGDEC_WidthTooLarge PNG decoding failed due to the image width is larger than 1024.
256 * retval kStatus_PNGDEC_NotSupported PNG decoding failed due to the image is interlaced or the bit depth is less
257 * than 8.
258 */
PNGDEC_Decode(PNGDEC_Type * base,pngdec_image_t * image,uint32_t * status)259 status_t PNGDEC_Decode(PNGDEC_Type *base, pngdec_image_t *image, uint32_t *status)
260 {
261 status_t result = kStatus_Success;
262 uint32_t statusFlags;
263 uint32_t DoneFlags = (uint32_t)kPNGDEC_DecodePixelDoneFlag;
264
265 image->imageData = (uint8_t *)(base->DEC_PIXEL_DMA_DES_ADDR);
266 image->ancillaryData = (uint8_t *)(base->DEC_ANC_DMA_DES_ADDR);
267
268 /* Clear dirty counter, write 1 then clear. */
269 base->CNT_CTRL_CLR = PNGDEC_CNT_CTRL_CLR_CNT_CTRL_CLR_MASK;
270 base->CNT_CTRL_CLR = 0U;
271
272 /* Clear all status. */
273 base->DEC_INT_STS = 0xFFFFU;
274
275 /* Start decoding. */
276 PNGDEC_StartDecode(base);
277
278 /* Wait for the decoding done. */
279 if ((base->GLB_CTRL & PNGDEC_GLB_CTRL_ANC_DROP_EN_MASK) != 0U)
280 {
281 DoneFlags |= (uint32_t)kPNGDEC_DecodeAncillaryDoneFlag;
282 }
283 statusFlags = PNGDEC_GetStatusFlags(base);
284 while ((PNGDEC_GetStatusFlags(base) & DoneFlags) != DoneFlags)
285 {
286 statusFlags = PNGDEC_GetStatusFlags(base);
287 if ((statusFlags & (uint32_t)kPNGDEC_ErrorFlags) != 0U)
288 {
289 result = kStatus_Fail;
290 break;
291 }
292 }
293
294 if ((statusFlags & (uint32_t)kPNGDEC_ErrorFlags) != 0U)
295 {
296 if ((statusFlags & (uint32_t)kPNGDEC_WidthErrorFlag) != 0U)
297 {
298 result = kStatus_PNGDEC_WidthTooLarge;
299 }
300 if ((statusFlags & ((uint32_t)kPNGDEC_BitDepthErrorFlag | (uint32_t)kPNGDEC_InterlaceErrorFlag)) != 0U)
301 {
302 result = kStatus_PNGDEC_NotSupported;
303 }
304 }
305 else
306 {
307 image->ancillaryLength = base->DEC_ANC_DMA_DES_LEN;
308 }
309
310 if (status != NULL)
311 {
312 *status = statusFlags;
313 }
314
315 return result;
316 }