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