Skip to content

Commit f071b54

Browse files
committed
Merge branch 'bugfix/remove_lcd_signals_on_delete' into 'master'
fix(lcd): reserve the GPIOs used by RGB LCD and disconnect the LCD signals when the dirver is uninstalled. Closes AUD-6545 See merge request espressif/esp-idf!40734
2 parents a8d3b48 + e0ddcb8 commit f071b54

File tree

4 files changed

+82
-19
lines changed

4 files changed

+82
-19
lines changed

components/esp_lcd/rgb/esp_lcd_panel_rgb.c

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "esp_private/esp_dma_utils.h"
3636
#include "esp_private/periph_ctrl.h"
3737
#include "esp_private/gpio.h"
38+
#include "esp_private/esp_gpio_reserve.h"
3839
#include "esp_psram.h"
3940
#include "esp_lcd_common.h"
4041
#include "esp_cache.h"
@@ -90,6 +91,7 @@ static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *rgb_panel, lcd_
9091
static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *rgb_panel);
9192
static esp_err_t lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *rgb_panel);
9293
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *rgb_panel, const esp_lcd_rgb_panel_config_t *panel_config);
94+
static void lcd_rgb_panel_release_gpio(esp_rgb_panel_t *rgb_panel);
9395
static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel);
9496
static void rgb_lcd_default_isr_handler(void *args);
9597

