2/18/2011

LCD Driver (1)

因為打英文很累...打到後面就放棄改打中文= =

第一章理解的都只是初步,未涉及到相關LCD的知識

但為了怕一些細節容易忘記...似懂非懂的

還是記錄下來...

後面的陸續補上,看自己讀code的時間要花多少了 XD

如有錯誤,也請路過的鄉民指點,感激不盡^^

(恩...英文文法有錯的話看看就好,別太在意...意思到就好 !)

==============================

Written by Dicky

SAARB board init code the path is arch/arm/mach-pxa/saarb.c

First,We check the saarb.c code,because this is configure LCD Controller source,can be find pxa950fb_mach_info struct,such as :


static struct pxa950fb_mach_info saarb_lcd_info __initdata = {
.id = "Base",
.modes = video_modes,
.num_modes = ARRAY_SIZE(video_modes),
.pix_fmt_in = PIX_FMTIN_RGB_16,
.pix_fmt_out = PIX_FMTOUT_24_RGB888,
.panel_type = LCD_Controller_Active,
/* .mixer0 = LCD_M2PARALELL_CONVERTER,*/
.mixer0 = LCD_MIXER_DISABLE,
.mixer1 = LCD_M2DSI1,
.active = 1,
.pxa950fb_lcd_power = espon_lcd_power,
.pxa950fb_dsi_reset = tavorpv2_saarb_dsi_reset,
.invert_pixclock = 1,
};


And also find video modes struct,that is important :

static struct fb_videomode video_modes[] = {
[0] = {
.pixclock = 41701,
.refresh = 60,
.xres = 480,
.yres = 800,
.hsync_len = 19,
.left_margin = 40,
.right_margin = 59,
.vsync_len = 9,
.upper_margin = 4,
.lower_margin = 9,
.sync = 0,
},
};


1. How to register platorm device to kernel

Before discuss that,first look at how to initialize & register LCD driver for saarb board :

static void __init saarb_init(void)
{
.......
#if defined(CONFIG_FB_PXA950)
pxa3xx_mfp_config(ARRAY_AND_SIZE(lcd_mfp_cfg));
saarb_init_lcd();
#endif
........
}


saarb_init_lcd function :

static void __init saarb_init_lcd(void)
{
set_pxa950_fb_info(&saarb_lcd_info);
set_pxa950_fb_ovly_info(&saarb_lcd_ovly_info);
}


To call it :

void __init set_pxa950_fb_info(struct pxa950fb_mach_info *info)
{
pxa_register_device(&pxa950_device_fb, info);
}


See ? We can be find the platform_device struct :

