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