@@ -102,7 +104,6 @@ struct esp_rgb_panel_t {
102104
size_t num_fbs; // Number of frame buffers
103105
size_t output_bits_per_pixel; // Color depth seen from the output data line. Default to fb_bits_per_pixel, but can be changed by YUV-RGB conversion
104106
size_t dma_burst_size; // DMA transfer burst size
105-
int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off"
106107
intr_handle_t intr; // LCD peripheral interrupt handle
107108
#if CONFIG_PM_ENABLE
108109
esp_pm_lock_handle_t pm_lock; // Power management lock
@@ -122,7 +123,13 @@ struct esp_rgb_panel_t {
122123
uint8_t bb_fb_index; // Current frame buffer index which used by bounce buffer
123124
size_t int_mem_align; // DMA buffer alignment for internal memory
124125
size_t ext_mem_align; // DMA buffer alignment for external memory
126+
int hsync_gpio_num; // GPIO used for HSYNC signal
127+
int vsync_gpio_num; // GPIO used for VSYNC signal
128+
int de_gpio_num; // GPIO used for DE signal, set to -1 if it's not used
129+
int pclk_gpio_num; // GPIO used for PCLK signal, set to -1 if it's not used
130+
int disp_gpio_num; // GPIO used for display control signal, set to -1 if it's not used
125131
int data_gpio_nums[SOC_LCDCAM_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
132+
uint64_t gpio_reserve_mask; // GPIOs reserved by this panel, used to revoke the GPIO reservation when the panel is deleted
126133
uint32_t src_clk_hz; // Peripheral source clock resolution
127134
esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
128135
int bounce_pos_px; // Position in whatever source material is used for the bounce buffer, in pixels
@@ -198,6 +205,8 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(esp_rgb_panel_t *rgb_panel)
198205

199206
static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
200207
{
208+
// ensure the HW state machine is stopped
209+
lcd_ll_stop(rgb_panel->hal.dev);
201210
LCD_CLOCK_SRC_ATOMIC() {
202211
lcd_ll_enable_clock(rgb_panel->hal.dev, false);
203212
}
@@ -209,6 +218,8 @@ static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
209218
}
210219
lcd_com_remove_device(LCD_COM_DEVICE_TYPE_RGB, rgb_panel->panel_id);
211220
}
221+
// release the GPIOs
222+
lcd_rgb_panel_release_gpio(rgb_panel);
212223
if (rgb_panel->dma_chan) {
213224
gdma_disconnect(rgb_panel->dma_chan);
214225
gdma_del_channel(rgb_panel->dma_chan);
@@ -356,10 +367,14 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
356367
ESP_GOTO_ON_ERROR(ret, err, TAG, "configure GPIO failed");
357368
// fill other rgb panel runtime parameters
358369
memcpy(rgb_panel->data_gpio_nums, rgb_panel_config->data_gpio_nums, sizeof(rgb_panel->data_gpio_nums));
370+
rgb_panel->disp_gpio_num = rgb_panel_config->disp_gpio_num;
371+
rgb_panel->de_gpio_num = rgb_panel_config->de_gpio_num;
372+
rgb_panel->hsync_gpio_num = rgb_panel_config->hsync_gpio_num;
373+
rgb_panel->vsync_gpio_num = rgb_panel_config->vsync_gpio_num;
374+
rgb_panel->pclk_gpio_num = rgb_panel_config->pclk_gpio_num;
359375
rgb_panel->timings = rgb_panel_config->timings;
360376
rgb_panel->data_width = rgb_panel_config->data_width;
361377
rgb_panel->output_bits_per_pixel = fb_bits_per_pixel; // by default, the output bpp is the same as the frame buffer bpp
362-
rgb_panel->disp_gpio_num = rgb_panel_config->disp_gpio_num;
363378
rgb_panel->flags.disp_en_level = !rgb_panel_config->flags.disp_active_low;
364379
rgb_panel->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
365380
// fill function table
@@ -742,47 +757,92 @@ static esp_err_t rgb_panel_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
742757

743758
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *rgb_panel, const esp_lcd_rgb_panel_config_t *panel_config)
744759
{
760+
uint64_t gpio_reserve_mask = 0;
745761
int panel_id = rgb_panel->panel_id;
746762
// Set the number of output data lines
747763
lcd_ll_set_data_wire_width(rgb_panel->hal.dev, panel_config->data_width);
748764
// connect peripheral signals via GPIO matrix
749765
for (size_t i = 0; i < panel_config->data_width; i++) {
750766
if (panel_config->data_gpio_nums[i] >= 0) {
751-
gpio_func_sel(panel_config->data_gpio_nums[i], PIN_FUNC_GPIO);
752-
esp_rom_gpio_connect_out_signal(panel_config->data_gpio_nums[i],
753-
lcd_periph_rgb_signals.panels[panel_id].data_sigs[i], false, false);
767+
gpio_matrix_output(panel_config->data_gpio_nums[i],
768+
lcd_periph_rgb_signals.panels[panel_id].data_sigs[i], false, false);
769+
gpio_reserve_mask |= (1 << panel_config->data_gpio_nums[i]);
754770
}
755771
}
756772
if (panel_config->hsync_gpio_num >= 0) {
757-
gpio_func_sel(panel_config->hsync_gpio_num, PIN_FUNC_GPIO);
758-
esp_rom_gpio_connect_out_signal(panel_config->hsync_gpio_num,
759-
lcd_periph_rgb_signals.panels[panel_id].hsync_sig, false, false);
773+
gpio_matrix_output(panel_config->hsync_gpio_num,
774+
lcd_periph_rgb_signals.panels[panel_id].hsync_sig, false, false);
775+
gpio_reserve_mask |= (1 << panel_config->hsync_gpio_num);
760776
}
761777
if (panel_config->vsync_gpio_num >= 0) {
762-
gpio_func_sel(panel_config->vsync_gpio_num, PIN_FUNC_GPIO);
763-
esp_rom_gpio_connect_out_signal(panel_config->vsync_gpio_num,
764-
lcd_periph_rgb_signals.panels[panel_id].vsync_sig, false, false);
778+
gpio_matrix_output(panel_config->vsync_gpio_num,
779+
lcd_periph_rgb_signals.panels[panel_id].vsync_sig, false, false);
780+
gpio_reserve_mask |= (1 << panel_config->vsync_gpio_num);
765781
}
766782
// PCLK may not be necessary in some cases (i.e. VGA output)
767783
if (panel_config->pclk_gpio_num >= 0) {
768-
gpio_func_sel(panel_config->pclk_gpio_num, PIN_FUNC_GPIO);
769-
esp_rom_gpio_connect_out_signal(panel_config->pclk_gpio_num,
770-
lcd_periph_rgb_signals.panels[panel_id].pclk_sig, false, false);
784+
gpio_matrix_output(panel_config->pclk_gpio_num,
785+
lcd_periph_rgb_signals.panels[panel_id].pclk_sig, false, false);
786+
gpio_reserve_mask |= (1 << panel_config->pclk_gpio_num);
771787
}
772788
// DE signal might not be necessary for some RGB LCD
773789
if (panel_config->de_gpio_num >= 0) {
774-
gpio_func_sel(panel_config->de_gpio_num, PIN_FUNC_GPIO);
775-
esp_rom_gpio_connect_out_signal(panel_config->de_gpio_num,
776-
lcd_periph_rgb_signals.panels[panel_id].de_sig, false, false);
790+
gpio_matrix_output(panel_config->de_gpio_num,
791+
lcd_periph_rgb_signals.panels[panel_id].de_sig, false, false);
792+
gpio_reserve_mask |= (1 << panel_config->de_gpio_num);
777793
}
778794
// disp enable GPIO is optional, it is a general purpose output GPIO
779795
if (panel_config->disp_gpio_num >= 0) {
780-
gpio_func_sel(panel_config->disp_gpio_num, PIN_FUNC_GPIO);
781-
gpio_output_enable(panel_config->disp_gpio_num);
796+
gpio_matrix_output(panel_config->disp_gpio_num,
797+
lcd_periph_rgb_signals.panels[panel_id].disp_sig, false, false);
798+
gpio_reserve_mask |= (1 << panel_config->disp_gpio_num);
799+
}
800+
801+
// reserve the GPIOs
802+
uint64_t busy_mask = esp_gpio_reserve(gpio_reserve_mask);
803+
uint64_t conflict_mask = busy_mask & gpio_reserve_mask;
804+
for (; conflict_mask > 0;) {
805+
uint8_t pos = __builtin_ctzll(conflict_mask);
806+
conflict_mask &= ~(1ULL << pos);
807+
ESP_LOGW(TAG, "GPIO %d is not usable, maybe is reserved by others", pos);
782808
}
809+
810+
rgb_panel->gpio_reserve_mask = gpio_reserve_mask;
783811
return ESP_OK;
784812
}
785813

814+
static void lcd_rgb_panel_release_gpio(esp_rgb_panel_t *rgb_panel)
815+
{
816+
if (rgb_panel->gpio_reserve_mask) {
817+
// disconnect the GPIOs from the LCD signals
818+
for (size_t i = 0; i < rgb_panel->data_width; i++) {
819+
if (rgb_panel->data_gpio_nums[i] >= 0) {
820+
gpio_output_disable(rgb_panel->data_gpio_nums[i]);
821+
}
822+
}
823+
if (rgb_panel->hsync_gpio_num >= 0) {
824+
gpio_output_disable(rgb_panel->hsync_gpio_num);
825+
}
826+
if (rgb_panel->vsync_gpio_num >= 0) {
827+
gpio_output_disable(rgb_panel->vsync_gpio_num);
828+
}
829+
// PCLK may not be necessary in some cases (i.e. VGA output)
830+
if (rgb_panel->pclk_gpio_num >= 0) {
831+
gpio_output_disable(rgb_panel->pclk_gpio_num);
832+
}
833+
// DE signal might not be necessary for some RGB LCD
834+
if (rgb_panel->de_gpio_num >= 0) {
835+
gpio_output_disable(rgb_panel->de_gpio_num);
836+
}
837+
// disp enable GPIO is optional, it is a general purpose output GPIO
838+
if (rgb_panel->disp_gpio_num >= 0) {
839+
gpio_output_disable(rgb_panel->disp_gpio_num);
840+
}
841+
// release the IOs so they can be used by others again
842+
esp_gpio_revoke(rgb_panel->gpio_reserve_mask);
843+
}
844+
}
845+
786846
static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *rgb_panel, lcd_clock_source_t clk_src)
787847
{
788848
// get clock source frequency

components/soc/esp32p4/lcd_periph.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ const lcd_rgb_signal_conn_t lcd_periph_rgb_signals = {
8383
.vsync_sig = LCD_V_SYNC_PAD_OUT_IDX,
8484
.pclk_sig = LCD_PCLK_PAD_OUT_IDX,
8585
.de_sig = LCD_H_ENABLE_PAD_OUT_IDX,
86+
.disp_sig = SIG_GPIO_OUT_IDX,
8687
}
8788
}
8889
};

components/soc/esp32s3/lcd_periph.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const lcd_rgb_signal_conn_t lcd_periph_rgb_signals = {
6464
.vsync_sig = LCD_V_SYNC_IDX,
6565
.pclk_sig = LCD_PCLK_IDX,
6666
.de_sig = LCD_H_ENABLE_IDX,
67+
.disp_sig = SIG_GPIO_OUT_IDX,
6768
}
6869
}
6970
};

components/soc/include/soc/lcd_periph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ typedef struct {
3838
const int vsync_sig;
3939
const int pclk_sig;
4040
const int de_sig;
41+
const int disp_sig;
4142
} panels[SOC_LCDCAM_RGB_NUM_PANELS];
4243
} lcd_rgb_signal_conn_t;
4344

0 commit comments

Comments
 (0)