01
12

Framebuffer兩三事-Test On QT2410

Framebuffer是個很好玩的驅動程式,它 allocate一塊自己的kernel memory,並藉由user space file open/read/write方式,把圖形寫入已allocate的空間,而這個已被allocate的kernel memory會對映LCD的pixel,framebuffer依靠此對應把圖形打到LCD上(2009.1.16修正),通常屬於framebuffer的device都被命名為/dev/fbx(x=any number),你可以做個實驗,假設你螢幕的driver是framebuffer,而且它在/dev資料夾下是/dev/fb0,你可以用下面指令補捉螢幕畫面

dd if=/dev/fb0 of=fbdata bs=1024 count=768(假設解析度為1024*768)

也可以用下面指令把fbdata顯示在螢幕上
dd if=fbdata of=/dev/fb0 bs=1024 count=768
所以透過open,read,write /dev/fb0我們可以直接對video card memory讀寫

我先寫一個小的簡單的framebuffer driver範例,並試著解釋一些數據的原理,因為小弟並不是攻這方面的人,所以有錯誤或缺失的地方煩請先進指正

Framebuffer driver寫作要點如下
1.註冊callback函式: fb_check_var, fb_set_par, fb_setcolreg, fb_blank, fb_fillrect, fb_copyarea, fb_imageblit
2.Allocate一塊可讀寫的記憶體供framebuffer使用,因為Ben Dooks已經提供一組DMA API,所以我們可以直接拿來用
3.初始化硬體暫存器並開啟clock(這邊又要感謝Ben Dooks,原來clock在2410可以分成不同組別啟動)
4.向kernel註冊我們的framebuffer device

小弟的sample code開機時可顯示linux logo,但是沒用到中斷與palette,而其中有幾個重點我列如下
1.在probing時先alloc framebuffer info的structure memory,要特別注意framebuffer_alloc這個函式,它第一個參數是我們private data的size,第二個是plateform device變數


2.填寫framebuffer資料,可以先填寫fix的資料,var的資料我們可以單獨宣告一組structure與其對應,其中比較重要的欄位如fbops,就是我們前面提到的callback函式,fb_set_par和fb_fillrect, fb_copyarea, fb_imageblit一定要有相對應的方法處理,而pseudo_palette也十分重要,16 bit TFT需要使用這塊pseudo_palette儲存pixel color(如果fbinfo->fix.visual選擇的是FB_VISUAL_TRUECOLOR,那你一定得用pseudo_palette,否則開機就當了), fbinfo->par可儲存driver private data


3.fbinfo->var的部份最重要的地方在於
.pixclock = 1000000,
.left_margin = 30,//HFPD 30
.right_margin = 6,//HBPD 6
.upper_margin = 2,//VFPD 2
.lower_margin = 1,//VBPD 1
.vsync_len = 1,//VSPW 1
.hsync_len = 3,//HSPW 3
這些值怎麼來的?先看看它們各自的意義
pixclock - pixel clock in pico seconds
left_margin - time fron sync to picture對應HFPD
right_margin - time from picture to sync對應HBPD
upper_margin - time from sync to picture對應VFPD
lower_margin - time from picture to sync對應VBPD
hsync_len - length of horizontal sync對應HSPW
vsync_len - length of vertical sync對應VSPW
在Samsung 2410 user manual LCD section內有一幅重要的圖如下,它詳細說明了如何算出這些sync值

我翻閱了NEC LCD的相關說明,我還是無法將其Timing chart與上面這張對應,不過後來查閱Samsung Portrait LCD發現其Timing chart 100% match 2410 user manual的圖型,請參考下面圖示

從這張我們可以算出240*320的LCD參數大概可以設為
VSPW+1=2
VBPD+1=2
VFPD+1=3
而透過Honzital Timing chart可算出HSPW,HPBD,HFPD,請參考下圖

所以我把這些值直接拿來用,好像是可以動的,而至於pixclock的算法是
MHZ/DCF(CLKVAL),因為我的CLKVAL divisor為1,所以pixclock為1000000


4.S3C2410 LCD controller的部份直接照說明書填就可以了,比較特殊的是LCD controller5的部份,要小心byteswap的設定,而LCD address只要把一開始allocate的dma memory位址指派給LCD address register即可(一共三個,照manual填),底下是我的範例code

