1 /*
2 * Copyright 2019-2021, 2023 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7 #include <rtthread.h>
8 #include "display_support.h"
9 #include "fsl_gpio.h"
10 #include "fsl_mipi_dsi.h"
11
12 /*******************************************************************************
13 * Definitions
14 ******************************************************************************/
15
16 /*
17 * The DPHY bit clock must be fast enough to send out the pixels, it should be
18 * larger than:
19 *
20 * (Pixel clock * bit per output pixel) / number of MIPI data lane
21 *
22 * Here the desired DPHY bit clock multiplied by ( 9 / 8 = 1.125) to ensure
23 * it is fast enough.
24 */
25 #define DEMO_MIPI_DPHY_BIT_CLK_ENLARGE(origin) (((origin) / 8) * 9)
26
27 /*******************************************************************************
28 * Prototypes
29 ******************************************************************************/
30
31 static void BOARD_PullPanelResetPin(bool pullUp);
32 static void BOARD_PullPanelPowerPin(bool pullUp);
33 static void BOARD_InitLcdifClock(void);
34 static void BOARD_InitMipiDsiClock(void);
35 static status_t BOARD_DSI_Transfer(dsi_transfer_t *xfer);
36
37 /*******************************************************************************
38 * Variables
39 ******************************************************************************/
40
41 static uint32_t mipiDsiTxEscClkFreq_Hz;
42 static uint32_t mipiDsiDphyBitClkFreq_Hz;
43 static uint32_t mipiDsiDphyRefClkFreq_Hz;
44 static uint32_t mipiDsiDpiClkFreq_Hz;
45
46 const MIPI_DSI_Type g_mipiDsi = {
47 .host = DSI_HOST,
48 .apb = DSI_HOST_APB_PKT_IF,
49 .dpi = DSI_HOST_DPI_INTFC,
50 .dphy = DSI_HOST_DPHY_INTFC,
51 };
52
53 #if defined(DISPLAY_USING_RK055AHD091)
54
55 static mipi_dsi_device_t dsiDevice = {
56 .virtualChannel = 0,
57 .xferFunc = BOARD_DSI_Transfer,
58 };
59
60 static const rm68200_resource_t rm68200Resource = {
61 .dsiDevice = &dsiDevice,
62 .pullResetPin = BOARD_PullPanelResetPin,
63 .pullPowerPin = BOARD_PullPanelPowerPin,
64 };
65
66 static display_handle_t rm68200Handle = {
67 .resource = &rm68200Resource,
68 .ops = &rm68200_ops,
69 };
70
71 #elif defined(DISPLAY_USING_RK055MHD091)
72
73 static mipi_dsi_device_t dsiDevice = {
74 .virtualChannel = 0,
75 .xferFunc = BOARD_DSI_Transfer,
76 };
77
78 static const hx8394_resource_t hx8394Resource = {
79 .dsiDevice = &dsiDevice,
80 .pullResetPin = BOARD_PullPanelResetPin,
81 .pullPowerPin = BOARD_PullPanelPowerPin,
82 };
83
84 static display_handle_t hx8394Handle = {
85 .resource = &hx8394Resource,
86 .ops = &hx8394_ops,
87 };
88
89 #elif defined(DISPLAY_USING_RK055IQH091)
90
91 static mipi_dsi_device_t dsiDevice = {
92 .virtualChannel = 0,
93 .xferFunc = BOARD_DSI_Transfer,
94 };
95
96 static const rm68191_resource_t rm68191Resource = {
97 .dsiDevice = &dsiDevice,
98 .pullResetPin = BOARD_PullPanelResetPin,
99 .pullPowerPin = BOARD_PullPanelPowerPin,
100 };
101
102 static display_handle_t rm68191Handle = {
103 .resource = &rm68191Resource,
104 .ops = &rm68191_ops,
105 };
106
107 #endif
108
109 #if defined(BSP_USING_LCDIFV2)
110 static dc_fb_lcdifv2_handle_t s_dcFbLcdifv2Handle = {0};
111
112 static const dc_fb_lcdifv2_config_t s_dcFbLcdifv2Config = {
113 .lcdifv2 = DEMO_LCDIF,
114 .width = LCD_MIPI_WIDTH,
115 .height = LCD_MIPI_HEIGHT,
116 .hsw = LCD_MIPI_HSW,
117 .hfp = LCD_MIPI_HFP,
118 .hbp = LCD_MIPI_HBP,
119 .vsw = LCD_MIPI_VSW,
120 .vfp = LCD_MIPI_VFP,
121 .vbp = LCD_MIPI_VBP,
122 .polarityFlags = DEMO_LCDIF_POL_FLAGS,
123 .lineOrder = kLCDIFV2_LineOrderRGB,
124 /* CM4 is domain 1, CM7 is domain 0. */
125 #if (__CORTEX_M <= 4)
126 .domain = 1,
127 #else
128 .domain = 0,
129 #endif
130 };
131
132 const dc_fb_t g_dc = {
133 .ops = &g_dcFbOpsLcdifv2,
134 .prvData = &s_dcFbLcdifv2Handle,
135 .config = &s_dcFbLcdifv2Config,
136 };
137
138 #elif defined(BSP_USING_ELCDIF)
139
140 dc_fb_elcdif_handle_t s_dcFbElcdifHandle = {0}; /* The handle must be initialized to 0. */
141
142 const dc_fb_elcdif_config_t s_dcFbElcdifConfig = {
143 .elcdif = DEMO_LCDIF,
144 .width = LCD_MIPI_WIDTH,
145 .height = LCD_MIPI_HEIGHT,
146 .hsw = LCD_MIPI_HSW,
147 .hfp = LCD_MIPI_HFP,
148 .hbp = LCD_MIPI_HBP,
149 .vsw = LCD_MIPI_VSW,
150 .vfp = LCD_MIPI_VFP,
151 .vbp = LCD_MIPI_VBP,
152 .polarityFlags = DEMO_LCDIF_POL_FLAGS,
153 #if (!DEMO_USE_XRGB8888) && (DEMO_USE_LUT8)
154 .dataBus = kELCDIF_DataBus8Bit,
155 #else
156 .dataBus = kELCDIF_DataBus24Bit,
157 #endif
158 };
159
160 const dc_fb_t g_dc = {
161 .ops = &g_dcFbOpsElcdif,
162 .prvData = &s_dcFbElcdifHandle,
163 .config = &s_dcFbElcdifConfig,
164 };
165 #endif
166
167 /*******************************************************************************
168 * Code
169 ******************************************************************************/
170
BOARD_PullPanelResetPin(bool pullUp)171 static void BOARD_PullPanelResetPin(bool pullUp)
172 {
173 if (pullUp)
174 {
175 GPIO_PinWrite(BOARD_MIPI_PANEL_RST_GPIO, BOARD_MIPI_PANEL_RST_PIN, 1);
176 }
177 else
178 {
179 GPIO_PinWrite(BOARD_MIPI_PANEL_RST_GPIO, BOARD_MIPI_PANEL_RST_PIN, 0);
180 }
181 }
182
BOARD_PullPanelPowerPin(bool pullUp)183 static void BOARD_PullPanelPowerPin(bool pullUp)
184 {
185 if (pullUp)
186 {
187 GPIO_PinWrite(BOARD_MIPI_PANEL_POWER_GPIO, BOARD_MIPI_PANEL_POWER_PIN, 1);
188 }
189 else
190 {
191 GPIO_PinWrite(BOARD_MIPI_PANEL_POWER_GPIO, BOARD_MIPI_PANEL_POWER_PIN, 0);
192 }
193 }
194
BOARD_DSI_Transfer(dsi_transfer_t * xfer)195 static status_t BOARD_DSI_Transfer(dsi_transfer_t *xfer)
196 {
197 return DSI_TransferBlocking(DEMO_LCD_MIPI, xfer);
198 }
199
BOARD_InitLcdifClock(void)200 static void BOARD_InitLcdifClock(void)
201 {
202 /*
203 * The pixel clock is (height + VSW + VFP + VBP) * (width + HSW + HFP + HBP) * frame rate.
204 *
205 * For 60Hz frame rate, the RK055IQH091 pixel clock should be 36MHz.
206 * the RK055AHD091 pixel clock should be 62MHz.
207 */
208 const clock_root_config_t lcdifClockConfig = {
209 .clockOff = false,
210 .mux = 4, /*!< PLL_528. */
211 #if (defined(DISPLAY_USING_RK055AHD091) || defined(DISPLAY_USING_RK055MHD091))
212 .div = 9,
213 #elif defined(DISPLAY_USING_RK055IQH091)
214 .div = 15,
215 #endif
216 };
217
218 #if defined(BSP_USING_LCDIFV2)
219 CLOCK_SetRootClock(kCLOCK_Root_Lcdifv2, &lcdifClockConfig);
220
221 mipiDsiDpiClkFreq_Hz = CLOCK_GetRootClockFreq(kCLOCK_Root_Lcdifv2);
222
223 #elif defined(BSP_USING_ELCDIF)
224
225 CLOCK_SetRootClock(kCLOCK_Root_Lcdif, &lcdifClockConfig);
226
227 mipiDsiDpiClkFreq_Hz = CLOCK_GetRootClockFreq(kCLOCK_Root_Lcdif);
228 #endif
229 }
230
BOARD_InitMipiDsiClock(void)231 static void BOARD_InitMipiDsiClock(void)
232 {
233 uint32_t mipiDsiEscClkFreq_Hz;
234
235 /* RxClkEsc max 60MHz, TxClkEsc 12 to 20MHz. */
236 /* RxClkEsc = 528MHz / 11 = 48MHz. */
237 /* TxClkEsc = 528MHz / 11 / 4 = 16MHz. */
238 const clock_root_config_t mipiEscClockConfig = {
239 .clockOff = false,
240 .mux = 4, /*!< PLL_528. */
241 .div = 11,
242 };
243
244 CLOCK_SetRootClock(kCLOCK_Root_Mipi_Esc, &mipiEscClockConfig);
245
246 mipiDsiEscClkFreq_Hz = CLOCK_GetRootClockFreq(kCLOCK_Root_Mipi_Esc);
247
248 const clock_group_config_t mipiEscClockGroupConfig = {
249 .clockOff = false, .resetDiv = 2, .div0 = 2, /* TX esc clock. */
250 };
251
252 CLOCK_SetGroupConfig(kCLOCK_Group_MipiDsi, &mipiEscClockGroupConfig);
253
254 mipiDsiTxEscClkFreq_Hz = mipiDsiEscClkFreq_Hz / 3;
255
256 /* DPHY reference clock, use OSC 24MHz clock. */
257 const clock_root_config_t mipiDphyRefClockConfig = {
258 .clockOff = false,
259 .mux = 1, /*!< OSC_24M. */
260 .div = 1,
261 };
262
263 CLOCK_SetRootClock(kCLOCK_Root_Mipi_Ref, &mipiDphyRefClockConfig);
264
265 mipiDsiDphyRefClkFreq_Hz = BOARD_XTAL0_CLK_HZ;
266 }
267
BOARD_InitLcdPanel(void)268 static status_t BOARD_InitLcdPanel(void)
269 {
270 status_t status;
271
272 const gpio_pin_config_t pinConfig = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
273
274 const display_config_t displayConfig = {
275 .resolution = FSL_VIDEO_RESOLUTION(LCD_MIPI_WIDTH, LCD_MIPI_HEIGHT),
276 .hsw = LCD_MIPI_HSW,
277 .hfp = LCD_MIPI_HFP,
278 .hbp = LCD_MIPI_HBP,
279 .vsw = LCD_MIPI_VSW,
280 .vfp = LCD_MIPI_VFP,
281 .vbp = LCD_MIPI_VBP,
282 .controlFlags = 0,
283 .dsiLanes = DEMO_LCD_MIPI_LANE_NUM,
284 };
285
286 GPIO_PinInit(BOARD_MIPI_PANEL_POWER_GPIO, BOARD_MIPI_PANEL_POWER_PIN, &pinConfig);
287 GPIO_PinInit(BOARD_MIPI_PANEL_BL_GPIO, BOARD_MIPI_PANEL_BL_PIN, &pinConfig);
288 GPIO_PinInit(BOARD_MIPI_PANEL_RST_GPIO, BOARD_MIPI_PANEL_RST_PIN, &pinConfig);
289
290 #if defined(DISPLAY_USING_RK055AHD091)
291 status = RM68200_Init(&rm68200Handle, &displayConfig);
292 #elif defined(DISPLAY_USING_RK055MHD091)
293 status = HX8394_Init(&hx8394Handle, &displayConfig);
294 #elif defined(DISPLAY_USING_RK055IQH091)
295 status = RM68191_Init(&rm68191Handle, &displayConfig);
296 #endif
297
298 if (status == kStatus_Success)
299 {
300 GPIO_PinWrite(BOARD_MIPI_PANEL_BL_GPIO, BOARD_MIPI_PANEL_BL_PIN, 1);
301 }
302
303 return status;
304 }
305
BOARD_SetMipiDsiConfig(void)306 static void BOARD_SetMipiDsiConfig(void)
307 {
308 dsi_config_t dsiConfig;
309 dsi_dphy_config_t dphyConfig;
310
311 const dsi_dpi_config_t dpiConfig = {.pixelPayloadSize = LCD_MIPI_WIDTH,
312 .dpiColorCoding = kDSI_Dpi24Bit,
313 .pixelPacket = kDSI_PixelPacket24Bit,
314 .videoMode = kDSI_DpiBurst,
315 .bllpMode = kDSI_DpiBllpLowPower,
316 .polarityFlags = kDSI_DpiVsyncActiveLow | kDSI_DpiHsyncActiveLow,
317 .hfp = LCD_MIPI_HFP,
318 .hbp = LCD_MIPI_HBP,
319 .hsw = LCD_MIPI_HSW,
320 .vfp = LCD_MIPI_VFP,
321 .vbp = LCD_MIPI_VBP,
322 .panelHeight = LCD_MIPI_HEIGHT,
323 .virtualChannel = 0};
324
325 /*
326 * dsiConfig.numLanes = 4;
327 * dsiConfig.enableNonContinuousHsClk = false;
328 * dsiConfig.autoInsertEoTp = true;
329 * dsiConfig.numExtraEoTp = 0;
330 * dsiConfig.htxTo_ByteClk = 0;
331 * dsiConfig.lrxHostTo_ByteClk = 0;
332 * dsiConfig.btaTo_ByteClk = 0;
333 */
334 DSI_GetDefaultConfig(&dsiConfig);
335 dsiConfig.numLanes = DEMO_LCD_MIPI_LANE_NUM;
336 dsiConfig.autoInsertEoTp = true;
337
338 /* Init the DSI module. */
339 DSI_Init(DEMO_LCD_MIPI, &dsiConfig);
340
341 /* Init DPHY.
342 *
343 * The DPHY bit clock must be fast enough to send out the pixels, it should be
344 * larger than:
345 *
346 * (Pixel clock * bit per output pixel) / number of MIPI data lane
347 *
348 * Here the desired DPHY bit clock multiplied by ( 9 / 8 = 1.125) to ensure
349 * it is fast enough.
350 *
351 * Note that the DSI output pixel is 24bit per pixel.
352 */
353 mipiDsiDphyBitClkFreq_Hz = mipiDsiDpiClkFreq_Hz * (24 / DEMO_LCD_MIPI_LANE_NUM);
354
355 mipiDsiDphyBitClkFreq_Hz = DEMO_MIPI_DPHY_BIT_CLK_ENLARGE(mipiDsiDphyBitClkFreq_Hz);
356
357 DSI_GetDphyDefaultConfig(&dphyConfig, mipiDsiDphyBitClkFreq_Hz, mipiDsiTxEscClkFreq_Hz);
358
359 mipiDsiDphyBitClkFreq_Hz = DSI_InitDphy(DEMO_LCD_MIPI, &dphyConfig, mipiDsiDphyRefClkFreq_Hz);
360
361 /* Init DPI interface. */
362 DSI_SetDpiConfig(DEMO_LCD_MIPI, &dpiConfig, DEMO_LCD_MIPI_LANE_NUM, mipiDsiDpiClkFreq_Hz, mipiDsiDphyBitClkFreq_Hz);
363 }
364
BOARD_InitDisplayInterface(void)365 status_t BOARD_InitDisplayInterface(void)
366 {
367 CLOCK_EnableClock(kCLOCK_Video_Mux);
368
369 #if defined(BSP_USING_LCDIFV2)
370 /* LCDIF v2 output to MIPI DSI. */
371 VIDEO_MUX->VID_MUX_CTRL.SET = VIDEO_MUX_VID_MUX_CTRL_MIPI_DSI_SEL_MASK;
372 #elif defined(BSP_USING_ELCDIF)
373 /* ELCDIF output to MIPI DSI. */
374 VIDEO_MUX->VID_MUX_CTRL.CLR = VIDEO_MUX_VID_MUX_CTRL_MIPI_DSI_SEL_MASK;
375 #endif
376
377 /* 1. Power on and isolation off. */
378 PGMC_BPC4->BPC_POWER_CTRL |= (PGMC_BPC_BPC_POWER_CTRL_PSW_ON_SOFT_MASK | PGMC_BPC_BPC_POWER_CTRL_ISO_OFF_SOFT_MASK);
379
380 /* 2. Assert MIPI reset. */
381 IOMUXC_GPR->GPR62 &=
382 ~(IOMUXC_GPR_GPR62_MIPI_DSI_PCLK_SOFT_RESET_N_MASK | IOMUXC_GPR_GPR62_MIPI_DSI_ESC_SOFT_RESET_N_MASK |
383 IOMUXC_GPR_GPR62_MIPI_DSI_BYTE_SOFT_RESET_N_MASK | IOMUXC_GPR_GPR62_MIPI_DSI_DPI_SOFT_RESET_N_MASK);
384
385 /* 3. Setup clock. */
386 BOARD_InitMipiDsiClock();
387
388 /* 4. Deassert PCLK and ESC reset. */
389 IOMUXC_GPR->GPR62 |=
390 (IOMUXC_GPR_GPR62_MIPI_DSI_PCLK_SOFT_RESET_N_MASK | IOMUXC_GPR_GPR62_MIPI_DSI_ESC_SOFT_RESET_N_MASK);
391
392 /* 5. Configures peripheral. */
393 BOARD_SetMipiDsiConfig();
394
395 /* 6. Deassert BYTE and DBI reset. */
396 IOMUXC_GPR->GPR62 |=
397 (IOMUXC_GPR_GPR62_MIPI_DSI_BYTE_SOFT_RESET_N_MASK | IOMUXC_GPR_GPR62_MIPI_DSI_DPI_SOFT_RESET_N_MASK);
398
399 /* 7. Configure the panel. */
400 return BOARD_InitLcdPanel();
401 }
402
403 #if defined(BSP_USING_LCDIFV2)
LCDIFv2_IRQHandler(void)404 void LCDIFv2_IRQHandler(void)
405 {
406 DC_FB_LCDIFV2_IRQHandler(&g_dc);
407 }
408 #elif defined(BSP_USING_ELCDIF)
eLCDIF_IRQHandler(void)409 void eLCDIF_IRQHandler(void)
410 {
411 DC_FB_ELCDIF_IRQHandler(&g_dc);
412 }
413 #endif
414
BOARD_VerifyDisplayClockSource(void)415 status_t BOARD_VerifyDisplayClockSource(void)
416 {
417 status_t status;
418 uint32_t srcClkFreq;
419
420 /*
421 * In this implementation, the SYSPLL2 (528M) clock is used as the source
422 * of LCDIFV2 pixel clock and MIPI DSI ESC clock. The OSC24M clock is used
423 * as the MIPI DSI DPHY PLL reference clock. This function checks the clock
424 * source are valid. OSC24M is always valid, so only verify the SYSPLL2.
425 */
426 srcClkFreq = CLOCK_GetPllFreq(kCLOCK_PllSys2);
427 if (528 != (srcClkFreq / 1000000))
428 {
429 status = kStatus_Fail;
430 }
431 else
432 {
433 status = kStatus_Success;
434 }
435
436 return status;
437 }
438
BOARD_PrepareDisplayController(void)439 status_t BOARD_PrepareDisplayController(void)
440 {
441 status_t status;
442
443 status = BOARD_VerifyDisplayClockSource();
444
445 if (status != kStatus_Success)
446 {
447 return status;
448 }
449
450 BOARD_InitLcdifClock();
451
452 status = BOARD_InitDisplayInterface();
453
454 if (kStatus_Success == status)
455 {
456 #if defined(BSP_USING_LCDIFV2)
457 NVIC_ClearPendingIRQ(LCDIFv2_IRQn);
458 NVIC_SetPriority(LCDIFv2_IRQn, 3);
459 EnableIRQ(LCDIFv2_IRQn);
460 #elif defined(BSP_USING_ELCDIF)
461 NVIC_ClearPendingIRQ(eLCDIF_IRQn);
462 NVIC_SetPriority(eLCDIF_IRQn, 3);
463 EnableIRQ(eLCDIF_IRQn);
464 #endif
465 }
466
467 return kStatus_Success;
468 }
469