tx3912fb.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  drivers/video/tx3912fb.c
  3.  *
  4.  *  Copyright (C) 1999 Harald Koerfgen
  5.  *  Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com)
  6.  *
  7.  * This file is subject to the terms and conditions of the GNU General Public
  8.  * License. See the file COPYING in the main directory of this archive for
  9.  * more details.
  10.  *
  11.  *  Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors
  12.  */
  13. #include <linux/config.h>
  14. #include <linux/module.h>
  15. #include <linux/kernel.h>
  16. #include <linux/errno.h>
  17. #include <linux/string.h>
  18. #include <linux/tty.h>
  19. #include <linux/delay.h>
  20. #include <linux/interrupt.h>
  21. #include <linux/init.h>
  22. #include <linux/pm.h>
  23. #include <linux/fb.h>
  24. #include <video/fbcon.h>
  25. #include <video/fbcon-mfb.h>
  26. #include <video/fbcon-cfb2.h>
  27. #include <video/fbcon-cfb4.h>
  28. #include <video/fbcon-cfb8.h>
  29. #include <asm/io.h>
  30. #include <asm/bootinfo.h>
  31. #include <asm/uaccess.h>
  32. #include <asm/tx3912.h>
  33. #include "tx3912fb.h"
  34. /*
  35.  * Frame buffer, palette and console structures
  36.  */
  37. static struct fb_info fb_info;
  38. static struct { u_char red, green, blue, pad; } palette[256];
  39. #ifdef FBCON_HAS_CFB8
  40. static union { u16 cfb8[16]; } fbcon_cmap;
  41. #endif
  42. static struct display global_disp;
  43. static int currcon = 0;
  44. /*
  45.  * Interface used by the world
  46.  */
  47. static int tx3912fb_get_fix(struct fb_fix_screeninfo *fix, int con,
  48. struct fb_info *info);
  49. static int tx3912fb_get_var(struct fb_var_screeninfo *var, int con,
  50. struct fb_info *info);
  51. static int tx3912fb_set_var(struct fb_var_screeninfo *var, int con,
  52. struct fb_info *info);
  53. static int tx3912fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
  54. struct fb_info *info);
  55. static int tx3912fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  56. struct fb_info *info);
  57. static int tx3912fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
  58. u_long arg, int con, struct fb_info *info);
  59. /*
  60.  * Interface used by console driver
  61.  */
  62. int tx3912fb_init(void);
  63. static int tx3912fbcon_switch(int con, struct fb_info *info);
  64. static int tx3912fbcon_updatevar(int con, struct fb_info *info);
  65. static void tx3912fbcon_blank(int blank, struct fb_info *info);
  66. /*
  67.  * Macros
  68.  */
  69. #define get_line_length(xres_virtual, bpp) 
  70. (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3)
  71. /*
  72.  * Internal routines
  73.  */
  74. static int tx3912fb_getcolreg(u_int regno, u_int *red, u_int *green,
  75. u_int *blue, u_int *transp, struct fb_info *info);
  76. static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  77. u_int transp, struct fb_info *info);
  78. static void tx3912fb_install_cmap(int con, struct fb_info *info);
  79. /*
  80.  * Frame buffer operations structure used by console driver
  81.  */
  82. static struct fb_ops tx3912fb_ops = {
  83. owner: THIS_MODULE,
  84. fb_get_fix: tx3912fb_get_fix,
  85. fb_get_var: tx3912fb_get_var,
  86. fb_set_var: tx3912fb_set_var,
  87. fb_get_cmap: tx3912fb_get_cmap,
  88. fb_set_cmap: tx3912fb_set_cmap,
  89. fb_ioctl: tx3912fb_ioctl,
  90. };
  91. /*
  92.  *  Get fixed display data
  93.  */
  94. static int tx3912fb_get_fix(struct fb_fix_screeninfo *fix, int con,
  95. struct fb_info *info)
  96. {
  97. struct display *display;
  98. memset(fix, 0, sizeof(struct fb_fix_screeninfo));
  99. strcpy(fix->id, TX3912FB_NAME);
  100. if (con == -1)
  101. display = &global_disp;
  102. else
  103. display = &fb_display[con];
  104. fix->smem_start = tx3912fb_vaddr;
  105. fix->smem_len = tx3912fb_size;
  106. fix->type = display->type;
  107. fix->type_aux = display->type_aux;
  108. fix->xpanstep = 0;
  109. fix->ypanstep = display->ypanstep;
  110. fix->ywrapstep = display->ywrapstep;
  111. fix->visual = display->visual;
  112. fix->line_length = display->line_length;
  113. fix->accel = FB_ACCEL_NONE;
  114. return 0;
  115. }
  116. /*
  117.  * Get user display data
  118.  */
  119. static int tx3912fb_get_var(struct fb_var_screeninfo *var, int con,
  120. struct fb_info *info)
  121. {
  122. if (con == -1)
  123. *var = tx3912fb_info;
  124. else
  125. *var = fb_display[con].var;
  126. return 0;
  127. }
  128. /*
  129.  *  Set user display data
  130.  */
  131. static int tx3912fb_set_var(struct fb_var_screeninfo *var, int con,
  132. struct fb_info *info)
  133. {
  134. int err, activate = var->activate;
  135. int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
  136. u_long line_length;
  137. struct display *display;
  138. if (con == -1)
  139. display = &global_disp;
  140. else
  141. display = &fb_display[con];
  142. /*
  143.  * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal
  144.  * as FB_VMODE_SMOOTH_XPAN is only used internally
  145.  */
  146. if (var->vmode & FB_VMODE_CONUPDATE) {
  147. var->xoffset = display->var.xoffset;
  148. var->yoffset = display->var.yoffset;
  149. var->vmode |= FB_VMODE_YWRAP;
  150. }
  151. /*
  152.  * Make sure values are in range
  153.  */
  154. if (!var->xres)
  155. var->xres = 1;
  156. if (!var->yres)
  157. var->yres = 1;
  158. if (var->xres > var->xres_virtual)
  159. var->xres_virtual = var->xres;
  160. if (var->yres > var->yres_virtual)
  161. var->yres_virtual = var->yres;
  162. if (var->bits_per_pixel <= 1)
  163. var->bits_per_pixel = 1;
  164. else if (var->bits_per_pixel <= 2)
  165. var->bits_per_pixel = 2;
  166. else if (var->bits_per_pixel <= 4)
  167. var->bits_per_pixel = 4;
  168. else if (var->bits_per_pixel <= 8)
  169. var->bits_per_pixel = 8;
  170. else
  171. return -EINVAL;
  172. /*
  173.  * Memory limit
  174.  */
  175. line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
  176. if ((line_length * var->yres_virtual) > tx3912fb_size)
  177. return -ENOMEM;
  178. /*
  179.  * This is only for color and we only support 8-bit color
  180.  */
  181. if (var->bits_per_pixel) {
  182. /* RGB 332 */
  183. var->red.offset = 5;
  184. var->red.length = 3;
  185. var->green.offset = 2;
  186. var->green.length = 3;
  187. var->blue.offset = 0;
  188. var->blue.length = 2;
  189. var->transp.offset = 0;
  190. var->transp.length = 0;
  191. }
  192. var->red.msb_right = 0;
  193. var->green.msb_right = 0;
  194. var->blue.msb_right = 0;
  195. var->transp.msb_right = 0;
  196. /*
  197.  * Make changes if necessary
  198.  */
  199. if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
  200. oldxres = display->var.xres;
  201. oldyres = display->var.yres;
  202. oldvxres = display->var.xres_virtual;
  203. oldvyres = display->var.yres_virtual;
  204. oldbpp = display->var.bits_per_pixel;
  205. display->var = *var;
  206. if (oldxres != var->xres || oldyres != var->yres ||
  207.     oldvxres != var->xres_virtual ||
  208.     oldvyres != var->yres_virtual ||
  209.     oldbpp != var->bits_per_pixel) {
  210. display->screen_base = (u_char *) tx3912fb_vaddr;
  211. switch (var->bits_per_pixel) {
  212. case 1:
  213. display->visual = FB_VISUAL_MONO10;
  214. break;
  215. case 2:
  216. display->visual = FB_VISUAL_PSEUDOCOLOR;
  217. case 4:
  218. case 8:
  219. display->visual = FB_VISUAL_TRUECOLOR;
  220. break;
  221. }
  222. display->type = FB_TYPE_PACKED_PIXELS;
  223. display->type_aux = 0;
  224. display->ypanstep = 0;
  225. display->ywrapstep = 0;
  226. display->next_line =
  227. display->line_length =
  228. get_line_length(var->xres_virtual,
  229. var->bits_per_pixel);
  230. display->can_soft_blank = 0;
  231. display->inverse = FB_IS_INVERSE;
  232. switch (var->bits_per_pixel) {
  233. #ifdef CONFIG_FBCON_MFB
  234. case 1:
  235. display->dispsw = &fbcon_mfb;
  236. break;
  237. #endif
  238. #ifdef CONFIG_FBCON_CFB2
  239. case 2:
  240. display->dispsw = &fbcon_cfb2;
  241. break;
  242. #endif
  243. #ifdef CONFIG_FBCON_CFB4
  244. case 4:
  245. display->dispsw = &fbcon_cfb4;
  246. break;
  247. #endif
  248. #ifdef CONFIG_FBCON_CFB8
  249. case 8:
  250. display->dispsw = &fbcon_cfb8;
  251. display->dispsw_data = fbcon_cmap.cfb8;
  252. break;
  253. #endif
  254. default:
  255. display->dispsw = &fbcon_dummy;
  256. break;
  257.      }
  258. if (fb_info.changevar)
  259. (*fb_info.changevar)(con);
  260. }
  261. if (oldbpp != var->bits_per_pixel) {
  262. if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
  263. return err;
  264. tx3912fb_install_cmap(con, info);
  265. }
  266. }
  267. return 0;
  268. }
  269. /*
  270.  *  Get the colormap
  271.  */
  272. static int tx3912fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
  273. struct fb_info *info)
  274. {
  275. if (con == currcon)
  276. return fb_get_cmap(cmap, kspc, tx3912fb_getcolreg, info);
  277. else if (fb_display[con].cmap.len) /* non default colormap? */
  278. fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
  279. else
  280. fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
  281. return 0;
  282. }
  283. /*
  284.  *  Set the Colormap
  285.  */
  286. static int tx3912fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  287. struct fb_info *info)
  288. {
  289. int err;
  290. if (!fb_display[con].cmap.len)
  291. if ((err = fb_alloc_cmap(&fb_display[con].cmap,
  292. 1<<fb_display[con].var.bits_per_pixel, 0)))
  293. return err;
  294. if (con == currcon)
  295. return fb_set_cmap(cmap, kspc, tx3912fb_setcolreg, info);
  296. else
  297. fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
  298. return 0;
  299. }
  300. /*
  301.  *  Framebuffer ioctl
  302.  */
  303. static int tx3912fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
  304. u_long arg, int con, struct fb_info *info)
  305. {
  306. return -EINVAL;
  307. }
  308. /*
  309.  * Initialization of the framebuffer
  310.  */
  311. int __init tx3912fb_init(void)
  312. {
  313. /* Disable the video logic */
  314. outl(inl(TX3912_VIDEO_CTRL1) &
  315. ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
  316. TX3912_VIDEO_CTRL1);
  317. udelay(200);
  318. /* Set start address for DMA transfer */
  319. outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
  320. /* Set end address for DMA transfer */
  321. outl((tx3912fb_paddr + tx3912fb_size + 1), TX3912_VIDEO_CTRL4);
  322. /* Set the pixel depth */
  323. switch (tx3912fb_info.bits_per_pixel) {
  324. case 1:
  325. /* Monochrome */
  326. outl(inl(TX3912_VIDEO_CTRL1) & ~TX3912_VIDEO_CTRL1_BITSEL_MASK,
  327. TX3912_VIDEO_CTRL1);
  328. break;
  329. case 4:
  330. /* 4-bit gray */
  331. outl(inl(TX3912_VIDEO_CTRL1) & ~TX3912_VIDEO_CTRL1_BITSEL_MASK,
  332. TX3912_VIDEO_CTRL1);
  333. outl(inl(TX3912_VIDEO_CTRL1) |
  334. TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
  335. TX3912_VIDEO_CTRL1);
  336. break;
  337. case 8:
  338. /* 8-bit color */
  339. outl(inl(TX3912_VIDEO_CTRL1) & ~TX3912_VIDEO_CTRL1_BITSEL_MASK,
  340. TX3912_VIDEO_CTRL1);
  341. outl(inl(TX3912_VIDEO_CTRL1) |
  342. TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
  343. TX3912_VIDEO_CTRL1);
  344. break;
  345. case 2:
  346. default:
  347. /* 2-bit gray */
  348. outl(inl(TX3912_VIDEO_CTRL1) & ~TX3912_VIDEO_CTRL1_BITSEL_MASK,
  349. TX3912_VIDEO_CTRL1);
  350. outl(inl(TX3912_VIDEO_CTRL1) |
  351. TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
  352. TX3912_VIDEO_CTRL1);
  353. break;
  354. }
  355. /* Enable the video clock */
  356. outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
  357. TX3912_CLK_CTRL);
  358. /* Unfreeze video logic and enable DF toggle */
  359. outl(inl(TX3912_VIDEO_CTRL1) &
  360. ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE),
  361. TX3912_VIDEO_CTRL1);
  362. udelay(200);
  363. /* Clear the framebuffer */
  364. memset((void *) tx3912fb_vaddr, 0xff, tx3912fb_size);
  365. udelay(200);
  366. /* Enable the video logic */
  367. outl(inl(TX3912_VIDEO_CTRL1) |
  368. (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
  369. TX3912_VIDEO_CTRL1);
  370. strcpy(fb_info.modename, TX3912FB_NAME);
  371. fb_info.changevar = NULL;
  372. fb_info.node = -1;
  373. fb_info.fbops = &tx3912fb_ops;
  374. fb_info.disp = &global_disp;
  375. fb_info.switch_con = &tx3912fbcon_switch;
  376. fb_info.updatevar = &tx3912fbcon_updatevar;
  377. fb_info.blank = &tx3912fbcon_blank;
  378. fb_info.flags = FBINFO_FLAG_DEFAULT;
  379. tx3912fb_set_var(&tx3912fb_info, -1, &fb_info);
  380. if (register_framebuffer(&fb_info) < 0)
  381. return -1;
  382. printk (KERN_INFO "fb%d: TX3912 frame buffer using %uKB.n",
  383. GET_FB_IDX(fb_info.node), (u_int) (tx3912fb_size >> 10));
  384. return 0;
  385. }
  386. /*
  387.  * Switch the console to be the framebuffer
  388.  */
  389. static int tx3912fbcon_switch(int con, struct fb_info *info)
  390. {
  391. /* Save off the color map if needed */
  392. if (fb_display[currcon].cmap.len)
  393. fb_get_cmap(&fb_display[currcon].cmap, 1,
  394. tx3912fb_getcolreg, info);
  395. /* Make the switch */
  396. currcon = con;
  397. /* Install new colormap */
  398. tx3912fb_install_cmap(con, info);
  399. return 0;
  400. }
  401. /*
  402.  * Update variable structure
  403.  */
  404. static int tx3912fbcon_updatevar(int con, struct fb_info *info)
  405. {
  406. /* Nothing */
  407. return 0;
  408. }
  409. /*
  410.  * Blank the display
  411.  */
  412. static void tx3912fbcon_blank(int blank, struct fb_info *info)
  413. {
  414. /* FIXME */
  415. printk("tx3912fbcon_blankn");
  416. }
  417. /*
  418.  * Read a single color register
  419.  */
  420. static int tx3912fb_getcolreg(u_int regno, u_int *red, u_int *green,
  421. u_int *blue, u_int *transp, struct fb_info *info)
  422. {
  423. if (regno > 255)
  424. return 1;
  425. #if FB_IS_GREY
  426. {
  427. u_int grey;
  428.             
  429. grey = regno * 255 / 15;
  430. #if FB_IS_INVERSE
  431. grey ^= 255;
  432. #endif
  433. grey |= grey << 8;
  434. *red = grey;
  435. *green = grey;
  436. *blue = grey;
  437. }
  438. #else
  439. *red = (palette[regno].red<<8) | palette[regno].red;
  440. *green = (palette[regno].green<<8) | palette[regno].green;
  441. *blue = (palette[regno].blue<<8) | palette[regno].blue;
  442. #endif
  443. *transp = 0;
  444. return 0;
  445. }
  446. /*
  447.  * Set a single color register
  448.  */
  449. static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  450. u_int transp, struct fb_info *info)
  451. {
  452. if (regno > 255)
  453. return 1;
  454. #ifdef FBCON_HAS_CFB8
  455. if( regno < 16 )
  456. fbcon_cmap.cfb8[regno] = ((red & 0xe000) >> 8)
  457. | ((green & 0xe000) >> 11)
  458. | ((blue & 0xc000) >> 14);
  459. #endif 
  460. red >>= 8;
  461. green >>= 8;
  462. blue >>= 8;
  463. palette[regno].red = red;
  464. palette[regno].green = green;
  465. palette[regno].blue = blue;
  466. return 0;
  467. }
  468. /*
  469.  * Install the color map
  470.  */
  471. static void tx3912fb_install_cmap(int con, struct fb_info *info)
  472. {
  473. if (con != currcon)
  474. return;
  475. if (fb_display[con].cmap.len)
  476. fb_set_cmap(&fb_display[con].cmap, 1, tx3912fb_setcolreg, info);
  477. else
  478. fb_set_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel), 1, tx3912fb_setcolreg, info);
  479. }
  480. MODULE_LICENSE("GPL");