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