rt-thread/bsp/allwinner/libraries/drivers/drv_lcd.c

814 lines
23 KiB
C

/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-04-12 RT-Thread the first version
* 2023-09-02 zbtrs support sdl2
*/
#include "rtthread.h"
#include <rthw.h>
#include <string.h>
#include <stdatomic.h>
#include "interrupt.h"
#include "mmu.h"
#include "cache.h"
#ifdef BSP_USING_LCD
#include "drv_lcd.h"
#include "lcd_cfg.h"
#ifdef RT_USING_SMART
#include <page.h>
#include <lwp_user_mm.h>
#endif
#include <video/sunxi_display2.h>
#include <dfs_file.h>
#include "dev_disp.h"
#define DEFAULT_SCREEN (0)
#define LCD_DRV_FB_SZ (lcd_drv->lcd_info.width * lcd_drv->lcd_info.height * sizeof(rt_uint32_t))
enum state_buff
{
EMPTY,
FULL
};
enum lcd_evt
{
LCD_EVT_VSYNC = 1,
};
struct buff_info
{
rt_uint32_t *buff;
rt_uint32_t *buff_phy;
enum state_buff status;
};
/* kind of a candidate for the official lcd driver framework */
struct lcd_device
{
struct rt_device lcd;
struct rt_device fb;
struct rt_device_graphic_info lcd_info; /* rtdef.h */
struct rt_event lcd_evt;
int use_screen; /* screen index */
void *framebuffer;
void *framebuffer_phy;
atomic_uint refresh_flag; /* atom flag, 0: nothing. 1:framebuffer ==> front_buf. 2:back_buf ==> front_buf. */
struct buff_info front_buf_info; /* TCON hardware framebuffer */
struct buff_info back_buf_info; /* rotate swap framebuffer */
const struct lcd_cfg_panel_info *panel;
};
typedef struct lcd_device *lcd_device_t;
static struct disp_layer_config layer_cfg;
static struct lcd_device _lcd_device;
static const struct lcd_cfg_panel_info *_panel;
static int lcd_status = 0;
static rt_uint8_t lcd_bn = 80;
#define LCD_PWM_DEV_CHANNEL 1
extern void rt_hw_cpu_dcache_clean(void *addr, int size);
extern int disp_ioctl(int cmd, void *arg);
extern int disp_probe(void);
struct lcd_device *g_lcd = RT_NULL;
/* set up the lcd pin function */
static void lcd_gpio_config(void)
{
int i;
gpio_pin_t pin;
gpio_muxsel_t function_index;
gpio_driving_level_t level;
if (_panel->bl_pin >= 0)
{
hal_gpio_set_direction(_panel->bl_pin, GPIO_DIRECTION_OUTPUT); // bl_pin
hal_gpio_set_driving_level(_panel->bl_pin, 3);
hal_gpio_set_data(_panel->bl_pin, _panel->bl_level);
}
if (_panel->pwr_pin >= 0)
{
hal_gpio_set_direction(_panel->pwr_pin, GPIO_DIRECTION_OUTPUT); // pwr_pin
hal_gpio_set_driving_level(_panel->pwr_pin, 3);
hal_gpio_set_data(_panel->pwr_pin, 0);
rt_thread_delay(10);
hal_gpio_set_data(_panel->pwr_pin, _panel->pwr_level);
rt_thread_delay(10);
lcd_status = _panel->pwr_level;
}
if (_panel->bl_mode == 0)
{
hal_gpio_set_direction(_panel->bl_gpio_pin, GPIO_DIRECTION_OUTPUT);
hal_gpio_set_driving_level(_panel->bl_gpio_pin, 3);
hal_gpio_set_data(_panel->bl_gpio_pin, _panel->bl_gpio_level);
}
else
{
lcd_bn = _panel->bl_pwm_val;
set_lcd_backlight(lcd_bn);
}
}
void *lcd_get_framebuffer(void *dev)
{
return ((struct lcd_device *)dev)->framebuffer;
}
s32 lcd_vsync_event_process(u32 sel)
{
lcd_device_t lcd_drv = &_lcd_device;
uint32_t refresh_flag = atomic_exchange(&lcd_drv->refresh_flag, 0); // read-modify-write, read & clean.
if (refresh_flag != 0)
{
uint32_t len = (uint32_t)lcd_drv->lcd_info.width * lcd_drv->lcd_info.height * (lcd_drv->lcd_info.bits_per_pixel / 8);
uint32_t len_stage1 = 1024;
void *dst = lcd_drv->front_buf_info.buff;
const void *src = lcd_drv->framebuffer;
if (refresh_flag == 1)
{
src = lcd_drv->framebuffer;
}
else if (refresh_flag == 2)
{
src = lcd_drv->back_buf_info.buff;
}
else
{
// TODO: error
}
memcpy((uint32_t *)dst, (uint32_t *)src, len_stage1);
rt_hw_cpu_dcache_clean(dst, len_stage1);
memcpy((uint32_t *)(dst + len_stage1), (uint32_t *)(src + len_stage1), len - len_stage1);
rt_hw_cpu_dcache_clean((uint32_t *)(dst + len_stage1), len - len_stage1);
rt_event_send(&lcd_drv->lcd_evt, LCD_EVT_VSYNC);
}
rt_event_send(&lcd_drv->lcd_evt, LCD_EVT_VSYNC);
}
static void _framebuffer_rotate_mirror(void *src_buf, void *dst_buf,
const struct rt_device_graphic_info *lcd_info, const struct lcd_cfg_panel_info *_panel_info)
{
lcd_device_t lcd_drv = &_lcd_device;
memcpy(dst_buf, src_buf, LCD_DRV_FB_SZ);
}
/* Multi-layer is not supported now. */
#ifdef GUIENGINE_USING_MULTI_LAYER
#include <rtgui/rtgui_layer.h>
struct debe_info
{
int index;
void *buffer;
rt_uint32_t bf_size;
};
static struct debe_info _debe_use[3];
#endif
/* pixel format, only 565 (2 bytes) or 666 (4 bytes) are supported */
static inline int _lcd_format_get(rt_uint8_t pixel_format)
{
switch (pixel_format)
{
case RTGRAPHIC_PIXEL_FORMAT_RGB565:
return DISP_FORMAT_RGB_565;
case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
return DISP_FORMAT_ARGB_8888;
default:
return -1;
}
}
static int _lcd_drv_init(lcd_device_t lcd_drv)
{
unsigned long arg[6] = {0};
void *framebuffer = RT_NULL;
void *frontbuf = RT_NULL;
void *backbuf = RT_NULL;
/*
* The event is used for the synchronization between updating the
* framebuffer and flushing the screen.
*/
rt_event_init(&lcd_drv->lcd_evt, "lcd_evt", RT_IPC_FLAG_FIFO);
/* the lcd device information defined by RT-Thread */
arg[0] = lcd_drv->use_screen;
lcd_drv->lcd_info.width = (rt_uint16_t)disp_ioctl(DISP_GET_SCN_WIDTH, arg);
lcd_drv->lcd_info.height = (rt_uint16_t)disp_ioctl(DISP_GET_SCN_HEIGHT, arg);
lcd_drv->lcd_info.bits_per_pixel = 32;
lcd_drv->lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_ARGB888; /* should be coherent to adding layers */
/* allocate the framebuffer, the front buffer and the back buffer */
/* framebuffer */
#ifdef RT_USING_SMART
framebuffer = rt_pages_alloc(rt_page_bits(LCD_DRV_FB_SZ));
#else
framebuffer = rt_malloc(LCD_DRV_FB_SZ);
#endif
if (!framebuffer)
{
rt_kprintf("malloc framebuffer fail\n");
goto out;
}
lcd_drv->lcd_info.framebuffer = framebuffer;
lcd_drv->framebuffer = framebuffer;
lcd_drv->framebuffer_phy = (void *)((size_t)framebuffer + PV_OFFSET);
memset(framebuffer, 0, LCD_DRV_FB_SZ);
rt_hw_cpu_dcache_clean(lcd_drv->framebuffer, LCD_DRV_FB_SZ);
#ifdef RT_USING_SMART
frontbuf = rt_pages_alloc(rt_page_bits(LCD_DRV_FB_SZ));
#else
frontbuf = rt_malloc(LCD_DRV_FB_SZ);
#endif
if (!frontbuf)
{
rt_kprintf("malloc frontbuf fail\n");
goto out;
}
lcd_drv->front_buf_info.buff = frontbuf;
lcd_drv->front_buf_info.buff_phy = (void *)((size_t)frontbuf + PV_OFFSET);
memset(frontbuf, 0, LCD_DRV_FB_SZ);
rt_hw_cpu_dcache_clean(lcd_drv->front_buf_info.buff, LCD_DRV_FB_SZ);
if ((lcd_drv->panel) && (lcd_drv->panel->swap_flag != 0))
{
/* backbuf */
#ifdef RT_USING_SMART
backbuf = rt_pages_alloc(rt_page_bits(LCD_DRV_FB_SZ));
#else
backbuf = rt_malloc(LCD_DRV_FB_SZ);
#endif
if (!backbuf)
{
rt_kprintf("malloc backbuf fail\n");
goto out;
}
lcd_drv->back_buf_info.buff = backbuf;
lcd_drv->back_buf_info.buff_phy = (void *)((size_t)backbuf + PV_OFFSET);
memset(backbuf, 0, LCD_DRV_FB_SZ);
rt_hw_cpu_dcache_clean(lcd_drv->back_buf_info.buff, LCD_DRV_FB_SZ);
}
return RT_EOK;
out:
if (framebuffer)
{
#ifdef RT_USING_SMART
rt_free_align(framebuffer);
#else
rt_free(framebuffer);
#endif
}
if (frontbuf)
{
#ifdef RT_USING_SMART
rt_free_align(frontbuf);
#else
rt_free(frontbuf);
#endif
}
if (backbuf)
{
#ifdef RT_USING_SMART
rt_free_align(backbuf);
#else
rt_free(backbuf);
#endif
}
return -RT_ERROR;
}
static int _lcd_layer_init(lcd_device_t lcd_drv)
{
int format;
int ret;
unsigned long arg[6] = {0};
format = _lcd_format_get(lcd_drv->lcd_info.pixel_format);
if (format < 0)
{
rt_kprintf("lcd init faile pixel_format:%d\n", lcd_drv->lcd_info.pixel_format);
return -RT_ERROR;
}
// config layer info
memset(&layer_cfg, 0, sizeof(layer_cfg));
layer_cfg.info.b_trd_out = 0;
layer_cfg.channel = de_feat_get_num_vi_chns(lcd_drv->use_screen); // skip vi channel
layer_cfg.layer_id = 0;
layer_cfg.info.fb.format = format;
layer_cfg.info.fb.crop.x = 0;
layer_cfg.info.fb.crop.y = 0;
layer_cfg.info.fb.crop.width = lcd_drv->lcd_info.width;
layer_cfg.info.fb.crop.height = lcd_drv->lcd_info.height;
layer_cfg.info.fb.crop.width = layer_cfg.info.fb.crop.width << 32;
layer_cfg.info.fb.crop.height = layer_cfg.info.fb.crop.height << 32;
layer_cfg.info.fb.align[0] = 4;
layer_cfg.info.mode = 0; // LAYER_MODE_BUFFER
layer_cfg.info.alpha_mode = 1;
layer_cfg.info.alpha_value = 255;
layer_cfg.info.zorder = 0;
layer_cfg.info.screen_win.x = 0;
layer_cfg.info.screen_win.y = 0;
layer_cfg.info.screen_win.width = lcd_drv->lcd_info.width;
layer_cfg.info.screen_win.height = lcd_drv->lcd_info.height;
layer_cfg.info.fb.size[0].width = lcd_drv->lcd_info.width;
layer_cfg.info.fb.size[0].height = lcd_drv->lcd_info.height;
layer_cfg.info.fb.size[1].width = lcd_drv->lcd_info.width;
layer_cfg.info.fb.size[1].height = lcd_drv->lcd_info.height;
layer_cfg.info.fb.size[2].width = lcd_drv->lcd_info.width;
layer_cfg.info.fb.size[2].height = lcd_drv->lcd_info.height;
layer_cfg.info.fb.addr[0] = (size_t)lcd_drv->front_buf_info.buff_phy;
/* INTERLEAVED */
layer_cfg.info.fb.addr[0] = (unsigned long long)(layer_cfg.info.fb.addr[0] + lcd_drv->lcd_info.width * lcd_drv->lcd_info.height / 3 * 0);
layer_cfg.info.fb.addr[1] = (unsigned long long)(layer_cfg.info.fb.addr[0] + lcd_drv->lcd_info.width * lcd_drv->lcd_info.height / 3 * 1);
layer_cfg.info.fb.addr[2] = (unsigned long long)(layer_cfg.info.fb.addr[0] + lcd_drv->lcd_info.width * lcd_drv->lcd_info.height / 3 * 2);
layer_cfg.info.fb.trd_right_addr[0] = (unsigned int)(layer_cfg.info.fb.addr[0] + lcd_drv->lcd_info.width * lcd_drv->lcd_info.height * 3 / 2);
layer_cfg.info.fb.trd_right_addr[1] = (unsigned int)(layer_cfg.info.fb.trd_right_addr[0] + lcd_drv->lcd_info.width * lcd_drv->lcd_info.height);
layer_cfg.info.fb.trd_right_addr[2] = (unsigned int)(layer_cfg.info.fb.trd_right_addr[0] + lcd_drv->lcd_info.width * lcd_drv->lcd_info.height * 3 / 2);
layer_cfg.enable = 1;
arg[0] = lcd_drv->use_screen;
arg[1] = (unsigned long)&layer_cfg;
arg[2] = 1;
arg[3] = 0;
ret = disp_ioctl(DISP_LAYER_SET_CONFIG, (void *)arg);
if (0 != ret)
{
rt_kprintf("fail to set layer cfg %d\n", ret);
return -RT_ERROR;
}
arg[0] = lcd_drv->use_screen;
arg[1] = 1; // enable
arg[2] = 0;
ret = disp_ioctl(DISP_VSYNC_EVENT_EN, (void *)arg);
if (0 != ret)
{
rt_kprintf("fail to set vsync enable %d\n", ret);
return -RT_ERROR;
}
return RT_EOK;
}
/* Add the first layer, then enable the interrupt */
static rt_err_t rt_lcd_init(rt_device_t dev)
{
lcd_device_t lcd_drv = (lcd_device_t)dev;
RT_ASSERT(lcd_drv != RT_NULL);
static int lcd_init = 0;
if (lcd_init)
{
return RT_EOK;
}
lcd_init = 1;
_panel = load_lcd_config_from_xml();
lcd_drv->panel = _panel;
if (disp_probe() != 0)
{
rt_kprintf("lcd disp probe failure\n");
return -RT_ERROR;
}
lcd_gpio_config();
if (_lcd_drv_init(lcd_drv) != RT_EOK)
{
rt_kprintf("lcd drv init failure\n");
return -RT_ERROR;
}
if (_lcd_layer_init(lcd_drv) != RT_EOK)
{
rt_kprintf("disp layer init failure\n");
return -RT_ERROR;
}
return RT_EOK;
}
void turn_on_lcd_backlight(void)
{
if (_panel->bl_pin >= 0)
{
hal_gpio_set_direction(_panel->bl_pin, GPIO_DIRECTION_OUTPUT); // bl_pin
hal_gpio_set_driving_level(_panel->bl_pin, 3);
hal_gpio_set_data(_panel->bl_pin, 1);
}
if (_panel->pwr_pin >= 0)
{
hal_gpio_set_direction(_panel->pwr_pin, GPIO_DIRECTION_OUTPUT); // pwr_pin
hal_gpio_set_driving_level(_panel->pwr_pin, 3);
hal_gpio_set_data(_panel->pwr_pin, 1);
}
if (_panel->bl_mode == 0)
{
hal_gpio_set_direction(_panel->bl_gpio_pin, GPIO_DIRECTION_OUTPUT);
hal_gpio_set_driving_level(_panel->bl_gpio_pin, 3);
hal_gpio_set_data(_panel->bl_gpio_pin, 1);
}
else
{
struct rt_device_pwm *pwm_dev;
pwm_dev = (struct rt_device_pwm *)rt_device_find(_panel->bl_pwm_name);
if (pwm_dev == RT_NULL)
{
rt_kprintf("%s open fail\n", _panel->bl_pwm_name);
return;
}
rt_pwm_set(pwm_dev, LCD_PWM_DEV_CHANNEL, 1000000000 / _panel->bl_pwm_hz, lcd_bn * (10000000 / _panel->bl_pwm_hz));
rt_pwm_enable(pwm_dev, LCD_PWM_DEV_CHANNEL);
}
lcd_status = 1;
}
void turn_down_lcd_backlight(void)
{
if (_panel->bl_pin >= 0)
{
hal_gpio_set_direction(_panel->bl_pin, GPIO_DIRECTION_OUTPUT); // bl_pin
hal_gpio_set_driving_level(_panel->bl_pin, 3);
hal_gpio_set_data(_panel->bl_pin, 0);
}
if (_panel->pwr_pin >= 0)
{
hal_gpio_set_direction(_panel->pwr_pin, GPIO_DIRECTION_OUTPUT); // pwr_pin
hal_gpio_set_driving_level(_panel->pwr_pin, 3);
hal_gpio_set_data(_panel->pwr_pin, 0);
}
if (_panel->bl_mode == 0)
{
hal_gpio_set_direction(_panel->bl_gpio_pin, GPIO_DIRECTION_OUTPUT);
hal_gpio_set_driving_level(_panel->bl_gpio_pin, 3);
hal_gpio_set_data(_panel->bl_gpio_pin, 0);
}
else
{
struct rt_device_pwm *pwm_dev;
pwm_dev = (struct rt_device_pwm *)rt_device_find(_panel->bl_pwm_name);
if (pwm_dev == RT_NULL)
{
rt_kprintf("%s open fail\n", _panel->bl_pwm_name);
return;
}
rt_pwm_set(pwm_dev, LCD_PWM_DEV_CHANNEL, 1000000000 / _panel->bl_pwm_hz, 0 * (10000000 / _panel->bl_pwm_hz));
rt_pwm_enable(pwm_dev, LCD_PWM_DEV_CHANNEL);
}
lcd_status = 0;
return;
}
void set_lcd_backlight(rt_uint8_t value)
{
struct rt_device_pwm *pwm_dev;
pwm_dev = (struct rt_device_pwm *)rt_device_find(_panel->bl_pwm_name);
if (pwm_dev == RT_NULL)
{
rt_kprintf("%s open fail\n", _panel->bl_pwm_name);
return;
}
rt_pwm_set(pwm_dev, LCD_PWM_DEV_CHANNEL, 1000000000 / _panel->bl_pwm_hz, value * (10000000 / _panel->bl_pwm_hz));
rt_pwm_enable(pwm_dev, LCD_PWM_DEV_CHANNEL);
}
rt_uint8_t get_lcd_backlight(void)
{
int result = 0;
struct rt_device_pwm *pwm_dev;
struct rt_pwm_configuration cfg = {0};
pwm_dev = (struct rt_device_pwm *)rt_device_find(_panel->bl_pwm_name);
cfg.channel = LCD_PWM_DEV_CHANNEL;
rt_pwm_get(pwm_dev, LCD_PWM_DEV_CHANNEL);
return cfg.pulse / (10000000 / _panel->bl_pwm_hz);
}
static rt_err_t rt_lcd_control(rt_device_t dev, int cmd, void *args)
{
struct lcd_device *lcd_drv = (struct lcd_device *)dev;
switch (cmd)
{
case RTGRAPHIC_CTRL_RECT_UPDATE:
{
unsigned long arg[6] = {0};
int ret;
// clean event.
rt_event_recv(&lcd_drv->lcd_evt, LCD_EVT_VSYNC, RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_OR, 0, NULL);
// rotate and set refresh_flag
if ((lcd_drv->panel) && (lcd_drv->panel->swap_flag != 0))
{
_framebuffer_rotate_mirror(lcd_drv->framebuffer, lcd_drv->back_buf_info.buff, &lcd_drv->lcd_info, _panel);
rt_hw_cpu_dcache_clean(lcd_drv->back_buf_info.buff, LCD_DRV_FB_SZ);
atomic_store(&lcd_drv->refresh_flag, 2); // lcd_drv->refresh_flag = 2;
}
else
{
atomic_store(&lcd_drv->refresh_flag, 1); // lcd_drv->refresh_flag = 1;
}
// wait irq
rt_err_t result = rt_event_recv(&lcd_drv->lcd_evt, LCD_EVT_VSYNC, RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_OR, RT_TICK_PER_SECOND / 20, NULL);
if (result != RT_EOK)
{
rt_kprintf("RTGRAPHIC_CTRL_RECT_UPDATE wait LCD_EVT_VSYNC:%d\n", result);
}
break;
}
case RTGRAPHIC_CTRL_POWERON:
if (lcd_status == 0)
{
#ifdef WATCH_APP_FWK_USING_SCREEN_MGT
extern void watch_screen_time_update(void);
watch_screen_time_update();
#endif
turn_on_lcd_backlight();
rt_kprintf("lcd driver control power on.\n");
lcd_status = 1;
}
break;
case RTGRAPHIC_CTRL_POWEROFF:
if (lcd_status == 1)
{
lcd_status = 0;
turn_down_lcd_backlight();
rt_kprintf("lcd driver control power off.\n");
}
break;
case RTGRAPHIC_CTRL_SET_BRIGHTNESS:
lcd_bn = *((rt_uint8_t *)args);
// TODO::if can SET_BRIGHTNESS
set_lcd_backlight(lcd_bn);
rt_kprintf("lcd driver control set brightness: %d.\n", lcd_bn);
break;
case RTGRAPHIC_CTRL_GET_BRIGHTNESS:
lcd_bn = get_lcd_backlight();
*((rt_uint8_t *)args) = lcd_bn;
// TODO::if can GET_BRIGHTNESS
rt_kprintf("lcd driver control get brightness: %d.\n", lcd_bn);
break;
case RTGRAPHIC_CTRL_GET_INFO:
memcpy(args, &lcd_drv->lcd_info, sizeof(struct rt_device_graphic_info));
break;
case FBIOGET_FSCREENINFO:
{
struct fb_fix_screeninfo *info = (struct fb_fix_screeninfo *)args;
strncpy(info->id, "lcd", sizeof(info->id));
info->smem_len = LCD_DRV_FB_SZ;
#ifdef RT_USING_SMART
info->smem_start = (size_t)lwp_map_user_phy(lwp_self(), RT_NULL, lcd_drv->framebuffer_phy, info->smem_len, 1);
#else
info->smem_start = (size_t)lcd_drv->framebuffer_phy;
#endif
info->line_length = lcd_drv->lcd_info.width * sizeof(rt_uint32_t);
memset((void *)info->smem_start, 0, info->smem_len);
}
case RTGRAPHIC_CTRL_SET_MODE:
break;
}
return RT_EOK;
}
static rt_err_t fb_open(rt_device_t dev,rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t fb_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t fb_control(rt_device_t dev, int cmd, void *args)
{
switch(cmd) {
case FBIOGET_PIXELINFO:
{
int *fmt = (int *)args;
*fmt = RTGRAPHIC_PIXEL_FORMAT_ARGB888;
break;
}
case FBIOPAN_DISPLAY:
{
struct lcd_device *lcd_drv = g_lcd;
rt_hw_cpu_dcache_clean(lcd_drv->framebuffer, LCD_DRV_FB_SZ);
rt_lcd_control((rt_device_t)g_lcd, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
break;
}
case FBIOGET_FSCREENINFO:
{
rt_lcd_control((rt_device_t)g_lcd,FBIOGET_FSCREENINFO,args);
break;
}
case FBIOGET_VSCREENINFO:
{
struct lcd_device *lcd_drv = g_lcd;
struct fb_var_screeninfo *info = (struct fb_var_screeninfo *)args;
info->xres = lcd_drv->lcd_info.width;
info->yres = lcd_drv->lcd_info.height;
break;
}
case RT_FIOMMAP2:
{
struct dfs_mmap2_args *mmap2 = (struct dfs_mmap2_args *)args;
if (mmap2)
{
mmap2->ret = lwp_map_user_phy(lwp_self(),RT_NULL,g_lcd->framebuffer,mmap2->length,1);
}
else
{
return -EIO;
}
break;
}
default:
break;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops fb_ops =
{
RT_NULL,
fb_open,
fb_close,
RT_NULL,
RT_NULL,
fb_control
};
#endif
/* register framebuffer device */
static int fb_init(rt_device_t fb)
{
static rt_bool_t fb_init_ok = RT_FALSE;
if (fb_init_ok)
{
return 0;
}
RT_ASSERT(!rt_device_find("fb0"));
fb->type = RT_Device_Class_Miscellaneous;
#ifdef RT_USING_DEVICE_OPS
fb->ops = &fb_ops;
#else
fb->init = RT_NULL;
fb->open = fb_open;
fb->close = fb_close;
fb->read = RT_NULL;
fb->write = RT_NULL;
fb->control = fb_control;
fb->user_data = RT_NULL;
#endif
rt_device_register(fb,"fb0",RT_DEVICE_FLAG_RDWR);
fb_init_ok = RT_TRUE;
return RT_EOK;
}
/* set up the 'lcd_device' and register it */
int rt_hw_lcd_init(void)
{
struct lcd_device *lcd_drv = &_lcd_device;
g_lcd = lcd_drv;
/* the content of tcon control registers can be loaded from a xml file ? */
// _panel = load_config_from_xml();
memset(lcd_drv, 0, sizeof(struct lcd_device));
lcd_drv->use_screen = DEFAULT_SCREEN;
/* initialize device structure, the type of 'lcd' is 'rt_device' */
lcd_drv->lcd.type = RT_Device_Class_Graphic;
lcd_drv->lcd.init = rt_lcd_init;
lcd_drv->lcd.open = RT_NULL;
lcd_drv->lcd.close = RT_NULL;
lcd_drv->lcd.control = rt_lcd_control;
lcd_drv->lcd.user_data = (void *)&lcd_drv->lcd_info;
/* register lcd device to RT-Thread */
rt_device_register(&lcd_drv->lcd, "lcd", RT_DEVICE_FLAG_RDWR);
rt_lcd_init((rt_device_t)lcd_drv);
if (fb_init(&(lcd_drv->fb)) != RT_EOK)
{
rt_kprintf("fb device init failure\n");
return -RT_ERROR;
}
return RT_EOK;
}
// INIT_DEVICE_EXPORT(rt_hw_lcd_init);
static int lcd_draw_point(int args, char *argv[])
{
struct lcd_device *lcd_drv = g_lcd;
int x = 0;
int y = 0;
int i, k;
rt_kprintf("lcd_draw_point\n");
x = atoi(argv[1]);
y = atoi(argv[2]);
if (x >= lcd_drv->lcd_info.width)
x = lcd_drv->lcd_info.width - 1;
if (y >= lcd_drv->lcd_info.height)
y = lcd_drv->lcd_info.height - 1;
if (x < 0)
x = 0;
if (y < 0)
y = 0;
rt_kprintf("Darw point is x:%d,y:%d\n", x, y);
// memset(lcd->framebuffer, 0, sizeof(rt_uint32_t) * lcd_drv->lcd_info.width * lcd_drv->lcd_info.height);
for (i = y - 100; i < y + 100; i++)
{
if (i < 0)
continue;
if (i >= lcd_drv->lcd_info.height)
break;
for (k = x - 100; k < x + 100; k++)
{
if (k < 0)
continue;
if (k >= lcd_drv->lcd_info.width)
break;
*((uint32_t *)lcd_drv->framebuffer + lcd_drv->lcd_info.width * i + k) = 0xff00ff00;
}
}
*((uint32_t *)lcd_drv->framebuffer + lcd_drv->lcd_info.width * y + x) = 0xffff0000;
// *((uint32_t *)lcd->framebuffer + lcd_drv->lcd_info.width * y + x + 2) = 0xff00ff00;
rt_hw_cpu_dcache_clean(lcd_drv->framebuffer, LCD_DRV_FB_SZ);
rt_lcd_control((rt_device_t)g_lcd, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
return 0;
}
MSH_CMD_EXPORT(lcd_draw_point, draw a point on lcd);
void lcd_pwm_test(int argc, char **argv)
{
set_lcd_backlight(atoi(argv[1]));
}
MSH_CMD_EXPORT(lcd_pwm_test, set pwm);
#endif