1 /*
2  * Copyright 2017-2021 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_pxp.h"
10 
11 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
12 #include "fsl_memory.h"
13 #endif
14 
15 /*******************************************************************************
16  * Definitions
17  ******************************************************************************/
18 
19 /* Component ID definition, used by tools. */
20 #ifndef FSL_COMPONENT_ID
21 #define FSL_COMPONENT_ID "platform.drivers.pxp"
22 #endif
23 
24 /* The CSC2 coefficient is ###.####_#### */
25 #define PXP_CSC2_COEF_INT_WIDTH  2
26 #define PXP_CSC2_COEF_FRAC_WIDTH 8
27 
28 /* Compatibility map macro. */
29 #if defined(PXP_PS_CLRKEYLOW_0_PIXEL_MASK) && (!defined(PXP_PS_CLRKEYLOW_PIXEL_MASK))
30 #define PS_CLRKEYLOW  PS_CLRKEYLOW_0
31 #define PS_CLRKEYHIGH PS_CLRKEYHIGH_0
32 #endif
33 #if defined(PXP_AS_CLRKEYLOW_0_PIXEL_MASK) && (!defined(PXP_AS_CLRKEYLOW_PIXEL_MASK))
34 #define AS_CLRKEYLOW  AS_CLRKEYLOW_0
35 #define AS_CLRKEYHIGH AS_CLRKEYHIGH_0
36 #endif
37 
38 #define PXP_MAX_HEIGHT ((PXP_OUT_LRC_Y_MASK >> PXP_OUT_LRC_Y_SHIFT) + 1U)
39 
40 /* Compatibility macro remap. */
41 #if (!defined(PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK) && defined(PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK))
42 #define PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK
43 #endif
44 
45 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
46 #define PXP_ADDR_CPU_2_IP(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_Local2DMA))
47 #else
48 #define PXP_ADDR_CPU_2_IP(addr) (addr)
49 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
50 
51 typedef union _u32_f32
52 {
53     float f32;
54     uint32_t u32;
55 } u32_f32_t;
56 
57 typedef union _pxp_pvoid_u32
58 {
59     void *pvoid;
60     uint32_t u32;
61 } pxp_pvoid_u32_t;
62 
63 /*******************************************************************************
64  * Prototypes
65  ******************************************************************************/
66 /*!
67  * @brief Get the instance from the base address
68  *
69  * @param base PXP peripheral base address
70  *
71  * @return The PXP module instance
72  */
73 static uint32_t PXP_GetInstance(PXP_Type *base);
74 
75 #if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
76 /*!
77  * @brief Convert IEEE 754 float value to the value could be written to registers.
78  *
79  * This function converts the float value to integer value to set the scaler
80  * and CSC parameters.
81  *
82  * This function is an alternative implemention of the following code with no
83  * MISRA 2004 rule 10.4 error:
84  *
85  * @code
86    return (uint32_t)(floatValue * (float)(1 << fracBits));
87    @endcode
88  *
89  * @param floatValue The float value to convert.
90  * @param intBits Bits number of integer part in result.
91  * @param fracBits Bits number of fractional part in result.
92  * @return The value to set to register.
93  */
94 static uint32_t PXP_ConvertFloat(float floatValue, uint8_t intBits, uint8_t fracBits);
95 #endif
96 
97 /*!
98  * @brief Convert the desired scale fact to DEC and PS_SCALE.
99  *
100  * @param inputDimension Input dimension.
101  * @param outputDimension Output dimension.
102  * @param dec The decimation filter contr0l value.
103  * @param scale The scale value set to register PS_SCALE.
104  */
105 static void PXP_GetScalerParam(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale);
106 
107 /*!
108  * @brief Reset the PXP to initialized state.
109  *
110  * @param base PXP peripheral base address.
111  */
112 static void PXP_ResetToInit(PXP_Type *base);
113 
114 /*!
115  * @brief Copy rectangle.
116  *
117  * @param base PXP peripheral base address.
118  * @param srcAddr Start address of the soruce rectangle.
119  * @param srcPitchBytes Pitch of source buffer.
120  * @param destAddr Start address of the destination rectangle.
121  * @param destPitchBytes Pitch of destination buffer.
122  * @param width How many pixels one line to copy.
123  * @param height How many lines to copy.
124  * @param pixelFormat Pixel format.
125  */
126 static void PXP_StartRectCopy(PXP_Type *base,
127                               uint32_t srcAddr,
128                               uint16_t srcPitchBytes,
129                               uint32_t destAddr,
130                               uint16_t destPitchBytes,
131                               uint16_t width,
132                               uint16_t height,
133                               pxp_as_pixel_format_t pixelFormat);
134 
135 /*******************************************************************************
136  * Variables
137  ******************************************************************************/
138 /*! @brief Pointers to PXP bases for each instance. */
139 static PXP_Type *const s_pxpBases[] = PXP_BASE_PTRS;
140 
141 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
142 /*! @brief Pointers to PXP clocks for each PXP submodule. */
143 static const clock_ip_name_t s_pxpClocks[] = PXP_CLOCKS;
144 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
145 
146 /*******************************************************************************
147  * Code
148  ******************************************************************************/
PXP_GetInstance(PXP_Type * base)149 static uint32_t PXP_GetInstance(PXP_Type *base)
150 {
151     uint32_t instance;
152 
153     /* Find the instance index from base address mappings. */
154     for (instance = 0; instance < ARRAY_SIZE(s_pxpBases); instance++)
155     {
156         if (s_pxpBases[instance] == base)
157         {
158             break;
159         }
160     }
161 
162     assert(instance < ARRAY_SIZE(s_pxpBases));
163 
164     return instance;
165 }
166 
167 #if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
PXP_ConvertFloat(float floatValue,uint8_t intBits,uint8_t fracBits)168 static uint32_t PXP_ConvertFloat(float floatValue, uint8_t intBits, uint8_t fracBits)
169 {
170     /* One bit reserved for sign bit. */
171     assert(intBits + fracBits < 32);
172 
173     u32_f32_t u32_f32;
174     uint32_t ret;
175 
176     u32_f32.f32        = floatValue;
177     uint32_t floatBits = u32_f32.u32;
178     int32_t expValue   = (int32_t)((floatBits & 0x7F800000U) >> 23U) - 127;
179 
180     ret = (floatBits & 0x007FFFFFU) | 0x00800000U;
181     expValue += fracBits;
182 
183     if (expValue < 0)
184     {
185         return 0U;
186     }
187     else if (expValue > 23)
188     {
189         /* should not exceed 31-bit when left shift. */
190         assert((expValue - 23) <= 7);
191         ret <<= (expValue - 23);
192     }
193     else
194     {
195         ret >>= (23 - expValue);
196     }
197 
198     /* Set the sign bit. */
199     if (floatBits & 0x80000000U)
200     {
201         ret = ((~ret) + 1U) & ~(((uint32_t)-1) << (intBits + fracBits + 1));
202     }
203 
204     return ret;
205 }
206 #endif
207 
PXP_GetScalerParam(uint16_t inputDimension,uint16_t outputDimension,uint8_t * dec,uint32_t * scale)208 static void PXP_GetScalerParam(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale)
209 {
210     uint32_t scaleFact = ((uint32_t)inputDimension << 12U) / outputDimension;
211 
212     if (scaleFact >= (16UL << 12U))
213     {
214         /* Desired fact is two large, use the largest support value. */
215         *dec   = 3U;
216         *scale = 0x2000U;
217     }
218     else
219     {
220         if (scaleFact > (8UL << 12U))
221         {
222             *dec = 3U;
223         }
224         else if (scaleFact > (4UL << 12U))
225         {
226             *dec = 2U;
227         }
228         else if (scaleFact > (2UL << 12U))
229         {
230             *dec = 1U;
231         }
232         else
233         {
234             *dec = 0U;
235         }
236 
237         *scale = scaleFact >> (*dec);
238 
239         if (0U == *scale)
240         {
241             *scale = 1U;
242         }
243     }
244 }
245 
PXP_ResetToInit(PXP_Type * base)246 static void PXP_ResetToInit(PXP_Type *base)
247 {
248     uint32_t ctrl = 0U;
249 
250     PXP_Reset(base);
251 
252 /* Enable the process engine in primary processing flow. */
253 #if defined(PXP_CTRL_ENABLE_ROTATE0_MASK)
254     ctrl |= PXP_CTRL_ENABLE_ROTATE0_MASK;
255 #endif
256 #if defined(PXP_CTRL_ENABLE_ROTATE1_MASK)
257     ctrl |= PXP_CTRL_ENABLE_ROTATE1_MASK;
258 #endif
259 #if defined(PXP_CTRL_ENABLE_CSC2_MASK)
260     ctrl |= PXP_CTRL_ENABLE_CSC2_MASK;
261 #endif
262 #if defined(PXP_CTRL_ENABLE_LUT_MASK)
263     ctrl |= PXP_CTRL_ENABLE_LUT_MASK;
264 #endif
265 #if defined(PXP_CTRL_ENABLE_PS_AS_OUT_MASK)
266     ctrl |= PXP_CTRL_ENABLE_PS_AS_OUT_MASK;
267 #endif
268 
269     base->CTRL = ctrl;
270 }
271 
272 /*!
273  * brief Initialize the PXP.
274  *
275  * This function enables the PXP peripheral clock, and resets the PXP registers
276  * to default status.
277  *
278  * param base PXP peripheral base address.
279  */
PXP_Init(PXP_Type * base)280 void PXP_Init(PXP_Type *base)
281 {
282 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
283     uint32_t instance = PXP_GetInstance(base);
284     CLOCK_EnableClock(s_pxpClocks[instance]);
285 #endif
286 
287     PXP_ResetToInit(base);
288 }
289 
290 /*!
291  * brief De-initialize the PXP.
292  *
293  * This function disables the PXP peripheral clock.
294  *
295  * param base PXP peripheral base address.
296  */
PXP_Deinit(PXP_Type * base)297 void PXP_Deinit(PXP_Type *base)
298 {
299 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
300     uint32_t instance = PXP_GetInstance(base);
301     CLOCK_DisableClock(s_pxpClocks[instance]);
302 #endif
303 }
304 
305 /*!
306  * brief Reset the PXP.
307  *
308  * This function resets the PXP peripheral registers to default status.
309  *
310  * param base PXP peripheral base address.
311  */
PXP_Reset(PXP_Type * base)312 void PXP_Reset(PXP_Type *base)
313 {
314     base->CTRL_SET = PXP_CTRL_SFTRST_MASK;
315     base->CTRL_CLR = (PXP_CTRL_SFTRST_MASK | PXP_CTRL_CLKGATE_MASK);
316 }
317 
318 /*!
319  * brief Set the alpha surface input buffer configuration.
320  *
321  * param base PXP peripheral base address.
322  * param config Pointer to the configuration.
323  */
PXP_SetAlphaSurfaceBufferConfig(PXP_Type * base,const pxp_as_buffer_config_t * config)324 void PXP_SetAlphaSurfaceBufferConfig(PXP_Type *base, const pxp_as_buffer_config_t *config)
325 {
326     assert(NULL != config);
327 
328     base->AS_CTRL = (base->AS_CTRL & ~PXP_AS_CTRL_FORMAT_MASK) | PXP_AS_CTRL_FORMAT(config->pixelFormat);
329 
330     base->AS_BUF   = PXP_ADDR_CPU_2_IP(config->bufferAddr);
331     base->AS_PITCH = config->pitchBytes;
332 }
333 
334 /*!
335  * brief Set the alpha surface blending configuration.
336  *
337  * param base PXP peripheral base address.
338  * param config Pointer to the configuration structure.
339  */
PXP_SetAlphaSurfaceBlendConfig(PXP_Type * base,const pxp_as_blend_config_t * config)340 void PXP_SetAlphaSurfaceBlendConfig(PXP_Type *base, const pxp_as_blend_config_t *config)
341 {
342     assert(NULL != config);
343     uint32_t reg;
344 
345     reg = base->AS_CTRL;
346     reg &=
347         ~(PXP_AS_CTRL_ALPHA0_INVERT_MASK | PXP_AS_CTRL_ROP_MASK | PXP_AS_CTRL_ALPHA_MASK | PXP_AS_CTRL_ALPHA_CTRL_MASK);
348     reg |= (PXP_AS_CTRL_ROP(config->ropMode) | PXP_AS_CTRL_ALPHA(config->alpha) |
349             PXP_AS_CTRL_ALPHA_CTRL(config->alphaMode));
350 
351     if (config->invertAlpha)
352     {
353         reg |= PXP_AS_CTRL_ALPHA0_INVERT_MASK;
354     }
355 
356     base->AS_CTRL = reg;
357 }
358 
359 /*!
360  * brief Set the alpha surface position in output buffer.
361  *
362  * param base PXP peripheral base address.
363  * param upperLeftX X of the upper left corner.
364  * param upperLeftY Y of the upper left corner.
365  * param lowerRightX X of the lower right corner.
366  * param lowerRightY Y of the lower right corner.
367  */
PXP_SetAlphaSurfacePosition(PXP_Type * base,uint16_t upperLeftX,uint16_t upperLeftY,uint16_t lowerRightX,uint16_t lowerRightY)368 void PXP_SetAlphaSurfacePosition(
369     PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY)
370 {
371     base->OUT_AS_ULC = PXP_OUT_AS_ULC_Y(upperLeftY) | PXP_OUT_AS_ULC_X(upperLeftX);
372     base->OUT_AS_LRC = PXP_OUT_AS_LRC_Y(lowerRightY) | PXP_OUT_AS_LRC_X(lowerRightX);
373 }
374 
375 /*!
376  * brief Set the alpha surface overlay color key.
377  *
378  * If a pixel in the current overlay image with a color that falls in the range
379  * from the p colorKeyLow to p colorKeyHigh range, it will use the process surface
380  * pixel value for that location. If no PS image is present or if the PS image also
381  * matches its colorkey range, the PS background color is used.
382  *
383  * param base PXP peripheral base address.
384  * param colorKeyLow Color key low range.
385  * param colorKeyHigh Color key high range.
386  *
387  * note Colorkey operations are higher priority than alpha or ROP operations
388  */
PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type * base,uint32_t colorKeyLow,uint32_t colorKeyHigh)389 void PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
390 {
391     base->AS_CLRKEYLOW  = colorKeyLow;
392     base->AS_CLRKEYHIGH = colorKeyHigh;
393 }
394 
395 /*!
396  * brief Set the process surface input buffer configuration.
397  *
398  * param base PXP peripheral base address.
399  * param config Pointer to the configuration.
400  */
PXP_SetProcessSurfaceBufferConfig(PXP_Type * base,const pxp_ps_buffer_config_t * config)401 void PXP_SetProcessSurfaceBufferConfig(PXP_Type *base, const pxp_ps_buffer_config_t *config)
402 {
403     assert(NULL != config);
404 
405     base->PS_CTRL = ((base->PS_CTRL & ~(PXP_PS_CTRL_FORMAT_MASK | PXP_PS_CTRL_WB_SWAP_MASK)) |
406                      PXP_PS_CTRL_FORMAT(config->pixelFormat) | PXP_PS_CTRL_WB_SWAP(config->swapByte));
407 
408     base->PS_BUF   = PXP_ADDR_CPU_2_IP(config->bufferAddr);
409     base->PS_UBUF  = PXP_ADDR_CPU_2_IP(config->bufferAddrU);
410     base->PS_VBUF  = PXP_ADDR_CPU_2_IP(config->bufferAddrV);
411     base->PS_PITCH = config->pitchBytes;
412 }
413 
414 /*!
415  * brief Set the process surface scaler configuration.
416  *
417  * The valid down scale fact is 1/(2^12) ~ 16.
418  *
419  * param base PXP peripheral base address.
420  * param inputWidth Input image width.
421  * param inputHeight Input image height.
422  * param outputWidth Output image width.
423  * param outputHeight Output image height.
424  */
PXP_SetProcessSurfaceScaler(PXP_Type * base,uint16_t inputWidth,uint16_t inputHeight,uint16_t outputWidth,uint16_t outputHeight)425 void PXP_SetProcessSurfaceScaler(
426     PXP_Type *base, uint16_t inputWidth, uint16_t inputHeight, uint16_t outputWidth, uint16_t outputHeight)
427 {
428     uint8_t decX, decY;
429     uint32_t scaleX, scaleY;
430 
431     PXP_GetScalerParam(inputWidth, outputWidth, &decX, &scaleX);
432     PXP_GetScalerParam(inputHeight, outputHeight, &decY, &scaleY);
433 
434     base->PS_CTRL = (base->PS_CTRL & ~(PXP_PS_CTRL_DECX_MASK | PXP_PS_CTRL_DECY_MASK)) | PXP_PS_CTRL_DECX(decX) |
435                     PXP_PS_CTRL_DECY(decY);
436 
437     base->PS_SCALE = PXP_PS_SCALE_XSCALE(scaleX) | PXP_PS_SCALE_YSCALE(scaleY);
438 }
439 
440 /*!
441  * brief Set the process surface position in output buffer.
442  *
443  * param base PXP peripheral base address.
444  * param upperLeftX X of the upper left corner.
445  * param upperLeftY Y of the upper left corner.
446  * param lowerRightX X of the lower right corner.
447  * param lowerRightY Y of the lower right corner.
448  */
PXP_SetProcessSurfacePosition(PXP_Type * base,uint16_t upperLeftX,uint16_t upperLeftY,uint16_t lowerRightX,uint16_t lowerRightY)449 void PXP_SetProcessSurfacePosition(
450     PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY)
451 {
452     base->OUT_PS_ULC = PXP_OUT_PS_ULC_Y(upperLeftY) | PXP_OUT_PS_ULC_X(upperLeftX);
453     base->OUT_PS_LRC = PXP_OUT_PS_LRC_Y(lowerRightY) | PXP_OUT_PS_LRC_X(lowerRightX);
454 }
455 
456 /*!
457  * brief Set the process surface color key.
458  *
459  * If the PS image matches colorkey range, the PS background color is output. Set
460  * p colorKeyLow to 0xFFFFFFFF and p colorKeyHigh to 0 will disable the colorkeying.
461  *
462  * param base PXP peripheral base address.
463  * param colorKeyLow Color key low range.
464  * param colorKeyHigh Color key high range.
465  */
PXP_SetProcessSurfaceColorKey(PXP_Type * base,uint32_t colorKeyLow,uint32_t colorKeyHigh)466 void PXP_SetProcessSurfaceColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
467 {
468     base->PS_CLRKEYLOW  = colorKeyLow;
469     base->PS_CLRKEYHIGH = colorKeyHigh;
470 }
471 
472 /*!
473  * brief Set the PXP outpt buffer configuration.
474  *
475  * param base PXP peripheral base address.
476  * param config Pointer to the configuration.
477  */
PXP_SetOutputBufferConfig(PXP_Type * base,const pxp_output_buffer_config_t * config)478 void PXP_SetOutputBufferConfig(PXP_Type *base, const pxp_output_buffer_config_t *config)
479 {
480     assert(NULL != config);
481 
482     base->OUT_CTRL = (base->OUT_CTRL & ~(PXP_OUT_CTRL_FORMAT_MASK | PXP_OUT_CTRL_INTERLACED_OUTPUT_MASK)) |
483                      PXP_OUT_CTRL_FORMAT(config->pixelFormat) | PXP_OUT_CTRL_INTERLACED_OUTPUT(config->interlacedMode);
484 
485     base->OUT_BUF  = PXP_ADDR_CPU_2_IP(config->buffer0Addr);
486     base->OUT_BUF2 = PXP_ADDR_CPU_2_IP(config->buffer1Addr);
487 
488     base->OUT_PITCH = config->pitchBytes;
489     base->OUT_LRC   = PXP_OUT_LRC_Y((uint32_t)config->height - 1U) | PXP_OUT_LRC_X((uint32_t)config->width - 1U);
490 
491 /*
492  * The dither store size must be set to the same with the output buffer size,
493  * otherwise the dither engine could not work.
494  */
495 #if defined(PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH_MASK)
496     base->DITHER_STORE_SIZE_CH0 = PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH(config->width - 1U) |
497                                   PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT(config->height - 1U);
498 #endif
499 }
500 
501 /*!
502  * brief Set the next command.
503  *
504  * The PXP supports a primitive ability to queue up one operation while the current
505  * operation is running. Workflow:
506  *
507  * 1. Prepare the PXP register values except STAT, CSCCOEFn, NEXT in the memory
508  * in the order they appear in the register map.
509  * 2. Call this function sets the new operation to PXP.
510  * 3. There are two methods to check whether the PXP has loaded the new operation.
511  * The first method is using ref PXP_IsNextCommandPending. If there is new operation
512  * not loaded by the PXP, this function returns true. The second method is checking
513  * the flag ref kPXP_CommandLoadFlag, if command loaded, this flag asserts. User
514  * could enable interrupt ref kPXP_CommandLoadInterruptEnable to get the loaded
515  * signal in interrupt way.
516  * 4. When command loaded by PXP, a new command could be set using this function.
517  *
518  * param base PXP peripheral base address.
519  * param commandAddr Address of the new command.
520  */
PXP_SetNextCommand(PXP_Type * base,void * commandAddr)521 void PXP_SetNextCommand(PXP_Type *base, void *commandAddr)
522 {
523     pxp_pvoid_u32_t addr;
524 
525     /* Make sure commands have been saved to memory. */
526     __DSB();
527 
528     addr.pvoid = commandAddr;
529 
530     base->NEXT = PXP_ADDR_CPU_2_IP(addr.u32) & PXP_NEXT_POINTER_MASK;
531 }
532 
533 #if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
534 /*!
535  * brief Set the CSC2 configuration.
536  *
537  * The CSC2 module receives pixels in any color space and can convert the pixels
538  * into any of RGB, YUV, or YCbCr color spaces. The output pixels are passed
539  * onto the LUT and rotation engine for further processing
540  *
541  * param base PXP peripheral base address.
542  * param config Pointer to the configuration.
543  */
PXP_SetCsc2Config(PXP_Type * base,const pxp_csc2_config_t * config)544 void PXP_SetCsc2Config(PXP_Type *base, const pxp_csc2_config_t *config)
545 {
546     assert(NULL != config);
547 
548     base->CSC2_CTRL = (base->CSC2_CTRL & ~PXP_CSC2_CTRL_CSC_MODE_MASK) | PXP_CSC2_CTRL_CSC_MODE(config->mode);
549 
550     base->CSC2_COEF0 =
551         (PXP_ConvertFloat(config->A1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF0_A1_SHIFT) |
552         (PXP_ConvertFloat(config->A2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF0_A2_SHIFT);
553 
554     base->CSC2_COEF1 =
555         (PXP_ConvertFloat(config->A3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF1_A3_SHIFT) |
556         (PXP_ConvertFloat(config->B1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF1_B1_SHIFT);
557 
558     base->CSC2_COEF2 =
559         (PXP_ConvertFloat(config->B2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF2_B2_SHIFT) |
560         (PXP_ConvertFloat(config->B3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF2_B3_SHIFT);
561 
562     base->CSC2_COEF3 =
563         (PXP_ConvertFloat(config->C1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF3_C1_SHIFT) |
564         (PXP_ConvertFloat(config->C2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF3_C2_SHIFT);
565 
566     base->CSC2_COEF4 =
567         (PXP_ConvertFloat(config->C3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF4_C3_SHIFT) |
568         PXP_CSC2_COEF4_D1(config->D1);
569 
570     base->CSC2_COEF5 = PXP_CSC2_COEF5_D2(config->D2) | PXP_CSC2_COEF5_D3(config->D3);
571 }
572 #endif
573 
574 /*!
575  * brief Set the CSC1 mode.
576  *
577  * The CSC1 module receives scaled YUV/YCbCr444 pixels from the scale engine and
578  * converts the pixels to the RGB888 color space. It could only be used by process
579  * surface.
580  *
581  * param base PXP peripheral base address.
582  * param mode The conversion mode.
583  */
PXP_SetCsc1Mode(PXP_Type * base,pxp_csc1_mode_t mode)584 void PXP_SetCsc1Mode(PXP_Type *base, pxp_csc1_mode_t mode)
585 {
586     /*
587      * The equations used for Colorspace conversion are:
588      *
589      * R = C0*(Y+Y_OFFSET)                   + C1(V+UV_OFFSET)
590      * G = C0*(Y+Y_OFFSET) + C3(U+UV_OFFSET) + C2(V+UV_OFFSET)
591      * B = C0*(Y+Y_OFFSET) + C4(U+UV_OFFSET)
592      */
593 
594     if (kPXP_Csc1YUV2RGB == mode)
595     {
596         base->CSC1_COEF0 = (base->CSC1_COEF0 & ~(PXP_CSC1_COEF0_C0_MASK | PXP_CSC1_COEF0_Y_OFFSET_MASK |
597                                                  PXP_CSC1_COEF0_UV_OFFSET_MASK | PXP_CSC1_COEF0_YCBCR_MODE_MASK)) |
598                            PXP_CSC1_COEF0_C0(0x100U)         /* 1.00. */
599                            | PXP_CSC1_COEF0_Y_OFFSET(0x0U)   /* 0. */
600                            | PXP_CSC1_COEF0_UV_OFFSET(0x0U); /* 0. */
601         base->CSC1_COEF1 = PXP_CSC1_COEF1_C1(0x0123U)        /* 1.140. */
602                            | PXP_CSC1_COEF1_C4(0x0208U);     /* 2.032. */
603         base->CSC1_COEF2 = PXP_CSC1_COEF2_C2(0x076BU)        /* -0.851. */
604                            | PXP_CSC1_COEF2_C3(0x079BU);     /* -0.394. */
605     }
606     else
607     {
608         base->CSC1_COEF0 = (base->CSC1_COEF0 &
609                             ~(PXP_CSC1_COEF0_C0_MASK | PXP_CSC1_COEF0_Y_OFFSET_MASK | PXP_CSC1_COEF0_UV_OFFSET_MASK)) |
610                            PXP_CSC1_COEF0_YCBCR_MODE_MASK | PXP_CSC1_COEF0_C0(0x12AU) /* 1.164. */
611                            | PXP_CSC1_COEF0_Y_OFFSET(0x1F0U)                          /* -16. */
612                            | PXP_CSC1_COEF0_UV_OFFSET(0x180U);                        /* -128. */
613         base->CSC1_COEF1 = PXP_CSC1_COEF1_C1(0x0198U)                                 /* 1.596. */
614                            | PXP_CSC1_COEF1_C4(0x0204U);                              /* 2.017. */
615         base->CSC1_COEF2 = PXP_CSC1_COEF2_C2(0x0730U)                                 /* -0.813. */
616                            | PXP_CSC1_COEF2_C3(0x079CU);                              /* -0.392. */
617     }
618 }
619 
620 #if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
621 /*!
622  * brief Set the LUT configuration.
623  *
624  * The lookup table (LUT) is used to modify pixels in a manner that is not linear
625  * and that cannot be achieved by the color space conversion modules. To setup
626  * the LUT, the complete workflow is:
627  * 1. Use ref PXP_SetLutConfig to set the configuration, such as the lookup mode.
628  * 2. Use ref PXP_LoadLutTable to load the lookup table to PXP.
629  * 3. Use ref PXP_EnableLut to enable the function.
630  *
631  * param base PXP peripheral base address.
632  * param config Pointer to the configuration.
633  */
PXP_SetLutConfig(PXP_Type * base,const pxp_lut_config_t * config)634 void PXP_SetLutConfig(PXP_Type *base, const pxp_lut_config_t *config)
635 {
636     base->LUT_CTRL = (base->LUT_CTRL & ~(PXP_LUT_CTRL_OUT_MODE_MASK | PXP_LUT_CTRL_LOOKUP_MODE_MASK)) |
637                      PXP_LUT_CTRL_LRU_UPD_MASK | /* Use Least Recently Used Policy Update Control. */
638                      PXP_LUT_CTRL_OUT_MODE(config->outMode) | PXP_LUT_CTRL_LOOKUP_MODE(config->lookupMode);
639 
640     if (kPXP_LutOutRGBW4444CFA == config->outMode)
641     {
642         base->CFA = config->cfaValue;
643     }
644 }
645 
646 /*!
647  * brief Set the look up table to PXP.
648  *
649  * If lookup mode is DIRECT mode, this function loads p bytesNum of values
650  * from the address p memAddr into PXP LUT address p lutStartAddr. So this
651  * function allows only update part of the PXP LUT.
652  *
653  * If lookup mode is CACHE mode, this function sets the new address to p memAddr
654  * and invalid the PXP LUT cache.
655  *
656  * param base PXP peripheral base address.
657  * param lookupMode Which lookup mode is used. Note that this parameter is only
658  * used to distinguish DIRECT mode and CACHE mode, it does not change the register
659  * value PXP_LUT_CTRL[LOOKUP_MODE]. To change that value, use function ref PXP_SetLutConfig.
660  * param bytesNum How many bytes to set. This value must be divisable by 8.
661  * param memAddr Address of look up table to set.
662  * param lutStartAddr The LUT value will be loaded to LUT from index lutAddr. It should
663  * be 8 bytes aligned.
664  *
665  * retval kStatus_Success Load successfully.
666  * retval kStatus_InvalidArgument Failed because of invalid argument.
667  */
PXP_LoadLutTable(PXP_Type * base,pxp_lut_lookup_mode_t lookupMode,uint32_t bytesNum,uint32_t memAddr,uint16_t lutStartAddr)668 status_t PXP_LoadLutTable(
669     PXP_Type *base, pxp_lut_lookup_mode_t lookupMode, uint32_t bytesNum, uint32_t memAddr, uint16_t lutStartAddr)
670 {
671     memAddr = PXP_ADDR_CPU_2_IP(memAddr);
672 
673     if (kPXP_LutCacheRGB565 == lookupMode)
674     {
675         /* Make sure the previous memory write is finished, especially the LUT data memory. */
676         __DSB();
677 
678         base->LUT_EXTMEM = memAddr;
679         /* Invalid cache. */
680         base->LUT_CTRL |= PXP_LUT_CTRL_INVALID_MASK;
681     }
682     else
683     {
684         /* Number of bytes must be divisable by 8. */
685         if ((bytesNum & 0x07U) || (bytesNum < 8U) || (lutStartAddr & 0x07U) ||
686             (bytesNum + lutStartAddr > PXP_LUT_TABLE_BYTE))
687         {
688             return kStatus_InvalidArgument;
689         }
690 
691         base->LUT_EXTMEM = memAddr;
692         base->LUT_ADDR   = PXP_LUT_ADDR_ADDR(lutStartAddr) | PXP_LUT_ADDR_NUM_BYTES(bytesNum);
693 
694         base->STAT_CLR = PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK;
695 
696         /* Start DMA transfer. */
697         base->LUT_CTRL |= PXP_LUT_CTRL_DMA_START_MASK;
698 
699         __DSB();
700 
701         /* Wait for transfer completed. */
702         while (!(base->STAT & PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK))
703         {
704         }
705     }
706 
707     return kStatus_Success;
708 }
709 #endif /* FSL_FEATURE_PXP_HAS_NO_LUT */
710 
711 #if (defined(FSL_FEATURE_PXP_HAS_DITHER) && FSL_FEATURE_PXP_HAS_DITHER)
712 /*!
713  * brief Write data to the PXP internal memory.
714  *
715  * param base PXP peripheral base address.
716  * param ram Which internal memory to write.
717  * param bytesNum How many bytes to write.
718  * param data Pointer to the data to write.
719  * param memStartAddr The start address in the internal memory to write the data.
720  */
PXP_SetInternalRamData(PXP_Type * base,pxp_ram_t ram,uint32_t bytesNum,uint8_t * data,uint16_t memStartAddr)721 void PXP_SetInternalRamData(PXP_Type *base, pxp_ram_t ram, uint32_t bytesNum, uint8_t *data, uint16_t memStartAddr)
722 {
723     assert((memStartAddr + bytesNum) <= PXP_INTERNAL_RAM_LUT_BYTE);
724 
725     base->INIT_MEM_CTRL =
726         PXP_INIT_MEM_CTRL_ADDR(memStartAddr) | PXP_INIT_MEM_CTRL_SELECT(ram) | PXP_INIT_MEM_CTRL_START_MASK;
727 
728     while (bytesNum--)
729     {
730         base->INIT_MEM_DATA = (uint32_t)(*data);
731         data++;
732     }
733 
734     base->INIT_MEM_CTRL = 0U;
735 }
736 
737 /*!
738  * brief Set the dither final LUT data.
739  *
740  * The dither final LUT is only applicble to dither engine 0. It takes the bits[7:4]
741  * of the output pixel and looks up and 8 bit value from the 16 value LUT to generate
742  * the final output pixel to the next process module.
743  *
744  * param base PXP peripheral base address.
745  * param data Pointer to the LUT data to set.
746  */
PXP_SetDitherFinalLutData(PXP_Type * base,const pxp_dither_final_lut_data_t * data)747 void PXP_SetDitherFinalLutData(PXP_Type *base, const pxp_dither_final_lut_data_t *data)
748 {
749     base->DITHER_FINAL_LUT_DATA0 = data->data_3_0;
750     base->DITHER_FINAL_LUT_DATA1 = data->data_7_4;
751     base->DITHER_FINAL_LUT_DATA2 = data->data_11_8;
752     base->DITHER_FINAL_LUT_DATA3 = data->data_15_12;
753 }
754 
755 /*!
756  * brief Enable or disable dither engine in the PXP process path.
757  *
758  * After the initialize function ref PXP_Init, the dither engine is disabled and not
759  * use in the PXP processing path. This function enables the dither engine and
760  * routes the dither engine output to the output buffer. When the dither engine
761  * is enabled using this function, ref PXP_SetDitherConfig must be called to
762  * configure dither engine correctly, otherwise there is not output to the output
763  * buffer.
764  *
765  * param base PXP peripheral base address.
766  * param enable Pass in true to enable, false to disable.
767  */
PXP_EnableDither(PXP_Type * base,bool enable)768 void PXP_EnableDither(PXP_Type *base, bool enable)
769 {
770     if (enable)
771     {
772         base->CTRL_SET = PXP_CTRL_ENABLE_DITHER_MASK;
773         /* Route dither output to output buffer. */
774         base->DATA_PATH_CTRL0 &= ~PXP_DATA_PATH_CTRL0_MUX14_SEL_MASK;
775     }
776     else
777     {
778         base->CTRL_CLR = PXP_CTRL_ENABLE_DITHER_MASK;
779         /* Route MUX 12 output to output buffer. */
780         base->DATA_PATH_CTRL0 |= PXP_DATA_PATH_CTRL0_MUX14_SEL(1U);
781     }
782 }
783 #endif /* FSL_FEATURE_PXP_HAS_DITHER */
784 
785 /*!
786  * brief Set the Porter Duff configuration.
787  *
788  * param base PXP peripheral base address.
789  * param config Pointer to the configuration.
790  */
PXP_SetPorterDuffConfig(PXP_Type * base,const pxp_porter_duff_config_t * config)791 void PXP_SetPorterDuffConfig(PXP_Type *base, const pxp_porter_duff_config_t *config)
792 {
793     assert(NULL != config);
794 
795     union
796     {
797         pxp_porter_duff_config_t pdConfigStruct;
798         uint32_t u32;
799     } pdConfig;
800 
801     pdConfig.pdConfigStruct = *config;
802 
803     base->PORTER_DUFF_CTRL = pdConfig.u32;
804 }
805 
806 /*!
807  * brief Get the Porter Duff configuration by blend mode.
808  *
809  * param mode The blend mode.
810  * param config Pointer to the configuration.
811  * retval kStatus_Success Successfully get the configuratoin.
812  * retval kStatus_InvalidArgument The blend mode not supported.
813  */
PXP_GetPorterDuffConfig(pxp_porter_duff_blend_mode_t mode,pxp_porter_duff_config_t * config)814 status_t PXP_GetPorterDuffConfig(pxp_porter_duff_blend_mode_t mode, pxp_porter_duff_config_t *config)
815 {
816     status_t status;
817 
818     union
819     {
820         pxp_porter_duff_config_t pdConfigStruct;
821         uint32_t u32;
822     } pdConfig;
823 
824     static const uint32_t pdCtrl[] = {
825         /* kPXP_PorterDuffSrc */
826         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
827             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorOne) |
828             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
829 
830         /* kPXP_PorterDuffAtop */
831         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
832             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorStraight) |
833             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
834 
835         /* kPXP_PorterDuffOver */
836         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
837             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorOne) |
838             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
839 
840         /* kPXP_PorterDuffIn */
841         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
842             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorStraight) |
843             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
844 
845         /* kPXP_PorterDuffOut */
846         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
847             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
848             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
849 
850         /* kPXP_PorterDuffDst */
851         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
852             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
853             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorOne),
854 
855         /* kPXP_PorterDuffDstAtop */
856         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
857             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
858             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorStraight),
859 
860         /* kPXP_PorterDuffDstOver */
861         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
862             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
863             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorOne),
864 
865         /* kPXP_PorterDuffDstIn */
866         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
867             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
868             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorStraight),
869 
870         /* kPXP_PorterDuffDstOut */
871         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
872             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
873             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
874 
875         /* kPXP_PorterDuffXor */
876         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
877             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
878             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
879 
880         /* kPXP_PorterDuffClear */
881         PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK |
882             PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
883             PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
884     };
885 
886     if (mode >= kPXP_PorterDuffMax)
887     {
888         status = kStatus_InvalidArgument;
889     }
890     else
891     {
892         pdConfig.u32 = pdCtrl[(uint32_t)mode] | PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
893                        PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
894                        PXP_PORTER_DUFF_CTRL_S0_COLOR_MODE(kPXP_PorterDuffColorWithAlpha) |
895                        PXP_PORTER_DUFF_CTRL_S1_COLOR_MODE(kPXP_PorterDuffColorWithAlpha) |
896                        PXP_PORTER_DUFF_CTRL_S0_ALPHA_MODE(kPXP_PorterDuffAlphaStraight) |
897                        PXP_PORTER_DUFF_CTRL_S1_ALPHA_MODE(kPXP_PorterDuffAlphaStraight);
898 
899         *config = pdConfig.pdConfigStruct;
900 
901         status = kStatus_Success;
902     }
903 
904     return status;
905 }
906 
PXP_StartRectCopy(PXP_Type * base,uint32_t srcAddr,uint16_t srcPitchBytes,uint32_t destAddr,uint16_t destPitchBytes,uint16_t width,uint16_t height,pxp_as_pixel_format_t pixelFormat)907 static void PXP_StartRectCopy(PXP_Type *base,
908                               uint32_t srcAddr,
909                               uint16_t srcPitchBytes,
910                               uint32_t destAddr,
911                               uint16_t destPitchBytes,
912                               uint16_t width,
913                               uint16_t height,
914                               pxp_as_pixel_format_t pixelFormat)
915 {
916     pxp_output_buffer_config_t outputBufferConfig;
917     pxp_as_buffer_config_t asBufferConfig;
918     uint32_t intMask;
919 
920 #if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
921     intMask =
922         base->CTRL & (PXP_CTRL_NEXT_IRQ_ENABLE_MASK | PXP_CTRL_IRQ_ENABLE_MASK | PXP_CTRL_LUT_DMA_IRQ_ENABLE_MASK);
923 #else
924     intMask = base->CTRL & (PXP_CTRL_NEXT_IRQ_ENABLE_MASK | PXP_CTRL_IRQ_ENABLE_MASK);
925 #endif
926 
927     PXP_ResetToInit(base);
928 
929     /* Restore previous interrupt configuration. */
930     PXP_EnableInterrupts(base, intMask);
931 
932     /* Disable PS */
933     PXP_SetProcessSurfacePosition(base, 0xFFFFU, 0xFFFFU, 0U, 0U);
934 
935     /* Input buffer. */
936     asBufferConfig.pixelFormat = pixelFormat;
937     asBufferConfig.bufferAddr  = srcAddr;
938     asBufferConfig.pitchBytes  = srcPitchBytes;
939 
940     PXP_SetAlphaSurfaceBufferConfig(base, &asBufferConfig);
941     PXP_SetAlphaSurfacePosition(base, 0U, 0U, width - 1U, height - 1U);
942 
943     /* Alpha mode set to ROP, AS OR PS*/
944     const pxp_as_blend_config_t asBlendConfig = {
945         .alpha = 0U, .invertAlpha = false, .alphaMode = kPXP_AlphaRop, .ropMode = kPXP_RopMergeAs};
946 
947     PXP_SetAlphaSurfaceBlendConfig(base, &asBlendConfig);
948 
949     /* Output buffer. */
950     outputBufferConfig.pixelFormat    = (pxp_output_pixel_format_t)pixelFormat;
951     outputBufferConfig.interlacedMode = kPXP_OutputProgressive;
952     outputBufferConfig.buffer0Addr    = destAddr;
953     outputBufferConfig.buffer1Addr    = 0U;
954     outputBufferConfig.pitchBytes     = destPitchBytes;
955     outputBufferConfig.width          = width;
956     outputBufferConfig.height         = height;
957 
958     PXP_SetOutputBufferConfig(base, &outputBufferConfig);
959 
960     PXP_ClearStatusFlags(base, (uint32_t)kPXP_CompleteFlag);
961 
962     PXP_Start(base);
963 }
964 
965 /*!
966  * brief Copy picture from one buffer to another buffer.
967  *
968  * This function copies a rectangle from one buffer to another buffer.
969  *
970  * param base PXP peripheral base address.
971  * retval kStatus_Success Successfully started the copy process.
972  * retval kStatus_InvalidArgument Invalid argument.
973  */
PXP_StartPictureCopy(PXP_Type * base,const pxp_pic_copy_config_t * config)974 status_t PXP_StartPictureCopy(PXP_Type *base, const pxp_pic_copy_config_t *config)
975 {
976     uint8_t bytePerPixel;
977     uint32_t copyFromAddr;
978     uint32_t copyToAddr;
979 
980     if ((0U == config->height) || (0U == config->width))
981     {
982         return kStatus_InvalidArgument;
983     }
984 
985     if ((config->pixelFormat == kPXP_AsPixelFormatARGB8888) || (config->pixelFormat == kPXP_AsPixelFormatRGB888))
986     {
987         bytePerPixel = 4U;
988     }
989     else
990     {
991         bytePerPixel = 2U;
992     }
993 
994     copyFromAddr = config->srcPicBaseAddr + ((uint32_t)config->srcOffsetY * (uint32_t)config->srcPitchBytes) +
995                    bytePerPixel * config->srcOffsetX;
996     copyToAddr = config->destPicBaseAddr + ((uint32_t)config->destOffsetY * (uint32_t)config->destPitchBytes) +
997                  bytePerPixel * config->destOffsetX;
998 
999     PXP_StartRectCopy(base, copyFromAddr, config->srcPitchBytes, copyToAddr, config->destPitchBytes, config->width,
1000                       config->height, config->pixelFormat);
1001 
1002     return kStatus_Success;
1003 }
1004 
1005 /*!
1006  * brief Copy continous memory.
1007  *
1008  * The copy size should be 512 byte aligned.
1009  *
1010  * param base PXP peripheral base address.
1011  * retval kStatus_Success Successfully started the copy process.
1012  * retval kStatus_InvalidArgument Invalid argument.
1013  */
PXP_StartMemCopy(PXP_Type * base,uint32_t srcAddr,uint32_t destAddr,uint32_t size)1014 status_t PXP_StartMemCopy(PXP_Type *base, uint32_t srcAddr, uint32_t destAddr, uint32_t size)
1015 {
1016     uint16_t pitchBytes;
1017     uint32_t height;
1018 
1019     if ((0U == size) || ((size % 512U) != 0U))
1020     {
1021         return kStatus_InvalidArgument;
1022     }
1023 
1024     /*
1025      * By default, PXP process block is 8x8. For better performance, choose
1026      * width and height dividable by block size.
1027      */
1028     if (size < 8U * 512U)
1029     {
1030         height     = 8U;
1031         pitchBytes = (uint16_t)(size / height);
1032     }
1033     else
1034     {
1035         pitchBytes = 512U;
1036         height     = size / pitchBytes;
1037     }
1038 
1039     if (height > PXP_MAX_HEIGHT)
1040     {
1041         return kStatus_InvalidArgument;
1042     }
1043 
1044     PXP_StartRectCopy(base, srcAddr, pitchBytes, destAddr, pitchBytes, pitchBytes / 4U, (uint16_t)height,
1045                       kPXP_AsPixelFormatARGB8888);
1046 
1047     return kStatus_Success;
1048 }
1049