Files
AC707N/SDK/cpu/br35/ui_driver/lcd_drive/lcd_drive.c
T
2025-12-03 11:12:34 +08:00

1451 lines
40 KiB
C

#include "app_config.h"
#include "includes.h"
#include "ui/ui_api.h"
#include "system/includes.h"
#include "system/timer.h"
#include "asm/spi_hw.h"
#include "asm/mcpwm.h"
#include "gpio.h"
#include "os/os_api.h"
#include "ui/lcd/lcd_drive.h"
#include "generic/rect.h"
#include "perf_counter/perf_counter.h"
#include "clock_manager/clock_manager.h"
#include "dbi_sfr.h"
#include "battery_manager.h"
#if (TCFG_UI_ENABLE && TCFG_SPI_LCD_ENABLE)
#define lcd_debug printf
static u8 backlight_status = 0;
static u8 lcd_sleep_in = 0;
static volatile u8 is_lcd_busy = 0;
static struct lcd_platform_data *lcd_dat = NULL;
struct mcpwm_config lcd_pwm_p_data;
static struct lcd_drive *__lcd = NULL;
static struct dbi_param *__this = NULL;
static void lcd_drv_cmd_list(u8 *cmd_list, int cmd_cnt);
static void lcd_drv_power_on(void *p);
static void lcd_drv_clear_screen(u32 color, int xstart, int xend, int ystart, int yend);
static OS_SEM lcd_sem;
static OS_SEM te_sem;
static int buffer_total_size;
static u8 *buffer;
struct lcd_init_param {
OS_SEM lcd_init_sem;
OS_SEM tp_init_sem;
u32 lcd_reinit : 1;
u32 tp_reinit : 1;
};
struct lcd_init_param lcd_init_param_t = {0};
#define __lcd_init (&lcd_init_param_t)
extern const int JLUI_USED_PSRAM_DISPLAY_BUF;
extern const int JLUI_GPU_DMA_TO_PSRAM;
// EN 控制
void lcd_en_ctrl(u8 val)
{
if (lcd_dat == NULL) {
return ;
}
enum gpio_mode mode = val ? PORT_OUTPUT_HIGH : PORT_OUTPUT_LOW;
if ((lcd_dat->pin_en != NO_CONFIG_PORT) && (lcd_dat->pin_en_ex != NO_CONFIG_PORT) && lcd_dat->pin_en != lcd_dat->pin_en_ex) {
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_en), PORT_HIGHZ);//防止电平翻转短路损坏io
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_en_ex), PORT_HIGHZ);
}
#if TCFG_LCD_TP_USE_SAME_PWR
if (!val) { //tp和lcd共同控制电,部分模组tp 和 屏幕cs 有电阻导通,因此需要cs设置为高阻
if (dbi_port_con->csx_en) {
gpio_set_mode(IO_PORT_SPILT(DBI_CSX_VSYNC), PORT_HIGHZ);
}
} else {
if (dbi_port_con->csx_en) {
gpio_set_mode(IO_PORT_SPILT(DBI_CSX_VSYNC), PORT_OUTPUT_HIGH);
}
}
#endif
enum gpio_drive_strength drive = PORT_DRIVE_STRENGT_64p0mA;
if (lcd_dat->pin_en != NO_CONFIG_PORT) {
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_en), mode);
gpio_set_drive_strength(IO_PORT_SPILT(lcd_dat->pin_en), drive);
}
if (lcd_dat->pin_en_ex != NO_CONFIG_PORT) {
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_en_ex), mode);
gpio_set_drive_strength(IO_PORT_SPILT(lcd_dat->pin_en_ex), drive);
}
}
// BL 控制
void lcd_bl_ctrl(u8 val)
{
if (lcd_dat == NULL) {
return ;
}
if (lcd_dat->pin_bl == NO_CONFIG_PORT) {
return;
}
if (lcd_dat->pin_bl == IO_LCD_PG) {
u32 value = val ? 0 : 1;
power_gate_open_drain_output(lcd_dat->pin_bl, value);
return;
}
enum gpio_mode mode = val ? PORT_OUTPUT_HIGH : PORT_OUTPUT_LOW;
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_bl), mode);
}
// TE 控制
static int spi_te_stat()
{
if (lcd_dat == NULL) {
return -1;
}
if (lcd_dat->pin_te == NO_CONFIG_PORT) {
return -1;
}
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_te), PORT_INPUT_PULLUP_100K);
return gpio_read(lcd_dat->pin_te);
}
#if (defined TCFG_LCD_TE_USED_PEND && TCFG_LCD_TE_USED_PEND)
/*------------------
* te中断配置
* -----------------*/
static void te_signal_sync_int_handler(enum gpio_port port, u32 pin, enum gpio_irq_edge edge);
static void lcd_te_irq_init(u32 io_port_pin)
{
if (io_port_pin == NO_CONFIG_PORT) {
return;
}
struct gpio_irq_config_st lcd_te_int_irq_config = {
.pin = NO_CONFIG_PORT,
.irq_edge = PORT_IRQ_EDGE_FALL,
.callback = te_signal_sync_int_handler,
.irq_priority = 3,
};
u8 port_x = io_port_pin / IO_GROUP_NUM;
u16 port_pin_x = BIT(io_port_pin % IO_GROUP_NUM);
lcd_te_int_irq_config.pin = port_pin_x;
gpio_set_mode(IO_PORT_SPILT(io_port_pin), PORT_INPUT_PULLUP_10K);
gpio_irq_config(port_x, &lcd_te_int_irq_config);
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief te_signal_sync_int_handler TE 信号中断回调
*/
/* ------------------------------------------------------------------------------------*/
static u32 te_frame_period = 16000; //先给一个最小周期的值,单位微秒
static u32 spi_frame_period = 0; //spi period先给一个最小周期的值,单位微秒
static u8 te_line_period;
/* ------------------------------------------------------------------------------------*/
//待整理
volatile int64_t dc_te_absolute_us;
volatile int64_t dc_start_absolute_us;
volatile int lcd_spi_last_us = 25 * 1000;
#if (defined TCFG_LCD_NB3030_172X320 && TCFG_LCD_NB3030_172X320)
const int lcd_te_display_line = 0x80;
#elif (defined TCFG_LCD_GC9307_172X320 && TCFG_LCD_GC9307_172X320)
const int lcd_te_display_line = 0x80;
#elif (defined TCFG_LCD_SPI_GC9B71_ENABLE && TCFG_LCD_SPI_GC9B71_ENABLE)
const int lcd_te_display_line = 0x80;
#elif (defined TCFG_LCD_SPI_ST77916_ENABLE && TCFG_LCD_SPI_ST77916_ENABLE)
const int lcd_te_display_line = 0x0;
#else
const int lcd_te_display_line = 0x0;
#endif
/* ------------------------------------------------------------------------------------*/
u32 lcd_get_te_frame_period_us(void)
{
return te_frame_period;
}
u32 lcd_get_te_phase_us()
{
//判断spi 和 te相位
return te_line_period * lcd_te_display_line;
}
u32 lcd_get_spi_frame_period_us(void)
{
if (!spi_frame_period) {
spi_frame_period = 1000 * 1000 / dbi_get_actual_fps();
}
return spi_frame_period;
}
u8 lcd_get_te_line_period_us(void)
{
return te_line_period;
}
__attribute__((weak)) void lcd_te_sync_int_handler(void)
{
}
__attribute__((weak)) void lv_lcd_te_sync_int_handler(void)
{
}
static void te_signal_sync_int_handler(enum gpio_port port, u32 pin, enum gpio_irq_edge edge)
{
#if CONFIG_LVGL_UI_ENABLE
lv_lcd_te_sync_int_handler();
#else
lcd_te_sync_int_handler();
#endif
/* 注册了上升、下降沿中断,如果上升沿则忽略、下降沿则post消息 */
/*if (!spi_te_stat()) */
/* { */
/* os_sem_post(&te_sem); */
/* } */
#if 1 //跑几次,取最小值即可,然后可屏蔽代码写死TE行周期变量
static u32 last_te_trig_time;
static u8 statistics_cnt;
if (statistics_cnt < 8) {
++statistics_cnt;
te_frame_period = get_system_us() - last_te_trig_time;
last_te_trig_time = get_system_us();
if (te_line_period != te_frame_period / (__this->lcd_height + 10)) {
te_line_period = te_frame_period / (__this->lcd_height + 10);
printf("update line_period = %dus \r\n", te_line_period);
}
printf("te_interupt frame_period = %dus, line_period = %dus \r\n", te_frame_period, te_line_period);
}
#endif
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief lcd_te_signal_sync_init TE信号同步初始化
* 1、注册TE中断回调
* 2、注册TE等待回调
* 3、创建te_sem信号量
*/
/* ------------------------------------------------------------------------------------*/
void lcd_te_signal_sync_init()
{
te_line_period = te_frame_period / __this->lcd_height; //预置一个最小情况的TE行周期,防止刚开始推屏的时候用到
lcd_te_irq_init(TCFG_LCD_TE_IO);
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* LCD DEVICE RESET
*
* Description: LCD 设备复位
*
* Arguments : none
*
* Returns : none
*
* Notes : 1、判断是否在屏驱有重新定义LCD复位函数,
* 是使用屏驱上定义的LCD复位函数,
* 否使用GPIO控制板级配置的LCD复位IO
*********************************************************************************************************
*/
static void lcd_reset(struct lcd_drive *lcd)
{
if (lcd->reset) {
lcd->reset();
} else {
if ((!lcd_dat) || (lcd_dat->pin_reset == NO_CONFIG_PORT)) {
return ;
}
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_reset), PORT_OUTPUT_HIGH);
/* udelay(200); */
os_time_dly(1);
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_reset), PORT_OUTPUT_LOW);
/* udelay(200); */
os_time_dly(1);
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_reset), PORT_OUTPUT_HIGH);
os_time_dly(10);
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* LCD BACKLIGHT CONTROL
*
* Description: LCD 背光控制
*
* Arguments : on LCD 背光开关标志,0为关,其它值为开
*
* Returns : none
*
* Notes : 1、判断是否在屏驱有重新定义背光控制函数,
* 是使用屏驱上定义的背光控制函数,
* 否使用GPIO控制板级配置的背光IO
*
* 2、配置背光状态标志,打开为true,关闭为false
*********************************************************************************************************
*/
static void lcd_mcpwm_init()
{
#if (TCFG_BACKLIGHT_PWM_MODE == 2)
if (lcd_dat == NULL) {
return ;
}
if (lcd_dat->pin_bl == IO_LCD_PG) {
power_gate_pwm_init(lcd_dat->pin_bl, 10000, 0);
return ;
}
lcd_pwm_p_data.aligned_mode = MCPWM_EDGE_ALIGNED; //边沿对齐
lcd_pwm_p_data.ch = MCPWM_CH0; //通道
lcd_pwm_p_data.frequency = 10000; //Hz
lcd_pwm_p_data.duty = 10000; //占空比
lcd_pwm_p_data.h_pin = lcd_dat->pin_bl; //任意引脚
lcd_pwm_p_data.l_pin = -1; //任意引脚,不需要就填-1
lcd_pwm_p_data.detect_port = -1; //任意引脚,不需要就填-1
lcd_pwm_p_data.complementary_en = 1; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
mcpwm_init(&lcd_pwm_p_data);
mcpwm_start(MCPWM_CH0);
#endif
}
int lcd_drv_backlight_ctrl_base(u8 percent)
{
if (__lcd->backlight_ctrl) {
printf("__lcd->backlight_ctrl : 0x%x\n", (u32)__lcd->backlight_ctrl);
__lcd->backlight_ctrl(percent);
} else if (lcd_dat && lcd_dat->pin_bl != NO_CONFIG_PORT) {
#if (TCFG_BACKLIGHT_PWM_MODE == 0)
if (percent > 0) {
lcd_bl_ctrl(1);
} else {
lcd_bl_ctrl(0);
}
#elif (TCFG_BACKLIGHT_PWM_MODE == 1)
//注意:duty不能大于prd,并且prd和duty是非标准非线性的,建议用示波器看着来调
extern int pwm_led_output_clk(u8 gpio, u8 prd, u8 duty);
if (percent) {
u32 light_level = (percent + 9) / 10;
if (light_level > 10) {
printf("lcd pwm full\n");
light_level = 10;
}
pwm_led_output_clk(lcd_dat->pin_bl, 10, light_level);
} else {
pwm_led_output_clk(lcd_dat->pin_bl, 10, 0);
}
#elif (TCFG_BACKLIGHT_PWM_MODE == 2)
battery_offset_usr_set(VBAT_OFFSET_USR_LCD, 50 * percent / 100);
if (percent) {
u32 pwm_duty = percent * 100;
if (pwm_duty > 10000) {
pwm_duty = 10000;
printf("lcd pwm full\n");
}
if (lcd_dat->pin_bl == IO_LCD_PG) {
power_gate_pwm_set_duty(lcd_dat->pin_bl, pwm_duty);
} else {
mcpwm_set_duty(lcd_pwm_p_data.ch, pwm_duty);
}
} else {
if (lcd_dat->pin_bl == IO_LCD_PG) {
power_gate_pwm_set_duty(lcd_dat->pin_bl, 0);
} else {
mcpwm_set_duty(lcd_pwm_p_data.ch, 0);
}
}
#endif
} else {
return -1;
}
return 0;
}
int lcd_drv_backlight_ctrl(u8 percent)
{
int ret = lcd_drv_backlight_ctrl_base(percent);
if (ret < 0) {
backlight_status = 0;
} else {
backlight_status = percent;
}
return ret;
}
int lcd_drv_power_ctrl(u8 on)
{
if (!__lcd) {
__lcd = lcd_drv_get_hdl(TCFG_LCD_MATCH_MODE, LCD_LOGO);
}
if (!__this) {
__this = __lcd->param;
}
if (__lcd && __lcd->power_ctrl) {
__lcd->power_ctrl(on);
}
return 0;
}
struct lcd_platform_data *lcd_get_platform_data()
{
return lcd_dat;
}
static int find_begin(u8 *begin, u8 *end, int pos)
{
u8 *p = &begin[pos];
while ((p + 3) < end) {
if ((p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]) == BEGIN_FLAG) {
return (&p[4] - begin);
}
p++;
}
return -1;
}
static int find_end(u8 *begin, u8 *end, int pos)
{
u8 *p = &begin[pos];
while ((p + 3) < end) {
if ((p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]) == END_FLAG) {
return (&p[0] - begin);
}
p++;
}
return -1;
}
#define LCD_CMD_DEBUG 0
void lcd_drv_cmd_list(u8 *cmd_list, int cmd_cnt)
{
int i;
int k;
u8 *p8;
u8 *temp = NULL;
u16 temp_len = 5 * 64;
u16 len;
temp = (u8 *)malloc(temp_len);
for (i = 0; i < cmd_cnt;) {
int begin = find_begin(cmd_list, &cmd_list[cmd_cnt], i);
int cnt = 0;
if ((begin != -1)) {
int end = find_end(cmd_list, &cmd_list[cmd_cnt], begin);
if (end != -1) {
p8 = (u8 *)&cmd_list[begin];
u8 *param;
u32 addr;
if (lcd_get_param(CMD_MODE) == CMD_24BIT) {
cnt = end - begin - 3;
param = &p8[3];
addr = (p8[0] << 16) | (p8[1] << 8) | p8[2];
} else if (lcd_get_param(CMD_MODE) == CMD_16BIT) {
cnt = end - begin - 2;
param = &p8[2];
addr = (p8[0] << 8) | p8[1];
} else {
cnt = end - begin - 1;
param = &p8[1];
addr = p8[0];
}
if (((p8[0] << 24) | (p8[1] << 16) | (p8[2] << 8) | p8[3]) == REGFLAG_DELAY_FLAG) {
printf("delay %d ms\n", p8[4]);
os_time_dly(p8[4] / 10);
} else if (((p8[0] << 24) | (p8[1] << 16) | (p8[2] << 8) | p8[3]) == REGFLAG_CONFIRM_FLAG) {
u8 addr1 = p8[4];
u8 value = p8[5];
u8 timeout = p8[6];
printf("addr : 0x%x, value : 0x%x, timeout : %d\n", addr1, value, timeout);
u8 power_mode;
u32 jiffies_begin = jiffies_msec();
int wait_timeout = jiffies + msecs_to_jiffies(timeout); //超时时间设置
while (1) {
if (time_after(jiffies, wait_timeout)) {
printf("confirm fail! lcd power_mode status 0x%x wait timeout\n", value);
break;
}
lcd_read_cmd(addr, &power_mode, sizeof(power_mode));
if (power_mode == value) {
cnt++;
if (cnt > 10) {
break;
}
} else {
cnt = 0;
}
}
u32 jiffies_end = jiffies_msec();
printf("0x%x wait %d ms\n", addr1, jiffies_end - jiffies_begin);
} else {
#if LCD_CMD_DEBUG
len = sprintf((char *)temp, "send : 0x%08x(%d), ", addr, cnt);
for (k = 0; k < cnt; k++) {
len += sprintf((char *)&temp[len], "0x%02x, ", param[k]);
if (len > (temp_len - 10)) {
len += sprintf((char *)&temp[len], "...");
break;
}
}
len += sprintf((char *)&temp[len], "\n");
if (len <= temp_len) {
printf("cmd:%s", temp);
}
#endif
lcd_write_cmd(addr, param, cnt);
}
i = end + 4;
}
}
}
free(temp);
}
/*$PAGE*/
/*
*********************************************************************************************************
* LCD DEVICE MATCH
*
* Description: LCD 设备初始化
*
* Arguments : 匹配模式, 屏驱LOGO
*
* Returns : 屏设备句柄
*
* Notes : 1、当只有一个屏驱时,不进行匹配,直接返回该屏驱句柄
*
* 2、两种匹配方式 LOGO 或者 ID
*
* 3、若存在屏设备句柄时直接返回
*********************************************************************************************************
*/
struct lcd_drive *lcd_drv_get_hdl(u8 mode, const char *logo)
{
if (__lcd) {
return __lcd;
} else {
if (mode == LCD_MATCH_BY_LOGO) {
return lcd_drv_get_hdl_by_logo(logo);
} else {
return lcd_drv_get_hdl_by_id();
}
}
}
int __attribute__((weak)) ui_gpu_buf_max_size_set(int max_size)
{
return 0;
}
/*$PAGE*/
/*
*********************************************************************************************************
* LCD DEVICE INIT
*
* Description: LCD 设备初始化
*
* Arguments : *p 板级配置的 LCD SPI 信息
*
* Returns : 0 初始化成功
* -1 初始化失败
*
* Notes : 1、判断是否在板级文件配置SPI,是继续,否进入断言,
*
* 2、配置SPI可操作IO给IMD操作
*
* 3、LCD设备复位
*
* 4、SPI模块初始化,IMD模块初始化
*********************************************************************************************************
*/
void lcd_drv_init(void *p)
{
lcd_debug("lcd_drv_init ...\n");
struct ui_devices_cfg *cfg = (struct ui_devices_cfg *)p;
/* lcd_dat = (struct lcd_platform_data *)cfg->private_data; */
if (lcd_dat == NULL) {
lcd_dat = zalloc(sizeof(struct lcd_platform_data));
ASSERT(lcd_dat);
}
memcpy(lcd_dat, cfg->private_data, sizeof(struct lcd_platform_data));
ASSERT(lcd_dat, "Error! spi io not config");
lcd_debug("spi pin rest:%d, en:%d\n", \
lcd_dat->pin_reset, lcd_dat->pin_en);
//可通过屏幕logo或者屏幕id匹配屏驱,任选一种匹配方式
if (!__lcd) {
__lcd = lcd_drv_get_hdl(TCFG_LCD_MATCH_MODE, LCD_LOGO);
}
if (!__this) {
__this = __lcd->param;
}
ASSERT(__lcd, ", don't find lcd_device");
ASSERT(__this, ", don't find dbi_param");
/* 如果有使能IO,设置使能IO输出高电平 */
lcd_en_ctrl(true);
/* 把 CS、DC IO 的控制配置到IMD */
if (__lcd->row_addr_align && __lcd->column_addr_align) {
lcd_set_align(__lcd->row_addr_align, __lcd->column_addr_align);
} else {
lcd_set_align(1, 1);
}
#if 0//LCD_POWER_DOWN_EN
/* 初始化imd和硬件SPI等 */
lcd_init(__this);
#if (defined TCFG_LCD_TE_USED_PEND && TCFG_LCD_TE_USED_PEND)
lcd_te_signal_sync_init();
#endif
lcd_drv_power_on((void *) 1);
lcd_mcpwm_init();
return;
#endif
#if (defined TCFG_LCD_SPI_ICNA3310B_ENABLE && TCFG_LCD_SPI_ICNA3310B_ENABLE)
gpio_set_drive_strength(IO_PORT_SPILT(IO_PORTA_12), PORT_DRIVE_STRENGT_64p0mA);
#endif
#if (defined TCFG_LCD_QSPI_jd9161c_ENABLE && TCFG_LCD_QSPI_jd9161c_ENABLE)
// 由于是飞线调试这个屏驱,线较长,信号不好,故开此强驱,PCBA板上可注释掉这句看下效果
gpio_set_drive_strength(IO_PORT_SPILT(IO_PORTA_12), PORT_DRIVE_STRENGT_8p0mA);
#endif
#if (defined TCFG_LCD_QSPI_ST77903_V2_ENABLE && TCFG_LCD_QSPI_ST77903_V2_ENABLE)
// 由于是飞线调试这个屏驱,线较长,信号不好,故开此强驱,PCBA板上可注释掉这句看下效果
gpio_set_drive_strength(IO_PORT_SPILT(IO_PORTA_12), PORT_DRIVE_STRENGT_8p0mA);
#endif
/* 初始化imd和硬件SPI等 */
lcd_init(__this);
int buf_size = (__this->buffer_size + 3) / 4 * 4;
buf_size = buf_size / 2;
ui_gpu_buf_max_size_set(buf_size);
/* lcd复位 */
lcd_reset(__lcd);
#if (defined TCFG_LCD_TE_USED_PEND && TCFG_LCD_TE_USED_PEND)
lcd_te_signal_sync_init();
#endif
/* 屏幕初始化指令 */
lcd_drv_cmd_list(__lcd->lcd_cmd, __lcd->cmd_cnt);
#if (defined TCFG_LCD_SPI_ST77916_ENABLE && TCFG_LCD_SPI_ST77916_ENABLE)
if (JLUI_GPU_DMA_TO_PSRAM) {
u8 te_pos_params[] = {0x00, 0x80};
lcd_write_cmd(0x44, te_pos_params, sizeof(te_pos_params));
lcd_clock_reinit(65);
}
#endif
#if 1
u8 power_mode = 0;
lcd_read_cmd(0x0a, &power_mode, sizeof(power_mode));
printf("power_mode : 0x%x\n", power_mode);
u8 pixel_format = 0;
lcd_read_cmd(0x0c, &pixel_format, sizeof(pixel_format));
printf("pixel_format : 0x%x\n", pixel_format);
#elif 0//mcu屏,dummy byte
u8 power_mode[2] = {0};
lcd_read_cmd(0x0a, power_mode, sizeof(power_mode));
printf("power_mode : 0x%x, 0x%x\n", power_mode[0], power_mode[1]);
u8 pixel_format[2] = {0};
lcd_read_cmd(0x0c, pixel_format, sizeof(pixel_format));
printf("pixel_format : 0x%x, 0x%x\n", pixel_format[0], pixel_format[1]);
#endif
lcd_mcpwm_init();
}
/*$PAGE*/
/*
*********************************************************************************************************
* GET LCD DEVICE INFO
*
* Description: 获取 LCD 设备信息
*
* Arguments : *info LCD 设备信息缓存结构体,根据结构体内容赋值即可
*
* Returns : 0 获取成功
* -1 获取失败
*
* Notes : 1、根据参数结构体的内容,将LCD对应信息赋值给结构体元素
*********************************************************************************************************
*/
static void lcd_drv_get_screen_info(struct lcd_info *info)
{
/* imb的宽高 */
ASSERT(__this);
info->width = __this->in_width;
info->height = __this->in_height;
info->radius = __lcd->radius;
info->fill_argb = __lcd->fill_argb;
/* imb的输出格式 */
info->color_format = __this->in_format;//OUTPUT_FORMAT_RGB565;
if (info->color_format == OUTPUT_FORMAT_RGB565) {
info->stride = (info->width * 2 + 3) / 4 * 4;
} else if (info->color_format == OUTPUT_FORMAT_RGB888) {
info->stride = (info->width * 3 + 3) / 4 * 4;
}
/* 屏幕类型 */
info->interface = __this->lcd_type;
info->fps = __this->fps;
/* 对齐 */
info->col_align = __lcd->column_addr_align;
info->row_align = __lcd->row_addr_align;
if (!info->col_align) {
info->col_align = 1;
}
if (!info->row_align) {
info->row_align = 1;
}
/* 背光状态 */
info->bl_status = !!backlight_status;
info->buf_num = __this->buffer_num;
info->buffer = buffer;
info->buffer_size = buffer_total_size;
ASSERT(info->col_align, " = 0, lcd driver column address align error, default value is 1");
ASSERT(info->row_align, " = 0, lcd driver row address align error, default value is 1");
/* return 0; */
}
int lcd_get_screen_width()
{
return __this->in_width;
}
int lcd_get_screen_height()
{
return __this->in_height;
}
/*$PAGE*/
/*
*********************************************************************************************************
* MALLOC DISPLAY BUFFER
*
* Description: 申请 LCD 显存 buffer
*
* Arguments : **buf 保存显存buffer指针
* *size 保存显存buffer大小
*
* Returns : 0 成功
* -1 失败
*
* Notes : 1、根据LCD驱动中配置的显存大小和数量申请显存BUFFER
*
* 2、将显存buffer指针赋值给参数**buf,显存buffer大小赋值给参数*size
*
* 注意:buffer默认是lock状态,此时不能推屏,需由UI框架获取并写入数据后才能推屏
*********************************************************************************************************
*/
extern u32 _LCD_BUF_STATIC_START;
extern u32 _LCD_BUF_STATIC_END;
static void lcd_drv_buffer_malloc(u8 **buf, u32 *size)
{
/* int buf_size = ((__this->lcd_width * __this->lcd_height * 2) + 3) / 4 * 4; */
ASSERT(__this);
int buf_size = (__this->buffer_size + 3) / 4 * 4; // 把buffer大小做四字节对齐
/* printf("lcdbuf, s:0x%x, e:0x%x \n", (u32)&_LCD_BUF_STATIC_START, (u32)&_LCD_BUF_STATIC_END); */
if (CONFIG_LCD_BUF_STATIC_RAM_LEN) {
u32 buf_len = (u32)&_LCD_BUF_STATIC_END - (u32)&_LCD_BUF_STATIC_START;
u32 use_len = buf_size * __this->buffer_num;
/* printf("lcdbuf, size:0x%x, 0x%x \n", buf_len, use_len); */
ASSERT(buf_len == use_len);
*buf = (u8 *)&_LCD_BUF_STATIC_START;
} else if (JLUI_USED_PSRAM_DISPLAY_BUF) {
*buf = (u8 *)malloc_psram(buf_size * __this->buffer_num);
} else if (TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE) {
*buf = NULL;
} else {
*buf = (u8 *)malloc(buf_size * __this->buffer_num);
}
#if (! TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE)
if (*buf == NULL) {
// 如果buffer申请失败
*size = 0;
return;
}
#endif
*size = buf_size * __this->buffer_num;
buffer = *buf;
buffer_total_size = *size;
return;
}
/*$PAGE*/
/*
*********************************************************************************************************
* FREE DISPLAY BUFFER
*
* Description: 释放 LCD 显存 buffer
*
* Arguments : *buf 显存buffer指针
*
* Returns : 0 成功
* -1 失败
*
* Notes : 1、使用memory API 释放显存buffer
*********************************************************************************************************
*/
static void lcd_drv_buffer_free(u8 *buf)
{
if (buf) {
if (CONFIG_LCD_BUF_STATIC_RAM_LEN) {
} else if (JLUI_USED_PSRAM_DISPLAY_BUF) {
free_psram(buf);
} else {
free(buf);
}
}
return;
}
/*$PAGE*/
/*
*********************************************************************************************************
* LCD DRAW BUFFER
*
* Description: 把显存 buf 推送到屏幕
*
* Arguments : *buf 显存buffer指针
* len 显存buffer的数据量
* wait 是否等待
*
* Returns : 0 成功
* -1 失败
*
* Notes : 1、使用 IMD 模块将显存buffer推给屏幕
*********************************************************************************************************
*/
static void lcd_drv_draw(u8 *buf, int xstart, int xend, int ystart, int yend)
{
lcd_draw(buf, xstart, xend, ystart, yend);
}
static void lcd_drv_draw_continue(u8 *buf, int xstart, int xend, int ystart, int yend)
{
lcd_draw_continue(buf, xstart, xend, ystart, yend);
}
/*$PAGE*/
/*
*********************************************************************************************************
* GET LCD BACKLIGHT STATUS
*
* Description: 获取 LCD 背光状态
*
* Arguments : none
*
* Returns : 0 背光熄灭
* 1 背光点亮
*
* Notes :
*********************************************************************************************************
*/
int lcd_backlight_status()
{
return !!backlight_status;
}
/*
*********************************************************************************************************
* GET LCD BACKLIGHT STATUS
*
* Description: 获取 LCD sleep状态
*
* Arguments : none
*
* Returns : 0 sleep out
* 1 sleep in
*
* Notes :
*********************************************************************************************************
*/
int lcd_sleep_status()
{
return lcd_sleep_in;
}
// 触摸屏sleep处理
__attribute__((weak)) void ctp_enter_sleep(void)
{
}
__attribute__((weak)) void ctp_exit_sleep(void)
{
}
/*
* 弱函数重定义(升级复位前停止刷屏)
* */
void update_process_before_cpu_reset(void)
{
if (lcd_sleep_in) {
} else {
}
}
#if LCD_POWER_DOWN_EN
void lcd_reinit_wait_finish(void)
{
if (__lcd_init && __lcd_init->lcd_reinit) {
os_sem_pend(&__lcd_init->lcd_init_sem, 0);
os_sem_del(&__lcd_init->lcd_init_sem, OS_DEL_ALWAYS);
int ret = task_kill("lcd_init");
ASSERT(!ret);
__lcd_init->lcd_reinit = 0;
}
}
static void lcd_drv_power_off()
{
// 关闭之前检查上次是否已经完成
lcd_reinit_wait_finish();
/* lcd断电 */
printf("lcd power off\n");
lcd_drv_power_ctrl(false);
struct lcd_platform_data *lcd_dat = lcd_get_platform_data();
if (lcd_dat && lcd_dat->pin_te != NO_CONFIG_PORT) {
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_te), PORT_HIGHZ);
}
if (lcd_dat && lcd_dat->pin_reset != NO_CONFIG_PORT) {
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_reset), PORT_HIGHZ);
}
}
static void lcd_init_task(void *p)
{
int first_init = (int)p;
if (!first_init) {
/* lcd上电 */
lcd_drv_power_ctrl(true);
}
/* lcd复位 */
lcd_reset(__lcd);
if (lcd_dat && lcd_dat->pin_te != NO_CONFIG_PORT) {
gpio_set_mode(IO_PORT_SPILT(lcd_dat->pin_te), PORT_INPUT_PULLUP_10K);
}
/* SPI发送屏幕初始化代码 */
lcd_drv_cmd_list(__lcd->lcd_cmd, __lcd->cmd_cnt);
lcd_drv_clear_screen(0x0, 0, __this->lcd_width - 1, 0, __this->lcd_height - 1);
os_sem_post(&__lcd_init->lcd_init_sem);
while (1) {
os_time_dly(100);
}
}
static void lcd_drv_power_on(void *p)
{
int err;
__lcd_init->lcd_reinit = 1;
os_sem_create(&__lcd_init->lcd_init_sem, 0);
err = task_create(lcd_init_task, p, "lcd_init");
ASSERT(err == 0);
}
#endif
#if TP_POWER_DOWN_EN
extern void ctp_poweron(void);
extern void ctp_poweroff(void);
void tp_reinit_wait_finish(void)
{
if (__lcd_init && __lcd_init->tp_reinit) {
os_sem_pend(&__lcd_init->tp_init_sem, 0);
os_sem_del(&__lcd_init->tp_init_sem, OS_DEL_ALWAYS);
int ret = task_kill("tp_init");
ASSERT(!ret);
__lcd_init->tp_reinit = 0;
}
}
static void tp_drv_power_off()
{
// 关闭之前检查上次是否已经完成
tp_reinit_wait_finish();
#if TCFG_TP_CST816D_ENABLE
extern void cst816d_deinit();
cst816d_deinit();
#endif // TCFG_TP_CST816D_ENABLE
#if TCFG_TP_FT3X68_ENABLE
extern void fts_ts_deinit();
fts_ts_deinit();
#endif// TCFG_TP_FT3X68_ENABLE
#if TCFG_TP_AXS5106_ENABLE
extern void axs5106_deinit();
axs5106_deinit();
#endif // TCFG_TP_AXS5106_ENABLE
/* TP掉电 */
#if !TCFG_LCD_TP_USE_SAME_PWR
ctp_poweroff();
#endif
}
static void tp_init_task(void *p)
{
/* TP上电 */
#if !TCFG_LCD_TP_USE_SAME_PWR
ctp_poweron();
#endif
#if TCFG_TP_BL6133_ENABLE
extern void bl6133_test();
extern void bl6133_int_en();
/* TP初始化 */
bl6133_test();
/* TP int中断使能 */
bl6133_int_en();
#endif
#if TCFG_TP_CST816D_ENABLE
extern void cst816d_init();
cst816d_init();
#endif // TCFG_TP_CST816D_ENABLE
#if TCFG_TP_FT3X68_ENABLE
extern void fts_ts_init();
fts_ts_init();
#endif
#if TCFG_TP_AXS5106_ENABLE
extern void axs5106_init();
axs5106_init();
#endif // TCFG_TP_AXS5106_ENABLE
os_sem_post(&__lcd_init->tp_init_sem);
while (1) {
os_time_dly(100);
}
}
static void tp_drv_power_on()
{
int err;
__lcd_init->tp_reinit = 1;
os_sem_create(&__lcd_init->tp_init_sem, 0);
err = task_create(tp_init_task, NULL, "tp_init");
ASSERT(err == 0);
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* LCD SLEEP CONTROL
*
* Description: LCD 休眠控制
*
* Arguments : enter 是否进入休眠,true 进入休眠,false 退出休眠
*
* Returns : 0 成功
* -1 失败
*
* Notes : 1、判断 LCD 是否正在使用,是等待使用结束,否进入下一步
*
* 2、enter是否进入休眠,是使用LCD休眠函数进入休眠状态,否使用LCD退出休眠函数退出休眠状态
*
* 3、lcd_sleep_in 记录LCD的休眠状态
*********************************************************************************************************
*/
int lcd_sleep_ctrl(u8 enter)
{
struct lcd_sleep_headler *p;
if ((!!enter) == lcd_sleep_in) {
return -1;
}
while (is_lcd_busy);
is_lcd_busy = 0x11;
#if (defined TCFG_EARPHONE_PROTOCOL) && (TCFG_EARPHONE_PROTOCOL)
extern void set_sleep_control_status(u8 en);
set_sleep_control_status(enter);
void custom_client_sleep_control(u8 on);
custom_client_sleep_control(enter);
#endif
if (enter) {
lcd_drv_backlight_ctrl_base(0);
lcd_enter_sleep();
#if TCFG_TP_SLEEP_EN
ctp_enter_sleep();
#endif /* #if TCFG_TP_SLEEP_EN */
#if TP_POWER_DOWN_EN
tp_drv_power_off();
#endif
#if LCD_POWER_DOWN_EN == 0
if (__lcd->entersleep) {
__lcd->entersleep();
lcd_sleep_in = true;
}
#else
if (__lcd->entersleep) {
__lcd->entersleep();
}
lcd_drv_power_off();
lcd_sleep_in = true;
#endif
list_for_each_lcd_sleep_headler(p) {
if (p->enter) {
p->enter();
}
}
/* 释放PSRAM帧缓存,在息屏时才释放,亮屏时不释放 */
if (JLUI_GPU_DMA_TO_PSRAM) {
extern void psram_frame_buf_release();
psram_frame_buf_release();
}
clock_unlock("ui_show");
} else {
clock_lock("ui_show", clk_get_max_frequency());
lcd_exit_sleep();
#if LCD_POWER_DOWN_EN == 0
if (__lcd->exitsleep) {
__lcd->exitsleep();
lcd_sleep_in = false;
}
#else
lcd_drv_power_on(NULL);
lcd_sleep_in = false;
#endif
#if TP_POWER_DOWN_EN
tp_drv_power_on();
#endif
#if TCFG_COLOR_SCREEN_CHARGING_CASE_ENABLE
#if (defined TCFG_LCD_TE_USED_PEND && TCFG_LCD_TE_USED_PEND)
lcd_te_signal_sync_init();
#endif
#endif
#if TCFG_TP_SLEEP_EN
ctp_exit_sleep();
#endif /* #if TCFG_TP_SLEEP_EN */
list_for_each_lcd_sleep_headler(p) {
if (p->exit) {
p->exit();
}
}
/* lcd_drv_backlight_ctrl_base(backlight_status); */
}
is_lcd_busy = 0;
return 0;
}
void lcd_bl_open()
{
/* lcd_mcpwm_init(); */
lcd_drv_backlight_ctrl_base(backlight_status);
}
/*$PAGE*/
/*
*********************************************************************************************************
* GET LCD DRIVE HANDLER
*
* Description: 获取LCD驱动句柄
*
* Arguments : none
*
* Returns : struct lcd_interface* LCD驱动接口句柄
*
* Notes : 1、从LCD接口列表中找到LCD接口句柄并返回
*********************************************************************************************************
*/
struct lcd_interface *lcd_get_hdl()
{
struct lcd_interface *p;
ASSERT(lcd_interface_begin != lcd_interface_end, "don't find lcd interface!");
for (p = lcd_interface_begin; p < lcd_interface_end; p++) {
return p;
}
return NULL;
}
static void lcd_drv_set_draw_area(u16 xs, u16 xe, u16 ys, u16 ye)
{
lcd_set_draw_area(xs, xe, ys, ye);
}
static void lcd_drv_clear_screen(u32 color, int xstart, int xend, int ystart, int yend)
{
lcd_clear(color, xstart, xend, ystart, yend);
lcd_wait_busy();
}
struct lcd_drive *lcd_drv_get_hdl_by_logo(const char *logo)
{
struct lcd_drive *p;
int lcd_type;
int spi_mode;
int spi_submode;
int lcd_num = 0;
/* printf("find logo %s\n", logo); */
ASSERT(lcd_device_begin != lcd_device_end, "don't find lcd device!");
//统计屏驱的个数
for (p = lcd_device_begin; p < lcd_device_end; p++) {
lcd_num++;
}
//只有一个屏驱时不进行匹配
if (lcd_num == 1) {
p = lcd_device_begin;
printf("Due to lcd_num = %d, don't match any lcd device. Only one lcd device %s is selected by default.\n", lcd_num, p->logo ? p->logo : "null");
return p;
}
//需确保所有使能的屏驱接口保持一致
for (p = lcd_device_begin; p < lcd_device_end; p++) {
if (p == lcd_device_begin) {
lcd_type = ((struct dbi_param *)p->param)->lcd_type;
spi_mode = ((struct dbi_param *)p->param)->spi.spi_mode & 0xf0;
spi_submode = ((struct dbi_param *)p->param)->spi.spi_mode & 0x0f;
} else {
ASSERT(lcd_type == ((struct dbi_param *)p->param)->lcd_type, ", all lcd interface must the same");
ASSERT(spi_mode == (((struct dbi_param *)p->param)->spi.spi_mode & 0xf0), ", all spi_mode must the same");
ASSERT(spi_submode == (((struct dbi_param *)p->param)->spi.spi_mode & 0x0f), ", all spi_submode must the same");
}
}
for (p = lcd_device_begin; p < lcd_device_end; p++) {
printf("p->logo : %s\n", p->logo);
if (p->logo && logo && !strcmp(p->logo, logo)) {
return p;
}
}
return NULL;
}
struct lcd_drive *lcd_drv_get_hdl_by_id()
{
struct lcd_drive *p;
int lcd_type;
int spi_mode;
int spi_submode;
int lcd_num = 0;
ASSERT(lcd_device_begin != lcd_device_end, "don't find lcd device!");
//统计屏驱的个数
for (p = lcd_device_begin; p < lcd_device_end; p++) {
lcd_num++;
}
//只有一个屏驱时不进行匹配
if (lcd_num == 1) {
p = lcd_device_begin;
printf("Due to lcd_num = %d, don't match any lcd device. Only one lcd device %s is selected by default.\n", lcd_num, p->logo ? p->logo : "null");
return p;
}
//需确保所有使能的屏驱接口保持一致
for (p = lcd_device_begin; p < lcd_device_end; p++) {
if (p == lcd_device_begin) {
lcd_type = ((struct dbi_param *)p->param)->lcd_type;
spi_mode = ((struct dbi_param *)p->param)->spi.spi_mode & 0xf0;
spi_submode = ((struct dbi_param *)p->param)->spi.spi_mode & 0x0f;
} else {
ASSERT(lcd_type == ((struct dbi_param *)p->param)->lcd_type, ", all lcd interface must the same");
ASSERT(spi_mode == (((struct dbi_param *)p->param)->spi.spi_mode & 0xf0), ", all spi_mode must the same");
ASSERT(spi_submode == (((struct dbi_param *)p->param)->spi.spi_mode & 0x0f), ", all spi_submode must the same");
}
}
for (p = lcd_device_begin; p < lcd_device_end; p++) {
struct dbi_param *this = (struct dbi_param *)p->param;
extern struct dbi_variable dbi_var;
dbi_var.clock_init = false;
lcd_en_ctrl(true);
lcd_set_ctrl_pin_func(spi_te_stat);
lcd_reset(p); /* lcd复位 */
lcd_init(this); /* 初始化lcd控制器 */
u32 lcd_read_id = 0;
if (p->read_id) {
lcd_read_id = p->read_id();
}
printf("p->logo : %s, p->lcd_id : 0x%x, read_id : 0x%x\n", p->logo ? p->logo : "null", p->lcd_id, lcd_read_id);
if (p->lcd_id == lcd_read_id) {
return p;
}
}
return NULL;
}
int lcd_drv_get_info(void *info)
{
struct lcd_interface *lcd;
lcd = lcd_get_hdl();
ASSERT(lcd);
if (lcd->get_screen_info) {
lcd->get_screen_info(info);
}
return 0;
}
REGISTER_LCD_INTERFACE(lcd) = {
.init = lcd_drv_init,
.draw = lcd_drv_draw,
.draw_continue = lcd_drv_draw_continue,
.get_screen_info = lcd_drv_get_screen_info,
.buffer_malloc = lcd_drv_buffer_malloc,
.buffer_free = lcd_drv_buffer_free,
.backlight_ctrl = lcd_drv_backlight_ctrl,
.power_ctrl = lcd_drv_power_ctrl,
.set_draw_area = lcd_drv_set_draw_area,
.clear_screen = lcd_drv_clear_screen,
};
static u8 lcd_idle_query(void)
{
return !is_lcd_busy;
}
REGISTER_LP_TARGET(lcd_lp_target) = {
.name = "lcd",
.is_idle = lcd_idle_query,
};
#endif /* #if (TCFG_UI_ENABLE && TCFG_SPI_LCD_ENABLE) */