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