[qt2410_fb.c]

  1. #include "qt2410fb.h" 
  2.  
  3. static u_int pseudo_pal[16];
  4.  
  5. struct lcdregs 
  6. { 
  7. void __iomem *lcdcon1;
  8. void __iomem *lcdcon2;
  9. void __iomem *lcdcon3;
  10. void __iomem *lcdcon4;
  11. void __iomem *lcdcon5;
  12. void __iomem *lcdsaddr1;
  13. void __iomem *lcdsaddr2;
  14. void __iomem *lcdsaddr3;
  15. void __iomem *gpioccon;
  16. void __iomem *gpiodcon;
  17. void __iomem *gpiocup;
  18. void __iomem *gpiodup;
  19. void __iomem *lpcsel;
  20. void __iomem *tmppal;
  21. void __iomem *pal;
  22. };
  23.  
  24. typedef struct _driver_private_data 
  25. { 
  26. struct device *dev;
  27. struct lcdregs regs;
  28. struct clk *clk;//2410 specified structure clock
  29.  
  30. }driver_private_data;
  31.  
  32. static struct fb_var_screeninfo qt2410fb_var __initdata = { 
  33. .xres = 240,
  34. .yres = 320,
  35. .xres_virtual =240,
  36. .yres_virtual = 320,
  37. .bits_per_pixel = 16,
  38. .red = {11, 5, 0},
  39. .green = {5, 6, 0},
  40. .blue = {0, 5, 0},
  41. .activate = FB_ACTIVATE_NOW,
  42. .height = 320,
  43. .width = 240,
  44. .vmode = FB_VMODE_NONINTERLACED,
  45.  
  46. /* NEC LCD hardware stuff */ 
  47. .pixclock = /*100000*/1000000,
  48. .left_margin = 30,//HFPD 30
  49. .right_margin = 6,//HBPD 6
  50. .upper_margin = 2,//VFPD 2
  51. .lower_margin = 1,//VBPD 1
  52. .vsync_len = 1,//VSPW 1
  53. .hsync_len = 3,//HSPW 3
  54. };
  55.  
  56. /* from pxafb.c */ 
  57. static inline unsigned int chan_to_field(unsigned int chan,
  58. struct fb_bitfield *bf) 
  59. { 
  60. chan &= 0xffff;
  61. chan >>= 16 - bf->length;
  62. return chan << bf->offset;
  63. } 
  64.  
  65. int Phy2VM(unsigned long phyaddr,char *name,void __iomem **vaddr) 
  66. { 
  67. if (!request_mem_region(phyaddr, 4, name)) 
  68. return 0;
  69. *vaddr= ioremap(phyaddr, 4);
  70. if (*vaddr==0) return 0;
  71. else printk("[qt2410fb]%s virtual address:0x%p\n",name,*vaddr);
  72.  
  73. return 1;
  74. } 
  75.  
  76. void reqREGmem(struct lcdregs *regs) 
  77. { 
  78. Phy2VM(LCDCON1,"LCDCON1",&reg;s->lcdcon1);
  79. Phy2VM(LCDCON2,"LCDCON2",&reg;s->lcdcon2);
  80. Phy2VM(LCDCON3,"LCDCON3",&reg;s->lcdcon3);
  81. Phy2VM(LCDCON4,"LCDCON4",&reg;s->lcdcon4);
  82. Phy2VM(LCDCON5,"LCDCON5",&reg;s->lcdcon5);
  83. Phy2VM(GPCCON,"GPCCON",&reg;s->gpioccon);
  84. Phy2VM(GPDCON,"GPDCON",&reg;s->gpiodcon);
  85. Phy2VM(GPCUP,"GPCUP",&reg;s->gpiocup);
  86. Phy2VM(GPDUP,"GPDUP",&reg;s->gpiodup);
  87. Phy2VM(LPCSEL,"LPCSEL",&reg;s->lpcsel);
  88. Phy2VM(TPAL,"TPAL",&reg;s->tmppal);
  89. Phy2VM(LCDSADDR1,"LCDSADDR1",&reg;s->lcdsaddr1);
  90. Phy2VM(LCDSADDR2,"LCDSADDR2",&reg;s->lcdsaddr2);
  91. Phy2VM(LCDSADDR3,"LCDSADDR3",&reg;s->lcdsaddr3);
  92. Phy2VM(PALETTE,"PALETTE",&reg;s->pal);
  93. } 
  94.  
  95. void initRegs(struct lcdregs *regs) 
  96. { 
  97. DEBUG_TRACE();
  98. (*(volatile unsigned *)regs->gpioccon)|=0xaaaaaaaa;
  99. (*(volatile unsigned *)regs->gpiodcon)|=0xaaaaaaaa;
  100. (*(volatile unsigned *)regs->gpiocup)|=0xffffffff;
  101. (*(volatile unsigned*)regs->gpiodup)|=0xffffffff;
  102. (*(volatile unsigned *)regs->lpcsel)&=(~7);
  103. (*(volatile unsigned *)regs->tmppal)&=0;
  104. } 
  105.  
  106. /*
  107. * Blank the display.
  108. */ 
  109. static int qt2410fb_blank(int blank, struct fb_info *info) 
  110. { 
  111. DEBUG_TRACE();
  112. return 0;
  113. } 
  114.  
  115.  
  116. static int qt2410fb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) 
  117. { 
  118. DEBUG_TRACE();
  119. return 0;
  120. } 
  121. static int qt2410fb_set_par(struct fb_info *fbinfo) 
  122. { 
  123. driver_private_data *dpd=fbinfo->par;
  124. struct lcdregs *regs=&dpd->regs;
  125. unsigned long saddr1, saddr2, saddr3;
  126. u_int* palette;
  127. int i;
  128.  
  129. DEBUG_TRACE();
  130. fbinfo->fix.visual = FB_VISUAL_TRUECOLOR;
  131. (*(volatile unsigned *)regs->lcdcon1)=(4<<8)|(0<<7)|(3<<5)|(12<<1)|0;
  132. (*(volatile unsigned *)regs->lcdcon2)=(VBPD<<24)|(319<<14)|(VFPD<<6)|(VSPW);
  133. (*(volatile unsigned *)regs->lcdcon3)=(HBPD<<19)|(239<<8)|(HFPD);
  134. (*(volatile unsigned *)regs->lcdcon4)=(0<<8)|(HSPW);
  135. (*(volatile unsigned *)regs->lcdcon5)=(1<<11)|(1<<9)|(1<<8)|1<<0; //FRM5:6:5,HSYNC and VSYNC are inverted,turn on BSWP
  136. (*(volatile unsigned *)regs->lcdcon5)&= ~S3C2410_LCDCON5_BSWP;
  137. fbinfo->fix.line_length = (fbinfo->var.xres_virtual * fbinfo->var.bits_per_pixel) / 8;
  138. saddr1 = fbinfo->fix.smem_start >> 1;
  139. saddr2 = fbinfo->fix.smem_start;
  140. saddr2 += fbinfo->fix.line_length * fbinfo->var.yres;
  141. saddr2 >>= 1;
  142. saddr3 = S3C2410_OFFSIZE(0) |S3C2410_PAGEWIDTH((fbinfo->fix.line_length / 2) & 0x3ff);
  143. (*(volatile unsigned *)regs->lcdsaddr1)=saddr1;
  144. (*(volatile unsigned *)regs->lcdsaddr2)=saddr2;
  145. (*(volatile unsigned *)regs->lcdsaddr3)=saddr3;
  146. (*(volatile unsigned *)regs->lcdcon1)|=1;
  147. return 0;
  148. } 
  149.  
  150. static int qt2410fb_setcolreg(unsigned regno,
  151. unsigned red, unsigned green, unsigned blue,
  152. unsigned transp, struct fb_info *info) 
  153. { 
  154. unsigned int val;
  155.  
  156. printk("regno %d, fix.visual:%d\n",regno,info->fix.visual);
  157. if (info->fix.visual==FB_VISUAL_TRUECOLOR) 
  158. { 
  159. if (regno < 16) 
  160. { 
  161. u32 *pal = info->pseudo_palette;
  162.  
  163. val = chan_to_field(red, &info->var.red);
  164. val |= chan_to_field(green, &info->var.green);
  165. val |= chan_to_field(blue, &info->var.blue);
  166.  
  167. pal[regno] = val;
  168. } 
  169. } 
  170. return 0;
  171. } 
  172.  
  173. static struct fb_ops qt2410fb_ops = { 
  174. .owner = THIS_MODULE,
  175. .fb_check_var = qt2410fb_check_var,
  176. .fb_set_par = qt2410fb_set_par,
  177. .fb_setcolreg = qt2410fb_setcolreg,
  178. .fb_blank = qt2410fb_blank,
  179. .fb_fillrect = cfb_fillrect,
  180. .fb_copyarea = cfb_copyarea,
  181. .fb_imageblit = cfb_imageblit,
  182. };
  183.  
  184. static int __init qt2410fb_map_video_memory(struct fb_info *info) 
  185. { 
  186. dma_addr_t map_dma;
  187. unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
  188. driver_private_data *dpd;
  189. DEBUG_TRACE();
  190.  
  191. dpd=info->par;
  192. info->screen_base = dma_alloc_writecombine(dpd->dev, map_size,&map_dma, GFP_KERNEL);
  193. if (info->screen_base) 
  194. { 
  195. info->fix.smem_start = map_dma;
  196. DEBUG_TRACE();
  197. return 0;
  198. } 
  199. else return -ENOMEM;
  200.  
  201. } 
  202. static inline void qt2410fb_unmap_video_memory(struct fb_info *info) 
  203. { 
  204. driver_private_data *dpd;
  205.  
  206. dpd=info->par;
  207. dma_free_writecombine(dpd->dev, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start);
  208. } 
  209. static int __init qt2410fb_probe(struct platform_device *pdev) 
  210. { 
  211.  
  212. int ret;
  213. struct fb_info *fbinfo;
  214. driver_private_data *dpd;
  215.  
  216. DEBUG_TRACE();
  217. fbinfo = framebuffer_alloc(sizeof(driver_private_data)/*size of driver private data*/, &pdev->dev);
  218. if (!fbinfo) 
  219. return -ENOMEM;
  220. platform_set_drvdata(pdev, fbinfo);
  221.  
  222. strcpy(fbinfo->fix.id,"qt2410");
  223. fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
  224. fbinfo->fix.type_aux = 0;
  225. fbinfo->fix.xpanstep = 0;
  226. fbinfo->fix.ypanstep = 0;
  227. fbinfo->fix.ywrapstep = 0;
  228. fbinfo->fix.accel = FB_ACCEL_NONE;
  229. fbinfo->fbops = &qt2410fb_ops;
  230. fbinfo->flags = FBINFO_FLAG_DEFAULT;
  231. fbinfo->var=qt2410fb_var;//set variable
  232. fbinfo->fix.smem_len = ((fbinfo->var.xres)*(fbinfo->var.yres)*(fbinfo->var.bits_per_pixel))/8;
  233. fbinfo->pseudo_palette=&pseudo_pal;
  234. dpd=fbinfo->par;
  235. dpd->dev=&pdev->dev;
  236. qt2410fb_map_video_memory(fbinfo);
  237.  
  238. //from here we initail LCD hardware stuff
  239. reqREGmem(&dpd->regs);
  240. dpd->clk = clk_get(NULL, "lcd");//2410 special stuff
  241. if (!dpd->clk || IS_ERR(dpd->clk)) 
  242. { 
  243. printk(KERN_ERR "failed to get lcd clock source\n");
  244. return -ENOENT;
  245. } 
  246. clk_enable(dpd->clk);
  247. initRegs(&dpd->regs);
  248. DEBUG_TRACE();
  249. ret = register_framebuffer(fbinfo);
  250. if (ret <0) 
  251. { 
  252. qt2410fb_unmap_video_memory(fbinfo);
  253. platform_set_drvdata(pdev, NULL);
  254. framebuffer_release(fbinfo);
  255. } 
  256. printk("fb%d: %s frame buffer device\n",fbinfo->node, fbinfo->fix.id);
  257. return ret;
  258. } 
  259.  
  260. static int qt2410fb_remove(struct platform_device *pdev) 
  261. { 
  262. DEBUG_TRACE();
  263. return 0;
  264. } 
  265.  
  266. static struct platform_driver qt2410fb_driver =
  267. { 
  268. .probe = qt2410fb_probe,
  269. .remove = qt2410fb_remove,
  270. .driver = { 
  271. .name = "s3c2410-lcd",
  272. .owner = THIS_MODULE,
  273. },
  274. };
  275.  
  276. int __init qt2410fb_init(void) 
  277. { 
  278. int ret;
  279. DEBUG_TRACE();
  280. ret = platform_driver_register(&qt2410fb_driver);
  281. return ret;
  282. } 
  283.  
  284. static void __exit qt2410fb_cleanup(void) 
  285. { 
  286. DEBUG_TRACE();
  287.  
  288. platform_driver_unregister(&qt2410fb_driver);
  289.  
  290. } 
  291.  
  292. module_init(qt2410fb_init);
  293. module_exit(qt2410fb_cleanup);

