lcdc_lark.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  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_lark.h"
  15. #include <logging/log.h>
  16. LOG_MODULE_REGISTER(lcdc, CONFIG_DISPLAY_LOG_LEVEL);
  17. #define USE_LCDC_TE 0
  18. #define SUPPORTED_PIXEL_FORMATS (PIXEL_FORMAT_BGR_565 | PIXEL_FORMAT_RGB_888 | \
  19. PIXEL_FORMAT_BGR_888 | PIXEL_FORMAT_ARGB_8888 | PIXEL_FORMAT_XRGB_8888)
  20. #define LCDC ((LCDC_Type *)LCDC_REG_BASE)
  21. #define DMACHAN ((LCDC_DMACHAN_CTL_Type *)(DMA_REG_BASE + 0x100 + CONFIG_LCDC_DMA_CHAN_ID * 0x100))
  22. #define DMALINE ((LCDC_DMALINE_CTL_Type *)(DMA_LINE0_REG_BASE + 0x20 * CONFIG_LCDC_DMA_LINE_ID))
  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. bool busy;
  42. };
  43. static int lcdc_config_port(const struct device *dev, const struct display_videoport *port)
  44. {
  45. uint32_t lcd_ctl = LCD_EN | LCD_CLK_EN;
  46. if (port->type != DISPLAY_PORT_QSPI_SYNC) {
  47. lcd_ctl |= LCD_HOLD_EN;
  48. }
  49. switch (port->major_type) {
  50. case DISPLAY_PORT_MCU:
  51. lcd_ctl |= (port->minor_type == DISPLAY_MCU_8080) ?
  52. LCD_IF_SEL_MCU_8080 : LCD_IF_SEL_MCU_6880;
  53. lcd_ctl |= LCD_IF_CE_SEL(port->mcu_mode.cs) | LCD_IF_MLS_SEL(port->mcu_mode.lsb_first);
  54. LCDC->CPU_CTL = LCD_CPU_FEND_IRQ_EN | LCD_CPU_AHB_F565_16BIT | LCD_CPU_AHB_CSX(1);
  55. LCDC->CPU_CLK = LCD_CPU_CLK(port->mcu_mode.clk_high_duration,
  56. port->mcu_mode.clk_low_duration, port->mcu_mode.clk_low_duration);
  57. break;
  58. case DISPLAY_PORT_SPI:
  59. lcd_ctl |= LCD_IF_SEL_SPI;
  60. lcd_ctl |= LCD_IF_CE_SEL(port->spi_mode.cs) | LCD_IF_MLS_SEL(port->spi_mode.lsb_first);
  61. LCDC->SPI_CTL = LCD_SPI_FTC_IRQ_EN | LCD_SPI_FEND_PD_EN |
  62. LCD_SPI_CDX(1) | LCD_SPI_AHB_CSX(1) | LCD_SPI_AHB_F565_16BIT |
  63. LCD_SPI_TYPE_SEL(port->minor_type == LCD_QSPI_SYNC ? LCD_QSPI : port->minor_type) |
  64. LCD_SPI_SCLK_POL((port->spi_mode.cpol == port->spi_mode.cpha) ? 0 : 1) |
  65. LCD_SPI_DELAY_CHAIN_SEL(port->spi_mode.rd_delay_ns) |
  66. LCD_SPI_RDLC_SEL(port->spi_mode.rd_dummy_cycles) |
  67. LCD_SPI_DCP_SEL(port->spi_mode.dcp_mode) |
  68. LCD_SPI_DUAL_LANE_SEL(port->spi_mode.dual_lane);
  69. break;
  70. default:
  71. return -ENOTSUP;
  72. }
  73. LCDC->CTL = lcd_ctl;
  74. return 0;
  75. }
  76. static int lcdc_config_src_pixel_format(const struct device *dev,
  77. uint32_t pixel_format, uint8_t *bytes_per_pixel)
  78. {
  79. struct lcdc_data *data = dev->data;
  80. if (pixel_format == PIXEL_FORMAT_BGR_565) {
  81. *bytes_per_pixel = 2;
  82. switch (data->port->major_type) {
  83. case DISPLAY_PORT_SPI:
  84. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_RGB565;
  85. break;
  86. default:
  87. case DISPLAY_PORT_MCU:
  88. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_RGB565;
  89. break;
  90. }
  91. } else if (pixel_format == PIXEL_FORMAT_ARGB_8888 ||
  92. pixel_format == PIXEL_FORMAT_XRGB_8888) {
  93. *bytes_per_pixel = 4;
  94. switch (data->port->major_type) {
  95. case DISPLAY_PORT_SPI:
  96. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_ARGB8888;
  97. break;
  98. case DISPLAY_PORT_MCU:
  99. default:
  100. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_ARGB8888;
  101. break;
  102. }
  103. } else if (pixel_format == PIXEL_FORMAT_RGB_888) {
  104. *bytes_per_pixel = 3;
  105. switch (data->port->major_type) {
  106. case DISPLAY_PORT_SPI:
  107. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_RGB888;
  108. break;
  109. case DISPLAY_PORT_MCU:
  110. default:
  111. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_RGB888;
  112. break;
  113. }
  114. } else if (pixel_format == PIXEL_FORMAT_BGR_888) {
  115. *bytes_per_pixel = 3;
  116. switch (data->port->major_type) {
  117. case DISPLAY_PORT_SPI:
  118. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_BGR888;
  119. break;
  120. case DISPLAY_PORT_MCU:
  121. default:
  122. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_BGR888;
  123. break;
  124. } else {
  125. return -EINVAL;
  126. }
  127. return 0;
  128. }
  129. static int lcdc_config_mode(const struct device *dev, const struct display_videomode *mode)
  130. {
  131. struct lcdc_data *data = dev->data;
  132. clk_set_rate(CLOCK_ID_LCD, KHZ(mode->pixel_clk));
  133. LCDC->CTL &= ~(LCD_TE_EN | LCD_TE_MODE_MASK | LCD_OUT_FORMAT_MASK);
  134. #if USE_LCDC_TE
  135. if (mode->flags & DISPLAY_FLAGS_TE_HIGH) {
  136. LCDC->CTL |= LCD_TE_EN | LCD_TE_MODE_RISING_EDGE;
  137. } else if (mode->flags & DISPLAY_FLAGS_TE_LOW) {
  138. LCDC->CTL |= LCD_TE_EN | LCD_TE_MODE_FALLING_EDGE;
  139. }
  140. #endif
  141. switch (mode->pixel_format) {
  142. case PIXEL_FORMAT_BGR_565:
  143. LCDC->CTL |= LCD_OUT_FORMAT_RGB565;
  144. break;
  145. case PIXEL_FORMAT_RGB_888:
  146. case PIXEL_FORMAT_BGR_888:
  147. case PIXEL_FORMAT_ARGB_8888:
  148. case PIXEL_FORMAT_XRGB_8888:
  149. default:
  150. LCDC->CTL |= LCD_OUT_FORMAT_RGB888;
  151. break;
  152. }
  153. if (data->port->type == DISPLAY_PORT_QSPI_SYNC) {
  154. uint16_t data_cycles = mode->hactive *
  155. display_format_get_bits_per_pixel(mode->pixel_format) / 4;
  156. LCDC->QSPI_DTAS = LCD_QSPI_DTAS(0, data_cycles);
  157. LCDC->QSPI_SYNC_TIM = LCD_QSPI_SYNC_TIM(
  158. mode->hsync_len + mode->hback_porch + mode->hfront_porch,
  159. mode->vfront_porch, mode->vback_porch);
  160. }
  161. return 0;
  162. }
  163. static int lcdc_config_source(const struct device *dev,
  164. enum display_controller_source_type source_type)
  165. {
  166. static const uint32_t mcu_source_set[DISPLAY_CONTROLLER_NUM_SOURCES] = {
  167. LCD_CPU_SRC_SEL_AHB,
  168. LCD_CPU_SRC_SEL_DE | LCD_CPU_RS_HIGH,
  169. LCD_CPU_SRC_SEL_DMA | LCD_CPU_RS_HIGH,
  170. };
  171. static const uint32_t spi_source_set[DISPLAY_CONTROLLER_NUM_SOURCES] = {
  172. LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(1),
  173. LCD_SPI_SRC_SEL_DE | LCD_SPI_CDX(1),
  174. LCD_SPI_SRC_SEL_DMA | LCD_SPI_CDX(1),
  175. };
  176. struct lcdc_data *data = dev->data;
  177. #if CONFIG_LCDC_DMA_CHAN_ID < 0
  178. if (source_type == DISPLAY_CONTROLLER_SOURCE_DMA)
  179. return -EINVAL;
  180. #endif
  181. switch (data->port->major_type) {
  182. case DISPLAY_PORT_MCU:
  183. LCDC->CPU_CTL = (LCDC->CPU_CTL & ~(LCD_CPU_SRC_MASK | LCD_CPU_RS_MASK))
  184. | mcu_source_set[source_type];
  185. break;
  186. case DISPLAY_PORT_SPI:
  187. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~(LCD_SPI_SRC_MASK | LCD_SPI_CDX_MASK))
  188. | spi_source_set[source_type];
  189. break;
  190. default:
  191. return -EINVAL;
  192. }
  193. return 0;
  194. }
  195. static int lcdc_enable(const struct device *dev, const struct display_videoport *port)
  196. {
  197. struct lcdc_data *data = dev->data;
  198. if (data->port != NULL) {
  199. return -EALREADY;
  200. }
  201. if (port == NULL) {
  202. return -EINVAL;
  203. }
  204. /* initially use the CMU_LCDCLK default setting: HOSC 1/1 */
  205. //clk_set_rate(CLOCK_ID_LCD, MHZ(50));
  206. acts_reset_peripheral_assert(RESET_ID_LCD);
  207. acts_clock_peripheral_enable(CLOCK_ID_LCD);
  208. acts_reset_peripheral_deassert(RESET_ID_LCD);
  209. if (lcdc_config_port(dev, port)) {
  210. return -EINVAL;
  211. }
  212. /* FIXME: just save the pointer ? */
  213. data->port = port;
  214. data->mode = NULL;
  215. data->source_type = UINT8_MAX;
  216. return 0;
  217. }
  218. static int lcdc_disable(const struct device *dev)
  219. {
  220. struct lcdc_data *data = dev->data;
  221. if (data->port != NULL) {
  222. data->port = NULL;
  223. data->busy = false;
  224. #if CONFIG_LCDC_DMA_CHAN_ID >= 0
  225. DMACHAN->START = 0; /* force stop DMA */
  226. #endif
  227. acts_clock_peripheral_disable(CLOCK_ID_LCD);
  228. }
  229. return 0;
  230. }
  231. static int lcdc_set_mode(const struct device *dev,
  232. const struct display_videomode *mode)
  233. {
  234. struct lcdc_data *data = dev->data;
  235. if (mode == NULL) {
  236. return -EINVAL;
  237. }
  238. if (mode == data->mode) {
  239. return 0;
  240. }
  241. if (lcdc_config_mode(dev, mode)) {
  242. return -EINVAL;
  243. }
  244. /* FIXME: just save the pointer ? */
  245. data->mode = mode;
  246. return 0;
  247. }
  248. static int lcdc_set_source(const struct device *dev,
  249. enum display_controller_source_type source_type, const struct device *source_dev)
  250. {
  251. struct lcdc_data *data = dev->data;
  252. if (data->port == NULL) {
  253. return -EINVAL;
  254. }
  255. if (source_type == data->source_type) {
  256. return 0;
  257. }
  258. if (lcdc_config_source(dev, source_type)) {
  259. return -EINVAL;
  260. }
  261. data->source_type = source_type;
  262. return 0;
  263. }
  264. static void _read_config_data32(uint8_t *buf8, const uint32_t *data, uint32_t len)
  265. {
  266. int pos = (len >= 4) ? 24 : (len - 1) * 8;
  267. while (len-- > 0) {
  268. *buf8++ = (data[0] >> pos) & 0xFF;
  269. pos -= 8;
  270. if (pos < 0) {
  271. pos = 24;
  272. data++;
  273. }
  274. }
  275. }
  276. static int lcdc_read_config(const struct device *dev,
  277. uint32_t cmd, void *buf, uint32_t len)
  278. {
  279. struct lcdc_data *lcdc_data = dev->data;
  280. if (lcdc_data->port == NULL) {
  281. return -EINVAL;
  282. }
  283. if (buf == NULL || len == 0) {
  284. return -EINVAL;
  285. }
  286. if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
  287. uint32_t lcdc_spi_ctl = LCDC->SPI_CTL; /* save REG SPI_CTL */
  288. if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
  289. LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
  290. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(0);
  291. LCDC->DATA = cmd;
  292. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  293. LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_DUAL_LANE_MASK);
  294. if (len <= 4) {
  295. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA | LCD_SPI_RWL(len);
  296. uint32_t data = LCDC->DATA;
  297. _read_config_data32(buf, &data, len);
  298. } else {
  299. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA | LCD_SPI_RWL(1);
  300. do {
  301. *(uint8_t *)buf = LCDC->DATA & 0xff;
  302. buf = (uint8_t *)buf + 1;
  303. } while (--len > 0);
  304. }
  305. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  306. } else {
  307. uint32_t tmp_data[8];
  308. int i;
  309. if (len > 32)
  310. return -EDOM;
  311. /* config spi type 'LCD_QSPI_SYNC' to 'LCD_QSPI' temporarily */
  312. LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_TYPE_MASK);
  313. LCDC->SPI_CTL |= LCD_QSPI | LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA |
  314. LCD_SPI_CDX(0) | LCD_SPI_RWL(len);
  315. LCDC->QSPI_CMD = cmd;
  316. tmp_data[0] = LCDC->DATA;
  317. for (i = (len - 1) / 4 - 1; i >= 0; i--) {
  318. tmp_data[i + 1] = LCDC->DATA_1[i];
  319. }
  320. _read_config_data32(buf, tmp_data, len);
  321. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  322. }
  323. /* restore REG SPI_CTL */
  324. LCDC->SPI_CTL = lcdc_spi_ctl;
  325. } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
  326. uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save REG CPU_CTL */
  327. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  328. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_LOW;
  329. LCDC->DATA = cmd;
  330. LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
  331. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  332. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_HIGH;
  333. do {
  334. *(uint8_t *)buf = LCDC->DATA & 0xff;
  335. buf = (uint8_t *)buf + 1;
  336. } while (--len > 0);
  337. LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
  338. /* restore REG CPU_CTL */
  339. LCDC->CPU_CTL = lcdc_cpu_ctl;
  340. }
  341. return 0;
  342. }
  343. static int _fill_spi_config_data32(uint32_t *data, const uint8_t *buf8, uint32_t len)
  344. {
  345. int data_num = (len + 3) >> 2;
  346. for (; len >= 4; len -= 4) {
  347. *data++ = ((uint32_t)buf8[0] << 24) | ((uint32_t)buf8[1] << 16) |
  348. ((uint32_t)buf8[2] << 8) | buf8[3];
  349. buf8 += 4;
  350. }
  351. if (len > 0) {
  352. *data = *buf8++;
  353. while (--len > 0) {
  354. *data = (*data << 8) | (*buf8++);
  355. }
  356. }
  357. return data_num;
  358. }
  359. static int lcdc_write_config(const struct device *dev,
  360. uint32_t cmd, const void *buf, uint32_t len)
  361. {
  362. struct lcdc_data *lcdc_data = dev->data;
  363. const uint8_t *buf8 = buf;
  364. if (lcdc_data->port == NULL) {
  365. return -EINVAL;
  366. }
  367. if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
  368. uint32_t lcdc_spi_ctl = LCDC->SPI_CTL;
  369. if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
  370. if (cmd != DC_INVALID_CMD) {
  371. /* make sure source has selected AHB successfully */
  372. LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
  373. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(0);
  374. LCDC->DATA = cmd;
  375. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  376. }
  377. if (len > 0) {
  378. uint32_t data;
  379. LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_DUAL_LANE_MASK);
  380. if (len <= 4) {
  381. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA |
  382. LCD_SPI_CDX(1) | LCD_SPI_RWL(len);
  383. _fill_spi_config_data32(&data, buf8, len);
  384. LCDC->DATA = data;
  385. } else {
  386. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA |
  387. LCD_SPI_CDX(1) | LCD_SPI_RWL(1);
  388. do {
  389. LCDC->DATA = *buf8++;
  390. } while (--len > 0);
  391. }
  392. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  393. }
  394. } else {
  395. uint32_t tmp_data[8];
  396. int i;
  397. if (len > 32)
  398. return -EDOM;
  399. /* config spi type 'LCD_QSPI_SYNC' to 'LCD_QSPI' temporarily */
  400. LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_TYPE_MASK);
  401. LCDC->SPI_CTL |= LCD_QSPI | LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA |
  402. LCD_SPI_CDX(0) | LCD_SPI_RWL(len);
  403. /* Transfer sequence:
  404. * 1) DATA, DATA_1, ..., DATA_7
  405. * 2) In every DATA: always (effective) MSB first:
  406. * if 32 bit in DATA, then [31..24], [23..16], [15..8], [7..0]
  407. * if 24 bit in DATA, then [23..16], [15..8], [7..0]
  408. * if 16 bit in DATA, then [15..8], [7..0]
  409. * if 8 bit in DATA, then [7..0]
  410. */
  411. i = _fill_spi_config_data32(tmp_data, buf8, len);
  412. LCDC->QSPI_CMD = cmd;
  413. for (i -= 1; i > 0; i--) {
  414. LCDC->DATA_1[i - 1] = tmp_data[i];
  415. }
  416. LCDC->DATA = tmp_data[0];
  417. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  418. }
  419. /* restore REG SPI_CTL */
  420. LCDC->SPI_CTL = lcdc_spi_ctl;
  421. } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
  422. uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save REG CPU_CTL */
  423. if (cmd != DC_INVALID_CMD) {
  424. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  425. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_LOW;
  426. LCDC->DATA = cmd;
  427. LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
  428. }
  429. if (len > 0) {
  430. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  431. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_HIGH;
  432. do {
  433. LCDC->DATA = *buf8++;
  434. } while (--len > 0);
  435. LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
  436. }
  437. /* restore REG CPU_CTL */
  438. LCDC->CPU_CTL = lcdc_cpu_ctl;
  439. }
  440. return 0;
  441. }
  442. static int lcdc_write_pixels_by_mcu(const struct device *dev, uint32_t cmd,
  443. const struct display_buffer_descriptor *desc, const void *buf)
  444. {
  445. struct lcdc_data *lcdc_data = dev->data;
  446. uint32_t pixel_format = desc->pixel_format;
  447. uint16_t bytes_per_line;
  448. bool f565_24bit = false;
  449. int i, j;
  450. if (pixel_format == 0) {
  451. pixel_format = lcdc_data->mode->pixel_format;
  452. } else if (pixel_format != lcdc_data->mode->pixel_format) {
  453. if (pixel_format == PIXEL_FORMAT_ARGB_8888 && (
  454. lcdc_data->mode->pixel_format == PIXEL_FORMAT_BGR_565)) {
  455. f565_24bit = true;
  456. } else {
  457. return -EINVAL;
  458. }
  459. }
  460. bytes_per_line = (desc->pitch > 0) ? desc->pitch :
  461. (desc->width * display_format_get_bits_per_pixel(pixel_format) / 8);
  462. lcdc_data->busy = true;
  463. if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
  464. uint32_t lcdc_spi_ctl = LCDC->SPI_CTL; /* save LCD_SPI_CTL */
  465. LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
  466. LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(1) |
  467. (f565_24bit ? LCD_SPI_AHB_F565_24BIT : LCD_SPI_AHB_F565_16BIT);
  468. if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
  469. if (pixel_format == PIXEL_FORMAT_BGR_565) { // rgb565
  470. for (j = desc->height; j > 0; j--) {
  471. for (i = desc->width; i > 0; i--) {
  472. LCDC->DATA = *(uint16_t *)buf;
  473. buf = (uint16_t *)buf + 1;
  474. }
  475. buf = (uint8_t *)buf + (bytes_per_line - desc->width * 2);
  476. }
  477. } else { /* argb_8888 */
  478. for (j = desc->height; j > 0; j--) {
  479. for (i = desc->width; i > 0; i--) {
  480. LCDC->DATA = *(uint32_t *)buf;
  481. buf = (uint32_t *)buf + 1;
  482. }
  483. buf = (uint8_t *)buf + (bytes_per_line - desc->width * 4);
  484. }
  485. }
  486. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  487. } else {
  488. if (pixel_format == PIXEL_FORMAT_BGR_565) { // rgb565
  489. for (j = desc->height; j > 0; j--) {
  490. for (i = desc->width; i > 0; i--) {
  491. LCDC->SPI_CTL &= ~LCD_SPI_AHB_CSX_MASK;
  492. LCDC->QSPI_CMD = cmd;
  493. LCDC->DATA = *(uint16_t *)buf;
  494. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  495. buf = (uint16_t *)buf + 1;
  496. }
  497. buf = (uint8_t *)buf + (bytes_per_line - desc->width * 2);
  498. }
  499. } else { /* argb_8888 */
  500. for (j = desc->height; j > 0; j--) {
  501. for (i = desc->width; i > 0; i--) {
  502. LCDC->SPI_CTL &= ~LCD_SPI_AHB_CSX_MASK;
  503. LCDC->QSPI_CMD = cmd;
  504. LCDC->DATA = *(uint32_t *)buf;
  505. LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
  506. buf = (uint32_t *)buf + 1;
  507. }
  508. buf = (uint8_t *)buf + (bytes_per_line - desc->width * 4);
  509. }
  510. }
  511. }
  512. /* restore LCD_SPI_CTL */
  513. LCDC->SPI_CTL = lcdc_spi_ctl;
  514. } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
  515. uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save LCD_CPU_CTL */
  516. LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
  517. LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_IMG | LCD_CPU_RS_HIGH |
  518. (f565_24bit ? LCD_CPU_AHB_F565_24BIT : LCD_CPU_AHB_F565_16BIT);
  519. if (pixel_format == PIXEL_FORMAT_BGR_565) { // rgb565
  520. for (j = desc->height; j > 0; j--) {
  521. for (i = desc->width; i > 0; i--) {
  522. LCDC->DATA = *(uint16_t *)buf;
  523. buf = (uint16_t *)buf + 1;
  524. }
  525. buf = (uint8_t *)buf + (bytes_per_line - desc->width * 2);
  526. }
  527. } else { /* argb_8888 */
  528. for (j = desc->height; j > 0; j--) {
  529. for (i = desc->width; i > 0; i--) {
  530. LCDC->DATA = *(uint32_t *)buf;
  531. buf = (uint32_t *)buf + 1;
  532. }
  533. buf = (uint8_t *)buf + (bytes_per_line - desc->width * 4);
  534. }
  535. }
  536. /* restore LCD_CPU_CTL */
  537. LCDC->CPU_CTL = lcdc_cpu_ctl;
  538. }
  539. lcdc_data->busy = false;
  540. /* notify transfer completed */
  541. if (lcdc_data->complete_fn) {
  542. lcdc_data->complete_fn(lcdc_data->complete_fn_arg);
  543. }
  544. return 0;
  545. }
  546. static int lcdc_write_pixels_by_de(const struct device *dev,
  547. uint32_t cmd, uint32_t hsync_cmd,
  548. const struct display_buffer_descriptor *desc)
  549. {
  550. struct lcdc_data *data = dev->data;
  551. data->busy = true;
  552. /* only required for non-sync mode */
  553. LCDC->TPL = (uint32_t)desc->width * desc->height - 1;
  554. switch (data->port->major_type) {
  555. case DISPLAY_PORT_SPI:
  556. LOG_DBG("start spi-if\n");
  557. LCDC->QSPI_CMD = cmd;
  558. if (data->port->minor_type == DISPLAY_QSPI_SYNC) {
  559. LCDC->QSPI_CMD1 = hsync_cmd; /* only required for QUAD_SYNC */
  560. LCDC->QSPI_IMG_SIZE = LCD_QSPI_IMG_SIZE(desc->width, desc->height);
  561. LCDC->CTL &= ~LCD_EN;
  562. /* set to quad sync mode */
  563. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_TYPE_MASK) | LCD_QSPI_SYNC;
  564. LCDC->CTL |= LCD_EN;
  565. }
  566. LCDC->SPI_CTL |= LCD_SPI_START;
  567. break;
  568. case DISPLAY_PORT_MCU:
  569. default:
  570. LOG_DBG("start cpu-if\n");
  571. LCDC->CPU_CTL |= LCD_CPU_START;
  572. break;
  573. }
  574. return 0;
  575. }
  576. #if CONFIG_LCDC_DMA_CHAN_ID >= 0
  577. static int lcdc_write_pixels_by_dma(const struct device *dev,
  578. uint32_t cmd, uint32_t hsync_cmd,
  579. const struct display_buffer_descriptor *desc, const void *buf)
  580. {
  581. struct lcdc_data *data = dev->data;
  582. uint32_t pixel_format = desc->pixel_format;
  583. uint16_t copy_per_line, bytes_per_line;
  584. uint8_t bytes_per_pixel;
  585. if ((uintptr_t)buf & 0x3) {
  586. LOG_ERR("unaligned addr %p", buf);
  587. return -EINVAL;
  588. }
  589. if (pixel_format == 0) {
  590. pixel_format = data->mode->pixel_format;
  591. }
  592. if (lcdc_config_src_pixel_format(dev, pixel_format, &bytes_per_pixel)) {
  593. LOG_ERR("invalid pixel format 0x%x", pixel_format);
  594. return -EINVAL;
  595. }
  596. copy_per_line = desc->width * bytes_per_pixel;
  597. bytes_per_line = (desc->pitch > 0) ? desc->pitch : copy_per_line;
  598. if (copy_per_line != bytes_per_line &&
  599. ((copy_per_line & 0x3) || (bytes_per_line & 0x3))) {
  600. LOG_ERR("width %u or stride %u unaligned\n", desc->width, desc->pitch);
  601. return -EINVAL;
  602. }
  603. if (buf_is_psram(buf)) {
  604. buf = cache_to_uncache((void *)buf);
  605. }
  606. data->busy = true;
  607. /* configure DMA */
  608. assert(DMACHAN->START == 0);
  609. DMACHAN->BC = (uint32_t)copy_per_line * desc->height;
  610. DMACHAN->SADDR0 = (uint32_t)buf;
  611. DMACHAN->DADDR0 = (uint32_t)&LCDC->DATA;
  612. if (copy_per_line == bytes_per_line) {
  613. DMACHAN->CTL = BIT(15) | (0x16 << 8);
  614. } else {
  615. DMALINE->COUNT = desc->height;
  616. DMALINE->LENGTH = copy_per_line;
  617. DMALINE->STRIDE = bytes_per_line;
  618. DMACHAN->CTL = BIT(15) | (0x16 << 8) | BIT(24) | (CONFIG_LCDC_DMA_LINE_ID << 25);
  619. }
  620. /* start DMA */
  621. DMACHAN->START = 0x1;
  622. LCDC->DISP_SIZE = LCD_DISP_SIZE(desc->width, desc->height);
  623. if (data->port->major_type == DISPLAY_PORT_SPI) {
  624. LCDC->QSPI_CMD = cmd;
  625. if (data->port->minor_type == DISPLAY_QSPI_SYNC) {
  626. LCDC->QSPI_CMD1 = hsync_cmd;
  627. LCDC->QSPI_IMG_SIZE = LCD_QSPI_IMG_SIZE(desc->width, desc->height);
  628. LCDC->CTL &= ~LCD_EN;
  629. /* set to quad sync mode */
  630. LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_TYPE_MASK) | LCD_QSPI_SYNC;
  631. LCDC->CTL |= LCD_EN;
  632. }
  633. LCDC->SPI_CTL |= LCD_SPI_START;
  634. } else { /* DISPLAY_PORT_MCU */
  635. LCDC->CPU_CTL |= LCD_CPU_START;
  636. }
  637. return 0;
  638. }
  639. #endif /* CONFIG_LCDC_DMA_CHAN_ID >= 0 */
  640. static int lcdc_write_pixels(const struct device *dev,
  641. uint32_t cmd, uint32_t hsync_cmd,
  642. const struct display_buffer_descriptor *desc, const void *buf)
  643. {
  644. struct lcdc_data *data = dev->data;
  645. if (data->port == NULL || data->mode == NULL) {
  646. return -EINVAL;
  647. }
  648. switch (data->source_type) {
  649. #if CONFIG_LCDC_DMA_CHAN_ID >= 0
  650. case DISPLAY_CONTROLLER_SOURCE_DMA:
  651. return lcdc_write_pixels_by_dma(dev, cmd, hsync_cmd, desc, buf);
  652. #endif
  653. case DISPLAY_CONTROLLER_SOURCE_ENGINE:
  654. return lcdc_write_pixels_by_de(dev, cmd, hsync_cmd, desc);
  655. case DISPLAY_CONTROLLER_SOURCE_MCU:
  656. return lcdc_write_pixels_by_mcu(dev, cmd, desc, buf);
  657. default:
  658. return -EINVAL;
  659. }
  660. }
  661. static int lcdc_read_pixels(const struct device *dev, uint32_t cmd,
  662. const struct display_buffer_descriptor *desc, void *buf)
  663. {
  664. return -ENOTSUP;
  665. }
  666. static int lcdc_control(const struct device *dev, int cmd, void *arg1, void *arg2)
  667. {
  668. struct lcdc_data *data = dev->data;
  669. switch (cmd) {
  670. case DISPLAY_CONTROLLER_CTRL_COMPLETE_CB:
  671. data->complete_fn_arg = arg2;
  672. data->complete_fn = arg1;
  673. break;
  674. default:
  675. return -EINVAL;
  676. }
  677. return 0;
  678. }
  679. void lcdc_dump(void)
  680. {
  681. int i;
  682. printk("lcdc regs:\n");
  683. printk("\t LCD_CTL 0x%08x\n", LCDC->CTL);
  684. printk("\t LCD_DISP_SIZE 0x%08x\n", LCDC->DISP_SIZE);
  685. printk("\t LCD_CPU_CTL 0x%08x\n", LCDC->CPU_CTL);
  686. printk("\t LCD_DATA 0x%08x\n", LCDC->DATA);
  687. printk("\t LCD_CPU_CLK 0x%08x\n", LCDC->CPU_CLK);
  688. printk("\t LCD_TPL 0x%08x\n", LCDC->TPL);
  689. printk("\t LCD_SPI_CTL 0x%08x\n", LCDC->SPI_CTL);
  690. printk("\t LCD_QSPI_CMD 0x%08x\n", LCDC->QSPI_CMD);
  691. printk("\t LCD_QSPI_CMD1 0x%08x\n", LCDC->QSPI_CMD1);
  692. printk("\t LCD_QSPI_SYNC_TIM 0x%08x\n", LCDC->QSPI_SYNC_TIM);
  693. printk("\t LCD_QSPI_IMG_SIZE 0x%08x\n", LCDC->QSPI_IMG_SIZE);
  694. printk("\t DE_INTERFACE_CTL 0x%08x\n", LCDC->DE_INTERFACE_CTL);
  695. printk("\t LCD_PENDING 0x%08x\n", LCDC->PENDING);
  696. printk("\t LCD_QSPI_DTAS 0x%08x\n", LCDC->QSPI_DTAS);
  697. for (i = 0; i < ARRAY_SIZE(LCDC->DATA_1); i++) {
  698. printk("\t LCD_DATA_%d 0x%08x\n", i + 1, LCDC->DATA_1[i]);
  699. }
  700. #if CONFIG_LCDC_DMA_CHAN_ID >= 0
  701. printk("\t DMA_CTL 0x%08x\n", DMACHAN->CTL);
  702. printk("\t DMA_START 0x%08x\n", DMACHAN->START);
  703. printk("\t DMA_SADDR0 0x%08x\n", DMACHAN->SADDR0);
  704. printk("\t DMA_SADDR1 0x%08x\n", DMACHAN->SADDR1);
  705. printk("\t DMA_DADDR0 0x%08x\n", DMACHAN->DADDR0);
  706. printk("\t DMA_DADDR1 0x%08x\n", DMACHAN->DADDR1);
  707. printk("\t DMA_BC 0x%08x\n", DMACHAN->BC);
  708. printk("\t DMA_RC 0x%08x\n", DMACHAN->RC);
  709. printk("\t DMA_LINE_LENGTH 0x%08x\n", DMALINE->LENGTH);
  710. printk("\t DMA_LINE_COUNT 0x%08x\n", DMALINE->COUNT);
  711. printk("\t DMA_LINE_STRIDE 0x%08x\n", DMALINE->STRIDE);
  712. printk("\t DMA_LINE_REMAIN 0x%08x\n", DMALINE->REMAIN);
  713. #endif
  714. }
  715. static void lcdc_isr(const void *arg)
  716. {
  717. const struct device *dev = arg;
  718. struct lcdc_data *data = dev->data;
  719. uint32_t pending = LCDC->PENDING;
  720. LCDC->PENDING = pending;
  721. if (pending & LCD_STAT_FTC) {
  722. if (pending & LCD_STAT_QSPI_SYNC_FTC) {
  723. #if CONFIG_LCDC_DMA_CHAN_ID >= 0
  724. if (data->source_type == DISPLAY_CONTROLLER_SOURCE_DMA) {
  725. if (DMACHAN->START > 0) {
  726. LOG_ERR("LCD remain %u", DMACHAN->RC);
  727. DMACHAN->START = 0;
  728. }
  729. /* restart DMA */
  730. DMACHAN->START = 0x1;
  731. }
  732. #endif
  733. } else {
  734. data->busy = false;
  735. }
  736. if (data->complete_fn)
  737. data->complete_fn(data->complete_fn_arg);
  738. }
  739. LOG_DBG("LCD pending 0x%x", pending);
  740. }
  741. DEVICE_DECLARE(lcdc);
  742. static int lcdc_init(const struct device *dev)
  743. {
  744. IRQ_CONNECT(IRQ_ID_LCD, 0, lcdc_isr, DEVICE_GET(lcdc), 0);
  745. irq_enable(IRQ_ID_LCD);
  746. return 0;
  747. }
  748. #ifdef CONFIG_PM_DEVICE
  749. static int lcdc_pm_control(const struct device *dev, enum pm_device_action action)
  750. {
  751. struct lcdc_data *data = dev->data;
  752. int ret = 0;
  753. switch (action) {
  754. case PM_DEVICE_ACTION_SUSPEND:
  755. case PM_DEVICE_ACTION_FORCE_SUSPEND:
  756. case PM_DEVICE_ACTION_TURN_OFF:
  757. if (data->busy) {
  758. LOG_WRN("lcdc busy (action=%d)", action);
  759. ret = -EBUSY;
  760. }
  761. break;
  762. default:
  763. break;
  764. }
  765. return ret;
  766. }
  767. #endif /* CONFIG_PM_DEVICE */
  768. static const struct display_controller_driver_api lcdc_api = {
  769. .control = lcdc_control,
  770. .enable = lcdc_enable,
  771. .disable = lcdc_disable,
  772. .set_mode = lcdc_set_mode,
  773. .set_source = lcdc_set_source,
  774. .read_config = lcdc_read_config,
  775. .write_config = lcdc_write_config,
  776. .read_pixels = lcdc_read_pixels,
  777. .write_pixels = lcdc_write_pixels,
  778. };
  779. static struct lcdc_data lcdc_drv_data;
  780. DEVICE_DEFINE(lcdc, CONFIG_LCDC_DEV_NAME, &lcdc_init,
  781. lcdc_pm_control, &lcdc_drv_data, NULL, POST_KERNEL,
  782. CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &lcdc_api);