app: open("/dev/fb0", ...) 主设备号: 29, 次设备号: 0
--------------------------------------------------------------
kernel:
fb_open // fbmem.c
struct fb_info *info;
info = get_fb_info(fbidx);
if (info->fbops->fb_open)
{
res = info->fbops->fb_open(info,1); // 硬件相关的驱动
if (res)
module_put(info->fbops->owner);
}
app: ioctl(fd, FBIOGET_VSCREENINFO, &fb_info->var);
-------------------------------------------------------------------------
kernel:
fb_ioctl // fbmem.c
struct fb_info *info = file_fb_info(file);
do_fb_ioctl(info, cmd, arg);
var = info->var; // 硬件相关的驱动设置的
ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
app: ioctl(fd, FBIOGET_FSCREENINFO, &fb_info->fix);
-------------------------------------------------------------------------
kernel:
fb_ioctl // fbmem.c
struct fb_info *info = file_fb_info(file);
do_fb_ioctl(info, cmd, arg);
fix = info->fix; // 硬件相关的驱动设置的
ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
app:void *ptr = mmap(0,
fb_info->var.yres_virtual * fb_info->fix.line_length,
PROT_WRITE | PROT_READ,
MAP_SHARED, fd, 0);
-------------------------------------------------------------------------
kernel:
fb_mmap // fbmem.c
struct fb_info *info = file_fb_info(file);
start = info->fix.smem_start;
len = info->fix.smem_len;
return vm_iomap_memory(vma, start, len);
刚拿到手一款新的芯片进入目录 drivers/video/fbdev/ 目录下查看有哪些.o文件,就可以得知有没有LCD驱动程序。
LCD驱动程序核心就是:
我们只需要针对IMX6ULL的编写硬件相关的代码,涉及3部分:
有两种方法:
设备树arch/arm/boot/dts/100ask_imx6ull-14x14.dts
中:
IMX6ULL的LCD控制器涉及2个时钟:
代码里直接使用时钟子系统的代码。
在设备树里指定频率:
文件:arch/arm/boot/dts/100ask_imx6ull-14x14.dts
代码:clock-frequency
display-timings {
native-mode = <&timing0>;
timing0: timing0_1024x768 {
clock-frequency = <50000000>;
从设备树获得dot clock,存入display_timing
文件:drivers\video\of_display_timing.c
代码:
ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock);
使用display_timing来设置videomode
文件:drivers\video\videomode.c
代码:
void videomode_from_timing(const struct display_timing *dt,struct videomode *vm)
{
vm->pixelclock = dt->pixelclock.typ;
vm->hactive = dt->hactive.typ;
vm->hfront_porch = dt->hfront_porch.typ;
vm->hback_porch = dt->hback_porch.typ;
vm->hsync_len = dt->hsync_len.typ;
vm->vactive = dt->vactive.typ;
vm->vfront_porch = dt->vfront_porch.typ;
vm->vback_porch = dt->vback_porch.typ;
vm->vsync_len = dt->vsync_len.typ;
vm->flags = dt->flags;
}
根据videomode的值,使用时钟子系统的函数设置时钟:
以设置分辨率为例。
在设备树里指定频率:
文件:arch/arm/boot/dts/100ask_imx6ull-14x14.dts
代码:clock-frequency
display-timings {
native-mode = <&timing0>;
timing0: timing0_1024x768 {
hactive = <1024>;
vactive = <600>;
从设备树获得分辨率,存入display_timing
文件:drivers\video\of_display_timing.c
代码:
ret |= parse_timing_property(np, "hactive", &dt->hactive);
ret |= parse_timing_property(np, "vactive", &dt->vactive);
使用display_timing来设置videomode
文件:drivers\video\videomode.c
代码:
void videomode_from_timing(const struct display_timing *dt,struct videomode *vm)
{
vm->hactive = dt->hactive.typ;
vm->vactive = dt->vactive.typ;
根据videomode的值,设置fb_videomode
文件:drivers\video\fbdev\core\fbmon.c
代码:
int fb_videomode_from_videomode(const struct videomode *vm,struct fb_videomode *fbmode)
{
unsigned int htotal, vtotal;
fbmode->xres = vm->hactive;
fbmode->yres = vm->vactive;
根据fb_videomode的值,设置fb_info中的var:
文件:drivers\video\fbdev\core\modedb.c
代码:
void fb_videomode_to_var(struct fb_var_screeninfo *var,const struct fb_videomode *mode)
{
var->xres = mode->xres;
var->yres = mode->yres;
根据var的分辨率,设置寄存器
文件:drivers\video\fbdev\mxsfb.c
代码:
writel(TRANSFER_COUNT_SET_VCOUNT(fb_info->var.yres) |TRANSFER_COUNT_SET_HCOUNT(fb_info->var.xres),
host->base + host->devdata->transfer_count);