LCD驅動程序分析_第1頁
LCD驅動程序分析_第2頁
LCD驅動程序分析_第3頁
LCD驅動程序分析_第4頁
LCD驅動程序分析_第5頁
已閱讀5頁,還剩31頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、*/*/* 2007.6.18*在/kernel/include/asm-arm/arch-s3c2410/bitfield.h 文件中:#ifndef _ASSEMBLY_#define UData(Data) (unsigned long) (Data)#else#define UData(Data) (Data)#endif例:UData(5); = 5/* MACRO: Fld*PurposeThe macro Fld encodes a bit field, given its siz( and its shift valuewith respect to bit 0.*NoteA

2、more intuitive way to encode bit fields would ha、 been to use theirmask. However, extracting size and shift value information from a bitfields mask is cumbersome and might break the assembler (255-characterline-size limit).*InputSizeSize of the bit field, in number of bitShftShift value of the bitfi

3、eld with respectto bit 0.*OutputFldEncoded bit field.*/#define Fld(Size, Shft) (Size) 16)例:FSize(0 x20005);#define FShft(Field)(Field)& 0 x0000FFFF)例:FShft(0 x20005);/* MACRO: FInsrt* Purpose* The macro FInsrt inserts a value into a bit fiel by shifting the* former appropriately.* Input*ValueBit-fie

4、ld value.*FieldEncoded bit field (using the macro Fld)*Output*FInsrtBit-field value positionedappropriately.*/#define FInsrt(Value, Field) (UData (Value) FShft (Field)例:FInsrt(0 x3, 0 x20005); = 0 x3 fb.fix.smem_len = fbi-max_xres * fbi-max_yres * fbi-max_bpp / 8;fbi-map_size = PAGE_ALIGN(fbi-fb.fix

5、.smem_len + PAGE_SIZE);fbi-map_cpu = consistent_alloc(GFP_KERNEL,fbi-map_size,&fbi-map_dma);if (fbi-map_cpu)(fbi-screen_cpu = fbi-map_cpu + PAGE_SIZE;fbi-screen_dma = fbi-map_dma + PAGE_SIZE;fbi-fb.fix.smem_start = fbi-screen_dma;在/kernel/include/asm-arm/proc-armo/page.h 文件中:/* PAGE_SHIFT determines

6、 the page size. This is configurable. */#if defined(CONFIG_PAGESIZE_16)#define PAGE_SHIFT 14 /* 16K */#else /* default */#define PAGE_SHIFT 15 /* 32K */#endif在/kernel/include/asm-arm/page.h 文件中:#define PAGE_SIZE(1UL fb.fix.smem_len = 240*320*16/8 = 0 x25800 =150K(9.375 個 PAGE)PAGE_SHIFT = 14PAGE_SIZ

7、E = 1map_size = PAGE_ALIGN(fbi-fb.fix.smem_len +PAGE_SIZE) = PAGE_ALIGN(150K + 16K) = PAGE_ALIGN(166K)=(166K + 16K - 1) & 0 xFFFFC000 = 0 x2D7FF & 0 xFFFFC000 : 0 x2C000 =176Kconsistent_alloc(GFP_KERNEL, 176K, &fbi-map_dma);最后得到:framebuffer (物理地址) TOC o 1-5 h z I1I.I11map_dmaI16K|分配了 |1screen_dma =f

8、bi-fb.fix.smem_start176K |共 11 個 | 160K = 10個 PAGEPAGE |160K |可以容下所需的150K視頻緩沖區大小(16K) |11|. |1*/* 2007.6.19*/*在/kernel/drivers/video/s3c2410fb.c 文件中的 s3c2410fb_activate_var 函數中:unsigned long VideoPhysicalTemp = fbi-screen_dma;這里已經得到了 framebuffer在內存中的起始地址為 VideoPhysicalTemp,地址數據位為 A30:0。 I 4 n *I I 4

9、 c 2. cr 4 mi j I rnew_regs.lcdcon1 - fbi-reg.lcdcon1 & LCD1_ENVID;new_regs.lcdcon2 - (fbi-reg.lcdcon2 & LCD2_LINEVAL_MSK)| LCD2_LINEVAL(var-yres - 1);/* TFT LCD only ! */new_regs.lcdcon3 - (fbi-reg.lcdcon3 & LCD3_HOZVAL_MSK)| LCD3_HOZVAL(var-xres - 1);new_regs.lcdcon4 - fbi-reg.lcdcon4;new_regs.lcd

10、con5 - fbi-reg.lcdcon5;LCDCON1首先需要禁止視頻輸出才能進行寄存器的設置,然后 對LCDCON2,LCDCON3進行設置,主要是增加LINEVAL和HOZVAL這 兩個顯示尺寸的參數。LCDCON4,LCDCON5按原來配置設置。LCDBANK29:21為系統內存中視頻緩沖區在系統存儲器內的段地址的A30:22LCDBASEU20:0 為 LCD framebuffer 的起始地址的 A21:1LCDBASEL20:0 為 LCD framebuffer 的結束地址的 A21:1OFFSIZE21:11為某一行的第一個半字與前一行最后一個半字 之間的距離(單位:半字

11、數,即2個字節)PAGEWIDTH10:0為顯示存儲區的可見幀寬度(單位:半字數, 即2個字節)new_regs.lcdsaddr1 =LCDADDR_BANK(unsigned long)VideoPhysicalTemp 22)| LCDADDR_BASEU(unsigned long)VideoPhysicalTemp 1);new_regs.lcdsaddr2 = LCDADDR_BASEL(unsigned long)VideoPhysicalTemp + (var-xres * 2 * (varyres) 1);這里LCDADDR_BASEL的計算方法為用framebuffer在內

