fb-puv3.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /*
  2. * Frame Buffer Driver for PKUnity-v3 Unigfx
  3. * Code specific to PKUnity SoC and UniCore ISA
  4. *
  5. * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
  6. * Copyright (C) 2001-2010 Guan Xuetao
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/kernel.h>
  14. #include <linux/errno.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/clk.h>
  17. #include <linux/fb.h>
  18. #include <linux/init.h>
  19. #include <linux/console.h>
  20. #include <linux/mm.h>
  21. #include <asm/sizes.h>
  22. #include <asm/pgtable.h>
  23. #include <mach/hardware.h>
  24. /* Platform_data reserved for unifb registers. */
  25. #define UNIFB_REGS_NUM 10
  26. /* RAM reserved for the frame buffer. */
  27. #define UNIFB_MEMSIZE (SZ_4M) /* 4 MB for 1024*768*32b */
  28. /*
  29. * cause UNIGFX don not have EDID
  30. * all the modes are organized as follow
  31. */
  32. static const struct fb_videomode unifb_modes[] = {
  33. /* 0 640x480-60 VESA */
  34. { "640x480@60", 60, 640, 480, 25175000, 48, 16, 34, 10, 96, 1,
  35. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  36. /* 1 640x480-75 VESA */
  37. { "640x480@75", 75, 640, 480, 31500000, 120, 16, 18, 1, 64, 1,
  38. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  39. /* 2 800x600-60 VESA */
  40. { "800x600@60", 60, 800, 600, 40000000, 88, 40, 26, 1, 128, 1,
  41. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  42. /* 3 800x600-75 VESA */
  43. { "800x600@75", 75, 800, 600, 49500000, 160, 16, 23, 1, 80, 1,
  44. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  45. /* 4 1024x768-60 VESA */
  46. { "1024x768@60", 60, 1024, 768, 65000000, 160, 24, 34, 3, 136, 1,
  47. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  48. /* 5 1024x768-75 VESA */
  49. { "1024x768@75", 75, 1024, 768, 78750000, 176, 16, 30, 1, 96, 1,
  50. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  51. /* 6 1280x960-60 VESA */
  52. { "1280x960@60", 60, 1280, 960, 108000000, 312, 96, 38, 1, 112, 1,
  53. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  54. /* 7 1440x900-60 VESA */
  55. { "1440x900@60", 60, 1440, 900, 106500000, 232, 80, 30, 3, 152, 1,
  56. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  57. /* 8 FIXME 9 1024x600-60 VESA UNTESTED */
  58. { "1024x600@60", 60, 1024, 600, 50650000, 160, 24, 26, 1, 136, 1,
  59. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  60. /* 9 FIXME 10 1024x600-75 VESA UNTESTED */
  61. { "1024x600@75", 75, 1024, 600, 61500000, 176, 16, 23, 1, 96, 1,
  62. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  63. /* 10 FIXME 11 1366x768-60 VESA UNTESTED */
  64. { "1366x768@60", 60, 1366, 768, 85500000, 256, 58, 18, 1, 112, 3,
  65. 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  66. };
  67. static struct fb_var_screeninfo unifb_default = {
  68. .xres = 640,
  69. .yres = 480,
  70. .xres_virtual = 640,
  71. .yres_virtual = 480,
  72. .bits_per_pixel = 16,
  73. .red = { 11, 5, 0 },
  74. .green = { 5, 6, 0 },
  75. .blue = { 0, 5, 0 },
  76. .activate = FB_ACTIVATE_NOW,
  77. .height = -1,
  78. .width = -1,
  79. .pixclock = 25175000,
  80. .left_margin = 48,
  81. .right_margin = 16,
  82. .upper_margin = 33,
  83. .lower_margin = 10,
  84. .hsync_len = 96,
  85. .vsync_len = 2,
  86. .vmode = FB_VMODE_NONINTERLACED,
  87. };
  88. static struct fb_fix_screeninfo unifb_fix = {
  89. .id = "UNIGFX FB",
  90. .type = FB_TYPE_PACKED_PIXELS,
  91. .visual = FB_VISUAL_TRUECOLOR,
  92. .xpanstep = 1,
  93. .ypanstep = 1,
  94. .ywrapstep = 1,
  95. .accel = FB_ACCEL_NONE,
  96. };
  97. static void unifb_sync(struct fb_info *info)
  98. {
  99. /* TODO: may, this can be replaced by interrupt */
  100. int cnt;
  101. for (cnt = 0; cnt < 0x10000000; cnt++) {
  102. if (readl(UGE_COMMAND) & 0x1000000)
  103. return;
  104. }
  105. if (cnt > 0x8000000)
  106. dev_warn(info->device, "Warning: UniGFX GE time out ...\n");
  107. }
  108. static void unifb_prim_fillrect(struct fb_info *info,
  109. const struct fb_fillrect *region)
  110. {
  111. int awidth = region->width;
  112. int aheight = region->height;
  113. int m_iBpp = info->var.bits_per_pixel;
  114. int screen_width = info->var.xres;
  115. int src_sel = 1; /* from fg_color */
  116. int pat_sel = 1;
  117. int src_x0 = 0;
  118. int dst_x0 = region->dx;
  119. int src_y0 = 0;
  120. int dst_y0 = region->dy;
  121. int rop_alpha_sel = 0;
  122. int rop_alpha_code = 0xCC;
  123. int x_dir = 1;
  124. int y_dir = 1;
  125. int alpha_r = 0;
  126. int alpha_sel = 0;
  127. int dst_pitch = screen_width * (m_iBpp / 8);
  128. int dst_offset = dst_y0 * dst_pitch + dst_x0 * (m_iBpp / 8);
  129. int src_pitch = screen_width * (m_iBpp / 8);
  130. int src_offset = src_y0 * src_pitch + src_x0 * (m_iBpp / 8);
  131. unsigned int command = 0;
  132. int clip_region = 0;
  133. int clip_en = 0;
  134. int tp_en = 0;
  135. int fg_color = 0;
  136. int bottom = info->var.yres - 1;
  137. int right = info->var.xres - 1;
  138. int top = 0;
  139. bottom = (bottom << 16) | right;
  140. command = (rop_alpha_sel << 26) | (pat_sel << 18) | (src_sel << 16)
  141. | (x_dir << 20) | (y_dir << 21) | (command << 24)
  142. | (clip_region << 23) | (clip_en << 22) | (tp_en << 27);
  143. src_pitch = (dst_pitch << 16) | src_pitch;
  144. awidth = awidth | (aheight << 16);
  145. alpha_r = ((rop_alpha_code & 0xff) << 8) | (alpha_r & 0xff)
  146. | (alpha_sel << 16);
  147. src_x0 = (src_x0 & 0x1fff) | ((src_y0 & 0x1fff) << 16);
  148. dst_x0 = (dst_x0 & 0x1fff) | ((dst_y0 & 0x1fff) << 16);
  149. fg_color = region->color;
  150. unifb_sync(info);
  151. writel(((u32 *)(info->pseudo_palette))[fg_color], UGE_FCOLOR);
  152. writel(0, UGE_BCOLOR);
  153. writel(src_pitch, UGE_PITCH);
  154. writel(src_offset, UGE_SRCSTART);
  155. writel(dst_offset, UGE_DSTSTART);
  156. writel(awidth, UGE_WIDHEIGHT);
  157. writel(top, UGE_CLIP0);
  158. writel(bottom, UGE_CLIP1);
  159. writel(alpha_r, UGE_ROPALPHA);
  160. writel(src_x0, UGE_SRCXY);
  161. writel(dst_x0, UGE_DSTXY);
  162. writel(command, UGE_COMMAND);
  163. }
  164. static void unifb_fillrect(struct fb_info *info,
  165. const struct fb_fillrect *region)
  166. {
  167. struct fb_fillrect modded;
  168. int vxres, vyres;
  169. if (info->flags & FBINFO_HWACCEL_DISABLED) {
  170. sys_fillrect(info, region);
  171. return;
  172. }
  173. vxres = info->var.xres_virtual;
  174. vyres = info->var.yres_virtual;
  175. memcpy(&modded, region, sizeof(struct fb_fillrect));
  176. if (!modded.width || !modded.height ||
  177. modded.dx >= vxres || modded.dy >= vyres)
  178. return;
  179. if (modded.dx + modded.width > vxres)
  180. modded.width = vxres - modded.dx;
  181. if (modded.dy + modded.height > vyres)
  182. modded.height = vyres - modded.dy;
  183. unifb_prim_fillrect(info, &modded);
  184. }
  185. static void unifb_prim_copyarea(struct fb_info *info,
  186. const struct fb_copyarea *area)
  187. {
  188. int awidth = area->width;
  189. int aheight = area->height;
  190. int m_iBpp = info->var.bits_per_pixel;
  191. int screen_width = info->var.xres;
  192. int src_sel = 2; /* from mem */
  193. int pat_sel = 0;
  194. int src_x0 = area->sx;
  195. int dst_x0 = area->dx;
  196. int src_y0 = area->sy;
  197. int dst_y0 = area->dy;
  198. int rop_alpha_sel = 0;
  199. int rop_alpha_code = 0xCC;
  200. int x_dir = 1;
  201. int y_dir = 1;
  202. int alpha_r = 0;
  203. int alpha_sel = 0;
  204. int dst_pitch = screen_width * (m_iBpp / 8);
  205. int dst_offset = dst_y0 * dst_pitch + dst_x0 * (m_iBpp / 8);
  206. int src_pitch = screen_width * (m_iBpp / 8);
  207. int src_offset = src_y0 * src_pitch + src_x0 * (m_iBpp / 8);
  208. unsigned int command = 0;
  209. int clip_region = 0;
  210. int clip_en = 1;
  211. int tp_en = 0;
  212. int top = 0;
  213. int bottom = info->var.yres;
  214. int right = info->var.xres;
  215. int fg_color = 0;
  216. int bg_color = 0;
  217. if (src_x0 < 0)
  218. src_x0 = 0;
  219. if (src_y0 < 0)
  220. src_y0 = 0;
  221. if (src_y0 - dst_y0 > 0) {
  222. y_dir = 1;
  223. } else {
  224. y_dir = 0;
  225. src_offset = (src_y0 + aheight) * src_pitch +
  226. src_x0 * (m_iBpp / 8);
  227. dst_offset = (dst_y0 + aheight) * dst_pitch +
  228. dst_x0 * (m_iBpp / 8);
  229. src_y0 += aheight;
  230. dst_y0 += aheight;
  231. }
  232. command = (rop_alpha_sel << 26) | (pat_sel << 18) | (src_sel << 16) |
  233. (x_dir << 20) | (y_dir << 21) | (command << 24) |
  234. (clip_region << 23) | (clip_en << 22) | (tp_en << 27);
  235. src_pitch = (dst_pitch << 16) | src_pitch;
  236. awidth = awidth | (aheight << 16);
  237. alpha_r = ((rop_alpha_code & 0xff) << 8) | (alpha_r & 0xff) |
  238. (alpha_sel << 16);
  239. src_x0 = (src_x0 & 0x1fff) | ((src_y0 & 0x1fff) << 16);
  240. dst_x0 = (dst_x0 & 0x1fff) | ((dst_y0 & 0x1fff) << 16);
  241. bottom = (bottom << 16) | right;
  242. unifb_sync(info);
  243. writel(src_pitch, UGE_PITCH);
  244. writel(src_offset, UGE_SRCSTART);
  245. writel(dst_offset, UGE_DSTSTART);
  246. writel(awidth, UGE_WIDHEIGHT);
  247. writel(top, UGE_CLIP0);
  248. writel(bottom, UGE_CLIP1);
  249. writel(bg_color, UGE_BCOLOR);
  250. writel(fg_color, UGE_FCOLOR);
  251. writel(alpha_r, UGE_ROPALPHA);
  252. writel(src_x0, UGE_SRCXY);
  253. writel(dst_x0, UGE_DSTXY);
  254. writel(command, UGE_COMMAND);
  255. }
  256. static void unifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
  257. {
  258. struct fb_copyarea modded;
  259. u32 vxres, vyres;
  260. modded.sx = area->sx;
  261. modded.sy = area->sy;
  262. modded.dx = area->dx;
  263. modded.dy = area->dy;
  264. modded.width = area->width;
  265. modded.height = area->height;
  266. if (info->flags & FBINFO_HWACCEL_DISABLED) {
  267. sys_copyarea(info, area);
  268. return;
  269. }
  270. vxres = info->var.xres_virtual;
  271. vyres = info->var.yres_virtual;
  272. if (!modded.width || !modded.height ||
  273. modded.sx >= vxres || modded.sy >= vyres ||
  274. modded.dx >= vxres || modded.dy >= vyres)
  275. return;
  276. if (modded.sx + modded.width > vxres)
  277. modded.width = vxres - modded.sx;
  278. if (modded.dx + modded.width > vxres)
  279. modded.width = vxres - modded.dx;
  280. if (modded.sy + modded.height > vyres)
  281. modded.height = vyres - modded.sy;
  282. if (modded.dy + modded.height > vyres)
  283. modded.height = vyres - modded.dy;
  284. unifb_prim_copyarea(info, &modded);
  285. }
  286. static void unifb_imageblit(struct fb_info *info, const struct fb_image *image)
  287. {
  288. sys_imageblit(info, image);
  289. }
  290. static u_long get_line_length(int xres_virtual, int bpp)
  291. {
  292. u_long length;
  293. length = xres_virtual * bpp;
  294. length = (length + 31) & ~31;
  295. length >>= 3;
  296. return length;
  297. }
  298. /*
  299. * Setting the video mode has been split into two parts.
  300. * First part, xxxfb_check_var, must not write anything
  301. * to hardware, it should only verify and adjust var.
  302. * This means it doesn't alter par but it does use hardware
  303. * data from it to check this var.
  304. */
  305. static int unifb_check_var(struct fb_var_screeninfo *var,
  306. struct fb_info *info)
  307. {
  308. u_long line_length;
  309. /*
  310. * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
  311. * as FB_VMODE_SMOOTH_XPAN is only used internally
  312. */
  313. if (var->vmode & FB_VMODE_CONUPDATE) {
  314. var->vmode |= FB_VMODE_YWRAP;
  315. var->xoffset = info->var.xoffset;
  316. var->yoffset = info->var.yoffset;
  317. }
  318. /*
  319. * Some very basic checks
  320. */
  321. if (!var->xres)
  322. var->xres = 1;
  323. if (!var->yres)
  324. var->yres = 1;
  325. if (var->xres > var->xres_virtual)
  326. var->xres_virtual = var->xres;
  327. if (var->yres > var->yres_virtual)
  328. var->yres_virtual = var->yres;
  329. if (var->bits_per_pixel <= 1)
  330. var->bits_per_pixel = 1;
  331. else if (var->bits_per_pixel <= 8)
  332. var->bits_per_pixel = 8;
  333. else if (var->bits_per_pixel <= 16)
  334. var->bits_per_pixel = 16;
  335. else if (var->bits_per_pixel <= 24)
  336. var->bits_per_pixel = 24;
  337. else if (var->bits_per_pixel <= 32)
  338. var->bits_per_pixel = 32;
  339. else
  340. return -EINVAL;
  341. if (var->xres_virtual < var->xoffset + var->xres)
  342. var->xres_virtual = var->xoffset + var->xres;
  343. if (var->yres_virtual < var->yoffset + var->yres)
  344. var->yres_virtual = var->yoffset + var->yres;
  345. /*
  346. * Memory limit
  347. */
  348. line_length =
  349. get_line_length(var->xres_virtual, var->bits_per_pixel);
  350. if (line_length * var->yres_virtual > UNIFB_MEMSIZE)
  351. return -ENOMEM;
  352. /*
  353. * Now that we checked it we alter var. The reason being is that the
  354. * video mode passed in might not work but slight changes to it might
  355. * make it work. This way we let the user know what is acceptable.
  356. */
  357. switch (var->bits_per_pixel) {
  358. case 1:
  359. case 8:
  360. var->red.offset = 0;
  361. var->red.length = 8;
  362. var->green.offset = 0;
  363. var->green.length = 8;
  364. var->blue.offset = 0;
  365. var->blue.length = 8;
  366. var->transp.offset = 0;
  367. var->transp.length = 0;
  368. break;
  369. case 16: /* RGBA 5551 */
  370. if (var->transp.length) {
  371. var->red.offset = 0;
  372. var->red.length = 5;
  373. var->green.offset = 5;
  374. var->green.length = 5;
  375. var->blue.offset = 10;
  376. var->blue.length = 5;
  377. var->transp.offset = 15;
  378. var->transp.length = 1;
  379. } else { /* RGB 565 */
  380. var->red.offset = 11;
  381. var->red.length = 5;
  382. var->green.offset = 5;
  383. var->green.length = 6;
  384. var->blue.offset = 0;
  385. var->blue.length = 5;
  386. var->transp.offset = 0;
  387. var->transp.length = 0;
  388. }
  389. break;
  390. case 24: /* RGB 888 */
  391. var->red.offset = 0;
  392. var->red.length = 8;
  393. var->green.offset = 8;
  394. var->green.length = 8;
  395. var->blue.offset = 16;
  396. var->blue.length = 8;
  397. var->transp.offset = 0;
  398. var->transp.length = 0;
  399. break;
  400. case 32: /* RGBA 8888 */
  401. var->red.offset = 16;
  402. var->red.length = 8;
  403. var->green.offset = 8;
  404. var->green.length = 8;
  405. var->blue.offset = 0;
  406. var->blue.length = 8;
  407. var->transp.offset = 24;
  408. var->transp.length = 8;
  409. break;
  410. }
  411. var->red.msb_right = 0;
  412. var->green.msb_right = 0;
  413. var->blue.msb_right = 0;
  414. var->transp.msb_right = 0;
  415. return 0;
  416. }
  417. /*
  418. * This routine actually sets the video mode. It's in here where we
  419. * the hardware state info->par and fix which can be affected by the
  420. * change in par. For this driver it doesn't do much.
  421. */
  422. static int unifb_set_par(struct fb_info *info)
  423. {
  424. int hTotal, vTotal, hSyncStart, hSyncEnd, vSyncStart, vSyncEnd;
  425. int format;
  426. #ifdef CONFIG_PUV3_PM
  427. struct clk *clk_vga;
  428. u32 pixclk = 0;
  429. int i;
  430. for (i = 0; i <= 10; i++) {
  431. if (info->var.xres == unifb_modes[i].xres
  432. && info->var.yres == unifb_modes[i].yres
  433. && info->var.upper_margin == unifb_modes[i].upper_margin
  434. && info->var.lower_margin == unifb_modes[i].lower_margin
  435. && info->var.left_margin == unifb_modes[i].left_margin
  436. && info->var.right_margin == unifb_modes[i].right_margin
  437. && info->var.hsync_len == unifb_modes[i].hsync_len
  438. && info->var.vsync_len == unifb_modes[i].vsync_len) {
  439. pixclk = unifb_modes[i].pixclock;
  440. break;
  441. }
  442. }
  443. /* set clock rate */
  444. clk_vga = clk_get(info->device, "VGA_CLK");
  445. if (clk_vga == ERR_PTR(-ENOENT))
  446. return -ENOENT;
  447. if (pixclk != 0) {
  448. if (clk_set_rate(clk_vga, pixclk)) { /* set clock failed */
  449. info->fix = unifb_fix;
  450. info->var = unifb_default;
  451. if (clk_set_rate(clk_vga, unifb_default.pixclock))
  452. return -EINVAL;
  453. }
  454. }
  455. #endif
  456. info->fix.line_length = get_line_length(info->var.xres_virtual,
  457. info->var.bits_per_pixel);
  458. hSyncStart = info->var.xres + info->var.right_margin;
  459. hSyncEnd = hSyncStart + info->var.hsync_len;
  460. hTotal = hSyncEnd + info->var.left_margin;
  461. vSyncStart = info->var.yres + info->var.lower_margin;
  462. vSyncEnd = vSyncStart + info->var.vsync_len;
  463. vTotal = vSyncEnd + info->var.upper_margin;
  464. switch (info->var.bits_per_pixel) {
  465. case 8:
  466. format = UDE_CFG_DST8;
  467. break;
  468. case 16:
  469. format = UDE_CFG_DST16;
  470. break;
  471. case 24:
  472. format = UDE_CFG_DST24;
  473. break;
  474. case 32:
  475. format = UDE_CFG_DST32;
  476. break;
  477. default:
  478. return -EINVAL;
  479. }
  480. writel(info->fix.smem_start, UDE_FSA);
  481. writel(info->var.yres, UDE_LS);
  482. writel(get_line_length(info->var.xres,
  483. info->var.bits_per_pixel) >> 3, UDE_PS);
  484. /* >> 3 for hardware required. */
  485. writel((hTotal << 16) | (info->var.xres), UDE_HAT);
  486. writel(((hTotal - 1) << 16) | (info->var.xres - 1), UDE_HBT);
  487. writel(((hSyncEnd - 1) << 16) | (hSyncStart - 1), UDE_HST);
  488. writel((vTotal << 16) | (info->var.yres), UDE_VAT);
  489. writel(((vTotal - 1) << 16) | (info->var.yres - 1), UDE_VBT);
  490. writel(((vSyncEnd - 1) << 16) | (vSyncStart - 1), UDE_VST);
  491. writel(UDE_CFG_GDEN_ENABLE | UDE_CFG_TIMEUP_ENABLE
  492. | format | 0xC0000001, UDE_CFG);
  493. return 0;
  494. }
  495. /*
  496. * Set a single color register. The values supplied are already
  497. * rounded down to the hardware's capabilities (according to the
  498. * entries in the var structure). Return != 0 for invalid regno.
  499. */
  500. static int unifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  501. u_int transp, struct fb_info *info)
  502. {
  503. if (regno >= 256) /* no. of hw registers */
  504. return 1;
  505. /* grayscale works only partially under directcolor */
  506. if (info->var.grayscale) {
  507. /* grayscale = 0.30*R + 0.59*G + 0.11*B */
  508. red = green = blue =
  509. (red * 77 + green * 151 + blue * 28) >> 8;
  510. }
  511. #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
  512. switch (info->fix.visual) {
  513. case FB_VISUAL_TRUECOLOR:
  514. case FB_VISUAL_PSEUDOCOLOR:
  515. red = CNVT_TOHW(red, info->var.red.length);
  516. green = CNVT_TOHW(green, info->var.green.length);
  517. blue = CNVT_TOHW(blue, info->var.blue.length);
  518. transp = CNVT_TOHW(transp, info->var.transp.length);
  519. break;
  520. case FB_VISUAL_DIRECTCOLOR:
  521. red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */
  522. green = CNVT_TOHW(green, 8);
  523. blue = CNVT_TOHW(blue, 8);
  524. /* hey, there is bug in transp handling... */
  525. transp = CNVT_TOHW(transp, 8);
  526. break;
  527. }
  528. #undef CNVT_TOHW
  529. /* Truecolor has hardware independent palette */
  530. if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
  531. u32 v;
  532. if (regno >= 16)
  533. return 1;
  534. v = (red << info->var.red.offset) |
  535. (green << info->var.green.offset) |
  536. (blue << info->var.blue.offset) |
  537. (transp << info->var.transp.offset);
  538. switch (info->var.bits_per_pixel) {
  539. case 8:
  540. break;
  541. case 16:
  542. case 24:
  543. case 32:
  544. ((u32 *) (info->pseudo_palette))[regno] = v;
  545. break;
  546. default:
  547. return 1;
  548. }
  549. return 0;
  550. }
  551. return 0;
  552. }
  553. /*
  554. * Pan or Wrap the Display
  555. *
  556. * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
  557. */
  558. static int unifb_pan_display(struct fb_var_screeninfo *var,
  559. struct fb_info *info)
  560. {
  561. if (var->vmode & FB_VMODE_YWRAP) {
  562. if (var->yoffset < 0
  563. || var->yoffset >= info->var.yres_virtual
  564. || var->xoffset)
  565. return -EINVAL;
  566. } else {
  567. if (var->xoffset + info->var.xres > info->var.xres_virtual ||
  568. var->yoffset + info->var.yres > info->var.yres_virtual)
  569. return -EINVAL;
  570. }
  571. info->var.xoffset = var->xoffset;
  572. info->var.yoffset = var->yoffset;
  573. if (var->vmode & FB_VMODE_YWRAP)
  574. info->var.vmode |= FB_VMODE_YWRAP;
  575. else
  576. info->var.vmode &= ~FB_VMODE_YWRAP;
  577. return 0;
  578. }
  579. int unifb_mmap(struct fb_info *info,
  580. struct vm_area_struct *vma)
  581. {
  582. vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  583. return vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len);
  584. }
  585. static struct fb_ops unifb_ops = {
  586. .fb_read = fb_sys_read,
  587. .fb_write = fb_sys_write,
  588. .fb_check_var = unifb_check_var,
  589. .fb_set_par = unifb_set_par,
  590. .fb_setcolreg = unifb_setcolreg,
  591. .fb_pan_display = unifb_pan_display,
  592. .fb_fillrect = unifb_fillrect,
  593. .fb_copyarea = unifb_copyarea,
  594. .fb_imageblit = unifb_imageblit,
  595. .fb_mmap = unifb_mmap,
  596. };
  597. /*
  598. * Initialisation
  599. */
  600. static int unifb_probe(struct platform_device *dev)
  601. {
  602. struct fb_info *info;
  603. u32 unifb_regs[UNIFB_REGS_NUM];
  604. int retval = -ENOMEM;
  605. struct resource *iomem;
  606. void *videomemory;
  607. videomemory = (void *)__get_free_pages(GFP_KERNEL | __GFP_COMP,
  608. get_order(UNIFB_MEMSIZE));
  609. if (!videomemory)
  610. goto err;
  611. memset(videomemory, 0, UNIFB_MEMSIZE);
  612. unifb_fix.smem_start = virt_to_phys(videomemory);
  613. unifb_fix.smem_len = UNIFB_MEMSIZE;
  614. iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
  615. unifb_fix.mmio_start = iomem->start;
  616. info = framebuffer_alloc(sizeof(u32)*256, &dev->dev);
  617. if (!info)
  618. goto err;
  619. info->screen_base = (char __iomem *)videomemory;
  620. info->fbops = &unifb_ops;
  621. retval = fb_find_mode(&info->var, info, NULL,
  622. unifb_modes, 10, &unifb_modes[0], 16);
  623. if (!retval || (retval == 4))
  624. info->var = unifb_default;
  625. info->fix = unifb_fix;
  626. info->pseudo_palette = info->par;
  627. info->par = NULL;
  628. info->flags = FBINFO_FLAG_DEFAULT;
  629. #ifdef FB_ACCEL_PUV3_UNIGFX
  630. info->fix.accel = FB_ACCEL_PUV3_UNIGFX;
  631. #endif
  632. retval = fb_alloc_cmap(&info->cmap, 256, 0);
  633. if (retval < 0)
  634. goto err1;
  635. retval = register_framebuffer(info);
  636. if (retval < 0)
  637. goto err2;
  638. platform_set_drvdata(dev, info);
  639. platform_device_add_data(dev, unifb_regs, sizeof(u32) * UNIFB_REGS_NUM);
  640. fb_info(info, "Virtual frame buffer device, using %dM of video memory\n",
  641. UNIFB_MEMSIZE >> 20);
  642. return 0;
  643. err2:
  644. fb_dealloc_cmap(&info->cmap);
  645. err1:
  646. framebuffer_release(info);
  647. err:
  648. return retval;
  649. }
  650. static int unifb_remove(struct platform_device *dev)
  651. {
  652. struct fb_info *info = platform_get_drvdata(dev);
  653. if (info) {
  654. unregister_framebuffer(info);
  655. fb_dealloc_cmap(&info->cmap);
  656. framebuffer_release(info);
  657. }
  658. return 0;
  659. }
  660. #ifdef CONFIG_PM
  661. static int unifb_resume(struct platform_device *dev)
  662. {
  663. int rc = 0;
  664. u32 *unifb_regs = dev->dev.platform_data;
  665. if (dev->dev.power.power_state.event == PM_EVENT_ON)
  666. return 0;
  667. console_lock();
  668. if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
  669. writel(unifb_regs[0], UDE_FSA);
  670. writel(unifb_regs[1], UDE_LS);
  671. writel(unifb_regs[2], UDE_PS);
  672. writel(unifb_regs[3], UDE_HAT);
  673. writel(unifb_regs[4], UDE_HBT);
  674. writel(unifb_regs[5], UDE_HST);
  675. writel(unifb_regs[6], UDE_VAT);
  676. writel(unifb_regs[7], UDE_VBT);
  677. writel(unifb_regs[8], UDE_VST);
  678. writel(unifb_regs[9], UDE_CFG);
  679. }
  680. dev->dev.power.power_state = PMSG_ON;
  681. console_unlock();
  682. return rc;
  683. }
  684. static int unifb_suspend(struct platform_device *dev, pm_message_t mesg)
  685. {
  686. u32 *unifb_regs = dev->dev.platform_data;
  687. unifb_regs[0] = readl(UDE_FSA);
  688. unifb_regs[1] = readl(UDE_LS);
  689. unifb_regs[2] = readl(UDE_PS);
  690. unifb_regs[3] = readl(UDE_HAT);
  691. unifb_regs[4] = readl(UDE_HBT);
  692. unifb_regs[5] = readl(UDE_HST);
  693. unifb_regs[6] = readl(UDE_VAT);
  694. unifb_regs[7] = readl(UDE_VBT);
  695. unifb_regs[8] = readl(UDE_VST);
  696. unifb_regs[9] = readl(UDE_CFG);
  697. if (mesg.event == dev->dev.power.power_state.event)
  698. return 0;
  699. switch (mesg.event) {
  700. case PM_EVENT_FREEZE: /* about to take snapshot */
  701. case PM_EVENT_PRETHAW: /* before restoring snapshot */
  702. goto done;
  703. }
  704. console_lock();
  705. /* do nothing... */
  706. console_unlock();
  707. done:
  708. dev->dev.power.power_state = mesg;
  709. return 0;
  710. }
  711. #else
  712. #define unifb_resume NULL
  713. #define unifb_suspend NULL
  714. #endif
  715. static struct platform_driver unifb_driver = {
  716. .probe = unifb_probe,
  717. .remove = unifb_remove,
  718. .resume = unifb_resume,
  719. .suspend = unifb_suspend,
  720. .driver = {
  721. .name = "PKUnity-v3-UNIGFX",
  722. },
  723. };
  724. static int __init unifb_init(void)
  725. {
  726. #ifndef MODULE
  727. if (fb_get_options("unifb", NULL))
  728. return -ENODEV;
  729. #endif
  730. return platform_driver_register(&unifb_driver);
  731. }
  732. module_init(unifb_init);
  733. static void __exit unifb_exit(void)
  734. {
  735. platform_driver_unregister(&unifb_driver);
  736. }
  737. module_exit(unifb_exit);
  738. MODULE_LICENSE("GPL v2");