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