mmpfb.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. /*
  2. * linux/drivers/video/mmp/fb/mmpfb.c
  3. * Framebuffer driver for Marvell Display controller.
  4. *
  5. * Copyright (C) 2012 Marvell Technology Group Ltd.
  6. * Authors: Zhou Zhu <zzhu3@marvell.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. * more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along with
  19. * this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include <linux/module.h>
  23. #include <linux/dma-mapping.h>
  24. #include <linux/platform_device.h>
  25. #include "mmpfb.h"
  26. static int var_to_pixfmt(struct fb_var_screeninfo *var)
  27. {
  28. /*
  29. * Pseudocolor mode?
  30. */
  31. if (var->bits_per_pixel == 8)
  32. return PIXFMT_PSEUDOCOLOR;
  33. /*
  34. * Check for YUV422PLANAR.
  35. */
  36. if (var->bits_per_pixel == 16 && var->red.length == 8 &&
  37. var->green.length == 4 && var->blue.length == 4) {
  38. if (var->green.offset >= var->blue.offset)
  39. return PIXFMT_YUV422P;
  40. else
  41. return PIXFMT_YVU422P;
  42. }
  43. /*
  44. * Check for YUV420PLANAR.
  45. */
  46. if (var->bits_per_pixel == 12 && var->red.length == 8 &&
  47. var->green.length == 2 && var->blue.length == 2) {
  48. if (var->green.offset >= var->blue.offset)
  49. return PIXFMT_YUV420P;
  50. else
  51. return PIXFMT_YVU420P;
  52. }
  53. /*
  54. * Check for YUV422PACK.
  55. */
  56. if (var->bits_per_pixel == 16 && var->red.length == 16 &&
  57. var->green.length == 16 && var->blue.length == 16) {
  58. if (var->red.offset == 0)
  59. return PIXFMT_YUYV;
  60. else if (var->green.offset >= var->blue.offset)
  61. return PIXFMT_UYVY;
  62. else
  63. return PIXFMT_VYUY;
  64. }
  65. /*
  66. * Check for 565/1555.
  67. */
  68. if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
  69. var->green.length <= 6 && var->blue.length <= 5) {
  70. if (var->transp.length == 0) {
  71. if (var->red.offset >= var->blue.offset)
  72. return PIXFMT_RGB565;
  73. else
  74. return PIXFMT_BGR565;
  75. }
  76. }
  77. /*
  78. * Check for 888/A888.
  79. */
  80. if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
  81. var->green.length <= 8 && var->blue.length <= 8) {
  82. if (var->bits_per_pixel == 24 && var->transp.length == 0) {
  83. if (var->red.offset >= var->blue.offset)
  84. return PIXFMT_RGB888PACK;
  85. else
  86. return PIXFMT_BGR888PACK;
  87. }
  88. if (var->bits_per_pixel == 32 && var->transp.offset == 24) {
  89. if (var->red.offset >= var->blue.offset)
  90. return PIXFMT_RGBA888;
  91. else
  92. return PIXFMT_BGRA888;
  93. } else {
  94. if (var->red.offset >= var->blue.offset)
  95. return PIXFMT_RGB888UNPACK;
  96. else
  97. return PIXFMT_BGR888UNPACK;
  98. }
  99. /* fall through */
  100. }
  101. return -EINVAL;
  102. }
  103. static void pixfmt_to_var(struct fb_var_screeninfo *var, int pix_fmt)
  104. {
  105. switch (pix_fmt) {
  106. case PIXFMT_RGB565:
  107. var->bits_per_pixel = 16;
  108. var->red.offset = 11; var->red.length = 5;
  109. var->green.offset = 5; var->green.length = 6;
  110. var->blue.offset = 0; var->blue.length = 5;
  111. var->transp.offset = 0; var->transp.length = 0;
  112. break;
  113. case PIXFMT_BGR565:
  114. var->bits_per_pixel = 16;
  115. var->red.offset = 0; var->red.length = 5;
  116. var->green.offset = 5; var->green.length = 6;
  117. var->blue.offset = 11; var->blue.length = 5;
  118. var->transp.offset = 0; var->transp.length = 0;
  119. break;
  120. case PIXFMT_RGB888UNPACK:
  121. var->bits_per_pixel = 32;
  122. var->red.offset = 16; var->red.length = 8;
  123. var->green.offset = 8; var->green.length = 8;
  124. var->blue.offset = 0; var->blue.length = 8;
  125. var->transp.offset = 0; var->transp.length = 0;
  126. break;
  127. case PIXFMT_BGR888UNPACK:
  128. var->bits_per_pixel = 32;
  129. var->red.offset = 0; var->red.length = 8;
  130. var->green.offset = 8; var->green.length = 8;
  131. var->blue.offset = 16; var->blue.length = 8;
  132. var->transp.offset = 0; var->transp.length = 0;
  133. break;
  134. case PIXFMT_RGBA888:
  135. var->bits_per_pixel = 32;
  136. var->red.offset = 16; var->red.length = 8;
  137. var->green.offset = 8; var->green.length = 8;
  138. var->blue.offset = 0; var->blue.length = 8;
  139. var->transp.offset = 24; var->transp.length = 8;
  140. break;
  141. case PIXFMT_BGRA888:
  142. var->bits_per_pixel = 32;
  143. var->red.offset = 0; var->red.length = 8;
  144. var->green.offset = 8; var->green.length = 8;
  145. var->blue.offset = 16; var->blue.length = 8;
  146. var->transp.offset = 24; var->transp.length = 8;
  147. break;
  148. case PIXFMT_RGB888PACK:
  149. var->bits_per_pixel = 24;
  150. var->red.offset = 16; var->red.length = 8;
  151. var->green.offset = 8; var->green.length = 8;
  152. var->blue.offset = 0; var->blue.length = 8;
  153. var->transp.offset = 0; var->transp.length = 0;
  154. break;
  155. case PIXFMT_BGR888PACK:
  156. var->bits_per_pixel = 24;
  157. var->red.offset = 0; var->red.length = 8;
  158. var->green.offset = 8; var->green.length = 8;
  159. var->blue.offset = 16; var->blue.length = 8;
  160. var->transp.offset = 0; var->transp.length = 0;
  161. break;
  162. case PIXFMT_YUV420P:
  163. var->bits_per_pixel = 12;
  164. var->red.offset = 4; var->red.length = 8;
  165. var->green.offset = 2; var->green.length = 2;
  166. var->blue.offset = 0; var->blue.length = 2;
  167. var->transp.offset = 0; var->transp.length = 0;
  168. break;
  169. case PIXFMT_YVU420P:
  170. var->bits_per_pixel = 12;
  171. var->red.offset = 4; var->red.length = 8;
  172. var->green.offset = 0; var->green.length = 2;
  173. var->blue.offset = 2; var->blue.length = 2;
  174. var->transp.offset = 0; var->transp.length = 0;
  175. break;
  176. case PIXFMT_YUV422P:
  177. var->bits_per_pixel = 16;
  178. var->red.offset = 8; var->red.length = 8;
  179. var->green.offset = 4; var->green.length = 4;
  180. var->blue.offset = 0; var->blue.length = 4;
  181. var->transp.offset = 0; var->transp.length = 0;
  182. break;
  183. case PIXFMT_YVU422P:
  184. var->bits_per_pixel = 16;
  185. var->red.offset = 8; var->red.length = 8;
  186. var->green.offset = 0; var->green.length = 4;
  187. var->blue.offset = 4; var->blue.length = 4;
  188. var->transp.offset = 0; var->transp.length = 0;
  189. break;
  190. case PIXFMT_UYVY:
  191. var->bits_per_pixel = 16;
  192. var->red.offset = 8; var->red.length = 16;
  193. var->green.offset = 4; var->green.length = 16;
  194. var->blue.offset = 0; var->blue.length = 16;
  195. var->transp.offset = 0; var->transp.length = 0;
  196. break;
  197. case PIXFMT_VYUY:
  198. var->bits_per_pixel = 16;
  199. var->red.offset = 8; var->red.length = 16;
  200. var->green.offset = 0; var->green.length = 16;
  201. var->blue.offset = 4; var->blue.length = 16;
  202. var->transp.offset = 0; var->transp.length = 0;
  203. break;
  204. case PIXFMT_YUYV:
  205. var->bits_per_pixel = 16;
  206. var->red.offset = 0; var->red.length = 16;
  207. var->green.offset = 4; var->green.length = 16;
  208. var->blue.offset = 8; var->blue.length = 16;
  209. var->transp.offset = 0; var->transp.length = 0;
  210. break;
  211. case PIXFMT_PSEUDOCOLOR:
  212. var->bits_per_pixel = 8;
  213. var->red.offset = 0; var->red.length = 8;
  214. var->green.offset = 0; var->green.length = 8;
  215. var->blue.offset = 0; var->blue.length = 8;
  216. var->transp.offset = 0; var->transp.length = 0;
  217. break;
  218. }
  219. }
  220. /*
  221. * fb framework has its limitation:
  222. * 1. input color/output color is not seprated
  223. * 2. fb_videomode not include output color
  224. * so for fb usage, we keep a output format which is not changed
  225. * then it's added for mmpmode
  226. */
  227. static void fbmode_to_mmpmode(struct mmp_mode *mode,
  228. struct fb_videomode *videomode, int output_fmt)
  229. {
  230. u64 div_result = 1000000000000ll;
  231. mode->name = videomode->name;
  232. mode->refresh = videomode->refresh;
  233. mode->xres = videomode->xres;
  234. mode->yres = videomode->yres;
  235. do_div(div_result, videomode->pixclock);
  236. mode->pixclock_freq = (u32)div_result;
  237. mode->left_margin = videomode->left_margin;
  238. mode->right_margin = videomode->right_margin;
  239. mode->upper_margin = videomode->upper_margin;
  240. mode->lower_margin = videomode->lower_margin;
  241. mode->hsync_len = videomode->hsync_len;
  242. mode->vsync_len = videomode->vsync_len;
  243. mode->hsync_invert = !!(videomode->sync & FB_SYNC_HOR_HIGH_ACT);
  244. mode->vsync_invert = !!(videomode->sync & FB_SYNC_VERT_HIGH_ACT);
  245. /* no defined flag in fb, use vmode>>3*/
  246. mode->invert_pixclock = !!(videomode->vmode & 8);
  247. mode->pix_fmt_out = output_fmt;
  248. }
  249. static void mmpmode_to_fbmode(struct fb_videomode *videomode,
  250. struct mmp_mode *mode)
  251. {
  252. u64 div_result = 1000000000000ll;
  253. videomode->name = mode->name;
  254. videomode->refresh = mode->refresh;
  255. videomode->xres = mode->xres;
  256. videomode->yres = mode->yres;
  257. do_div(div_result, mode->pixclock_freq);
  258. videomode->pixclock = (u32)div_result;
  259. videomode->left_margin = mode->left_margin;
  260. videomode->right_margin = mode->right_margin;
  261. videomode->upper_margin = mode->upper_margin;
  262. videomode->lower_margin = mode->lower_margin;
  263. videomode->hsync_len = mode->hsync_len;
  264. videomode->vsync_len = mode->vsync_len;
  265. videomode->sync = (mode->hsync_invert ? FB_SYNC_HOR_HIGH_ACT : 0)
  266. | (mode->vsync_invert ? FB_SYNC_VERT_HIGH_ACT : 0);
  267. videomode->vmode = mode->invert_pixclock ? 8 : 0;
  268. }
  269. static int mmpfb_check_var(struct fb_var_screeninfo *var,
  270. struct fb_info *info)
  271. {
  272. struct mmpfb_info *fbi = info->par;
  273. if (var->bits_per_pixel == 8)
  274. return -EINVAL;
  275. /*
  276. * Basic geometry sanity checks.
  277. */
  278. if (var->xoffset + var->xres > var->xres_virtual)
  279. return -EINVAL;
  280. if (var->yoffset + var->yres > var->yres_virtual)
  281. return -EINVAL;
  282. /*
  283. * Check size of framebuffer.
  284. */
  285. if (var->xres_virtual * var->yres_virtual *
  286. (var->bits_per_pixel >> 3) > fbi->fb_size)
  287. return -EINVAL;
  288. return 0;
  289. }
  290. static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
  291. {
  292. return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
  293. }
  294. static u32 to_rgb(u16 red, u16 green, u16 blue)
  295. {
  296. red >>= 8;
  297. green >>= 8;
  298. blue >>= 8;
  299. return (red << 16) | (green << 8) | blue;
  300. }
  301. static int mmpfb_setcolreg(unsigned int regno, unsigned int red,
  302. unsigned int green, unsigned int blue,
  303. unsigned int trans, struct fb_info *info)
  304. {
  305. struct mmpfb_info *fbi = info->par;
  306. u32 val;
  307. if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
  308. val = chan_to_field(red, &info->var.red);
  309. val |= chan_to_field(green, &info->var.green);
  310. val |= chan_to_field(blue , &info->var.blue);
  311. fbi->pseudo_palette[regno] = val;
  312. }
  313. if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
  314. val = to_rgb(red, green, blue);
  315. /* TODO */
  316. }
  317. return 0;
  318. }
  319. static int mmpfb_pan_display(struct fb_var_screeninfo *var,
  320. struct fb_info *info)
  321. {
  322. struct mmpfb_info *fbi = info->par;
  323. struct mmp_addr addr;
  324. memset(&addr, 0, sizeof(addr));
  325. addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset)
  326. * var->bits_per_pixel / 8 + fbi->fb_start_dma;
  327. mmp_overlay_set_addr(fbi->overlay, &addr);
  328. return 0;
  329. }
  330. static int var_update(struct fb_info *info)
  331. {
  332. struct mmpfb_info *fbi = info->par;
  333. struct fb_var_screeninfo *var = &info->var;
  334. struct fb_videomode *m;
  335. int pix_fmt;
  336. /* set pix_fmt */
  337. pix_fmt = var_to_pixfmt(var);
  338. if (pix_fmt < 0)
  339. return -EINVAL;
  340. pixfmt_to_var(var, pix_fmt);
  341. fbi->pix_fmt = pix_fmt;
  342. /* set var according to best video mode*/
  343. m = (struct fb_videomode *)fb_match_mode(var, &info->modelist);
  344. if (!m) {
  345. dev_err(fbi->dev, "set par: no match mode, use best mode\n");
  346. m = (struct fb_videomode *)fb_find_best_mode(var,
  347. &info->modelist);
  348. fb_videomode_to_var(var, m);
  349. }
  350. memcpy(&fbi->mode, m, sizeof(struct fb_videomode));
  351. /* fix to 2* yres */
  352. var->yres_virtual = var->yres * 2;
  353. info->fix.visual = (pix_fmt == PIXFMT_PSEUDOCOLOR) ?
  354. FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
  355. info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
  356. info->fix.ypanstep = var->yres;
  357. return 0;
  358. }
  359. static void mmpfb_set_win(struct fb_info *info)
  360. {
  361. struct mmpfb_info *fbi = info->par;
  362. struct fb_var_screeninfo *var = &info->var;
  363. struct mmp_win win;
  364. u32 stride;
  365. memset(&win, 0, sizeof(win));
  366. win.xsrc = win.xdst = fbi->mode.xres;
  367. win.ysrc = win.ydst = fbi->mode.yres;
  368. win.pix_fmt = fbi->pix_fmt;
  369. stride = pixfmt_to_stride(win.pix_fmt);
  370. win.pitch[0] = var->xres_virtual * stride;
  371. win.pitch[1] = win.pitch[2] =
  372. (stride == 1) ? (var->xres_virtual >> 1) : 0;
  373. mmp_overlay_set_win(fbi->overlay, &win);
  374. }
  375. static int mmpfb_set_par(struct fb_info *info)
  376. {
  377. struct mmpfb_info *fbi = info->par;
  378. struct fb_var_screeninfo *var = &info->var;
  379. struct mmp_addr addr;
  380. struct mmp_mode mode;
  381. int ret;
  382. ret = var_update(info);
  383. if (ret != 0)
  384. return ret;
  385. /* set window/path according to new videomode */
  386. fbmode_to_mmpmode(&mode, &fbi->mode, fbi->output_fmt);
  387. mmp_path_set_mode(fbi->path, &mode);
  388. /* set window related info */
  389. mmpfb_set_win(info);
  390. /* set address always */
  391. memset(&addr, 0, sizeof(addr));
  392. addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset)
  393. * var->bits_per_pixel / 8 + fbi->fb_start_dma;
  394. mmp_overlay_set_addr(fbi->overlay, &addr);
  395. return 0;
  396. }
  397. static void mmpfb_power(struct mmpfb_info *fbi, int power)
  398. {
  399. struct mmp_addr addr;
  400. struct fb_var_screeninfo *var = &fbi->fb_info->var;
  401. /* for power on, always set address/window again */
  402. if (power) {
  403. /* set window related info */
  404. mmpfb_set_win(fbi->fb_info);
  405. /* set address always */
  406. memset(&addr, 0, sizeof(addr));
  407. addr.phys[0] = fbi->fb_start_dma +
  408. (var->yoffset * var->xres_virtual + var->xoffset)
  409. * var->bits_per_pixel / 8;
  410. mmp_overlay_set_addr(fbi->overlay, &addr);
  411. }
  412. mmp_overlay_set_onoff(fbi->overlay, power);
  413. }
  414. static int mmpfb_blank(int blank, struct fb_info *info)
  415. {
  416. struct mmpfb_info *fbi = info->par;
  417. mmpfb_power(fbi, (blank == FB_BLANK_UNBLANK));
  418. return 0;
  419. }
  420. static struct fb_ops mmpfb_ops = {
  421. .owner = THIS_MODULE,
  422. .fb_blank = mmpfb_blank,
  423. .fb_check_var = mmpfb_check_var,
  424. .fb_set_par = mmpfb_set_par,
  425. .fb_setcolreg = mmpfb_setcolreg,
  426. .fb_pan_display = mmpfb_pan_display,
  427. .fb_fillrect = cfb_fillrect,
  428. .fb_copyarea = cfb_copyarea,
  429. .fb_imageblit = cfb_imageblit,
  430. };
  431. static int modes_setup(struct mmpfb_info *fbi)
  432. {
  433. struct fb_videomode *videomodes;
  434. struct mmp_mode *mmp_modes;
  435. struct fb_info *info = fbi->fb_info;
  436. int videomode_num, i;
  437. /* get videomodes from path */
  438. videomode_num = mmp_path_get_modelist(fbi->path, &mmp_modes);
  439. if (!videomode_num) {
  440. dev_warn(fbi->dev, "can't get videomode num\n");
  441. return 0;
  442. }
  443. /* put videomode list to info structure */
  444. videomodes = kzalloc(sizeof(struct fb_videomode) * videomode_num,
  445. GFP_KERNEL);
  446. if (!videomodes) {
  447. dev_err(fbi->dev, "can't malloc video modes\n");
  448. return -ENOMEM;
  449. }
  450. for (i = 0; i < videomode_num; i++)
  451. mmpmode_to_fbmode(&videomodes[i], &mmp_modes[i]);
  452. fb_videomode_to_modelist(videomodes, videomode_num, &info->modelist);
  453. /* set videomode[0] as default mode */
  454. memcpy(&fbi->mode, &videomodes[0], sizeof(struct fb_videomode));
  455. fbi->output_fmt = mmp_modes[0].pix_fmt_out;
  456. fb_videomode_to_var(&info->var, &fbi->mode);
  457. mmp_path_set_mode(fbi->path, &mmp_modes[0]);
  458. kfree(videomodes);
  459. return videomode_num;
  460. }
  461. static int fb_info_setup(struct fb_info *info,
  462. struct mmpfb_info *fbi)
  463. {
  464. int ret = 0;
  465. /* Initialise static fb parameters.*/
  466. info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
  467. FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
  468. info->node = -1;
  469. strcpy(info->fix.id, fbi->name);
  470. info->fix.type = FB_TYPE_PACKED_PIXELS;
  471. info->fix.type_aux = 0;
  472. info->fix.xpanstep = 0;
  473. info->fix.ypanstep = info->var.yres;
  474. info->fix.ywrapstep = 0;
  475. info->fix.accel = FB_ACCEL_NONE;
  476. info->fix.smem_start = fbi->fb_start_dma;
  477. info->fix.smem_len = fbi->fb_size;
  478. info->fix.visual = (fbi->pix_fmt == PIXFMT_PSEUDOCOLOR) ?
  479. FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
  480. info->fix.line_length = info->var.xres_virtual *
  481. info->var.bits_per_pixel / 8;
  482. info->fbops = &mmpfb_ops;
  483. info->pseudo_palette = fbi->pseudo_palette;
  484. info->screen_base = fbi->fb_start;
  485. info->screen_size = fbi->fb_size;
  486. /* For FB framework: Allocate color map and Register framebuffer*/
  487. if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
  488. ret = -ENOMEM;
  489. return ret;
  490. }
  491. static void fb_info_clear(struct fb_info *info)
  492. {
  493. fb_dealloc_cmap(&info->cmap);
  494. }
  495. static int mmpfb_probe(struct platform_device *pdev)
  496. {
  497. struct mmp_buffer_driver_mach_info *mi;
  498. struct fb_info *info = 0;
  499. struct mmpfb_info *fbi = 0;
  500. int ret, modes_num;
  501. mi = pdev->dev.platform_data;
  502. if (mi == NULL) {
  503. dev_err(&pdev->dev, "no platform data defined\n");
  504. return -EINVAL;
  505. }
  506. /* initialize fb */
  507. info = framebuffer_alloc(sizeof(struct mmpfb_info), &pdev->dev);
  508. if (info == NULL)
  509. return -ENOMEM;
  510. fbi = info->par;
  511. if (!fbi) {
  512. ret = -EINVAL;
  513. goto failed;
  514. }
  515. /* init fb */
  516. fbi->fb_info = info;
  517. platform_set_drvdata(pdev, fbi);
  518. fbi->dev = &pdev->dev;
  519. fbi->name = mi->name;
  520. fbi->pix_fmt = mi->default_pixfmt;
  521. pixfmt_to_var(&info->var, fbi->pix_fmt);
  522. mutex_init(&fbi->access_ok);
  523. /* get display path by name */
  524. fbi->path = mmp_get_path(mi->path_name);
  525. if (!fbi->path) {
  526. dev_err(&pdev->dev, "can't get the path %s\n", mi->path_name);
  527. ret = -EINVAL;
  528. goto failed_destroy_mutex;
  529. }
  530. dev_info(fbi->dev, "path %s get\n", fbi->path->name);
  531. /* get overlay */
  532. fbi->overlay = mmp_path_get_overlay(fbi->path, mi->overlay_id);
  533. if (!fbi->overlay) {
  534. ret = -EINVAL;
  535. goto failed_destroy_mutex;
  536. }
  537. /* set fetch used */
  538. mmp_overlay_set_fetch(fbi->overlay, mi->dmafetch_id);
  539. modes_num = modes_setup(fbi);
  540. if (modes_num < 0) {
  541. ret = modes_num;
  542. goto failed_destroy_mutex;
  543. }
  544. /*
  545. * if get modes success, means not hotplug panels, use caculated buffer
  546. * or use default size
  547. */
  548. if (modes_num > 0) {
  549. /* fix to 2* yres */
  550. info->var.yres_virtual = info->var.yres * 2;
  551. /* Allocate framebuffer memory: size = modes xy *4 */
  552. fbi->fb_size = info->var.xres_virtual * info->var.yres_virtual
  553. * info->var.bits_per_pixel / 8;
  554. } else {
  555. fbi->fb_size = MMPFB_DEFAULT_SIZE;
  556. }
  557. fbi->fb_start = dma_alloc_coherent(&pdev->dev, PAGE_ALIGN(fbi->fb_size),
  558. &fbi->fb_start_dma, GFP_KERNEL);
  559. if (fbi->fb_start == NULL) {
  560. dev_err(&pdev->dev, "can't alloc framebuffer\n");
  561. ret = -ENOMEM;
  562. goto failed_destroy_mutex;
  563. }
  564. memset(fbi->fb_start, 0, fbi->fb_size);
  565. dev_info(fbi->dev, "fb %dk allocated\n", fbi->fb_size/1024);
  566. /* fb power on */
  567. if (modes_num > 0)
  568. mmpfb_power(fbi, 1);
  569. ret = fb_info_setup(info, fbi);
  570. if (ret < 0)
  571. goto failed_free_buff;
  572. ret = register_framebuffer(info);
  573. if (ret < 0) {
  574. dev_err(&pdev->dev, "Failed to register fb: %d\n", ret);
  575. ret = -ENXIO;
  576. goto failed_clear_info;
  577. }
  578. dev_info(fbi->dev, "loaded to /dev/fb%d <%s>.\n",
  579. info->node, info->fix.id);
  580. #ifdef CONFIG_LOGO
  581. if (fbi->fb_start) {
  582. fb_prepare_logo(info, 0);
  583. fb_show_logo(info, 0);
  584. }
  585. #endif
  586. return 0;
  587. failed_clear_info:
  588. fb_info_clear(info);
  589. failed_free_buff:
  590. dma_free_coherent(&pdev->dev, PAGE_ALIGN(fbi->fb_size), fbi->fb_start,
  591. fbi->fb_start_dma);
  592. failed_destroy_mutex:
  593. mutex_destroy(&fbi->access_ok);
  594. failed:
  595. dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n");
  596. framebuffer_release(info);
  597. return ret;
  598. }
  599. static struct platform_driver mmpfb_driver = {
  600. .driver = {
  601. .name = "mmp-fb",
  602. .owner = THIS_MODULE,
  603. },
  604. .probe = mmpfb_probe,
  605. };
  606. static int mmpfb_init(void)
  607. {
  608. return platform_driver_register(&mmpfb_driver);
  609. }
  610. module_init(mmpfb_init);
  611. MODULE_AUTHOR("Zhou Zhu <zhou.zhu@marvell.com>");
  612. MODULE_DESCRIPTION("Framebuffer driver for Marvell displays");
  613. MODULE_LICENSE("GPL");