mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 13:14:32 +02:00
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
This commit is contained in:
@@ -35,6 +35,7 @@
|
|||||||
#include "esp_private/esp_dma_utils.h"
|
#include "esp_private/esp_dma_utils.h"
|
||||||
#include "esp_private/periph_ctrl.h"
|
#include "esp_private/periph_ctrl.h"
|
||||||
#include "esp_private/gpio.h"
|
#include "esp_private/gpio.h"
|
||||||
|
#include "esp_private/esp_gpio_reserve.h"
|
||||||
#include "esp_psram.h"
|
#include "esp_psram.h"
|
||||||
#include "esp_lcd_common.h"
|
#include "esp_lcd_common.h"
|
||||||
#include "esp_cache.h"
|
#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_
|
|||||||
static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *rgb_panel);
|
static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *rgb_panel);
|
||||||
static esp_err_t lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *rgb_panel);
|
static esp_err_t lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *rgb_panel);
|
||||||
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *rgb_panel, const esp_lcd_rgb_panel_config_t *panel_config);
|
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *rgb_panel, const esp_lcd_rgb_panel_config_t *panel_config);
|
||||||
|
static void lcd_rgb_panel_release_gpio(esp_rgb_panel_t *rgb_panel);
|
||||||
static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel);
|
static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel);
|
||||||
static void rgb_lcd_default_isr_handler(void *args);
|
static void rgb_lcd_default_isr_handler(void *args);
|
||||||
|
|
||||||
@@ -102,7 +104,6 @@ struct esp_rgb_panel_t {
|
|||||||
size_t num_fbs; // Number of frame buffers
|
size_t num_fbs; // Number of frame buffers
|
||||||
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
|
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
|
||||||
size_t dma_burst_size; // DMA transfer burst size
|
size_t dma_burst_size; // DMA transfer burst size
|
||||||
int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off"
|
|
||||||
intr_handle_t intr; // LCD peripheral interrupt handle
|
intr_handle_t intr; // LCD peripheral interrupt handle
|
||||||
#if CONFIG_PM_ENABLE
|
#if CONFIG_PM_ENABLE
|
||||||
esp_pm_lock_handle_t pm_lock; // Power management lock
|
esp_pm_lock_handle_t pm_lock; // Power management lock
|
||||||
@@ -122,7 +123,13 @@ struct esp_rgb_panel_t {
|
|||||||
uint8_t bb_fb_index; // Current frame buffer index which used by bounce buffer
|
uint8_t bb_fb_index; // Current frame buffer index which used by bounce buffer
|
||||||
size_t int_mem_align; // DMA buffer alignment for internal memory
|
size_t int_mem_align; // DMA buffer alignment for internal memory
|
||||||
size_t ext_mem_align; // DMA buffer alignment for external memory
|
size_t ext_mem_align; // DMA buffer alignment for external memory
|
||||||
|
int hsync_gpio_num; // GPIO used for HSYNC signal
|
||||||
|
int vsync_gpio_num; // GPIO used for VSYNC signal
|
||||||
|
int de_gpio_num; // GPIO used for DE signal, set to -1 if it's not used
|
||||||
|
int pclk_gpio_num; // GPIO used for PCLK signal, set to -1 if it's not used
|
||||||
|
int disp_gpio_num; // GPIO used for display control signal, set to -1 if it's not used
|
||||||
int data_gpio_nums[SOC_LCDCAM_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
|
int data_gpio_nums[SOC_LCDCAM_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
|
||||||
|
uint64_t gpio_reserve_mask; // GPIOs reserved by this panel, used to revoke the GPIO reservation when the panel is deleted
|
||||||
uint32_t src_clk_hz; // Peripheral source clock resolution
|
uint32_t src_clk_hz; // Peripheral source clock resolution
|
||||||
esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
|
esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
|
||||||
int bounce_pos_px; // Position in whatever source material is used for the bounce buffer, in pixels
|
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)
|
|||||||
|
|
||||||
static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
|
static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
|
||||||
{
|
{
|
||||||
|
// ensure the HW state machine is stopped
|
||||||
|
lcd_ll_stop(rgb_panel->hal.dev);
|
||||||
LCD_CLOCK_SRC_ATOMIC() {
|
LCD_CLOCK_SRC_ATOMIC() {
|
||||||
lcd_ll_enable_clock(rgb_panel->hal.dev, false);
|
lcd_ll_enable_clock(rgb_panel->hal.dev, false);
|
||||||
}
|
}
|
||||||
@@ -209,6 +218,8 @@ static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
|
|||||||
}
|
}
|
||||||
lcd_com_remove_device(LCD_COM_DEVICE_TYPE_RGB, rgb_panel->panel_id);
|
lcd_com_remove_device(LCD_COM_DEVICE_TYPE_RGB, rgb_panel->panel_id);
|
||||||
}
|
}
|
||||||
|
// release the GPIOs
|
||||||
|
lcd_rgb_panel_release_gpio(rgb_panel);
|
||||||
if (rgb_panel->dma_chan) {
|
if (rgb_panel->dma_chan) {
|
||||||
gdma_disconnect(rgb_panel->dma_chan);
|
gdma_disconnect(rgb_panel->dma_chan);
|
||||||
gdma_del_channel(rgb_panel->dma_chan);
|
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
|
|||||||
ESP_GOTO_ON_ERROR(ret, err, TAG, "configure GPIO failed");
|
ESP_GOTO_ON_ERROR(ret, err, TAG, "configure GPIO failed");
|
||||||
// fill other rgb panel runtime parameters
|
// fill other rgb panel runtime parameters
|
||||||
memcpy(rgb_panel->data_gpio_nums, rgb_panel_config->data_gpio_nums, sizeof(rgb_panel->data_gpio_nums));
|
memcpy(rgb_panel->data_gpio_nums, rgb_panel_config->data_gpio_nums, sizeof(rgb_panel->data_gpio_nums));
|
||||||
|
rgb_panel->disp_gpio_num = rgb_panel_config->disp_gpio_num;
|
||||||
|
rgb_panel->de_gpio_num = rgb_panel_config->de_gpio_num;
|
||||||
|
rgb_panel->hsync_gpio_num = rgb_panel_config->hsync_gpio_num;
|
||||||
|
rgb_panel->vsync_gpio_num = rgb_panel_config->vsync_gpio_num;
|
||||||
|
rgb_panel->pclk_gpio_num = rgb_panel_config->pclk_gpio_num;
|
||||||
rgb_panel->timings = rgb_panel_config->timings;
|
rgb_panel->timings = rgb_panel_config->timings;
|
||||||
rgb_panel->data_width = rgb_panel_config->data_width;
|
rgb_panel->data_width = rgb_panel_config->data_width;
|
||||||
rgb_panel->output_bits_per_pixel = fb_bits_per_pixel; // by default, the output bpp is the same as the frame buffer bpp
|
rgb_panel->output_bits_per_pixel = fb_bits_per_pixel; // by default, the output bpp is the same as the frame buffer bpp
|
||||||
rgb_panel->disp_gpio_num = rgb_panel_config->disp_gpio_num;
|
|
||||||
rgb_panel->flags.disp_en_level = !rgb_panel_config->flags.disp_active_low;
|
rgb_panel->flags.disp_en_level = !rgb_panel_config->flags.disp_active_low;
|
||||||
rgb_panel->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
rgb_panel->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||||
// fill function table
|
// fill function table
|
||||||
@@ -742,47 +757,92 @@ static esp_err_t rgb_panel_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
|||||||
|
|
||||||
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *rgb_panel, const esp_lcd_rgb_panel_config_t *panel_config)
|
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *rgb_panel, const esp_lcd_rgb_panel_config_t *panel_config)
|
||||||
{
|
{
|
||||||
|
uint64_t gpio_reserve_mask = 0;
|
||||||
int panel_id = rgb_panel->panel_id;
|
int panel_id = rgb_panel->panel_id;
|
||||||
// Set the number of output data lines
|
// Set the number of output data lines
|
||||||
lcd_ll_set_data_wire_width(rgb_panel->hal.dev, panel_config->data_width);
|
lcd_ll_set_data_wire_width(rgb_panel->hal.dev, panel_config->data_width);
|
||||||
// connect peripheral signals via GPIO matrix
|
// connect peripheral signals via GPIO matrix
|
||||||
for (size_t i = 0; i < panel_config->data_width; i++) {
|
for (size_t i = 0; i < panel_config->data_width; i++) {
|
||||||
if (panel_config->data_gpio_nums[i] >= 0) {
|
if (panel_config->data_gpio_nums[i] >= 0) {
|
||||||
gpio_func_sel(panel_config->data_gpio_nums[i], PIN_FUNC_GPIO);
|
gpio_matrix_output(panel_config->data_gpio_nums[i],
|
||||||
esp_rom_gpio_connect_out_signal(panel_config->data_gpio_nums[i],
|
lcd_periph_rgb_signals.panels[panel_id].data_sigs[i], false, false);
|
||||||
lcd_periph_rgb_signals.panels[panel_id].data_sigs[i], false, false);
|
gpio_reserve_mask |= (1 << panel_config->data_gpio_nums[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (panel_config->hsync_gpio_num >= 0) {
|
if (panel_config->hsync_gpio_num >= 0) {
|
||||||
gpio_func_sel(panel_config->hsync_gpio_num, PIN_FUNC_GPIO);
|
gpio_matrix_output(panel_config->hsync_gpio_num,
|
||||||
esp_rom_gpio_connect_out_signal(panel_config->hsync_gpio_num,
|
lcd_periph_rgb_signals.panels[panel_id].hsync_sig, false, false);
|
||||||
lcd_periph_rgb_signals.panels[panel_id].hsync_sig, false, false);
|
gpio_reserve_mask |= (1 << panel_config->hsync_gpio_num);
|
||||||
}
|
}
|
||||||
if (panel_config->vsync_gpio_num >= 0) {
|
if (panel_config->vsync_gpio_num >= 0) {
|
||||||
gpio_func_sel(panel_config->vsync_gpio_num, PIN_FUNC_GPIO);
|
gpio_matrix_output(panel_config->vsync_gpio_num,
|
||||||
esp_rom_gpio_connect_out_signal(panel_config->vsync_gpio_num,
|
lcd_periph_rgb_signals.panels[panel_id].vsync_sig, false, false);
|
||||||
lcd_periph_rgb_signals.panels[panel_id].vsync_sig, false, false);
|
gpio_reserve_mask |= (1 << panel_config->vsync_gpio_num);
|
||||||
}
|
}
|
||||||
// PCLK may not be necessary in some cases (i.e. VGA output)
|
// PCLK may not be necessary in some cases (i.e. VGA output)
|
||||||
if (panel_config->pclk_gpio_num >= 0) {
|
if (panel_config->pclk_gpio_num >= 0) {
|
||||||
gpio_func_sel(panel_config->pclk_gpio_num, PIN_FUNC_GPIO);
|
gpio_matrix_output(panel_config->pclk_gpio_num,
|
||||||
esp_rom_gpio_connect_out_signal(panel_config->pclk_gpio_num,
|
lcd_periph_rgb_signals.panels[panel_id].pclk_sig, false, false);
|
||||||
lcd_periph_rgb_signals.panels[panel_id].pclk_sig, false, false);
|
gpio_reserve_mask |= (1 << panel_config->pclk_gpio_num);
|
||||||
}
|
}
|
||||||
// DE signal might not be necessary for some RGB LCD
|
// DE signal might not be necessary for some RGB LCD
|
||||||
if (panel_config->de_gpio_num >= 0) {
|
if (panel_config->de_gpio_num >= 0) {
|
||||||
gpio_func_sel(panel_config->de_gpio_num, PIN_FUNC_GPIO);
|
gpio_matrix_output(panel_config->de_gpio_num,
|
||||||
esp_rom_gpio_connect_out_signal(panel_config->de_gpio_num,
|
lcd_periph_rgb_signals.panels[panel_id].de_sig, false, false);
|
||||||
lcd_periph_rgb_signals.panels[panel_id].de_sig, false, false);
|
gpio_reserve_mask |= (1 << panel_config->de_gpio_num);
|
||||||
}
|
}
|
||||||
// disp enable GPIO is optional, it is a general purpose output GPIO
|
// disp enable GPIO is optional, it is a general purpose output GPIO
|
||||||
if (panel_config->disp_gpio_num >= 0) {
|
if (panel_config->disp_gpio_num >= 0) {
|
||||||
gpio_func_sel(panel_config->disp_gpio_num, PIN_FUNC_GPIO);
|
gpio_matrix_output(panel_config->disp_gpio_num,
|
||||||
gpio_output_enable(panel_config->disp_gpio_num);
|
lcd_periph_rgb_signals.panels[panel_id].disp_sig, false, false);
|
||||||
|
gpio_reserve_mask |= (1 << panel_config->disp_gpio_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reserve the GPIOs
|
||||||
|
uint64_t busy_mask = esp_gpio_reserve(gpio_reserve_mask);
|
||||||
|
uint64_t conflict_mask = busy_mask & gpio_reserve_mask;
|
||||||
|
for (; conflict_mask > 0;) {
|
||||||
|
uint8_t pos = __builtin_ctzll(conflict_mask);
|
||||||
|
conflict_mask &= ~(1ULL << pos);
|
||||||
|
ESP_LOGW(TAG, "GPIO %d is not usable, maybe is reserved by others", pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb_panel->gpio_reserve_mask = gpio_reserve_mask;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lcd_rgb_panel_release_gpio(esp_rgb_panel_t *rgb_panel)
|
||||||
|
{
|
||||||
|
if (rgb_panel->gpio_reserve_mask) {
|
||||||
|
// disconnect the GPIOs from the LCD signals
|
||||||
|
for (size_t i = 0; i < rgb_panel->data_width; i++) {
|
||||||
|
if (rgb_panel->data_gpio_nums[i] >= 0) {
|
||||||
|
gpio_output_disable(rgb_panel->data_gpio_nums[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rgb_panel->hsync_gpio_num >= 0) {
|
||||||
|
gpio_output_disable(rgb_panel->hsync_gpio_num);
|
||||||
|
}
|
||||||
|
if (rgb_panel->vsync_gpio_num >= 0) {
|
||||||
|
gpio_output_disable(rgb_panel->vsync_gpio_num);
|
||||||
|
}
|
||||||
|
// PCLK may not be necessary in some cases (i.e. VGA output)
|
||||||
|
if (rgb_panel->pclk_gpio_num >= 0) {
|
||||||
|
gpio_output_disable(rgb_panel->pclk_gpio_num);
|
||||||
|
}
|
||||||
|
// DE signal might not be necessary for some RGB LCD
|
||||||
|
if (rgb_panel->de_gpio_num >= 0) {
|
||||||
|
gpio_output_disable(rgb_panel->de_gpio_num);
|
||||||
|
}
|
||||||
|
// disp enable GPIO is optional, it is a general purpose output GPIO
|
||||||
|
if (rgb_panel->disp_gpio_num >= 0) {
|
||||||
|
gpio_output_disable(rgb_panel->disp_gpio_num);
|
||||||
|
}
|
||||||
|
// release the IOs so they can be used by others again
|
||||||
|
esp_gpio_revoke(rgb_panel->gpio_reserve_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *rgb_panel, lcd_clock_source_t clk_src)
|
static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *rgb_panel, lcd_clock_source_t clk_src)
|
||||||
{
|
{
|
||||||
// get clock source frequency
|
// get clock source frequency
|
||||||
|
@@ -83,6 +83,7 @@ const lcd_rgb_signal_conn_t lcd_periph_rgb_signals = {
|
|||||||
.vsync_sig = LCD_V_SYNC_PAD_OUT_IDX,
|
.vsync_sig = LCD_V_SYNC_PAD_OUT_IDX,
|
||||||
.pclk_sig = LCD_PCLK_PAD_OUT_IDX,
|
.pclk_sig = LCD_PCLK_PAD_OUT_IDX,
|
||||||
.de_sig = LCD_H_ENABLE_PAD_OUT_IDX,
|
.de_sig = LCD_H_ENABLE_PAD_OUT_IDX,
|
||||||
|
.disp_sig = SIG_GPIO_OUT_IDX,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -64,6 +64,7 @@ const lcd_rgb_signal_conn_t lcd_periph_rgb_signals = {
|
|||||||
.vsync_sig = LCD_V_SYNC_IDX,
|
.vsync_sig = LCD_V_SYNC_IDX,
|
||||||
.pclk_sig = LCD_PCLK_IDX,
|
.pclk_sig = LCD_PCLK_IDX,
|
||||||
.de_sig = LCD_H_ENABLE_IDX,
|
.de_sig = LCD_H_ENABLE_IDX,
|
||||||
|
.disp_sig = SIG_GPIO_OUT_IDX,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -38,6 +38,7 @@ typedef struct {
|
|||||||
const int vsync_sig;
|
const int vsync_sig;
|
||||||
const int pclk_sig;
|
const int pclk_sig;
|
||||||
const int de_sig;
|
const int de_sig;
|
||||||
|
const int disp_sig;
|
||||||
} panels[SOC_LCDCAM_RGB_NUM_PANELS];
|
} panels[SOC_LCDCAM_RGB_NUM_PANELS];
|
||||||
} lcd_rgb_signal_conn_t;
|
} lcd_rgb_signal_conn_t;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user