tx3912fb.c 8.2 KB

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