[qt2410fb.h]

  1. #include <linux/module.h> 
  2. #include <linux/kernel.h> 
  3. #include <linux/errno.h> 
  4. #include <linux/string.h> 
  5. #include <linux/mm.h> 
  6. #include <linux/slab.h> 
  7. #include <linux/delay.h> 
  8. #include <linux/fb.h> 
  9. #include <linux/init.h> 
  10. #include <linux/dma-mapping.h> 
  11. #include <linux/interrupt.h> 
  12. #include <linux/platform_device.h> 
  13. #include <linux/clk.h> 
  14.  
  15. #include <asm/io.h> 
  16. #include <asm/div64.h> 
  17.  
  18. #include <asm/mach/map.h> 
  19. #include <asm/arch/regs-lcd.h> 
  20. #include <asm/arch/regs-gpio.h> 
  21. #include <asm/arch/fb.h> 
  22. #include <asm/uaccess.h> 
  23. #include <linux/ioport.h> 
  24. #include <asm/io.h> 
  25.  
  26. #define PALETTE_BUFF_CLEAR (0x80000000) /* entry is clear/invalid */
  27. #define DEBUG_TRACE() printk("[%s]:%d =>\n",__FUNCTION__,__LINE__)
  28.  
  29. // LCD CONTROLLER
  30. #define LCDCON1 0x4d000000 //LCD control 1
  31. #define LCDCON2 0x4d000004 //LCD control 2
  32. #define LCDCON3 0x4d000008 //LCD control 3
  33. #define LCDCON4 0x4d00000c //LCD control 4
  34. #define LCDCON5 0x4d000010 //LCD control 5
  35. #define LCDSADDR1 0x4d000014 //STN/TFT Frame buffer start address 1
  36. #define LCDSADDR2 0x4d000018 //STN/TFT Frame buffer start address 2
  37. #define LCDSADDR3 0x4d00001c //STN/TFT Virtual screen address set
  38. #define TPAL 0x4d000050 //TFT Temporary palette
  39. #define LCDINTPND 0x4d000054 //LCD Interrupt pending
  40. #define LCDSRCPND 0x4d000058 //LCD Interrupt source
  41. #define LCDINTMSK 0x4d00005c //LCD Interrupt mask
  42. #define LPCSEL 0x4d000060 //LPC3600 Control
  43. #define PALETTE 0x4d000400 //Palette start address
  44.  
  45. #define GPCCON 0x56000020 //Port C control
  46. #define GPCUP 0x56000028 //Pull-up control C
  47. #define GPDCON 0x56000030 //Port D control
  48. #define GPDUP 0x56000038 //Pull-up control D
  49.  
  50. // SYNC settings
  51.  
  52. #define HFPD 30
  53. #define HBPD 6
  54. #define VFPD 2
  55. #define VBPD 1
  56. #define VSPW 1
  57. #define HSPW 3

