lcdc_leopard.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. /*
  2. * Copyright (c) 2020 Actions Technology Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <soc.h>
  7. #include <spicache.h>
  8. #include <drivers/cfg_drv/dev_config.h>
  9. #include <drivers/display.h>
  10. #include <drivers/display/display_engine.h>
  11. #include <drivers/display/display_controller.h>
  12. #include <assert.h>
  13. #include <string.h>
  14. #include "lcdc_leopard.h"
  15. #include <logging/log.h>
  16. LOG_MODULE_REGISTER(lcdc, CONFIG_DISPLAY_LOG_LEVEL);
  17. #define USE_LCDC_TE 0
  18. #define USE_LCDC_SEND_DBG 0
  19. #define SUPPORTED_PIXEL_FORMATS (PIXEL_FORMAT_BGR_565 | PIXEL_FORMAT_RGB_888 | \
  20. PIXEL_FORMAT_BGR_888 | PIXEL_FORMAT_ARGB_8888 | PIXEL_FORMAT_XRGB_8888)
  21. #define LCDC ((LCDC_Type *)LCDC_REG_BASE)
  22. #define SDMA0 ((LCDC_SDMA_Type *)SDMA0_REG_BASE)
  23. #define SPI_AHB_CMD_MASK \
  24. (LCD_SPI_SRC_MASK | LCD_SPI_AHB_CSX_MASK | LCD_SPI_CDX_MASK)
  25. #define SPI_AHB_DATA_MASK \
  26. (SPI_AHB_CMD_MASK | LCD_SPI_AHB_F565_MASK | \
  27. LCD_SPI_AHB_CFG_DATA | LCD_SPI_RWL_MASK)
  28. #define CPU_AHB_CMD_MASK \
  29. (LCD_CPU_SRC_MASK | LCD_CPU_AHB_F565_MASK | \
  30. LCD_CPU_RS_MASK | LCD_CPU_AHB_DATA_MASK | LCD_CPU_AHB_CSX_MASK)
  31. #define CPU_AHB_DATA_MASK CPU_AHB_CMD_MASK
  32. struct lcdc_data {
  33. /* pointer to current video port passed in interface enable() */
  34. const struct display_videoport *port;
  35. /* pointer to current video mode passed in interface set_mode() */
  36. const struct display_videomode *mode;
  37. /* enum display_controller_source_type */
  38. uint8_t source_type;
  39. display_controller_complete_t complete_fn;
  40. void *complete_fn_arg;
  41. #ifdef CONFIG_PM_DEVICE
  42. const struct display_videoport *saved_port;
  43. const struct display_videomode *saved_mode;
  44. #endif
  45. bool busy;
  46. };
  47. static int lcdc_config_port(const struct device *dev, const struct display_videoport *port)
  48. {
  49. uint32_t lcd_ctl;
  50. #if USE_LCDC_SEND_DBG
  51. lcd_ctl = LCD_EN | LCD_CLK_EN | LCD_FIFO_EN | LCD_AUTO_RST_FIFO_EN | LCD_SDCHK_CLK_EN |
  52. LCD_IN_RGB666_CVT_LOW | LCD_IN_RGB565_CVT_LOW /*| LCD_OUT_RGB565_FORCE_555*/;
  53. LCDC->SD_CNT = LCD_SDCNT_EN;
  54. LCDC->SD_CHECKSUM = LCD_CHKSUM_EN;
  55. #else
  56. lcd_ctl = LCD_EN | LCD_CLK_EN | LCD_FIFO_EN | LCD_AUTO_RST_FIFO_EN |
  57. LCD_IN_RGB666_CVT_LOW | LCD_IN_RGB565_CVT_LOW /*| LCD_OUT_RGB565_FORCE_555*/;
  58. #endif /* USE_LCDC_SEND_DBG */
  59. if (port->type != DISPLAY_PORT_QSPI_SYNC) {
  60. lcd_ctl |= LCD_HOLD_EN;
  61. }
  62. switch (port->major_type) {
  63. case DISPLAY_PORT_MCU:
  64. lcd_ctl |= (port->minor_type == DISPLAY_MCU_8080) ? LCD_IF_SEL_MCU_8080 : LCD_IF_SEL_MCU_6880;
  65. lcd_ctl |= LCD_IF_CE_SEL(port->mcu_mode.cs) | LCD_IF_MLS_SEL(port->mcu_mode.lsb_first);
  66. LCDC->CPU_CTL = LCD_CPU_FEND_IRQ_EN | LCD_CPU_RX_DELAY_SEL(0) | LCD_CPU_AHB_F565_16BIT | LCD_CPU_AHB_CSX(1);
  67. LCDC->CPU_CLK = LCD_CPU_CLK(port->mcu_mode.clk_high_duration,
  68. port->mcu_mode.clk_low_duration, port->mcu_mode.clk_low_duration);
  69. break;
  70. case DISPLAY_PORT_SPI:
  71. lcd_ctl |= LCD_IF_SEL_SPI | LCD_IF_CE_SEL(port->spi_mode.cs) | LCD_IF_MLS_SEL(port->spi_mode.lsb_first);
  72. LCDC->SPI_CTL = LCD_SPI_FTC_IRQ_EN | LCD_SPI_FEND_PD_EN |
  73. LCD_SPI_CDX(1) | LCD_SPI_AHB_CSX(1) | LCD_SPI_AHB_F565_16BIT |
  74. LCD_SPI_TYPE_SEL(port->minor_type >= LCD_QSPI_SYNC ? LCD_QSPI : port->minor_type) |
  75. LCD_SPI_RD_DELAY_CHAIN_SEL(port->spi_mode.rd_delay_ns) |
  76. LCD_SPI_RD_LANE_SEL(port->spi_mode.rd_lane) |
  77. LCD_SPI_DCP_SEL(port->spi_mode.dcp_mode) |
  78. LCD_SPI_DUAL_LANE_SEL(port->spi_mode.dual_lane);
  79. LCDC->SPI_CTL1 = LCD_SPI_RDLC_SEL(port->spi_mode.rd_dummy_cycles) |
  80. LCD_SPI_AHB_CLK_DIV(port->spi_mode.ahb_clk_div);
  81. LCDC->SPI_CTL2 = LCD_SPI_SIG_DELAY(port->spi_mode.delay_csx_ns,
  82. port->spi_mode.delay_scl_ns, port->spi_mode.wr_delay_d0_ns,
  83. port->spi_mode.wr_delay_d1_ns, port->spi_mode.wr_delay_d2_ns,
  84. port->spi_mode.wr_delay_d3_ns);
  85. if (port->minor_type >= DISPLAY_QSPI_DDR_0) {
  86. LCDC->QSPI_DDR_CTL = LCD_SPI_MODE(port->spi_mode.cpol, port->spi_mode.cpha) |
  87. LCD_SPI_DDR_SEL(port->minor_type - DISPLAY_QSPI_DDR_0 + 1) |
  88. LCD_SPI_CLK_KEEP_SEL(0) | LCD_SPI_DDR_EN;
  89. } else if (port->minor_type == DISPLAY_QSPI) {
  90. LCDC->QSPI_DDR_CTL = LCD_SPI_MODE(port->spi_mode.cpol, port->spi_mode.cpha) |
  91. LCD_SPI_DDR_SEL(0) | LCD_SPI_CLK_KEEP_SEL(1) | LCD_SPI_DDR_EN;
  92. } else {
  93. LCDC->SPI_CTL |= LCD_SPI_SCLK_POL((port->spi_mode.cpol == port->spi_mode.cpha) ? 0 : 1);
  94. }
  95. break;
  96. case DISPLAY_PORT_TR:
  97. lcd_ctl |= LCD_IF_SEL_TR;
  98. LCDC->TR_CTL = LCD_TR_FTC_IRQ_EN | LCD_TR_F565_16BIT | LCD_TR_LB_SEL(port->tr_mode.low_bit) |
  99. LCD_TR_HCK_TAIL_EN(port->tr_mode.hck_tail_on) | LCD_TR_VCK_CONT_EN(port->tr_mode.vck_on_xrstl) |
  100. LCD_TR_VCK_MODE(port->tr_mode.vck_on_idle) | LCD_TR_HCK_MODE(port->tr_mode.hck_on_idle) |
  101. LCD_TR_PU_MODE(port->tr_mode.ptl_on) | LCD_TR_FRP_EN(port->tr_mode.frp_on) |
  102. LCD_TR_VCOM_INV(port->tr_mode.vcom_inv) | LCD_TR_FRP_INV(port->tr_mode.frp_inv) |
  103. LCD_TR_XFRP_INV(port->tr_mode.xfrp_inv) | LCD_TR_XRST_INV(port->tr_mode.xrst_inv) |
  104. LCD_TR_VST_INV(port->tr_mode.vst_inv) | LCD_TR_HST_INV(port->tr_mode.hst_inv) |
  105. LCD_TR_VCK_INV(port->tr_mode.vck_inv) | LCD_TR_HCK_INV(port->tr_mode.hck_inv) |
  106. LCD_TR_ENB_INV(port->tr_mode.enb_inv);
  107. LCDC->TR_TIM[0] = LCD_TR_TIM0(port->tr_mode.tw_xrst, port->tr_mode.tw_vcom);
  108. LCDC->TR_TIM[1] = LCD_TR_TIM1(port->tr_mode.td_vst, port->tr_mode.tw_vst,
  109. port->tr_mode.td_hst, port->tr_mode.tw_hst);
  110. LCDC->TR_TIM[2] = LCD_TR_TIM2(port->tr_mode.td_vck, port->tr_mode.tw_vck,
  111. port->tr_mode.tp_hck, port->tr_mode.td_hck);
  112. LCDC->TR_TIM[3] = LCD_TR_TIM3(port->tr_mode.ts_enb, port->tr_mode.th_enb,
  113. port->tr_mode.td_data);
  114. LCDC->TR_TIM[4] = LCD_TR_TIM4(port->tr_mode.td_enb, port->tr_mode.tw_enb);
  115. LCDC->TR_TIM[5] = LCD_TR_TIM5(port->tr_mode.tsm_enb, port->tr_mode.thm_enb,
  116. port->tr_mode.twm_vck);
  117. break;
  118. default:
  119. return -ENOTSUP;
  120. }
  121. LCDC->CTL = lcd_ctl;
  122. return 0;
  123. }
  124. static int lcdc_config_src_pixel_format(const struct device *dev,
  125. uint32_t pixel_format, uint8_t *bytes_per_pixel)
  126. {
  127. struct lcdc_data *data = dev->data;
  128. if (pixel_format == PIXEL_FORMAT_BGR_565) {
  129. *bytes_per_pixel = 2;
  130. switch (data->port->major_type) {
  131. case DISPLAY_PORT_SPI:
  132. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_RGB565;
  133. break;
  134. case DISPLAY_PORT_MCU:
  135. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_RGB565;
  136. case DISPLAY_PORT_TR:
  137. default:
  138. LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SDT_MASK) | LCD_TR_SDT_RGB565;
  139. break;
  140. }
  141. } else if (pixel_format == PIXEL_FORMAT_ARGB_8888 ||
  142. pixel_format == PIXEL_FORMAT_XRGB_8888) {
  143. *bytes_per_pixel = 4;
  144. switch (data->port->major_type) {
  145. case DISPLAY_PORT_SPI:
  146. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_ARGB8888;
  147. break;
  148. case DISPLAY_PORT_MCU:
  149. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_ARGB8888;
  150. case DISPLAY_PORT_TR:
  151. default:
  152. LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SDT_MASK) | LCD_TR_SDT_ARGB8888;
  153. break;
  154. }
  155. } else if (pixel_format == PIXEL_FORMAT_RGB_888) {
  156. *bytes_per_pixel = 3;
  157. switch (data->port->major_type) {
  158. case DISPLAY_PORT_SPI:
  159. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_BGR888;
  160. break;
  161. case DISPLAY_PORT_MCU:
  162. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_BGR888;
  163. case DISPLAY_PORT_TR:
  164. default:
  165. LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SDT_MASK) | LCD_TR_SDT_BGR888;
  166. break;
  167. }
  168. } else if (pixel_format == PIXEL_FORMAT_BGR_888) {
  169. *bytes_per_pixel = 3;
  170. switch (data->port->major_type) {
  171. case DISPLAY_PORT_SPI:
  172. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_RGB888;
  173. break;
  174. case DISPLAY_PORT_MCU:
  175. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_RGB888;
  176. case DISPLAY_PORT_TR:
  177. default:
  178. LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SDT_MASK) | LCD_TR_SDT_RGB888;
  179. break;
  180. }
  181. } else {
  182. return -EINVAL;
  183. }
  184. return 0;
  185. }
  186. static int lcdc_config_mode(const struct device *dev, const struct display_videomode *mode)
  187. {
  188. struct lcdc_data *data = dev->data;
  189. if (mode->hactive > 512 || mode->vactive > 512 ||
  190. (mode->pixel_format & SUPPORTED_PIXEL_FORMATS) == 0) {
  191. return -ENOTSUP;
  192. }
  193. clk_set_rate(CLOCK_ID_LCD, KHZ(mode->pixel_clk));
  194. LCDC->CTL &= ~(LCD_TE_EN | LCD_TE_MODE_MASK | LCD_OUT_FORMAT_MASK);
  195. #if USE_LCDC_TE
  196. if (mode->flags & DISPLAY_FLAGS_TE_HIGH) {
  197. LCDC->CTL |= LCD_TE_EN | LCD_TE_MODE_RISING_EDGE;
  198. } else if (mode->flags & DISPLAY_FLAGS_TE_LOW) {
  199. LCDC->CTL |= LCD_TE_EN | LCD_TE_MODE_FALLING_EDGE;
  200. }
  201. #endif
  202. switch (mode->pixel_format) {
  203. case PIXEL_FORMAT_BGR_565:
  204. LCDC->CTL |= LCD_OUT_FORMAT_RGB565;
  205. break;
  206. case PIXEL_FORMAT_RGB_888:
  207. case PIXEL_FORMAT_BGR_888:
  208. case PIXEL_FORMAT_ARGB_8888:
  209. case PIXEL_FORMAT_XRGB_8888:
  210. default:
  211. LCDC->CTL |= LCD_OUT_FORMAT_BGR888;
  212. break;
  213. }
  214. if (data->port->type == DISPLAY_PORT_QSPI_SYNC) {
  215. uint16_t data_cycles = mode->hactive *
  216. display_format_get_bits_per_pixel(mode->pixel_format) / 4;
  217. LCDC->QSPI_DTAS = LCD_QSPI_DTAS(0, data_cycles);
  218. LCDC->QSPI_SYNC_TIM = LCD_QSPI_SYNC_TIM(
  219. mode->hsync_len + mode->hback_porch + mode->hfront_porch,
  220. mode->vfront_porch, mode->vback_porch);
  221. } else if (data->port->type == DISPLAY_PORT_TR_LCD) {
  222. LCDC->TR_IMG_SIZE = LCD_TR_IMG_SIZE(mode->hactive, mode->vactive);
  223. }
  224. return 0;
  225. }
  226. static int lcdc_config_source(const struct device *dev,
  227. enum display_controller_source_type source_type)
  228. {
  229. static const uint32_t mcu_source_set[DISPLAY_CONTROLLER_NUM_SOURCES] = {
  230. LCD_CPU_SRC_SEL_AHB,
  231. LCD_CPU_SRC_SEL_DE | LCD_CPU_RS_HIGH,
  232. LCD_CPU_SRC_SEL_DMA | LCD_CPU_RS_HIGH,
  233. };
  234. static const uint32_t spi_source_set[DISPLAY_CONTROLLER_NUM_SOURCES] = {
  235. LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(1),
  236. LCD_SPI_SRC_SEL_DE | LCD_SPI_CDX(1),
  237. LCD_SPI_SRC_SEL_DMA | LCD_SPI_CDX(1),
  238. };
  239. static const uint32_t tr_source_set[DISPLAY_CONTROLLER_NUM_SOURCES] = {
  240. LCD_TR_SRC_SEL_DE,
  241. LCD_TR_SRC_SEL_DMA,
  242. };
  243. struct lcdc_data *data = dev->data;
  244. if (source_type >= DISPLAY_CONTROLLER_NUM_SOURCES) {
  245. return -EINVAL;
  246. }
  247. switch (data->port->major_type) {
  248. case DISPLAY_PORT_MCU:
  249. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~(LCD_CPU_SRC_MASK | LCD_CPU_RS_MASK))
  250. | mcu_source_set[source_type];
  251. break;
  252. case DISPLAY_PORT_SPI:
  253. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~(LCD_SPI_SRC_MASK | LCD_SPI_CDX_MASK))
  254. | spi_source_set[source_type];
  255. break;
  256. case DISPLAY_PORT_TR:
  257. if (source_type == DISPLAY_CONTROLLER_SOURCE_MCU)
  258. return -EINVAL;
  259. LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SRC_MASK)
  260. | tr_source_set[source_type - 1];
  261. break;
  262. default:
  263. return -EINVAL;
  264. }
  265. return 0;
  266. }
  267. static int lcdc_enable(const struct device *dev, const struct display_videoport *port)
  268. {
  269. struct lcdc_data *data = dev->data;
  270. if (data->port != NULL) {
  271. return -EALREADY;
  272. }
  273. if (port == NULL) {
  274. return -EINVAL;
  275. }
  276. /* initially use the CMU_LCDCLK default setting: HOSC 1/1 */
  277. //clk_set_rate(CLOCK_ID_LCD, MHZ(50));
  278. acts_reset_peripheral_assert(RESET_ID_LCD);
  279. acts_clock_peripheral_enable(CLOCK_ID_LCD);
  280. acts_reset_peripheral_deassert(RESET_ID_LCD);
  281. if (lcdc_config_port(dev, port)) {
  282. return -EINVAL;
  283. }
  284. /* FIXME: just save the pointer ? */
  285. data->port = port;
  286. data->mode = NULL;
  287. data->source_type = UINT8_MAX;
  288. return 0;
  289. }
  290. static int lcdc_disable(const struct device *dev)
  291. {
  292. struct lcdc_data *data = dev->data;
  293. if (data->port != NULL) {
  294. data->port = NULL;
  295. data->busy = false;
  296. SDMA0->START = 0; /* force stop DMA */
  297. acts_clock_peripheral_disable(CLOCK_ID_LCD);
  298. }
  299. return 0;
  300. }
  301. static int lcdc_set_mode(const struct device *dev,
  302. const struct display_videomode *mode)
  303. {
  304. struct lcdc_data *data = dev->data;
  305. if (mode == NULL) {
  306. return -EINVAL;
  307. }
  308. if (mode == data->mode) {
  309. return 0;
  310. }
  311. if (lcdc_config_mode(dev, mode)) {
  312. return -EINVAL;
  313. }
  314. /* FIXME: just save the pointer ? */
  315. data->mode = mode;
  316. return 0;
  317. }
  318. static int lcdc_set_source(const struct device *dev,
  319. enum display_controller_source_type source_type, const struct device *source_dev)
  320. {
  321. struct lcdc_data *data = dev->data;
  322. if (data->port == NULL) {
  323. return -EINVAL;
  324. }
  325. if (source_type == data->source_type) {
  326. return 0;
  327. }
  328. if (lcdc_config_source(dev, source_type)) {
  329. return -EINVAL;
  330. }
  331. data->source_type = source_type;
  332. return 0;
  333. }
  334. static void _read_config_data32(uint8_t *buf8, const uint32_t *data, uint32_t len)
  335. {
  336. int pos = (len >= 4) ? 24 : (len - 1) * 8;
  337. while (len-- > 0) {
  338. *buf8++ = (data[0] >> pos) & 0xFF;
  339. pos -= 8;
  340. if (pos < 0) {
  341. pos = 24;
  342. data++;
  343. }
  344. }
  345. }
  346. static int lcdc_read_config(const struct device *dev,
  347. uint32_t cmd, void *buf, uint32_t len)
  348. {
  349. struct lcdc_data *lcdc_data = dev->data;
  350. if (lcdc_data->port == NULL) {
  351. return -EINVAL;
  352. }
  353. if (buf == NULL || len == 0) {
  354. return -EINVAL;
  355. }
  356. if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
  357. uint32_t lcdc_spi_ctl = LCDC->SPI_CTL; /* save REG SPI_CTL */
  358. uint32_t lcdc_spi_ctl1 = LCDC->SPI_CTL1; /* save REG SPI_CTL1 */
  359. LCDC->SPI_CTL1 |= LCD_SPI_AHB_CLK_DIV_MAX; /* set lowest clock */
  360. if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
  361. LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
  362. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(0);
  363. LCDC->DATA = cmd;
  364. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  365. LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_DUAL_LANE_MASK);
  366. if (len <= 4) {
  367. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA | LCD_SPI_RWL(len);
  368. uint32_t data = LCDC->DATA;
  369. _read_config_data32(buf, &data, len);
  370. } else {
  371. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA | LCD_SPI_RWL(1);
  372. do {
  373. *(uint8_t *)buf = LCDC->DATA & 0xff;
  374. buf = (uint8_t *)buf + 1;
  375. } while (--len > 0);
  376. }
  377. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  378. } else {
  379. uint32_t tmp_data[8];
  380. int i;
  381. if (len > 32)
  382. return -EDOM;
  383. /* config spi type 'LCD_QSPI_SYNC' to 'LCD_QSPI' temporarily */
  384. LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_TYPE_MASK);
  385. LCDC->SPI_CTL |= LCD_QSPI | LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA |
  386. LCD_SPI_CDX(0) | LCD_SPI_RWL(len);
  387. LCDC->QSPI_CMD = cmd;
  388. tmp_data[0] = LCDC->DATA;
  389. for (i = (len - 1) / 4 - 1; i >= 0; i--) {
  390. tmp_data[i + 1] = LCDC->DATA_1[i];
  391. }
  392. _read_config_data32(buf, tmp_data, len);
  393. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  394. }
  395. /* restore REG SPI_CTL */
  396. LCDC->SPI_CTL = lcdc_spi_ctl;
  397. LCDC->SPI_CTL1 = lcdc_spi_ctl1;
  398. } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
  399. uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save REG CPU_CTL */
  400. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  401. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_LOW;
  402. LCDC->DATA = cmd;
  403. LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
  404. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  405. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_HIGH;
  406. do {
  407. *(uint8_t *)buf = LCDC->DATA & 0xff;
  408. buf = (uint8_t *)buf + 1;
  409. } while (--len > 0);
  410. LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
  411. /* restore REG CPU_CTL */
  412. LCDC->CPU_CTL = lcdc_cpu_ctl;
  413. }
  414. return 0;
  415. }
  416. static int _fill_spi_config_data32(uint32_t *data, const uint8_t *buf8, uint32_t len)
  417. {
  418. int data_num = (len + 3) >> 2;
  419. for (; len >= 4; len -= 4) {
  420. *data++ = ((uint32_t)buf8[0] << 24) | ((uint32_t)buf8[1] << 16) |
  421. ((uint32_t)buf8[2] << 8) | buf8[3];
  422. buf8 += 4;
  423. }
  424. if (len > 0) {
  425. *data = *buf8++;
  426. while (--len > 0) {
  427. *data = (*data << 8) | (*buf8++);
  428. }
  429. }
  430. return data_num;
  431. }
  432. static int lcdc_write_config(const struct device *dev,
  433. uint32_t cmd, const void *buf, uint32_t len)
  434. {
  435. struct lcdc_data *lcdc_data = dev->data;
  436. const uint8_t *buf8 = buf;
  437. if (lcdc_data->port == NULL) {
  438. return -EINVAL;
  439. }
  440. if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
  441. uint32_t lcdc_spi_ctl = LCDC->SPI_CTL;
  442. if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
  443. if (cmd != DC_INVALID_CMD) {
  444. /* make sure source has selected AHB successfully */
  445. LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
  446. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(0);
  447. LCDC->DATA = cmd;
  448. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  449. }
  450. if (len > 0) {
  451. uint32_t data;
  452. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~(SPI_AHB_DATA_MASK | LCD_SPI_DUAL_LANE_MASK)) |
  453. (LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA | LCD_SPI_CDX(1) | LCD_SPI_RWL(4));
  454. for (; len >= 4; buf8 += 4, len -= 4) {
  455. LCDC->SPI_CTL &= ~LCD_SPI_AHB_CSX_MASK;
  456. _fill_spi_config_data32(&data, buf8, 4);
  457. LCDC->DATA = data;
  458. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  459. }
  460. if (len > 0) {
  461. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~(LCD_SPI_RWL_MASK | LCD_SPI_AHB_CSX_MASK)) | LCD_SPI_RWL(len);
  462. _fill_spi_config_data32(&data, buf8, len);
  463. LCDC->DATA = data;
  464. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  465. }
  466. }
  467. } else {
  468. uint32_t tmp_data[8];
  469. int i;
  470. if (len > 32)
  471. return -EDOM;
  472. /* config spi type 'LCD_QSPI_SYNC' to 'LCD_QSPI' temporarily */
  473. LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_TYPE_MASK);
  474. LCDC->SPI_CTL |= LCD_QSPI | LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA |
  475. LCD_SPI_CDX(0) | LCD_SPI_RWL(len);
  476. /* Transfer sequence:
  477. * 1) DATA, DATA_1, ..., DATA_7
  478. * 2) In every DATA: always (effective) MSB first:
  479. * if 32 bit in DATA, then [31..24], [23..16], [15..8], [7..0]
  480. * if 24 bit in DATA, then [23..16], [15..8], [7..0]
  481. * if 16 bit in DATA, then [15..8], [7..0]
  482. * if 8 bit in DATA, then [7..0]
  483. */
  484. i = _fill_spi_config_data32(tmp_data, buf8, len);
  485. LCDC->QSPI_CMD = cmd;
  486. for (i -= 1; i > 0; i--) {
  487. LCDC->DATA_1[i - 1] = tmp_data[i];
  488. }
  489. LCDC->DATA = tmp_data[0];
  490. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  491. }
  492. /* restore REG SPI_CTL */
  493. LCDC->SPI_CTL = lcdc_spi_ctl;
  494. } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
  495. uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save REG CPU_CTL */
  496. if (cmd != DC_INVALID_CMD) {
  497. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  498. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_LOW;
  499. LCDC->DATA = cmd;
  500. LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
  501. }
  502. if (len > 0) {
  503. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  504. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_HIGH;
  505. do {
  506. LCDC->DATA = *buf8++;
  507. } while (--len > 0);
  508. LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
  509. }
  510. /* restore REG CPU_CTL */
  511. LCDC->CPU_CTL = lcdc_cpu_ctl;
  512. }
  513. return 0;
  514. }
  515. static int lcdc_write_pixels_by_mcu(const struct device *dev, uint32_t cmd,
  516. const struct display_buffer_descriptor *desc, const void *buf)
  517. {
  518. struct lcdc_data *lcdc_data = dev->data;
  519. uint32_t pixel_format = desc->pixel_format;
  520. const uint8_t *buf8 = buf;
  521. int16_t row_offset;
  522. uint16_t bytes_per_line;
  523. uint8_t bytes_per_pixel;
  524. bool f565_24bit = false;
  525. int i, j;
  526. if (lcdc_data->port->type == DISPLAY_PORT_TR_LCD ||
  527. lcdc_data->port->type == DISPLAY_PORT_QSPI_SYNC) {
  528. return -ENOTSUP;
  529. }
  530. if (pixel_format == 0) {
  531. pixel_format = lcdc_data->mode->pixel_format;
  532. }
  533. if (lcdc_config_src_pixel_format(dev, pixel_format, &bytes_per_pixel)) {
  534. LOG_ERR("invalid pixel format 0x%x", pixel_format);
  535. return -EINVAL;
  536. }
  537. bytes_per_line = (desc->pitch > 0) ? desc->pitch : desc->width * bytes_per_pixel;
  538. row_offset = bytes_per_line - desc->width * bytes_per_pixel;
  539. if (CONFIG_LCDC_Y_FLIP) {
  540. row_offset -= bytes_per_line * 2;
  541. buf8 += (uint32_t)bytes_per_line * (desc->height - 1);
  542. }
  543. lcdc_data->busy = true;
  544. if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
  545. uint32_t lcdc_spi_ctl = LCDC->SPI_CTL; /* save LCD_SPI_CTL */
  546. LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
  547. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(1) |
  548. (f565_24bit ? LCD_SPI_AHB_F565_24BIT : LCD_SPI_AHB_F565_16BIT);
  549. if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
  550. for (j = desc->height; j > 0; j--) {
  551. for (i = desc->width; i > 0; i--) {
  552. uint32_t color;
  553. switch (bytes_per_pixel) {
  554. case 2: /* PIXEL_FORMAT_BGR_565 */
  555. color = buf8[0] | ((uint32_t)buf8[1] << 8);
  556. break;
  557. case 3: /* PIXEL_FORMAT_RGB_888 or PIXEL_FORMAT_BGR_888 */
  558. color = ((uint32_t)buf8[0] << 16) | ((uint32_t)buf8[1] << 8) | buf8[2];
  559. break;
  560. default:
  561. color = buf8[0] | ((uint32_t)buf8[1] << 8) | ((uint32_t)buf8[2] << 16) | ((uint32_t)buf8[3] << 24);
  562. break;
  563. }
  564. LCDC->DATA = color;
  565. buf8 += bytes_per_pixel;
  566. }
  567. buf8 += row_offset;
  568. }
  569. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  570. } else {
  571. for (j = desc->height; j > 0; j--) {
  572. for (i = desc->width; i > 0; i--) {
  573. uint32_t color;
  574. switch (bytes_per_pixel) {
  575. case 2: /* PIXEL_FORMAT_BGR_565 */
  576. color = buf8[0] | ((uint32_t)buf8[1] << 8);
  577. break;
  578. case 3: /* PIXEL_FORMAT_RGB_888 or PIXEL_FORMAT_BGR_888 */
  579. color = ((uint32_t)buf8[0] << 16) | ((uint32_t)buf8[1] << 8) | buf8[2];
  580. break;
  581. default:
  582. color = buf8[0] | ((uint32_t)buf8[1] << 8) | ((uint32_t)buf8[2] << 16) | ((uint32_t)buf8[3] << 24);
  583. break;
  584. }
  585. LCDC->SPI_CTL &= ~LCD_SPI_AHB_CSX_MASK;
  586. LCDC->QSPI_CMD = cmd;
  587. LCDC->DATA = color;
  588. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  589. buf8 += bytes_per_pixel;
  590. }
  591. buf8 += row_offset;
  592. }
  593. }
  594. /* restore LCD_SPI_CTL */
  595. LCDC->SPI_CTL = lcdc_spi_ctl;
  596. } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
  597. uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save LCD_CPU_CTL */
  598. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  599. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_IMG | LCD_CPU_RS_HIGH |
  600. (f565_24bit ? LCD_CPU_AHB_F565_24BIT : LCD_CPU_AHB_F565_16BIT);
  601. for (j = desc->height; j > 0; j--) {
  602. for (i = desc->width; i > 0; i--) {
  603. uint32_t color;
  604. switch (bytes_per_pixel) {
  605. case 2: /* PIXEL_FORMAT_BGR_565 */
  606. color = buf8[0] | ((uint32_t)buf8[1] << 8);
  607. break;
  608. case 3: /* PIXEL_FORMAT_RGB_888 or PIXEL_FORMAT_BGR_888 */
  609. color = ((uint32_t)buf8[0] << 16) | ((uint32_t)buf8[1] << 8) | buf8[2];
  610. break;
  611. default:
  612. color = buf8[0] | ((uint32_t)buf8[1] << 8) | ((uint32_t)buf8[2] << 16) | ((uint32_t)buf8[3] << 24);
  613. break;
  614. }
  615. LCDC->DATA = color;
  616. buf8 += bytes_per_pixel;
  617. }
  618. buf8 += row_offset;
  619. }
  620. /* restore LCD_CPU_CTL */
  621. LCDC->CPU_CTL = lcdc_cpu_ctl;
  622. }
  623. lcdc_data->busy = false;
  624. /* notify transfer completed */
  625. if (lcdc_data->complete_fn) {
  626. lcdc_data->complete_fn(lcdc_data->complete_fn_arg);
  627. }
  628. return 0;
  629. }
  630. static int lcdc_write_pixels_by_de(const struct device *dev,
  631. uint32_t cmd, uint32_t hsync_cmd,
  632. const struct display_buffer_descriptor *desc)
  633. {
  634. struct lcdc_data *data = dev->data;
  635. data->busy = true;
  636. /* only required for non-sync mode */
  637. LCDC->TPL = (uint32_t)desc->width * desc->height - 1;
  638. switch (data->port->major_type) {
  639. case DISPLAY_PORT_SPI:
  640. LOG_DBG("start spi-if\n");
  641. LCDC->QSPI_CMD = cmd;
  642. if (data->port->minor_type == DISPLAY_QSPI_SYNC) {
  643. LCDC->QSPI_CMD1 = hsync_cmd; /* only required for QUAD_SYNC */
  644. LCDC->QSPI_IMG_SIZE = LCD_QSPI_IMG_SIZE(desc->width, desc->height);
  645. LCDC->CTL &= ~LCD_EN;
  646. /* set to quad sync mode */
  647. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_TYPE_MASK) | LCD_QSPI_SYNC;
  648. LCDC->CTL |= LCD_EN;
  649. }
  650. LCDC->SPI_CTL |= LCD_SPI_START;
  651. break;
  652. case DISPLAY_PORT_MCU:
  653. LOG_DBG("start cpu-if\n");
  654. LCDC->CPU_CTL |= LCD_CPU_START;
  655. break;
  656. case DISPLAY_PORT_TR:
  657. default:
  658. LOG_DBG("start tr-if\n");
  659. LCDC->TR_CTL |= LCD_TR_START;
  660. break;
  661. }
  662. return 0;
  663. }
  664. static int lcdc_write_pixels_by_dma(const struct device *dev,
  665. uint32_t cmd, uint32_t hsync_cmd,
  666. const struct display_buffer_descriptor *desc, const void *buf)
  667. {
  668. struct lcdc_data *data = dev->data;
  669. uint32_t pixel_format = desc->pixel_format;
  670. uint16_t copy_per_line, bytes_per_line;
  671. uint8_t bytes_per_pixel;
  672. if (pixel_format == 0) {
  673. pixel_format = data->mode->pixel_format;
  674. }
  675. if (lcdc_config_src_pixel_format(dev, pixel_format, &bytes_per_pixel)) {
  676. LOG_ERR("invalid pixel format 0x%x", pixel_format);
  677. return -EINVAL;
  678. }
  679. copy_per_line = desc->width * bytes_per_pixel;
  680. bytes_per_line = (desc->pitch > 0) ? desc->pitch : copy_per_line;
  681. buf = cache_to_uncache((void *)buf);
  682. data->busy = true;
  683. /* configure DMA */
  684. assert(SDMA0->START == 0);
  685. if (CONFIG_LCDC_Y_FLIP) {
  686. SDMA0->CTL = BIT(24) | BIT(6); /* stride mode and address decrease mode */
  687. SDMA0->SADDR = (uint32_t)buf + bytes_per_line * (desc->height - 1);
  688. } else {
  689. SDMA0->CTL = BIT(24); /* stride mode */
  690. SDMA0->SADDR = (uint32_t)buf;
  691. }
  692. SDMA0->COUNT = desc->height;
  693. SDMA0->LENGTH = copy_per_line;
  694. SDMA0->SSTRIDE = bytes_per_line;
  695. SDMA0->BC = (uint32_t)copy_per_line * desc->height;
  696. /* start DMA */
  697. SDMA0->START = 0x1;
  698. LCDC->DISP_SIZE = LCD_DISP_SIZE(desc->width, desc->height);
  699. switch (data->port->major_type) {
  700. case DISPLAY_PORT_SPI:
  701. LCDC->QSPI_CMD = cmd;
  702. if (data->port->minor_type == DISPLAY_QSPI_SYNC) {
  703. LCDC->QSPI_CMD1 = hsync_cmd;
  704. LCDC->QSPI_IMG_SIZE = LCD_QSPI_IMG_SIZE(desc->width, desc->height);
  705. LCDC->CTL &= ~LCD_EN;
  706. /* set to quad sync mode */
  707. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_TYPE_MASK) | LCD_QSPI_SYNC;
  708. LCDC->CTL |= LCD_EN;
  709. }
  710. LOG_DBG("start spi-if\n");
  711. LCDC->SPI_CTL |= LCD_SPI_START;
  712. break;
  713. case DISPLAY_PORT_MCU:
  714. LOG_DBG("start cpu-if\n");
  715. LCDC->CPU_CTL |= LCD_CPU_START;
  716. break;
  717. case DISPLAY_PORT_TR:
  718. default:
  719. LOG_DBG("start tr-if\n");
  720. LCDC->TR_CTL |= LCD_TR_START;
  721. break;
  722. }
  723. return 0;
  724. }
  725. static int lcdc_write_pixels(const struct device *dev,
  726. uint32_t cmd, uint32_t hsync_cmd,
  727. const struct display_buffer_descriptor *desc, const void *buf)
  728. {
  729. struct lcdc_data *data = dev->data;
  730. if (data->port == NULL || data->mode == NULL) {
  731. return -EINVAL;
  732. }
  733. switch (data->source_type) {
  734. case DISPLAY_CONTROLLER_SOURCE_DMA:
  735. return lcdc_write_pixels_by_dma(dev, cmd, hsync_cmd, desc, buf);
  736. case DISPLAY_CONTROLLER_SOURCE_ENGINE:
  737. return lcdc_write_pixels_by_de(dev, cmd, hsync_cmd, desc);
  738. case DISPLAY_CONTROLLER_SOURCE_MCU:
  739. return lcdc_write_pixels_by_mcu(dev, cmd, desc, buf);
  740. default:
  741. return -EINVAL;
  742. }
  743. }
  744. static int lcdc_read_pixels(const struct device *dev, uint32_t cmd,
  745. const struct display_buffer_descriptor *desc, void *buf)
  746. {
  747. return -ENOTSUP;
  748. }
  749. static int lcdc_control(const struct device *dev, int cmd, void *arg1, void *arg2)
  750. {
  751. struct lcdc_data *data = dev->data;
  752. switch (cmd) {
  753. case DISPLAY_CONTROLLER_CTRL_COMPLETE_CB:
  754. data->complete_fn_arg = arg2;
  755. data->complete_fn = arg1;
  756. break;
  757. default:
  758. return -EINVAL;
  759. }
  760. return 0;
  761. }
  762. void lcdc_dump(void)
  763. {
  764. int i;
  765. printk("lcdc regs:\n");
  766. printk("\t LCD_CTL 0x%08x\n", LCDC->CTL);
  767. printk("\t LCD_DISP_SIZE 0x%08x\n", LCDC->DISP_SIZE);
  768. printk("\t LCD_CPU_CTL 0x%08x\n", LCDC->CPU_CTL);
  769. printk("\t LCD_DATA 0x%08x\n", LCDC->DATA);
  770. printk("\t LCD_CPU_CLK 0x%08x\n", LCDC->CPU_CLK);
  771. printk("\t LCD_TPL 0x%08x\n", LCDC->TPL);
  772. printk("\t LCD_SPI_CTL 0x%08x\n", LCDC->SPI_CTL);
  773. printk("\t LCD_QSPI_CMD 0x%08x\n", LCDC->QSPI_CMD);
  774. printk("\t LCD_QSPI_CMD1 0x%08x\n", LCDC->QSPI_CMD1);
  775. printk("\t LCD_QSPI_SYNC_TIM 0x%08x\n", LCDC->QSPI_SYNC_TIM);
  776. printk("\t LCD_QSPI_IMG_SIZE 0x%08x\n", LCDC->QSPI_IMG_SIZE);
  777. printk("\t DE_INTERFACE_CTL 0x%08x\n", LCDC->DE_INTERFACE_CTL);
  778. printk("\t LCD_PENDING 0x%08x\n", LCDC->PENDING);
  779. printk("\t LCD_QSPI_DTAS 0x%08x\n", LCDC->QSPI_DTAS);
  780. for (i = 0; i < ARRAY_SIZE(LCDC->DATA_1); i++) {
  781. printk("\t LCD_DATA_%d 0x%08x\n", i + 1, LCDC->DATA_1[i]);
  782. }
  783. printk("\t LCD_SPI_CTL1 0x%08x\n", LCDC->SPI_CTL1);
  784. printk("\t LCD_SPI_CTL2 0x%08x\n", LCDC->SPI_CTL2);
  785. printk("\t LCD_QSPI_DDR_CTL 0x%08x\n", LCDC->QSPI_DDR_CTL);
  786. printk("\t LCD_SD_CNT 0x%08x\n", LCDC->SD_CNT);
  787. printk("\t LCD_SD_CHECKSUM 0x%08x\n", LCDC->SD_CHECKSUM);
  788. printk("\t LCD_TR_CTL 0x%08x\n", LCDC->TR_CTL);
  789. printk("\t LCD_TR_IMG_SIZE 0x%08x\n", LCDC->TR_IMG_SIZE);
  790. for (i = 0; i < ARRAY_SIZE(LCDC->TR_TIM); i++) {
  791. printk("\t LCD_TR_TIM_%d 0x%08x\n", i, LCDC->TR_TIM[i]);
  792. }
  793. printk("\t SDMA0_CTL 0x%08x\n", SDMA0->CTL);
  794. printk("\t SDMA0_START 0x%08x\n", SDMA0->START);
  795. printk("\t SDMA0_SADDR 0x%08x\n", SDMA0->SADDR);
  796. printk("\t SDMA0_BC 0x%08x\n", SDMA0->BC);
  797. printk("\t SDMA0_RC 0x%08x\n", SDMA0->RC);
  798. printk("\t SDMA0_LINE_LENGTH 0x%08x\n", SDMA0->LENGTH);
  799. printk("\t SDMA0_LINE_COUNT 0x%08x\n", SDMA0->COUNT);
  800. printk("\t SDMA0_LINE_SSTRIDE 0x%08x\n", SDMA0->SSTRIDE);
  801. printk("\t SDMA0_LINE_REMAIN 0x%08x\n", SDMA0->REMAIN);
  802. }
  803. static void lcdc_isr(const void *arg)
  804. {
  805. const struct device *dev = arg;
  806. struct lcdc_data *data = dev->data;
  807. uint32_t pending = LCDC->PENDING;
  808. LCDC->PENDING = pending;
  809. if (pending & LCD_STAT_FTC) {
  810. if (pending & LCD_STAT_QSPI_SYNC_FTC) {
  811. if (data->source_type == DISPLAY_CONTROLLER_SOURCE_DMA) {
  812. if (SDMA0->START > 0) {
  813. LOG_ERR("LCD remain %u", SDMA0->RC);
  814. SDMA0->START = 0;
  815. }
  816. /* restart DMA */
  817. SDMA0->START = 0x1;
  818. }
  819. } else {
  820. data->busy = false;
  821. }
  822. if (data->complete_fn)
  823. data->complete_fn(data->complete_fn_arg);
  824. }
  825. LOG_DBG("LCD pending 0x%x", pending);
  826. }
  827. DEVICE_DECLARE(lcdc);
  828. static int lcdc_init(const struct device *dev)
  829. {
  830. IRQ_CONNECT(IRQ_ID_LCD, 0, lcdc_isr, DEVICE_GET(lcdc), 0);
  831. irq_enable(IRQ_ID_LCD);
  832. return 0;
  833. }
  834. #ifdef CONFIG_PM_DEVICE
  835. static int lcdc_pm_control(const struct device *dev, enum pm_device_action action)
  836. {
  837. struct lcdc_data *data = dev->data;
  838. int ret = 0;
  839. switch (action) {
  840. case PM_DEVICE_ACTION_SUSPEND:
  841. case PM_DEVICE_ACTION_FORCE_SUSPEND:
  842. case PM_DEVICE_ACTION_TURN_OFF:
  843. sl_dbg("lcdc suspend\n");
  844. if (data->busy) {
  845. LOG_WRN("lcdc busy (action=%d)", action);
  846. ret = -EBUSY;
  847. } else {
  848. data->saved_port = data->port;
  849. data->saved_mode = data->mode;
  850. lcdc_disable(dev);
  851. }
  852. break;
  853. case PM_DEVICE_ACTION_RESUME:
  854. if (data->saved_port) {
  855. lcdc_enable(dev, data->saved_port);
  856. if (data->saved_mode)
  857. lcdc_set_mode(dev, data->saved_mode);
  858. }
  859. sl_dbg("lcdc resume\n");
  860. break;
  861. default:
  862. break;
  863. }
  864. return ret;
  865. }
  866. #endif /* CONFIG_PM_DEVICE */
  867. static const struct display_controller_driver_api lcdc_api = {
  868. .control = lcdc_control,
  869. .enable = lcdc_enable,
  870. .disable = lcdc_disable,
  871. .set_mode = lcdc_set_mode,
  872. .set_source = lcdc_set_source,
  873. .read_config = lcdc_read_config,
  874. .write_config = lcdc_write_config,
  875. .read_pixels = lcdc_read_pixels,
  876. .write_pixels = lcdc_write_pixels,
  877. };
  878. static struct lcdc_data lcdc_drv_data;
  879. DEVICE_DEFINE(lcdc, CONFIG_LCDC_DEV_NAME, &lcdc_init,
  880. lcdc_pm_control, &lcdc_drv_data, NULL, POST_KERNEL,
  881. CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &lcdc_api);