123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080 |
- /*
- * Copyright (c) 2020 Actions Technology Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include <soc.h>
- #include <spicache.h>
- #include <drivers/cfg_drv/dev_config.h>
- #include <drivers/display.h>
- #include <drivers/display/display_engine.h>
- #include <drivers/display/display_controller.h>
- #include <assert.h>
- #include <string.h>
- #include "lcdc_leopard.h"
- #include <logging/log.h>
- LOG_MODULE_REGISTER(lcdc, CONFIG_DISPLAY_LOG_LEVEL);
- #define USE_LCDC_TE 0
- #define USE_LCDC_SEND_DBG 0
- #define SUPPORTED_PIXEL_FORMATS (PIXEL_FORMAT_BGR_565 | PIXEL_FORMAT_RGB_888 | \
- PIXEL_FORMAT_BGR_888 | PIXEL_FORMAT_ARGB_8888 | PIXEL_FORMAT_XRGB_8888)
- #define LCDC ((LCDC_Type *)LCDC_REG_BASE)
- #define SDMA0 ((LCDC_SDMA_Type *)SDMA0_REG_BASE)
- #define SPI_AHB_CMD_MASK \
- (LCD_SPI_SRC_MASK | LCD_SPI_AHB_CSX_MASK | LCD_SPI_CDX_MASK)
- #define SPI_AHB_DATA_MASK \
- (SPI_AHB_CMD_MASK | LCD_SPI_AHB_F565_MASK | \
- LCD_SPI_AHB_CFG_DATA | LCD_SPI_RWL_MASK)
- #define CPU_AHB_CMD_MASK \
- (LCD_CPU_SRC_MASK | LCD_CPU_AHB_F565_MASK | \
- LCD_CPU_RS_MASK | LCD_CPU_AHB_DATA_MASK | LCD_CPU_AHB_CSX_MASK)
- #define CPU_AHB_DATA_MASK CPU_AHB_CMD_MASK
- struct lcdc_data {
- /* pointer to current video port passed in interface enable() */
- const struct display_videoport *port;
- /* pointer to current video mode passed in interface set_mode() */
- const struct display_videomode *mode;
- /* enum display_controller_source_type */
- uint8_t source_type;
- display_controller_complete_t complete_fn;
- void *complete_fn_arg;
- #ifdef CONFIG_PM_DEVICE
- const struct display_videoport *saved_port;
- const struct display_videomode *saved_mode;
- #endif
- bool busy;
- };
- static int lcdc_config_port(const struct device *dev, const struct display_videoport *port)
- {
- uint32_t lcd_ctl;
- #if USE_LCDC_SEND_DBG
- lcd_ctl = LCD_EN | LCD_CLK_EN | LCD_FIFO_EN | LCD_AUTO_RST_FIFO_EN | LCD_SDCHK_CLK_EN |
- LCD_IN_RGB666_CVT_LOW | LCD_IN_RGB565_CVT_LOW /*| LCD_OUT_RGB565_FORCE_555*/;
- LCDC->SD_CNT = LCD_SDCNT_EN;
- LCDC->SD_CHECKSUM = LCD_CHKSUM_EN;
- #else
- lcd_ctl = LCD_EN | LCD_CLK_EN | LCD_FIFO_EN | LCD_AUTO_RST_FIFO_EN |
- LCD_IN_RGB666_CVT_LOW | LCD_IN_RGB565_CVT_LOW /*| LCD_OUT_RGB565_FORCE_555*/;
- #endif /* USE_LCDC_SEND_DBG */
- if (port->type != DISPLAY_PORT_QSPI_SYNC) {
- lcd_ctl |= LCD_HOLD_EN;
- }
- switch (port->major_type) {
- case DISPLAY_PORT_MCU:
- lcd_ctl |= (port->minor_type == DISPLAY_MCU_8080) ? LCD_IF_SEL_MCU_8080 : LCD_IF_SEL_MCU_6880;
- lcd_ctl |= LCD_IF_CE_SEL(port->mcu_mode.cs) | LCD_IF_MLS_SEL(port->mcu_mode.lsb_first);
- LCDC->CPU_CTL = LCD_CPU_FEND_IRQ_EN | LCD_CPU_RX_DELAY_SEL(0) | LCD_CPU_AHB_F565_16BIT | LCD_CPU_AHB_CSX(1);
- LCDC->CPU_CLK = LCD_CPU_CLK(port->mcu_mode.clk_high_duration,
- port->mcu_mode.clk_low_duration, port->mcu_mode.clk_low_duration);
- break;
- case DISPLAY_PORT_SPI:
- lcd_ctl |= LCD_IF_SEL_SPI | LCD_IF_CE_SEL(port->spi_mode.cs) | LCD_IF_MLS_SEL(port->spi_mode.lsb_first);
- LCDC->SPI_CTL = LCD_SPI_FTC_IRQ_EN | LCD_SPI_FEND_PD_EN |
- LCD_SPI_CDX(1) | LCD_SPI_AHB_CSX(1) | LCD_SPI_AHB_F565_16BIT |
- LCD_SPI_TYPE_SEL(port->minor_type >= LCD_QSPI_SYNC ? LCD_QSPI : port->minor_type) |
- LCD_SPI_RD_DELAY_CHAIN_SEL(port->spi_mode.rd_delay_ns) |
- LCD_SPI_RD_LANE_SEL(port->spi_mode.rd_lane) |
- LCD_SPI_DCP_SEL(port->spi_mode.dcp_mode) |
- LCD_SPI_DUAL_LANE_SEL(port->spi_mode.dual_lane);
- LCDC->SPI_CTL1 = LCD_SPI_RDLC_SEL(port->spi_mode.rd_dummy_cycles) |
- LCD_SPI_AHB_CLK_DIV(port->spi_mode.ahb_clk_div);
- LCDC->SPI_CTL2 = LCD_SPI_SIG_DELAY(port->spi_mode.delay_csx_ns,
- port->spi_mode.delay_scl_ns, port->spi_mode.wr_delay_d0_ns,
- port->spi_mode.wr_delay_d1_ns, port->spi_mode.wr_delay_d2_ns,
- port->spi_mode.wr_delay_d3_ns);
- if (port->minor_type >= DISPLAY_QSPI_DDR_0) {
- LCDC->QSPI_DDR_CTL = LCD_SPI_MODE(port->spi_mode.cpol, port->spi_mode.cpha) |
- LCD_SPI_DDR_SEL(port->minor_type - DISPLAY_QSPI_DDR_0 + 1) |
- LCD_SPI_CLK_KEEP_SEL(0) | LCD_SPI_DDR_EN;
- } else if (port->minor_type == DISPLAY_QSPI) {
- LCDC->QSPI_DDR_CTL = LCD_SPI_MODE(port->spi_mode.cpol, port->spi_mode.cpha) |
- LCD_SPI_DDR_SEL(0) | LCD_SPI_CLK_KEEP_SEL(1) | LCD_SPI_DDR_EN;
- } else {
- LCDC->SPI_CTL |= LCD_SPI_SCLK_POL((port->spi_mode.cpol == port->spi_mode.cpha) ? 0 : 1);
- }
- break;
- case DISPLAY_PORT_TR:
- lcd_ctl |= LCD_IF_SEL_TR;
- LCDC->TR_CTL = LCD_TR_FTC_IRQ_EN | LCD_TR_F565_16BIT | LCD_TR_LB_SEL(port->tr_mode.low_bit) |
- LCD_TR_HCK_TAIL_EN(port->tr_mode.hck_tail_on) | LCD_TR_VCK_CONT_EN(port->tr_mode.vck_on_xrstl) |
- LCD_TR_VCK_MODE(port->tr_mode.vck_on_idle) | LCD_TR_HCK_MODE(port->tr_mode.hck_on_idle) |
- LCD_TR_PU_MODE(port->tr_mode.ptl_on) | LCD_TR_FRP_EN(port->tr_mode.frp_on) |
- LCD_TR_VCOM_INV(port->tr_mode.vcom_inv) | LCD_TR_FRP_INV(port->tr_mode.frp_inv) |
- LCD_TR_XFRP_INV(port->tr_mode.xfrp_inv) | LCD_TR_XRST_INV(port->tr_mode.xrst_inv) |
- LCD_TR_VST_INV(port->tr_mode.vst_inv) | LCD_TR_HST_INV(port->tr_mode.hst_inv) |
- LCD_TR_VCK_INV(port->tr_mode.vck_inv) | LCD_TR_HCK_INV(port->tr_mode.hck_inv) |
- LCD_TR_ENB_INV(port->tr_mode.enb_inv);
- LCDC->TR_TIM[0] = LCD_TR_TIM0(port->tr_mode.tw_xrst, port->tr_mode.tw_vcom);
- LCDC->TR_TIM[1] = LCD_TR_TIM1(port->tr_mode.td_vst, port->tr_mode.tw_vst,
- port->tr_mode.td_hst, port->tr_mode.tw_hst);
- LCDC->TR_TIM[2] = LCD_TR_TIM2(port->tr_mode.td_vck, port->tr_mode.tw_vck,
- port->tr_mode.tp_hck, port->tr_mode.td_hck);
- LCDC->TR_TIM[3] = LCD_TR_TIM3(port->tr_mode.ts_enb, port->tr_mode.th_enb,
- port->tr_mode.td_data);
- LCDC->TR_TIM[4] = LCD_TR_TIM4(port->tr_mode.td_enb, port->tr_mode.tw_enb);
- LCDC->TR_TIM[5] = LCD_TR_TIM5(port->tr_mode.tsm_enb, port->tr_mode.thm_enb,
- port->tr_mode.twm_vck);
- break;
- default:
- return -ENOTSUP;
- }
- LCDC->CTL = lcd_ctl;
- return 0;
- }
- static int lcdc_config_src_pixel_format(const struct device *dev,
- uint32_t pixel_format, uint8_t *bytes_per_pixel)
- {
- struct lcdc_data *data = dev->data;
- if (pixel_format == PIXEL_FORMAT_BGR_565) {
- *bytes_per_pixel = 2;
- switch (data->port->major_type) {
- case DISPLAY_PORT_SPI:
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_RGB565;
- break;
- case DISPLAY_PORT_MCU:
- LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_RGB565;
- case DISPLAY_PORT_TR:
- default:
- LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SDT_MASK) | LCD_TR_SDT_RGB565;
- break;
- }
- } else if (pixel_format == PIXEL_FORMAT_ARGB_8888 ||
- pixel_format == PIXEL_FORMAT_XRGB_8888) {
- *bytes_per_pixel = 4;
- switch (data->port->major_type) {
- case DISPLAY_PORT_SPI:
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_ARGB8888;
- break;
- case DISPLAY_PORT_MCU:
- LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_ARGB8888;
- case DISPLAY_PORT_TR:
- default:
- LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SDT_MASK) | LCD_TR_SDT_ARGB8888;
- break;
- }
- } else if (pixel_format == PIXEL_FORMAT_RGB_888) {
- *bytes_per_pixel = 3;
- switch (data->port->major_type) {
- case DISPLAY_PORT_SPI:
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_BGR888;
- break;
- case DISPLAY_PORT_MCU:
- LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_BGR888;
- case DISPLAY_PORT_TR:
- default:
- LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SDT_MASK) | LCD_TR_SDT_BGR888;
- break;
- }
- } else if (pixel_format == PIXEL_FORMAT_BGR_888) {
- *bytes_per_pixel = 3;
- switch (data->port->major_type) {
- case DISPLAY_PORT_SPI:
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_SDT_MASK) | LCD_SPI_SDT_RGB888;
- break;
- case DISPLAY_PORT_MCU:
- LCDC->CPU_CTL = (LCDC->CPU_CTL & ~LCD_SPI_SDT_MASK) | LCD_CPU_SDT_RGB888;
- case DISPLAY_PORT_TR:
- default:
- LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SDT_MASK) | LCD_TR_SDT_RGB888;
- break;
- }
- } else {
- return -EINVAL;
- }
- return 0;
- }
- static int lcdc_config_mode(const struct device *dev, const struct display_videomode *mode)
- {
- struct lcdc_data *data = dev->data;
- if (mode->hactive > 512 || mode->vactive > 512 ||
- (mode->pixel_format & SUPPORTED_PIXEL_FORMATS) == 0) {
- return -ENOTSUP;
- }
- clk_set_rate(CLOCK_ID_LCD, KHZ(mode->pixel_clk));
- LCDC->CTL &= ~(LCD_TE_EN | LCD_TE_MODE_MASK | LCD_OUT_FORMAT_MASK);
- #if USE_LCDC_TE
- if (mode->flags & DISPLAY_FLAGS_TE_HIGH) {
- LCDC->CTL |= LCD_TE_EN | LCD_TE_MODE_RISING_EDGE;
- } else if (mode->flags & DISPLAY_FLAGS_TE_LOW) {
- LCDC->CTL |= LCD_TE_EN | LCD_TE_MODE_FALLING_EDGE;
- }
- #endif
- switch (mode->pixel_format) {
- case PIXEL_FORMAT_BGR_565:
- LCDC->CTL |= LCD_OUT_FORMAT_RGB565;
- break;
- case PIXEL_FORMAT_RGB_888:
- case PIXEL_FORMAT_BGR_888:
- case PIXEL_FORMAT_ARGB_8888:
- case PIXEL_FORMAT_XRGB_8888:
- default:
- LCDC->CTL |= LCD_OUT_FORMAT_BGR888;
- break;
- }
- if (data->port->type == DISPLAY_PORT_QSPI_SYNC) {
- uint16_t data_cycles = mode->hactive *
- display_format_get_bits_per_pixel(mode->pixel_format) / 4;
- LCDC->QSPI_DTAS = LCD_QSPI_DTAS(0, data_cycles);
- LCDC->QSPI_SYNC_TIM = LCD_QSPI_SYNC_TIM(
- mode->hsync_len + mode->hback_porch + mode->hfront_porch,
- mode->vfront_porch, mode->vback_porch);
- } else if (data->port->type == DISPLAY_PORT_TR_LCD) {
- LCDC->TR_IMG_SIZE = LCD_TR_IMG_SIZE(mode->hactive, mode->vactive);
- }
- return 0;
- }
- static int lcdc_config_source(const struct device *dev,
- enum display_controller_source_type source_type)
- {
- static const uint32_t mcu_source_set[DISPLAY_CONTROLLER_NUM_SOURCES] = {
- LCD_CPU_SRC_SEL_AHB,
- LCD_CPU_SRC_SEL_DE | LCD_CPU_RS_HIGH,
- LCD_CPU_SRC_SEL_DMA | LCD_CPU_RS_HIGH,
- };
- static const uint32_t spi_source_set[DISPLAY_CONTROLLER_NUM_SOURCES] = {
- LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(1),
- LCD_SPI_SRC_SEL_DE | LCD_SPI_CDX(1),
- LCD_SPI_SRC_SEL_DMA | LCD_SPI_CDX(1),
- };
- static const uint32_t tr_source_set[DISPLAY_CONTROLLER_NUM_SOURCES] = {
- LCD_TR_SRC_SEL_DE,
- LCD_TR_SRC_SEL_DMA,
- };
- struct lcdc_data *data = dev->data;
- if (source_type >= DISPLAY_CONTROLLER_NUM_SOURCES) {
- return -EINVAL;
- }
- switch (data->port->major_type) {
- case DISPLAY_PORT_MCU:
- LCDC->CPU_CTL = (LCDC->CPU_CTL & ~(LCD_CPU_SRC_MASK | LCD_CPU_RS_MASK))
- | mcu_source_set[source_type];
- break;
- case DISPLAY_PORT_SPI:
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~(LCD_SPI_SRC_MASK | LCD_SPI_CDX_MASK))
- | spi_source_set[source_type];
- break;
- case DISPLAY_PORT_TR:
- if (source_type == DISPLAY_CONTROLLER_SOURCE_MCU)
- return -EINVAL;
- LCDC->TR_CTL = (LCDC->TR_CTL & ~LCD_TR_SRC_MASK)
- | tr_source_set[source_type - 1];
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int lcdc_enable(const struct device *dev, const struct display_videoport *port)
- {
- struct lcdc_data *data = dev->data;
- if (data->port != NULL) {
- return -EALREADY;
- }
- if (port == NULL) {
- return -EINVAL;
- }
- /* initially use the CMU_LCDCLK default setting: HOSC 1/1 */
- //clk_set_rate(CLOCK_ID_LCD, MHZ(50));
- acts_reset_peripheral_assert(RESET_ID_LCD);
- acts_clock_peripheral_enable(CLOCK_ID_LCD);
- acts_reset_peripheral_deassert(RESET_ID_LCD);
- if (lcdc_config_port(dev, port)) {
- return -EINVAL;
- }
- /* FIXME: just save the pointer ? */
- data->port = port;
- data->mode = NULL;
- data->source_type = UINT8_MAX;
- return 0;
- }
- static int lcdc_disable(const struct device *dev)
- {
- struct lcdc_data *data = dev->data;
- if (data->port != NULL) {
- data->port = NULL;
- data->busy = false;
- SDMA0->START = 0; /* force stop DMA */
- acts_clock_peripheral_disable(CLOCK_ID_LCD);
- }
- return 0;
- }
- static int lcdc_set_mode(const struct device *dev,
- const struct display_videomode *mode)
- {
- struct lcdc_data *data = dev->data;
- if (mode == NULL) {
- return -EINVAL;
- }
- if (mode == data->mode) {
- return 0;
- }
- if (lcdc_config_mode(dev, mode)) {
- return -EINVAL;
- }
- /* FIXME: just save the pointer ? */
- data->mode = mode;
- return 0;
- }
- static int lcdc_set_source(const struct device *dev,
- enum display_controller_source_type source_type, const struct device *source_dev)
- {
- struct lcdc_data *data = dev->data;
- if (data->port == NULL) {
- return -EINVAL;
- }
- if (source_type == data->source_type) {
- return 0;
- }
- if (lcdc_config_source(dev, source_type)) {
- return -EINVAL;
- }
- data->source_type = source_type;
- return 0;
- }
- static void _read_config_data32(uint8_t *buf8, const uint32_t *data, uint32_t len)
- {
- int pos = (len >= 4) ? 24 : (len - 1) * 8;
- while (len-- > 0) {
- *buf8++ = (data[0] >> pos) & 0xFF;
- pos -= 8;
- if (pos < 0) {
- pos = 24;
- data++;
- }
- }
- }
- static int lcdc_read_config(const struct device *dev,
- uint32_t cmd, void *buf, uint32_t len)
- {
- struct lcdc_data *lcdc_data = dev->data;
- if (lcdc_data->port == NULL) {
- return -EINVAL;
- }
- if (buf == NULL || len == 0) {
- return -EINVAL;
- }
- if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
- uint32_t lcdc_spi_ctl = LCDC->SPI_CTL; /* save REG SPI_CTL */
- uint32_t lcdc_spi_ctl1 = LCDC->SPI_CTL1; /* save REG SPI_CTL1 */
- LCDC->SPI_CTL1 |= LCD_SPI_AHB_CLK_DIV_MAX; /* set lowest clock */
- if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
- LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
- LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(0);
- LCDC->DATA = cmd;
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_DUAL_LANE_MASK);
- if (len <= 4) {
- LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA | LCD_SPI_RWL(len);
- uint32_t data = LCDC->DATA;
- _read_config_data32(buf, &data, len);
- } else {
- LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA | LCD_SPI_RWL(1);
- do {
- *(uint8_t *)buf = LCDC->DATA & 0xff;
- buf = (uint8_t *)buf + 1;
- } while (--len > 0);
- }
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- } else {
- uint32_t tmp_data[8];
- int i;
- if (len > 32)
- return -EDOM;
- /* config spi type 'LCD_QSPI_SYNC' to 'LCD_QSPI' temporarily */
- LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_TYPE_MASK);
- LCDC->SPI_CTL |= LCD_QSPI | LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA |
- LCD_SPI_CDX(0) | LCD_SPI_RWL(len);
- LCDC->QSPI_CMD = cmd;
- tmp_data[0] = LCDC->DATA;
- for (i = (len - 1) / 4 - 1; i >= 0; i--) {
- tmp_data[i + 1] = LCDC->DATA_1[i];
- }
- _read_config_data32(buf, tmp_data, len);
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- }
- /* restore REG SPI_CTL */
- LCDC->SPI_CTL = lcdc_spi_ctl;
- LCDC->SPI_CTL1 = lcdc_spi_ctl1;
- } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
- uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save REG CPU_CTL */
- LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
- LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_LOW;
- LCDC->DATA = cmd;
- LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
- LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
- LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_HIGH;
- do {
- *(uint8_t *)buf = LCDC->DATA & 0xff;
- buf = (uint8_t *)buf + 1;
- } while (--len > 0);
- LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
- /* restore REG CPU_CTL */
- LCDC->CPU_CTL = lcdc_cpu_ctl;
- }
- return 0;
- }
- static int _fill_spi_config_data32(uint32_t *data, const uint8_t *buf8, uint32_t len)
- {
- int data_num = (len + 3) >> 2;
- for (; len >= 4; len -= 4) {
- *data++ = ((uint32_t)buf8[0] << 24) | ((uint32_t)buf8[1] << 16) |
- ((uint32_t)buf8[2] << 8) | buf8[3];
- buf8 += 4;
- }
- if (len > 0) {
- *data = *buf8++;
- while (--len > 0) {
- *data = (*data << 8) | (*buf8++);
- }
- }
- return data_num;
- }
- static int lcdc_write_config(const struct device *dev,
- uint32_t cmd, const void *buf, uint32_t len)
- {
- struct lcdc_data *lcdc_data = dev->data;
- const uint8_t *buf8 = buf;
- if (lcdc_data->port == NULL) {
- return -EINVAL;
- }
- if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
- uint32_t lcdc_spi_ctl = LCDC->SPI_CTL;
- if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
- if (cmd != DC_INVALID_CMD) {
- /* make sure source has selected AHB successfully */
- LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
- LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(0);
- LCDC->DATA = cmd;
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- }
- if (len > 0) {
- uint32_t data;
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~(SPI_AHB_DATA_MASK | LCD_SPI_DUAL_LANE_MASK)) |
- (LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA | LCD_SPI_CDX(1) | LCD_SPI_RWL(4));
- for (; len >= 4; buf8 += 4, len -= 4) {
- LCDC->SPI_CTL &= ~LCD_SPI_AHB_CSX_MASK;
- _fill_spi_config_data32(&data, buf8, 4);
- LCDC->DATA = data;
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- }
- if (len > 0) {
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~(LCD_SPI_RWL_MASK | LCD_SPI_AHB_CSX_MASK)) | LCD_SPI_RWL(len);
- _fill_spi_config_data32(&data, buf8, len);
- LCDC->DATA = data;
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- }
- }
- } else {
- uint32_t tmp_data[8];
- int i;
- if (len > 32)
- return -EDOM;
- /* config spi type 'LCD_QSPI_SYNC' to 'LCD_QSPI' temporarily */
- LCDC->SPI_CTL &= ~(SPI_AHB_DATA_MASK | LCD_SPI_TYPE_MASK);
- LCDC->SPI_CTL |= LCD_QSPI | LCD_SPI_SRC_SEL_AHB | LCD_SPI_AHB_CFG_DATA |
- LCD_SPI_CDX(0) | LCD_SPI_RWL(len);
- /* Transfer sequence:
- * 1) DATA, DATA_1, ..., DATA_7
- * 2) In every DATA: always (effective) MSB first:
- * if 32 bit in DATA, then [31..24], [23..16], [15..8], [7..0]
- * if 24 bit in DATA, then [23..16], [15..8], [7..0]
- * if 16 bit in DATA, then [15..8], [7..0]
- * if 8 bit in DATA, then [7..0]
- */
- i = _fill_spi_config_data32(tmp_data, buf8, len);
- LCDC->QSPI_CMD = cmd;
- for (i -= 1; i > 0; i--) {
- LCDC->DATA_1[i - 1] = tmp_data[i];
- }
- LCDC->DATA = tmp_data[0];
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- }
- /* restore REG SPI_CTL */
- LCDC->SPI_CTL = lcdc_spi_ctl;
- } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
- uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save REG CPU_CTL */
- if (cmd != DC_INVALID_CMD) {
- LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
- LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_LOW;
- LCDC->DATA = cmd;
- LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
- }
- if (len > 0) {
- LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
- LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_CFG | LCD_CPU_RS_HIGH;
- do {
- LCDC->DATA = *buf8++;
- } while (--len > 0);
- LCDC->CPU_CTL |= LCD_CPU_AHB_CSX(1);
- }
- /* restore REG CPU_CTL */
- LCDC->CPU_CTL = lcdc_cpu_ctl;
- }
- return 0;
- }
- static int lcdc_write_pixels_by_mcu(const struct device *dev, uint32_t cmd,
- const struct display_buffer_descriptor *desc, const void *buf)
- {
- struct lcdc_data *lcdc_data = dev->data;
- uint32_t pixel_format = desc->pixel_format;
- const uint8_t *buf8 = buf;
- int16_t row_offset;
- uint16_t bytes_per_line;
- uint8_t bytes_per_pixel;
- bool f565_24bit = false;
- int i, j;
- if (lcdc_data->port->type == DISPLAY_PORT_TR_LCD ||
- lcdc_data->port->type == DISPLAY_PORT_QSPI_SYNC) {
- return -ENOTSUP;
- }
- if (pixel_format == 0) {
- pixel_format = lcdc_data->mode->pixel_format;
- }
- if (lcdc_config_src_pixel_format(dev, pixel_format, &bytes_per_pixel)) {
- LOG_ERR("invalid pixel format 0x%x", pixel_format);
- return -EINVAL;
- }
- bytes_per_line = (desc->pitch > 0) ? desc->pitch : desc->width * bytes_per_pixel;
- row_offset = bytes_per_line - desc->width * bytes_per_pixel;
- if (CONFIG_LCDC_Y_FLIP) {
- row_offset -= bytes_per_line * 2;
- buf8 += (uint32_t)bytes_per_line * (desc->height - 1);
- }
- lcdc_data->busy = true;
- if (lcdc_data->port->major_type == DISPLAY_PORT_SPI) {
- uint32_t lcdc_spi_ctl = LCDC->SPI_CTL; /* save LCD_SPI_CTL */
- LCDC->SPI_CTL &= ~SPI_AHB_DATA_MASK;
- LCDC->SPI_CTL |= LCD_SPI_SRC_SEL_AHB | LCD_SPI_CDX(1) |
- (f565_24bit ? LCD_SPI_AHB_F565_24BIT : LCD_SPI_AHB_F565_16BIT);
- if (lcdc_data->port->minor_type < DISPLAY_QSPI) {
- for (j = desc->height; j > 0; j--) {
- for (i = desc->width; i > 0; i--) {
- uint32_t color;
- switch (bytes_per_pixel) {
- case 2: /* PIXEL_FORMAT_BGR_565 */
- color = buf8[0] | ((uint32_t)buf8[1] << 8);
- break;
- case 3: /* PIXEL_FORMAT_RGB_888 or PIXEL_FORMAT_BGR_888 */
- color = ((uint32_t)buf8[0] << 16) | ((uint32_t)buf8[1] << 8) | buf8[2];
- break;
- default:
- color = buf8[0] | ((uint32_t)buf8[1] << 8) | ((uint32_t)buf8[2] << 16) | ((uint32_t)buf8[3] << 24);
- break;
- }
- LCDC->DATA = color;
- buf8 += bytes_per_pixel;
- }
- buf8 += row_offset;
- }
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- } else {
- for (j = desc->height; j > 0; j--) {
- for (i = desc->width; i > 0; i--) {
- uint32_t color;
- switch (bytes_per_pixel) {
- case 2: /* PIXEL_FORMAT_BGR_565 */
- color = buf8[0] | ((uint32_t)buf8[1] << 8);
- break;
- case 3: /* PIXEL_FORMAT_RGB_888 or PIXEL_FORMAT_BGR_888 */
- color = ((uint32_t)buf8[0] << 16) | ((uint32_t)buf8[1] << 8) | buf8[2];
- break;
- default:
- color = buf8[0] | ((uint32_t)buf8[1] << 8) | ((uint32_t)buf8[2] << 16) | ((uint32_t)buf8[3] << 24);
- break;
- }
- LCDC->SPI_CTL &= ~LCD_SPI_AHB_CSX_MASK;
- LCDC->QSPI_CMD = cmd;
- LCDC->DATA = color;
- LCDC->SPI_CTL |= LCD_SPI_AHB_CSX(1);
- buf8 += bytes_per_pixel;
- }
- buf8 += row_offset;
- }
- }
- /* restore LCD_SPI_CTL */
- LCDC->SPI_CTL = lcdc_spi_ctl;
- } else if (lcdc_data->port->major_type == DISPLAY_PORT_MCU) {
- uint32_t lcdc_cpu_ctl = LCDC->CPU_CTL; /* save LCD_CPU_CTL */
- LCDC->CPU_CTL &= ~CPU_AHB_CMD_MASK;
- LCDC->CPU_CTL |= LCD_CPU_AHB_DATA_SEL_IMG | LCD_CPU_RS_HIGH |
- (f565_24bit ? LCD_CPU_AHB_F565_24BIT : LCD_CPU_AHB_F565_16BIT);
- for (j = desc->height; j > 0; j--) {
- for (i = desc->width; i > 0; i--) {
- uint32_t color;
- switch (bytes_per_pixel) {
- case 2: /* PIXEL_FORMAT_BGR_565 */
- color = buf8[0] | ((uint32_t)buf8[1] << 8);
- break;
- case 3: /* PIXEL_FORMAT_RGB_888 or PIXEL_FORMAT_BGR_888 */
- color = ((uint32_t)buf8[0] << 16) | ((uint32_t)buf8[1] << 8) | buf8[2];
- break;
- default:
- color = buf8[0] | ((uint32_t)buf8[1] << 8) | ((uint32_t)buf8[2] << 16) | ((uint32_t)buf8[3] << 24);
- break;
- }
- LCDC->DATA = color;
- buf8 += bytes_per_pixel;
- }
- buf8 += row_offset;
- }
- /* restore LCD_CPU_CTL */
- LCDC->CPU_CTL = lcdc_cpu_ctl;
- }
- lcdc_data->busy = false;
- /* notify transfer completed */
- if (lcdc_data->complete_fn) {
- lcdc_data->complete_fn(lcdc_data->complete_fn_arg);
- }
- return 0;
- }
- static int lcdc_write_pixels_by_de(const struct device *dev,
- uint32_t cmd, uint32_t hsync_cmd,
- const struct display_buffer_descriptor *desc)
- {
- struct lcdc_data *data = dev->data;
- data->busy = true;
- /* only required for non-sync mode */
- LCDC->TPL = (uint32_t)desc->width * desc->height - 1;
- switch (data->port->major_type) {
- case DISPLAY_PORT_SPI:
- LOG_DBG("start spi-if\n");
- LCDC->QSPI_CMD = cmd;
- if (data->port->minor_type == DISPLAY_QSPI_SYNC) {
- LCDC->QSPI_CMD1 = hsync_cmd; /* only required for QUAD_SYNC */
- LCDC->QSPI_IMG_SIZE = LCD_QSPI_IMG_SIZE(desc->width, desc->height);
- LCDC->CTL &= ~LCD_EN;
- /* set to quad sync mode */
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_TYPE_MASK) | LCD_QSPI_SYNC;
- LCDC->CTL |= LCD_EN;
- }
- LCDC->SPI_CTL |= LCD_SPI_START;
- break;
- case DISPLAY_PORT_MCU:
- LOG_DBG("start cpu-if\n");
- LCDC->CPU_CTL |= LCD_CPU_START;
- break;
- case DISPLAY_PORT_TR:
- default:
- LOG_DBG("start tr-if\n");
- LCDC->TR_CTL |= LCD_TR_START;
- break;
- }
- return 0;
- }
- static int lcdc_write_pixels_by_dma(const struct device *dev,
- uint32_t cmd, uint32_t hsync_cmd,
- const struct display_buffer_descriptor *desc, const void *buf)
- {
- struct lcdc_data *data = dev->data;
- uint32_t pixel_format = desc->pixel_format;
- uint16_t copy_per_line, bytes_per_line;
- uint8_t bytes_per_pixel;
- if (pixel_format == 0) {
- pixel_format = data->mode->pixel_format;
- }
- if (lcdc_config_src_pixel_format(dev, pixel_format, &bytes_per_pixel)) {
- LOG_ERR("invalid pixel format 0x%x", pixel_format);
- return -EINVAL;
- }
- copy_per_line = desc->width * bytes_per_pixel;
- bytes_per_line = (desc->pitch > 0) ? desc->pitch : copy_per_line;
- buf = cache_to_uncache((void *)buf);
- data->busy = true;
- /* configure DMA */
- assert(SDMA0->START == 0);
- if (CONFIG_LCDC_Y_FLIP) {
- SDMA0->CTL = BIT(24) | BIT(6); /* stride mode and address decrease mode */
- SDMA0->SADDR = (uint32_t)buf + bytes_per_line * (desc->height - 1);
- } else {
- SDMA0->CTL = BIT(24); /* stride mode */
- SDMA0->SADDR = (uint32_t)buf;
- }
- SDMA0->COUNT = desc->height;
- SDMA0->LENGTH = copy_per_line;
- SDMA0->SSTRIDE = bytes_per_line;
- SDMA0->BC = (uint32_t)copy_per_line * desc->height;
- /* start DMA */
- SDMA0->START = 0x1;
- LCDC->DISP_SIZE = LCD_DISP_SIZE(desc->width, desc->height);
- switch (data->port->major_type) {
- case DISPLAY_PORT_SPI:
- LCDC->QSPI_CMD = cmd;
- if (data->port->minor_type == DISPLAY_QSPI_SYNC) {
- LCDC->QSPI_CMD1 = hsync_cmd;
- LCDC->QSPI_IMG_SIZE = LCD_QSPI_IMG_SIZE(desc->width, desc->height);
- LCDC->CTL &= ~LCD_EN;
- /* set to quad sync mode */
- LCDC->SPI_CTL = (LCDC->SPI_CTL & ~LCD_SPI_TYPE_MASK) | LCD_QSPI_SYNC;
- LCDC->CTL |= LCD_EN;
- }
- LOG_DBG("start spi-if\n");
- LCDC->SPI_CTL |= LCD_SPI_START;
- break;
- case DISPLAY_PORT_MCU:
- LOG_DBG("start cpu-if\n");
- LCDC->CPU_CTL |= LCD_CPU_START;
- break;
- case DISPLAY_PORT_TR:
- default:
- LOG_DBG("start tr-if\n");
- LCDC->TR_CTL |= LCD_TR_START;
- break;
- }
- return 0;
- }
- static int lcdc_write_pixels(const struct device *dev,
- uint32_t cmd, uint32_t hsync_cmd,
- const struct display_buffer_descriptor *desc, const void *buf)
- {
- struct lcdc_data *data = dev->data;
- if (data->port == NULL || data->mode == NULL) {
- return -EINVAL;
- }
- switch (data->source_type) {
- case DISPLAY_CONTROLLER_SOURCE_DMA:
- return lcdc_write_pixels_by_dma(dev, cmd, hsync_cmd, desc, buf);
- case DISPLAY_CONTROLLER_SOURCE_ENGINE:
- return lcdc_write_pixels_by_de(dev, cmd, hsync_cmd, desc);
- case DISPLAY_CONTROLLER_SOURCE_MCU:
- return lcdc_write_pixels_by_mcu(dev, cmd, desc, buf);
- default:
- return -EINVAL;
- }
- }
- static int lcdc_read_pixels(const struct device *dev, uint32_t cmd,
- const struct display_buffer_descriptor *desc, void *buf)
- {
- return -ENOTSUP;
- }
- static int lcdc_control(const struct device *dev, int cmd, void *arg1, void *arg2)
- {
- struct lcdc_data *data = dev->data;
- switch (cmd) {
- case DISPLAY_CONTROLLER_CTRL_COMPLETE_CB:
- data->complete_fn_arg = arg2;
- data->complete_fn = arg1;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- void lcdc_dump(void)
- {
- int i;
- printk("lcdc regs:\n");
- printk("\t LCD_CTL 0x%08x\n", LCDC->CTL);
- printk("\t LCD_DISP_SIZE 0x%08x\n", LCDC->DISP_SIZE);
- printk("\t LCD_CPU_CTL 0x%08x\n", LCDC->CPU_CTL);
- printk("\t LCD_DATA 0x%08x\n", LCDC->DATA);
- printk("\t LCD_CPU_CLK 0x%08x\n", LCDC->CPU_CLK);
- printk("\t LCD_TPL 0x%08x\n", LCDC->TPL);
- printk("\t LCD_SPI_CTL 0x%08x\n", LCDC->SPI_CTL);
- printk("\t LCD_QSPI_CMD 0x%08x\n", LCDC->QSPI_CMD);
- printk("\t LCD_QSPI_CMD1 0x%08x\n", LCDC->QSPI_CMD1);
- printk("\t LCD_QSPI_SYNC_TIM 0x%08x\n", LCDC->QSPI_SYNC_TIM);
- printk("\t LCD_QSPI_IMG_SIZE 0x%08x\n", LCDC->QSPI_IMG_SIZE);
- printk("\t DE_INTERFACE_CTL 0x%08x\n", LCDC->DE_INTERFACE_CTL);
- printk("\t LCD_PENDING 0x%08x\n", LCDC->PENDING);
- printk("\t LCD_QSPI_DTAS 0x%08x\n", LCDC->QSPI_DTAS);
- for (i = 0; i < ARRAY_SIZE(LCDC->DATA_1); i++) {
- printk("\t LCD_DATA_%d 0x%08x\n", i + 1, LCDC->DATA_1[i]);
- }
- printk("\t LCD_SPI_CTL1 0x%08x\n", LCDC->SPI_CTL1);
- printk("\t LCD_SPI_CTL2 0x%08x\n", LCDC->SPI_CTL2);
- printk("\t LCD_QSPI_DDR_CTL 0x%08x\n", LCDC->QSPI_DDR_CTL);
- printk("\t LCD_SD_CNT 0x%08x\n", LCDC->SD_CNT);
- printk("\t LCD_SD_CHECKSUM 0x%08x\n", LCDC->SD_CHECKSUM);
- printk("\t LCD_TR_CTL 0x%08x\n", LCDC->TR_CTL);
- printk("\t LCD_TR_IMG_SIZE 0x%08x\n", LCDC->TR_IMG_SIZE);
- for (i = 0; i < ARRAY_SIZE(LCDC->TR_TIM); i++) {
- printk("\t LCD_TR_TIM_%d 0x%08x\n", i, LCDC->TR_TIM[i]);
- }
- printk("\t SDMA0_CTL 0x%08x\n", SDMA0->CTL);
- printk("\t SDMA0_START 0x%08x\n", SDMA0->START);
- printk("\t SDMA0_SADDR 0x%08x\n", SDMA0->SADDR);
- printk("\t SDMA0_BC 0x%08x\n", SDMA0->BC);
- printk("\t SDMA0_RC 0x%08x\n", SDMA0->RC);
- printk("\t SDMA0_LINE_LENGTH 0x%08x\n", SDMA0->LENGTH);
- printk("\t SDMA0_LINE_COUNT 0x%08x\n", SDMA0->COUNT);
- printk("\t SDMA0_LINE_SSTRIDE 0x%08x\n", SDMA0->SSTRIDE);
- printk("\t SDMA0_LINE_REMAIN 0x%08x\n", SDMA0->REMAIN);
- }
- static void lcdc_isr(const void *arg)
- {
- const struct device *dev = arg;
- struct lcdc_data *data = dev->data;
- uint32_t pending = LCDC->PENDING;
- LCDC->PENDING = pending;
- if (pending & LCD_STAT_FTC) {
- if (pending & LCD_STAT_QSPI_SYNC_FTC) {
- if (data->source_type == DISPLAY_CONTROLLER_SOURCE_DMA) {
- if (SDMA0->START > 0) {
- LOG_ERR("LCD remain %u", SDMA0->RC);
- SDMA0->START = 0;
- }
- /* restart DMA */
- SDMA0->START = 0x1;
- }
- } else {
- data->busy = false;
- }
- if (data->complete_fn)
- data->complete_fn(data->complete_fn_arg);
- }
- LOG_DBG("LCD pending 0x%x", pending);
- }
- DEVICE_DECLARE(lcdc);
- static int lcdc_init(const struct device *dev)
- {
- IRQ_CONNECT(IRQ_ID_LCD, 0, lcdc_isr, DEVICE_GET(lcdc), 0);
- irq_enable(IRQ_ID_LCD);
- return 0;
- }
- #ifdef CONFIG_PM_DEVICE
- static int lcdc_pm_control(const struct device *dev, enum pm_device_action action)
- {
- struct lcdc_data *data = dev->data;
- int ret = 0;
- switch (action) {
- case PM_DEVICE_ACTION_SUSPEND:
- case PM_DEVICE_ACTION_FORCE_SUSPEND:
- case PM_DEVICE_ACTION_TURN_OFF:
- sl_dbg("lcdc suspend\n");
- if (data->busy) {
- LOG_WRN("lcdc busy (action=%d)", action);
- ret = -EBUSY;
- } else {
- data->saved_port = data->port;
- data->saved_mode = data->mode;
- lcdc_disable(dev);
- }
- break;
- case PM_DEVICE_ACTION_RESUME:
- if (data->saved_port) {
- lcdc_enable(dev, data->saved_port);
- if (data->saved_mode)
- lcdc_set_mode(dev, data->saved_mode);
- }
- sl_dbg("lcdc resume\n");
- break;
- default:
- break;
- }
- return ret;
- }
- #endif /* CONFIG_PM_DEVICE */
- static const struct display_controller_driver_api lcdc_api = {
- .control = lcdc_control,
- .enable = lcdc_enable,
- .disable = lcdc_disable,
- .set_mode = lcdc_set_mode,
- .set_source = lcdc_set_source,
- .read_config = lcdc_read_config,
- .write_config = lcdc_write_config,
- .read_pixels = lcdc_read_pixels,
- .write_pixels = lcdc_write_pixels,
- };
- static struct lcdc_data lcdc_drv_data;
- DEVICE_DEFINE(lcdc, CONFIG_LCDC_DEV_NAME, &lcdc_init,
- lcdc_pm_control, &lcdc_drv_data, NULL, POST_KERNEL,
- CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &lcdc_api);
|