fb-puv3.c 22 KB

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