1 /*
2  * Copyright 2020-2021 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_mipi_dsi.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.mipi_dsi_split"
17 #endif
18 
19 /* The timeout cycles to wait for DSI state machine idle. */
20 #ifndef FSL_MIPI_DSI_IDLE_TIMEOUT
21 #define FSL_MIPI_DSI_IDLE_TIMEOUT 0x1000U
22 #endif
23 
24 /* PLL CN should be in the range of 1 to 32. */
25 #define DSI_DPHY_PLL_CN_MIN 1U
26 #define DSI_DPHY_PLL_CN_MAX 32U
27 
28 /* PLL refClk / CN should be in the range of 24M to 30M. */
29 #define DSI_DPHY_PLL_REFCLK_CN_MIN 24000000U
30 #define DSI_DPHY_PLL_REFCLK_CN_MAX 30000000U
31 
32 /* PLL CM should be in the range of 16 to 255. */
33 #define DSI_DPHY_PLL_CM_MIN 16U
34 #define DSI_DPHY_PLL_CM_MAX 255U
35 
36 /* PLL VCO output frequency max value is 1.5GHz, VCO output is (refClk / CN ) * CM. */
37 #define DSI_DPHY_PLL_VCO_MAX 1500000000U
38 #define DSI_DPHY_PLL_VCO_MIN (DSI_DPHY_PLL_REFCLK_CN_MIN * DSI_DPHY_PLL_CM_MIN)
39 
40 #define PKT_CONTROL_WORD_COUNT(wc)    ((uint32_t)(wc) << 0U)
41 #define PKT_CONTROL_VC(vc)            ((uint32_t)(vc) << 16U)
42 #define PKT_CONTROL_HEADER_TYPE(type) ((uint32_t)(type) << 18U)
43 #define PKT_CONTROL_HS_MASK           (1UL << 24U)
44 #define PKT_CONTROL_BTA_MASK          (1UL << 25U)
45 #define PKT_CONTROL_BTA_ONLY_MASK     (1UL << 26U)
46 
47 /* Macro used for D-PHY timing setting. */
48 #define DSI_THS_ZERO_BYTE_CLK_BASE         6U
49 #define DSI_TCLK_ZERO_BYTE_CLK_BASE        3U
50 #define DSI_THS_PREPARE_HALF_ESC_CLK_BASE  2U
51 #define DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE 2U
52 
53 #define DSI_THS_PREPARE_HALF_ESC_CLK_MIN  (DSI_THS_PREPARE_HALF_ESC_CLK_BASE)
54 #define DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN (DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE)
55 
56 #define DSI_THS_PREPARE_HALF_ESC_CLK_MAX  (5U)
57 #define DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX (3U)
58 
59 /* Convert ns to byte clock. */
60 #define DSI_NS_TO_BYTE_CLK(ns, byte_clk_khz) ((ns) * (byte_clk_khz) / 1000000U)
61 /* Convert ns+UI to byte clock. */
62 #define DSI_NS_UI_TO_BYTE_CLK(ns, UI, byte_clk_khz) ((((ns) * (byte_clk_khz)) + ((UI)*125000U)) / 1000000U)
63 
64 /* Packet overhead for HSA, HFP, HBP */
65 #define DSI_HSA_OVERHEAD_BYTE 10UL /* HSS + HSA header + HSA CRC. */
66 #define DSI_HFP_OVERHEAD_BYTE 8UL  /* RGB data packet CRC + HFP header + HFP CRC. */
67 #define DSI_HBP_OVERHEAD_BYTE 14UL /* HSE + HBP header + HBP CRC + RGB data packet header */
68 
69 #define DSI_INT_STATUS_TRIGGER_MASK                                                                           \
70     ((uint32_t)kDSI_InterruptGroup1ResetTriggerReceived | (uint32_t)kDSI_InterruptGroup1TearTriggerReceived | \
71      (uint32_t)kDSI_InterruptGroup1AckTriggerReceived)
72 #define DSI_INT_STATUS_ERROR_REPORT_MASK (0xFFFFU << 9U)
73 
74 #if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && FSL_FEATURE_DSI_CSR_OFFSET)
75 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
76 typedef MIPI_DSI_LVDS_COMBO_CSR_Type MIPI_DSI_CSR_Type;
77 #define MIPI_DSI_CSR_ULPS_CTRL(csr)      ((csr)->ULPS_CTRL)
78 #define MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK MIPI_DSI_LVDS_COMBO_CSR_ULPS_CTRL_TX_ULPS_MASK
79 #define MIPI_DSI_CSR_PXL2DPI(csr)        ((csr)->PXL2DPI_CTRL)
80 #else
81 #define MIPI_DSI_CSR_ULPS_CTRL(csr)      ((csr)->TX_ULPS_ENABLE)
82 #define MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK MIPI_DSI_TX_ULPS_ENABLE_TX_ULPS_ENABLE_MASK
83 #define MIPI_DSI_CSR_PXL2DPI(csr)        ((csr)->PXL2DPI_CONFIG)
84 #endif
85 
86 #define DSI_GET_CSR(dsi_base) (MIPI_DSI_CSR_Type *)((uint32_t)(dsi_base) - (uint32_t)FSL_FEATURE_DSI_CSR_OFFSET)
87 #endif
88 
89 /*! @brief Typedef for MIPI DSI interrupt handler. */
90 typedef void (*dsi_isr_t)(const MIPI_DSI_Type *base, dsi_handle_t *handle);
91 
92 /*******************************************************************************
93  * Variables
94  ******************************************************************************/
95 #if defined(DSI_HOST_IRQS)
96 /* Array of DSI IRQ number. */
97 static const DSI_HOST_IRQn s_dsiIRQ[] = DSI_HOST_IRQS;
98 #endif
99 /*! @brief Pointers to MIPI DSI bases for each instance. */
100 static DSI_HOST_Type *const s_dsiBases[] = DSI_HOST_BASE_PTRS;
101 /*! @brief MIPI DSI internal handle pointer array */
102 static dsi_handle_t *s_dsiHandle[ARRAY_SIZE(s_dsiBases)];
103 /*! @brief Pointer to IRQ handler. */
104 static dsi_isr_t s_dsiIsr;
105 
106 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
107 /*! @brief Pointers to MIPI DSI clocks for each instance. */
108 static const clock_ip_name_t s_dsiClocks[] = MIPI_DSI_HOST_CLOCKS;
109 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
110 
111 /*******************************************************************************
112  * Prototypes
113  ******************************************************************************/
114 /*!
115  * @brief Get the MIPI DSI host controller instance from peripheral base address.
116  *
117  * @param base MIPI DSI peripheral base address.
118  * @return MIPI DSI instance.
119  */
120 uint32_t DSI_GetInstance(const MIPI_DSI_Type *base);
121 
122 #if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL) && (FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL)))
123 /*!
124  * @brief Convert the D-PHY PLL CN to the value could be set to register.
125  *
126  * @param cn The CN value.
127  * @return The register value.
128  */
129 static uint8_t DSI_EncodeDphyPllCn(uint8_t cn);
130 
131 /*!
132  * @brief Convert the D-PHY PLL CM to the value could be set to register.
133  *
134  * @param cm The CM value.
135  * @return The register value.
136  */
137 static uint8_t DSI_EncodeDphyPllCm(uint8_t cm);
138 
139 /*!
140  * @brief Calculate the D-PHY PLL dividers to generate the desired output frequency.
141  *
142  * Calculate the PLL dividers to generate the most close desired output PLL frequency.
143  *
144  * txHsBitClk_Hz = refClkFreq_Hz * CM / (CN * CO).
145  * CM: 16 ~ 255
146  * CN: 1 ~ 32
147  * CO: 1, 2, 4, 8
148  *
149  * @param cn The CN value, convert using @ref DSI_EncodeDphyPllCn before setting to register.
150  * @param cm The CM value, convert using @ref DSI_EncodeDphyPllCm before setting to register.
151  * @param co The CO value, could set to register directly.
152  * @param refClkFreq_Hz The D-PHY input reference clock frequency (REF_CLK).
153  * @param desiredOutFreq_Hz Desired PLL output frequency.
154  * @return The actually output frequency using the returned dividers. If could not
155  * find suitable dividers, return 0.
156  */
157 static uint32_t DSI_DphyGetPllDivider(
158     uint32_t *cn, uint32_t *cm, uint32_t *co, uint32_t refClkFreq_Hz, uint32_t desiredOutFreq_Hz);
159 #endif
160 
161 /*!
162  * @brief Clear the RX FIFO.
163  *
164  * @param base MIPI DSI host peripheral base address.
165  */
166 static void DSI_ApbClearRxFifo(const MIPI_DSI_Type *base);
167 
168 /*!
169  * @brief Handle the DSI transfer result.
170  *
171  * @param base MIPI DSI host peripheral base address.
172  * @param xfer The transfer definition.
173  * @param intFlags1 Interrupt flag group 1.
174  * @param intFlags2 Interrupt flag group 2.
175  * @retval kStatus_Success No error happens.
176  * @retval kStatus_Timeout Hardware timeout detected.
177  * @retval kStatus_DSI_RxDataError RX data error.
178  * @retval kStatus_DSI_ErrorReportReceived Error Report packet received.
179  * @retval kStatus_DSI_Fail Transfer failed for other reasons.
180  */
181 static status_t DSI_HandleResult(const MIPI_DSI_Type *base,
182                                  uint32_t intFlags1,
183                                  uint32_t intFlags2,
184                                  dsi_transfer_t *xfer);
185 
186 /*!
187  * @brief Prepare for the DSI APB transfer.
188  *
189  * This function fills TX data to DSI TX FIFO and sets the packet control
190  * register. Packet transfer could start using @ref DSI_SendApbPacket after
191  * this function.
192  *
193  * @param base MIPI DSI host peripheral base address.
194  * @param xfer The transfer definition.
195  * @retval kStatus_Success It is ready to start transfer.
196  * @retval kStatus_DSI_NotSupported The transfer format is not supported.
197  */
198 static status_t DSI_PrepareApbTransfer(const MIPI_DSI_Type *base, dsi_transfer_t *xfer);
199 
200 /*******************************************************************************
201  * Code
202  ******************************************************************************/
203 
DSI_GetInstance(const MIPI_DSI_Type * base)204 uint32_t DSI_GetInstance(const MIPI_DSI_Type *base)
205 {
206     uint32_t instance;
207 
208     /* Find the instance index from base address mappings. */
209     for (instance = 0; instance < ARRAY_SIZE(s_dsiBases); instance++)
210     {
211         if (s_dsiBases[instance] == base->host)
212         {
213             break;
214         }
215     }
216 
217     assert(instance < ARRAY_SIZE(s_dsiBases));
218 
219     return instance;
220 }
221 
222 #if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL) && (FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL)))
DSI_EncodeDphyPllCn(uint8_t cn)223 static uint8_t DSI_EncodeDphyPllCn(uint8_t cn)
224 {
225     assert((cn >= 1U) && (cn <= 32U));
226 
227     if (1U == cn)
228     {
229         return 0x1FU;
230     }
231     else
232     {
233         return (uint8_t)((0x65BD44E0UL >> ((uint32_t)cn - 2U)) & 0x1FU);
234     }
235 }
236 
DSI_EncodeDphyPllCm(uint8_t cm)237 static uint8_t DSI_EncodeDphyPllCm(uint8_t cm)
238 {
239     assert(cm >= 16U);
240 
241     if (cm <= 31U)
242     {
243         return 0xE0U | cm;
244     }
245     else if (cm <= 63U)
246     {
247         return 0xC0U | (cm & 0x1FU);
248     }
249     else if (cm <= 127U)
250     {
251         return 0x80U | (cm & 0x3FU);
252     }
253     else
254     {
255         return cm & 0xCFU;
256     }
257 }
258 
DSI_DphyGetPllDivider(uint32_t * cn,uint32_t * cm,uint32_t * co,uint32_t refClkFreq_Hz,uint32_t desiredOutFreq_Hz)259 static uint32_t DSI_DphyGetPllDivider(
260     uint32_t *cn, uint32_t *cm, uint32_t *co, uint32_t refClkFreq_Hz, uint32_t desiredOutFreq_Hz)
261 {
262     uint32_t cnCur, cmCur, coShiftCur, pllFreqCur, diffCur, vcoFreq, refClk_CN;
263     uint32_t diff             = 0xFFFFFFFFU;
264     uint32_t pllFreqCandidate = 0U;
265 
266     /* CO available values are 1, 2, 4, 8, so the shift values are 0, 1, 2, 3.  */
267     for (coShiftCur = 0U; coShiftCur <= 3U; coShiftCur++)
268     {
269         /* Desired VCO output frequency. */
270         vcoFreq = desiredOutFreq_Hz << coShiftCur;
271 
272         /* If desired VCO output frequency is too small, try larger CO value. */
273         if (vcoFreq < DSI_DPHY_PLL_VCO_MIN)
274         {
275             continue;
276         }
277 
278         /* If desired VCO output frequency is too large, search finished. */
279         if (vcoFreq > DSI_DPHY_PLL_VCO_MAX)
280         {
281             break;
282         }
283 
284         /* Now search the best CN and CM to generate disired VCO output frequency. */
285         for (cnCur = DSI_DPHY_PLL_CN_MIN; cnCur <= DSI_DPHY_PLL_CN_MAX; cnCur++)
286         {
287             /* REF_CLK / CN. */
288             refClk_CN = refClkFreq_Hz / cnCur;
289 
290             /* If desired REF_CLK / CN frequency is too large, try larger CN value. */
291             if (refClk_CN > DSI_DPHY_PLL_REFCLK_CN_MAX)
292             {
293                 continue;
294             }
295 
296             /* If desired REF_CLK / CN frequency is too small, stop search. */
297             if (refClk_CN < DSI_DPHY_PLL_REFCLK_CN_MIN)
298             {
299                 break;
300             }
301 
302             /* Get the CM most close. */
303             cmCur = (vcoFreq + (refClk_CN / 2U)) / refClk_CN;
304 
305             /* If calculated value is (DSI_DPHY_PLL_CM_MAX + 1), use DSI_DPHY_PLL_CM_MAX. */
306             if ((DSI_DPHY_PLL_CM_MAX + 1U) == cmCur)
307             {
308                 cmCur = DSI_DPHY_PLL_CM_MAX;
309             }
310 
311             if ((cmCur < DSI_DPHY_PLL_CM_MIN) || (cmCur > DSI_DPHY_PLL_CM_MAX))
312             {
313                 continue;
314             }
315 
316             /* Output frequency using current dividers. */
317             pllFreqCur = (refClk_CN * cmCur) >> coShiftCur;
318 
319             diffCur =
320                 (pllFreqCur > desiredOutFreq_Hz) ? (pllFreqCur - desiredOutFreq_Hz) : (desiredOutFreq_Hz - pllFreqCur);
321 
322             /* If the dividers is better. */
323             if (diffCur < diff)
324             {
325                 diff             = diffCur;
326                 *cm              = cmCur;
327                 *cn              = cnCur;
328                 *co              = coShiftCur;
329                 pllFreqCandidate = pllFreqCur;
330 
331                 /* If the output PLL frequency is exactly the disired value, return directly. */
332                 if (0U == diff)
333                 {
334                     return pllFreqCandidate;
335                 }
336             }
337         }
338     }
339 
340     return pllFreqCandidate;
341 }
342 #endif
343 
DSI_ApbClearRxFifo(const MIPI_DSI_Type * base)344 static void DSI_ApbClearRxFifo(const MIPI_DSI_Type *base)
345 {
346     volatile uint32_t dummy;
347     uint32_t level = base->apb->PKT_FIFO_RD_LEVEL;
348 
349     while (0U != (level--))
350     {
351         dummy = base->apb->PKT_RX_PAYLOAD;
352     }
353 
354     (void)dummy;
355 }
356 
357 /*!
358  * brief Initializes an MIPI DSI host with the user configuration.
359  *
360  * This function initializes the MIPI DSI host with the configuration, it should
361  * be called first before other MIPI DSI driver functions.
362  *
363  * param base MIPI DSI host peripheral base address.
364  * param config Pointer to a user-defined configuration structure.
365  */
DSI_Init(const MIPI_DSI_Type * base,const dsi_config_t * config)366 void DSI_Init(const MIPI_DSI_Type *base, const dsi_config_t *config)
367 {
368     assert(config);
369 
370 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
371     (void)CLOCK_EnableClock(s_dsiClocks[DSI_GetInstance(base)]);
372 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
373 
374     DSI_HOST_Type *host = base->host;
375 
376 #if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && FSL_FEATURE_DSI_CSR_OFFSET)
377     MIPI_DSI_CSR_Type *csr = DSI_GET_CSR(base);
378     if (config->enableTxUlps)
379     {
380         MIPI_DSI_CSR_ULPS_CTRL(csr) = MIPI_DSI_CSR_ULPS_CTRL_ULPS_MASK;
381     }
382     else
383     {
384         MIPI_DSI_CSR_ULPS_CTRL(csr) = 0U;
385     }
386 #endif
387 
388     host->CFG_NUM_LANES = config->numLanes - 1UL;
389 
390     if (config->enableNonContinuousHsClk)
391     {
392         host->CFG_NONCONTINUOUS_CLK = 0x01U;
393     }
394     else
395     {
396         host->CFG_NONCONTINUOUS_CLK = 0x00U;
397     }
398 
399     if (config->autoInsertEoTp)
400     {
401         host->CFG_AUTOINSERT_EOTP = 0x01U;
402     }
403     else
404     {
405         host->CFG_AUTOINSERT_EOTP = 0x00U;
406     }
407 
408     host->CFG_EXTRA_CMDS_AFTER_EOTP = config->numExtraEoTp;
409     host->CFG_HTX_TO_COUNT          = config->htxTo_ByteClk;
410     host->CFG_LRX_H_TO_COUNT        = config->lrxHostTo_ByteClk;
411     host->CFG_BTA_H_TO_COUNT        = config->btaTo_ByteClk;
412 
413     DSI_ApbClearRxFifo(base);
414 
415     /* Disable all interrupts by default, user could enable
416      * the desired interrupts later.
417      */
418     base->apb->IRQ_MASK  = 0xFFFFFFFFU;
419     base->apb->IRQ_MASK2 = 0xFFFFFFFFU;
420 }
421 
422 /*!
423  * brief Deinitializes an MIPI DSI host.
424  *
425  * This function should be called after all bother MIPI DSI driver functions.
426  *
427  * param base MIPI DSI host peripheral base address.
428  */
DSI_Deinit(const MIPI_DSI_Type * base)429 void DSI_Deinit(const MIPI_DSI_Type *base)
430 {
431 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
432     (void)CLOCK_DisableClock(s_dsiClocks[DSI_GetInstance(base)]);
433 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
434 }
435 
436 /*!
437  * brief Get the default configuration to initialize the MIPI DSI host.
438  *
439  * The default value is:
440  * code
441     config->numLanes = 4;
442     config->enableNonContinuousHsClk = false;
443     config->enableTxUlps = false;
444     config->autoInsertEoTp = true;
445     config->numExtraEoTp = 0;
446     config->htxTo_ByteClk = 0;
447     config->lrxHostTo_ByteClk = 0;
448     config->btaTo_ByteClk = 0;
449    endcode
450  *
451  * param config Pointer to a user-defined configuration structure.
452  */
DSI_GetDefaultConfig(dsi_config_t * config)453 void DSI_GetDefaultConfig(dsi_config_t *config)
454 {
455     assert(config);
456 
457     /* Initializes the configure structure to zero. */
458     (void)memset(config, 0, sizeof(*config));
459 
460     config->numLanes                 = 4;
461     config->enableNonContinuousHsClk = false;
462     config->enableTxUlps             = false;
463     config->autoInsertEoTp           = true;
464     config->numExtraEoTp             = 0;
465     config->htxTo_ByteClk            = 0;
466     config->lrxHostTo_ByteClk        = 0;
467     config->btaTo_ByteClk            = 0;
468 }
469 
470 /*!
471  * brief Configure the DPI interface core.
472  *
473  * This function sets the DPI interface configuration, it should be used in
474  * video mode.
475  *
476  * param base MIPI DSI host peripheral base address.
477  * param config Pointer to the DPI interface configuration.
478  * param numLanes Lane number, should be same with the setting in ref dsi_dpi_config_t.
479  * param dpiPixelClkFreq_Hz The DPI pixel clock frequency in Hz.
480  * param dsiHsBitClkFreq_Hz The DSI high speed bit clock frequency in Hz. It is
481  * the same with DPHY PLL output.
482  */
DSI_SetDpiConfig(const MIPI_DSI_Type * base,const dsi_dpi_config_t * config,uint8_t numLanes,uint32_t dpiPixelClkFreq_Hz,uint32_t dsiHsBitClkFreq_Hz)483 void DSI_SetDpiConfig(const MIPI_DSI_Type *base,
484                       const dsi_dpi_config_t *config,
485                       uint8_t numLanes,
486                       uint32_t dpiPixelClkFreq_Hz,
487                       uint32_t dsiHsBitClkFreq_Hz)
488 {
489     assert(config);
490 
491     /* coefficient DPI event size to number of DSI bytes. */
492     uint32_t coff = (numLanes * dsiHsBitClkFreq_Hz) / (dpiPixelClkFreq_Hz * 8U);
493 
494     DSI_HOST_DPI_INTFC_Type *dpi = base->dpi;
495 
496 #if (defined(FSL_FEATURE_DSI_CSR_OFFSET) && FSL_FEATURE_DSI_CSR_OFFSET)
497     MIPI_DSI_CSR_Type *csr    = DSI_GET_CSR(base);
498     MIPI_DSI_CSR_PXL2DPI(csr) = (uint32_t)config->dpiColorCoding;
499 #endif
500 
501     dpi->PIXEL_PAYLOAD_SIZE     = config->pixelPayloadSize;
502     dpi->INTERFACE_COLOR_CODING = (uint32_t)config->dpiColorCoding;
503     dpi->PIXEL_FORMAT           = (uint32_t)config->pixelPacket;
504     dpi->VIDEO_MODE             = (uint32_t)config->videoMode;
505 
506     if (kDSI_DpiBllpLowPower == config->bllpMode)
507     {
508         dpi->BLLP_MODE         = 0x1U;
509         dpi->USE_NULL_PKT_BLLP = 0x0U;
510     }
511     else if (kDSI_DpiBllpBlanking == config->bllpMode)
512     {
513         dpi->BLLP_MODE         = 0x0U;
514         dpi->USE_NULL_PKT_BLLP = 0x0U;
515     }
516     else
517     {
518         dpi->BLLP_MODE         = 0x0U;
519         dpi->USE_NULL_PKT_BLLP = 0x1U;
520     }
521 
522     if (0U != (config->polarityFlags & (uint32_t)kDSI_DpiVsyncActiveHigh))
523     {
524         dpi->VSYNC_POLARITY = 0x01U;
525     }
526     else
527     {
528         dpi->VSYNC_POLARITY = 0x00U;
529     }
530 
531     if (0U != (config->polarityFlags & (uint32_t)kDSI_DpiHsyncActiveHigh))
532     {
533         dpi->HSYNC_POLARITY = 0x01U;
534     }
535     else
536     {
537         dpi->HSYNC_POLARITY = 0x00U;
538     }
539 
540     if (kDSI_DpiNonBurstWithSyncPulse == config->videoMode)
541     {
542         dpi->HFP                   = config->hfp - DSI_HFP_OVERHEAD_BYTE;
543         dpi->HBP                   = config->hbp - DSI_HBP_OVERHEAD_BYTE;
544         dpi->HSA                   = config->hsw - DSI_HSA_OVERHEAD_BYTE;
545         dpi->PIXEL_FIFO_SEND_LEVEL = 8;
546     }
547     else
548     {
549         dpi->HFP                   = config->hfp * coff;
550         dpi->HBP                   = config->hbp * coff;
551         dpi->HSA                   = config->hsw * coff;
552         dpi->PIXEL_FIFO_SEND_LEVEL = config->pixelPayloadSize;
553     }
554 
555     dpi->VBP = config->vbp;
556     dpi->VFP = config->vfp;
557 
558     dpi->VACTIVE = config->panelHeight - 1UL;
559 
560     /* TODO: Configure VC if it is available. */
561 }
562 
563 /*!
564  * brief Initializes the D-PHY
565  *
566  * This function configures the D-PHY timing and setups the D-PHY PLL based on
567  * user configuration. The configuration structure could be got by the function
568  * ref DSI_GetDphyDefaultConfig.
569  *
570  * param base MIPI DSI host peripheral base address.
571  * param config Pointer to the D-PHY configuration.
572  * param refClkFreq_Hz The REFCLK frequency in Hz.
573  * return The actual D-PHY PLL output frequency. If could not configure the
574  * PLL to the target frequency, the return value is 0.
575  */
DSI_InitDphy(const MIPI_DSI_Type * base,const dsi_dphy_config_t * config,uint32_t refClkFreq_Hz)576 uint32_t DSI_InitDphy(const MIPI_DSI_Type *base, const dsi_dphy_config_t *config, uint32_t refClkFreq_Hz)
577 {
578     assert(config);
579 
580     DSI_HOST_NXP_FDSOI28_DPHY_INTFC_Type *dphy = base->dphy;
581     DSI_HOST_Type *host                        = base->host;
582 
583 #if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL) && (FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL)))
584     uint32_t cn, cm, co, outputPllFreq;
585 
586     outputPllFreq = DSI_DphyGetPllDivider(&cn, &cm, &co, refClkFreq_Hz, config->txHsBitClk_Hz);
587 
588     /* If could not find dividers for the output PLL frequency. */
589     if (0U == outputPllFreq)
590     {
591         return 0U;
592     }
593 
594     /* Set the DPHY parameters. */
595     dphy->CN = (uint32_t)DSI_EncodeDphyPllCn((uint8_t)cn);
596     dphy->CM = (uint32_t)DSI_EncodeDphyPllCm((uint8_t)cm);
597     dphy->CO = co;
598 #endif
599 
600     /* Set the timing parameters. */
601     dphy->M_PRG_HS_PREPARE  = (uint32_t)config->tHsPrepare_HalfEscClk - DSI_THS_PREPARE_HALF_ESC_CLK_BASE;
602     dphy->MC_PRG_HS_PREPARE = (uint32_t)config->tClkPrepare_HalfEscClk - DSI_TCLK_PREPARE_HALF_ESC_CLK_BASE;
603     dphy->M_PRG_HS_ZERO     = (uint32_t)config->tHsZero_ByteClk - DSI_THS_ZERO_BYTE_CLK_BASE;
604     dphy->MC_PRG_HS_ZERO    = (uint32_t)config->tClkZero_ByteClk - DSI_TCLK_ZERO_BYTE_CLK_BASE;
605     dphy->M_PRG_HS_TRAIL    = config->tHsTrail_ByteClk;
606     dphy->MC_PRG_HS_TRAIL   = config->tClkTrail_ByteClk;
607 
608     host->CFG_T_PRE   = config->tClkPre_ByteClk;
609     host->CFG_T_POST  = config->tClkPost_ByteClk;
610     host->CFG_TX_GAP  = config->tHsExit_ByteClk;
611     host->CFG_TWAKEUP = config->tWakeup_EscClk;
612 
613 #if defined(MIPI_RTERM_SEL_dphy_rterm_sel_MASK)
614     dphy->RTERM_SEL = MIPI_RTERM_SEL_dphy_rterm_sel_MASK;
615 #endif
616 #if defined(MIPI_TX_RCAL_dphy_tx_rcal_MASK)
617     dphy->TX_RCAL = 1;
618 #endif
619     dphy->RXLPRP = 1;
620     dphy->RXCDRP = 1;
621 
622     /* Auto power down the inactive lanes. */
623     dphy->AUTO_PD_EN = 0x1U;
624 
625     dphy->TST = 0x25U;
626 
627 #if !((defined(FSL_FEATURE_MIPI_NO_PLL) && (FSL_FEATURE_MIPI_DSI_HOST_NO_PLL)))
628     /* Power up the PLL. */
629     dphy->PD_PLL = 0U;
630 
631     /* Wait for the PLL lock. */
632     while (0UL == dphy->LOCK)
633     {
634     }
635 #endif
636 
637     /* Power up the DPHY. */
638     dphy->PD_TX = 0U;
639 
640 #if !((defined(FSL_FEATURE_MIPI_NO_PLL) && (FSL_FEATURE_MIPI_DSI_HOST_NO_PLL)))
641     return outputPllFreq;
642 #else
643     return config->txHsBitClk_Hz;
644 #endif
645 }
646 
647 /*!
648  * brief Deinitializes the D-PHY
649  *
650  * Power down the D-PHY PLL and shut down D-PHY.
651  *
652  * param base MIPI DSI host peripheral base address.
653  */
DSI_DeinitDphy(const MIPI_DSI_Type * base)654 void DSI_DeinitDphy(const MIPI_DSI_Type *base)
655 {
656 #if !((defined(FSL_FEATURE_MIPI_NO_DPHY_PLL) && (FSL_FEATURE_MIPI_DSI_HOST_NO_DPHY_PLL)))
657     /* Power down the PLL. */
658     base->dphy->PD_PLL = 1U;
659 #endif
660 
661     /* Power down the DPHY. */
662     base->dphy->PD_TX = 1U;
663 }
664 
665 /*!
666  * brief Get the default D-PHY configuration.
667  *
668  * Gets the default D-PHY configuration, the timing parameters are set according
669  * to D-PHY specification. User could use the configuration directly, or change
670  * some parameters according to the special device.
671  *
672  * param config Pointer to the D-PHY configuration.
673  * param txHsBitClk_Hz High speed bit clock in Hz.
674  * param txEscClk_Hz Esc clock in Hz.
675  */
DSI_GetDphyDefaultConfig(dsi_dphy_config_t * config,uint32_t txHsBitClk_Hz,uint32_t txEscClk_Hz)676 void DSI_GetDphyDefaultConfig(dsi_dphy_config_t *config, uint32_t txHsBitClk_Hz, uint32_t txEscClk_Hz)
677 {
678     assert(config);
679 
680     /* Initializes the configure structure to zero. */
681     (void)memset(config, 0, sizeof(*config));
682 
683     uint32_t byteClkFreq_kHz = txHsBitClk_Hz / 8U / 1000U;
684     uint32_t txEscClk_kHz    = txEscClk_Hz / 1000U;
685 
686     config->txHsBitClk_Hz = txHsBitClk_Hz;
687 
688     /* THS-EXIT in byte clock. At least 100ns. */
689     config->tHsExit_ByteClk = (uint8_t)(DSI_NS_TO_BYTE_CLK(100U, byteClkFreq_kHz) + 1U);
690 
691     /* T-WAKEUP. At least 1ms. */
692     config->tWakeup_EscClk = txEscClk_Hz / 1000U + 1U;
693 
694     /* THS-PREPARE. 40ns+4*UI to 85ns+6*UI. */
695     config->tHsPrepare_HalfEscClk =
696         (uint8_t)((40U * txEscClk_kHz * 2U) / 1000000U + (4U * txEscClk_Hz * 2U / txHsBitClk_Hz) + 1U);
697     if (config->tHsPrepare_HalfEscClk < DSI_THS_PREPARE_HALF_ESC_CLK_MIN)
698     {
699         config->tHsPrepare_HalfEscClk = DSI_THS_PREPARE_HALF_ESC_CLK_MIN;
700     }
701     else if (config->tHsPrepare_HalfEscClk > DSI_THS_PREPARE_HALF_ESC_CLK_MAX)
702     {
703         config->tHsPrepare_HalfEscClk = DSI_THS_PREPARE_HALF_ESC_CLK_MAX;
704     }
705     else
706     {
707         /* For MISRA check. */
708     }
709 
710     /* TCLK-PREPARE. 38ns to 95ns. */
711     config->tClkPrepare_HalfEscClk = (uint8_t)((38U * txEscClk_kHz * 2U) / 1000000U + 1U);
712     if (config->tClkPrepare_HalfEscClk < DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN)
713     {
714         config->tClkPrepare_HalfEscClk = DSI_TCLK_PREPARE_HALF_ESC_CLK_MIN;
715     }
716     else if (config->tClkPrepare_HalfEscClk > DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX)
717     {
718         config->tClkPrepare_HalfEscClk = DSI_TCLK_PREPARE_HALF_ESC_CLK_MAX;
719     }
720     else
721     {
722         /* For MISRA check. */
723     }
724 
725     /* THS-ZERO, At least 105ns+6*UI. */
726     config->tHsZero_ByteClk = (uint8_t)(DSI_NS_UI_TO_BYTE_CLK(105U, 6U, byteClkFreq_kHz) + 1U);
727     if (config->tHsZero_ByteClk < DSI_THS_ZERO_BYTE_CLK_BASE)
728     {
729         config->tHsZero_ByteClk = DSI_THS_ZERO_BYTE_CLK_BASE;
730     }
731 
732     /* TCLK-ZERO, At least 262ns. */
733     config->tClkZero_ByteClk = (uint8_t)(DSI_NS_TO_BYTE_CLK(262U, byteClkFreq_kHz) + 1U);
734     if (config->tClkZero_ByteClk < DSI_TCLK_ZERO_BYTE_CLK_BASE)
735     {
736         config->tClkZero_ByteClk = DSI_TCLK_ZERO_BYTE_CLK_BASE;
737     }
738 
739     /* THS-TRAIL, 60ns+4*UI to 105ns+12UI. */
740     /* Due to IP design, extra 4*UI should be added. */
741     config->tHsTrail_ByteClk = (uint8_t)(DSI_NS_UI_TO_BYTE_CLK(60U, 8U, byteClkFreq_kHz) + 1U);
742 
743     /* TCLK-TRAIL, at least 60ns. */
744     /* Due to IP design, extra 4*UI should be added. */
745     config->tClkTrail_ByteClk = (uint8_t)(DSI_NS_UI_TO_BYTE_CLK(60U, 4U, byteClkFreq_kHz) + 1U);
746 
747     /*
748      * T_LPX + T_CLK-PREPARE + T_CLK-ZERO + T_CLK-PRE
749      * T_LPX >= 50ns
750      * T_CLK-PREPARE >= 38ns
751      * T_CLK-ZERO >= 262ns
752      * T_CLK-PRE >= 8*UI
753      */
754     config->tClkPre_ByteClk =
755         (uint8_t)(DSI_NS_UI_TO_BYTE_CLK(88U, 8U, byteClkFreq_kHz) + 1U) + config->tClkZero_ByteClk;
756 
757     /*
758      * T_CLK-POST + T_CLK-TRAIL
759      * T_CLK-POST >= 60ns + 52*UI.
760      * T_CLK-TRAIL >= 60ns
761      */
762     config->tClkPost_ByteClk =
763         (uint8_t)(DSI_NS_UI_TO_BYTE_CLK(60U, 52U, byteClkFreq_kHz) + 1U) + config->tClkTrail_ByteClk;
764 }
765 
766 /*!
767  * brief Configure the APB packet to send.
768  *
769  * This function configures the next APB packet transfer. After configuration,
770  * the packet transfer could be started with function ref DSI_SendApbPacket.
771  * If the packet is long packet, Use ref DSI_WriteApbTxPayload to fill the payload
772  * before start transfer.
773  *
774  * param base MIPI DSI host peripheral base address.
775  * param wordCount For long packet, this is the byte count of the payload.
776  * For short packet, this is (data1 << 8) | data0.
777  * param virtualChannel Virtual channel.
778  * param dataType The packet data type, (DI).
779  * param flags The transfer control flags, see ref _dsi_transfer_flags.
780  */
DSI_SetApbPacketControl(const MIPI_DSI_Type * base,uint16_t wordCount,uint8_t virtualChannel,dsi_tx_data_type_t dataType,uint8_t flags)781 void DSI_SetApbPacketControl(
782     const MIPI_DSI_Type *base, uint16_t wordCount, uint8_t virtualChannel, dsi_tx_data_type_t dataType, uint8_t flags)
783 {
784     uint32_t pktCtrl = PKT_CONTROL_WORD_COUNT(wordCount) | PKT_CONTROL_HEADER_TYPE(dataType);
785 
786 #if defined(DSI_HOST_PKT_CONTROL_VC)
787     pktCtrl |= DSI_HOST_PKT_CONTROL_VC(virtualChannel);
788 #endif
789 
790     if (0U != (flags & (uint8_t)kDSI_TransferUseHighSpeed))
791     {
792         pktCtrl |= PKT_CONTROL_HS_MASK;
793     }
794 
795     if (0U != (flags & (uint8_t)kDSI_TransferPerformBTA))
796     {
797         pktCtrl |= PKT_CONTROL_BTA_MASK;
798     }
799 
800     base->apb->PKT_CONTROL = pktCtrl;
801 }
802 
803 /*!
804  * brief Fill the long APB packet payload.
805  *
806  * Write the long packet payload to TX FIFO.
807  *
808  * param base MIPI DSI host peripheral base address.
809  * param payload Pointer to the payload.
810  * param payloadSize Payload size in byte.
811  */
DSI_WriteApbTxPayload(const MIPI_DSI_Type * base,const uint8_t * payload,uint16_t payloadSize)812 void DSI_WriteApbTxPayload(const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize)
813 {
814     DSI_WriteApbTxPayloadExt(base, payload, payloadSize, false, 0U);
815 }
816 
DSI_WriteApbTxPayloadExt(const MIPI_DSI_Type * base,const uint8_t * payload,uint16_t payloadSize,bool sendDscCmd,uint8_t dscCmd)817 void DSI_WriteApbTxPayloadExt(
818     const MIPI_DSI_Type *base, const uint8_t *payload, uint16_t payloadSize, bool sendDscCmd, uint8_t dscCmd)
819 {
820     uint32_t firstWord;
821     uint16_t i;
822 
823     DSI_HOST_APB_PKT_IF_Type *apb = base->apb;
824 
825     payloadSize = sendDscCmd ? payloadSize + 1U : payloadSize;
826 
827     assert(payloadSize <= FSL_DSI_TX_MAX_PAYLOAD_BYTE);
828 
829     /* The first 4-byte. */
830     if (sendDscCmd)
831     {
832         firstWord = dscCmd;
833     }
834     else
835     {
836         firstWord = *payload;
837         payload++;
838     }
839 
840     payloadSize--;
841 
842     for (i = 1U; i < 4U; i++)
843     {
844         if (payloadSize > 0U)
845         {
846             firstWord |= ((uint32_t)(*payload) << (i << 3U));
847             payload++;
848             payloadSize--;
849         }
850         else
851         {
852             break;
853         }
854     }
855 
856     apb->TX_PAYLOAD = firstWord;
857 
858     /* Write the payload to the FIFO. */
859     for (i = 0; i < payloadSize / 4U; i++)
860     {
861         apb->TX_PAYLOAD = *(const uint32_t *)(const void *)payload;
862         payload += 4U;
863     }
864 
865     /* Write the remaining data. */
866     switch (payloadSize & 0x03U)
867     {
868         case 3:
869             apb->TX_PAYLOAD = ((uint32_t)payload[2] << 16U) | ((uint32_t)payload[1] << 8U) | payload[0];
870             break;
871         case 2:
872             apb->TX_PAYLOAD = ((uint32_t)payload[1] << 8U) | payload[0];
873             break;
874         case 1:
875             apb->TX_PAYLOAD = payload[0];
876             break;
877         default:
878             /* For MISRA 2012 16.4 */
879             break;
880     }
881 }
882 
DSI_PrepareApbTransfer(const MIPI_DSI_Type * base,dsi_transfer_t * xfer)883 static status_t DSI_PrepareApbTransfer(const MIPI_DSI_Type *base, dsi_transfer_t *xfer)
884 {
885     /* The receive data size should be smaller than the RX FIRO. */
886     assert(xfer->rxDataSize <= FSL_DSI_RX_MAX_PAYLOAD_BYTE);
887     assert(xfer->txDataSize <= FSL_DSI_TX_MAX_PAYLOAD_BYTE);
888 
889     uint8_t txDataIndex;
890     uint16_t wordCount;
891     uint32_t intFlags1, intFlags2;
892     uint32_t txDataSize;
893 
894     if (xfer->rxDataSize > 2U)
895     {
896         return kStatus_DSI_NotSupported;
897     }
898 
899     if (xfer->rxDataSize != 0U)
900     {
901         xfer->flags |= (uint8_t)kDSI_TransferPerformBTA;
902     }
903 
904     /* ========================== Prepare TX. ========================== */
905     /* If xfer->sendDscCmd is true, then the DSC command is not included in the
906        xfer->txData, but specified by xfer->dscCmd.
907      */
908     txDataSize = xfer->sendDscCmd ? (uint32_t)xfer->txDataSize + 1U : (uint32_t)xfer->txDataSize;
909 
910     /* Short packet. */
911     if (txDataSize <= 2U)
912     {
913         if (0U == txDataSize)
914         {
915             wordCount = 0U;
916         }
917         else
918         {
919             txDataIndex = 0;
920 
921             if (xfer->sendDscCmd)
922             {
923                 wordCount = xfer->dscCmd;
924             }
925             else
926             {
927                 wordCount = xfer->txData[txDataIndex++];
928             }
929 
930             if (2U == txDataSize)
931             {
932                 wordCount |= ((uint16_t)xfer->txData[txDataIndex] << 8U);
933             }
934         }
935     }
936     /* Long packet. */
937     else
938     {
939         wordCount = (uint16_t)txDataSize;
940         DSI_WriteApbTxPayloadExt(base, xfer->txData, xfer->txDataSize, xfer->sendDscCmd, xfer->dscCmd);
941     }
942 
943     DSI_SetApbPacketControl(base, wordCount, xfer->virtualChannel, xfer->txDataType, xfer->flags);
944 
945     /* Clear the interrupt flags set by previous transfer. */
946     DSI_GetAndClearInterruptStatus(base, &intFlags1, &intFlags2);
947 
948     return kStatus_Success;
949 }
950 
951 /*!
952  * brief Read the long APB packet payload.
953  *
954  * Read the long packet payload from RX FIFO. This function reads directly but
955  * does not check the RX FIFO status. Upper layer should make sure there are
956  * available data.
957  *
958  * param base MIPI DSI host peripheral base address.
959  * param payload Pointer to the payload.
960  * param payloadSize Payload size in byte.
961  */
DSI_ReadApbRxPayload(const MIPI_DSI_Type * base,uint8_t * payload,uint16_t payloadSize)962 void DSI_ReadApbRxPayload(const MIPI_DSI_Type *base, uint8_t *payload, uint16_t payloadSize)
963 {
964     uint32_t tmp;
965 
966     for (uint16_t i = 0; i < payloadSize / 4U; i++)
967     {
968         tmp        = base->apb->PKT_RX_PAYLOAD;
969         payload[0] = (uint8_t)(tmp & 0xFFU);
970         payload[1] = (uint8_t)((tmp >> 8U) & 0xFFU);
971         payload[2] = (uint8_t)((tmp >> 16U) & 0xFFU);
972         payload[3] = (uint8_t)((tmp >> 24U) & 0xFFU);
973         payload += 4U;
974     }
975 
976     /* Read out the remaining data. */
977     if (0U != (payloadSize & 0x03U))
978     {
979         tmp = base->apb->PKT_RX_PAYLOAD;
980 
981         for (uint16_t i = 0; i < (payloadSize & 0x3U); i++)
982         {
983             payload[i] = (uint8_t)(tmp & 0xFFU);
984             tmp >>= 8U;
985         }
986     }
987 }
988 
989 /*!
990  * brief APB data transfer using blocking method.
991  *
992  * Perform APB data transfer using blocking method. This function waits until all
993  * data send or received, or timeout happens.
994  *
995  * param base MIPI DSI host peripheral base address.
996  * param xfer Pointer to the transfer structure.
997  * retval kStatus_Success Data transfer finished with no error.
998  * retval kStatus_Timeout Transfer failed because of timeout.
999  * retval kStatus_DSI_RxDataError RX data error, user could use ref DSI_GetRxErrorStatus
1000  * to check the error details.
1001  * retval kStatus_DSI_ErrorReportReceived Error Report packet received, user could use
1002  *        ref DSI_GetAndClearHostStatus to check the error report status.
1003  * retval kStatus_DSI_NotSupported Transfer format not supported.
1004  * retval kStatus_DSI_Fail Transfer failed for other reasons.
1005  */
DSI_TransferBlocking(const MIPI_DSI_Type * base,dsi_transfer_t * xfer)1006 status_t DSI_TransferBlocking(const MIPI_DSI_Type *base, dsi_transfer_t *xfer)
1007 {
1008     status_t status;
1009     uint32_t intFlags1Old, intFlags2Old;
1010     uint32_t intFlags1New, intFlags2New;
1011 
1012     DSI_HOST_APB_PKT_IF_Type *apb = base->apb;
1013 
1014     /* Wait for the APB state idle. */
1015     while (0U != (apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
1016     {
1017     }
1018 
1019     status = DSI_PrepareApbTransfer(base, xfer);
1020 
1021     if (kStatus_Success != status)
1022     {
1023         return status;
1024     }
1025 
1026     DSI_SendApbPacket(base);
1027 
1028     /* Make sure the transfer is started. */
1029     while (true)
1030     {
1031         DSI_GetAndClearInterruptStatus(base, &intFlags1Old, &intFlags2Old);
1032 
1033         if (0U != (intFlags1Old & (uint32_t)kDSI_InterruptGroup1ApbNotIdle))
1034         {
1035             break;
1036         }
1037     }
1038 
1039     /* Wait for transfer finished. */
1040     while (true)
1041     {
1042         /* Transfer completed. */
1043         if (0U == (apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
1044         {
1045             break;
1046         }
1047 
1048         /* Time out. */
1049         if (0U != (base->host->RX_ERROR_STATUS &
1050                    ((uint32_t)kDSI_RxErrorHtxTo | (uint32_t)kDSI_RxErrorLrxTo | (uint32_t)kDSI_RxErrorBtaTo)))
1051         {
1052             DSI_GetAndClearInterruptStatus(base, &intFlags1New, &intFlags2New);
1053             return kStatus_Timeout;
1054         }
1055     }
1056 
1057     DSI_GetAndClearInterruptStatus(base, &intFlags1New, &intFlags2New);
1058 
1059     return DSI_HandleResult(base, intFlags1Old | intFlags1New, intFlags2Old | intFlags2New, xfer);
1060 }
1061 
DSI_HandleResult(const MIPI_DSI_Type * base,uint32_t intFlags1,uint32_t intFlags2,dsi_transfer_t * xfer)1062 static status_t DSI_HandleResult(const MIPI_DSI_Type *base,
1063                                  uint32_t intFlags1,
1064                                  uint32_t intFlags2,
1065                                  dsi_transfer_t *xfer)
1066 {
1067     uint32_t rxPktHeader;
1068 
1069     /* If hardware detect timeout. */
1070     if (0U != (((uint32_t)kDSI_InterruptGroup1HtxTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
1071                 (uint32_t)kDSI_InterruptGroup1BtaTo) &
1072                intFlags1))
1073     {
1074         return kStatus_Timeout;
1075     }
1076 
1077     /* If received data error. */
1078     if (0U != (((uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError) & intFlags2))
1079     {
1080         return kStatus_DSI_RxDataError;
1081     }
1082 
1083     /* If BTA is performed. */
1084     if (0U != (xfer->flags & (uint32_t)kDSI_TransferPerformBTA))
1085     {
1086         if (0U != (intFlags1 & DSI_INT_STATUS_ERROR_REPORT_MASK))
1087         {
1088             return kStatus_DSI_ErrorReportReceived;
1089         }
1090 
1091         if (0U != ((uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived & intFlags1))
1092         {
1093             rxPktHeader = DSI_GetRxPacketHeader(base);
1094 
1095             /* If received error report. */
1096             if (kDSI_RxDataAckAndErrorReport == DSI_GetRxPacketType(rxPktHeader))
1097             {
1098                 return kStatus_DSI_ErrorReportReceived;
1099             }
1100             else
1101             {
1102                 /* Only handle short packet, long packet is not supported currently. */
1103                 xfer->rxData[0] = (uint8_t)(rxPktHeader & 0xFFU);
1104 
1105                 if (2U == xfer->rxDataSize)
1106                 {
1107                     xfer->rxData[1] = (uint8_t)((rxPktHeader >> 8U) & 0xFFU);
1108                 }
1109 
1110                 return kStatus_Success;
1111             }
1112         }
1113 
1114         return kStatus_Success;
1115     }
1116     else
1117     {
1118         /* Tx Done. */
1119         if (0U != ((uint32_t)kDSI_InterruptGroup1ApbTxDone & intFlags1))
1120         {
1121             return kStatus_Success;
1122         }
1123     }
1124 
1125     return kStatus_Fail;
1126 }
1127 
1128 /*!
1129  * brief Create the MIPI DSI handle.
1130  *
1131  * This function initializes the MIPI DSI handle which can be used for other transactional APIs.
1132  *
1133  * param base MIPI DSI host peripheral base address.
1134  * param handle Handle pointer.
1135  * param callback Callback function.
1136  * param userData User data.
1137  */
DSI_TransferCreateHandle(const MIPI_DSI_Type * base,dsi_handle_t * handle,dsi_callback_t callback,void * userData)1138 status_t DSI_TransferCreateHandle(const MIPI_DSI_Type *base,
1139                                   dsi_handle_t *handle,
1140                                   dsi_callback_t callback,
1141                                   void *userData)
1142 {
1143     assert(handle);
1144 
1145     uint32_t instance = DSI_GetInstance(base);
1146 
1147     /* Zero the handle */
1148     (void)memset(handle, 0, sizeof(*handle));
1149 
1150     /* Initialize the handle */
1151     s_dsiHandle[instance] = handle;
1152     handle->callback      = callback;
1153     handle->userData      = userData;
1154     handle->isBusy        = false;
1155     handle->dsi           = base;
1156     s_dsiIsr              = DSI_TransferHandleIRQ;
1157 
1158 #if defined(MIPI_IRQS)
1159     /* Enable interrupt in NVIC. */
1160     EnableIRQ(s_dsiIRQ[instance]);
1161 #endif
1162 
1163     return kStatus_Success;
1164 }
1165 
1166 /*!
1167  * brief APB data transfer using interrupt method.
1168  *
1169  * Perform APB data transfer using interrupt method, when transfer finished,
1170  * upper layer could be informed through callback function.
1171  *
1172  * param base MIPI DSI host peripheral base address.
1173  * param handle pointer to dsi_handle_t structure which stores the transfer state.
1174  * param xfer Pointer to the transfer structure.
1175  *
1176  * retval kStatus_Success Data transfer started successfully.
1177  * retval kStatus_DSI_Busy Failed to start transfer because DSI is busy with pervious transfer.
1178  * retval kStatus_DSI_NotSupported Transfer format not supported.
1179  */
DSI_TransferNonBlocking(const MIPI_DSI_Type * base,dsi_handle_t * handle,dsi_transfer_t * xfer)1180 status_t DSI_TransferNonBlocking(const MIPI_DSI_Type *base, dsi_handle_t *handle, dsi_transfer_t *xfer)
1181 {
1182     status_t status;
1183 
1184     if ((handle->isBusy) || (0U != (base->apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle)))
1185     {
1186         return kStatus_DSI_Busy;
1187     }
1188 
1189     handle->xfer = *xfer;
1190 
1191     status = DSI_PrepareApbTransfer(base, &handle->xfer);
1192 
1193     if (kStatus_Success != status)
1194     {
1195         return status;
1196     }
1197 
1198     DSI_SendApbPacket(base);
1199     handle->isBusy = true;
1200 
1201     /* Enable the interrupts. */
1202     if (0U != (handle->xfer.flags & (uint32_t)kDSI_TransferPerformBTA))
1203     {
1204         DSI_EnableInterrupts(base,
1205                              DSI_INT_STATUS_TRIGGER_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
1206                                  (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived |
1207                                  (uint32_t)kDSI_InterruptGroup1BtaTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
1208                                  (uint32_t)kDSI_InterruptGroup1HtxTo | (uint32_t)kDSI_InterruptGroup1AckTriggerReceived,
1209                              (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
1210     }
1211     else
1212     {
1213         DSI_EnableInterrupts(base, (uint32_t)kDSI_InterruptGroup1ApbTxDone | (uint32_t)kDSI_InterruptGroup1HtxTo, 0U);
1214     }
1215 
1216     return kStatus_Success;
1217 }
1218 
1219 /*!
1220  * brief Abort current APB data transfer.
1221  *
1222  * param base MIPI DSI host peripheral base address.
1223  * param handle pointer to dsi_handle_t structure which stores the transfer state.
1224  */
DSI_TransferAbort(const MIPI_DSI_Type * base,dsi_handle_t * handle)1225 void DSI_TransferAbort(const MIPI_DSI_Type *base, dsi_handle_t *handle)
1226 {
1227     assert(handle);
1228 
1229     if (handle->isBusy)
1230     {
1231         /* Disable the interrupts. */
1232         DSI_DisableInterrupts(base,
1233                               (uint32_t)kDSI_InterruptGroup1ApbTxDone | DSI_INT_STATUS_TRIGGER_MASK |
1234                                   DSI_INT_STATUS_ERROR_REPORT_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
1235                                   (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived |
1236                                   (uint32_t)kDSI_InterruptGroup1BtaTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
1237                                   (uint32_t)kDSI_InterruptGroup1HtxTo,
1238                               (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
1239 
1240         /* Reset transfer info. */
1241         (void)memset(&handle->xfer, 0, sizeof(handle->xfer));
1242 
1243         /* Reset the state to idle. */
1244         handle->isBusy = false;
1245     }
1246 }
1247 
1248 /*!
1249  * @brief Interrupt handler for the DSI.
1250  *
1251  * @param base MIPI DSI host peripheral base address.
1252  * @param handle pointer to dsi_handle_t structure which stores the transfer state.
1253  */
1254 /*!
1255  * brief Interrupt handler for the DSI.
1256  *
1257  * param base MIPI DSI host peripheral base address.
1258  * param handle pointer to dsi_handle_t structure which stores the transfer state.
1259  */
DSI_TransferHandleIRQ(const MIPI_DSI_Type * base,dsi_handle_t * handle)1260 void DSI_TransferHandleIRQ(const MIPI_DSI_Type *base, dsi_handle_t *handle)
1261 {
1262     assert(handle);
1263 
1264     status_t status;
1265     uint32_t intFlags1, intFlags2;
1266     uint32_t timeout;
1267     base = handle->dsi;
1268 
1269     /* If no transfer in progress, return directly. */
1270     if (!handle->isBusy)
1271     {
1272         return;
1273     }
1274 
1275     /* Make sure the transfer is completed. */
1276     timeout = FSL_MIPI_DSI_IDLE_TIMEOUT;
1277     while (0U != (timeout--))
1278     {
1279         if (0U == (base->apb->PKT_STATUS & (uint32_t)kDSI_ApbNotIdle))
1280         {
1281             break;
1282         }
1283     }
1284 
1285     if (0U == timeout)
1286     {
1287         DSI_TransferAbort(base, handle);
1288         status = kStatus_Timeout;
1289     }
1290     else
1291     {
1292         /* Disable the interrupts. */
1293         DSI_DisableInterrupts(base,
1294                               (uint32_t)kDSI_InterruptGroup1ApbTxDone | DSI_INT_STATUS_TRIGGER_MASK |
1295                                   DSI_INT_STATUS_ERROR_REPORT_MASK | (uint32_t)kDSI_InterruptGroup1ApbRxHeaderReceived |
1296                                   (uint32_t)kDSI_InterruptGroup1ApbRxPacketReceived |
1297                                   (uint32_t)kDSI_InterruptGroup1BtaTo | (uint32_t)kDSI_InterruptGroup1LrxTo |
1298                                   (uint32_t)kDSI_InterruptGroup1HtxTo,
1299                               (uint32_t)kDSI_InterruptGroup2EccMultiBit | (uint32_t)kDSI_InterruptGroup2CrcError);
1300 
1301         DSI_GetAndClearInterruptStatus(base, &intFlags1, &intFlags2);
1302 
1303         status         = DSI_HandleResult(base, intFlags1, intFlags2, &handle->xfer);
1304         handle->isBusy = false;
1305     }
1306 
1307     if (NULL != handle->callback)
1308     {
1309         handle->callback(base, handle, status, handle->userData);
1310     }
1311 }
1312 
1313 #if defined(DSI_HOST)
1314 void MIPI_DriverIRQHandler(void);
MIPI_DriverIRQHandler(void)1315 void MIPI_DriverIRQHandler(void)
1316 {
1317     /* The first parameter is not used, use the peripheral address defined in
1318      * handle.
1319      */
1320     s_dsiIsr(NULL, s_dsiHandle[0]);
1321 }
1322 #endif
1323