struct platform_device pxa950_device_fb = {
.name = "pxa950-fb",
.id = -1,
.dev = {
.dma_mask = &fb_dma_mask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(pxa950fb_resources),
.resource = pxa950fb_resources,
};


What is Platform ? That like is character,block,net device,for register to kernel,need write data into the platform_device & platform_driver.

Normal define in the arch/arm/mach-xxx/devices.c

There is another important member of the platform_device :

.resource = pxa950fb_resources,


The mean is description the hardware resource occupied by device(as memory address,IRQ number etc,). :

static struct resource pxa950fb_resources[] = {
[0] = {
.start = 0x44100000,
.end = 0x4410ffff,
.flags= IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCDGLOBAL,
.end = IRQ_LCDGLOBAL,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start= IRQ_LCDPARALLEL,
.end= IRQ_LCDPARALLEL,
.flags= IORESOURCE_IRQ,
},
[3] = {
.start= IRQ_DSI0,
.end = IRQ_DSI0,
.flags = IORESOURCE_IRQ,
}
[4] = {
.start = IRQ_DSI1,
.end = IRQ_DSI1,
.flags = IORESOURCE_IRQ,
},
};


Lastly add device to kernel of complete by call function platform_device register :

void __init set_pxa950_fb_info(struct pxa950fb_mach_info *info)
{
pxa_register_device(&pxa950_device_fb, info);
}

void __init pxa_register_device(struct platform_device *dev, void *data)
{
int ret;

dev->dev.platform_data = data;
ret = platform_device_register(dev);
if (ret)
&dev_err(&dev->dev, "unable to register device: %d\n", ret);
}


As you see,the pxa950fb_mach_info has link to member of dev.platform_data.

What is pxa950fb_mach_info ?
That's main board the LCD controlle register infomation sturct.
Also see the point variable(*dev) will be register to kernel. ( That struct generate by pxa950_device_fb)

2. How to register platform driver to kernel

到目前為止,我們己經完成LCD裝置所需的硬體資源和配置

現在可以為它寫一支驅動程式來驅動它

一般來說,所有Driver的程式碼都會在kernel/driver的路徑下,如MMC Driver是kernel/driver/mmc

所以LCD的driver就在kernel/driver/video底下了

各家不同平台的驅動都會放在這,Marvell平台的LCD驅動就叫pxa950fb.c

一樣,直接先來看它如何做初始化驅動的 :

static int __devinit pxa950fb_gfx_init(void)
{
#ifdef CONFIG_PXA3xx_DVFM
dvfm_register("pxa950-fb", &dvfm_dev_idx);
#endif
return platform_driver_register(&pxa950fb_gfx_driver);
}


DVFM先撇開不談,後續再來討論,因為它只是一種視訊格式而己,

從init function可以發現一個很有趣的結構 :

static struct platform_driver pxa950fb_gfx_driver = {
.driver = {
.name = "pxa950-fb",
.owner = THIS_MODULE,
},
.probe = pxa950fb_gfx_probe,
};


這個結構相當重要,前面有提到,一個Platform有兩個最重要的資料結構,分別是platform_device和platform_driver

這兩個結構都可以在kernel/include/linux/platform_deivce.h找到

在這此結構當中,有兩個成員是必填的,分別是Name和Probe

沒有Name值,Kernel不知道如何把這支驅動對應到哪個裝置

沒有probe functuion pointer,Kernel不知道如何初始化驅動程式..

所以接下來第二個進入點就是probe function了,不管什麼驅動,probe必存在 !

這個LCD driver在probe function裡面做了很多事....一步一步來探討,先列出一部份:

struct pxa950fb_mach_info *mi;
struct fb_info *info = 0;
struct pxa950fb_info *fbi = 0;
struct resource *res;
struct clk *clk_lcd, *clk_dsi0, *clk_dsi1, *clk_axi;
int irq_ctl, irq_conv[2], ret;
int i;
u32 converter;

mi = pdev->dev.platform_data;
if (mi == NULL) {
dev_err(&pdev->dev, "no platform data defined\n");
return -EINVAL;
}


一開始就把pdev->gt;dev.platform_data的Address指向mi,而mi又指向pxa950fb_mach_info.....

也就是說,pxa950fb_mach_info的位址(值)等同於pdev->gt;dev.platform_data...

重點來了 ! pxa950fb_mach_info是什麼呢 !? 前面有提到,它是LCD裝置控制器的結構

可是它幹嘛把pdev->gt;dev.platform_data指向LCD裝置控制器呢 ?

因為在註冊platform_device的時候,就己經把這些LCD控制器的定義都註冊進去了(翻前面的程式碼)

現在驅動需要用到,當然要把它給指過來 ! 不然驅動怎麼知道device到底定義哪些東西,又該如何使用

所以這一步就把下到上的資料結構串起來,驅動程式才可以針對裝置去做其它操作了 !

然後就能看到後面開始去做什麼開啟Clock啦....註冊中斷啦....打開什麼一堆東西啦等等..

2 comments:

  1. 我咧 少林足球到底看到了沒?

    上面一堆都是廢話,真的會改到的就這個地方,看懂就好
    static struct fb_videomode video_modes[] = {
    [0] = {
    .pixclock = 41701,
    .refresh = 60,
    .xres = 480, <- LCD的寬(配合你用的LCD修改)
    .yres = 800, <- LCD的高(配合你用的LCD修改)
    .hsync_len = 19, <- 根據你LCD的DATASHEET去改
    .left_margin = 40, <- 這邊不一定,自己去試最佳值
    .right_margin = 59, <- 這邊不一定,自己去試最佳值
    .vsync_len = 9, <- 根據你LCD的DATASHEET去改
    .upper_margin = 4, <- 這邊不一定,自己去試最佳值
    .lower_margin = 9, <- 這邊不一定,自己去試最佳值
    .sync = 0,
    },
    };

    它只做了一組LCD參數,一般可以設個好幾組,像320X240,640X480,800X480....你就根據你用的LCD去選擇

    硬體要做的:
    1.先點亮背光,看你亮度能不能調
    2.LCD ENABLE

    如果你用的是LCD CONTROLLER的話,上面這堆全部不用做,把
    DATASHEET讀完就夠了

    ReplyDelete