Skip to content

Commit 106dc4c

Browse files
drivers: display: mcux_elcdif: rework frame completion logic
Rework the frame completion logic for the eLCDIF. Per the documentation of the eLCDIF frame completion interrupt, the interrupt will be asserted at every vertical blanking interval. In order to be sure the eLCDIF has streamed a full frame we need to: - wait for the start of a vertical blanking interval - wait for the next vertical blanking interval, as that indicates a full frame was rendered In order to do this, wait for two frame completion interrupts from the eLCDIF every time we reload the framebuffer. The first interrupt signals that our new frame is now being displayed, the second interrupt signals it is fully rendered and the buffer is no longer needed by the eLCDIF. Fixes #80590 Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent 022c8ee commit 106dc4c

File tree

2 files changed

+17
-31
lines changed

2 files changed

+17
-31
lines changed

drivers/display/Kconfig.mcux_elcdif

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,6 @@ config MCUX_ELCDIF_PXP
5454
display_write is called with a framebuffer equal in size to the
5555
display.
5656

57-
config MCUX_ELCDIF_LP
58-
bool "ELCDIF low power"
59-
help
60-
This option, when enabled, will enable CUR_FRAME_DONE_IRQ at the display
61-
write function and disable it at the interruption handler for each new frame.
62-
Disabling the interrupt when no new frame needs to be sent gives the CPU the
63-
possibility to enter low-power mode, thus saving energy.
64-
This option, when disabled, CUR_FRAME_DONE_IRQ will be enabled only
65-
once at initialization. This option should be disabled when the application's
66-
frame rate is close to the display's refresh rate to avoid introducing
67-
additional latency caused by frequently enabling and disabling CUR_FRAME_DONE_IRQ.
68-
6957
if MCUX_ELCDIF_PXP
7058

7159
choice MCUX_ELCDIF_PXP_ROTATE_DIRECTION

drivers/display/display_mcux_elcdif.c

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ struct mcux_elcdif_data {
5050
size_t pixel_bytes;
5151
size_t fb_bytes;
5252
elcdif_rgb_mode_config_t rgb_mode;
53-
struct k_sem sem;
53+
struct k_sem vblank_sem;
5454
/* Tracks index of next active driver framebuffer */
5555
uint8_t next_idx;
5656
#ifdef CONFIG_MCUX_ELCDIF_PXP
@@ -214,12 +214,19 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, const u
214214
/* Update index of active framebuffer */
215215
dev_data->next_idx = (dev_data->next_idx + 1) % CONFIG_MCUX_ELCDIF_FB_NUM;
216216
#endif
217-
218-
if (IS_ENABLED(CONFIG_MCUX_ELCDIF_LP)) {
219-
ELCDIF_EnableInterrupts(config->base, kELCDIF_CurFrameDoneInterruptEnable);
220-
}
221-
/* Wait for frame send to complete */
222-
k_sem_take(&dev_data->sem, K_FOREVER);
217+
/*
218+
* In order to be sure we have rendered the framebuffer, we need to
219+
* wait a full vertical blank interval. Enable the ELCDIF
220+
* frame done interrupt (which fires at each vertical blank),
221+
* and wait for the vblank_sem to be posted to twice
222+
*/
223+
ELCDIF_EnableInterrupts(config->base, kELCDIF_CurFrameDoneInterruptEnable);
224+
/* Wait for first vblank */
225+
k_sem_take(&dev_data->vblank_sem, K_FOREVER);
226+
/* Wait for second vblank */
227+
k_sem_take(&dev_data->vblank_sem, K_FOREVER);
228+
/* Disable vblank interrupt */
229+
ELCDIF_DisableInterrupts(config->base, kELCDIF_CurFrameDoneInterruptEnable);
223230
return ret;
224231
}
225232

@@ -309,14 +316,8 @@ static void mcux_elcdif_isr(const struct device *dev)
309316

310317
status = ELCDIF_GetInterruptStatus(config->base);
311318
ELCDIF_ClearInterruptStatus(config->base, status);
312-
if (config->base->CUR_BUF == ((uint32_t)dev_data->active_fb)) {
313-
if (IS_ENABLED(CONFIG_MCUX_ELCDIF_LP)) {
314-
/* Disable frame completion interrupt if Low power mode is activated*/
315-
ELCDIF_DisableInterrupts(config->base, kELCDIF_CurFrameDoneInterruptEnable);
316-
}
317-
/* Post to sem to notify that frame display is complete.*/
318-
k_sem_give(&dev_data->sem);
319-
}
319+
/* Post to sem to notify that vertical blank occurred */
320+
k_sem_give(&dev_data->vblank_sem);
320321
}
321322

322323
static int mcux_elcdif_init(const struct device *dev)
@@ -335,7 +336,7 @@ static int mcux_elcdif_init(const struct device *dev)
335336
return err;
336337
}
337338

338-
k_sem_init(&dev_data->sem, 0, 1);
339+
k_sem_init(&dev_data->vblank_sem, 0, 1);
339340
#ifdef CONFIG_MCUX_ELCDIF_PXP
340341
k_sem_init(&dev_data->pxp_done, 0, 1);
341342
if (!device_is_ready(config->pxp)) {
@@ -352,9 +353,6 @@ static int mcux_elcdif_init(const struct device *dev)
352353
dev_data->active_fb = dev_data->fb[0];
353354

354355
ELCDIF_RgbModeInit(config->base, &dev_data->rgb_mode);
355-
if (!IS_ENABLED(CONFIG_MCUX_ELCDIF_LP)) {
356-
ELCDIF_EnableInterrupts(config->base, kELCDIF_CurFrameDoneInterruptEnable);
357-
}
358356
ELCDIF_RgbModeStart(config->base);
359357

360358
return 0;

0 commit comments

Comments
 (0)