第一章理解的都只是初步,未涉及到相關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啦....註冊中斷啦....打開什麼一堆東西啦等等..
我咧 少林足球到底看到了沒?
ReplyDelete上面一堆都是廢話,真的會改到的就這個地方,看懂就好
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讀完就夠了
多謝益嘉大的指導:D
ReplyDelete