echoplayer: implement LCD enable and shutdown

rockbox-gerrit-noreply--- via rockbox-cvs <[email protected]>
Newsgroups gmane.comp.systems.archos.rockbox.cvs
Message-ID <[email protected]>
commit 1afa2ca50d21cb4a234caece29ed3ef8ae848482
Author: Aidan MacDonald <[email protected]>
Date:   Sun Jan 18 15:30:03 2026 +0000

    echoplayer: implement LCD enable and shutdown
    
    This also gets rid of the long startup delays which were
    leftovers from debugging.
    
    Change-Id: Iee9fec1fb210a006a1af53bf47535d7ba2ffa904

diff --git a/firmware/export/config/echor1.h b/firmware/export/config/echor1.h
index 6a6bba342f..41149258c9 100644
--- a/firmware/export/config/echor1.h
+++ b/firmware/export/config/echor1.h
@@ -36,6 +36,7 @@
 #define HAVE_LCD_COLOR
 #define HAVE_LCD_BITMAP
 #define HAVE_LCD_ENABLE
+#define HAVE_LCD_SHUTDOWN
 
 /* Backlight defines */
 #define HAVE_BACKLIGHT
diff --git a/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c b/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c
index 947342b1fb..0800f3aad8 100644
--- a/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c
+++ b/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c
@@ -31,6 +31,9 @@
 #include "regs/stm32h743/spi.h"
 #include "regs/stm32h743/ltdc.h"
 
+#define MS_TO_TICKS(x) \
+    (((x) + (1000 / HZ - 1)) / (1000 / HZ))
+
 /*
  * ILI9342C specifies 10 MHz max
  *
@@ -39,6 +42,14 @@
  */
 #define LCD_SPI_FREQ 12000000
 
