Back to home page

LXR

 
 

    


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

0001 /*
0002  * Copyright 2020-2022 NXP
0003  * All rights reserved.
0004  *
0005  * SPDX-License-Identifier: BSD-3-Clause
0006  */
0007 
0008 #include "fsl_mipi_dsi.h"
0009 
0010 /*******************************************************************************
0011  * Definitions
0012  ******************************************************************************/
0013 
0014 /* Component ID definition, used by tools. */
0015 #ifndef FSL_COMPONENT_ID
0016 #define FSL_COMPONENT_ID "platform.drivers.mipi_dsi_split"
0017 #endif
0018 
0019 /* The timeout cycles to wait for DSI state machine idle. */
0020 #ifndef FSL_MIPI_DSI_IDLE_TIMEOUT
0021 #define FSL_MIPI_DSI_IDLE_TIMEOUT 0x1000U
0022 #endif
0023 
0024 /* PLL CN should be in the range of 1 to 32. */
0025 #define DSI_DPHY_PLL_CN_MIN 1U
0026 #define DSI_DPHY_PLL_CN_MAX 32U
0027 
0028 /* PLL refClk / CN should be in the range of 24M to 30M. */
0029 #define DSI_DPHY_PLL_REFCLK_CN_MIN 24000000U
0030 #define DSI_DPHY_PLL_REFCLK_CN_MAX 30000000U
0031 
0032 /* PLL CM should be in the range of 16 to 255. */
0033 #define DSI_DPHY_PLL_CM_MIN 16U
0034 #define DSI_DPHY_PLL_CM_MAX 255U
0035 
0036 /* PLL VCO output frequency max value is 1.5GHz, VCO output is (refClk / CN ) * CM. */
0037 #define DSI_DPHY_PLL_VCO_MAX 1500000000U
0038 #define DSI_DPHY_PLL_VCO_MIN (DSI_DPHY_PLL_REFCLK_CN_MIN * DSI_DPHY_PLL_CM_MIN)
0039 
0040 #define PKT_CONTROL_WORD_COUNT(wc)  ((uint32_t)(wc) << 0U)
0041 #define PKT_CONTROL_VC(vc)          ((uint32_t)(vc) << 16U)
0042 #define PKT_CONTROL_HEADER_TYPE(ht) ((uint32_t)(ht) << 18U)
0043 #define PKT_CONTROL_HS_MASK         (1UL << 24U)
0044 #define PKT_CONTROL_BTA_MASK        (1UL << 25U)
0045 #define PKT_CONTROL_BTA_ONLY_MASK   (1UL << 26U)
0046 
0047 /* Macro used for D-PHY timing setting. */
0048 #define DSI_THS_ZERO_BYTE_CLK_BASE         6U
0049 #define DSI_TCLK_ZERO_BYTE_CLK_BASE        3U
0050 #define DSI_THS_PREPARE_HALF_ESC_CLK_BASE  2U
0051 #define DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE 2U
0052 
0053 #define DSI_THS_PREPARE_HALF_ESC_CLK_MIN  (DSI_THS_PREPARE_HALF_ESC_CLK_BASE)
0054 #define DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN (DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE)
0055 
0056 #define DSI_THS_PREPARE_HALF_ESC_CLK_MAX  (5U)
0057 #define DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX (3U)
0058 
0059 /* Convert ns to byte clock. */
0060 #define DSI_NS_TO_BYTE_CLK(ns, byte_clk_khz) ((ns) * (byte_clk_khz) / 1000000U)
0061 /* Convert ns+UI to byte clock. */
0062 #define DSI_NS_UI_TO_BYTE_CLK(ns, UI, byte_clk_khz) ((((ns) * (byte_clk_khz)) + ((UI)*125000U)) / 1000000U)
0063 
0064 /* Packet overhead for HSA, HFP, HBP */
0065 #define DSI_HSA_OVERHEAD_BYTE 10UL /* HSS + HSA header + HSA CRC. */
0066 #define DSI_HFP_OVERHEAD_BYTE 12UL /* RGB data packet CRC + HFP header + HFP CRC. */
0067 #define DSI_HBP_OVERHEAD_BYTE 10UL /* HSE + HBP header + HBP CRC + RGB data packet header */
0068 
0069 #define DSI_INT_STATUS_TRIGGER_MASK                                                                           \
0070     ((uint32_t)kDSI_InterruptGroup1ResetTriggerReceived | (uint32_t)kDSI_InterruptGroup1TearTriggerReceived | \
0071      (uint32_t)kDSI_InterruptGroup1AckTriggerReceived)
0072 #define DSI_INT_STATUS_ERROR_REPORT_MASK (0xFFFFU << 9U)
0073 
0074 #if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
0075 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && (0 != FSL_FEATURE_LDB_COMBO_PHY))
0076 typedef MIPI_DSI_LVDS_COMBO_CSR_Type MIPI_DSI_CSR_Type;
0077 #define MIPI_DSI_CSR_ULPS_CTRL(csr)      ((csr)->ULPS_CTRL)
0078 #define MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK MIPI_DSI_LVDS_COMBO_CSR_ULPS_CTRL_TX_ULPS_MASK
0079 #define MIPI_DSI_CSR_PXL2DPI(csr)        ((csr)->PXL2DPI_CTRL)
0080 #else
0081 #define MIPI_DSI_CSR_ULPS_CTRL(csr)      ((csr)->TX_ULPS_ENABLE)
0082 #define MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK MIPI_DSI_TX_ULPS_ENABLE_TX_ULPS_ENABLE_MASK
0083 #define MIPI_DSI_CSR_PXL2DPI(csr)        ((csr)->PXL2DPI_CONFIG)
0084 #endif
0085 
0086 #define DSI_GET_CSR(dsi_base) ((MIPI_DSI_CSR_Type *)(((uint32_t)(dsi_base)) - (uint32_t)FSL_FEATURE_DSI_CSR_OFFSET))
0087 #endif
0088 
0089 /*! @brief Typedef for MIPI DSI interrupt handler. */
0090 typedef void (*dsi_isr_t)(const MIPI_DSI_Type *base, dsi_handle_t *handle);
0091 
0092 /*******************************************************************************
0093  * Variables
0094  ******************************************************************************/
0095 #if defined(DSI_HOST_DSI_IRQS)
0096 /* Array of DSI IRQ number. */
0097 static const IRQn_Type s_dsiIRQ[] = DSI_HOST_DSI_IRQS;
0098 #endif
0099 /*! @brief Pointers to MIPI DSI bases for each instance. */
0100 static DSI_HOST_Type *const s_dsiBases[] = DSI_HOST_BASE_PTRS;
0101 /*! @brief MIPI DSI internal handle pointer array */
0102 static dsi_handle_t *s_dsiHandle[ARRAY_SIZE(s_dsiBases)];
0103 /*! @brief Pointer to IRQ handler. */
0104 static dsi_isr_t s_dsiIsr;
0105 
0106 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0107 /*! @brief Pointers to MIPI DSI clocks for each instance. */
0108 static const clock_ip_name_t s_dsiClocks[] = MIPI_DSI_HOST_CLOCKS;
0109 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0110 
0111 /*******************************************************************************
0112  * Prototypes
0113  ******************************************************************************/
0114 /*!
0115  * @brief Get the MIPI DSI host controller instance from peripheral base address.
0116  *
0117  * @param base MIPI DSI peripheral base address.
0118  * @return MIPI DSI instance.
0119  */
0120 static uint32_t DSI_GetInstance(const MIPI_DSI_Type *base);
0121 
0122 #if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
0123 /*!
0124  * @brief Convert the D-PHY PLL CN to the value could be set to register.
0125  *
0126  * @param cn The CN value.
0127  * @return The register value.
0128  */
0129 static uint8_t DSI_EncodeDphyPllCn(uint8_t cn);
0130 
0131 /*!
0132  * @brief Convert the D-PHY PLL CM to the value could be set to register.
0133  *
0134  * @param cm The CM value.
0135  * @return The register value.
0136  */
0137 static uint8_t DSI_EncodeDphyPllCm(uint8_t cm);
0138 
0139 /*!
0140  * @brief Calculate the D-PHY PLL dividers to generate the desired output frequency.
0141  *
0142  * Calculate the PLL dividers to generate the most close desired output PLL frequency.
0143  *
0144  * txHsBitClk_Hz = refClkFreq_Hz * CM / (CN * CO).
0145  * CM: 16 ~ 255
0146  * CN: 1 ~ 32
0147  * CO: 1, 2, 4, 8
0148  *
0149  * @param cn The CN value, convert using @ref DSI_EncodeDphyPllCn before setting to register.
0150  * @param cm The CM value, convert using @ref DSI_EncodeDphyPllCm before setting to register.
0151  * @param co The CO value, could set to register directly.
0152  * @param refClkFreq_Hz The D-PHY input reference clock frequency (REF_CLK).
0153  * @param desiredOutFreq_Hz Desired PLL output frequency.
0154  * @return The actually output frequency using the returned dividers. If could not
0155  * find suitable dividers, return 0.
0156  */
0157 static uint32_t DSI_DphyGetPllDivider(
0158     uint32_t *cn, uint32_t *cm, uint32_t *co, uint32_t refClkFreq_Hz, uint32_t desiredOutFreq_Hz);
0159 #endif
0160 
0161 /*!
0162  * @brief Clear the RX FIFO.
0163  *
0164  * @param base MIPI DSI host peripheral base address.
0165  */
0166 static void DSI_ApbClearRxFifo(const MIPI_DSI_Type *base);
0167 
0168 /*!
0169  * @brief Handle the DSI transfer result.
0170  *
0171  * @param base MIPI DSI host peripheral base address.
0172  * @param xfer The transfer definition.
0173  * @param intFlags1 Interrupt flag group 1.
0174  * @param intFlags2 Interrupt flag group 2.
0175  * @retval kStatus_Success No error happens.
0176  * @retval kStatus_Timeout Hardware timeout detected.
0177  * @retval kStatus_DSI_RxDataError RX data error.
0178  * @retval kStatus_DSI_ErrorReportReceived Error Report packet received.
0179  * @retval kStatus_DSI_Fail Transfer failed for other reasons.
0180  */
0181 static status_t DSI_HandleResult(const MIPI_DSI_Type *base,
0182                                  uint32_t intFlags1,
0183                                  uint32_t intFlags2,
0184                                  dsi_transfer_t *xfer);
0185 
0186 /*!
0187  * @brief Prepare for the DSI APB transfer.
0188  *
0189  * This function fills TX data to DSI TX FIFO and sets the packet control
0190  * register. Packet transfer could start using @ref DSI_SendApbPacket after
0191  * this function.
0192  *
0193  * @param base MIPI DSI host peripheral base address.
0194  * @param xfer The transfer definition.
0195  * @retval kStatus_Success It is ready to start transfer.
0196  * @retval kStatus_DSI_NotSupported The transfer format is not supported.
0197  */
0198 static status_t DSI_PrepareApbTransfer(const MIPI_DSI_Type *base, dsi_transfer_t *xfer);
0199 
0200 /*!
0201  * @brief Convert time from nano-second to count of byte clock.
0202  *
0203  * @param ns Time in nano-second.
0204  * @param byteclk_khz Byte clock frequency in kHz.
0205  * @return Time in byte clock.
0206  */
0207 static uint32_t DSI_NsToByteClk(uint32_t ns, uint32_t byteclk_khz)
0208 {
0209     return (ns * byteclk_khz) / 1000000UL;
0210 }
0211 
0212 /*!
0213  * @brief Convert the time to count of byte clock.
0214  *
0215  * The time is the sum of nano-second specified by ns and count of UI.
0216  *
0217  * @param ns Time in nano-second.
0218  * @param UI Count of UI.
0219  * @param byteclk_khz Byte clock frequency in kHz.
0220  * @return Time in byte clock.
0221  */
0222 static uint32_t DSI_NsUiToByteClk(uint32_t ns, uint32_t UI, uint32_t byteclk_khz)
0223 {
0224     return ((ns * byteclk_khz) + (UI * 125000UL)) / 1000000UL;
0225 }
0226 
0227 /*******************************************************************************
0228  * Code
0229  ******************************************************************************/
0230 
0231 static uint32_t DSI_GetInstance(const MIPI_DSI_Type *base)
0232 {
0233     uint32_t instance;
0234 
0235     /* Find the instance index from base address mappings. */
0236     for (instance = 0; instance < ARRAY_SIZE(s_dsiBases); instance++)
0237     {
0238         if (s_dsiBases[instance] == base->host)
0239         {
0240             break;
0241         }
0242     }
0243 
0244     assert(instance < ARRAY_SIZE(s_dsiBases));
0245 
0246     return instance;
0247 }
0248 
0249 #if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
0250 static uint8_t DSI_EncodeDphyPllCn(uint8_t cn)
0251 {
0252     uint8_t ret = 0U;
0253 
0254     assert((cn >= 1U) && (cn <= 32U));
0255 
0256     if (1U == cn)
0257     {
0258         ret = 0x1FU;
0259     }
0260     else
0261     {
0262         ret = (uint8_t)((0x65BD44E0UL >> ((uint32_t)cn - 2U)) & 0x1FU);
0263     }
0264 
0265     return ret;
0266 }
0267 
0268 static uint8_t DSI_EncodeDphyPllCm(uint8_t cm)
0269 {
0270     uint8_t ret = 0U;
0271 
0272     assert(cm >= 16U);
0273 
0274     if (cm <= 31U)
0275     {
0276         ret = 0xE0U | cm;
0277     }
0278     else if (cm <= 63U)
0279     {
0280         ret = 0xC0U | (cm & 0x1FU);
0281     }
0282     else if (cm <= 127U)
0283     {
0284         ret = 0x80U | (cm & 0x3FU);
0285     }
0286     else
0287     {
0288         ret = cm & 0xCFU;
0289     }
0290 
0291     return ret;
0292 }
0293 
0294 static uint32_t DSI_DphyGetPllDivider(
0295     uint32_t *cn, uint32_t *cm, uint32_t *co, uint32_t refClkFreq_Hz, uint32_t desiredOutFreq_Hz)
0296 {
0297     uint32_t cnCur;
0298     uint32_t cmCur;
0299     uint32_t coShiftCur;
0300     uint32_t pllFreqCur;
0301     uint32_t diffCur;
0302     uint32_t vcoFreq;
0303     uint32_t refClk_CN;
0304     uint32_t diff             = 0xFFFFFFFFU;
0305     uint32_t pllFreqCandidate = 0U;
0306 
0307     /* CO available values are 1, 2, 4, 8, so the shift values are 0, 1, 2, 3.  */
0308     for (coShiftCur = 0U; coShiftCur <= 3U; coShiftCur++)
0309     {
0310         /* Desired VCO output frequency. */
0311         vcoFreq = desiredOutFreq_Hz << coShiftCur;
0312 
0313         /* If desired VCO output frequency is too small, try larger CO value. */
0314         if (vcoFreq < DSI_DPHY_PLL_VCO_MIN)
0315         {
0316             continue;
0317         }
0318 
0319         /* If desired VCO output frequency is too large, search finished. */
0320         if (vcoFreq > DSI_DPHY_PLL_VCO_MAX)
0321         {
0322             break;
0323         }
0324 
0325         /* Now search the best CN and CM to generate disired VCO output frequency. */
0326         for (cnCur = DSI_DPHY_PLL_CN_MIN; cnCur <= DSI_DPHY_PLL_CN_MAX; cnCur++)
0327         {
0328             /* REF_CLK / CN. */
0329             refClk_CN = refClkFreq_Hz / cnCur;
0330 
0331             /* If desired REF_CLK / CN frequency is too large, try larger CN value. */
0332             if (refClk_CN > DSI_DPHY_PLL_REFCLK_CN_MAX)
0333             {
0334                 continue;
0335             }
0336 
0337             /* If desired REF_CLK / CN frequency is too small, stop search. */
0338             if (refClk_CN < DSI_DPHY_PLL_REFCLK_CN_MIN)
0339             {
0340                 break;
0341             }
0342 
0343             /* Get the CM most close. */
0344             cmCur = (vcoFreq + (refClk_CN / 2U)) / refClk_CN;
0345 
0346             /* If calculated value is (DSI_DPHY_PLL_CM_MAX + 1), use DSI_DPHY_PLL_CM_MAX. */
0347             if ((DSI_DPHY_PLL_CM_MAX + 1U) == cmCur)
0348             {
0349                 cmCur = DSI_DPHY_PLL_CM_MAX;
0350             }
0351 
0352             if ((cmCur < DSI_DPHY_PLL_CM_MIN) || (cmCur > DSI_DPHY_PLL_CM_MAX))
0353             {
0354                 continue;
0355             }
0356 
0357             /* Output frequency using current dividers. */
0358             pllFreqCur = (refClk_CN * cmCur) >> coShiftCur;
0359 
0360             if (pllFreqCur > desiredOutFreq_Hz)
0361             {
0362                 diffCur = (pllFreqCur - desiredOutFreq_Hz);
0363             }
0364             else
0365             {
0366                 diffCur = (desiredOutFreq_Hz - pllFreqCur);
0367             }
0368 
0369             /* If the dividers is better. */
0370             if (diffCur < diff)
0371             {
0372                 diff             = diffCur;
0373                 *cm              = cmCur;
0374                 *cn              = cnCur;
0375                 *co              = coShiftCur;
0376                 pllFreqCandidate = pllFreqCur;
0377 
0378                 /* If the output PLL frequency is exactly the disired value, return directly. */
0379                 if (0U == diff)
0380                 {
0381                     break;
0382                 }
0383             }
0384         }
0385 
0386         /* If the output PLL frequency is exactly the disired value, return directly. */
0387         if (0U == diff)
0388         {
0389             break;
0390         }
0391     }
0392 
0393     return pllFreqCandidate;
0394 }
0395 #endif
0396 
0397 static void DSI_ApbClearRxFifo(const MIPI_DSI_Type *base)
0398 {
0399     volatile uint32_t dummy = 0U;
0400     uint32_t level          = base->apb->PKT_FIFO_RD_LEVEL;
0401 
0402     while (0U != (level--))
0403     {
0404         dummy = base->apb->PKT_RX_PAYLOAD;
0405     }
0406 
0407     (void)dummy;
0408 }
0409 
0410 /*!
0411  * brief Initializes an MIPI DSI host with the user configuration.
0412  *
0413  * This function initializes the MIPI DSI host with the configuration, it should
0414  * be called first before other MIPI DSI driver functions.
0415  *
0416  * param base MIPI DSI host peripheral base address.
0417  * param config Pointer to a user-defined configuration structure.
0418  */
0419 void DSI_Init(const MIPI_DSI_Type *base, const dsi_config_t *config)
0420 {
0421     assert(NULL != config);
0422 
0423 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
0424     (void)CLOCK_EnableClock(s_dsiClocks[DSI_GetInstance(base)]);
0425 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0426 
0427     DSI_HOST_Type *host = base->host;
0428 
0429 #if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
0430     MIPI_DSI_CSR_Type *csr = DSI_GET_CSR(base);
0431     if (config->enableTxUlps)
0432     {
0433         MIPI_DSI_CSR_ULPS_CTRL(csr) = MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK;
0434     }
0435     else
0436     {
0437         MIPI_DSI_CSR_ULPS_CTRL(csr) = 0U;
0438     }
0439 #endif
0440 
0441     host->CFG_NUM_LANES = config->numLanes - 1UL;
0442 
0443     if (config->enableNonContinuousHsClk)
0444     {
0445         host->CFG_NONCONTINUOUS_CLK = 0x01U;
0446     }
0447     else
0448     {
0449         host->CFG_NONCONTINUOUS_CLK = 0x00U;
0450     }
0451 
0452     if (config->autoInsertEoTp)
0453     {
0454         host->CFG_AUTOINSERT_EOTP = 0x01U;
0455     }
0456     else
0457     {
0458         host->CFG_AUTOINSERT_EOTP = 0x00U;
0459     }
0460 
0461     host->CFG_EXTRA_CMDS_AFTER_EOTP = config->numExtraEoTp;
0462     host->CFG_HTX_TO_COUNT          = config->htxTo_ByteClk;
0463     host->CFG_LRX_H_TO_COUNT        = config->lrxHostTo_ByteClk;
0464     host->CFG_BTA_H_TO_COUNT        = config->btaTo_ByteClk;
0465 
0466     DSI_ApbClearRxFifo(base);
0467 
0468     /* Disable all interrupts by default, user could enable
0469      * the desired interrupts later.
0470      */
0471     base->apb->IRQ_MASK  = 0xFFFFFFFFU;
0472     base->apb->IRQ_MASK2 = 0xFFFFFFFFU;
0473 }
0474 
0475 /*!
0476  * brief Deinitializes an MIPI DSI host.
0477  *
0478  * This function should be called after all bother MIPI DSI driver functions.
0479  *
0480  * param base MIPI DSI host peripheral base address.
0481  */
0482 void DSI_Deinit(const MIPI_DSI_Type *base)
0483 {
0484 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
0485     (void)CLOCK_DisableClock(s_dsiClocks[DSI_GetInstance(base)]);
0486 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0487 }
0488 
0489 /*!
0490  * brief Get the default configuration to initialize the MIPI DSI host.
0491  *
0492  * The default value is:
0493  * code
0494     config->numLanes = 4;
0495     config->enableNonContinuousHsClk = false;
0496     config->enableTxUlps = false;
0497     config->autoInsertEoTp = true;
0498     config->numExtraEoTp = 0;
0499     config->htxTo_ByteClk = 0;
0500     config->lrxHostTo_ByteClk = 0;
0501     config->btaTo_ByteClk = 0;
0502    endcode
0503  *
0504  * param config Pointer to a user-defined configuration structure.
0505  */
0506 void DSI_GetDefaultConfig(dsi_config_t *config)
0507 {
0508     assert(NULL != config);
0509 
0510     /* Initializes the configure structure to zero. */
0511     (void)memset(config, 0, sizeof(*config));
0512 
0513     config->numLanes                 = 4;
0514     config->enableNonContinuousHsClk = false;
0515     config->enableTxUlps             = false;
0516     config->autoInsertEoTp           = true;
0517     config->numExtraEoTp             = 0;
0518     config->htxTo_ByteClk            = 0;
0519     config->lrxHostTo_ByteClk        = 0;
0520     config->btaTo_ByteClk            = 0;
0521 }
0522 
0523 /*!
0524  * brief Configure the DPI interface core.
0525  *
0526  * This function sets the DPI interface configuration, it should be used in
0527  * video mode.
0528  *
0529  * param base MIPI DSI host peripheral base address.
0530  * param config Pointer to the DPI interface configuration.
0531  * param numLanes Lane number, should be same with the setting in ref dsi_dpi_config_t.
0532  * param dpiPixelClkFreq_Hz The DPI pixel clock frequency in Hz.
0533  * param dsiHsBitClkFreq_Hz The DSI high speed bit clock frequency in Hz. It is
0534  * the same with DPHY PLL output.
0535  */
0536 void DSI_SetDpiConfig(const MIPI_DSI_Type *base,
0537                       const dsi_dpi_config_t *config,
0538                       uint8_t numLanes,
0539                       uint32_t dpiPixelClkFreq_Hz,
0540                       uint32_t dsiHsBitClkFreq_Hz)
0541 {
0542     assert(NULL != config);
0543 
0544     /* coefficient DPI event size to number of DSI bytes. */
0545     uint32_t coff = (numLanes * dsiHsBitClkFreq_Hz) / (dpiPixelClkFreq_Hz * 8U);
0546 
0547     DSI_HOST_DPI_INTFC_Type *dpi = base->dpi;
0548 
0549 #if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
0550     MIPI_DSI_CSR_Type *csr    = DSI_GET_CSR(base);
0551     MIPI_DSI_CSR_PXL2DPI(csr) = (uint32_t)config->dpiColorCoding;
0552 #endif
0553 
0554     dpi->PIXEL_PAYLOAD_SIZE     = config->pixelPayloadSize;
0555     dpi->INTERFACE_COLOR_CODING = (uint32_t)config->dpiColorCoding;
0556     dpi->PIXEL_FORMAT           = (uint32_t)config->pixelPacket;
0557     dpi->VIDEO_MODE             = (uint32_t)config->videoMode;
0558 
0559     if (kDSI_DpiBllpLowPower == config->bllpMode)
0560     {
0561         dpi->BLLP_MODE         = 0x1U;
0562         dpi->USE_NULL_PKT_BLLP = 0x0U;
0563     }
0564     else if (kDSI_DpiBllpBlanking == config->bllpMode)
0565     {
0566         dpi->BLLP_MODE         = 0x0U;
0567         dpi->USE_NULL_PKT_BLLP = 0x0U;
0568     }
0569     else
0570     {
0571         dpi->BLLP_MODE         = 0x0U;
0572         dpi->USE_NULL_PKT_BLLP = 0x1U;
0573     }
0574 
0575     if (0U != (config->polarityFlags & (uint32_t)kDSI_DpiVsyncActiveHigh))
0576     {
0577         dpi->VSYNC_POLARITY = 0x01U;
0578     }
0579     else
0580     {
0581         dpi->VSYNC_POLARITY = 0x00U;
0582     }
0583 
0584     if (0U != (config->polarityFlags & (uint32_t)kDSI_DpiHsyncActiveHigh))
0585     {
0586         dpi->HSYNC_POLARITY = 0x01U;
0587     }
0588     else
0589     {
0590         dpi->HSYNC_POLARITY = 0x00U;
0591     }
0592 
0593     dpi->HFP                   = config->hfp * coff - DSI_HFP_OVERHEAD_BYTE;
0594     dpi->HBP                   = config->hbp * coff - DSI_HBP_OVERHEAD_BYTE;
0595     dpi->HSA                   = config->hsw * coff - DSI_HSA_OVERHEAD_BYTE;
0596     dpi->PIXEL_FIFO_SEND_LEVEL = config->pixelPayloadSize;
0597 
0598     dpi->VBP = config->vbp;
0599     dpi->VFP = config->vfp;
0600 
0601     dpi->VACTIVE = config->panelHeight - 1UL;
0602 
0603     /* TODO: Configure VC if it is available. */
0604 }
0605 
0606 /*!
0607  * brief Initializes the D-PHY
0608  *
0609  * This function configures the D-PHY timing and setups the D-PHY PLL based on
0610  * user configuration. The configuration structure could be got by the function
0611  * ref DSI_GetDphyDefaultConfig.
0612  *
0613  * param base MIPI DSI host peripheral base address.
0614  * param config Pointer to the D-PHY configuration.
0615  * param refClkFreq_Hz The REFCLK frequency in Hz.
0616  * return The actual D-PHY PLL output frequency. If could not configure the
0617  * PLL to the target frequency, the return value is 0.
0618  */
0619 uint32_t DSI_InitDphy(const MIPI_DSI_Type *base, const dsi_dphy_config_t *config, uint32_t refClkFreq_Hz)
0620 {
0621     assert(NULL != config);
0622 
0623     DSI_HOST_NXP_FDSOI28_DPHY_INTFC_Type *dphy = base->dphy;
0624     DSI_HOST_Type *host                        = base->host;
0625 
0626 #if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
0627     uint32_t cn;
0628     uint32_t cm;
0629     uint32_t co;
0630     uint32_t outputPllFreq;
0631 
0632     outputPllFreq = DSI_DphyGetPllDivider(&cn, &cm, &co, refClkFreq_Hz, config->txHsBitClk_Hz);
0633 
0634     /* If could not find dividers for the output PLL frequency. */
0635     if (0U == outputPllFreq)
0636     {
0637         return 0U;
0638     }
0639 
0640     /* Set the DPHY parameters. */
0641     dphy->CN = (uint32_t)DSI_EncodeDphyPllCn((uint8_t)cn);
0642     dphy->CM = (uint32_t)DSI_EncodeDphyPllCm((uint8_t)cm);
0643     dphy->CO = co;
0644 #endif
0645 
0646     /* Set the timing parameters. */
0647     dphy->M_PRG_HS_PREPARE  = (uint32_t)config->tHsPrepare_HalfEscClk - DSI_THS_PREPARE_HALF_ESC_CLK_BASE;
0648     dphy->MC_PRG_HS_PREPARE = (uint32_t)config->tClkPrepare_HalfEscClk - DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE;
0649     dphy->M_PRG_HS_ZERO     = (uint32_t)config->tHsZero_ByteClk - DSI_THS_ZERO_BYTE_CLK_BASE;
0650     dphy->MC_PRG_HS_ZERO    = (uint32_t)config->tClkZero_ByteClk - DSI_TCLK_ZERO_BYTE_CLK_BASE;
0651     dphy->M_PRG_HS_TRAIL    = config->tHsTrail_ByteClk;
0652     dphy->MC_PRG_HS_TRAIL   = config->tClkTrail_ByteClk;
0653 
0654     host->CFG_T_PRE   = config->tClkPre_ByteClk;
0655     host->CFG_T_POST  = config->tClkPost_ByteClk;
0656     host->CFG_TX_GAP  = config->tHsExit_ByteClk;
0657     host->CFG_TWAKEUP = config->tWakeup_EscClk;
0658 
0659 #if defined(MIPI_RTERM_SEL_dphy_rterm_sel_MASK)
0660     dphy->RTERM_SEL = MIPI_RTERM_SEL_dphy_rterm_sel_MASK;
0661 #endif
0662 #if defined(MIPI_TX_RCAL_dphy_tx_rcal_MASK)
0663     dphy->TX_RCAL = 1;
0664 #endif
0665     dphy->RXLPRP = 1;
0666     dphy->RXCDRP = 1;
0667 
0668     /* Auto power down the inactive lanes. */
0669     dphy->AUTO_PD_EN = 0x1U;
0670 
0671     dphy->TST = 0x25U;
0672 
0673 #if !((defined(FSL_FEATURE_MIPI_NO_PLL) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_PLL)))
0674     /* Power up the PLL. */
0675     dphy->PD_PLL = 0U;
0676 
0677     /* Wait for the PLL lock. */
0678     while (0UL == dphy->LOCK)
0679     {
0680     }
0681 #endif
0682 
0683     /* Power up the DPHY. */
0684     dphy->PD_TX = 0U;
0685 
0686 #if !((defined(FSL_FEATURE_MIPI_NO_PLL) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_PLL)))
0687     return outputPllFreq;
0688 #else
0689     return config->txHsBitClk_Hz;
0690 #endif
0691 }
0692 
0693 /*!
0694  * brief Deinitializes the D-PHY
0695  *
0696  * Power down the D-PHY PLL and shut down D-PHY.
0697  *
0698  * param base MIPI DSI host peripheral base address.
0699  */
0700 void DSI_DeinitDphy(const MIPI_DSI_Type *base)
0701 {
0702 #if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
0703     /* Power down the PLL. */
0704     base->dphy->PD_PLL = 1U;
0705 #endif
0706 
0707     /* Power down the DPHY. */
0708     base->dphy->PD_TX = 1U;
0709 }
0710 
0711 /*!
0712  * brief Get the default D-PHY configuration.
0713  *
0714  * Gets the default D-PHY configuration, the timing parameters are set according
0715  * to D-PHY specification. User could use the configuration directly, or change
0716  * some parameters according to the special device.
0717  *
0718  * param config Pointer to the D-PHY configuration.
0719  * param txHsBitClk_Hz High speed bit clock in Hz.
0720  * param txEscClk_Hz Esc clock in Hz.
0721  */
0722 void DSI_GetDphyDefaultConfig(dsi_dphy_config_t *config, uint32_t txHsBitClk_Hz, uint32_t txEscClk_Hz)
0723 {
0724     assert(NULL != config);
0725 
0726     /* Initializes the configure structure to zero. */
0727     (void)memset(config, 0, sizeof(*config));
0728 
0729     uint32_t byteClkFreq_kHz = txHsBitClk_Hz / 8U / 1000U;
0730     uint32_t txEscClk_kHz    = txEscClk_Hz / 1000U;
0731 
0732     config->txHsBitClk_Hz = txHsBitClk_Hz;
0733 
0734     /* THS-EXIT in byte clock. At least 100ns. */
0735     config->tHsExit_ByteClk = (uint8_t)(DSI_NsToByteClk(100U, byteClkFreq_kHz) + 1U);
0736 
0737     /* T-WAKEUP. At least 1ms. */
0738     config->tWakeup_EscClk = (txEscClk_Hz / 1000U) + 1U;
0739 
0740     /* THS-PREPARE. 40ns+4*UI to 85ns+6*UI. */
0741     config->tHsPrepare_HalfEscClk =
0742         (uint8_t)(((40U * txEscClk_kHz * 2U) / 1000000U) + (4U * txEscClk_Hz * 2U / txHsBitClk_Hz) + 1U);
0743     if (config->tHsPrepare_HalfEscClk < DSI_THS_PREPARE_HALF_ESC_CLK_MIN)
0744     {
0745         config->tHsPrepare_HalfEscClk = DSI_THS_PREPARE_HALF_ESC_CLK_MIN;
0746     }
0747     else if (config->tHsPrepare_HalfEscClk > DSI_THS_PREPARE_HALF_ESC_CLK_MAX)
0748     {
0749         config->tHsPrepare_HalfEscClk = DSI_THS_PREPARE_HALF_ESC_CLK_MAX;
0750     }
0751     else
0752     {
0753         /* For MISRA check. */
0754     }
0755 
0756     /* TCLK-PREPARE. 38ns to 95ns. */
0757     config->tClkPrepare_HalfEscClk = (uint8_t)((38U * txEscClk_kHz * 2U) / 1000000U + 1U);
0758     if (config->tClkPrepare_HalfEscClk < DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN)
0759     {
0760         config->tClkPrepare_HalfEscClk = DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN;
0761     }
0762     else if (config->tClkPrepare_HalfEscClk > DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX)
0763     {
0764         config->tClkPrepare_HalfEscClk = DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX;
0765     }
0766     else
0767     {
0768         /* For MISRA check. */
0769     }
0770 
0771     /* THS-ZERO, At least 105ns+6*UI. */
0772     config->tHsZero_ByteClk = (uint8_t)(DSI_NsUiToByteClk(105U, 6U, byteClkFreq_kHz) + 1U);
0773     if (config->tHsZero_ByteClk < DSI_THS_ZERO_BYTE_CLK_BASE)
0774     {
0775         config->tHsZero_ByteClk = DSI_THS_ZERO_BYTE_CLK_BASE;
0776     }
0777 
0778     /* TCLK-ZERO, At least 262ns. */
0779     config->tClkZero_ByteClk = (uint8_t)(DSI_NsToByteClk(262U, byteClkFreq_kHz) + 1U);
0780     if (config->tClkZero_ByteClk < DSI_TCLK_ZERO_BYTE_CLK_BASE)
0781     {
0782         config->tClkZero_ByteClk = DSI_TCLK_ZERO_BYTE_CLK_BASE;
0783     }
0784 
0785     /* THS-TRAIL, 60ns+4*UI to 105ns+12UI. */
0786     /* Due to IP design, extra 4*UI should be added. */
0787     config->tHsTrail_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 8U, byteClkFreq_kHz) + 1U);
0788 
0789     /* TCLK-TRAIL, at least 60ns. */
0790     /* Due to IP design, extra 4*UI should be added. */
0791     config->tClkTrail_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 4U, byteClkFreq_kHz) + 1U);
0792 
0793     /*
0794      * T_LPX + T_CLK-PREPARE + T_CLK-ZERO + T_CLK-PRE
0795      * T_LPX >= 50ns
0796      * T_CLK-PREPARE >= 38ns
0797      * T_CLK-ZERO >= 262ns
0798      * T_CLK-PRE >= 8*UI
0799      */
0800     config->tClkPre_ByteClk = (uint8_t)(DSI_NsUiToByteClk(88U, 8U, byteClkFreq_kHz) + 1U) + config->tClkZero_ByteClk;
0801 
0802     /*
0803      * T_CLK-POST + T_CLK-TRAIL
0804      * T_CLK-POST >= 60ns + 52*UI.
0805      * T_CLK-TRAIL >= 60ns
0806      */
0807     config->tClkPost_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 52U, byteClkFreq_kHz) + 1U) + config->tClkTrail_ByteClk;
0808 }
0809 
0810 /*!
0811  * brief Configure the APB packet to send.
0812  *
0813  * This function configures the next APB packet transfer. After configuration,
0814  * the packet transfer could be started with function ref DSI_SendApbPacket.
0815  * If the packet is long packet, Use ref DSI_WriteApbTxPayload to fill the payload
0816  * before start transfer.
0817  *
0818  * param base MIPI DSI host peripheral base address.
0819  * param wordCount For long packet, this is the byte count of the payload.
0820  * For short packet, this is (data1 << 8) | data0.
0821  * param virtualChannel Virtual channel.
0822  * param dataType The packet data type, (DI).
0823  * param flags The transfer control flags, see ref _dsi_transfer_flags.
0824  */
0825 void DSI_SetApbPacketControl(
0826     const MIPI_DSI_Type *base, uint16_t wordCount, uint8_t virtualChannel, dsi_tx_data_type_t dataType, uint8_t flags)
0827 {
0828     uint32_t pktCtrl = PKT_CONTROL_WORD_COUNT(wordCount) | PKT_CONTROL_HEADER_TYPE(dataType);
0829 
0830 #if defined(DSI_HOST_PKT_CONTROL_VC)
0831     pktCtrl |= (uint32_t)DSI_HOST_PKT_CONTROL_VC(virtualChannel);
0832 #endif
0833 
0834     if (0U != (flags & (uint8_t)kDSI_TransferUseHighSpeed))
0835     {
0836         pktCtrl |= PKT_CONTROL_HS_MASK;
0837     }
0838 
0839     if (0U != (flags & (uint8_t)kDSI_TransferPerformBTA))
0840     {
0841         pktCtrl |= PKT_CONTROL_BTA_MASK;
0842     }
0843 
0844     base->apb->PKT_CONTROL = pktCtrl;
0845 }
0846 
0847 /*!
0848  * brief Fill the long APB packet payload.
0849  *
0850  * Write the long packet payload to TX FIFO.
0851  *
0852  * param base MIPI DSI host peripheral base address.
0853  * param payload Pointer to the payload.
0854  * param payloadSize Payload size in byte.
0855  */
0856 void DSI_WriteApbTxPayload(const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize)
0857 {
0858     DSI_WriteApbTxPayloadExt(base, payload, payloadSize, false, 0U);
0859 }
0860 
0861 void DSI_WriteApbTxPayloadExt(
0862     const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize, bool sendDscCmd, uint8_t dscCmd)
0863 {
0864     uint32_t firstWord;
0865     uint16_t i;
0866     uint16_t payloadSizeLocal   = payloadSize;
0867     const uint8_t *payloadLocal = payload;
0868 
0869     DSI_HOST_APB_PKT_IF_Type *apb = base->apb;
0870 
0871     if (sendDscCmd)
0872     {
0873         payloadSizeLocal += 1U;
0874     }
0875 
0876     assert(payloadSizeLocal <= FSL_DSI_TX_MAX_PAYLOAD_BYTE);
0877 
0878     /* The first 4-byte. */
0879     if (sendDscCmd)
0880     {
0881         firstWord = dscCmd;
0882     }
0883     else
0884     {
0885         firstWord = *payloadLocal;
0886         payloadLocal++;
0887     }
0888 
0889     payloadSizeLocal--;
0890 
0891     for (i = 1U; i < 4U; i++)
0892     {
0893         if (payloadSizeLocal > 0U)
0894         {
0895             firstWord |= ((uint32_t)(*payloadLocal) << (i << 3U));
0896             payloadLocal++;
0897             payloadSizeLocal--;
0898         }
0899         else
0900         {
0901             break;
0902         }
0903     }
0904 
0905     apb->TX_PAYLOAD = firstWord;
0906 
0907     /* Write the payloadLocal to the FIFO. */
0908     for (i = 0; i < (payloadSizeLocal / 4U); i++)
0909     {
0910         apb->TX_PAYLOAD = ((uint32_t)payloadLocal[3] << 24U) | ((uint32_t)payloadLocal[2] << 16U) |
0911                           ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
0912         payloadLocal = &payloadLocal[4];
0913     }
0914 
0915     /* Write the remaining data. */
0916     switch (payloadSizeLocal & 0x03U)
0917     {
0918         case 3:
0919             apb->TX_PAYLOAD = ((uint32_t)payloadLocal[2] << 16U) | ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
0920             break;
0921         case 2:
0922             apb->TX_PAYLOAD = ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
0923             break;
0924         case 1:
0925             apb->TX_PAYLOAD = payloadLocal[0];
0926             break;
0927         default:
0928             /* For MISRA 2012 16.4 */
0929             break;
0930     }
0931 }
0932 
0933 static status_t DSI_PrepareApbTransfer(const MIPI_DSI_Type *base, dsi_transfer_t *xfer)
0934 {
0935     /* The receive data size should be smaller than the RX FIRO. */
0936     assert(xfer->rxDataSize <= FSL_DSI_RX_MAX_PAYLOAD_BYTE);
0937     assert(xfer->txDataSize <= FSL_DSI_TX_MAX_PAYLOAD_BYTE);
0938 
0939     uint8_t txDataIndex;
0940     uint16_t wordCount;
0941     uint32_t intFlags1;
0942     uint32_t intFlags2;
0943     uint32_t txDataSize;
0944 
0945     status_t status;
0946 
0947     if (xfer->rxDataSize > FSL_DSI_RX_MAX_PAYLOAD_BYTE)
0948     {
0949         status = kStatus_DSI_NotSupported;
0950     }
0951     else
0952     {
0953         if (xfer->rxDataSize != 0U)
0954         {
0955             xfer->flags |= (uint8_t)kDSI_TransferPerformBTA;
0956         }
0957 
0958         /* ========================== Prepare TX. ========================== */
0959         /* If xfer->sendDscCmd is true, then the DSC command is not included in the
0960            xfer->txData, but specified by xfer->dscCmd.
0961          */
0962         if (xfer->sendDscCmd)
0963         {
0964             txDataSize = (uint32_t)xfer->txDataSize + 1U;
0965         }
0966         else
0967         {
0968             txDataSize = (uint32_t)xfer->txDataSize;
0969         }
0970 
0971         /* Short packet. */
0972         if (txDataSize <= 2U)
0973         {
0974             if (0U == txDataSize)
0975             {
0976                 wordCount = 0U;
0977             }
0978             else
0979             {
0980                 txDataIndex = 0;
0981 
0982                 if (xfer->sendDscCmd)
0983                 {
0984                     wordCount = xfer->dscCmd;
0985                 }
0986                 else
0987                 {
0988                     wordCount = xfer->txData[txDataIndex++];
0989                 }
0990 
0991                 if (2U == txDataSize)
0992                 {
0993                     wordCount |= ((uint16_t)xfer->txData[txDataIndex] << 8U);
0994                 }
0995             }
0996         }
0997         /* Long packet. */
0998         else
0999         {
1000             wordCount = (uint16_t)txDataSize;
1001             DSI_WriteApbTxPayloadExt(base, xfer->txData, xfer->txDataSize, xfer->sendDscCmd, xfer->dscCmd);
1002         }
1003 
1004         DSI_SetApbPacketControl(base, wordCount, xfer->virtualChannel, xfer->txDataType, xfer->flags);
1005 
1006         /* Clear the interrupt flags set by previous transfer. */
1007         DSI_GetAndClearInterruptStatus(base, &intFlags1, &intFlags2);
1008 
1009         status = kStatus_Success;
1010     }
1011 
1012     return status;
1013 }
1014 
1015 /*!
1016  * brief Read the long APB packet payload.
1017  *
1018  * Read the long packet payload from RX FIFO. This function reads directly but
1019  * does not check the RX FIFO status. Upper layer should make sure there are
1020  * available data.
1021  *
1022  * param base MIPI DSI host peripheral base address.
1023  * param payload Pointer to the payload.
1024  * param payloadSize Payload size in byte.
1025  */
1026 void DSI_ReadApbRxPayload(const MIPI_DSI_Type *base, uint8_t *payload, uint16_t payloadSize)
1027 {
1028     uint32_t tmp;
1029     uint16_t i;
1030     uint8_t *payloadLocal = payload;
1031 
1032     for (i = 0; i < payloadSize / 4U; i++)
1033     {
1034         tmp             = base->apb->PKT_RX_PAYLOAD;
1035         payloadLocal[0] = (uint8_t)(tmp & 0xFFU);
1036         payloadLocal[1] = (uint8_t)((tmp >> 8U) & 0xFFU);
1037         payloadLocal[2] = (uint8_t)((tmp >> 16U) & 0xFFU);
1038         payloadLocal[3] = (uint8_t)((tmp >> 24U) & 0xFFU);
1039         payloadLocal    = &payloadLocal[4];
1040     }
1041 
1042     /* Read out the remaining data. */
1043     if (0U != (payloadSize & 0x03U))
1044     {
1045         tmp = base->apb->PKT_RX_PAYLOAD;
1046 
1047         for (i = 0; i < (payloadSize & 0x3U); i++)
1048         {
1049             payloadLocal[i] = (uint8_t)(tmp & 0xFFU);
1050             tmp >>= 8U;
1051         }
1052     }
1053 }
1054 
1055 /*!
1056  * brief APB data transfer using blocking method.
1057  *
1058  * Perform APB data transfer using blocking method. This function waits until all
1059  * data send or received, or timeout happens.
1060  *
1061  * param base MIPI DSI host peripheral base address.
1062  * param xfer Pointer to the transfer structure.
1063  * retval kStatus_Success Data transfer finished with no error.
1064  * retval kStatus_Timeout Transfer failed because of timeout.
1065  * retval kStatus_DSI_RxDataError RX data error, user could use ref DSI_GetRxErrorStatus
1066  * to check the error details.
1067  * retval kStatus_DSI_ErrorReportReceived Error Report packet received, user could use
1068  *        ref DSI_GetAndClearHostStatus to check the error report status.
1069  * retval kStatus_DSI_NotSupported Transfer format not supported.
1070  * retval kStatus_DSI_Fail Transfer failed for other reasons.
1071  */
1072 status_t DSI_TransferBlocking(const MIPI_DSI_Type *base, dsi_transfer_t *xfer)
1073 {
1074     status_t status;
1075     uint32_t intFlags1Old;
1076     uint32_t intFlags2Old;
1077     uint32_t intFlags1New;
1078     uint32_t intFlags2New;
1079 
1080     DSI_HOST_APB_PKT_IF_Type *apb = base->apb;
1081 
1082     /* Wait for the APB state idle. */
1083     while (0U != (apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
1084     {
1085     }
1086 
1087     status = DSI_PrepareApbTransfer(base, xfer);
1088 
1089     if (kStatus_Success == status)
1090     {
1091         DSI_SendApbPacket(base);
1092 
1093         /* Make sure the transfer is started. */
1094         while (true)
1095         {
1096             DSI_GetAndClearInterruptStatus(base, &intFlags1Old, &intFlags2Old);
1097 
1098             if (0U != (intFlags1Old & (uint32_t)kDSI_InterruptGroup1ApbNotIdle))
1099             {
1100                 break;
1101             }
1102         }
1103 
1104         /* Wait for transfer finished. */
1105         while (true)
1106         {
1107             /* Transfer completed. */
1108             if (0U == (apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
1109             {
1110                 break;
1111             }
1112 
1113             /* Time out. */
1114             if (0U != (base->host->RX_ERROR_STATUS &
1115                        ((uint32_t)kDSI_RxErrorHtxTo | (uint32_t)kDSI_RxErrorLrxTo | (uint32_t)kDSI_RxErrorBtaTo)))
1116             {
1117                 status = kStatus_Timeout;
1118                 break;
1119             }
1120         }
1121 
1122         DSI_GetAndClearInterruptStatus(base, &intFlags1New, &intFlags2New);
1123 
1124         if (kStatus_Success == status)
1125         {
1126             status = DSI_HandleResult(base, intFlags1Old | intFlags1New, intFlags2Old | intFlags2New, xfer);
1127         }
1128     }
1129 
1130     return status;
1131 }
1132 
1133 static status_t DSI_HandleResult(const MIPI_DSI_Type *base,
1134                                  uint32_t intFlags1,
1135                                  uint32_t intFlags2,
1136                                  dsi_transfer_t *xfer)
1137 {
1138     uint32_t rxPktHeader;
1139     uint16_t actualRxByteCount;
1140     dsi_rx_data_type_t rxDataType;
1141     bool readRxDataFromPayload;
1142 
1143     /* If hardware detect timeout. */
1144     if (0U != (((uint32_t)kDSI_InterruptGroup1HtxTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
1145                 (uint32_t)kDSI_InterruptGroup1BtaTo) &
1146                intFlags1))
1147     {
1148         return kStatus_Timeout;
1149     }
1150 
1151     /* If received data error. */
1152     if (0U != (((uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError) & intFlags2))
1153     {
1154         return kStatus_DSI_RxDataError;
1155     }
1156 
1157     /* If BTA is performed. */
1158     if (0U != (xfer->flags & (uint32_t)kDSI_TransferPerformBTA))
1159     {
1160         if (0U != (intFlags1 & DSI_INT_STATUS_ERROR_REPORT_MASK))
1161         {
1162             return kStatus_DSI_ErrorReportReceived;
1163         }
1164 
1165         if (0U != ((uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived & intFlags1))
1166         {
1167             rxPktHeader = DSI_GetRxPacketHeader(base);
1168             rxDataType  = DSI_GetRxPacketType(rxPktHeader);
1169 
1170             /* If received error report. */
1171             if (kDSI_RxDataAckAndErrorReport == rxDataType)
1172             {
1173                 return kStatus_DSI_ErrorReportReceived;
1174             }
1175             else
1176             {
1177                 if ((kDSI_RxDataGenShortRdResponseOneByte == rxDataType) ||
1178                     (kDSI_RxDataDcsShortRdResponseOneByte == rxDataType))
1179                 {
1180                     readRxDataFromPayload = false;
1181                     actualRxByteCount     = 1U;
1182                 }
1183                 else if ((kDSI_RxDataGenShortRdResponseTwoByte == rxDataType) ||
1184                          (kDSI_RxDataDcsShortRdResponseTwoByte == rxDataType))
1185                 {
1186                     readRxDataFromPayload = false;
1187                     actualRxByteCount     = 2U;
1188                 }
1189                 else if ((kDSI_RxDataGenLongRdResponse == rxDataType) || (kDSI_RxDataDcsLongRdResponse == rxDataType))
1190                 {
1191                     readRxDataFromPayload = true;
1192                     actualRxByteCount     = DSI_GetRxPacketWordCount(rxPktHeader);
1193                 }
1194                 else
1195                 {
1196                     readRxDataFromPayload = false;
1197                     xfer->rxDataSize      = 0U;
1198                     actualRxByteCount     = 0U;
1199                 }
1200 
1201                 xfer->rxDataSize = MIN(xfer->rxDataSize, actualRxByteCount);
1202 
1203                 if (xfer->rxDataSize > 0U)
1204                 {
1205                     if (readRxDataFromPayload)
1206                     {
1207                         DSI_ReadApbRxPayload(base, xfer->rxData, xfer->rxDataSize);
1208                     }
1209                     else
1210                     {
1211                         xfer->rxData[0] = (uint8_t)(rxPktHeader & 0xFFU);
1212 
1213                         if (2U == xfer->rxDataSize)
1214                         {
1215                             xfer->rxData[1] = (uint8_t)((rxPktHeader >> 8U) & 0xFFU);
1216                         }
1217                     }
1218                 }
1219 
1220                 return kStatus_Success;
1221             }
1222         }
1223 
1224         return kStatus_Success;
1225     }
1226     else
1227     {
1228         /* Tx Done. */
1229         if (0U != ((uint32_t)kDSI_InterruptGroup1ApbTxDone & intFlags1))
1230         {
1231             return kStatus_Success;
1232         }
1233     }
1234 
1235     return kStatus_Fail;
1236 }
1237 
1238 /*!
1239  * brief Create the MIPI DSI handle.
1240  *
1241  * This function initializes the MIPI DSI handle which can be used for other transactional APIs.
1242  *
1243  * param base MIPI DSI host peripheral base address.
1244  * param handle Handle pointer.
1245  * param callback Callback function.
1246  * param userData User data.
1247  */
1248 status_t DSI_TransferCreateHandle(const MIPI_DSI_Type *base,
1249                                   dsi_handle_t *handle,
1250                                   dsi_callback_t callback,
1251                                   void *userData)
1252 {
1253     assert(NULL != handle);
1254 
1255     uint32_t instance = DSI_GetInstance(base);
1256 
1257     /* Zero the handle */
1258     (void)memset(handle, 0, sizeof(*handle));
1259 
1260     /* Initialize the handle */
1261     s_dsiHandle[instance] = handle;
1262     handle->callback      = callback;
1263     handle->userData      = userData;
1264     handle->isBusy        = false;
1265     handle->dsi           = base;
1266     s_dsiIsr              = DSI_TransferHandleIRQ;
1267 
1268 #if defined(DSI_HOST_DSI_IRQS)
1269     /* Enable interrupt in NVIC. */
1270     (void)EnableIRQ(s_dsiIRQ[instance]);
1271 #endif
1272 
1273     return kStatus_Success;
1274 }
1275 
1276 /*!
1277  * brief APB data transfer using interrupt method.
1278  *
1279  * Perform APB data transfer using interrupt method, when transfer finished,
1280  * upper layer could be informed through callback function.
1281  *
1282  * param base MIPI DSI host peripheral base address.
1283  * param handle pointer to dsi_handle_t structure which stores the transfer state.
1284  * param xfer Pointer to the transfer structure.
1285  *
1286  * retval kStatus_Success Data transfer started successfully.
1287  * retval kStatus_DSI_Busy Failed to start transfer because DSI is busy with pervious transfer.
1288  * retval kStatus_DSI_NotSupported Transfer format not supported.
1289  */
1290 status_t DSI_TransferNonBlocking(const MIPI_DSI_Type *base, dsi_handle_t *handle, dsi_transfer_t *xfer)
1291 {
1292     status_t status;
1293 
1294     if (handle->isBusy)
1295     {
1296         status = kStatus_DSI_Busy;
1297     }
1298     else if (0U != (base->apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
1299     {
1300         status = kStatus_DSI_Busy;
1301     }
1302     else
1303     {
1304         handle->xfer = *xfer;
1305 
1306         status = DSI_PrepareApbTransfer(base, &handle->xfer);
1307 
1308         if (kStatus_Success == status)
1309         {
1310             DSI_SendApbPacket(base);
1311             handle->isBusy = true;
1312 
1313             /* Enable the interrupts. */
1314             if (0U != (handle->xfer.flags & (uint32_t)kDSI_TransferPerformBTA))
1315             {
1316                 DSI_EnableInterrupts(
1317                     base,
1318                     DSI_INT_STATUS_TRIGGER_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
1319                         (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived | (uint32_t)kDSI_InterruptGroup1BtaTo |
1320                         (uint32_t)kDSI_InterruptGroup1LrxTo | (uint32_t)kDSI_InterruptGroup1HtxTo |
1321                         (uint32_t)kDSI_InterruptGroup1AckTriggerReceived,
1322                     (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
1323             }
1324             else
1325             {
1326                 DSI_EnableInterrupts(base,
1327                                      (uint32_t)kDSI_InterruptGroup1ApbTxDone | (uint32_t)kDSI_InterruptGroup1HtxTo, 0U);
1328             }
1329         }
1330     }
1331 
1332     return status;
1333 }
1334 
1335 /*!
1336  * brief Abort current APB data transfer.
1337  *
1338  * param base MIPI DSI host peripheral base address.
1339  * param handle pointer to dsi_handle_t structure which stores the transfer state.
1340  */
1341 void DSI_TransferAbort(const MIPI_DSI_Type *base, dsi_handle_t *handle)
1342 {
1343     assert(NULL != handle);
1344 
1345     if (handle->isBusy)
1346     {
1347         /* Disable the interrupts. */
1348         DSI_DisableInterrupts(base,
1349                               (uint32_t)kDSI_InterruptGroup1ApbTxDone | DSI_INT_STATUS_TRIGGER_MASK |
1350                                   DSI_INT_STATUS_ERROR_REPORT_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
1351                                   (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived |
1352                                   (uint32_t)kDSI_InterruptGroup1BtaTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
1353                                   (uint32_t)kDSI_InterruptGroup1HtxTo,
1354                               (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
1355 
1356         /* Reset transfer info. */
1357         (void)memset(&handle->xfer, 0, sizeof(handle->xfer));
1358 
1359         /* Reset the state to idle. */
1360         handle->isBusy = false;
1361     }
1362 }
1363 
1364 /*!
1365  * brief Interrupt handler for the DSI.
1366  *
1367  * param base MIPI DSI host peripheral base address.
1368  * param handle pointer to dsi_handle_t structure which stores the transfer state.
1369  */
1370 void DSI_TransferHandleIRQ(const MIPI_DSI_Type *base, dsi_handle_t *handle)
1371 {
1372     assert(NULL != handle);
1373 
1374     status_t status;
1375     uint32_t intFlags1;
1376     uint32_t intFlags2;
1377     uint32_t timeout;
1378     const MIPI_DSI_Type *dsi = handle->dsi;
1379 
1380     /* If no transfer in progress, return directly. */
1381     if (handle->isBusy)
1382     {
1383         /* Make sure the transfer is completed. */
1384         timeout = FSL_MIPI_DSI_IDLE_TIMEOUT;
1385         while (0U != (timeout--))
1386         {
1387             if (0U == (dsi->apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
1388             {
1389                 break;
1390             }
1391         }
1392 
1393         if (0U == timeout)
1394         {
1395             DSI_TransferAbort(dsi, handle);
1396             status = kStatus_Timeout;
1397         }
1398         else
1399         {
1400             /* Disable the interrupts. */
1401             DSI_DisableInterrupts(
1402                 dsi,
1403                 (uint32_t)kDSI_InterruptGroup1ApbTxDone | DSI_INT_STATUS_TRIGGER_MASK |
1404                     DSI_INT_STATUS_ERROR_REPORT_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
1405                     (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived | (uint32_t)kDSI_InterruptGroup1BtaTo |
1406                     (uint32_t)kDSI_InterruptGroup1LrxTo | (uint32_t)kDSI_InterruptGroup1HtxTo,
1407                 (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
1408 
1409             DSI_GetAndClearInterruptStatus(dsi, &intFlags1, &intFlags2);
1410 
1411             status         = DSI_HandleResult(dsi, intFlags1, intFlags2, &handle->xfer);
1412             handle->isBusy = false;
1413         }
1414 
1415         if (NULL != handle->callback)
1416         {
1417             handle->callback(dsi, handle, status, handle->userData);
1418         }
1419     }
1420 
1421     return;
1422 }
1423 
1424 #if defined(DSI_HOST)
1425 void MIPI_DSI_DriverIRQHandler(void);
1426 void MIPI_DSI_DriverIRQHandler(void)
1427 {
1428     /* The first parameter is not used, use the peripheral address defined in
1429      * handle.
1430      */
1431     s_dsiIsr(NULL, s_dsiHandle[0]);
1432 }
1433 #endif