另外一個qt2410 LCD framebuffer的懶人移植法就是直接參考mach-qt2410.c的source並把mach-smdk2410.c修改成如下

  1. #include <linux/kernel.h> 
  2. #include <linux/types.h> 
  3. #include <linux/interrupt.h> 
  4. #include <linux/list.h> 
  5. #include <linux/timer.h> 
  6. #include <linux/init.h> 
  7. #include <linux/serial_core.h> 
  8. #include <linux/platform_device.h> 
  9.  
  10. #include <asm/mach/arch.h> 
  11. #include <asm/mach/map.h> 
  12. #include <asm/mach/irq.h> 
  13.  
  14. #include <asm/hardware.h> 
  15. #include <asm/io.h> 
  16. #include <asm/irq.h> 
  17. #include <asm/mach-types.h> 
  18.  
  19. #include <asm/plat-s3c/regs-serial.h> 
  20.  
  21. #include <asm/plat-s3c24xx/devs.h> 
  22. #include <asm/plat-s3c24xx/cpu.h> 
  23.  
  24. #include <asm/plat-s3c24xx/common-smdk.h> 
  25. #include <asm/arch-s3c2410/fb.h> 
  26.  
  27. static struct map_desc smdk2410_iodesc[] __initdata = { 
  28. /* nothing here yet */ 
  29. };
  30.  
  31. #define UCON S3C2410_UCON_DEFAULT
  32. #define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
  33. #define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
  34.  
  35. static struct s3c2410_uartcfg smdk2410_uartcfgs[] __initdata = { 
  36. [0] = { 
  37. .hwport = 0,
  38. .flags = 0,
  39. .ucon = UCON,
  40. .ulcon = ULCON,
  41. .ufcon = UFCON,
  42. },
  43. [1] = { 
  44. .hwport = 1,
  45. .flags = 0,
  46. .ucon = UCON,
  47. .ulcon = ULCON,
  48. .ufcon = UFCON,
  49. },
  50. [2] = { 
  51. .hwport = 2,
  52. .flags = 0,
  53. .ucon = UCON,
  54. .ulcon = ULCON,
  55. .ufcon = UFCON,
  56. } 
  57. };
  58.  
  59. /* CS8900 */ 
  60.  
  61. static struct resource s3c_cs89x0_resources[] = { 
  62. [0] = { 
  63. .start = 0x19000300,
  64. .end = 0x19000300 + 16,
  65. .flags = IORESOURCE_MEM,
  66. },
  67. [1] = { 
  68. .start = IRQ_EINT9,
  69. .end = IRQ_EINT9,
  70. .flags = IORESOURCE_IRQ,
  71. },
  72. };
  73.  
  74. static struct platform_device s3c_cs89x0 = { 
  75. .name = "cirrus-cs89x0",
  76. .num_resources = ARRAY_SIZE(s3c_cs89x0_resources),
  77. .resource = s3c_cs89x0_resources,
  78. };
  79.  
  80. static struct resource s3c_led_resources[] = { 
  81. [0] = { 
  82. .start = 0x56000000,
  83. .end = 0x56000000 + 24,
  84. .flags = IORESOURCE_MEM,
  85. },
  86. [1] = { 
  87. .start = IRQ_EINT23,
  88. .end = IRQ_EINT23,
  89. .flags = IORESOURCE_IRQ,
  90. },
  91. };
  92.  
  93.  
  94. static struct platform_device s3c_led = { 
  95. .name = "JoeyLED",
  96. .num_resources = ARRAY_SIZE(s3c_led_resources),
  97. .resource = s3c_led_resources,
  98. };
  99.  
  100.  
  101. /* LCD Controller */ 
  102.  
  103. static struct s3c2410fb_display qt2410_lcd_cfg[] __initdata = { 
  104. { 
  105. /* Configuration for 640x480 SHARP LQ080V3DG01 */ 
  106. .lcdcon5 = S3C2410_LCDCON5_FRM565 |
  107. S3C2410_LCDCON5_INVVLINE |
  108. S3C2410_LCDCON5_INVVFRAME |
  109. S3C2410_LCDCON5_PWREN |
  110. S3C2410_LCDCON5_HWSWP,
  111.  
  112. .type = S3C2410_LCDCON1_TFT,
  113. .width = 640,
  114. .height = 480,
  115.  
  116. .pixclock = 40000, /* HCLK/4 */ 
  117. .xres = 640,
  118. .yres = 480,
  119. .bpp = 16,
  120. .left_margin = 44,
  121. .right_margin = 116,
  122. .hsync_len = 96,
  123. .upper_margin = 19,
  124. .lower_margin = 11,
  125. .vsync_len = 15,
  126. },
  127. { 
  128. /* Configuration for 480x640 toppoly TD028TTEC1 */ 
  129. .lcdcon5 = S3C2410_LCDCON5_FRM565 |
  130. S3C2410_LCDCON5_INVVLINE |
  131. S3C2410_LCDCON5_INVVFRAME |
  132. S3C2410_LCDCON5_PWREN |
  133. S3C2410_LCDCON5_HWSWP,
  134.  
  135. .type = S3C2410_LCDCON1_TFT,
  136. .width = 480,
  137. .height = 640,
  138. .pixclock = 40000, /* HCLK/4 */ 
  139. .xres = 480,
  140. .yres = 640,
  141. .bpp = 16,
  142. .left_margin = 8,
  143. .right_margin = 24,
  144. .hsync_len = 8,
  145. .upper_margin = 2,
  146. .lower_margin = 4,
  147. .vsync_len = 2,
  148. },
  149. { 
  150. /* Config for 240x320 LCD */ 
  151. .lcdcon5 = S3C2410_LCDCON5_FRM565 |
  152. S3C2410_LCDCON5_INVVLINE |
  153. S3C2410_LCDCON5_INVVFRAME |
  154. S3C2410_LCDCON5_PWREN |
  155. S3C2410_LCDCON5_HWSWP,
  156.  
  157. .type = S3C2410_LCDCON1_TFT,
  158. .width = 240,
  159. .height = 320,
  160. .pixclock = 100000, /* HCLK/10 */ 
  161. .xres = 240,
  162. .yres = 320,
  163. .bpp = 16,
  164. .left_margin = 13,
  165. .right_margin = 8,
  166. .hsync_len = 4,
  167. .upper_margin = 2,
  168. .lower_margin = 7,
  169. .vsync_len = 4,
  170. },
  171. };
  172.  
  173.  
  174. static struct s3c2410fb_mach_info qt2410_fb_info __initdata = { 
  175. .displays = qt2410_lcd_cfg,
  176. .num_displays = ARRAY_SIZE(qt2410_lcd_cfg),
  177. .default_display = 0,
  178.  
  179. .lpcsel = ((0xCE6) & ~7) | 1<<4,
  180. };
  181.  
  182. /*static struct resource s3c_lcd_resource[] = {
  183. [0] = {
  184. .start = S3C24XX_PA_LCD,
  185. .end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
  186. .flags = IORESOURCE_MEM,
  187. },
  188. [1] = {
  189. .start = IRQ_LCD,
  190. .end = IRQ_LCD,
  191. .flags = IORESOURCE_IRQ,
  192. }
  193.  
  194. };
  195.  
  196. static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
  197.  
  198. struct platform_device s3c_device_lcd = {
  199. .name = "qt2410-lcd",
  200. .id = -1,
  201. .num_resources = ARRAY_SIZE(s3c_lcd_resource),
  202. .resource = s3c_lcd_resource,
  203. .dev = {
  204. .dma_mask = &s3c_device_lcd_dmamask,
  205. .coherent_dma_mask = 0xffffffffUL
  206. }
  207. };*/ 
  208.  
  209. static char tft_type = 's';
  210.  
  211. static int __init qt2410_tft_setup(char *str) 
  212. { 
  213. tft_type = /*str[0]*/'s';
  214. return 1;
  215. } 
  216. /*__setup("tft=", qt2410_tft_setup);*/ 
  217.  
  218.  
  219. static struct platform_device *smdk2410_devices[] __initdata = { 
  220. &s3c_device_usb,
  221. &s3c_device_lcd,
  222. &s3c_device_wdt,
  223. &s3c_device_i2c,
  224. &s3c_device_iis,
  225. &s3c_cs89x0,
  226. &s3c_led,
  227. };
  228.  
  229. static void __init smdk2410_map_io(void) 
  230. { 
  231. s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
  232. s3c24xx_init_clocks(0);
  233. s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
  234. } 
  235.  
  236. static void __init smdk2410_init(void) 
  237. { 
  238. switch (tft_type) { 
  239. case 'p': /* production */ 
  240. qt2410_fb_info.default_display = 1;
  241. break;
  242. case 'b': /* big */ 
  243. qt2410_fb_info.default_display = 0;
  244. break;
  245. case 's': /* small */ 
  246. default:
  247. qt2410_fb_info.default_display = 2;
  248. break;
  249. } 
  250. s3c24xx_fb_set_platdata(&qt2410_fb_info);
  251.  
  252. platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
  253. smdk_machine_init();
  254. } 
  255.  
  256. MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
  257. * to SMDK2410 */ 
  258. /* Maintainer: Jonas Dietsche */ 
  259. .phys_io = S3C2410_PA_UART,
  260. .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
  261. .boot_params = S3C2410_SDRAM_PA + 0x100,
  262. .map_io = smdk2410_map_io,
  263. .init_irq = s3c24xx_init_irq,
  264. .init_machine = smdk2410_init,
  265. .timer = &s3c24xx_timer,
  266. MACHINE_END

小弟會找時間以官方driver為基礎繼續講解embedded GUI的應用

 

 

標籤: embedded
評論: 0 | 引用: 0 | 閱讀: 20195
發表評論
暱 稱: 密 碼:
網 址: E - mail:
驗證碼: 驗證碼圖片 選 項:
頭 像:
內 容: