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