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