+#define ili_cmd(cmd, ...) \
+    do { \
+        uint16_t arr[] = {cmd, __VA_ARGS__}; \
+        for (size_t i = 1; i < ARRAYLEN(arr); ++i) \
+            arr[i] |= 0x100; \
+        stm_spi_transmit(&spi, arr, sizeof(arr)); \
+    } while (0)
+
 struct stm_spi_config spi_cfg = {
     .instance = ITA_SPI5,
     .clock = &spi5_ker_clock,
@@ -51,15 +62,16 @@ struct stm_spi_config spi_cfg = {
 
 struct stm_spi spi;
 
-#define ili_cmd(cmd, ...) \
-    do { \
-        uint16_t arr[] = {cmd, __VA_ARGS__}; \
-        for (size_t i = 1; i < ARRAYLEN(arr); ++i) \
-            arr[i] |= 0x100; \
-        stm_spi_transmit(&spi, arr, sizeof(arr)); \
-    } while (0)
+enum lcd_controller_state
+{
+    RESET,  /* Controller in hardware reset, LTDC disabled */
+    SLEEP,  /* Controller in sleep-in mode, LTDC disabled */
+    AWAKE,  /* Controller in sleep-out mode, LTDC enabled */
+};
 
-static void init_ltdc(void)
+static enum lcd_controller_state lcd_controller_state = RESET;
+
+static void enable_ltdc(void)
 {
     /* Enable LTDC clock */
     stm32_clock_enable(&ltdc_ker_clock);
@@ -101,63 +113,143 @@ static void init_ltdc(void)
     reg_writef(LTDC_GCR, LTDCEN(1));
 }
 
-void lcd_init_device(void)
+static void disable_ltdc(void)
 {
-    /* Configure SPI bus */
-    stm_spi_init(&spi, &spi_cfg);
-    nvic_enable_irq(NVIC_IRQN_SPI5);
+    reg_writef(LTDC_GCR, LTDCEN(0));
 
-    /* Enable LCD controller */
-    init_ltdc();
+    stm32_clock_disable(&ltdc_ker_clock);
+}
 
-    /* Ensure controller is reset */
-    gpio_set_level(GPIO_LCD_RESET, 0);
-    sleep(12);
+/* TODO: thread safety, is a mutex needed here? */
 
-    gpio_set_level(GPIO_LCD_RESET, 1);
-    sleep(12);
+static void reset_lcd(void)
+{
+    if (lcd_controller_state != RESET)
+    {
+        if (lcd_controller_state == AWAKE)
+            disable_ltdc();
 
-    /* Sleep out */
-    ili_cmd(0x11);
-    sleep(12);
+        /* Must be >= 10 us to take effect */
+        gpio_set_level(GPIO_LCD_RESET, 0);
+        udelay(10);
 
-    /* memory access control (X/Y invert, BGR panel) */
-    ili_cmd(0x36, 0xc8);
+        lcd_controller_state = RESET;
+    }
+}
 
-    /* pixel format set (18bpp for RGB bus, 16bpp for SPI bus) */
-    ili_cmd(0x3a, 0x65);
+static void sleep_lcd(void)
+{
+    if (lcd_controller_state == AWAKE)
+    {
+        /*
+         * Send sleep in command -- empirically this seems to
+         * require a delay of 10ms before disabling the LTDC.
+         * The clock output appears to be necessary to fully
+         * blank the screen before entering sleep mode.
+         *
+         * Sometimes there is an effect where the screen is
+         * only partly blanked and only later fully blanked,
+         * which goes away with a 20ms delay.
+         */
+        ili_cmd(0x10);
+        sleep(MS_TO_TICKS(20));
 
-    /* send set EXTC command to allow configuring RGB interface */
-    ili_cmd(0xc8, 0xff, 0x93, 0x42);
+        /* Disable LTDC */
+        disable_ltdc();
 
-    /*
-     * Enable RGB interface transferring to internal GRAM.
-     *
-     * Direct to shift register mode doesn't work; for one, the
-     * framebuffer doesn't get transferred properly which might
-     * just be timing issues. Two, the display is horizontally
-     * flipped and there doesn't seem to be a way to change it
-     * in the shift register mode.
-     */
-    ili_cmd(0xb0, 0xc0);
-    ili_cmd(0xf6, 0x01, 0x00, 0x06);
+        lcd_controller_state = SLEEP;
+    }
+}
+
+static void wake_lcd(void)
+{
+    if (lcd_controller_state == RESET)
+    {
+        /* Release reset line */
+        gpio_set_level(GPIO_LCD_RESET, 1);
+        sleep(MS_TO_TICKS(5));
+
+        /* Memory access control (X/Y invert, BGR panel) */
+        ili_cmd(0x36, 0xc8);
+
+        /* Pixel format set (18bpp for RGB bus, 16bpp for SPI bus) */
+        ili_cmd(0x3a, 0x65);
+
+        /* Send set EXTC command to allow configuring RGB interface */
+        ili_cmd(0xc8, 0xff, 0x93, 0x42);
+
+        /*
+         * Enable RGB interface transferring to internal GRAM.
+         *
+         * Direct to shift register mode doesn't work; for one, the
+         * framebuffer doesn't get transferred properly which might
+         * just be timing issues. Two, the display is horizontally
+         * flipped and there doesn't seem to be a way to change it
+         * in the shift register mode.
+         */
+        ili_cmd(0xb0, 0xc0);
+        ili_cmd(0xf6, 0x01, 0x00, 0x06);
+
+        /* Display ON */
+        ili_cmd(0x29);
+    }
+
+    if (lcd_controller_state != AWAKE)
+    {
+        /* Sync framebuffer & enable LTDC output */
+        commit_dcache();
+        enable_ltdc();
+
+        /* Sleep out command */
+        ili_cmd(0x11);
+        sleep(MS_TO_TICKS(5));
+
+        lcd_controller_state = AWAKE;
+        send_event(LCD_EVENT_ACTIVATION, NULL);
+    }
+}
+
+void lcd_init_device(void)
+{
+    /* Configure SPI bus */
+    stm_spi_init(&spi, &spi_cfg);
+    nvic_enable_irq(NVIC_IRQN_SPI5);
 
-    /* display ON */
-    ili_cmd(0x29);
+    /* Enable LTDC and LCD controller */
+    wake_lcd();
 }
 
 bool lcd_active(void)
 {
-    return true;
+    return lcd_controller_state == AWAKE;
+}
+
+void lcd_enable(bool enable)
+{
+    if (enable)
+        wake_lcd();
+    else
+        sleep_lcd();
+}
+
+void lcd_shutdown(void)
+{
+    reset_lcd();
 }
 
 void lcd_update(void)
 {
+    if (!lcd_active())
+        return;
+
     commit_dcache();
 }
 
 void lcd_update_rect(int x, int y, int width, int height)
 {
+    if (!lcd_active())
+        return;
+
     if (x < 0)
         x = 0;
     else if (x >= LCD_WIDTH)
-- 
rockbox-cvs mailing list
[email protected]
https://lists.haxx.se/mailman/listinfo/rockbox-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.