display_support.c 14 KB

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