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