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