1010#include <zephyr/drivers/clock_control.h>
1111#include <zephyr/kernel.h>
1212#include <fsl_lcdifv3.h>
13-
1413#include <zephyr/logging/log.h>
1514#include <zephyr/irq.h>
1615#include <zephyr/cache.h>
1716
18- #define MCUX_LCDIFV3_FB_NUM 1
19-
2017LOG_MODULE_REGISTER (display_mcux_lcdifv3 , CONFIG_DISPLAY_LOG_LEVEL );
2118
2219/* Required by DEVICE_MMIO_NAMED_* macros */
@@ -40,56 +37,103 @@ struct mcux_lcdifv3_config {
4037 lcdifv3_buffer_config_t buffer_config ;
4138 lcdifv3_display_config_t display_config ;
4239 enum display_pixel_format pixel_format ;
43- size_t pixel_bytes ;
40+ uint8_t * fb_ptr ;
4441 size_t fb_bytes ;
4542};
4643
4744struct mcux_lcdifv3_data {
4845 DEVICE_MMIO_NAMED_RAM (reg_base );
49- uint8_t * fb_ptr ;
50- uint8_t * fb [MCUX_LCDIFV3_FB_NUM ];
46+ /* Pointer to active framebuffer */
47+ const uint8_t * active_fb ;
48+ uint8_t * fb [CONFIG_MCUX_LCDIFV3_FB_NUM ];
49+ uint8_t pixel_bytes ;
5150 struct k_sem sem ;
52- uint8_t write_idx ;
51+ /* Tracks index of next active driver framebuffer */
52+ uint8_t next_idx ;
5353};
5454
55+ static void dump_reg (LCDIF_Type * base )
56+ {
57+ /* Dump LCDIF Registers */
58+ LOG_DBG ("CTRL: 0x%x" , base -> CTRL .RW );
59+ LOG_DBG ("DISP_PARA: 0x%x" , base -> DISP_PARA );
60+ LOG_DBG ("DISP_SIZE: 0x%x" , base -> DISP_SIZE );
61+ LOG_DBG ("HSYN_PARA: 0x%x" , base -> HSYN_PARA );
62+ LOG_DBG ("VSYN_PARA: 0x%x" , base -> VSYN_PARA );
63+ LOG_DBG ("VSYN_HSYN_WIDTH: 0x%x" , base -> VSYN_HSYN_WIDTH );
64+ LOG_DBG ("INT_STATUS_D0: 0x%x" , base -> INT_STATUS_D0 );
65+ LOG_DBG ("INT_STATUS_D1: 0x%x" , base -> INT_STATUS_D1 );
66+ LOG_DBG ("CTRLDESCL_1: 0x%x" , base -> CTRLDESCL_1 [0 ]);
67+ LOG_DBG ("CTRLDESCL_3: 0x%x" , base -> CTRLDESCL_3 [0 ]);
68+ LOG_DBG ("CTRLDESCL_LOW_4: 0x%x" , base -> CTRLDESCL_LOW_4 [0 ]);
69+ LOG_DBG ("CTRLDESCL_HIGH_4: 0x%x" , base -> CTRLDESCL_HIGH_4 [0 ]);
70+ LOG_DBG ("CTRLDESCL_5: 0x%x" , base -> CTRLDESCL_5 [0 ]);
71+ }
72+
5573static int mcux_lcdifv3_write (const struct device * dev , const uint16_t x , const uint16_t y ,
5674 const struct display_buffer_descriptor * desc , const void * buf )
5775{
5876 const struct mcux_lcdifv3_config * config = dev -> config ;
59- struct mcux_lcdifv3_data * dev_data = dev -> data ;
77+ struct mcux_lcdifv3_data * data = dev -> data ;
6078 LCDIF_Type * base = (LCDIF_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
61-
62- if ((config -> pixel_bytes * desc -> pitch * desc -> height ) > desc -> buf_size ) {
63- LOG_ERR ("Input buffer too small" );
64- return - ENOTSUP ;
79+ uint32_t h_idx ;
80+ const uint8_t * src ;
81+ uint8_t * dst ;
82+
83+ __ASSERT ((data -> pixel_bytes * desc -> pitch * desc -> height ) <= desc -> buf_size ,
84+ "Input buffer too small" );
85+
86+ LOG_DBG ("W=%d, H=%d @%d,%d" , desc -> width , desc -> height , x , y );
87+
88+ if ((x == 0 ) && (y == 0 ) && (desc -> width == config -> display_config .panelWidth ) &&
89+ (desc -> height == config -> display_config .panelHeight ) && (desc -> pitch == desc -> width )) {
90+ /* We can use the display buffer directly, without copying */
91+ LOG_DBG ("Setting FB from %p->%p" , (void * )data -> active_fb , (void * )buf );
92+ data -> active_fb = buf ;
93+ } else {
94+ /* We must use partial framebuffer copy */
95+ if (CONFIG_MCUX_LCDIFV3_FB_NUM == 0 ) {
96+ LOG_ERR ("Partial display refresh requires driver framebuffers" );
97+ return - ENOTSUP ;
98+ } else if (data -> active_fb != data -> fb [data -> next_idx ]) {
99+ /*
100+ * Copy the entirety of the current framebuffer to new
101+ * buffer, since we are changing the active buffer address
102+ */
103+ src = data -> active_fb ;
104+ dst = data -> fb [data -> next_idx ];
105+ memcpy (dst , src , config -> fb_bytes );
106+ }
107+ /* Write the display update to the active framebuffer */
108+ src = buf ;
109+ dst = data -> fb [data -> next_idx ];
110+ dst += data -> pixel_bytes * (y * config -> display_config .panelWidth + x );
111+
112+ for (h_idx = 0 ; h_idx < desc -> height ; h_idx ++ ) {
113+ memcpy (dst , src , data -> pixel_bytes * desc -> width );
114+ src += data -> pixel_bytes * desc -> pitch ;
115+ dst += data -> pixel_bytes * config -> display_config .panelWidth ;
116+ }
117+ LOG_DBG ("Setting FB from %p->%p" , (void * )data -> active_fb ,
118+ (void * )data -> fb [data -> next_idx ]);
119+ /* Set new active framebuffer */
120+ data -> active_fb = data -> fb [data -> next_idx ];
65121 }
66122
67- LOG_DBG ( "W=%d, H=%d, @%d,%d" , desc -> width , desc -> height , x , y );
123+ sys_cache_data_flush_and_invd_range (( void * ) data -> active_fb , config -> fb_bytes );
68124
69- /* Dump LCDIF Registers */
70- LOG_DBG ("CTRL: 0x%x\n" , base -> CTRL .RW );
71- LOG_DBG ("DISP_PARA: 0x%x\n" , base -> DISP_PARA );
72- LOG_DBG ("DISP_SIZE: 0x%x\n" , base -> DISP_SIZE );
73- LOG_DBG ("HSYN_PARA: 0x%x\n" , base -> HSYN_PARA );
74- LOG_DBG ("VSYN_PARA: 0x%x\n" , base -> VSYN_PARA );
75- LOG_DBG ("VSYN_HSYN_WIDTH: 0x%x\n" , base -> VSYN_HSYN_WIDTH );
76- LOG_DBG ("INT_STATUS_D0: 0x%x\n" , base -> INT_STATUS_D0 );
77- LOG_DBG ("INT_STATUS_D1: 0x%x\n" , base -> INT_STATUS_D1 );
78- LOG_DBG ("CTRLDESCL_1: 0x%x\n" , base -> CTRLDESCL_1 [0 ]);
79- LOG_DBG ("CTRLDESCL_3: 0x%x\n" , base -> CTRLDESCL_3 [0 ]);
80- LOG_DBG ("CTRLDESCL_LOW_4: 0x%x\n" , base -> CTRLDESCL_LOW_4 [0 ]);
81- LOG_DBG ("CTRLDESCL_HIGH_4: 0x%x\n" , base -> CTRLDESCL_HIGH_4 [0 ]);
82- LOG_DBG ("CTRLDESCL_5: 0x%x\n" , base -> CTRLDESCL_5 [0 ]);
83-
84- /* wait for the next frame done */
85- k_sem_reset (& dev_data -> sem );
86-
87- sys_cache_data_flush_and_invd_range ((void * )buf , desc -> buf_size );
88- LCDIFV3_SetLayerSize (base , 0 , desc -> width , desc -> height );
89- LCDIFV3_SetLayerBufferAddr (base , 0 , (uint32_t )(uintptr_t )buf );
125+ k_sem_reset (& data -> sem );
126+
127+ /* Set new framebuffer */
128+ LCDIFV3_SetLayerBufferAddr (base , 0 , (uint32_t )(uintptr_t )data -> active_fb );
90129 LCDIFV3_TriggerLayerShadowLoad (base , 0 );
91130
92- k_sem_take (& dev_data -> sem , K_FOREVER );
131+ #if CONFIG_MCUX_LCDIFV3_FB_NUM != 0
132+ /* Update index of active framebuffer */
133+ data -> next_idx = (data -> next_idx + 1 ) % CONFIG_MCUX_LCDIFV3_FB_NUM ;
134+ #endif
135+ /* Wait for frame to complete */
136+ k_sem_take (& data -> sem , K_FOREVER );
93137
94138 return 0 ;
95139}
@@ -98,7 +142,7 @@ static void *mcux_lcdifv3_get_framebuffer(const struct device *dev)
98142{
99143 struct mcux_lcdifv3_data * dev_data = dev -> data ;
100144
101- return dev_data -> fb_ptr ;
145+ return ( void * ) dev_data -> active_fb ;
102146}
103147
104148static void mcux_lcdifv3_get_capabilities (const struct device * dev ,
@@ -172,21 +216,28 @@ static int mcux_axi_apb_configure_clock(const struct device *dev)
172216static int mcux_lcdifv3_init (const struct device * dev )
173217{
174218 const struct mcux_lcdifv3_config * config = dev -> config ;
175- struct mcux_lcdifv3_data * dev_data = dev -> data ;
219+ struct mcux_lcdifv3_data * data = dev -> data ;
176220 uint32_t clk_freq ;
177221
178222 DEVICE_MMIO_NAMED_MAP (dev , reg_base , K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP );
179223 LCDIF_Type * base = (LCDIF_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
180224
181- dev_data -> fb [ 0 ] = dev_data -> fb_ptr ;
225+ config -> irq_config_func ( dev ) ;
182226
183- k_sem_init (& dev_data -> sem , 1 , 1 );
227+ for (int i = 0 ; i < CONFIG_MCUX_LCDIFV3_FB_NUM ; i ++ ) {
228+ /* Record pointers to each driver framebuffer */
229+ data -> fb [i ] = config -> fb_ptr + (config -> fb_bytes * i );
230+ }
231+ data -> active_fb = config -> fb_ptr ;
184232
185- config -> irq_config_func (dev );
233+ k_sem_init (& data -> sem , 1 , 1 );
234+
235+ /* Clear external memory, as it is uninitialized */
236+ memset (config -> fb_ptr , 0 , config -> fb_bytes * CONFIG_MCUX_LCDIFV3_FB_NUM );
186237
187238 /* configure disp_pix_clk */
188239 if (!device_is_ready (config -> disp_pix_clk_dev )) {
189- LOG_ERR ("cam_pix clock control device not ready\n " );
240+ LOG_ERR ("cam_pix clock control device not ready" );
190241 return - ENODEV ;
191242 }
192243
@@ -195,7 +246,7 @@ static int mcux_lcdifv3_init(const struct device *dev)
195246
196247 if (clock_control_get_rate (config -> disp_pix_clk_dev , config -> disp_pix_clk_subsys ,
197248 & clk_freq )) {
198- LOG_ERR ("Failed to get disp_pix_clk\n " );
249+ LOG_ERR ("Failed to get disp_pix_clk" );
199250 return - EINVAL ;
200251 }
201252 LOG_INF ("disp_pix clock frequency %d" , clk_freq );
@@ -219,11 +270,13 @@ static int mcux_lcdifv3_init(const struct device *dev)
219270 LCDIFV3_SetLayerSize (base , 0 , display_config .panelWidth , display_config .panelHeight );
220271 LCDIFV3_EnableLayer (base , 0 , true);
221272 LCDIFV3_EnablePlanePanic (base );
222- LCDIFV3_SetLayerBufferAddr (base , 0 , (uint64_t )dev_data -> fb [0 ]);
273+ LCDIFV3_SetLayerBufferAddr (base , 0 , (uint64_t )data -> fb [0 ]);
223274 LCDIFV3_TriggerLayerShadowLoad (base , 0 );
224275 LCDIFV3_EnableInterrupts (base , kLCDIFV3_VerticalBlankingInterrupt );
225276
226- LOG_INF ("%s init succeeded\n" , dev -> name );
277+ LOG_INF ("%s init succeeded" , dev -> name );
278+
279+ dump_reg (base );
227280
228281 return 0 ;
229282}
@@ -245,13 +298,24 @@ static const struct display_driver_api mcux_lcdifv3_api = {
245298 ? 2 \
246299 : ((DT_INST_ENUM_IDX(id, pixel_format) == 1) ? 3 : 4))
247300
301+ #define MCUX_LCDIFV3_FRAMEBUFFER_DECL (id ) \
302+ uint8_t __aligned(64) \
303+ mcux_lcdifv3_frame_buffer_##id[DT_INST_PROP(id, width) * DT_INST_PROP(id, height) * \
304+ GET_PIXEL_BYTES(id) * CONFIG_MCUX_LCDIFV3_FB_NUM]
305+ #define MCUX_LCDIFV3_FRAMEBUFFER (id ) mcux_lcdifv3_frame_buffer_##id
306+
248307#define MCUX_LCDIFV3_DEVICE_INIT (id ) \
249308 static void mcux_lcdifv3_config_func_##id(const struct device *dev) \
250309 { \
251310 IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority), mcux_lcdifv3_isr, \
252311 DEVICE_DT_INST_GET(id), 0); \
253312 irq_enable(DT_INST_IRQN(id)); \
254313 } \
314+ MCUX_LCDIFV3_FRAMEBUFFER_DECL(id); \
315+ static struct mcux_lcdifv3_data mcux_lcdifv3_data_##id = { \
316+ .next_idx = 0, \
317+ .pixel_bytes = GET_PIXEL_BYTES(id), \
318+ }; \
255319 static const struct mcux_lcdifv3_config mcux_lcdifv3_config_##id = { \
256320 DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(id)), \
257321 .disp_pix_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_IDX(id, 0)), \
@@ -298,16 +362,10 @@ static const struct display_driver_api mcux_lcdifv3_api = {
298362 : kLCDIFV3_DriveDataOnFallingClkEdge), \
299363 }, \
300364 .pixel_format = GET_PIXEL_FORMAT(id), \
301- .pixel_bytes = GET_PIXEL_BYTES (id), \
365+ .fb_ptr = MCUX_LCDIFV3_FRAMEBUFFER (id), \
302366 .fb_bytes = \
303367 DT_INST_PROP(id, width) * DT_INST_PROP(id, height) * GET_PIXEL_BYTES(id), \
304368 }; \
305- static uint8_t \
306- __aligned(64) frame_buffer_##id[MCUX_LCDIFV3_FB_NUM * DT_INST_PROP(id, width) * \
307- DT_INST_PROP(id, height) * GET_PIXEL_BYTES(id)]; \
308- static struct mcux_lcdifv3_data mcux_lcdifv3_data_##id = { \
309- .fb_ptr = frame_buffer_##id, \
310- }; \
311369 DEVICE_DT_INST_DEFINE(id, &mcux_lcdifv3_init, NULL, &mcux_lcdifv3_data_##id, \
312370 &mcux_lcdifv3_config_##id, POST_KERNEL, \
313371 CONFIG_DISPLAY_INIT_PRIORITY, &mcux_lcdifv3_api);
0 commit comments