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