1451 lines
40 KiB
C
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) */
|
|
|
|
|