Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:01

0001 /*
0002  * Copyright 2017-2022 NXP
0003  * All rights reserved.
0004  *
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_pxp.h"
0010 
0011 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
0012 #include "fsl_memory.h"
0013 #endif
0014 
0015 /*******************************************************************************
0016  * Definitions
0017  ******************************************************************************/
0018 
0019 /* Component ID definition, used by tools. */
0020 #ifndef FSL_COMPONENT_ID
0021 #define FSL_COMPONENT_ID "platform.drivers.pxp"
0022 #endif
0023 
0024 /* The CSC2 coefficient is ###.####_#### */
0025 #define PXP_CSC2_COEF_INT_WIDTH  2
0026 #define PXP_CSC2_COEF_FRAC_WIDTH 8
0027 
0028 /* Compatibility map macro. */
0029 #if defined(PXP_PS_CLRKEYLOW_0_PIXEL_MASK) && (!defined(PXP_PS_CLRKEYLOW_PIXEL_MASK))
0030 #define PS_CLRKEYLOW  PS_CLRKEYLOW_0
0031 #define PS_CLRKEYHIGH PS_CLRKEYHIGH_0
0032 #endif
0033 #if defined(PXP_AS_CLRKEYLOW_0_PIXEL_MASK) && (!defined(PXP_AS_CLRKEYLOW_PIXEL_MASK))
0034 #define AS_CLRKEYLOW  AS_CLRKEYLOW_0
0035 #define AS_CLRKEYHIGH AS_CLRKEYHIGH_0
0036 #endif
0037 
0038 #define PXP_MAX_HEIGHT ((PXP_OUT_LRC_Y_MASK >> PXP_OUT_LRC_Y_SHIFT) + 1U)
0039 
0040 /* Compatibility macro remap. */
0041 #if (!defined(PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK) && defined(PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK))
0042 #define PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK
0043 #endif
0044 
0045 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
0046 #define PXP_ADDR_CPU_2_IP(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_Local2DMA))
0047 #else
0048 #define PXP_ADDR_CPU_2_IP(addr) (addr)
0049 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
0050 
0051 #if !(defined(FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL) && FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL)
0052 #define S1_COLOR_MODE           PXP_PORTER_DUFF_CTRL_S1_COLOR_MODE
0053 #define S1_ALPHA_MODE           PXP_PORTER_DUFF_CTRL_S1_ALPHA_MODE
0054 #define S1_GLOBAL_ALPHA_MODE    PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE
0055 #define S1_S0_FACTOR_MODE       PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE
0056 #define S0_COLOR_MODE           PXP_PORTER_DUFF_CTRL_S0_COLOR_MODE
0057 #define S0_ALPHA_MODE           PXP_PORTER_DUFF_CTRL_S0_ALPHA_MODE
0058 #define S0_GLOBAL_ALPHA_MODE    PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE
0059 #define S0_S1_FACTOR_MODE       PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE
0060 #define PORTER_DUFF_ENABLE_MASK PXP_PORTER_DUFF_CTRL_PORTER_DUFF_ENABLE_MASK
0061 #endif /* FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL */
0062 
0063 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
0064 #define S1_COLOR_MODE           PXP_ALPHA_A_CTRL_S1_COLOR_MODE
0065 #define S1_ALPHA_MODE           PXP_ALPHA_A_CTRL_S1_ALPHA_MODE
0066 #define S1_GLOBAL_ALPHA_MODE    PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE
0067 #define S1_S0_FACTOR_MODE       PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE
0068 #define S0_COLOR_MODE           PXP_ALPHA_A_CTRL_S0_COLOR_MODE
0069 #define S0_ALPHA_MODE           PXP_ALPHA_A_CTRL_S0_ALPHA_MODE
0070 #define S0_GLOBAL_ALPHA_MODE    PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE
0071 #define S0_S1_FACTOR_MODE       PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE
0072 #define PORTER_DUFF_ENABLE_MASK PXP_ALPHA_A_CTRL_PORTER_DUFF_ENABLE_MASK
0073 #endif /* FSL_FEATURE_PXP_V3 */
0074 
0075 typedef union _u32_f32
0076 {
0077     float f32;
0078     uint32_t u32;
0079 } u32_f32_t;
0080 
0081 typedef union _pxp_pvoid_u32
0082 {
0083     void *pvoid;
0084     uint32_t u32;
0085 } pxp_pvoid_u32_t;
0086 
0087 /*******************************************************************************
0088  * Prototypes
0089  ******************************************************************************/
0090 /*!
0091  * @brief Get the instance from the base address
0092  *
0093  * @param base PXP peripheral base address
0094  *
0095  * @return The PXP module instance
0096  */
0097 static uint32_t PXP_GetInstance(PXP_Type *base);
0098 
0099 #if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
0100 /*!
0101  * @brief Convert IEEE 754 float value to the value could be written to registers.
0102  *
0103  * This function converts the float value to integer value to set the scaler
0104  * and CSC parameters.
0105  *
0106  * This function is an alternative implemention of the following code with no
0107  * MISRA 2004 rule 10.4 error:
0108  *
0109  * @code
0110    return (uint32_t)(floatValue * (float)(1 << fracBits));
0111    @endcode
0112  *
0113  * @param floatValue The float value to convert.
0114  * @param intBits Bits number of integer part in result.
0115  * @param fracBits Bits number of fractional part in result.
0116  * @return The value to set to register.
0117  */
0118 static uint32_t PXP_ConvertFloat(float floatValue, uint8_t intBits, uint8_t fracBits);
0119 #endif
0120 
0121 /*!
0122  * @brief Convert the desired scale fact to DEC and PS_SCALE.
0123  *
0124  * @param inputDimension Input dimension.
0125  * @param outputDimension Output dimension.
0126  * @param dec The decimation filter contr0l value.
0127  * @param scale The scale value set to register PS_SCALE.
0128  */
0129 static void PXP_GetScalerParam(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale);
0130 
0131 /*!
0132  * @brief Copy rectangle.
0133  *
0134  * @param base PXP peripheral base address.
0135  * @param srcAddr Start address of the soruce rectangle.
0136  * @param srcPitchBytes Pitch of source buffer.
0137  * @param destAddr Start address of the destination rectangle.
0138  * @param destPitchBytes Pitch of destination buffer.
0139  * @param width How many pixels one line to copy.
0140  * @param height How many lines to copy.
0141  * @param pixelFormat Pixel format.
0142  */
0143 static void PXP_StartRectCopy(PXP_Type *base,
0144                               uint32_t srcAddr,
0145                               uint16_t srcPitchBytes,
0146                               uint32_t destAddr,
0147                               uint16_t destPitchBytes,
0148                               uint16_t width,
0149                               uint16_t height,
0150                               pxp_as_pixel_format_t pixelFormat);
0151 
0152 /*******************************************************************************
0153  * Variables
0154  ******************************************************************************/
0155 /*! @brief Pointers to PXP bases for each instance. */
0156 static PXP_Type *const s_pxpBases[] = PXP_BASE_PTRS;
0157 
0158 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0159 /*! @brief Pointers to PXP clocks for each PXP submodule. */
0160 static const clock_ip_name_t s_pxpClocks[] = PXP_CLOCKS;
0161 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0162 
0163 /*******************************************************************************
0164  * Code
0165  ******************************************************************************/
0166 static uint32_t PXP_GetInstance(PXP_Type *base)
0167 {
0168     uint32_t instance;
0169 
0170     /* Find the instance index from base address mappings. */
0171     for (instance = 0; instance < ARRAY_SIZE(s_pxpBases); instance++)
0172     {
0173         if (s_pxpBases[instance] == base)
0174         {
0175             break;
0176         }
0177     }
0178 
0179     assert(instance < ARRAY_SIZE(s_pxpBases));
0180 
0181     return instance;
0182 }
0183 
0184 #if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
0185 static uint32_t PXP_ConvertFloat(float floatValue, uint8_t intBits, uint8_t fracBits)
0186 {
0187     /* One bit reserved for sign bit. */
0188     assert(intBits + fracBits < 32U);
0189 
0190     u32_f32_t u32_f32;
0191     uint32_t ret;
0192 
0193     u32_f32.f32        = floatValue;
0194     uint32_t floatBits = u32_f32.u32;
0195     int32_t expValue   = (int32_t)((uint16_t)((floatBits & 0x7F800000UL) >> 23U)) - 127;
0196 
0197     ret = (floatBits & 0x007FFFFFU) | 0x00800000U;
0198     expValue += (int32_t)fracBits;
0199 
0200     if (expValue < 0)
0201     {
0202         return 0U;
0203     }
0204     else if (expValue > 23)
0205     {
0206         /* should not exceed 31-bit when left shift. */
0207         assert((expValue - 23) <= 7);
0208         ret <<= ((uint16_t)expValue - 23U);
0209     }
0210     else
0211     {
0212         ret >>= (23U - (uint16_t)expValue);
0213     }
0214 
0215     /* Set the sign bit. */
0216     if ((floatBits & 0x80000000UL) != 0U)
0217     {
0218         ret = ((~ret) + 1UL) & ~(((uint32_t)-1) << ((uint32_t)intBits + (uint32_t)fracBits + 1UL));
0219     }
0220 
0221     return ret;
0222 }
0223 #endif
0224 
0225 static void PXP_GetScalerParam(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale)
0226 {
0227     uint32_t scaleFact = ((uint32_t)inputDimension << 12U) / outputDimension;
0228 
0229     if (scaleFact >= (16UL << 12U))
0230     {
0231         /* Desired fact is two large, use the largest support value. */
0232         *dec   = 3U;
0233         *scale = 0x2000U;
0234     }
0235     else
0236     {
0237         if (scaleFact > (8UL << 12U))
0238         {
0239             *dec = 3U;
0240         }
0241         else if (scaleFact > (4UL << 12U))
0242         {
0243             *dec = 2U;
0244         }
0245         else if (scaleFact > (2UL << 12U))
0246         {
0247             *dec = 1U;
0248         }
0249         else
0250         {
0251             *dec = 0U;
0252         }
0253 
0254         *scale = scaleFact >> (*dec);
0255 
0256         if (0U == *scale)
0257         {
0258             *scale = 1U;
0259         }
0260     }
0261 }
0262 
0263 /*!
0264  * brief Reset the PXP and the control register to initialized state.
0265  *
0266  * param base PXP peripheral base address.
0267  */
0268 void PXP_ResetControl(PXP_Type *base)
0269 {
0270     uint32_t ctrl = 0U;
0271 
0272     PXP_Reset(base);
0273 
0274 /* Enable the process engine in primary processing flow. */
0275 #if defined(PXP_CTRL_ENABLE_ROTATE0_MASK)
0276     ctrl |= PXP_CTRL_ENABLE_ROTATE0_MASK;
0277 #endif
0278 #if defined(PXP_CTRL_ENABLE_ROTATE1_MASK)
0279     ctrl |= PXP_CTRL_ENABLE_ROTATE1_MASK;
0280 #endif
0281 #if defined(PXP_CTRL_ENABLE_CSC2_MASK)
0282     ctrl |= PXP_CTRL_ENABLE_CSC2_MASK;
0283 #endif
0284 #if defined(PXP_CTRL_ENABLE_LUT_MASK)
0285     ctrl |= PXP_CTRL_ENABLE_LUT_MASK;
0286 #endif
0287 #if defined(PXP_CTRL_ENABLE_PS_AS_OUT_MASK)
0288     ctrl |= PXP_CTRL_ENABLE_PS_AS_OUT_MASK;
0289 #endif
0290 
0291     base->CTRL = ctrl;
0292 }
0293 
0294 /*!
0295  * brief Initialize the PXP.
0296  *
0297  * This function enables the PXP peripheral clock, and resets the PXP registers
0298  * to default status.
0299  *
0300  * param base PXP peripheral base address.
0301  */
0302 void PXP_Init(PXP_Type *base)
0303 {
0304 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0305     uint32_t instance = PXP_GetInstance(base);
0306     CLOCK_EnableClock(s_pxpClocks[instance]);
0307 #endif
0308 
0309     PXP_ResetControl(base);
0310 
0311     /* Disable the alpha surface. */
0312     PXP_SetAlphaSurfacePosition(base, 0xFFFFU, 0xFFFFU, 0U, 0U);
0313 }
0314 
0315 /*!
0316  * brief De-initialize the PXP.
0317  *
0318  * This function disables the PXP peripheral clock.
0319  *
0320  * param base PXP peripheral base address.
0321  */
0322 void PXP_Deinit(PXP_Type *base)
0323 {
0324 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0325     uint32_t instance = PXP_GetInstance(base);
0326     CLOCK_DisableClock(s_pxpClocks[instance]);
0327 #endif
0328 }
0329 
0330 /*!
0331  * brief Reset the PXP.
0332  *
0333  * This function resets the PXP peripheral registers to default status.
0334  *
0335  * param base PXP peripheral base address.
0336  */
0337 void PXP_Reset(PXP_Type *base)
0338 {
0339     base->CTRL_SET = PXP_CTRL_SFTRST_MASK;
0340     base->CTRL_CLR = (PXP_CTRL_SFTRST_MASK | PXP_CTRL_CLKGATE_MASK);
0341 }
0342 
0343 /*!
0344  * brief Set the alpha surface input buffer configuration.
0345  *
0346  * param base PXP peripheral base address.
0347  * param config Pointer to the configuration.
0348  */
0349 void PXP_SetAlphaSurfaceBufferConfig(PXP_Type *base, const pxp_as_buffer_config_t *config)
0350 {
0351     assert(NULL != config);
0352 
0353     base->AS_CTRL = (base->AS_CTRL & ~PXP_AS_CTRL_FORMAT_MASK) | PXP_AS_CTRL_FORMAT(config->pixelFormat);
0354 
0355     base->AS_BUF   = PXP_ADDR_CPU_2_IP(config->bufferAddr);
0356     base->AS_PITCH = config->pitchBytes;
0357 }
0358 
0359 /*!
0360  * brief Set the alpha surface blending configuration.
0361  *
0362  * param base PXP peripheral base address.
0363  * param config Pointer to the configuration structure.
0364  */
0365 void PXP_SetAlphaSurfaceBlendConfig(PXP_Type *base, const pxp_as_blend_config_t *config)
0366 {
0367     assert(NULL != config);
0368     uint32_t reg;
0369 
0370     reg = base->AS_CTRL;
0371     reg &=
0372         ~(PXP_AS_CTRL_ALPHA0_INVERT_MASK | PXP_AS_CTRL_ROP_MASK | PXP_AS_CTRL_ALPHA_MASK | PXP_AS_CTRL_ALPHA_CTRL_MASK);
0373     reg |= (PXP_AS_CTRL_ROP(config->ropMode) | PXP_AS_CTRL_ALPHA(config->alpha) |
0374             PXP_AS_CTRL_ALPHA_CTRL(config->alphaMode));
0375 
0376     if (config->invertAlpha)
0377     {
0378         reg |= PXP_AS_CTRL_ALPHA0_INVERT_MASK;
0379     }
0380 
0381     base->AS_CTRL = reg;
0382 }
0383 
0384 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
0385 /*!
0386  * brief Set the alpha surface blending configuration for the secondary engine.
0387  *
0388  * param base PXP peripheral base address.
0389  * param config Pointer to the configuration structure.
0390  */
0391 void PXP_SetAlphaSurfaceBlendSecondaryConfig(PXP_Type *base, const pxp_as_blend_secondary_config_t *config)
0392 {
0393     assert(NULL != config);
0394 
0395     base->ALPHA_B_CTRL_1 =
0396         (base->ALPHA_B_CTRL_1 & ~(PXP_ALPHA_B_CTRL_1_ROP_MASK | PXP_ALPHA_B_CTRL_1_ROP_ENABLE_MASK)) |
0397         PXP_ALPHA_B_CTRL_1_ROP((uint32_t)config->ropMode) | PXP_ALPHA_B_CTRL_1_ROP_ENABLE((uint32_t)config->ropEnable);
0398 
0399     if (config->invertAlpha)
0400     {
0401         base->AS_CTRL |= PXP_AS_CTRL_ALPHA1_INVERT_MASK;
0402     }
0403     else
0404     {
0405         base->AS_CTRL &= ~PXP_AS_CTRL_ALPHA1_INVERT_MASK;
0406     }
0407 }
0408 #endif /* FSL_FEATURE_PXP_V3 */
0409 
0410 /*!
0411  * brief Set the alpha surface position in output buffer.
0412  *
0413  * param base PXP peripheral base address.
0414  * param upperLeftX X of the upper left corner.
0415  * param upperLeftY Y of the upper left corner.
0416  * param lowerRightX X of the lower right corner.
0417  * param lowerRightY Y of the lower right corner.
0418  */
0419 void PXP_SetAlphaSurfacePosition(
0420     PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY)
0421 {
0422     base->OUT_AS_ULC = PXP_OUT_AS_ULC_Y(upperLeftY) | PXP_OUT_AS_ULC_X(upperLeftX);
0423     base->OUT_AS_LRC = PXP_OUT_AS_LRC_Y(lowerRightY) | PXP_OUT_AS_LRC_X(lowerRightX);
0424 }
0425 
0426 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
0427 /*!
0428  * brief Set the alpha surface overlay color key.
0429  *
0430  * If a pixel in the current overlay image with a color that falls in the range
0431  * from the p colorKeyLow to p colorKeyHigh range, it will use the process surface
0432  * pixel value for that location. If no PS image is present or if the PS image also
0433  * matches its colorkey range, the PS background color is used.
0434  *
0435  * param base PXP peripheral base address.
0436  * param num instance number. 0 for alpha engine A, 1 for alpha engine B.
0437  * param colorKeyLow Color key low range.
0438  * param colorKeyHigh Color key high range.
0439  *
0440  * note Colorkey operations are higher priority than alpha or ROP operations
0441  */
0442 void PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type *base, uint8_t num, uint32_t colorKeyLow, uint32_t colorKeyHigh)
0443 {
0444     switch (num)
0445     {
0446         case 0:
0447             base->AS_CLRKEYLOW  = colorKeyLow;
0448             base->AS_CLRKEYHIGH = colorKeyHigh;
0449             break;
0450 
0451         case 1:
0452             base->AS_CLRKEYLOW_1  = colorKeyLow;
0453             base->AS_CLRKEYHIGH_1 = colorKeyHigh;
0454             break;
0455 
0456         default:
0457             /* Only 2 alpha process engine instances are supported. */
0458             assert(false);
0459             break;
0460     }
0461 }
0462 #else
0463 /*!
0464  * brief Set the alpha surface overlay color key.
0465  *
0466  * If a pixel in the current overlay image with a color that falls in the range
0467  * from the p colorKeyLow to p colorKeyHigh range, it will use the process surface
0468  * pixel value for that location. If no PS image is present or if the PS image also
0469  * matches its colorkey range, the PS background color is used.
0470  *
0471  * param base PXP peripheral base address.
0472  * param colorKeyLow Color key low range.
0473  * param colorKeyHigh Color key high range.
0474  *
0475  * note Colorkey operations are higher priority than alpha or ROP operations
0476  */
0477 void PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
0478 {
0479     base->AS_CLRKEYLOW  = colorKeyLow;
0480     base->AS_CLRKEYHIGH = colorKeyHigh;
0481 }
0482 #endif /* FSL_FEATURE_PXP_V3 */
0483 
0484 /*!
0485  * brief Set the process surface input buffer configuration.
0486  *
0487  * param base PXP peripheral base address.
0488  * param config Pointer to the configuration.
0489  */
0490 void PXP_SetProcessSurfaceBufferConfig(PXP_Type *base, const pxp_ps_buffer_config_t *config)
0491 {
0492     assert(NULL != config);
0493 
0494     base->PS_CTRL = ((base->PS_CTRL & ~(PXP_PS_CTRL_FORMAT_MASK | PXP_PS_CTRL_WB_SWAP_MASK)) |
0495                      PXP_PS_CTRL_FORMAT(config->pixelFormat) | PXP_PS_CTRL_WB_SWAP(config->swapByte));
0496 
0497     base->PS_BUF   = PXP_ADDR_CPU_2_IP(config->bufferAddr);
0498     base->PS_UBUF  = PXP_ADDR_CPU_2_IP(config->bufferAddrU);
0499     base->PS_VBUF  = PXP_ADDR_CPU_2_IP(config->bufferAddrV);
0500     base->PS_PITCH = config->pitchBytes;
0501 }
0502 
0503 /*!
0504  * brief Set the process surface scaler configuration.
0505  *
0506  * The valid down scale fact is 1/(2^12) ~ 16.
0507  *
0508  * param base PXP peripheral base address.
0509  * param inputWidth Input image width.
0510  * param inputHeight Input image height.
0511  * param outputWidth Output image width.
0512  * param outputHeight Output image height.
0513  */
0514 void PXP_SetProcessSurfaceScaler(
0515     PXP_Type *base, uint16_t inputWidth, uint16_t inputHeight, uint16_t outputWidth, uint16_t outputHeight)
0516 {
0517     uint8_t decX, decY;
0518     uint32_t scaleX, scaleY;
0519 
0520     PXP_GetScalerParam(inputWidth, outputWidth, &decX, &scaleX);
0521     PXP_GetScalerParam(inputHeight, outputHeight, &decY, &scaleY);
0522 
0523     base->PS_CTRL = (base->PS_CTRL & ~(PXP_PS_CTRL_DECX_MASK | PXP_PS_CTRL_DECY_MASK)) | PXP_PS_CTRL_DECX(decX) |
0524                     PXP_PS_CTRL_DECY(decY);
0525 
0526     base->PS_SCALE = PXP_PS_SCALE_XSCALE(scaleX) | PXP_PS_SCALE_YSCALE(scaleY);
0527 }
0528 
0529 /*!
0530  * brief Set the process surface position in output buffer.
0531  *
0532  * param base PXP peripheral base address.
0533  * param upperLeftX X of the upper left corner.
0534  * param upperLeftY Y of the upper left corner.
0535  * param lowerRightX X of the lower right corner.
0536  * param lowerRightY Y of the lower right corner.
0537  */
0538 void PXP_SetProcessSurfacePosition(
0539     PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY)
0540 {
0541     base->OUT_PS_ULC = PXP_OUT_PS_ULC_Y(upperLeftY) | PXP_OUT_PS_ULC_X(upperLeftX);
0542     base->OUT_PS_LRC = PXP_OUT_PS_LRC_Y(lowerRightY) | PXP_OUT_PS_LRC_X(lowerRightX);
0543 }
0544 
0545 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
0546 /*!
0547  * brief Set the process surface color key.
0548  *
0549  * If the PS image matches colorkey range, the PS background color is output. Set
0550  * p colorKeyLow to 0xFFFFFFFF and p colorKeyHigh to 0 will disable the colorkeying.
0551  *
0552  * param base PXP peripheral base address.
0553  * param num instance number. 0 for alpha engine A, 1 for alpha engine B.
0554  * param colorKeyLow Color key low range.
0555  * param colorKeyHigh Color key high range.
0556  */
0557 void PXP_SetProcessSurfaceColorKey(PXP_Type *base, uint8_t num, uint32_t colorKeyLow, uint32_t colorKeyHigh)
0558 {
0559     switch (num)
0560     {
0561         case 0:
0562             base->PS_CLRKEYLOW  = colorKeyLow;
0563             base->PS_CLRKEYHIGH = colorKeyHigh;
0564             break;
0565 
0566         case 1:
0567             base->PS_CLRKEYLOW_1  = colorKeyLow;
0568             base->PS_CLRKEYHIGH_1 = colorKeyHigh;
0569             break;
0570 
0571         default:
0572             /* Only 2 alpha process engine instances are supported. */
0573             assert(false);
0574             break;
0575     }
0576 }
0577 #else
0578 /*!
0579  * brief Set the process surface color key.
0580  *
0581  * If the PS image matches colorkey range, the PS background color is output. Set
0582  * p colorKeyLow to 0xFFFFFFFF and p colorKeyHigh to 0 will disable the colorkeying.
0583  *
0584  * param base PXP peripheral base address.
0585  * param colorKeyLow Color key low range.
0586  * param colorKeyHigh Color key high range.
0587  */
0588 void PXP_SetProcessSurfaceColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
0589 {
0590     base->PS_CLRKEYLOW  = colorKeyLow;
0591     base->PS_CLRKEYHIGH = colorKeyHigh;
0592 }
0593 #endif /* FSL_FEATURE_PXP_V3 */
0594 
0595 /*!
0596  * brief Set the PXP outpt buffer configuration.
0597  *
0598  * param base PXP peripheral base address.
0599  * param config Pointer to the configuration.
0600  */
0601 void PXP_SetOutputBufferConfig(PXP_Type *base, const pxp_output_buffer_config_t *config)
0602 {
0603     assert(NULL != config);
0604 
0605     base->OUT_CTRL = (base->OUT_CTRL & ~(PXP_OUT_CTRL_FORMAT_MASK | PXP_OUT_CTRL_INTERLACED_OUTPUT_MASK)) |
0606                      PXP_OUT_CTRL_FORMAT(config->pixelFormat) | PXP_OUT_CTRL_INTERLACED_OUTPUT(config->interlacedMode);
0607 
0608     base->OUT_BUF  = PXP_ADDR_CPU_2_IP(config->buffer0Addr);
0609     base->OUT_BUF2 = PXP_ADDR_CPU_2_IP(config->buffer1Addr);
0610 
0611     base->OUT_PITCH = config->pitchBytes;
0612     base->OUT_LRC   = PXP_OUT_LRC_Y((uint32_t)config->height - 1U) | PXP_OUT_LRC_X((uint32_t)config->width - 1U);
0613 
0614 /*
0615  * The dither store size must be set to the same with the output buffer size,
0616  * otherwise the dither engine could not work.
0617  */
0618 #if defined(PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH_MASK)
0619     base->DITHER_STORE_SIZE_CH0 = PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH((uint32_t)config->width - 1U) |
0620                                   PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT((uint32_t)config->height - 1U);
0621 #endif
0622 }
0623 
0624 /*!
0625  * brief Build a solid rectangle of given pixel value.
0626  *
0627  * param base PXP peripheral base address.
0628  * param outFormat output pixel format.
0629  * param value The value of the pixel to be filled in the rectangle in ARGB8888 format.
0630  * param width width of the rectangle.
0631  * param height height of the rectangle.
0632  * param pitch output pitch in byte.
0633  * param outAddr address of the memory to store the rectangle.
0634  */
0635 void PXP_BuildRect(PXP_Type *base,
0636                    pxp_output_pixel_format_t outFormat,
0637                    uint32_t value,
0638                    uint16_t width,
0639                    uint16_t height,
0640                    uint16_t pitch,
0641                    uint32_t outAddr)
0642 {
0643     /* Only support RGB format output. */
0644     assert((uint8_t)outFormat <= (uint8_t)kPXP_OutputPixelFormatRGB565);
0645 
0646     /* PS configuration */
0647 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
0648     PXP_SetProcessSurfaceBackGroundColor(base, 0U, value);
0649 #else
0650     PXP_SetProcessSurfaceBackGroundColor(base, value);
0651 #endif
0652     PXP_SetProcessSurfacePosition(base, 0xFFFF, 0xFFFF, 0, 0);
0653 
0654     if ((outFormat == kPXP_OutputPixelFormatARGB8888) || (outFormat == kPXP_OutputPixelFormatARGB1555) ||
0655         (outFormat == kPXP_OutputPixelFormatARGB4444))
0656     {
0657         uint8_t alpha                         = (uint8_t)(value >> 24U);
0658         pxp_as_buffer_config_t asBufferConfig = {
0659             .pixelFormat = kPXP_AsPixelFormatARGB8888,
0660             .bufferAddr  = outAddr,
0661             .pitchBytes  = pitch,
0662         };
0663         PXP_SetAlphaSurfaceBufferConfig(base, &asBufferConfig);
0664 
0665         pxp_as_blend_config_t asBlendConfig = {
0666             .alpha = alpha, .invertAlpha = false, .alphaMode = kPXP_AlphaOverride, .ropMode = kPXP_RopMergeAs};
0667         PXP_SetAlphaSurfaceBlendConfig(base, &asBlendConfig);
0668 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
0669         PXP_SetAlphaSurfaceOverlayColorKey(base, 0U, 0U, 0xFFFFFFFFUL);
0670         PXP_EnableAlphaSurfaceOverlayColorKey(base, 0U, true);
0671 #else
0672         PXP_SetAlphaSurfaceOverlayColorKey(base, 0U, 0xFFFFFFFFUL);
0673         PXP_EnableAlphaSurfaceOverlayColorKey(base, true);
0674 #endif
0675         PXP_SetAlphaSurfacePosition(base, 0, 0, width, height);
0676     }
0677     else
0678     {
0679         /* No need to configure AS for formats that do not have alpha value. */
0680         PXP_SetAlphaSurfacePosition(base, 0xFFFFU, 0xFFFFU, 0, 0);
0681     }
0682 
0683     /* Output config. */
0684     pxp_output_buffer_config_t outputBufferConfig;
0685     outputBufferConfig.pixelFormat    = outFormat;
0686     outputBufferConfig.interlacedMode = kPXP_OutputProgressive;
0687     outputBufferConfig.buffer0Addr    = outAddr;
0688     outputBufferConfig.buffer1Addr    = 0U;
0689     outputBufferConfig.pitchBytes     = pitch;
0690     outputBufferConfig.width          = width;
0691     outputBufferConfig.height         = height;
0692     PXP_SetOutputBufferConfig(base, &outputBufferConfig);
0693 
0694     PXP_EnableCsc1(base, false);
0695 
0696 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
0697     PXP_SetPath(PXP, kPXP_Mux3SelectCsc1Engine);
0698     PXP_SetPath(PXP, kPXP_Mux8SelectAlphaBlending0);
0699     PXP_SetPath(PXP, kPXP_Mux11SelectMux8);
0700     PXP_SetPath(PXP, kPXP_Mux14SelectMux11);
0701     PXP_SetPath(PXP, kPXP_Mux0SelectNone);
0702     PXP_SetPath(PXP, kPXP_Mux6SelectNone);
0703     PXP_SetPath(PXP, kPXP_Mux9SelectNone);
0704     PXP_SetPath(PXP, kPXP_Mux12SelectNone);
0705 #endif
0706 
0707     PXP_ClearStatusFlags(base, (uint32_t)kPXP_CompleteFlag);
0708     /* Start PXP. */
0709     PXP_Start(base);
0710     /* Wait for process complete. */
0711     while (0UL == ((uint32_t)kPXP_CompleteFlag & PXP_GetStatusFlags(base)))
0712     {
0713     }
0714 }
0715 
0716 /*!
0717  * brief Set the next command.
0718  *
0719  * The PXP supports a primitive ability to queue up one operation while the current
0720  * operation is running. Workflow:
0721  *
0722  * 1. Prepare the PXP register values except STAT, CSCCOEFn, NEXT in the memory
0723  * in the order they appear in the register map.
0724  * 2. Call this function sets the new operation to PXP.
0725  * 3. There are two methods to check whether the PXP has loaded the new operation.
0726  * The first method is using ref PXP_IsNextCommandPending. If there is new operation
0727  * not loaded by the PXP, this function returns true. The second method is checking
0728  * the flag ref kPXP_CommandLoadFlag, if command loaded, this flag asserts. User
0729  * could enable interrupt ref kPXP_CommandLoadInterruptEnable to get the loaded
0730  * signal in interrupt way.
0731  * 4. When command loaded by PXP, a new command could be set using this function.
0732  *
0733  * param base PXP peripheral base address.
0734  * param commandAddr Address of the new command.
0735  */
0736 void PXP_SetNextCommand(PXP_Type *base, void *commandAddr)
0737 {
0738     pxp_pvoid_u32_t addr;
0739 
0740     /* Make sure commands have been saved to memory. */
0741     __DSB();
0742 
0743     addr.pvoid = commandAddr;
0744 
0745     base->NEXT = PXP_ADDR_CPU_2_IP(addr.u32) & PXP_NEXT_POINTER_MASK;
0746 }
0747 
0748 #if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
0749 /*!
0750  * brief Set the CSC2 configuration.
0751  *
0752  * The CSC2 module receives pixels in any color space and can convert the pixels
0753  * into any of RGB, YUV, or YCbCr color spaces. The output pixels are passed
0754  * onto the LUT and rotation engine for further processing
0755  *
0756  * param base PXP peripheral base address.
0757  * param config Pointer to the configuration.
0758  */
0759 void PXP_SetCsc2Config(PXP_Type *base, const pxp_csc2_config_t *config)
0760 {
0761     assert(NULL != config);
0762     uint32_t tempReg;
0763 
0764     base->CSC2_CTRL = (base->CSC2_CTRL & ~PXP_CSC2_CTRL_CSC_MODE_MASK) | PXP_CSC2_CTRL_CSC_MODE(config->mode);
0765 
0766     tempReg =
0767         (PXP_ConvertFloat(config->A1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF0_A1_SHIFT);
0768     base->CSC2_COEF0 = tempReg | (PXP_ConvertFloat(config->A2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH)
0769                                   << PXP_CSC2_COEF0_A2_SHIFT);
0770 
0771     tempReg =
0772         (PXP_ConvertFloat(config->A3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF1_A3_SHIFT);
0773     base->CSC2_COEF1 = tempReg | (PXP_ConvertFloat(config->B1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH)
0774                                   << PXP_CSC2_COEF1_B1_SHIFT);
0775 
0776     tempReg =
0777         (PXP_ConvertFloat(config->B2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF2_B2_SHIFT);
0778     base->CSC2_COEF2 = tempReg | (PXP_ConvertFloat(config->B3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH)
0779                                   << PXP_CSC2_COEF2_B3_SHIFT);
0780 
0781     tempReg =
0782         (PXP_ConvertFloat(config->C1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF3_C1_SHIFT);
0783     base->CSC2_COEF3 = tempReg | (PXP_ConvertFloat(config->C2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH)
0784                                   << PXP_CSC2_COEF3_C2_SHIFT);
0785 
0786     tempReg =
0787         (PXP_ConvertFloat(config->C3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF4_C3_SHIFT);
0788     base->CSC2_COEF4 = tempReg | PXP_CSC2_COEF4_D1(config->D1);
0789 
0790     base->CSC2_COEF5 = PXP_CSC2_COEF5_D2(config->D2) | PXP_CSC2_COEF5_D3(config->D3);
0791 }
0792 #endif
0793 
0794 /*!
0795  * brief Set the CSC1 mode.
0796  *
0797  * The CSC1 module receives scaled YUV/YCbCr444 pixels from the scale engine and
0798  * converts the pixels to the RGB888 color space. It could only be used by process
0799  * surface.
0800  *
0801  * param base PXP peripheral base address.
0802  * param mode The conversion mode.
0803  */
0804 void PXP_SetCsc1Mode(PXP_Type *base, pxp_csc1_mode_t mode)
0805 {
0806     /*
0807      * The equations used for Colorspace conversion are:
0808      *
0809      * R = C0*(Y+Y_OFFSET)                   + C1(V+UV_OFFSET)
0810      * G = C0*(Y+Y_OFFSET) + C3(U+UV_OFFSET) + C2(V+UV_OFFSET)
0811      * B = C0*(Y+Y_OFFSET) + C4(U+UV_OFFSET)
0812      */
0813 
0814     if (kPXP_Csc1YUV2RGB == mode)
0815     {
0816         base->CSC1_COEF0 = (base->CSC1_COEF0 & ~(PXP_CSC1_COEF0_C0_MASK | PXP_CSC1_COEF0_Y_OFFSET_MASK |
0817                                                  PXP_CSC1_COEF0_UV_OFFSET_MASK | PXP_CSC1_COEF0_YCBCR_MODE_MASK)) |
0818                            PXP_CSC1_COEF0_C0(0x100U)         /* 1.00. */
0819                            | PXP_CSC1_COEF0_Y_OFFSET(0x0U)   /* 0. */
0820                            | PXP_CSC1_COEF0_UV_OFFSET(0x0U); /* 0. */
0821         base->CSC1_COEF1 = PXP_CSC1_COEF1_C1(0x0123U)        /* 1.140. */
0822                            | PXP_CSC1_COEF1_C4(0x0208U);     /* 2.032. */
0823         base->CSC1_COEF2 = PXP_CSC1_COEF2_C2(0x076BU)        /* -0.851. */
0824                            | PXP_CSC1_COEF2_C3(0x079BU);     /* -0.394. */
0825     }
0826     else
0827     {
0828         base->CSC1_COEF0 = (base->CSC1_COEF0 &
0829                             ~(PXP_CSC1_COEF0_C0_MASK | PXP_CSC1_COEF0_Y_OFFSET_MASK | PXP_CSC1_COEF0_UV_OFFSET_MASK)) |
0830                            PXP_CSC1_COEF0_YCBCR_MODE_MASK | PXP_CSC1_COEF0_C0(0x12AU) /* 1.164. */
0831                            | PXP_CSC1_COEF0_Y_OFFSET(0x1F0U)                          /* -16. */
0832                            | PXP_CSC1_COEF0_UV_OFFSET(0x180U);                        /* -128. */
0833         base->CSC1_COEF1 = PXP_CSC1_COEF1_C1(0x0198U)                                 /* 1.596. */
0834                            | PXP_CSC1_COEF1_C4(0x0204U);                              /* 2.017. */
0835         base->CSC1_COEF2 = PXP_CSC1_COEF2_C2(0x0730U)                                 /* -0.813. */
0836                            | PXP_CSC1_COEF2_C3(0x079CU);                              /* -0.392. */
0837     }
0838 }
0839 
0840 #if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
0841 /*!
0842  * brief Set the LUT configuration.
0843  *
0844  * The lookup table (LUT) is used to modify pixels in a manner that is not linear
0845  * and that cannot be achieved by the color space conversion modules. To setup
0846  * the LUT, the complete workflow is:
0847  * 1. Use ref PXP_SetLutConfig to set the configuration, such as the lookup mode.
0848  * 2. Use ref PXP_LoadLutTable to load the lookup table to PXP.
0849  * 3. Use ref PXP_EnableLut to enable the function.
0850  *
0851  * param base PXP peripheral base address.
0852  * param config Pointer to the configuration.
0853  */
0854 void PXP_SetLutConfig(PXP_Type *base, const pxp_lut_config_t *config)
0855 {
0856     base->LUT_CTRL = (base->LUT_CTRL & ~(PXP_LUT_CTRL_OUT_MODE_MASK | PXP_LUT_CTRL_LOOKUP_MODE_MASK)) |
0857                      PXP_LUT_CTRL_LRU_UPD_MASK | /* Use Least Recently Used Policy Update Control. */
0858                      PXP_LUT_CTRL_OUT_MODE(config->outMode) | PXP_LUT_CTRL_LOOKUP_MODE(config->lookupMode);
0859 
0860     if (kPXP_LutOutRGBW4444CFA == config->outMode)
0861     {
0862         base->CFA = config->cfaValue;
0863     }
0864 }
0865 
0866 /*!
0867  * brief Set the look up table to PXP.
0868  *
0869  * If lookup mode is DIRECT mode, this function loads p bytesNum of values
0870  * from the address p memAddr into PXP LUT address p lutStartAddr. So this
0871  * function allows only update part of the PXP LUT.
0872  *
0873  * If lookup mode is CACHE mode, this function sets the new address to p memAddr
0874  * and invalid the PXP LUT cache.
0875  *
0876  * param base PXP peripheral base address.
0877  * param lookupMode Which lookup mode is used. Note that this parameter is only
0878  * used to distinguish DIRECT mode and CACHE mode, it does not change the register
0879  * value PXP_LUT_CTRL[LOOKUP_MODE]. To change that value, use function ref PXP_SetLutConfig.
0880  * param bytesNum How many bytes to set. This value must be divisable by 8.
0881  * param memAddr Address of look up table to set.
0882  * param lutStartAddr The LUT value will be loaded to LUT from index lutAddr. It should
0883  * be 8 bytes aligned.
0884  *
0885  * retval kStatus_Success Load successfully.
0886  * retval kStatus_InvalidArgument Failed because of invalid argument.
0887  */
0888 status_t PXP_LoadLutTable(
0889     PXP_Type *base, pxp_lut_lookup_mode_t lookupMode, uint32_t bytesNum, uint32_t memAddr, uint16_t lutStartAddr)
0890 {
0891     memAddr = PXP_ADDR_CPU_2_IP(memAddr);
0892 
0893     if (kPXP_LutCacheRGB565 == lookupMode)
0894     {
0895         /* Make sure the previous memory write is finished, especially the LUT data memory. */
0896         __DSB();
0897 
0898         base->LUT_EXTMEM = memAddr;
0899         /* Invalid cache. */
0900         base->LUT_CTRL |= PXP_LUT_CTRL_INVALID_MASK;
0901     }
0902     else
0903     {
0904         /* Number of bytes must be divisable by 8. */
0905         if (((bytesNum & 0x07U) != 0U) || (bytesNum < 8U) || ((lutStartAddr & 0x07U) != 0U) ||
0906             (bytesNum + (uint32_t)lutStartAddr > PXP_LUT_TABLE_BYTE))
0907         {
0908             return kStatus_InvalidArgument;
0909         }
0910 
0911         base->LUT_EXTMEM = memAddr;
0912         base->LUT_ADDR   = PXP_LUT_ADDR_ADDR(lutStartAddr) | PXP_LUT_ADDR_NUM_BYTES(bytesNum);
0913 
0914         base->STAT_CLR = PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK;
0915 
0916         /* Start DMA transfer. */
0917         base->LUT_CTRL |= PXP_LUT_CTRL_DMA_START_MASK;
0918 
0919         __DSB();
0920 
0921         /* Wait for transfer completed. */
0922         while (0U == (base->STAT & PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK))
0923         {
0924         }
0925     }
0926 
0927     return kStatus_Success;
0928 }
0929 #endif /* FSL_FEATURE_PXP_HAS_NO_LUT */
0930 
0931 #if (defined(FSL_FEATURE_PXP_HAS_DITHER) && FSL_FEATURE_PXP_HAS_DITHER)
0932 /*!
0933  * brief Write data to the PXP internal memory.
0934  *
0935  * param base PXP peripheral base address.
0936  * param ram Which internal memory to write.
0937  * param bytesNum How many bytes to write.
0938  * param data Pointer to the data to write.
0939  * param memStartAddr The start address in the internal memory to write the data.
0940  */
0941 void PXP_SetInternalRamData(PXP_Type *base, pxp_ram_t ram, uint32_t bytesNum, uint8_t *data, uint16_t memStartAddr)
0942 {
0943     assert(((uint32_t)memStartAddr + bytesNum) <= (uint32_t)PXP_INTERNAL_RAM_LUT_BYTE);
0944 
0945     base->INIT_MEM_CTRL =
0946         PXP_INIT_MEM_CTRL_ADDR(memStartAddr) | PXP_INIT_MEM_CTRL_SELECT(ram) | PXP_INIT_MEM_CTRL_START_MASK;
0947 
0948     while (0U != bytesNum--)
0949     {
0950         base->INIT_MEM_DATA = (uint32_t)(*data);
0951         data++;
0952     }
0953 
0954     base->INIT_MEM_CTRL = 0U;
0955 }
0956 
0957 /*!
0958  * brief Set the dither final LUT data.
0959  *
0960  * The dither final LUT is only applicble to dither engine 0. It takes the bits[7:4]
0961  * of the output pixel and looks up and 8 bit value from the 16 value LUT to generate
0962  * the final output pixel to the next process module.
0963  *
0964  * param base PXP peripheral base address.
0965  * param data Pointer to the LUT data to set.
0966  */
0967 void PXP_SetDitherFinalLutData(PXP_Type *base, const pxp_dither_final_lut_data_t *data)
0968 {
0969     base->DITHER_FINAL_LUT_DATA0 = data->data_3_0;
0970     base->DITHER_FINAL_LUT_DATA1 = data->data_7_4;
0971     base->DITHER_FINAL_LUT_DATA2 = data->data_11_8;
0972     base->DITHER_FINAL_LUT_DATA3 = data->data_15_12;
0973 }
0974 
0975 /*!
0976  * brief Enable or disable dither engine in the PXP process path.
0977  *
0978  * After the initialize function ref PXP_Init, the dither engine is disabled and not
0979  * use in the PXP processing path. This function enables the dither engine and
0980  * routes the dither engine output to the output buffer. When the dither engine
0981  * is enabled using this function, ref PXP_SetDitherConfig must be called to
0982  * configure dither engine correctly, otherwise there is not output to the output
0983  * buffer.
0984  *
0985  * param base PXP peripheral base address.
0986  * param enable Pass in true to enable, false to disable.
0987  */
0988 void PXP_EnableDither(PXP_Type *base, bool enable)
0989 {
0990     if (enable)
0991     {
0992         base->CTRL_SET = PXP_CTRL_ENABLE_DITHER_MASK;
0993     }
0994     else
0995     {
0996         base->CTRL_CLR = PXP_CTRL_ENABLE_DITHER_MASK;
0997     }
0998 }
0999 #endif /* FSL_FEATURE_PXP_HAS_DITHER */
1000 
1001 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
1002 /*!
1003  * brief Set the Porter Duff configuration for one of the alpha process engine.
1004  *
1005  * param base PXP peripheral base address.
1006  * param num instance number.
1007  * param config Pointer to the configuration.
1008  */
1009 void PXP_SetPorterDuffConfig(PXP_Type *base, uint8_t num, const pxp_porter_duff_config_t *config)
1010 {
1011     assert(NULL != config);
1012 
1013     union
1014     {
1015         pxp_porter_duff_config_t pdConfigStruct;
1016         uint32_t u32;
1017     } pdConfig;
1018 
1019     pdConfig.pdConfigStruct = *config;
1020 
1021     switch (num)
1022     {
1023         case 0:
1024             base->ALPHA_A_CTRL = pdConfig.u32;
1025             break;
1026 
1027         case 1:
1028             base->ALPHA_B_CTRL = pdConfig.u32;
1029             break;
1030 
1031         default:
1032             /* Only 2 alpha process engine instances are supported. */
1033             assert(false);
1034             break;
1035     }
1036 }
1037 #endif /* FSL_FEATURE_PXP_V3 */
1038 
1039 #if !(defined(FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL) && FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL)
1040 /*!
1041  * brief Set the Porter Duff configuration.
1042  *
1043  * param base PXP peripheral base address.
1044  * param config Pointer to the configuration.
1045  */
1046 void PXP_SetPorterDuffConfig(PXP_Type *base, const pxp_porter_duff_config_t *config)
1047 {
1048     assert(NULL != config);
1049 
1050     union
1051     {
1052         pxp_porter_duff_config_t pdConfigStruct;
1053         uint32_t u32;
1054     } pdConfig;
1055 
1056     pdConfig.pdConfigStruct = *config;
1057 
1058     base->PORTER_DUFF_CTRL = pdConfig.u32;
1059 }
1060 #endif /* FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL */
1061 
1062 #if (!(defined(FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL) && FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL)) || \
1063     (defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3)
1064 /*!
1065  * brief Get the Porter Duff configuration by blend mode.
1066  *
1067  * param mode The blend mode.
1068  * param config Pointer to the configuration.
1069  * retval kStatus_Success Successfully get the configuratoin.
1070  * retval kStatus_InvalidArgument The blend mode not supported.
1071  */
1072 status_t PXP_GetPorterDuffConfig(pxp_porter_duff_blend_mode_t mode, pxp_porter_duff_config_t *config)
1073 {
1074     status_t status;
1075 
1076     union
1077     {
1078         pxp_porter_duff_config_t pdConfigStruct;
1079         uint32_t u32;
1080     } pdConfig;
1081 
1082     static const uint32_t pdCtrl[] = {
1083         /* kPXP_PorterDuffSrc */
1084         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorOne) |
1085             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
1086 
1087         /* kPXP_PorterDuffAtop */
1088         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorStraight) |
1089             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
1090 
1091         /* kPXP_PorterDuffOver */
1092         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorOne) |
1093             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
1094 
1095         /* kPXP_PorterDuffIn */
1096         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorStraight) |
1097             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
1098 
1099         /* kPXP_PorterDuffOut */
1100         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
1101             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
1102 
1103         /* kPXP_PorterDuffDst */
1104         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
1105             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorOne),
1106 
1107         /* kPXP_PorterDuffDstAtop */
1108         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
1109             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorStraight),
1110 
1111         /* kPXP_PorterDuffDstOver */
1112         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
1113             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorOne),
1114 
1115         /* kPXP_PorterDuffDstIn */
1116         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
1117             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorStraight),
1118 
1119         /* kPXP_PorterDuffDstOut */
1120         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
1121             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
1122 
1123         /* kPXP_PorterDuffXor */
1124         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
1125             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
1126 
1127         /* kPXP_PorterDuffClear */
1128         PORTER_DUFF_ENABLE_MASK | S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
1129             S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
1130     };
1131 
1132     if (mode >= kPXP_PorterDuffMax)
1133     {
1134         status = kStatus_InvalidArgument;
1135     }
1136     else
1137     {
1138         pdConfig.u32 = pdCtrl[(uint32_t)mode] | S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
1139                        S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) | S0_COLOR_MODE(kPXP_PorterDuffColorWithAlpha) |
1140                        S1_COLOR_MODE(kPXP_PorterDuffColorWithAlpha) | S0_ALPHA_MODE(kPXP_PorterDuffAlphaStraight) |
1141                        S1_ALPHA_MODE(kPXP_PorterDuffAlphaStraight);
1142 
1143         *config = pdConfig.pdConfigStruct;
1144 
1145         status = kStatus_Success;
1146     }
1147 
1148     return status;
1149 }
1150 #endif /* FSL_FEATURE_PXP_V3 || FSL_FEATURE_PXP_HAS_NO_PORTER_DUFF_CTRL  */
1151 
1152 static void PXP_StartRectCopy(PXP_Type *base,
1153                               uint32_t srcAddr,
1154                               uint16_t srcPitchBytes,
1155                               uint32_t destAddr,
1156                               uint16_t destPitchBytes,
1157                               uint16_t width,
1158                               uint16_t height,
1159                               pxp_as_pixel_format_t pixelFormat)
1160 {
1161     pxp_output_buffer_config_t outputBufferConfig;
1162     pxp_as_buffer_config_t asBufferConfig;
1163     uint32_t intMask;
1164 
1165 #if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
1166     intMask =
1167         base->CTRL & (PXP_CTRL_NEXT_IRQ_ENABLE_MASK | PXP_CTRL_IRQ_ENABLE_MASK | PXP_CTRL_LUT_DMA_IRQ_ENABLE_MASK);
1168 #else
1169     intMask = base->CTRL & (PXP_CTRL_NEXT_IRQ_ENABLE_MASK | PXP_CTRL_IRQ_ENABLE_MASK);
1170 #endif
1171 
1172     PXP_ResetControl(base);
1173 
1174     /* Restore previous interrupt configuration. */
1175     PXP_EnableInterrupts(base, intMask);
1176 
1177     /* Disable PS */
1178     PXP_SetProcessSurfacePosition(base, 0xFFFFU, 0xFFFFU, 0U, 0U);
1179 
1180     /* Input buffer. */
1181     asBufferConfig.pixelFormat = pixelFormat;
1182     asBufferConfig.bufferAddr  = srcAddr;
1183     asBufferConfig.pitchBytes  = srcPitchBytes;
1184 
1185     PXP_SetAlphaSurfaceBufferConfig(base, &asBufferConfig);
1186     PXP_SetAlphaSurfacePosition(base, 0U, 0U, width - 1U, height - 1U);
1187 
1188     /* Alpha mode set to ROP, AS OR PS */
1189     const pxp_as_blend_config_t asBlendConfig = {
1190         .alpha = 0U, .invertAlpha = false, .alphaMode = kPXP_AlphaRop, .ropMode = kPXP_RopMergeAs};
1191 
1192     PXP_SetAlphaSurfaceBlendConfig(base, &asBlendConfig);
1193 
1194     /* Output buffer. */
1195     outputBufferConfig.pixelFormat    = (pxp_output_pixel_format_t)pixelFormat;
1196     outputBufferConfig.interlacedMode = kPXP_OutputProgressive;
1197     outputBufferConfig.buffer0Addr    = destAddr;
1198     outputBufferConfig.buffer1Addr    = 0U;
1199     outputBufferConfig.pitchBytes     = destPitchBytes;
1200     outputBufferConfig.width          = width;
1201     outputBufferConfig.height         = height;
1202 
1203     PXP_SetOutputBufferConfig(base, &outputBufferConfig);
1204 
1205     PXP_ClearStatusFlags(base, (uint32_t)kPXP_CompleteFlag);
1206 
1207     PXP_Start(base);
1208 }
1209 
1210 /*!
1211  * brief Copy picture from one buffer to another buffer.
1212  *
1213  * This function copies a rectangle from one buffer to another buffer.
1214  *
1215  * param base PXP peripheral base address.
1216  * retval kStatus_Success Successfully started the copy process.
1217  * retval kStatus_InvalidArgument Invalid argument.
1218  */
1219 status_t PXP_StartPictureCopy(PXP_Type *base, const pxp_pic_copy_config_t *config)
1220 {
1221     uint8_t bytePerPixel;
1222     uint32_t copyFromAddr;
1223     uint32_t copyToAddr;
1224 
1225     if ((0U == config->height) || (0U == config->width))
1226     {
1227         return kStatus_InvalidArgument;
1228     }
1229 
1230     if ((config->pixelFormat == kPXP_AsPixelFormatARGB8888) || (config->pixelFormat == kPXP_AsPixelFormatRGB888))
1231     {
1232         bytePerPixel = 4U;
1233     }
1234     else
1235     {
1236         bytePerPixel = 2U;
1237     }
1238 
1239     copyFromAddr = config->srcPicBaseAddr + ((uint32_t)config->srcOffsetY * (uint32_t)config->srcPitchBytes) +
1240                    bytePerPixel * config->srcOffsetX;
1241     copyToAddr = config->destPicBaseAddr + ((uint32_t)config->destOffsetY * (uint32_t)config->destPitchBytes) +
1242                  bytePerPixel * config->destOffsetX;
1243 
1244     PXP_StartRectCopy(base, copyFromAddr, config->srcPitchBytes, copyToAddr, config->destPitchBytes, config->width,
1245                       config->height, config->pixelFormat);
1246 
1247     return kStatus_Success;
1248 }
1249 
1250 /*!
1251  * brief Copy continous memory.
1252  *
1253  * The copy size should be 512 byte aligned.
1254  *
1255  * param base PXP peripheral base address.
1256  * retval kStatus_Success Successfully started the copy process.
1257  * retval kStatus_InvalidArgument Invalid argument.
1258  */
1259 status_t PXP_StartMemCopy(PXP_Type *base, uint32_t srcAddr, uint32_t destAddr, uint32_t size)
1260 {
1261     uint16_t pitchBytes;
1262     uint32_t height;
1263 
1264     if ((0U == size) || ((size % 512U) != 0U))
1265     {
1266         return kStatus_InvalidArgument;
1267     }
1268 
1269     /*
1270      * By default, PXP process block is 8x8. For better performance, choose
1271      * width and height dividable by block size.
1272      */
1273     if (size < 8U * 512U)
1274     {
1275         height     = 8U;
1276         pitchBytes = (uint16_t)(size / height);
1277     }
1278     else
1279     {
1280         pitchBytes = 512U;
1281         height     = size / pitchBytes;
1282     }
1283 
1284     if (height > PXP_MAX_HEIGHT)
1285     {
1286         return kStatus_InvalidArgument;
1287     }
1288 
1289     PXP_StartRectCopy(base, srcAddr, pitchBytes, destAddr, pitchBytes, pitchBytes / 4U, (uint16_t)height,
1290                       kPXP_AsPixelFormatARGB8888);
1291 
1292     return kStatus_Success;
1293 }
1294 
1295 /*!
1296  * brief Copy continous memory.
1297  *
1298  * param base PXP peripheral base address.
1299  * retval kStatus_Success Successfully started the copy process.
1300  * retval kStatus_InvalidArgument Invalid argument.
1301  */
1302 status_t PXP_MemCopy(PXP_Type *base, uint32_t srcAddr, uint32_t destAddr, uint32_t size)
1303 {
1304     uint16_t pitchBytes;
1305     uint32_t height;
1306     uint32_t unalignedSize;
1307 
1308     if (0U == size)
1309     {
1310         return kStatus_InvalidArgument;
1311     }
1312 
1313     /* For 512 not aligned part, copy by CPU. */
1314     unalignedSize = size % 512U;
1315 
1316     if (0UL != unalignedSize)
1317     {
1318         (void)memcpy((uint8_t *)destAddr, (uint8_t *)srcAddr, unalignedSize);
1319 
1320         destAddr += unalignedSize;
1321         srcAddr += unalignedSize;
1322         size -= unalignedSize;
1323     }
1324 
1325     if (0UL != size)
1326     {
1327         /*
1328          * By default, PXP process block is 8x8. For better performance, choose
1329          * width and height dividable by block size.
1330          */
1331         if (size < 8U * 512U)
1332         {
1333             height     = 8U;
1334             pitchBytes = (uint16_t)(size / height);
1335         }
1336         else
1337         {
1338             pitchBytes = 512U;
1339             height     = size / pitchBytes;
1340         }
1341 
1342         if (height > PXP_MAX_HEIGHT)
1343         {
1344             return kStatus_InvalidArgument;
1345         }
1346 
1347         PXP_StartRectCopy(base, srcAddr, pitchBytes, destAddr, pitchBytes, pitchBytes / 4U, (uint16_t)height,
1348                           kPXP_AsPixelFormatARGB8888);
1349 
1350         while (0UL == ((uint32_t)kPXP_CompleteFlag & PXP_GetStatusFlags(base)))
1351         {
1352         }
1353 
1354         PXP_ClearStatusFlags(base, (uint32_t)kPXP_CompleteFlag);
1355     }
1356 
1357     return kStatus_Success;
1358 }
1359 
1360 #if defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3
1361 
1362 /*!
1363  * brief Configures one channle of some block's fetch engine.
1364  *
1365  * Fetch engine is 64-bit input and 32-bit output per channel
1366  *
1367  * param base PXP peripheral base address.
1368  * param name which block the fetch engine belongs to.
1369  * param channel channel number.
1370  * param config pointer to the configuration structure.
1371  * retval kStatus_Success Successfully configured the engine.
1372  * retval kStatus_InvalidArgument Invalid argument.
1373  */
1374 status_t PXP_SetFetchEngineConfig(PXP_Type *base,
1375                                   pxp_fetch_engine_name_t name,
1376                                   uint8_t channel,
1377                                   const pxp_fetch_engine_config_t *config)
1378 {
1379     assert(NULL != config);
1380 
1381     /* Check fetch address */
1382     if ((config->inputBaseAddr0 == 0U) ||
1383         ((config->inputBaseAddr1 == 0U) && (config->pixelFormat == kPXP_FetchFormatYUV422_2P)))
1384     {
1385         return kStatus_InvalidArgument;
1386     }
1387     /* Must enable expand when input pixel format is YUV422_2P, to combine Y and UV buffer to one output. */
1388     if ((config->expandEnable == false) && (config->pixelFormat == kPXP_FetchFormatYUV422_2P))
1389     {
1390         return kStatus_InvalidArgument;
1391     }
1392     /* Must enable block if flip or rotation is enabled. */
1393     if ((config->fetchFormat.enableblock == false) &&
1394         ((config->flipMode != kPXP_FlipDisable) || (config->rotateDegree != kPXP_Rotate0)))
1395     {
1396         return kStatus_InvalidArgument;
1397     }
1398     /* Block mode cannot work in 64-bit mode */
1399     if ((config->fetchFormat.enableblock == true) && (config->activeBits == kPXP_Active64Bits))
1400     {
1401         return kStatus_InvalidArgument;
1402     }
1403 
1404     uint32_t ctrlReg        = 0U;
1405     uint32_t ulcReg         = 0U;
1406     uint32_t lrcReg         = 0U;
1407     uint32_t fetchSizeReg   = 0U;
1408     uint32_t shiftCtrlReg   = 0U;
1409     uint32_t shiftOffsetReg = 0U;
1410     uint32_t shiftWidthReg  = 0U;
1411     uint8_t scanlineNum     = 0U;
1412 
1413     /* When block disabled, handshake scanline mode can only use 1 line mode where scanlineNum = 0. */
1414     if (config->fetchFormat.enableblock)
1415     {
1416         /*  */
1417         if (config->fetchFormat.blockSize16)
1418         {
1419             scanlineNum = 2;
1420         }
1421         else
1422         {
1423             scanlineNum = 1;
1424         }
1425     }
1426 
1427     ctrlReg = PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM((uint32_t)scanlineNum) |
1428               PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES(config->fetchFormat.burstLength) |
1429               PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE((uint32_t)config->rotateDegree) |
1430               ((uint32_t)config->flipMode << PXP_INPUT_FETCH_CTRL_CH0_HFLIP_SHIFT) |
1431               PXP_INPUT_FETCH_CTRL_CH0_HIGH_BYTE((uint32_t)config->wordOrder) |
1432               ((uint32_t)config->interface << PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_EN_SHIFT) |
1433               PXP_INPUT_FETCH_CTRL_CH0_BLOCK_EN((uint32_t)config->fetchFormat.enableblock) |
1434               PXP_INPUT_FETCH_CTRL_CH0_BLOCK_16((uint32_t)config->fetchFormat.blockSize16) |
1435               PXP_INPUT_FETCH_CTRL_CH0_CH_EN((uint32_t)config->channelEnable);
1436     ulcReg       = (((uint32_t)config->ulcY) << 16U) | (uint32_t)config->ulcX;
1437     lrcReg       = (((uint32_t)config->lrcY) << 16U) | (uint32_t)config->lrcX;
1438     fetchSizeReg = (((uint32_t)config->totalHeight) << 16U) | ((uint32_t)config->totalWidth);
1439     shiftCtrlReg = PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP((uint32_t)config->activeBits) |
1440                    PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT((uint32_t)config->pixelFormat) |
1441                    PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_EN((uint32_t)config->expandEnable) |
1442                    PXP_INPUT_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS((uint32_t)config->shiftConfig.shiftBypass);
1443     if (!config->shiftConfig.shiftBypass)
1444     {
1445         shiftOffsetReg = (uint32_t)config->shiftConfig.component0.offset |
1446                          ((uint32_t)(config->shiftConfig.component1.offset) << 8U) |
1447                          ((uint32_t)(config->shiftConfig.component2.offset) << 16U) |
1448                          ((uint32_t)(config->shiftConfig.component3.offset) << 24U);
1449         shiftWidthReg = (uint32_t)config->shiftConfig.component0.width |
1450                         ((uint32_t)(config->shiftConfig.component1.width) << 4U) |
1451                         ((uint32_t)(config->shiftConfig.component2.width) << 8U) |
1452                         ((uint32_t)(config->shiftConfig.component3.width) << 12U);
1453     }
1454 
1455     if (name == kPXP_FetchInput)
1456     {
1457         switch (channel)
1458         {
1459             case 0:
1460                 base->INPUT_FETCH_CTRL_CH0            = ctrlReg;
1461                 base->INPUT_FETCH_ACTIVE_SIZE_ULC_CH0 = ulcReg;
1462                 base->INPUT_FETCH_ACTIVE_SIZE_LRC_CH0 = lrcReg;
1463                 base->INPUT_FETCH_SIZE_CH0            = fetchSizeReg;
1464                 base->INPUT_FETCH_PITCH = (base->INPUT_FETCH_PITCH & PXP_INPUT_FETCH_PITCH_CH1_INPUT_PITCH_MASK) |
1465                                           (uint32_t)config->pitchBytes;
1466                 base->INPUT_FETCH_SHIFT_CTRL_CH0 = shiftCtrlReg;
1467                 base->INPUT_FETCH_ADDR_0_CH0     = config->inputBaseAddr0;
1468                 base->INPUT_FETCH_ADDR_1_CH0     = config->inputBaseAddr1;
1469                 if (!config->shiftConfig.shiftBypass)
1470                 {
1471                     base->INPUT_FETCH_SHIFT_OFFSET_CH0 = shiftOffsetReg;
1472                     base->INPUT_FETCH_SHIFT_WIDTH_CH0  = shiftWidthReg;
1473                 }
1474                 break;
1475 
1476             case 1:
1477                 base->INPUT_FETCH_CTRL_CH1            = ctrlReg;
1478                 base->INPUT_FETCH_ACTIVE_SIZE_ULC_CH1 = ulcReg;
1479                 base->INPUT_FETCH_ACTIVE_SIZE_LRC_CH1 = lrcReg;
1480                 base->INPUT_FETCH_SIZE_CH1            = fetchSizeReg;
1481                 base->INPUT_FETCH_PITCH = (base->INPUT_FETCH_PITCH & PXP_INPUT_FETCH_PITCH_CH0_INPUT_PITCH_MASK) |
1482                                           ((uint32_t)config->pitchBytes << 16U);
1483                 base->INPUT_FETCH_SHIFT_CTRL_CH1 = shiftCtrlReg;
1484                 base->INPUT_FETCH_ADDR_0_CH1     = config->inputBaseAddr0;
1485                 base->INPUT_FETCH_ADDR_1_CH1     = config->inputBaseAddr1;
1486                 if (!config->shiftConfig.shiftBypass)
1487                 {
1488                     base->INPUT_FETCH_SHIFT_OFFSET_CH1 = shiftOffsetReg;
1489                     base->INPUT_FETCH_SHIFT_WIDTH_CH1  = shiftWidthReg;
1490                 }
1491                 break;
1492 
1493             default:
1494                 /* Only 2 channels are supported per fetch engine. */
1495                 assert(false);
1496                 break;
1497         }
1498     }
1499     else
1500     {
1501         switch (channel)
1502         {
1503             case 0:
1504                 base->DITHER_FETCH_CTRL_CH0            = ctrlReg;
1505                 base->DITHER_FETCH_ACTIVE_SIZE_ULC_CH0 = ulcReg;
1506                 base->DITHER_FETCH_ACTIVE_SIZE_LRC_CH0 = lrcReg;
1507                 base->DITHER_FETCH_SIZE_CH0            = fetchSizeReg;
1508                 base->DITHER_FETCH_PITCH = (base->INPUT_FETCH_PITCH & PXP_INPUT_FETCH_PITCH_CH1_INPUT_PITCH_MASK) |
1509                                            (uint32_t)config->pitchBytes;
1510                 base->DITHER_FETCH_SHIFT_CTRL_CH0 = shiftCtrlReg;
1511                 base->DITHER_FETCH_ADDR_0_CH0     = config->inputBaseAddr0;
1512                 base->DITHER_FETCH_ADDR_1_CH0     = config->inputBaseAddr1;
1513                 if (!config->shiftConfig.shiftBypass)
1514                 {
1515                     base->DITHER_FETCH_SHIFT_OFFSET_CH0 = shiftOffsetReg;
1516                     base->DITHER_FETCH_SHIFT_WIDTH_CH0  = shiftWidthReg;
1517                 }
1518                 break;
1519 
1520             case 1:
1521                 base->DITHER_FETCH_CTRL_CH1            = ctrlReg;
1522                 base->DITHER_FETCH_ACTIVE_SIZE_ULC_CH1 = ulcReg;
1523                 base->DITHER_FETCH_ACTIVE_SIZE_LRC_CH1 = lrcReg;
1524                 base->DITHER_FETCH_SIZE_CH1            = fetchSizeReg;
1525                 base->DITHER_FETCH_PITCH = (base->INPUT_FETCH_PITCH & PXP_INPUT_FETCH_PITCH_CH0_INPUT_PITCH_MASK) |
1526                                            ((uint32_t)config->pitchBytes << 16U);
1527                 base->DITHER_FETCH_SHIFT_CTRL_CH1 = shiftCtrlReg;
1528                 base->DITHER_FETCH_ADDR_0_CH1     = config->inputBaseAddr0;
1529                 base->DITHER_FETCH_ADDR_1_CH1     = config->inputBaseAddr1;
1530                 if (!config->shiftConfig.shiftBypass)
1531                 {
1532                     base->DITHER_FETCH_SHIFT_OFFSET_CH1 = shiftOffsetReg;
1533                     base->DITHER_FETCH_SHIFT_WIDTH_CH1  = shiftWidthReg;
1534                 }
1535                 break;
1536 
1537             default:
1538                 /* Only 2 channels are supported per fetch engine. */
1539                 assert(false);
1540                 break;
1541         }
1542     }
1543     return kStatus_Success;
1544 }
1545 
1546 /*!
1547  * brief Configures one channel of some block's store engine.
1548  *
1549  * Store engine is 32-bit input and 64-bit output per channel.
1550  * note: If there is only one channel used for data input, channel 0 must be used rather than channel 1.
1551  *
1552  * param base PXP peripheral base address.
1553  * param name the store engine belongs to which block.
1554  * param channel channel number.
1555  * param config pointer to the configuration structure.
1556  * retval kStatus_Success Successfully configured the engine.
1557  * retval kStatus_InvalidArgument Invalid argument.
1558  */
1559 status_t PXP_SetStoreEngineConfig(PXP_Type *base,
1560                                   pxp_store_engine_name_t name,
1561                                   uint8_t channel,
1562                                   const pxp_store_engine_config_t *config)
1563 {
1564     assert(NULL != config);
1565     /* Can only choose one plane for YUV422_2p for one channel output */
1566     if ((uint32_t)config->yuvMode == 0x3U)
1567     {
1568         return kStatus_InvalidArgument;
1569     }
1570 
1571     /* Block mode cannot work in 64-bit mode or YUV422_2p mode */
1572     if ((config->storeFormat.enableblock == true) &&
1573         ((config->activeBits == kPXP_Active64Bits) || (config->yuvMode != kPXP_StoreYUVDisable)))
1574     {
1575         return kStatus_InvalidArgument;
1576     }
1577 
1578     /* When block mode is disabled the interface array size can only be 1. TODO. The availiable fetch engine now are
1579        only input&fetch that can only use handshake 1x1, no need to check */
1580     // if ((config->storeFormat.enableblock == false) && (config->arraySize != kPXP_StoreHandshake1x1))
1581     // {
1582     //     return kStatus_InvalidArgument;
1583     // }
1584 
1585     uint32_t ctrlReg               = 0U;
1586     uint32_t shiftCtrlReg          = 0U;
1587     uint32_t sizeReg               = 0U;
1588     uint32_t dataShiftMaskRegAddr  = 0U;
1589     uint32_t dataShiftWidthRegAddr = 0U;
1590     uint32_t flagShiftMaskRegAddr  = 0U;
1591     uint32_t flagShiftWidthRegAddr = 0U;
1592 
1593     ctrlReg = PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES((uint32_t)config->storeFormat.burstLength) |
1594               PXP_INPUT_STORE_CTRL_CH0_FILL_DATA_EN((uint32_t)config->useFixedData) |
1595               PXP_INPUT_STORE_CTRL_CH0_PACK_IN_SEL((uint32_t)config->packInSelect) |
1596               ((uint32_t)config->interface << PXP_INPUT_STORE_CTRL_CH0_HANDSHAKE_EN_SHIFT) |
1597               // PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM((uint32_t)config->arraySize) |
1598               PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM(0U) |
1599               PXP_INPUT_STORE_CTRL_CH0_BLOCK_16((uint32_t)config->storeFormat.enableblock) |
1600               PXP_INPUT_STORE_CTRL_CH0_BLOCK_EN((uint32_t)config->storeFormat.blockSize16) |
1601               PXP_INPUT_STORE_CTRL_CH0_CH_EN((uint32_t)config->channelEnable);
1602     shiftCtrlReg = PXP_INPUT_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS((uint32_t)config->shiftConfig.shiftBypass) |
1603                    ((uint32_t)config->yuvMode << PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN_SHIFT) |
1604                    PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP((uint32_t)config->activeBits);
1605     sizeReg = (((uint32_t)config->totalHeight) << 16U) | ((uint32_t)config->totalWidth);
1606 
1607     if (name == kPXP_StoreInput)
1608     {
1609         switch (channel)
1610         {
1611             case 0:
1612                 base->INPUT_STORE_CTRL_CH0 = ctrlReg;
1613                 base->INPUT_STORE_SIZE_CH0 = sizeReg;
1614                 base->INPUT_STORE_PITCH    = (base->INPUT_STORE_PITCH & PXP_INPUT_STORE_PITCH_CH0_OUT_PITCH_MASK) |
1615                                           (uint32_t)(config->pitchBytes);
1616                 base->INPUT_STORE_SHIFT_CTRL_CH0 = shiftCtrlReg;
1617                 base->INPUT_STORE_ADDR_0_CH0     = config->outputBaseAddr0;
1618                 base->INPUT_STORE_ADDR_1_CH0     = config->outputBaseAddr1;
1619                 base->INPUT_STORE_FILL_DATA_CH0  = config->fixedData;
1620                 dataShiftMaskRegAddr             = (uint32_t) & (base->INPUT_STORE_D_MASK0_H_CH0);
1621                 dataShiftWidthRegAddr            = (uint32_t) & (base->INPUT_STORE_D_SHIFT_L_CH0);
1622                 flagShiftMaskRegAddr             = (uint32_t) & (base->INPUT_STORE_F_MASK_L_CH0);
1623                 flagShiftWidthRegAddr            = (uint32_t) & (base->INPUT_STORE_F_SHIFT_L_CH0);
1624                 break;
1625 
1626             case 1:
1627                 base->INPUT_STORE_CTRL_CH1 = ctrlReg;
1628                 base->INPUT_STORE_SIZE_CH1 = sizeReg;
1629                 base->INPUT_STORE_PITCH    = (base->INPUT_STORE_PITCH & PXP_INPUT_STORE_PITCH_CH0_OUT_PITCH_MASK) |
1630                                           ((uint32_t)(config->pitchBytes) << 16U);
1631                 base->INPUT_STORE_SHIFT_CTRL_CH1 = shiftCtrlReg;
1632                 base->INPUT_STORE_ADDR_0_CH1     = config->outputBaseAddr0;
1633                 base->INPUT_STORE_ADDR_1_CH1     = config->outputBaseAddr1;
1634                 dataShiftMaskRegAddr             = (uint32_t) & (base->INPUT_STORE_D_MASK0_H_CH0);
1635                 dataShiftWidthRegAddr            = (uint32_t) & (base->INPUT_STORE_D_SHIFT_L_CH0);
1636                 flagShiftMaskRegAddr             = (uint32_t) & (base->INPUT_STORE_F_MASK_L_CH0);
1637                 flagShiftWidthRegAddr            = (uint32_t) & (base->INPUT_STORE_F_SHIFT_L_CH0);
1638                 break;
1639 
1640             default:
1641                 /* Only 2 channels are supported per fetch engine. */
1642                 assert(false);
1643                 break;
1644         }
1645     }
1646     else
1647     {
1648         switch (channel)
1649         {
1650             case 0:
1651                 base->DITHER_STORE_CTRL_CH0 = ctrlReg;
1652                 base->DITHER_STORE_SIZE_CH0 = sizeReg;
1653                 base->DITHER_STORE_PITCH    = (base->DITHER_STORE_PITCH & PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH_MASK) |
1654                                            (uint32_t)(config->pitchBytes);
1655                 base->DITHER_STORE_SHIFT_CTRL_CH0 = shiftCtrlReg;
1656                 base->DITHER_STORE_ADDR_0_CH0     = config->outputBaseAddr0;
1657                 base->DITHER_STORE_ADDR_1_CH0     = config->outputBaseAddr1;
1658                 base->DITHER_STORE_FILL_DATA_CH0  = config->fixedData;
1659                 dataShiftMaskRegAddr              = (uint32_t) & (base->DITHER_STORE_D_MASK0_H_CH0);
1660                 dataShiftWidthRegAddr             = (uint32_t) & (base->DITHER_STORE_D_SHIFT_L_CH0);
1661                 flagShiftMaskRegAddr              = (uint32_t) & (base->DITHER_STORE_F_MASK_L_CH0);
1662                 flagShiftWidthRegAddr             = (uint32_t) & (base->DITHER_STORE_F_SHIFT_L_CH0);
1663                 break;
1664 
1665             case 1:
1666                 base->DITHER_STORE_CTRL_CH1 = ctrlReg;
1667                 base->DITHER_STORE_SIZE_CH1 = sizeReg;
1668                 base->DITHER_STORE_PITCH    = (base->DITHER_STORE_PITCH & PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH_MASK) |
1669                                            ((uint32_t)(config->pitchBytes) << 16U);
1670                 base->DITHER_STORE_SHIFT_CTRL_CH1 = shiftCtrlReg;
1671                 base->DITHER_STORE_ADDR_0_CH1     = config->outputBaseAddr0;
1672                 base->DITHER_STORE_ADDR_1_CH1     = config->outputBaseAddr1;
1673                 dataShiftMaskRegAddr              = (uint32_t) & (base->DITHER_STORE_D_MASK0_H_CH0);
1674                 dataShiftWidthRegAddr             = (uint32_t) & (base->DITHER_STORE_D_SHIFT_L_CH0);
1675                 flagShiftMaskRegAddr              = (uint32_t) & (base->DITHER_STORE_F_MASK_L_CH0);
1676                 flagShiftWidthRegAddr             = (uint32_t) & (base->DITHER_STORE_F_SHIFT_L_CH0);
1677                 break;
1678 
1679             default:
1680                 /* Only 2 channels are supported per fetch engine. */
1681                 assert(false);
1682                 break;
1683         }
1684     }
1685 
1686     /* Shift configuration */
1687     if (!config->shiftConfig.shiftBypass)
1688     {
1689         uint8_t i;
1690         uint32_t dataShiftMaskAddr  = (uint32_t) & (config->shiftConfig.pDataShiftMask);
1691         uint32_t dataShiftWidthAddr = (uint32_t) & (config->shiftConfig.pDataShiftWidth);
1692         uint32_t flagShiftMaskAddr  = (uint32_t) & (config->shiftConfig.pFlagShiftMask);
1693         uint32_t flagShiftWidthAddr = (uint32_t) & (config->shiftConfig.pFlagShiftWidth);
1694 
1695         /* Configure data shift mask */
1696         for (i = 0U; i < 8U; i++)
1697         {
1698             *(uint32_t *)dataShiftMaskRegAddr = (uint32_t)(*(uint64_t *)dataShiftMaskAddr >> 32U);
1699             dataShiftMaskRegAddr += 0x10U;
1700             *(uint32_t *)dataShiftMaskRegAddr = (uint32_t)(*(uint64_t *)dataShiftMaskAddr);
1701             dataShiftMaskRegAddr += 0x10U;
1702             dataShiftMaskAddr += 8U;
1703         }
1704 
1705         /* Configure data shift width, flag shift mask/width */
1706         for (i = 0U; i < 8U; i++)
1707         {
1708             *(uint8_t *)dataShiftWidthRegAddr = *(uint8_t *)dataShiftWidthAddr;
1709             *(uint8_t *)flagShiftMaskRegAddr  = *(uint8_t *)flagShiftMaskAddr;
1710             *(uint8_t *)flagShiftWidthRegAddr = *(uint8_t *)flagShiftWidthAddr;
1711             dataShiftWidthRegAddr++;
1712             flagShiftMaskRegAddr++;
1713             flagShiftWidthRegAddr++;
1714             dataShiftWidthAddr++;
1715             flagShiftMaskAddr++;
1716             flagShiftWidthAddr++;
1717             if (i == 3U)
1718             {
1719                 dataShiftWidthRegAddr += 12U;
1720                 flagShiftMaskRegAddr += 12U;
1721                 flagShiftWidthRegAddr += 12U;
1722             }
1723         }
1724     }
1725 
1726     return kStatus_Success;
1727 }
1728 
1729 /*!
1730  * brief Configures the pre-dither CFA engine.
1731  *
1732  * param base PXP peripheral base address.
1733  * param config pointer to the configuration structure.
1734  * retval kStatus_Success Successfully configured the engine.
1735  * retval kStatus_InvalidArgument Invalid argument.
1736  */
1737 status_t PXP_SetCfaConfig(PXP_Type *base, const pxp_cfa_config_t *config)
1738 {
1739     assert(NULL != config);
1740     /* The CFA array cannot be larger than 15x15. */
1741     if ((config->arrayWidth > 15U) || (config->arrayHeight > 15U))
1742     {
1743         return kStatus_InvalidArgument;
1744     }
1745 
1746     uint32_t cfaArrayRegAddr = (uint32_t) & (base->CFA_ARRAY0);
1747     uint32_t cfaValueAddr    = (uint32_t) & (config->cfaValue);
1748     uint8_t wordCount        = 0U; /* How many 32-bit word does the CFA array need. */
1749 
1750     base->CFA_CTRL = PXP_CFA_CTRL_CFA_ARRAY_HSIZE((uint32_t)config->arrayWidth) |
1751                      PXP_CFA_CTRL_CFA_ARRAY_VSIZE((uint32_t)config->arrayHeight) |
1752                      PXP_CFA_CTRL_CFA_IN_RGB444((uint32_t)config->pixelInFormat) |
1753                      PXP_CFA_CTRL_CFA_BYPASS((uint32_t)config->bypass);
1754     base->CFA_SIZE = ((uint32_t)(config->totalWidth) << 16U) | (uint32_t)(config->totalHeight);
1755 
1756     /* Configure the CFA array value. */
1757     wordCount = (config->arrayWidth * config->arrayHeight * 2U + 32U) / 32U;
1758 
1759     for (uint8_t i = 0U; i < wordCount; i++)
1760     {
1761         *(uint32_t *)cfaArrayRegAddr = *(uint32_t *)cfaValueAddr;
1762         cfaArrayRegAddr += 0x10U;
1763         cfaValueAddr += 4U;
1764     }
1765 
1766     return kStatus_Success;
1767 }
1768 
1769 /*!
1770  * brief Configures histogram engine.
1771  *
1772  * param base PXP peripheral base address.
1773  * param num instance number.
1774  * param config pointer to the configuration structure.
1775  * retval kStatus_Success Successfully configured the engine.
1776  * retval kStatus_InvalidArgument Invalid argument.
1777  */
1778 status_t PXP_SetHistogramConfig(PXP_Type *base, uint8_t num, const pxp_histogram_config_t *config)
1779 {
1780     assert(NULL != config);
1781     /* The LUT value width can not be larger than 6. */
1782     if ((uint32_t)config->lutValueWidth > 6U)
1783     {
1784         return kStatus_InvalidArgument;
1785     }
1786 
1787     uint32_t ctrlReg = 0U;
1788     uint32_t maskReg = 0U;
1789 
1790     ctrlReg = PXP_HIST_A_CTRL_ENABLE((uint32_t)config->enable) |
1791               PXP_HIST_A_CTRL_PIXEL_OFFSET((uint32_t)config->lutValueOffset) |
1792               PXP_HIST_A_CTRL_PIXEL_WIDTH((uint32_t)config->lutValueWidth);
1793     maskReg = PXP_HIST_A_MASK_MASK_EN((uint32_t)config->enableMask) |
1794               PXP_HIST_A_MASK_MASK_MODE((uint32_t)config->condition) |
1795               PXP_HIST_A_MASK_MASK_OFFSET((uint32_t)config->maskOffset) |
1796               PXP_HIST_A_MASK_MASK_WIDTH((uint32_t)config->maskWidth) |
1797               PXP_HIST_A_MASK_MASK_VALUE0((uint32_t)config->maskValue0) |
1798               PXP_HIST_A_MASK_MASK_VALUE1((uint32_t)config->maskValue1);
1799 
1800     switch (num)
1801     {
1802         case 0:
1803             base->HIST_A_CTRL     = ctrlReg;
1804             base->HIST_A_MASK     = maskReg;
1805             base->HIST_A_BUF_SIZE = ((uint32_t)(config->totalHeight) << 16U) | (uint32_t)config->totalWidth;
1806             break;
1807 
1808         case 1:
1809             base->HIST_B_CTRL     = ctrlReg;
1810             base->HIST_B_MASK     = maskReg;
1811             base->HIST_B_BUF_SIZE = ((uint32_t)(config->totalHeight) << 16U) | (uint32_t)config->totalWidth;
1812             break;
1813 
1814         default:
1815             /* Only 2 histogram instances are supported. */
1816             assert(false);
1817             break;
1818     }
1819 
1820     /* Only configure the histogram params when user choose to, otherwise use the registers' reset value as default. */
1821     if (config->pParamValue != NULL)
1822     {
1823         uint32_t paramRegAddr   = (uint32_t) & (base->HIST2_PARAM);
1824         uint32_t paramValueAddr = (uint32_t) & (config->pParamValue);
1825         /* Configure the 2/4/8/16/32-level histogram params. */
1826         for (uint8_t i = 0; i < 62U; i++)
1827         {
1828             *(uint8_t *)paramRegAddr = *(uint8_t *)paramValueAddr;
1829             paramValueAddr += 1U;
1830             paramRegAddr++;
1831             if ((i % 4U) == 1U)
1832             {
1833                 paramRegAddr += 12U;
1834                 if (i == 1U)
1835                 {
1836                     paramRegAddr += 2U;
1837                 }
1838             }
1839         }
1840     }
1841 
1842     return kStatus_Success;
1843 }
1844 
1845 /*!
1846  * brief Gets the results of histogram mask operation.
1847  *
1848  * param base PXP peripheral base address.
1849  * param num instance number.
1850  * param result pointer to the result structure.
1851  */
1852 void PXP_GetHistogramMaskResult(PXP_Type *base, uint8_t num, pxp_histogram_mask_result_t *result)
1853 {
1854     assert(NULL != result);
1855     /* Initializes the result structure to zero. */
1856     (void)memset(result, 0, sizeof(*result));
1857 
1858     switch (num)
1859     {
1860         case 0:
1861             result->pixelCount = base->HIST_A_TOTAL_PIXEL;
1862             result->minX       = (uint16_t)base->HIST_A_ACTIVE_AREA_X;
1863             result->maxX       = (uint16_t)(base->HIST_A_ACTIVE_AREA_X >> 16U);
1864             result->minY       = (uint16_t)base->HIST_A_ACTIVE_AREA_Y;
1865             result->maxY       = (uint16_t)(base->HIST_A_ACTIVE_AREA_Y >> 16U);
1866             result->lutlist    = (uint64_t)base->HIST_A_RAW_STAT0 | ((uint64_t)base->HIST_A_RAW_STAT1 << 32U);
1867             break;
1868 
1869         case 1:
1870             result->pixelCount = base->HIST_B_TOTAL_PIXEL;
1871             result->minX       = (uint16_t)base->HIST_B_ACTIVE_AREA_X;
1872             result->maxX       = (uint16_t)(base->HIST_B_ACTIVE_AREA_X >> 16U);
1873             result->minY       = (uint16_t)base->HIST_B_ACTIVE_AREA_Y;
1874             result->maxY       = (uint16_t)(base->HIST_B_ACTIVE_AREA_Y >> 16U);
1875             result->lutlist    = (uint64_t)base->HIST_B_RAW_STAT0 | ((uint64_t)base->HIST_B_RAW_STAT1 << 32U);
1876             break;
1877 
1878         default:
1879             /* Only 2 histogram instances are supported. */
1880             assert(false);
1881             break;
1882     }
1883 }
1884 
1885 /*!
1886  * brief Initializes the WFE-A engine for waveform process.
1887  *
1888  * param base PXP peripheral base address.
1889  * param ditherHandshake true to enable handshake mode with upstream dither store engine.
1890  */
1891 void PXP_WfeaInit(PXP_Type *base, bool ditherHandshake)
1892 {
1893     /* FETCH engine configuration, user fetch buffer1 for Y4 data buffer and buffer2 for working buffer. */
1894     /* Enable buffer1&2 fetch. 2 bytes in each pixel for the buffer2.
1895        Other default configurations: fetch data from external axi bus, normal(not hanshake or by pass) mode, burst
1896        length 4, normal border pixels select(not sw reg mode), 1 line fetch, done IRQ disabled. */
1897     base->WFA_FETCH_CTRL = PXP_WFA_FETCH_CTRL_BF1_EN(1UL) | PXP_WFA_FETCH_CTRL_BF2_EN(1UL) |
1898                            PXP_WFA_FETCH_CTRL_BF2_BYTES_PP(1UL) |
1899                            PXP_WFA_FETCH_CTRL_BF1_HSK_MODE((uint32_t)ditherHandshake);
1900     /* Select pixel from bufer 2, set the right/left bit position on the original pixel as 0/3 */
1901     /* Other default configurations: x/y offset=0, positive offset. */
1902     base->WFA_ARRAY_PIXEL0_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1UL) | PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(3UL);
1903     /* Select pixel from bufer 2, set the right/left bit position on the original pixel as 4/7 */
1904     base->WFA_ARRAY_PIXEL1_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1UL) | PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(4UL) |
1905                                   PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(7UL);
1906     /* Select pixel from bufer 2, set the right/left bit position on the original pixel as 8/9 */
1907     base->WFA_ARRAY_PIXEL2_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1UL) | PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(8UL) |
1908                                   PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(9UL);
1909     /* Select pixel from bufer 2, set the right/left bit position on the original pixel as 10/15 */
1910     base->WFA_ARRAY_PIXEL3_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1UL) | PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(10UL) |
1911                                   PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(15UL);
1912     /* Select pixel from bufer 1, set the right/left bit position on the original pixel as 4/7 */
1913     base->WFA_ARRAY_PIXEL4_MASK = PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(4UL) | PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(7UL);
1914     /* Software define flag0=1, other flags 1~15 =0 */
1915     base->WFA_ARRAY_REG2 = 1UL;
1916 
1917     /* STORE engine configuration */
1918     /* Channel 0 y4, channel 1 wb */
1919     /* Enable channel 0, store data to memory, select low 32 bit shift out data to pack, enable combine 2 channel. */
1920     /* Other default configurations: Arbitration disable(if using 2 channels, will output 2 axi bus sets), 8 bytes in a
1921        burst, fill data mode disable, block mode disable. */
1922     base->WFE_A_STORE_CTRL_CH0 = PXP_WFE_A_STORE_CTRL_CH0_CH_EN(1UL) | PXP_WFE_A_STORE_CTRL_CH0_STORE_MEMORY_EN(1UL) |
1923                                  PXP_WFE_A_STORE_CTRL_CH0_PACK_IN_SEL(1UL) |
1924                                  PXP_WFE_A_STORE_CTRL_CH0_COMBINE_2CHANNEL(1UL);
1925     /* Enable channel 1, store data to memory, select low 32 bit shift out data to pack, 16 bytes in a write burst. */
1926     base->WFE_A_STORE_CTRL_CH1 = PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1UL) | PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN(1UL) |
1927                                  PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL(1UL) | PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES(1UL);
1928     /* 8 Bpp, disable YUV planes, disable shift bypass. */
1929     base->WFE_A_STORE_SHIFT_CTRL_CH0 = 0UL;
1930     /* 16 Bpp, disable YUV planes, disable shift bypass. */
1931     base->WFE_A_STORE_SHIFT_CTRL_CH1 = PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(1);
1932     base->WFE_A_STORE_FILL_DATA_CH0  = 0UL;
1933     /* 8 data masks, mask 0-7. Only use mask 0-4 */
1934     /* mask 0: 0xF << 32; mask 1: 0xF00 << 28; mask 2: 0x0 << 24; mask 3: 0x3F00'0000 << 18; mask 4: 0xF'0000'0000 >> 28
1935      */
1936     base->WFE_A_STORE_D_MASK0_H_CH0 = 0UL;
1937     base->WFE_A_STORE_D_MASK0_L_CH0 = PXP_WFE_A_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(0xfUL); /* fetch CP */
1938     base->WFE_A_STORE_D_MASK1_H_CH0 = 0UL;
1939     base->WFE_A_STORE_D_MASK1_L_CH0 = PXP_WFE_A_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0xf00UL); /* fetch NP */
1940     base->WFE_A_STORE_D_MASK2_H_CH0 = 0UL;
1941     base->WFE_A_STORE_D_MASK2_L_CH0 = 0UL;
1942     base->WFE_A_STORE_D_MASK3_H_CH0 = 0UL;
1943     base->WFE_A_STORE_D_MASK3_L_CH0 = PXP_WFE_A_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0(0x3f000000UL); /* fetch LUT */
1944     base->WFE_A_STORE_D_MASK4_H_CH0 = PXP_WFE_A_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0(0xfUL);
1945     base->WFE_A_STORE_D_MASK4_L_CH0 = 0UL; /* fetch Y4 */
1946     base->WFE_A_STORE_D_SHIFT_L_CH0 =
1947         PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(32UL) | PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(1UL) |
1948         PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(28UL) | PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(1UL) |
1949         PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(24UL) | PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(1UL) |
1950         PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(18UL) | PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(1UL);
1951     base->WFE_A_STORE_D_SHIFT_H_CH0 = PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(28UL);
1952 
1953     /* 8 flag masks, mask 0-7. Only use mask 0-3 */
1954     /* mask 0: 0x1 << 1; mask 1: 0x2 >> 1; mask 2: 0x4 << 38; mask 3: 0x8 << 38 */
1955     /* Switch flag bit 0&1, bit 2&3 << 38 */
1956     base->WFE_A_STORE_F_MASK_H_CH0 = 0UL;
1957     base->WFE_A_STORE_F_MASK_L_CH0 =
1958         PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK0(0x1UL) | PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK1(0x2UL) |
1959         PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK2(0x4UL) | PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK3(0x8UL);
1960     base->WFE_A_STORE_F_SHIFT_H_CH0 = 0UL;
1961     base->WFE_A_STORE_F_SHIFT_L_CH0 =
1962         PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(1UL) | PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(1UL) |
1963         PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(1UL) | PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(0UL) |
1964         PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(32UL + 6UL) | PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(1UL) |
1965         PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(32UL + 6UL) | PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(1UL);
1966 
1967     /* Enable and bypass the ALU process. */
1968     base->ALU_A_INST_ENTRY = 0UL;
1969     base->ALU_A_PARAM      = 0UL;
1970     base->ALU_A_CONFIG     = 0UL;
1971     base->ALU_A_LUT_CONFIG = 0UL;
1972     base->ALU_A_LUT_DATA0  = 0UL;
1973     base->ALU_A_LUT_DATA1  = 0UL;
1974     base->ALU_A_CTRL       = PXP_ALU_A_CTRL_BYPASS(1UL) | PXP_ALU_A_CTRL_ENABLE(1UL);
1975 
1976     /* WFE A */
1977     base->WFE_A_STAGE1_MUX0  = 0x3F3F0303UL;
1978     base->WFE_A_STAGE1_MUX1  = 0x0C00000CUL;
1979     base->WFE_A_STAGE1_MUX2  = 0x01040000UL;
1980     base->WFE_A_STAGE1_MUX3  = 0x0A0A0904UL;
1981     base->WFE_A_STAGE1_MUX4  = 0x00000B0BUL;
1982     base->WFE_A_STAGE2_MUX0  = 0x1800280EUL;
1983     base->WFE_A_STAGE2_MUX1  = 0x00280E01UL;
1984     base->WFE_A_STAGE2_MUX2  = 0x280E0118UL;
1985     base->WFE_A_STAGE2_MUX3  = 0x00011800UL;
1986     base->WFE_A_STAGE2_MUX4  = 0UL;
1987     base->WFE_A_STAGE2_MUX5  = 0x1800280EUL;
1988     base->WFE_A_STAGE2_MUX6  = 0x00280E01UL;
1989     base->WFE_A_STAGE2_MUX7  = 0x1A0E0118UL;
1990     base->WFE_A_STAGE2_MUX8  = 0x1B012911UL;
1991     base->WFE_A_STAGE2_MUX9  = 0x00002911UL;
1992     base->WFE_A_STAGE2_MUX10 = 0UL;
1993     base->WFE_A_STAGE2_MUX11 = 0UL;
1994     base->WFE_A_STAGE2_MUX12 = 0UL;
1995     base->WFE_A_STAGE3_MUX0  = 0x07060504UL;
1996     base->WFE_A_STAGE3_MUX1  = 0x3F3F3F08UL;
1997     base->WFE_A_STAGE3_MUX2  = 0x03020100UL;
1998     base->WFE_A_STAGE3_MUX3  = 0x3F3F3F3FUL;
1999 
2000     /* WFE_A_STG1_8X1_OUT0_0/1 is used to store LUT occupation status */
2001     /* Set LUT64-255 to occupied since we only have 64 LUTs in EPDC */
2002     base->WFE_A_STG1_8X1_OUT0_2 = 0xFFFFFFFFUL;
2003     base->WFE_A_STG1_8X1_OUT0_3 = 0xFFFFFFFFUL;
2004     base->WFE_A_STG1_8X1_OUT0_4 = 0xFFFFFFFFUL;
2005     base->WFE_A_STG1_8X1_OUT0_5 = 0xFFFFFFFFUL;
2006     base->WFE_A_STG1_8X1_OUT0_6 = 0xFFFFFFFFUL;
2007     base->WFE_A_STG1_8X1_OUT0_7 = 0xFFFFFFFFUL;
2008     /* OUT1.2.3 LUT0-255 */
2009     base->WFE_A_STG1_8X1_OUT1_0 = 0UL;
2010     base->WFE_A_STG1_8X1_OUT1_1 = 0UL;
2011     base->WFE_A_STG1_8X1_OUT1_2 = 0UL;
2012     base->WFE_A_STG1_8X1_OUT1_3 = 0UL;
2013     base->WFE_A_STG1_8X1_OUT1_4 = 0UL;
2014     base->WFE_A_STG1_8X1_OUT1_5 = 0UL;
2015     base->WFE_A_STG1_8X1_OUT1_6 = 0UL;
2016     base->WFE_A_STG1_8X1_OUT1_7 = 0UL;
2017     base->WFE_A_STG1_8X1_OUT2_0 = 0UL;
2018     base->WFE_A_STG1_8X1_OUT2_1 = 0UL;
2019     base->WFE_A_STG1_8X1_OUT2_2 = 0UL;
2020     base->WFE_A_STG1_8X1_OUT2_3 = 0UL;
2021     base->WFE_A_STG1_8X1_OUT2_4 = 0UL;
2022     base->WFE_A_STG1_8X1_OUT2_5 = 0UL;
2023     base->WFE_A_STG1_8X1_OUT2_6 = 0UL;
2024     base->WFE_A_STG1_8X1_OUT2_7 = 0UL;
2025     base->WFE_A_STG1_8X1_OUT3_0 = 0UL;
2026     base->WFE_A_STG1_8X1_OUT3_1 = 0UL;
2027     base->WFE_A_STG1_8X1_OUT3_2 = 0UL;
2028     base->WFE_A_STG1_8X1_OUT3_3 = 0UL;
2029     base->WFE_A_STG1_8X1_OUT3_4 = 0UL;
2030     base->WFE_A_STG1_8X1_OUT3_5 = 0UL;
2031     base->WFE_A_STG1_8X1_OUT3_6 = 0UL;
2032     base->WFE_A_STG1_8X1_OUT3_7 = 0UL;
2033     /* LUTOUT0-31 for OUT0-3.
2034        The 5x6 LUT output value for input value n. This output value determines which input to select (flag, data). */
2035     base->WFE_A_STG2_5X6_OUT0_0 = 0x04040404UL;
2036     base->WFE_A_STG2_5X6_OUT0_1 = 0x04040404UL;
2037     base->WFE_A_STG2_5X6_OUT0_2 = 0x04050505UL;
2038     base->WFE_A_STG2_5X6_OUT0_3 = 0x04040404UL;
2039     base->WFE_A_STG2_5X6_OUT0_4 = 0x04040404UL;
2040     base->WFE_A_STG2_5X6_OUT0_5 = 0x04040404UL;
2041     base->WFE_A_STG2_5X6_OUT0_6 = 0x04040404UL;
2042     base->WFE_A_STG2_5X6_OUT0_7 = 0x04040404UL;
2043     base->WFE_A_STG2_5X6_OUT1_0 = 0x05050505UL;
2044     base->WFE_A_STG2_5X6_OUT1_1 = 0x05050505UL;
2045     base->WFE_A_STG2_5X6_OUT1_2 = 0x05080808UL;
2046     base->WFE_A_STG2_5X6_OUT1_3 = 0x05050505UL;
2047     base->WFE_A_STG2_5X6_OUT1_4 = 0x05050505UL;
2048     base->WFE_A_STG2_5X6_OUT1_5 = 0x05050505UL;
2049     base->WFE_A_STG2_5X6_OUT1_6 = 0x05050505UL;
2050     base->WFE_A_STG2_5X6_OUT1_7 = 0x05050505UL;
2051     base->WFE_A_STG2_5X6_OUT2_0 = 0x07070707UL;
2052     base->WFE_A_STG2_5X6_OUT2_1 = 0x07070707UL;
2053     base->WFE_A_STG2_5X6_OUT2_2 = 0x070C0C0CUL;
2054     base->WFE_A_STG2_5X6_OUT2_3 = 0x07070707UL;
2055     base->WFE_A_STG2_5X6_OUT2_4 = 0X0F0F0F0FUL;
2056     base->WFE_A_STG2_5X6_OUT2_5 = 0X0F0F0F0FUL;
2057     base->WFE_A_STG2_5X6_OUT2_6 = 0X0F0F0F0FUL;
2058     base->WFE_A_STG2_5X6_OUT2_7 = 0X0F0F0F0FUL;
2059     base->WFE_A_STG2_5X6_OUT3_0 = 0UL;
2060     base->WFE_A_STG2_5X6_OUT3_1 = 0UL;
2061     base->WFE_A_STG2_5X6_OUT3_2 = 0UL;
2062     base->WFE_A_STG2_5X6_OUT3_3 = 0UL;
2063     base->WFE_A_STG2_5X6_OUT3_4 = 0UL;
2064     base->WFE_A_STG2_5X6_OUT3_5 = 0UL;
2065     base->WFE_A_STG2_5X6_OUT3_6 = 0UL;
2066     base->WFE_A_STG2_5X6_OUT3_7 = 0UL;
2067     /* MASK0-3, 5 bits each mask.
2068        Each set mask bit enables one of the corresponding flag input bits. There is one mask per 5x6 LUT. */
2069     base->WFE_A_STAGE2_5X6_MASKS_0 = 0x001F1F1FUL;
2070     /* MUXADDR 0-3, 6 bits each.
2071        Each Address specifies the MUX position in the MUX array. There is one MUXADDR per 5x6 LUT.*/
2072     base->WFE_A_STAGE2_5X6_ADDR_0 = 0x3f030100UL;
2073     /* Flag of LUTOUT0-31 for OUT0-3.
2074        The 5x1 LUT output value for input value n. This output value results in a flag that is added to the flag array.
2075      */
2076     base->WFE_A_STG2_5X1_OUT0 = 0x00000700UL;
2077     base->WFE_A_STG2_5X1_OUT1 = 0x00007000UL;
2078     base->WFE_A_STG2_5X1_OUT2 = 0x0000A000UL;
2079     base->WFE_A_STG2_5X1_OUT3 = 0x000000C0UL;
2080     /* MASK0-3, 5 bits each mask.
2081        Each set mask bit enables one of the corresponding flag input bits. There is one mask per 5x1 LUT. */
2082     base->WFE_A_STG2_5X1_MASKS = 0x071F1F1FUL;
2083 }
2084 
2085 /*!
2086  * brief Configure the WFE-A engine
2087  *
2088  * param base PXP peripheral base address.
2089  * param config pointer to the configuration structure.
2090  */
2091 void PXP_SetWfeaConfig(PXP_Type *base, const pxp_wfea_engine_config_t *config)
2092 {
2093     /* Fetch */
2094     base->WFA_FETCH_BUF1_ADDR  = config->y4Addr;
2095     base->WFA_FETCH_BUF1_PITCH = config->updatePitch;
2096     base->WFA_FETCH_BUF1_SIZE  = PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT((uint32_t)config->updateHeight - 1UL) |
2097                                 PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH((uint32_t)config->updateWidth - 1UL);
2098     base->WFA_FETCH_BUF1_CORD  = 0UL;
2099     base->WFA_FETCH_BUF2_ADDR  = config->wbAddr;
2100     base->WFA_FETCH_BUF2_PITCH = (uint32_t)config->resX * 2U; /* 2 bytes per pixel */
2101     base->WFA_FETCH_BUF2_SIZE  = PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT((uint32_t)config->updateHeight - 1UL) |
2102                                 PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH((uint32_t)config->updateWidth - 1UL);
2103     base->WFA_FETCH_BUF2_CORD =
2104         PXP_WFA_FETCH_BUF2_CORD_YCORD((uint32_t)config->ulcY) | PXP_WFA_FETCH_BUF2_CORD_XCORD((uint32_t)config->ulcX);
2105 
2106     /* Store */
2107     base->WFE_A_STORE_SIZE_CH0 = PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH((uint32_t)config->updateWidth - 1UL) |
2108                                  PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT((uint32_t)config->updateHeight - 1UL);
2109     base->WFE_A_STORE_SIZE_CH1 = PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH((uint32_t)config->updateWidth - 1UL) |
2110                                  PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT((uint32_t)config->updateHeight - 1UL);
2111     /* Channel 1: 2 byte per pixel. */
2112     base->WFE_A_STORE_PITCH = PXP_WFE_A_STORE_PITCH_CH0_OUT_PITCH((uint32_t)config->resX) |
2113                               PXP_WFE_A_STORE_PITCH_CH1_OUT_PITCH((uint32_t)config->resX * 2U);
2114     base->WFE_A_STORE_ADDR_0_CH0 = PXP_WFE_A_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(config->y4cAddr);
2115     base->WFE_A_STORE_ADDR_1_CH0 = 0U;
2116     /* Channel 1: 2 bytes per pixel. */
2117     base->WFE_A_STORE_ADDR_0_CH1 = PXP_WFE_A_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(
2118         (uint32_t)config->wbAddr + ((uint32_t)config->ulcX + (uint32_t)config->ulcY * (uint32_t)config->resX) * 2UL);
2119     base->WFE_A_STORE_ADDR_1_CH1 = 0U;
2120 
2121     /* ALU */
2122     base->ALU_A_BUF_SIZE = PXP_ALU_A_BUF_SIZE_BUF_WIDTH((uint32_t)config->updateWidth) |
2123                            PXP_ALU_A_BUF_SIZE_BUF_HEIGHT((uint32_t)config->updateHeight);
2124 
2125     /* WFE */
2126     /* Height and width of the updete region */
2127     base->WFE_A_DIMENSIONS =
2128         PXP_WFE_A_DIMENSIONS_WIDTH(config->updateWidth) | PXP_WFE_A_DIMENSIONS_HEIGHT(config->updateHeight);
2129     /* The distance from the frame origin to the update region origin in the X/Y direction. */
2130     base->WFE_A_OFFSET = PXP_WFE_A_OFFSET_X_OFFSET(config->ulcX) | PXP_WFE_A_OFFSET_Y_OFFSET(config->ulcY);
2131     /* val3,val2=0, val1=F, val0=lutNum */
2132     base->WFE_A_SW_DATA_REGS = (config->lutNum & 0x000000FFUL) | 0x00000F00UL;
2133     /* val3,val2=0, val1=0(disable reagl/-d), val0=partial(1)full(0) */
2134     base->WFE_A_SW_FLAG_REGS = ((uint32_t)(!config->fullUpdateEnable) | (0U << 1U));
2135     /* Enable and reset WFE-A state. Disable register of ALU inside waveform as default. */
2136     base->WFE_A_CTRL = PXP_WFE_A_CTRL_ENABLE(1UL) | PXP_WFE_A_CTRL_SW_RESET(1UL);
2137 
2138     if (config->alphaEnable)
2139     {
2140         base->WFA_ARRAY_FLAG0_MASK = 0U;
2141     }
2142     else
2143     {
2144         base->WFA_ARRAY_FLAG0_MASK = PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL(2UL);
2145     }
2146 
2147     /* disable CH1 when only doing detection */
2148     if (config->detectionOnly)
2149     {
2150         base->WFE_A_STORE_CTRL_CH1 &= ~PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1UL);
2151     }
2152     else
2153     {
2154         base->WFE_A_STORE_CTRL_CH1 |= PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1UL);
2155     }
2156     /* Enable engine */
2157     base->CTRL_SET = PXP_CTRL_ENABLE_WFE_A(1UL);
2158 }
2159 #endif /* FSL_FEATURE_PXP_V3 */
2160 
2161 #if PXP_USE_PATH
2162 /*!
2163  * brief Sets the path for one of the MUX
2164  *
2165  * param base PXP peripheral base address.
2166  * param path the path configuration for one of the mux.
2167  */
2168 void PXP_SetPath(PXP_Type *base, pxp_path_t path)
2169 {
2170     volatile uint32_t *pathReg;
2171     uint32_t mux = PXP_GET_MUX_FROM_PATH((uint32_t)path);
2172     uint32_t sel = PXP_GET_SEL_FROM_PATH((uint32_t)path);
2173 
2174     if (mux > 15U)
2175     {
2176         pathReg = &(base->DATA_PATH_CTRL1);
2177         mux -= 15U;
2178     }
2179     else
2180     {
2181         pathReg = &(base->DATA_PATH_CTRL0);
2182     }
2183 
2184     /* Convert mux to the register shift. */
2185     mux *= 2U;
2186     *pathReg = (*pathReg & ~(3UL << mux)) | (sel << mux);
2187 }
2188 #endif /* PXP_USE_PATH */