tx3912fb.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/errno.h>
  16. #include <linux/string.h>
  17. #include <linux/tty.h>
  18. #include <linux/delay.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/init.h>
  21. #include <linux/pm.h>
  22. #include <linux/fb.h>
  23. #include <asm/io.h>
  24. #include <asm/bootinfo.h>
  25. #include <asm/uaccess.h>
  26. #include <asm/tx3912.h>
  27. #include <video/tx3912.h>
  28. /*
  29. * Frame buffer, palette and console structures
  30. */
  31. static struct fb_info fb_info;
  32. static u32 cfb8[16];
  33. static struct fb_fix_screeninfo tx3912fb_fix __initdata = {
  34. .id = "tx3912fb",
  35. .smem_len = ((240 * 320)/2),
  36. .type = FB_TYPE_PACKED_PIXELS,
  37. .visual = FB_VISUAL_TRUECOLOR,
  38. .xpanstep = 1,
  39. .ypanstep = 1,
  40. .ywrapstep = 1,
  41. .accel = FB_ACCEL_NONE,
  42. };
  43. static struct fb_var_screeninfo tx3912fb_var = {
  44. .xres = 240,
  45. .yres = 320,
  46. .xres_virtual = 240,
  47. .yres_virtual = 320,
  48. .bits_per_pixel =4,
  49. .red = { 0, 4, 0 }, /* ??? */
  50. .green = { 0, 4, 0 },
  51. .blue = { 0, 4, 0 },
  52. .activate = FB_ACTIVATE_NOW,
  53. .width = -1,
  54. .height = -1,
  55. .pixclock = 20000,
  56. .left_margin = 64,
  57. .right_margin = 64,
  58. .upper_margin = 32,
  59. .lower_margin = 32,
  60. .hsync_len = 64,
  61. .vsync_len = 2,
  62. .vmode = FB_VMODE_NONINTERLACED,
  63. };
  64. /*
  65. * Interface used by the world
  66. */
  67. int tx3912fb_init(void);
  68. static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
  69. u_int blue, u_int transp,
  70. struct fb_info *info);
  71. /*
  72. * Macros
  73. */
  74. #define get_line_length(xres_virtual, bpp) \
  75. (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3)
  76. /*
  77. * Frame buffer operations structure used by console driver
  78. */
  79. static struct fb_ops tx3912fb_ops = {
  80. .owner = THIS_MODULE,
  81. .fb_setcolreg = tx3912fb_setcolreg,
  82. .fb_fillrect = cfb_fillrect,
  83. .fb_copyarea = cfb_copyarea,
  84. .fb_imageblit = cfb_imageblit,
  85. .fb_cursor = soft_cursor,
  86. };
  87. static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  88. {
  89. /*
  90. * Memory limit
  91. */
  92. line_length =
  93. get_line_length(var->xres_virtual, var->bits_per_pixel);
  94. if ((line_length * var->yres_virtual) > info->fix.smem_len)
  95. return -ENOMEM;
  96. return 0;
  97. }
  98. static int tx3912fb_set_par(struct fb_info *info)
  99. {
  100. u_long tx3912fb_paddr = 0;
  101. /* Disable the video logic */
  102. outl(inl(TX3912_VIDEO_CTRL1) &
  103. ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
  104. TX3912_VIDEO_CTRL1);
  105. udelay(200);
  106. /* Set start address for DMA transfer */
  107. outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
  108. /* Set end address for DMA transfer */
  109. outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
  110. /* Set the pixel depth */
  111. switch (info->var.bits_per_pixel) {
  112. case 1:
  113. /* Monochrome */
  114. outl(inl(TX3912_VIDEO_CTRL1) &
  115. ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
  116. info->fix.visual = FB_VISUAL_MONO10;
  117. break;
  118. case 4:
  119. /* 4-bit gray */
  120. outl(inl(TX3912_VIDEO_CTRL1) &
  121. ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
  122. outl(inl(TX3912_VIDEO_CTRL1) |
  123. TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
  124. TX3912_VIDEO_CTRL1);
  125. info->fix.visual = FB_VISUAL_TRUECOLOR;
  126. break;
  127. case 8:
  128. /* 8-bit color */
  129. outl(inl(TX3912_VIDEO_CTRL1) &
  130. ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
  131. outl(inl(TX3912_VIDEO_CTRL1) |
  132. TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
  133. TX3912_VIDEO_CTRL1);
  134. info->fix.visual = FB_VISUAL_TRUECOLOR;
  135. break;
  136. case 2:
  137. default:
  138. /* 2-bit gray */
  139. outl(inl(TX3912_VIDEO_CTRL1) &
  140. ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
  141. outl(inl(TX3912_VIDEO_CTRL1) |
  142. TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
  143. TX3912_VIDEO_CTRL1);
  144. info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
  145. break;
  146. }
  147. /* Enable the video clock */
  148. outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
  149. TX3912_CLK_CTRL);
  150. /* Unfreeze video logic and enable DF toggle */
  151. outl(inl(TX3912_VIDEO_CTRL1) &
  152. ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME |
  153. TX3912_VIDEO_CTRL1_DFMODE)
  154. , TX3912_VIDEO_CTRL1);
  155. udelay(200);
  156. /* Enable the video logic */
  157. outl(inl(TX3912_VIDEO_CTRL1) |
  158. (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
  159. TX3912_VIDEO_CTRL1);
  160. info->fix.line_length = get_line_length(var->xres_virtual,
  161. var->bits_per_pixel);
  162. }
  163. /*
  164. * Set a single color register
  165. */
  166. static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
  167. u_int blue, u_int transp,
  168. struct fb_info *info)
  169. {
  170. if (regno > 255)
  171. return 1;
  172. if (regno < 16)
  173. ((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8)
  174. | ((green & 0xe000) >> 11)
  175. | ((blue & 0xc000) >> 14);
  176. return 0;
  177. }
  178. int __init tx3912fb_setup(char *options);
  179. /*
  180. * Initialization of the framebuffer
  181. */
  182. int __init tx3912fb_init(void)
  183. {
  184. u_long tx3912fb_paddr = 0;
  185. int size = (info->var.bits_per_pixel == 8) ? 256 : 16;
  186. char *option = NULL;
  187. if (fb_get_options("tx3912fb", &option))
  188. return -ENODEV;
  189. tx3912fb_setup(option);
  190. /* Disable the video logic */
  191. outl(inl(TX3912_VIDEO_CTRL1) &
  192. ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
  193. TX3912_VIDEO_CTRL1);
  194. udelay(200);
  195. /* Set start address for DMA transfer */
  196. outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
  197. /* Set end address for DMA transfer */
  198. outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
  199. /* Set the pixel depth */
  200. switch (tx3912fb_var.bits_per_pixel) {
  201. case 1:
  202. /* Monochrome */
  203. outl(inl(TX3912_VIDEO_CTRL1) &
  204. ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
  205. tx3912fb_fix.visual = FB_VISUAL_MONO10;
  206. break;
  207. case 4:
  208. /* 4-bit gray */
  209. outl(inl(TX3912_VIDEO_CTRL1) &
  210. ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
  211. outl(inl(TX3912_VIDEO_CTRL1) |
  212. TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
  213. TX3912_VIDEO_CTRL1);
  214. tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
  215. tx3912fb_fix.grayscale = 1;
  216. break;
  217. case 8:
  218. /* 8-bit color */
  219. outl(inl(TX3912_VIDEO_CTRL1) &
  220. ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
  221. outl(inl(TX3912_VIDEO_CTRL1) |
  222. TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
  223. TX3912_VIDEO_CTRL1);
  224. tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
  225. break;
  226. case 2:
  227. default:
  228. /* 2-bit gray */
  229. outl(inl(TX3912_VIDEO_CTRL1) &
  230. ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
  231. outl(inl(TX3912_VIDEO_CTRL1) |
  232. TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
  233. TX3912_VIDEO_CTRL1);
  234. tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
  235. tx3912fb_fix.grayscale = 1;
  236. break;
  237. }
  238. /* Enable the video clock */
  239. outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
  240. TX3912_CLK_CTRL);
  241. /* Unfreeze video logic and enable DF toggle */
  242. outl(inl(TX3912_VIDEO_CTRL1) &
  243. ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE),
  244. TX3912_VIDEO_CTRL1);
  245. udelay(200);
  246. /* Clear the framebuffer */
  247. memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len);
  248. udelay(200);
  249. /* Enable the video logic */
  250. outl(inl(TX3912_VIDEO_CTRL1) |
  251. (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
  252. TX3912_VIDEO_CTRL1);
  253. /*
  254. * Memory limit
  255. */
  256. tx3912fb_fix.line_length =
  257. get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel);
  258. if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len)
  259. return -ENOMEM;
  260. fb_info.fbops = &tx3912fb_ops;
  261. fb_info.var = tx3912fb_var;
  262. fb_info.fix = tx3912fb_fix;
  263. fb_info.pseudo_palette = pseudo_palette;
  264. fb_info.flags = FBINFO_DEFAULT;
  265. /* Clear the framebuffer */
  266. memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len);
  267. udelay(200);
  268. fb_alloc_cmap(&info->cmap, size, 0);
  269. if (register_framebuffer(&fb_info) < 0)
  270. return -1;
  271. printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n",
  272. fb_info.node, (u_int) (fb_info.fix.smem_len >> 10));
  273. return 0;
  274. }
  275. int __init tx3912fb_setup(char *options)
  276. {
  277. char *this_opt;
  278. if (!options || !*options)
  279. return 0;
  280. while ((this_opt = strsep(&options, ","))) {
  281. if (!strncmp(options, "bpp:", 4))
  282. tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0);
  283. }
  284. return 0;
  285. }
  286. module_init(tx3912fb_init);
  287. MODULE_LICENSE("GPL");