summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c')
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c1433
1 files changed, 1433 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c
new file mode 100644
index 0000000000..7973e38b9b
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/mipi_dsi_split/fsl_mipi_dsi.c
@@ -0,0 +1,1433 @@
+/*
+ * Copyright 2020-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_mipi_dsi.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.mipi_dsi_split"
+#endif
+
+/* The timeout cycles to wait for DSI state machine idle. */
+#ifndef FSL_MIPI_DSI_IDLE_TIMEOUT
+#define FSL_MIPI_DSI_IDLE_TIMEOUT 0x1000U
+#endif
+
+/* PLL CN should be in the range of 1 to 32. */
+#define DSI_DPHY_PLL_CN_MIN 1U
+#define DSI_DPHY_PLL_CN_MAX 32U
+
+/* PLL refClk / CN should be in the range of 24M to 30M. */
+#define DSI_DPHY_PLL_REFCLK_CN_MIN 24000000U
+#define DSI_DPHY_PLL_REFCLK_CN_MAX 30000000U
+
+/* PLL CM should be in the range of 16 to 255. */
+#define DSI_DPHY_PLL_CM_MIN 16U
+#define DSI_DPHY_PLL_CM_MAX 255U
+
+/* PLL VCO output frequency max value is 1.5GHz, VCO output is (refClk / CN ) * CM. */
+#define DSI_DPHY_PLL_VCO_MAX 1500000000U
+#define DSI_DPHY_PLL_VCO_MIN (DSI_DPHY_PLL_REFCLK_CN_MIN * DSI_DPHY_PLL_CM_MIN)
+
+#define PKT_CONTROL_WORD_COUNT(wc) ((uint32_t)(wc) << 0U)
+#define PKT_CONTROL_VC(vc) ((uint32_t)(vc) << 16U)
+#define PKT_CONTROL_HEADER_TYPE(ht) ((uint32_t)(ht) << 18U)
+#define PKT_CONTROL_HS_MASK (1UL << 24U)
+#define PKT_CONTROL_BTA_MASK (1UL << 25U)
+#define PKT_CONTROL_BTA_ONLY_MASK (1UL << 26U)
+
+/* Macro used for D-PHY timing setting. */
+#define DSI_THS_ZERO_BYTE_CLK_BASE 6U
+#define DSI_TCLK_ZERO_BYTE_CLK_BASE 3U
+#define DSI_THS_PREPARE_HALF_ESC_CLK_BASE 2U
+#define DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE 2U
+
+#define DSI_THS_PREPARE_HALF_ESC_CLK_MIN (DSI_THS_PREPARE_HALF_ESC_CLK_BASE)
+#define DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN (DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE)
+
+#define DSI_THS_PREPARE_HALF_ESC_CLK_MAX (5U)
+#define DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX (3U)
+
+/* Convert ns to byte clock. */
+#define DSI_NS_TO_BYTE_CLK(ns, byte_clk_khz) ((ns) * (byte_clk_khz) / 1000000U)
+/* Convert ns+UI to byte clock. */
+#define DSI_NS_UI_TO_BYTE_CLK(ns, UI, byte_clk_khz) ((((ns) * (byte_clk_khz)) + ((UI)*125000U)) / 1000000U)
+
+/* Packet overhead for HSA, HFP, HBP */
+#define DSI_HSA_OVERHEAD_BYTE 10UL /* HSS + HSA header + HSA CRC. */
+#define DSI_HFP_OVERHEAD_BYTE 12UL /* RGB data packet CRC + HFP header + HFP CRC. */
+#define DSI_HBP_OVERHEAD_BYTE 10UL /* HSE + HBP header + HBP CRC + RGB data packet header */
+
+#define DSI_INT_STATUS_TRIGGER_MASK \
+ ((uint32_t)kDSI_InterruptGroup1ResetTriggerReceived | (uint32_t)kDSI_InterruptGroup1TearTriggerReceived | \
+ (uint32_t)kDSI_InterruptGroup1AckTriggerReceived)
+#define DSI_INT_STATUS_ERROR_REPORT_MASK (0xFFFFU << 9U)
+
+#if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
+#if (defined(FSL_FEATURE_LDB_COMBO_PHY) && (0 != FSL_FEATURE_LDB_COMBO_PHY))
+typedef MIPI_DSI_LVDS_COMBO_CSR_Type MIPI_DSI_CSR_Type;
+#define MIPI_DSI_CSR_ULPS_CTRL(csr) ((csr)->ULPS_CTRL)
+#define MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK MIPI_DSI_LVDS_COMBO_CSR_ULPS_CTRL_TX_ULPS_MASK
+#define MIPI_DSI_CSR_PXL2DPI(csr) ((csr)->PXL2DPI_CTRL)
+#else
+#define MIPI_DSI_CSR_ULPS_CTRL(csr) ((csr)->TX_ULPS_ENABLE)
+#define MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK MIPI_DSI_TX_ULPS_ENABLE_TX_ULPS_ENABLE_MASK
+#define MIPI_DSI_CSR_PXL2DPI(csr) ((csr)->PXL2DPI_CONFIG)
+#endif
+
+#define DSI_GET_CSR(dsi_base) ((MIPI_DSI_CSR_Type *)(((uint32_t)(dsi_base)) - (uint32_t)FSL_FEATURE_DSI_CSR_OFFSET))
+#endif
+
+/*! @brief Typedef for MIPI DSI interrupt handler. */
+typedef void (*dsi_isr_t)(const MIPI_DSI_Type *base, dsi_handle_t *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if defined(DSI_HOST_DSI_IRQS)
+/* Array of DSI IRQ number. */
+static const IRQn_Type s_dsiIRQ[] = DSI_HOST_DSI_IRQS;
+#endif
+/*! @brief Pointers to MIPI DSI bases for each instance. */
+static DSI_HOST_Type *const s_dsiBases[] = DSI_HOST_BASE_PTRS;
+/*! @brief MIPI DSI internal handle pointer array */
+static dsi_handle_t *s_dsiHandle[ARRAY_SIZE(s_dsiBases)];
+/*! @brief Pointer to IRQ handler. */
+static dsi_isr_t s_dsiIsr;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to MIPI DSI clocks for each instance. */
+static const clock_ip_name_t s_dsiClocks[] = MIPI_DSI_HOST_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the MIPI DSI host controller instance from peripheral base address.
+ *
+ * @param base MIPI DSI peripheral base address.
+ * @return MIPI DSI instance.
+ */
+static uint32_t DSI_GetInstance(const MIPI_DSI_Type *base);
+
+#if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
+/*!
+ * @brief Convert the D-PHY PLL CN to the value could be set to register.
+ *
+ * @param cn The CN value.
+ * @return The register value.
+ */
+static uint8_t DSI_EncodeDphyPllCn(uint8_t cn);
+
+/*!
+ * @brief Convert the D-PHY PLL CM to the value could be set to register.
+ *
+ * @param cm The CM value.
+ * @return The register value.
+ */
+static uint8_t DSI_EncodeDphyPllCm(uint8_t cm);
+
+/*!
+ * @brief Calculate the D-PHY PLL dividers to generate the desired output frequency.
+ *
+ * Calculate the PLL dividers to generate the most close desired output PLL frequency.
+ *
+ * txHsBitClk_Hz = refClkFreq_Hz * CM / (CN * CO).
+ * CM: 16 ~ 255
+ * CN: 1 ~ 32
+ * CO: 1, 2, 4, 8
+ *
+ * @param cn The CN value, convert using @ref DSI_EncodeDphyPllCn before setting to register.
+ * @param cm The CM value, convert using @ref DSI_EncodeDphyPllCm before setting to register.
+ * @param co The CO value, could set to register directly.
+ * @param refClkFreq_Hz The D-PHY input reference clock frequency (REF_CLK).
+ * @param desiredOutFreq_Hz Desired PLL output frequency.
+ * @return The actually output frequency using the returned dividers. If could not
+ * find suitable dividers, return 0.
+ */
+static uint32_t DSI_DphyGetPllDivider(
+ uint32_t *cn, uint32_t *cm, uint32_t *co, uint32_t refClkFreq_Hz, uint32_t desiredOutFreq_Hz);
+#endif
+
+/*!
+ * @brief Clear the RX FIFO.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ */
+static void DSI_ApbClearRxFifo(const MIPI_DSI_Type *base);
+
+/*!
+ * @brief Handle the DSI transfer result.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param xfer The transfer definition.
+ * @param intFlags1 Interrupt flag group 1.
+ * @param intFlags2 Interrupt flag group 2.
+ * @retval kStatus_Success No error happens.
+ * @retval kStatus_Timeout Hardware timeout detected.
+ * @retval kStatus_DSI_RxDataError RX data error.
+ * @retval kStatus_DSI_ErrorReportReceived Error Report packet received.
+ * @retval kStatus_DSI_Fail Transfer failed for other reasons.
+ */
+static status_t DSI_HandleResult(const MIPI_DSI_Type *base,
+ uint32_t intFlags1,
+ uint32_t intFlags2,
+ dsi_transfer_t *xfer);
+
+/*!
+ * @brief Prepare for the DSI APB transfer.
+ *
+ * This function fills TX data to DSI TX FIFO and sets the packet control
+ * register. Packet transfer could start using @ref DSI_SendApbPacket after
+ * this function.
+ *
+ * @param base MIPI DSI host peripheral base address.
+ * @param xfer The transfer definition.
+ * @retval kStatus_Success It is ready to start transfer.
+ * @retval kStatus_DSI_NotSupported The transfer format is not supported.
+ */
+static status_t DSI_PrepareApbTransfer(const MIPI_DSI_Type *base, dsi_transfer_t *xfer);
+
+/*!
+ * @brief Convert time from nano-second to count of byte clock.
+ *
+ * @param ns Time in nano-second.
+ * @param byteclk_khz Byte clock frequency in kHz.
+ * @return Time in byte clock.
+ */
+static uint32_t DSI_NsToByteClk(uint32_t ns, uint32_t byteclk_khz)
+{
+ return (ns * byteclk_khz) / 1000000UL;
+}
+
+/*!
+ * @brief Convert the time to count of byte clock.
+ *
+ * The time is the sum of nano-second specified by ns and count of UI.
+ *
+ * @param ns Time in nano-second.
+ * @param UI Count of UI.
+ * @param byteclk_khz Byte clock frequency in kHz.
+ * @return Time in byte clock.
+ */
+static uint32_t DSI_NsUiToByteClk(uint32_t ns, uint32_t UI, uint32_t byteclk_khz)
+{
+ return ((ns * byteclk_khz) + (UI * 125000UL)) / 1000000UL;
+}
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t DSI_GetInstance(const MIPI_DSI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dsiBases); instance++)
+ {
+ if (s_dsiBases[instance] == base->host)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dsiBases));
+
+ return instance;
+}
+
+#if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
+static uint8_t DSI_EncodeDphyPllCn(uint8_t cn)
+{
+ uint8_t ret = 0U;
+
+ assert((cn >= 1U) && (cn <= 32U));
+
+ if (1U == cn)
+ {
+ ret = 0x1FU;
+ }
+ else
+ {
+ ret = (uint8_t)((0x65BD44E0UL >> ((uint32_t)cn - 2U)) & 0x1FU);
+ }
+
+ return ret;
+}
+
+static uint8_t DSI_EncodeDphyPllCm(uint8_t cm)
+{
+ uint8_t ret = 0U;
+
+ assert(cm >= 16U);
+
+ if (cm <= 31U)
+ {
+ ret = 0xE0U | cm;
+ }
+ else if (cm <= 63U)
+ {
+ ret = 0xC0U | (cm & 0x1FU);
+ }
+ else if (cm <= 127U)
+ {
+ ret = 0x80U | (cm & 0x3FU);
+ }
+ else
+ {
+ ret = cm & 0xCFU;
+ }
+
+ return ret;
+}
+
+static uint32_t DSI_DphyGetPllDivider(
+ uint32_t *cn, uint32_t *cm, uint32_t *co, uint32_t refClkFreq_Hz, uint32_t desiredOutFreq_Hz)
+{
+ uint32_t cnCur;
+ uint32_t cmCur;
+ uint32_t coShiftCur;
+ uint32_t pllFreqCur;
+ uint32_t diffCur;
+ uint32_t vcoFreq;
+ uint32_t refClk_CN;
+ uint32_t diff = 0xFFFFFFFFU;
+ uint32_t pllFreqCandidate = 0U;
+
+ /* CO available values are 1, 2, 4, 8, so the shift values are 0, 1, 2, 3. */
+ for (coShiftCur = 0U; coShiftCur <= 3U; coShiftCur++)
+ {
+ /* Desired VCO output frequency. */
+ vcoFreq = desiredOutFreq_Hz << coShiftCur;
+
+ /* If desired VCO output frequency is too small, try larger CO value. */
+ if (vcoFreq < DSI_DPHY_PLL_VCO_MIN)
+ {
+ continue;
+ }
+
+ /* If desired VCO output frequency is too large, search finished. */
+ if (vcoFreq > DSI_DPHY_PLL_VCO_MAX)
+ {
+ break;
+ }
+
+ /* Now search the best CN and CM to generate disired VCO output frequency. */
+ for (cnCur = DSI_DPHY_PLL_CN_MIN; cnCur <= DSI_DPHY_PLL_CN_MAX; cnCur++)
+ {
+ /* REF_CLK / CN. */
+ refClk_CN = refClkFreq_Hz / cnCur;
+
+ /* If desired REF_CLK / CN frequency is too large, try larger CN value. */
+ if (refClk_CN > DSI_DPHY_PLL_REFCLK_CN_MAX)
+ {
+ continue;
+ }
+
+ /* If desired REF_CLK / CN frequency is too small, stop search. */
+ if (refClk_CN < DSI_DPHY_PLL_REFCLK_CN_MIN)
+ {
+ break;
+ }
+
+ /* Get the CM most close. */
+ cmCur = (vcoFreq + (refClk_CN / 2U)) / refClk_CN;
+
+ /* If calculated value is (DSI_DPHY_PLL_CM_MAX + 1), use DSI_DPHY_PLL_CM_MAX. */
+ if ((DSI_DPHY_PLL_CM_MAX + 1U) == cmCur)
+ {
+ cmCur = DSI_DPHY_PLL_CM_MAX;
+ }
+
+ if ((cmCur < DSI_DPHY_PLL_CM_MIN) || (cmCur > DSI_DPHY_PLL_CM_MAX))
+ {
+ continue;
+ }
+
+ /* Output frequency using current dividers. */
+ pllFreqCur = (refClk_CN * cmCur) >> coShiftCur;
+
+ if (pllFreqCur > desiredOutFreq_Hz)
+ {
+ diffCur = (pllFreqCur - desiredOutFreq_Hz);
+ }
+ else
+ {
+ diffCur = (desiredOutFreq_Hz - pllFreqCur);
+ }
+
+ /* If the dividers is better. */
+ if (diffCur < diff)
+ {
+ diff = diffCur;
+ *cm = cmCur;
+ *cn = cnCur;
+ *co = coShiftCur;
+ pllFreqCandidate = pllFreqCur;
+
+ /* If the output PLL frequency is exactly the disired value, return directly. */
+ if (0U == diff)
+ {
+ break;
+ }
+ }
+ }
+
+ /* If the output PLL frequency is exactly the disired value, return directly. */
+ if (0U == diff)
+ {
+ break;
+ }
+ }
+
+ return pllFreqCandidate;
+}
+#endif
+
+static void DSI_ApbClearRxFifo(const MIPI_DSI_Type *base)
+{
+ volatile uint32_t dummy = 0U;
+ uint32_t level = base->apb->PKT_FIFO_RD_LEVEL;
+
+ while (0U != (level--))
+ {
+ dummy = base->apb->PKT_RX_PAYLOAD;
+ }
+
+ (void)dummy;
+}
+
+/*!
+ * brief Initializes an MIPI DSI host with the user configuration.
+ *
+ * This function initializes the MIPI DSI host with the configuration, it should
+ * be called first before other MIPI DSI driver functions.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param config Pointer to a user-defined configuration structure.
+ */
+void DSI_Init(const MIPI_DSI_Type *base, const dsi_config_t *config)
+{
+ assert(NULL != config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ (void)CLOCK_EnableClock(s_dsiClocks[DSI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ DSI_HOST_Type *host = base->host;
+
+#if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
+ MIPI_DSI_CSR_Type *csr = DSI_GET_CSR(base);
+ if (config->enableTxUlps)
+ {
+ MIPI_DSI_CSR_ULPS_CTRL(csr) = MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK;
+ }
+ else
+ {
+ MIPI_DSI_CSR_ULPS_CTRL(csr) = 0U;
+ }
+#endif
+
+ host->CFG_NUM_LANES = config->numLanes - 1UL;
+
+ if (config->enableNonContinuousHsClk)
+ {
+ host->CFG_NONCONTINUOUS_CLK = 0x01U;
+ }
+ else
+ {
+ host->CFG_NONCONTINUOUS_CLK = 0x00U;
+ }
+
+ if (config->autoInsertEoTp)
+ {
+ host->CFG_AUTOINSERT_EOTP = 0x01U;
+ }
+ else
+ {
+ host->CFG_AUTOINSERT_EOTP = 0x00U;
+ }
+
+ host->CFG_EXTRA_CMDS_AFTER_EOTP = config->numExtraEoTp;
+ host->CFG_HTX_TO_COUNT = config->htxTo_ByteClk;
+ host->CFG_LRX_H_TO_COUNT = config->lrxHostTo_ByteClk;
+ host->CFG_BTA_H_TO_COUNT = config->btaTo_ByteClk;
+
+ DSI_ApbClearRxFifo(base);
+
+ /* Disable all interrupts by default, user could enable
+ * the desired interrupts later.
+ */
+ base->apb->IRQ_MASK = 0xFFFFFFFFU;
+ base->apb->IRQ_MASK2 = 0xFFFFFFFFU;
+}
+
+/*!
+ * brief Deinitializes an MIPI DSI host.
+ *
+ * This function should be called after all bother MIPI DSI driver functions.
+ *
+ * param base MIPI DSI host peripheral base address.
+ */
+void DSI_Deinit(const MIPI_DSI_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ (void)CLOCK_DisableClock(s_dsiClocks[DSI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Get the default configuration to initialize the MIPI DSI host.
+ *
+ * The default value is:
+ * code
+ config->numLanes = 4;
+ config->enableNonContinuousHsClk = false;
+ config->enableTxUlps = false;
+ config->autoInsertEoTp = true;
+ config->numExtraEoTp = 0;
+ config->htxTo_ByteClk = 0;
+ config->lrxHostTo_ByteClk = 0;
+ config->btaTo_ByteClk = 0;
+ endcode
+ *
+ * param config Pointer to a user-defined configuration structure.
+ */
+void DSI_GetDefaultConfig(dsi_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->numLanes = 4;
+ config->enableNonContinuousHsClk = false;
+ config->enableTxUlps = false;
+ config->autoInsertEoTp = true;
+ config->numExtraEoTp = 0;
+ config->htxTo_ByteClk = 0;
+ config->lrxHostTo_ByteClk = 0;
+ config->btaTo_ByteClk = 0;
+}
+
+/*!
+ * brief Configure the DPI interface core.
+ *
+ * This function sets the DPI interface configuration, it should be used in
+ * video mode.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param config Pointer to the DPI interface configuration.
+ * param numLanes Lane number, should be same with the setting in ref dsi_dpi_config_t.
+ * param dpiPixelClkFreq_Hz The DPI pixel clock frequency in Hz.
+ * param dsiHsBitClkFreq_Hz The DSI high speed bit clock frequency in Hz. It is
+ * the same with DPHY PLL output.
+ */
+void DSI_SetDpiConfig(const MIPI_DSI_Type *base,
+ const dsi_dpi_config_t *config,
+ uint8_t numLanes,
+ uint32_t dpiPixelClkFreq_Hz,
+ uint32_t dsiHsBitClkFreq_Hz)
+{
+ assert(NULL != config);
+
+ /* coefficient DPI event size to number of DSI bytes. */
+ uint32_t coff = (numLanes * dsiHsBitClkFreq_Hz) / (dpiPixelClkFreq_Hz * 8U);
+
+ DSI_HOST_DPI_INTFC_Type *dpi = base->dpi;
+
+#if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && (0 != FSL_FEATURE_DSI_CSR_OFFSET))
+ MIPI_DSI_CSR_Type *csr = DSI_GET_CSR(base);
+ MIPI_DSI_CSR_PXL2DPI(csr) = (uint32_t)config->dpiColorCoding;
+#endif
+
+ dpi->PIXEL_PAYLOAD_SIZE = config->pixelPayloadSize;
+ dpi->INTERFACE_COLOR_CODING = (uint32_t)config->dpiColorCoding;
+ dpi->PIXEL_FORMAT = (uint32_t)config->pixelPacket;
+ dpi->VIDEO_MODE = (uint32_t)config->videoMode;
+
+ if (kDSI_DpiBllpLowPower == config->bllpMode)
+ {
+ dpi->BLLP_MODE = 0x1U;
+ dpi->USE_NULL_PKT_BLLP = 0x0U;
+ }
+ else if (kDSI_DpiBllpBlanking == config->bllpMode)
+ {
+ dpi->BLLP_MODE = 0x0U;
+ dpi->USE_NULL_PKT_BLLP = 0x0U;
+ }
+ else
+ {
+ dpi->BLLP_MODE = 0x0U;
+ dpi->USE_NULL_PKT_BLLP = 0x1U;
+ }
+
+ if (0U != (config->polarityFlags & (uint32_t)kDSI_DpiVsyncActiveHigh))
+ {
+ dpi->VSYNC_POLARITY = 0x01U;
+ }
+ else
+ {
+ dpi->VSYNC_POLARITY = 0x00U;
+ }
+
+ if (0U != (config->polarityFlags & (uint32_t)kDSI_DpiHsyncActiveHigh))
+ {
+ dpi->HSYNC_POLARITY = 0x01U;
+ }
+ else
+ {
+ dpi->HSYNC_POLARITY = 0x00U;
+ }
+
+ dpi->HFP = config->hfp * coff - DSI_HFP_OVERHEAD_BYTE;
+ dpi->HBP = config->hbp * coff - DSI_HBP_OVERHEAD_BYTE;
+ dpi->HSA = config->hsw * coff - DSI_HSA_OVERHEAD_BYTE;
+ dpi->PIXEL_FIFO_SEND_LEVEL = config->pixelPayloadSize;
+
+ dpi->VBP = config->vbp;
+ dpi->VFP = config->vfp;
+
+ dpi->VACTIVE = config->panelHeight - 1UL;
+
+ /* TODO: Configure VC if it is available. */
+}
+
+/*!
+ * brief Initializes the D-PHY
+ *
+ * This function configures the D-PHY timing and setups the D-PHY PLL based on
+ * user configuration. The configuration structure could be got by the function
+ * ref DSI_GetDphyDefaultConfig.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param config Pointer to the D-PHY configuration.
+ * param refClkFreq_Hz The REFCLK frequency in Hz.
+ * return The actual D-PHY PLL output frequency. If could not configure the
+ * PLL to the target frequency, the return value is 0.
+ */
+uint32_t DSI_InitDphy(const MIPI_DSI_Type *base, const dsi_dphy_config_t *config, uint32_t refClkFreq_Hz)
+{
+ assert(NULL != config);
+
+ DSI_HOST_NXP_FDSOI28_DPHY_INTFC_Type *dphy = base->dphy;
+ DSI_HOST_Type *host = base->host;
+
+#if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
+ uint32_t cn;
+ uint32_t cm;
+ uint32_t co;
+ uint32_t outputPllFreq;
+
+ outputPllFreq = DSI_DphyGetPllDivider(&cn, &cm, &co, refClkFreq_Hz, config->txHsBitClk_Hz);
+
+ /* If could not find dividers for the output PLL frequency. */
+ if (0U == outputPllFreq)
+ {
+ return 0U;
+ }
+
+ /* Set the DPHY parameters. */
+ dphy->CN = (uint32_t)DSI_EncodeDphyPllCn((uint8_t)cn);
+ dphy->CM = (uint32_t)DSI_EncodeDphyPllCm((uint8_t)cm);
+ dphy->CO = co;
+#endif
+
+ /* Set the timing parameters. */
+ dphy->M_PRG_HS_PREPARE = (uint32_t)config->tHsPrepare_HalfEscClk - DSI_THS_PREPARE_HALF_ESC_CLK_BASE;
+ dphy->MC_PRG_HS_PREPARE = (uint32_t)config->tClkPrepare_HalfEscClk - DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE;
+ dphy->M_PRG_HS_ZERO = (uint32_t)config->tHsZero_ByteClk - DSI_THS_ZERO_BYTE_CLK_BASE;
+ dphy->MC_PRG_HS_ZERO = (uint32_t)config->tClkZero_ByteClk - DSI_TCLK_ZERO_BYTE_CLK_BASE;
+ dphy->M_PRG_HS_TRAIL = config->tHsTrail_ByteClk;
+ dphy->MC_PRG_HS_TRAIL = config->tClkTrail_ByteClk;
+
+ host->CFG_T_PRE = config->tClkPre_ByteClk;
+ host->CFG_T_POST = config->tClkPost_ByteClk;
+ host->CFG_TX_GAP = config->tHsExit_ByteClk;
+ host->CFG_TWAKEUP = config->tWakeup_EscClk;
+
+#if defined(MIPI_RTERM_SEL_dphy_rterm_sel_MASK)
+ dphy->RTERM_SEL = MIPI_RTERM_SEL_dphy_rterm_sel_MASK;
+#endif
+#if defined(MIPI_TX_RCAL_dphy_tx_rcal_MASK)
+ dphy->TX_RCAL = 1;
+#endif
+ dphy->RXLPRP = 1;
+ dphy->RXCDRP = 1;
+
+ /* Auto power down the inactive lanes. */
+ dphy->AUTO_PD_EN = 0x1U;
+
+ dphy->TST = 0x25U;
+
+#if !((defined(FSL_FEATURE_MIPI_NO_PLL) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_PLL)))
+ /* Power up the PLL. */
+ dphy->PD_PLL = 0U;
+
+ /* Wait for the PLL lock. */
+ while (0UL == dphy->LOCK)
+ {
+ }
+#endif
+
+ /* Power up the DPHY. */
+ dphy->PD_TX = 0U;
+
+#if !((defined(FSL_FEATURE_MIPI_NO_PLL) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_PLL)))
+ return outputPllFreq;
+#else
+ return config->txHsBitClk_Hz;
+#endif
+}
+
+/*!
+ * brief Deinitializes the D-PHY
+ *
+ * Power down the D-PHY PLL and shut down D-PHY.
+ *
+ * param base MIPI DSI host peripheral base address.
+ */
+void DSI_DeinitDphy(const MIPI_DSI_Type *base)
+{
+#if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL)) && (0 != FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL))
+ /* Power down the PLL. */
+ base->dphy->PD_PLL = 1U;
+#endif
+
+ /* Power down the DPHY. */
+ base->dphy->PD_TX = 1U;
+}
+
+/*!
+ * brief Get the default D-PHY configuration.
+ *
+ * Gets the default D-PHY configuration, the timing parameters are set according
+ * to D-PHY specification. User could use the configuration directly, or change
+ * some parameters according to the special device.
+ *
+ * param config Pointer to the D-PHY configuration.
+ * param txHsBitClk_Hz High speed bit clock in Hz.
+ * param txEscClk_Hz Esc clock in Hz.
+ */
+void DSI_GetDphyDefaultConfig(dsi_dphy_config_t *config, uint32_t txHsBitClk_Hz, uint32_t txEscClk_Hz)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ uint32_t byteClkFreq_kHz = txHsBitClk_Hz / 8U / 1000U;
+ uint32_t txEscClk_kHz = txEscClk_Hz / 1000U;
+
+ config->txHsBitClk_Hz = txHsBitClk_Hz;
+
+ /* THS-EXIT in byte clock. At least 100ns. */
+ config->tHsExit_ByteClk = (uint8_t)(DSI_NsToByteClk(100U, byteClkFreq_kHz) + 1U);
+
+ /* T-WAKEUP. At least 1ms. */
+ config->tWakeup_EscClk = (txEscClk_Hz / 1000U) + 1U;
+
+ /* THS-PREPARE. 40ns+4*UI to 85ns+6*UI. */
+ config->tHsPrepare_HalfEscClk =
+ (uint8_t)(((40U * txEscClk_kHz * 2U) / 1000000U) + (4U * txEscClk_Hz * 2U / txHsBitClk_Hz) + 1U);
+ if (config->tHsPrepare_HalfEscClk < DSI_THS_PREPARE_HALF_ESC_CLK_MIN)
+ {
+ config->tHsPrepare_HalfEscClk = DSI_THS_PREPARE_HALF_ESC_CLK_MIN;
+ }
+ else if (config->tHsPrepare_HalfEscClk > DSI_THS_PREPARE_HALF_ESC_CLK_MAX)
+ {
+ config->tHsPrepare_HalfEscClk = DSI_THS_PREPARE_HALF_ESC_CLK_MAX;
+ }
+ else
+ {
+ /* For MISRA check. */
+ }
+
+ /* TCLK-PREPARE. 38ns to 95ns. */
+ config->tClkPrepare_HalfEscClk = (uint8_t)((38U * txEscClk_kHz * 2U) / 1000000U + 1U);
+ if (config->tClkPrepare_HalfEscClk < DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN)
+ {
+ config->tClkPrepare_HalfEscClk = DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN;
+ }
+ else if (config->tClkPrepare_HalfEscClk > DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX)
+ {
+ config->tClkPrepare_HalfEscClk = DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX;
+ }
+ else
+ {
+ /* For MISRA check. */
+ }
+
+ /* THS-ZERO, At least 105ns+6*UI. */
+ config->tHsZero_ByteClk = (uint8_t)(DSI_NsUiToByteClk(105U, 6U, byteClkFreq_kHz) + 1U);
+ if (config->tHsZero_ByteClk < DSI_THS_ZERO_BYTE_CLK_BASE)
+ {
+ config->tHsZero_ByteClk = DSI_THS_ZERO_BYTE_CLK_BASE;
+ }
+
+ /* TCLK-ZERO, At least 262ns. */
+ config->tClkZero_ByteClk = (uint8_t)(DSI_NsToByteClk(262U, byteClkFreq_kHz) + 1U);
+ if (config->tClkZero_ByteClk < DSI_TCLK_ZERO_BYTE_CLK_BASE)
+ {
+ config->tClkZero_ByteClk = DSI_TCLK_ZERO_BYTE_CLK_BASE;
+ }
+
+ /* THS-TRAIL, 60ns+4*UI to 105ns+12UI. */
+ /* Due to IP design, extra 4*UI should be added. */
+ config->tHsTrail_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 8U, byteClkFreq_kHz) + 1U);
+
+ /* TCLK-TRAIL, at least 60ns. */
+ /* Due to IP design, extra 4*UI should be added. */
+ config->tClkTrail_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 4U, byteClkFreq_kHz) + 1U);
+
+ /*
+ * T_LPX + T_CLK-PREPARE + T_CLK-ZERO + T_CLK-PRE
+ * T_LPX >= 50ns
+ * T_CLK-PREPARE >= 38ns
+ * T_CLK-ZERO >= 262ns
+ * T_CLK-PRE >= 8*UI
+ */
+ config->tClkPre_ByteClk = (uint8_t)(DSI_NsUiToByteClk(88U, 8U, byteClkFreq_kHz) + 1U) + config->tClkZero_ByteClk;
+
+ /*
+ * T_CLK-POST + T_CLK-TRAIL
+ * T_CLK-POST >= 60ns + 52*UI.
+ * T_CLK-TRAIL >= 60ns
+ */
+ config->tClkPost_ByteClk = (uint8_t)(DSI_NsUiToByteClk(60U, 52U, byteClkFreq_kHz) + 1U) + config->tClkTrail_ByteClk;
+}
+
+/*!
+ * brief Configure the APB packet to send.
+ *
+ * This function configures the next APB packet transfer. After configuration,
+ * the packet transfer could be started with function ref DSI_SendApbPacket.
+ * If the packet is long packet, Use ref DSI_WriteApbTxPayload to fill the payload
+ * before start transfer.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param wordCount For long packet, this is the byte count of the payload.
+ * For short packet, this is (data1 << 8) | data0.
+ * param virtualChannel Virtual channel.
+ * param dataType The packet data type, (DI).
+ * param flags The transfer control flags, see ref _dsi_transfer_flags.
+ */
+void DSI_SetApbPacketControl(
+ const MIPI_DSI_Type *base, uint16_t wordCount, uint8_t virtualChannel, dsi_tx_data_type_t dataType, uint8_t flags)
+{
+ uint32_t pktCtrl = PKT_CONTROL_WORD_COUNT(wordCount) | PKT_CONTROL_HEADER_TYPE(dataType);
+
+#if defined(DSI_HOST_PKT_CONTROL_VC)
+ pktCtrl |= (uint32_t)DSI_HOST_PKT_CONTROL_VC(virtualChannel);
+#endif
+
+ if (0U != (flags & (uint8_t)kDSI_TransferUseHighSpeed))
+ {
+ pktCtrl |= PKT_CONTROL_HS_MASK;
+ }
+
+ if (0U != (flags & (uint8_t)kDSI_TransferPerformBTA))
+ {
+ pktCtrl |= PKT_CONTROL_BTA_MASK;
+ }
+
+ base->apb->PKT_CONTROL = pktCtrl;
+}
+
+/*!
+ * brief Fill the long APB packet payload.
+ *
+ * Write the long packet payload to TX FIFO.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param payload Pointer to the payload.
+ * param payloadSize Payload size in byte.
+ */
+void DSI_WriteApbTxPayload(const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize)
+{
+ DSI_WriteApbTxPayloadExt(base, payload, payloadSize, false, 0U);
+}
+
+void DSI_WriteApbTxPayloadExt(
+ const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize, bool sendDscCmd, uint8_t dscCmd)
+{
+ uint32_t firstWord;
+ uint16_t i;
+ uint16_t payloadSizeLocal = payloadSize;
+ const uint8_t *payloadLocal = payload;
+
+ DSI_HOST_APB_PKT_IF_Type *apb = base->apb;
+
+ if (sendDscCmd)
+ {
+ payloadSizeLocal += 1U;
+ }
+
+ assert(payloadSizeLocal <= FSL_DSI_TX_MAX_PAYLOAD_BYTE);
+
+ /* The first 4-byte. */
+ if (sendDscCmd)
+ {
+ firstWord = dscCmd;
+ }
+ else
+ {
+ firstWord = *payloadLocal;
+ payloadLocal++;
+ }
+
+ payloadSizeLocal--;
+
+ for (i = 1U; i < 4U; i++)
+ {
+ if (payloadSizeLocal > 0U)
+ {
+ firstWord |= ((uint32_t)(*payloadLocal) << (i << 3U));
+ payloadLocal++;
+ payloadSizeLocal--;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ apb->TX_PAYLOAD = firstWord;
+
+ /* Write the payloadLocal to the FIFO. */
+ for (i = 0; i < (payloadSizeLocal / 4U); i++)
+ {
+ apb->TX_PAYLOAD = ((uint32_t)payloadLocal[3] << 24U) | ((uint32_t)payloadLocal[2] << 16U) |
+ ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
+ payloadLocal = &payloadLocal[4];
+ }
+
+ /* Write the remaining data. */
+ switch (payloadSizeLocal & 0x03U)
+ {
+ case 3:
+ apb->TX_PAYLOAD = ((uint32_t)payloadLocal[2] << 16U) | ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
+ break;
+ case 2:
+ apb->TX_PAYLOAD = ((uint32_t)payloadLocal[1] << 8U) | payloadLocal[0];
+ break;
+ case 1:
+ apb->TX_PAYLOAD = payloadLocal[0];
+ break;
+ default:
+ /* For MISRA 2012 16.4 */
+ break;
+ }
+}
+
+static status_t DSI_PrepareApbTransfer(const MIPI_DSI_Type *base, dsi_transfer_t *xfer)
+{
+ /* The receive data size should be smaller than the RX FIRO. */
+ assert(xfer->rxDataSize <= FSL_DSI_RX_MAX_PAYLOAD_BYTE);
+ assert(xfer->txDataSize <= FSL_DSI_TX_MAX_PAYLOAD_BYTE);
+
+ uint8_t txDataIndex;
+ uint16_t wordCount;
+ uint32_t intFlags1;
+ uint32_t intFlags2;
+ uint32_t txDataSize;
+
+ status_t status;
+
+ if (xfer->rxDataSize > FSL_DSI_RX_MAX_PAYLOAD_BYTE)
+ {
+ status = kStatus_DSI_NotSupported;
+ }
+ else
+ {
+ if (xfer->rxDataSize != 0U)
+ {
+ xfer->flags |= (uint8_t)kDSI_TransferPerformBTA;
+ }
+
+ /* ========================== Prepare TX. ========================== */
+ /* If xfer->sendDscCmd is true, then the DSC command is not included in the
+ xfer->txData, but specified by xfer->dscCmd.
+ */
+ if (xfer->sendDscCmd)
+ {
+ txDataSize = (uint32_t)xfer->txDataSize + 1U;
+ }
+ else
+ {
+ txDataSize = (uint32_t)xfer->txDataSize;
+ }
+
+ /* Short packet. */
+ if (txDataSize <= 2U)
+ {
+ if (0U == txDataSize)
+ {
+ wordCount = 0U;
+ }
+ else
+ {
+ txDataIndex = 0;
+
+ if (xfer->sendDscCmd)
+ {
+ wordCount = xfer->dscCmd;
+ }
+ else
+ {
+ wordCount = xfer->txData[txDataIndex++];
+ }
+
+ if (2U == txDataSize)
+ {
+ wordCount |= ((uint16_t)xfer->txData[txDataIndex] << 8U);
+ }
+ }
+ }
+ /* Long packet. */
+ else
+ {
+ wordCount = (uint16_t)txDataSize;
+ DSI_WriteApbTxPayloadExt(base, xfer->txData, xfer->txDataSize, xfer->sendDscCmd, xfer->dscCmd);
+ }
+
+ DSI_SetApbPacketControl(base, wordCount, xfer->virtualChannel, xfer->txDataType, xfer->flags);
+
+ /* Clear the interrupt flags set by previous transfer. */
+ DSI_GetAndClearInterruptStatus(base, &intFlags1, &intFlags2);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Read the long APB packet payload.
+ *
+ * Read the long packet payload from RX FIFO. This function reads directly but
+ * does not check the RX FIFO status. Upper layer should make sure there are
+ * available data.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param payload Pointer to the payload.
+ * param payloadSize Payload size in byte.
+ */
+void DSI_ReadApbRxPayload(const MIPI_DSI_Type *base, uint8_t *payload, uint16_t payloadSize)
+{
+ uint32_t tmp;
+ uint16_t i;
+ uint8_t *payloadLocal = payload;
+
+ for (i = 0; i < payloadSize / 4U; i++)
+ {
+ tmp = base->apb->PKT_RX_PAYLOAD;
+ payloadLocal[0] = (uint8_t)(tmp & 0xFFU);
+ payloadLocal[1] = (uint8_t)((tmp >> 8U) & 0xFFU);
+ payloadLocal[2] = (uint8_t)((tmp >> 16U) & 0xFFU);
+ payloadLocal[3] = (uint8_t)((tmp >> 24U) & 0xFFU);
+ payloadLocal = &payloadLocal[4];
+ }
+
+ /* Read out the remaining data. */
+ if (0U != (payloadSize & 0x03U))
+ {
+ tmp = base->apb->PKT_RX_PAYLOAD;
+
+ for (i = 0; i < (payloadSize & 0x3U); i++)
+ {
+ payloadLocal[i] = (uint8_t)(tmp & 0xFFU);
+ tmp >>= 8U;
+ }
+ }
+}
+
+/*!
+ * brief APB data transfer using blocking method.
+ *
+ * Perform APB data transfer using blocking method. This function waits until all
+ * data send or received, or timeout happens.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param xfer Pointer to the transfer structure.
+ * retval kStatus_Success Data transfer finished with no error.
+ * retval kStatus_Timeout Transfer failed because of timeout.
+ * retval kStatus_DSI_RxDataError RX data error, user could use ref DSI_GetRxErrorStatus
+ * to check the error details.
+ * retval kStatus_DSI_ErrorReportReceived Error Report packet received, user could use
+ * ref DSI_GetAndClearHostStatus to check the error report status.
+ * retval kStatus_DSI_NotSupported Transfer format not supported.
+ * retval kStatus_DSI_Fail Transfer failed for other reasons.
+ */
+status_t DSI_TransferBlocking(const MIPI_DSI_Type *base, dsi_transfer_t *xfer)
+{
+ status_t status;
+ uint32_t intFlags1Old;
+ uint32_t intFlags2Old;
+ uint32_t intFlags1New;
+ uint32_t intFlags2New;
+
+ DSI_HOST_APB_PKT_IF_Type *apb = base->apb;
+
+ /* Wait for the APB state idle. */
+ while (0U != (apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
+ {
+ }
+
+ status = DSI_PrepareApbTransfer(base, xfer);
+
+ if (kStatus_Success == status)
+ {
+ DSI_SendApbPacket(base);
+
+ /* Make sure the transfer is started. */
+ while (true)
+ {
+ DSI_GetAndClearInterruptStatus(base, &intFlags1Old, &intFlags2Old);
+
+ if (0U != (intFlags1Old & (uint32_t)kDSI_InterruptGroup1ApbNotIdle))
+ {
+ break;
+ }
+ }
+
+ /* Wait for transfer finished. */
+ while (true)
+ {
+ /* Transfer completed. */
+ if (0U == (apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
+ {
+ break;
+ }
+
+ /* Time out. */
+ if (0U != (base->host->RX_ERROR_STATUS &
+ ((uint32_t)kDSI_RxErrorHtxTo | (uint32_t)kDSI_RxErrorLrxTo | (uint32_t)kDSI_RxErrorBtaTo)))
+ {
+ status = kStatus_Timeout;
+ break;
+ }
+ }
+
+ DSI_GetAndClearInterruptStatus(base, &intFlags1New, &intFlags2New);
+
+ if (kStatus_Success == status)
+ {
+ status = DSI_HandleResult(base, intFlags1Old | intFlags1New, intFlags2Old | intFlags2New, xfer);
+ }
+ }
+
+ return status;
+}
+
+static status_t DSI_HandleResult(const MIPI_DSI_Type *base,
+ uint32_t intFlags1,
+ uint32_t intFlags2,
+ dsi_transfer_t *xfer)
+{
+ uint32_t rxPktHeader;
+ uint16_t actualRxByteCount;
+ dsi_rx_data_type_t rxDataType;
+ bool readRxDataFromPayload;
+
+ /* If hardware detect timeout. */
+ if (0U != (((uint32_t)kDSI_InterruptGroup1HtxTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
+ (uint32_t)kDSI_InterruptGroup1BtaTo) &
+ intFlags1))
+ {
+ return kStatus_Timeout;
+ }
+
+ /* If received data error. */
+ if (0U != (((uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError) & intFlags2))
+ {
+ return kStatus_DSI_RxDataError;
+ }
+
+ /* If BTA is performed. */
+ if (0U != (xfer->flags & (uint32_t)kDSI_TransferPerformBTA))
+ {
+ if (0U != (intFlags1 & DSI_INT_STATUS_ERROR_REPORT_MASK))
+ {
+ return kStatus_DSI_ErrorReportReceived;
+ }
+
+ if (0U != ((uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived & intFlags1))
+ {
+ rxPktHeader = DSI_GetRxPacketHeader(base);
+ rxDataType = DSI_GetRxPacketType(rxPktHeader);
+
+ /* If received error report. */
+ if (kDSI_RxDataAckAndErrorReport == rxDataType)
+ {
+ return kStatus_DSI_ErrorReportReceived;
+ }
+ else
+ {
+ if ((kDSI_RxDataGenShortRdResponseOneByte == rxDataType) ||
+ (kDSI_RxDataDcsShortRdResponseOneByte == rxDataType))
+ {
+ readRxDataFromPayload = false;
+ actualRxByteCount = 1U;
+ }
+ else if ((kDSI_RxDataGenShortRdResponseTwoByte == rxDataType) ||
+ (kDSI_RxDataDcsShortRdResponseTwoByte == rxDataType))
+ {
+ readRxDataFromPayload = false;
+ actualRxByteCount = 2U;
+ }
+ else if ((kDSI_RxDataGenLongRdResponse == rxDataType) || (kDSI_RxDataDcsLongRdResponse == rxDataType))
+ {
+ readRxDataFromPayload = true;
+ actualRxByteCount = DSI_GetRxPacketWordCount(rxPktHeader);
+ }
+ else
+ {
+ readRxDataFromPayload = false;
+ xfer->rxDataSize = 0U;
+ actualRxByteCount = 0U;
+ }
+
+ xfer->rxDataSize = MIN(xfer->rxDataSize, actualRxByteCount);
+
+ if (xfer->rxDataSize > 0U)
+ {
+ if (readRxDataFromPayload)
+ {
+ DSI_ReadApbRxPayload(base, xfer->rxData, xfer->rxDataSize);
+ }
+ else
+ {
+ xfer->rxData[0] = (uint8_t)(rxPktHeader & 0xFFU);
+
+ if (2U == xfer->rxDataSize)
+ {
+ xfer->rxData[1] = (uint8_t)((rxPktHeader >> 8U) & 0xFFU);
+ }
+ }
+ }
+
+ return kStatus_Success;
+ }
+ }
+
+ return kStatus_Success;
+ }
+ else
+ {
+ /* Tx Done. */
+ if (0U != ((uint32_t)kDSI_InterruptGroup1ApbTxDone & intFlags1))
+ {
+ return kStatus_Success;
+ }
+ }
+
+ return kStatus_Fail;
+}
+
+/*!
+ * brief Create the MIPI DSI handle.
+ *
+ * This function initializes the MIPI DSI handle which can be used for other transactional APIs.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param handle Handle pointer.
+ * param callback Callback function.
+ * param userData User data.
+ */
+status_t DSI_TransferCreateHandle(const MIPI_DSI_Type *base,
+ dsi_handle_t *handle,
+ dsi_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ uint32_t instance = DSI_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Initialize the handle */
+ s_dsiHandle[instance] = handle;
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->isBusy = false;
+ handle->dsi = base;
+ s_dsiIsr = DSI_TransferHandleIRQ;
+
+#if defined(DSI_HOST_DSI_IRQS)
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(s_dsiIRQ[instance]);
+#endif
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief APB data transfer using interrupt method.
+ *
+ * Perform APB data transfer using interrupt method, when transfer finished,
+ * upper layer could be informed through callback function.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param handle pointer to dsi_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the transfer structure.
+ *
+ * retval kStatus_Success Data transfer started successfully.
+ * retval kStatus_DSI_Busy Failed to start transfer because DSI is busy with pervious transfer.
+ * retval kStatus_DSI_NotSupported Transfer format not supported.
+ */
+status_t DSI_TransferNonBlocking(const MIPI_DSI_Type *base, dsi_handle_t *handle, dsi_transfer_t *xfer)
+{
+ status_t status;
+
+ if (handle->isBusy)
+ {
+ status = kStatus_DSI_Busy;
+ }
+ else if (0U != (base->apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
+ {
+ status = kStatus_DSI_Busy;
+ }
+ else
+ {
+ handle->xfer = *xfer;
+
+ status = DSI_PrepareApbTransfer(base, &handle->xfer);
+
+ if (kStatus_Success == status)
+ {
+ DSI_SendApbPacket(base);
+ handle->isBusy = true;
+
+ /* Enable the interrupts. */
+ if (0U != (handle->xfer.flags & (uint32_t)kDSI_TransferPerformBTA))
+ {
+ DSI_EnableInterrupts(
+ base,
+ DSI_INT_STATUS_TRIGGER_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
+ (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived | (uint32_t)kDSI_InterruptGroup1BtaTo |
+ (uint32_t)kDSI_InterruptGroup1LrxTo | (uint32_t)kDSI_InterruptGroup1HtxTo |
+ (uint32_t)kDSI_InterruptGroup1AckTriggerReceived,
+ (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
+ }
+ else
+ {
+ DSI_EnableInterrupts(base,
+ (uint32_t)kDSI_InterruptGroup1ApbTxDone | (uint32_t)kDSI_InterruptGroup1HtxTo, 0U);
+ }
+ }
+ }
+
+ return status;
+}
+
+/*!
+ * brief Abort current APB data transfer.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param handle pointer to dsi_handle_t structure which stores the transfer state.
+ */
+void DSI_TransferAbort(const MIPI_DSI_Type *base, dsi_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ if (handle->isBusy)
+ {
+ /* Disable the interrupts. */
+ DSI_DisableInterrupts(base,
+ (uint32_t)kDSI_InterruptGroup1ApbTxDone | DSI_INT_STATUS_TRIGGER_MASK |
+ DSI_INT_STATUS_ERROR_REPORT_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
+ (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived |
+ (uint32_t)kDSI_InterruptGroup1BtaTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
+ (uint32_t)kDSI_InterruptGroup1HtxTo,
+ (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
+
+ /* Reset transfer info. */
+ (void)memset(&handle->xfer, 0, sizeof(handle->xfer));
+
+ /* Reset the state to idle. */
+ handle->isBusy = false;
+ }
+}
+
+/*!
+ * brief Interrupt handler for the DSI.
+ *
+ * param base MIPI DSI host peripheral base address.
+ * param handle pointer to dsi_handle_t structure which stores the transfer state.
+ */
+void DSI_TransferHandleIRQ(const MIPI_DSI_Type *base, dsi_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ status_t status;
+ uint32_t intFlags1;
+ uint32_t intFlags2;
+ uint32_t timeout;
+ const MIPI_DSI_Type *dsi = handle->dsi;
+
+ /* If no transfer in progress, return directly. */
+ if (handle->isBusy)
+ {
+ /* Make sure the transfer is completed. */
+ timeout = FSL_MIPI_DSI_IDLE_TIMEOUT;
+ while (0U != (timeout--))
+ {
+ if (0U == (dsi->apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
+ {
+ break;
+ }
+ }
+
+ if (0U == timeout)
+ {
+ DSI_TransferAbort(dsi, handle);
+ status = kStatus_Timeout;
+ }
+ else
+ {
+ /* Disable the interrupts. */
+ DSI_DisableInterrupts(
+ dsi,
+ (uint32_t)kDSI_InterruptGroup1ApbTxDone | DSI_INT_STATUS_TRIGGER_MASK |
+ DSI_INT_STATUS_ERROR_REPORT_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
+ (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived | (uint32_t)kDSI_InterruptGroup1BtaTo |
+ (uint32_t)kDSI_InterruptGroup1LrxTo | (uint32_t)kDSI_InterruptGroup1HtxTo,
+ (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
+
+ DSI_GetAndClearInterruptStatus(dsi, &intFlags1, &intFlags2);
+
+ status = DSI_HandleResult(dsi, intFlags1, intFlags2, &handle->xfer);
+ handle->isBusy = false;
+ }
+
+ if (NULL != handle->callback)
+ {
+ handle->callback(dsi, handle, status, handle->userData);
+ }
+ }
+
+ return;
+}
+
+#if defined(DSI_HOST)
+void MIPI_DSI_DriverIRQHandler(void);
+void MIPI_DSI_DriverIRQHandler(void)
+{
+ /* The first parameter is not used, use the peripheral address defined in
+ * handle.
+ */
+ s_dsiIsr(NULL, s_dsiHandle[0]);
+}
+#endif