12、存 中的起始地址VideoPhysicalTemp,加上framebuffer的大小(LCD 屏的寬度* LCD屏的高度*每像素的位數/每字節的位數),得到 framebuffer在內存中的結束地址,然后右移1位。new_regs.lcdsaddr3 = LCDADDR_OFFSET(0) |(LCDADDR_PAGE(var-xres);這里PAGEWIDTH的計算方法為:LCD屏的寬度*每像素的位數 /16位(半字)。問題:以上這些操作是否已經對DMA控制器進行了設置?我認為這里將framebuffer在內存中的起始地址為 VideoPhysicalTemp 變換后載入 LCDADDR1,

13、LCDADDR2,LCDADDR3 中 就已經完成了對LCDCDMA控制器的源數據的基地址設置,當打開 LCDCON1 |= LCD1_ENVID;后就可以由LCDCDMA控制器自動從 framebuffer中傳數據到LCD屏幕了。在/kernel/drivers/video/s3c2410fb.c 文件中的 xxx_stn_info 結構體初始化中:lcdcon5 : LCD5_FRM565 | LCD5_INVVLINE | LCD5_INVVFRAME | LCD5_HWSWP | LCD5_PWREN,INVVCLK, INVLINE, INVFRAME, INVVD :通過前面的 時

14、序圖,我們知道,CPU的LCD控制器輸出的時序默認是正脈沖,而 LCD 需要 VSYNC(VFRAME)、VLINE(HSYNC)均為負脈沖,因此 INVLINE 和INVFRAME必須設為“1 ”,即選擇反相輸出。INVVDENINVPWREN, INVLEND的功能同前面的類似。PWREN為LCD電源使能控制。在CPU LCD控制器的輸出信號 中,有一個電源使能管腳LCD_PWREN,用來做為LCD屏電源的開關信 號。其中LCD5_HWSWP 一項,設置了 LCD從內存中顯示數據時, 經過了半字交換。16BPP Display(BSWP = 0, HWSWP = 0)D31:16D15:0

15、 TOC o 1-5 h z 000HP1P2004HP3P4008HP5P6(BSWP = 0, HWSWP = 1)D31:16 D15:0000H P2P1004H P4P3008H P6 P5像素顯示順序如下:P1 P2 P3 P4 P5 .例如:內存地址的數據為:0 x11223344 (32位)系統存儲器采用Big-Endian (大端模式)存儲格式,地址數 據格式如下:D31:16 D15:00001020300H0 x11 0 x22 0 x33 0 x44(0 x1122)(0 x3344)04H .08H .則首先顯示0 x3344的數據到第一個像素,然后再顯示0 x112

16、2到 第二個像素。系統存儲器采用Little-Endian(小端模式)存儲格式,地 址數據格式如下:D31:16 D15:00302010000H0 x11 0 x22 0 x33 0 x44(0 x1122)(0 x3344)04H .08H .則首先顯示0 x3344的數據到第一個像素,然后再顯示0 x1122到 第二個像素。*/*/* 2007.6.20*/*在/kernel/arch/arm/mm/consistent.c 文件中的consistent_alloc 函數中:void *consistent_alloc(int gfp, size_t size, dma_addr_t*d

17、ma_handle)(virt = page_address(page);*dma_handle = virt_to_bus(virt);ret = _ioremap(virt_to_phys(virt), size, 0);這里調用該函數來分配一段內存空間有兩個返回值,一個返 回值返回給了 ret指針,另一個返回值返回給了 dma_handle指針。 virt_to_bus和virt_to_phys函數的調用可以參考下面的分析。經 過分析這兩個函數作用一樣,都是將virt這個虛擬地址轉換為物理 地址。所以返回給指針dma_handle的是所分配內存的起始地址(物 理地址)。_ioremap函

18、數的調用也可以參考下面的說明,該函數也 返回所分配內存的起始地址(虛擬地址),不過是經過I/O內存映射 的,把物理地址轉換為了虛擬地址。這樣一來就很清楚了,返回的framebuffer的物理地址給了 指針 dma_handle,也就是 fbi-map_dma,到 fbi-screen_dma,再 到 fbi-fb.fix.smem_start,最后到了指針 VideoPhysicalTemp,這 樣寫入到LCDADDR1,LCDADDR2寄存器中的framebuffer的地址其實 都是物理地址。而返回的framebuffer的虛擬地址給了指針ret,也就是 fbi-map_cpu,至lj fb

19、i-screen_cpu,最后到了 display-screen_base(見/kernel/drivers/video/s3c2410fb.c 文 件中的 s3c2410fb_set_var 函數)。在/kernel/drivers/video/fbmem.c 文件中:/*register_framebuffer - registers a frame buffer devicfb_info: frame buffer info structure*Registers a frame buffer device fb_info.*Returns negative errno on error

20、, or zero for success.*/intregister_framebuffer(struct fb_info *fb_info)/*unregister_framebuffer - releases a frame buffer devicefb_info: frame buffer info structure*Unregisters a frame buffer device fb_info.* Returns negative errno on error, or zero for success.*/intunregister_framebuffer(struct fb

21、_info *fb_info)static intfb_open(struct inode *inode, struct file *file)static intfb_release(struct inode *inode, struct file *file)static ssize_tfb_read(struct file *file, char *buf, size_t count, loff_t *ppos)static ssize_tfb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)sta

22、tic intfb_ioctl(struct inode *inode, struct file *file, unsignedint cmd,unsigned long arg)static intfb_mmap(struct file *file, struct vm_area_struct * vma)在該文件中包含了所有驅動LCD的函數。在fb_read和 fb_write這兩個函數中,都對framebuffer進行了操作。fb_read函數中:char *base_addr;base_addr = info-disp-screen_base;count -= copy_to_user

23、(buf, base_addr+p, count);fb_write函數中:char *base_addr;base_addr = info-disp-screen_base;count -= copy_from_user(base_addr+p, buf, count);所讀寫的framebuffer的基地址就是disp-screen_base,也就 是fbi-screen_cpu所指的framebuffer的虛擬地址。從而得到:framebuffer (虛擬地址) TOC o 1-5 h z |1|.|map_cpuI16K|分配了 |1screen_cpu =display-screen

24、_base176K |共 11 個 | 160K = 10個 PAGEPAGE |160K |可以容下所需的150K視頻緩沖區大小(16K) |11|. |1其中 display-screen_base 結構在/kernel/include/video/fbcon.h 文件中定義。得出結論,在分配framebuffer時一共返回兩個指針,雖然 是同一塊內存空間,但一個返回的是實際的物理地址,另一個返回的 是經過地址轉換的虛擬地址。在設置LCD控制器中framebuffer起 始地址寄存器時,用的是所分配內存的物理地址;而當要對 framebuffer進行讀寫操作時,用的是同一塊內存的物理地址所

25、轉換 后的虛擬地址。由此可以知道,內核在對每個I/O地址進行讀寫操 作時用的都是經過轉換的虛擬地址。在/kernel/include/asm-arm/arch-s3c2410/memory.h 文件中:/*Page offset: 3GB*/#define PAGE_OFFSET (0 xc0000000UL)#define PHYS_OFFSET (0 x30000000UL)/*We take advantage of the fact that physical and virtu address can be thesaem. Thu NUMA code is handling the

26、 large holes that might exist between* all memory banks.*/ #define _virt_to_phys_is_a_macro #define _phys_to_virt_is_a_macro#define_virt_to_phys(x) (x) - PAGE_OFFSET + PHYS_OFFSET)#define_phys_to_virt(x) (x) - PHYS_OFFSET + PAGE_OFFSET)由此可見:起始點地址PHYS_OFFSET TOC o 1-5 h z PAGE_OFFSET |-0 x30000000-|間

27、隔1PHYS_OFFSET (物理地址起始點): |1| |0 xc00000001PAGE_OFFSET (虛擬地址起始點): |1物理地址與虛擬地址的間隔為:PAGE_OFFSET - PHYS_OFFSET。這樣一來,以上對物理地址和虛擬地址之間轉換的宏定義就很好理解 了。虛擬地址轉為物理地址宏:_virt_to_phys(x)=(x) - (PAGE_OFFSET - PHYS_OFFSET) = (x) - PAGE_OFFSET PHYS_OFFSET物理地址轉為虛擬地址宏:_phys_to_virt(x)=(x) + (PAGE_OFFSET - PHYS_OFFSET) = (

28、x) + PAGE_OFFSET PHYS_OFFSET內核虛擬地址和實際物理地址僅僅是相差一個偏移量(PAGE_OFFSET),可以很方便的將其轉化為物理內存地址,同時內核 也提供了 virt_to_phys()函數將內核虛擬空間中的物理影射區地址 轉化為物理地址。/*Virtual view DMA view memory address translationsvirt_to_bus: Used to translate the virtual address to anaddress suitable to be passed to set_dma_addrbus_to_virt: U

29、sed to convert an address for DMA operationsto an address that the kernel can use.*/#define _virt_to_bus_is_a_macro#define _bus_to_virt_is_a_macro#define _virt_to_bus(x) _virt_to_phys(x)#define _bus_to_virt(x) _phys_to_virt(x)這里注意:virt_to_bus(x)就等于_virt_to_phys(x)在/kernel/include/asm-arm/memory.h 文件

30、中:/*These are *only* valid on the kernel direct mapped RA memory.*/static inline unsigned long virt_to_phys(volatile void *x)(return _virt_to_phys(unsigned long)(x);/*Virtual DMA view memory address translationsAgain, these are *only* valid on the kernel direct mapped RAMmemory.*/#define virt_to_bus

31、(x)(_virt_to_bus(unsignedlong)(x)由上面的分析可知:virt_to_bus(x)和 virt_to_phys(volatile void *x)這兩個函數調用的都是 _virt_to_phys(x)即(x) - PAGE_OFFSET + PHYS_OFFSET)。所以 這兩個調用都是將虛擬地址轉換為了物理地址。在/kernel/arch/arm/mm/ioremap.c 文件中:/*Remap an arbitrary physical address space into the kernel virtualaddress space. Needed whe

32、n the kernel wants to access high addressesdirectly.*NOTE! We need to allow nonaligned mappings too: we will obviouslyhave to convert them into an offset in a aligned mapping, but thecaller shouldnt need to know that small detail.*flags are the extra L_PTE_ flags that you wan to specify for thismapp

33、ing. See include/asm-arm/proc-armv/pgtable.h for more information.*/void * _ioremap(unsigned long phys_addr, size_t size, unsigned long flags)ioremap函數的作用是將physical address以及bus address 映射為 kernel 的virtual adrress。ioremap的作用是把I/O內存地址(物理地址)映射到虛擬 地址空間,使用之前需要分配I/O內存區域。但是,ioremap函數 的內部實現并不是簡單的(IO的物理地址)-

34、0 x10000000 +0XE4000000)。所以,得到的虛擬地址可能是不同的。因為linux用的是頁面映射機制,CPU不能按物理地址來訪 問存儲空間,而必須使用虛擬地址,所以必須反向的從物理地址出發 找到一片虛存空間并建立起映射。*/* 2007.6.22/* /*在/kernel/drivers/video/fbmem.c 文件中:static struct file_operations fb_fops = owner: THIS_MODULE,read: fb_read,write: fb_write,ioctl: fb_ioctl,mmap: fb_mmap,open: fb_o

35、pen,release: fb_release,#ifdef HAVE_ARCH_FB_UNMAPPED_AREAget_unmapped_area: get_fb_unmapped_area,#endif;這個結構中定義了對LCD所分配的framebuffer進行讀寫操作, 以及一些內存映射之類的函數,這些源函數都在該文件中。/*register_framebuffer - registers a frame buffer devicfb_info: frame buffer info structure*Registers a frame buffer device fb_info.*Re

36、turns negative errno on error, or zero for success.*/intregister_framebuffer(struct fb_info *fb_info)這個是對LCD的framebuffer設備進行注冊時調用到的注冊函數,該函數在/kernel/drivers/video/s3c2410fb.c 文件的s3c2410fb_init函數里的最后部分被調用。fb_info-devfs_handle =devfs_register (devfs_handle, name_buf,DEVFS_FL_DEFAULT,FB_MAJOR, i, S_IFCH

37、R | S_IRUGO | S_IWUGO,&fb_fops, NULL);在注冊函數的最后部分,將前面的fb_fops結構里的各個驅動函 數的入口點傳入到devfs_register()設備注冊函數中。*/*/* 2007.6.26*/*上面這個devfs_register函數(原型在/kernel/fs/devfs/base.c 文件中)執行前,在fbmem_init 函數中 調用了函數:devfs_handle = devfs_mk_dir (NULL, fb”, NULL);在/kernel/fs/devfs/base.c 文件中:/*devfs_mk_dir - Create a d

38、irectory in the devfs namespace.dir: The handle to the parent devfs directory entry. If this is %NULL thenew name is relative to the root of the : The name of the : An arbitrary pointer which will be associated with the entry.*Use of this function is optional. The devfs_register(

39、 functionwill automatically create intermediate directories as needed. This functionis provided for efficiency reasons, as it provides a handle to a directory.Returns a handle which may later be used in a call to devfs_unregister().On failure %NULL is returned.*/devfs_handle_t devfs_mk_dir (devfs_ha

40、ndle_t dir, const char *name, void *info)這個devfs_mk_dir函數會在設備文件系統中創建一個名為 fb的目錄,并返回一個帶有devfs設備文件系統目錄結構的數據結 構變量devfs_handle。然后把這個數據結構作為下一步調用 devfs_register函數時的參數,該參數在調用設備文件系統注冊清 除函數devfs_unregister時也要作為參數傳入。/*devfs_register - Register a device entry.dir: The handle to the parent devfs directory entry. If th

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論