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 }