adf_fbdev.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /*
  2. * Copyright (C) 2013 Google, Inc.
  3. *
  4. * This software is licensed under the terms of the GNU General Public
  5. * License version 2, as published by the Free Software Foundation, and
  6. * may be copied, distributed, and modified under those terms.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. */
  14. #include <linux/vmalloc.h>
  15. #include <video/adf.h>
  16. #include <video/adf_client.h>
  17. #include <video/adf_fbdev.h>
  18. #include <video/adf_format.h>
  19. #include "adf.h"
  20. struct adf_fbdev_format {
  21. u32 fourcc;
  22. u32 bpp;
  23. u32 r_length;
  24. u32 g_length;
  25. u32 b_length;
  26. u32 a_length;
  27. u32 r_offset;
  28. u32 g_offset;
  29. u32 b_offset;
  30. u32 a_offset;
  31. };
  32. static const struct adf_fbdev_format format_table[] = {
  33. {DRM_FORMAT_RGB332, 8, 3, 3, 2, 0, 5, 2, 0, 0},
  34. {DRM_FORMAT_BGR233, 8, 3, 3, 2, 0, 0, 3, 5, 0},
  35. {DRM_FORMAT_XRGB4444, 16, 4, 4, 4, 0, 8, 4, 0, 0},
  36. {DRM_FORMAT_XBGR4444, 16, 4, 4, 4, 0, 0, 4, 8, 0},
  37. {DRM_FORMAT_RGBX4444, 16, 4, 4, 4, 0, 12, 8, 4, 0},
  38. {DRM_FORMAT_BGRX4444, 16, 4, 4, 4, 0, 0, 4, 8, 0},
  39. {DRM_FORMAT_ARGB4444, 16, 4, 4, 4, 4, 8, 4, 0, 12},
  40. {DRM_FORMAT_ABGR4444, 16, 4, 4, 4, 4, 0, 4, 8, 12},
  41. {DRM_FORMAT_RGBA4444, 16, 4, 4, 4, 4, 12, 8, 4, 0},
  42. {DRM_FORMAT_BGRA4444, 16, 4, 4, 4, 4, 0, 4, 8, 0},
  43. {DRM_FORMAT_XRGB1555, 16, 5, 5, 5, 0, 10, 5, 0, 0},
  44. {DRM_FORMAT_XBGR1555, 16, 5, 5, 5, 0, 0, 5, 10, 0},
  45. {DRM_FORMAT_RGBX5551, 16, 5, 5, 5, 0, 11, 6, 1, 0},
  46. {DRM_FORMAT_BGRX5551, 16, 5, 5, 5, 0, 1, 6, 11, 0},
  47. {DRM_FORMAT_ARGB1555, 16, 5, 5, 5, 1, 10, 5, 0, 15},
  48. {DRM_FORMAT_ABGR1555, 16, 5, 5, 5, 1, 0, 5, 10, 15},
  49. {DRM_FORMAT_RGBA5551, 16, 5, 5, 5, 1, 11, 6, 1, 0},
  50. {DRM_FORMAT_BGRA5551, 16, 5, 5, 5, 1, 1, 6, 11, 0},
  51. {DRM_FORMAT_RGB565, 16, 5, 6, 5, 0, 11, 5, 0, 0},
  52. {DRM_FORMAT_BGR565, 16, 5, 6, 5, 0, 0, 5, 11, 0},
  53. {DRM_FORMAT_RGB888, 24, 8, 8, 8, 0, 16, 8, 0, 0},
  54. {DRM_FORMAT_BGR888, 24, 8, 8, 8, 0, 0, 8, 16, 0},
  55. {DRM_FORMAT_XRGB8888, 32, 8, 8, 8, 0, 16, 8, 0, 0},
  56. {DRM_FORMAT_XBGR8888, 32, 8, 8, 8, 0, 0, 8, 16, 0},
  57. {DRM_FORMAT_RGBX8888, 32, 8, 8, 8, 0, 24, 16, 8, 0},
  58. {DRM_FORMAT_BGRX8888, 32, 8, 8, 8, 0, 8, 16, 24, 0},
  59. {DRM_FORMAT_ARGB8888, 32, 8, 8, 8, 8, 16, 8, 0, 24},
  60. {DRM_FORMAT_ABGR8888, 32, 8, 8, 8, 8, 0, 8, 16, 24},
  61. {DRM_FORMAT_RGBA8888, 32, 8, 8, 8, 8, 24, 16, 8, 0},
  62. {DRM_FORMAT_BGRA8888, 32, 8, 8, 8, 8, 8, 16, 24, 0},
  63. {DRM_FORMAT_XRGB2101010, 32, 10, 10, 10, 0, 20, 10, 0, 0},
  64. {DRM_FORMAT_XBGR2101010, 32, 10, 10, 10, 0, 0, 10, 20, 0},
  65. {DRM_FORMAT_RGBX1010102, 32, 10, 10, 10, 0, 22, 12, 2, 0},
  66. {DRM_FORMAT_BGRX1010102, 32, 10, 10, 10, 0, 2, 12, 22, 0},
  67. {DRM_FORMAT_ARGB2101010, 32, 10, 10, 10, 2, 20, 10, 0, 30},
  68. {DRM_FORMAT_ABGR2101010, 32, 10, 10, 10, 2, 0, 10, 20, 30},
  69. {DRM_FORMAT_RGBA1010102, 32, 10, 10, 10, 2, 22, 12, 2, 0},
  70. {DRM_FORMAT_BGRA1010102, 32, 10, 10, 10, 2, 2, 12, 22, 0},
  71. };
  72. static u32 drm_fourcc_from_fb_var(struct fb_var_screeninfo *var)
  73. {
  74. size_t i;
  75. for (i = 0; i < ARRAY_SIZE(format_table); i++) {
  76. const struct adf_fbdev_format *f = &format_table[i];
  77. if (var->red.length == f->r_length &&
  78. var->red.offset == f->r_offset &&
  79. var->green.length == f->g_length &&
  80. var->green.offset == f->g_offset &&
  81. var->blue.length == f->b_length &&
  82. var->blue.offset == f->b_offset &&
  83. var->transp.length == f->a_length &&
  84. (var->transp.length == 0 ||
  85. var->transp.offset == f->a_offset))
  86. return f->fourcc;
  87. }
  88. return 0;
  89. }
  90. static const struct adf_fbdev_format *fbdev_format_info(u32 format)
  91. {
  92. size_t i;
  93. for (i = 0; i < ARRAY_SIZE(format_table); i++) {
  94. const struct adf_fbdev_format *f = &format_table[i];
  95. if (f->fourcc == format)
  96. return f;
  97. }
  98. BUG();
  99. }
  100. void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode,
  101. struct fb_videomode *vmode)
  102. {
  103. memset(vmode, 0, sizeof(*vmode));
  104. vmode->refresh = mode->vrefresh;
  105. vmode->xres = mode->hdisplay;
  106. vmode->yres = mode->vdisplay;
  107. vmode->pixclock = mode->clock ? KHZ2PICOS(mode->clock) : 0;
  108. vmode->left_margin = mode->htotal - mode->hsync_end;
  109. vmode->right_margin = mode->hsync_start - mode->hdisplay;
  110. vmode->upper_margin = mode->vtotal - mode->vsync_end;
  111. vmode->lower_margin = mode->vsync_start - mode->vdisplay;
  112. vmode->hsync_len = mode->hsync_end - mode->hsync_start;
  113. vmode->vsync_len = mode->vsync_end - mode->vsync_start;
  114. vmode->sync = 0;
  115. if (mode->flags & DRM_MODE_FLAG_PHSYNC)
  116. vmode->sync |= FB_SYNC_HOR_HIGH_ACT;
  117. if (mode->flags & DRM_MODE_FLAG_PVSYNC)
  118. vmode->sync |= FB_SYNC_VERT_HIGH_ACT;
  119. if (mode->flags & DRM_MODE_FLAG_PCSYNC)
  120. vmode->sync |= FB_SYNC_COMP_HIGH_ACT;
  121. if (mode->flags & DRM_MODE_FLAG_BCAST)
  122. vmode->sync |= FB_SYNC_BROADCAST;
  123. vmode->vmode = 0;
  124. if (mode->flags & DRM_MODE_FLAG_INTERLACE)
  125. vmode->vmode |= FB_VMODE_INTERLACED;
  126. if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
  127. vmode->vmode |= FB_VMODE_DOUBLE;
  128. }
  129. EXPORT_SYMBOL(adf_modeinfo_to_fb_videomode);
  130. void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode,
  131. struct drm_mode_modeinfo *mode)
  132. {
  133. memset(mode, 0, sizeof(*mode));
  134. mode->hdisplay = vmode->xres;
  135. mode->hsync_start = mode->hdisplay + vmode->right_margin;
  136. mode->hsync_end = mode->hsync_start + vmode->hsync_len;
  137. mode->htotal = mode->hsync_end + vmode->left_margin;
  138. mode->vdisplay = vmode->yres;
  139. mode->vsync_start = mode->vdisplay + vmode->lower_margin;
  140. mode->vsync_end = mode->vsync_start + vmode->vsync_len;
  141. mode->vtotal = mode->vsync_end + vmode->upper_margin;
  142. mode->clock = vmode->pixclock ? PICOS2KHZ(vmode->pixclock) : 0;
  143. mode->flags = 0;
  144. if (vmode->sync & FB_SYNC_HOR_HIGH_ACT)
  145. mode->flags |= DRM_MODE_FLAG_PHSYNC;
  146. if (vmode->sync & FB_SYNC_VERT_HIGH_ACT)
  147. mode->flags |= DRM_MODE_FLAG_PVSYNC;
  148. if (vmode->sync & FB_SYNC_COMP_HIGH_ACT)
  149. mode->flags |= DRM_MODE_FLAG_PCSYNC;
  150. if (vmode->sync & FB_SYNC_BROADCAST)
  151. mode->flags |= DRM_MODE_FLAG_BCAST;
  152. if (vmode->vmode & FB_VMODE_INTERLACED)
  153. mode->flags |= DRM_MODE_FLAG_INTERLACE;
  154. if (vmode->vmode & FB_VMODE_DOUBLE)
  155. mode->flags |= DRM_MODE_FLAG_DBLSCAN;
  156. if (vmode->refresh)
  157. mode->vrefresh = vmode->refresh;
  158. else
  159. adf_modeinfo_set_vrefresh(mode);
  160. if (vmode->name)
  161. strlcpy(mode->name, vmode->name, sizeof(mode->name));
  162. else
  163. adf_modeinfo_set_name(mode);
  164. }
  165. EXPORT_SYMBOL(adf_modeinfo_from_fb_videomode);
  166. static int adf_fbdev_post(struct adf_fbdev *fbdev)
  167. {
  168. struct adf_buffer buf;
  169. struct sync_fence *complete_fence;
  170. int ret = 0;
  171. memset(&buf, 0, sizeof(buf));
  172. buf.overlay_engine = fbdev->eng;
  173. buf.w = fbdev->info->var.xres;
  174. buf.h = fbdev->info->var.yres;
  175. buf.format = fbdev->format;
  176. buf.dma_bufs[0] = fbdev->dma_buf;
  177. buf.offset[0] = fbdev->offset +
  178. fbdev->info->var.yoffset * fbdev->pitch +
  179. fbdev->info->var.xoffset *
  180. (fbdev->info->var.bits_per_pixel / 8);
  181. buf.pitch[0] = fbdev->pitch;
  182. buf.n_planes = 1;
  183. complete_fence = adf_interface_simple_post(fbdev->intf, &buf);
  184. if (IS_ERR(complete_fence)) {
  185. ret = PTR_ERR(complete_fence);
  186. goto done;
  187. }
  188. sync_fence_put(complete_fence);
  189. done:
  190. return ret;
  191. }
  192. static const u16 vga_palette[][3] = {
  193. {0x0000, 0x0000, 0x0000},
  194. {0x0000, 0x0000, 0xAAAA},
  195. {0x0000, 0xAAAA, 0x0000},
  196. {0x0000, 0xAAAA, 0xAAAA},
  197. {0xAAAA, 0x0000, 0x0000},
  198. {0xAAAA, 0x0000, 0xAAAA},
  199. {0xAAAA, 0x5555, 0x0000},
  200. {0xAAAA, 0xAAAA, 0xAAAA},
  201. {0x5555, 0x5555, 0x5555},
  202. {0x5555, 0x5555, 0xFFFF},
  203. {0x5555, 0xFFFF, 0x5555},
  204. {0x5555, 0xFFFF, 0xFFFF},
  205. {0xFFFF, 0x5555, 0x5555},
  206. {0xFFFF, 0x5555, 0xFFFF},
  207. {0xFFFF, 0xFFFF, 0x5555},
  208. {0xFFFF, 0xFFFF, 0xFFFF},
  209. };
  210. static int adf_fb_alloc(struct adf_fbdev *fbdev)
  211. {
  212. int ret;
  213. ret = adf_interface_simple_buffer_alloc(fbdev->intf,
  214. fbdev->default_xres_virtual,
  215. fbdev->default_yres_virtual,
  216. fbdev->default_format,
  217. &fbdev->dma_buf, &fbdev->offset, &fbdev->pitch);
  218. if (ret < 0) {
  219. dev_err(fbdev->info->dev, "allocating fb failed: %d\n", ret);
  220. return ret;
  221. }
  222. fbdev->vaddr = dma_buf_vmap(fbdev->dma_buf);
  223. if (!fbdev->vaddr) {
  224. ret = -ENOMEM;
  225. dev_err(fbdev->info->dev, "vmapping fb failed\n");
  226. goto err_vmap;
  227. }
  228. fbdev->info->fix.line_length = fbdev->pitch;
  229. fbdev->info->var.xres_virtual = fbdev->default_xres_virtual;
  230. fbdev->info->var.yres_virtual = fbdev->default_yres_virtual;
  231. fbdev->info->fix.smem_len = fbdev->dma_buf->size;
  232. fbdev->info->screen_base = fbdev->vaddr;
  233. return 0;
  234. err_vmap:
  235. dma_buf_put(fbdev->dma_buf);
  236. return ret;
  237. }
  238. static void adf_fb_destroy(struct adf_fbdev *fbdev)
  239. {
  240. dma_buf_vunmap(fbdev->dma_buf, fbdev->vaddr);
  241. dma_buf_put(fbdev->dma_buf);
  242. }
  243. static void adf_fbdev_set_format(struct adf_fbdev *fbdev, u32 format)
  244. {
  245. size_t i;
  246. const struct adf_fbdev_format *info = fbdev_format_info(format);
  247. for (i = 0; i < ARRAY_SIZE(vga_palette); i++) {
  248. u16 r = vga_palette[i][0];
  249. u16 g = vga_palette[i][1];
  250. u16 b = vga_palette[i][2];
  251. r >>= (16 - info->r_length);
  252. g >>= (16 - info->g_length);
  253. b >>= (16 - info->b_length);
  254. fbdev->pseudo_palette[i] =
  255. (r << info->r_offset) |
  256. (g << info->g_offset) |
  257. (b << info->b_offset);
  258. if (info->a_length) {
  259. u16 a = BIT(info->a_length) - 1;
  260. fbdev->pseudo_palette[i] |= (a << info->a_offset);
  261. }
  262. }
  263. fbdev->info->var.bits_per_pixel = adf_format_bpp(format);
  264. fbdev->info->var.red.length = info->r_length;
  265. fbdev->info->var.red.offset = info->r_offset;
  266. fbdev->info->var.green.length = info->g_length;
  267. fbdev->info->var.green.offset = info->g_offset;
  268. fbdev->info->var.blue.length = info->b_length;
  269. fbdev->info->var.blue.offset = info->b_offset;
  270. fbdev->info->var.transp.length = info->a_length;
  271. fbdev->info->var.transp.offset = info->a_offset;
  272. fbdev->format = format;
  273. }
  274. static void adf_fbdev_fill_modelist(struct adf_fbdev *fbdev)
  275. {
  276. struct drm_mode_modeinfo *modelist;
  277. struct fb_videomode fbmode;
  278. size_t n_modes, i;
  279. int ret = 0;
  280. n_modes = adf_interface_modelist(fbdev->intf, NULL, 0);
  281. modelist = kzalloc(sizeof(modelist[0]) * n_modes, GFP_KERNEL);
  282. if (!modelist) {
  283. dev_warn(fbdev->info->dev, "allocating new modelist failed; keeping old modelist\n");
  284. return;
  285. }
  286. adf_interface_modelist(fbdev->intf, modelist, n_modes);
  287. fb_destroy_modelist(&fbdev->info->modelist);
  288. for (i = 0; i < n_modes; i++) {
  289. adf_modeinfo_to_fb_videomode(&modelist[i], &fbmode);
  290. ret = fb_add_videomode(&fbmode, &fbdev->info->modelist);
  291. if (ret < 0)
  292. dev_warn(fbdev->info->dev, "adding mode %s to modelist failed: %d\n",
  293. modelist[i].name, ret);
  294. }
  295. kfree(modelist);
  296. }
  297. /**
  298. * adf_fbdev_open - default implementation of fbdev open op
  299. */
  300. int adf_fbdev_open(struct fb_info *info, int user)
  301. {
  302. struct adf_fbdev *fbdev = info->par;
  303. int ret;
  304. mutex_lock(&fbdev->refcount_lock);
  305. if (unlikely(fbdev->refcount == UINT_MAX)) {
  306. ret = -EMFILE;
  307. goto done;
  308. }
  309. if (!fbdev->refcount) {
  310. struct drm_mode_modeinfo mode;
  311. struct fb_videomode fbmode;
  312. struct adf_device *dev = adf_interface_parent(fbdev->intf);
  313. ret = adf_device_attach(dev, fbdev->eng, fbdev->intf);
  314. if (ret < 0 && ret != -EALREADY)
  315. goto done;
  316. ret = adf_fb_alloc(fbdev);
  317. if (ret < 0)
  318. goto done;
  319. adf_interface_current_mode(fbdev->intf, &mode);
  320. adf_modeinfo_to_fb_videomode(&mode, &fbmode);
  321. fb_videomode_to_var(&fbdev->info->var, &fbmode);
  322. adf_fbdev_set_format(fbdev, fbdev->default_format);
  323. adf_fbdev_fill_modelist(fbdev);
  324. }
  325. ret = adf_fbdev_post(fbdev);
  326. if (ret < 0) {
  327. if (!fbdev->refcount)
  328. adf_fb_destroy(fbdev);
  329. goto done;
  330. }
  331. fbdev->refcount++;
  332. done:
  333. mutex_unlock(&fbdev->refcount_lock);
  334. return ret;
  335. }
  336. EXPORT_SYMBOL(adf_fbdev_open);
  337. /**
  338. * adf_fbdev_release - default implementation of fbdev release op
  339. */
  340. int adf_fbdev_release(struct fb_info *info, int user)
  341. {
  342. struct adf_fbdev *fbdev = info->par;
  343. mutex_lock(&fbdev->refcount_lock);
  344. BUG_ON(!fbdev->refcount);
  345. fbdev->refcount--;
  346. if (!fbdev->refcount)
  347. adf_fb_destroy(fbdev);
  348. mutex_unlock(&fbdev->refcount_lock);
  349. return 0;
  350. }
  351. EXPORT_SYMBOL(adf_fbdev_release);
  352. /**
  353. * adf_fbdev_check_var - default implementation of fbdev check_var op
  354. */
  355. int adf_fbdev_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  356. {
  357. struct adf_fbdev *fbdev = info->par;
  358. bool valid_format = true;
  359. u32 format = drm_fourcc_from_fb_var(var);
  360. u32 pitch = var->xres_virtual * var->bits_per_pixel / 8;
  361. if (!format) {
  362. dev_dbg(info->dev, "%s: unrecognized format\n", __func__);
  363. valid_format = false;
  364. }
  365. if (valid_format && var->grayscale) {
  366. dev_dbg(info->dev, "%s: grayscale modes not supported\n",
  367. __func__);
  368. valid_format = false;
  369. }
  370. if (valid_format && var->nonstd) {
  371. dev_dbg(info->dev, "%s: nonstandard formats not supported\n",
  372. __func__);
  373. valid_format = false;
  374. }
  375. if (valid_format && !adf_overlay_engine_supports_format(fbdev->eng,
  376. format)) {
  377. char format_str[ADF_FORMAT_STR_SIZE];
  378. adf_format_str(format, format_str);
  379. dev_dbg(info->dev, "%s: format %s not supported by overlay engine %s\n",
  380. __func__, format_str, fbdev->eng->base.name);
  381. valid_format = false;
  382. }
  383. if (valid_format && pitch > fbdev->pitch) {
  384. dev_dbg(info->dev, "%s: fb pitch too small for var (pitch = %u, xres_virtual = %u, bits_per_pixel = %u)\n",
  385. __func__, fbdev->pitch, var->xres_virtual,
  386. var->bits_per_pixel);
  387. valid_format = false;
  388. }
  389. if (valid_format && var->yres_virtual > fbdev->default_yres_virtual) {
  390. dev_dbg(info->dev, "%s: fb height too small for var (h = %u, yres_virtual = %u)\n",
  391. __func__, fbdev->default_yres_virtual,
  392. var->yres_virtual);
  393. valid_format = false;
  394. }
  395. if (valid_format) {
  396. var->activate = info->var.activate;
  397. var->height = info->var.height;
  398. var->width = info->var.width;
  399. var->accel_flags = info->var.accel_flags;
  400. var->rotate = info->var.rotate;
  401. var->colorspace = info->var.colorspace;
  402. /* userspace can't change these */
  403. } else {
  404. /* if any part of the format is invalid then fixing it up is
  405. impractical, so save just the modesetting bits and
  406. overwrite everything else */
  407. struct fb_videomode mode;
  408. fb_var_to_videomode(&mode, var);
  409. memcpy(var, &info->var, sizeof(*var));
  410. fb_videomode_to_var(var, &mode);
  411. }
  412. return 0;
  413. }
  414. EXPORT_SYMBOL(adf_fbdev_check_var);
  415. /**
  416. * adf_fbdev_set_par - default implementation of fbdev set_par op
  417. */
  418. int adf_fbdev_set_par(struct fb_info *info)
  419. {
  420. struct adf_fbdev *fbdev = info->par;
  421. struct adf_interface *intf = fbdev->intf;
  422. struct fb_videomode vmode;
  423. struct drm_mode_modeinfo mode;
  424. int ret;
  425. u32 format = drm_fourcc_from_fb_var(&info->var);
  426. fb_var_to_videomode(&vmode, &info->var);
  427. adf_modeinfo_from_fb_videomode(&vmode, &mode);
  428. ret = adf_interface_set_mode(intf, &mode);
  429. if (ret < 0)
  430. return ret;
  431. ret = adf_fbdev_post(fbdev);
  432. if (ret < 0)
  433. return ret;
  434. if (format != fbdev->format)
  435. adf_fbdev_set_format(fbdev, format);
  436. return 0;
  437. }
  438. EXPORT_SYMBOL(adf_fbdev_set_par);
  439. /**
  440. * adf_fbdev_blank - default implementation of fbdev blank op
  441. */
  442. int adf_fbdev_blank(int blank, struct fb_info *info)
  443. {
  444. struct adf_fbdev *fbdev = info->par;
  445. struct adf_interface *intf = fbdev->intf;
  446. u8 dpms_state;
  447. switch (blank) {
  448. case FB_BLANK_UNBLANK:
  449. dpms_state = DRM_MODE_DPMS_ON;
  450. break;
  451. case FB_BLANK_NORMAL:
  452. dpms_state = DRM_MODE_DPMS_STANDBY;
  453. break;
  454. case FB_BLANK_VSYNC_SUSPEND:
  455. dpms_state = DRM_MODE_DPMS_SUSPEND;
  456. break;
  457. case FB_BLANK_HSYNC_SUSPEND:
  458. dpms_state = DRM_MODE_DPMS_STANDBY;
  459. break;
  460. case FB_BLANK_POWERDOWN:
  461. dpms_state = DRM_MODE_DPMS_OFF;
  462. break;
  463. default:
  464. return -EINVAL;
  465. }
  466. return adf_interface_blank(intf, dpms_state);
  467. }
  468. EXPORT_SYMBOL(adf_fbdev_blank);
  469. /**
  470. * adf_fbdev_pan_display - default implementation of fbdev pan_display op
  471. */
  472. int adf_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
  473. {
  474. struct adf_fbdev *fbdev = info->par;
  475. return adf_fbdev_post(fbdev);
  476. }
  477. EXPORT_SYMBOL(adf_fbdev_pan_display);
  478. /**
  479. * adf_fbdev_mmap - default implementation of fbdev mmap op
  480. */
  481. int adf_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
  482. {
  483. struct adf_fbdev *fbdev = info->par;
  484. vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  485. return dma_buf_mmap(fbdev->dma_buf, vma, 0);
  486. }
  487. EXPORT_SYMBOL(adf_fbdev_mmap);
  488. /**
  489. * adf_fbdev_init - initialize helper to wrap ADF device in fbdev API
  490. *
  491. * @fbdev: the fbdev helper
  492. * @interface: the ADF interface that will display the framebuffer
  493. * @eng: the ADF overlay engine that will scan out the framebuffer
  494. * @xres_virtual: the virtual width of the framebuffer
  495. * @yres_virtual: the virtual height of the framebuffer
  496. * @format: the format of the framebuffer
  497. * @fbops: the device's fbdev ops
  498. * @fmt: formatting for the framebuffer identification string
  499. * @...: variable arguments
  500. *
  501. * @format must be a standard, non-indexed RGB format, i.e.,
  502. * adf_format_is_rgb(@format) && @format != @DRM_FORMAT_C8.
  503. *
  504. * Returns 0 on success or -errno on failure.
  505. */
  506. int adf_fbdev_init(struct adf_fbdev *fbdev, struct adf_interface *interface,
  507. struct adf_overlay_engine *eng,
  508. u16 xres_virtual, u16 yres_virtual, u32 format,
  509. struct fb_ops *fbops, const char *fmt, ...)
  510. {
  511. struct adf_device *parent = adf_interface_parent(interface);
  512. struct device *dev = &parent->base.dev;
  513. u16 width_mm, height_mm;
  514. va_list args;
  515. int ret;
  516. if (!adf_format_is_rgb(format) ||
  517. format == DRM_FORMAT_C8) {
  518. dev_err(dev, "fbdev helper does not support format %u\n",
  519. format);
  520. return -EINVAL;
  521. }
  522. memset(fbdev, 0, sizeof(*fbdev));
  523. fbdev->intf = interface;
  524. fbdev->eng = eng;
  525. fbdev->info = framebuffer_alloc(0, dev);
  526. if (!fbdev->info) {
  527. dev_err(dev, "allocating framebuffer device failed\n");
  528. return -ENOMEM;
  529. }
  530. mutex_init(&fbdev->refcount_lock);
  531. fbdev->default_xres_virtual = xres_virtual;
  532. fbdev->default_yres_virtual = yres_virtual;
  533. fbdev->default_format = format;
  534. fbdev->info->flags = FBINFO_FLAG_DEFAULT;
  535. ret = adf_interface_get_screen_size(interface, &width_mm, &height_mm);
  536. if (ret < 0) {
  537. width_mm = 0;
  538. height_mm = 0;
  539. }
  540. fbdev->info->var.width = width_mm;
  541. fbdev->info->var.height = height_mm;
  542. fbdev->info->var.activate = FB_ACTIVATE_VBL;
  543. va_start(args, fmt);
  544. vsnprintf(fbdev->info->fix.id, sizeof(fbdev->info->fix.id), fmt, args);
  545. va_end(args);
  546. fbdev->info->fix.type = FB_TYPE_PACKED_PIXELS;
  547. fbdev->info->fix.visual = FB_VISUAL_TRUECOLOR;
  548. fbdev->info->fix.xpanstep = 1;
  549. fbdev->info->fix.ypanstep = 1;
  550. INIT_LIST_HEAD(&fbdev->info->modelist);
  551. fbdev->info->fbops = fbops;
  552. fbdev->info->pseudo_palette = fbdev->pseudo_palette;
  553. fbdev->info->par = fbdev;
  554. ret = register_framebuffer(fbdev->info);
  555. if (ret < 0) {
  556. dev_err(dev, "registering framebuffer failed: %d\n", ret);
  557. return ret;
  558. }
  559. return 0;
  560. }
  561. EXPORT_SYMBOL(adf_fbdev_init);
  562. /**
  563. * adf_fbdev_destroy - destroy helper to wrap ADF device in fbdev API
  564. *
  565. * @fbdev: the fbdev helper
  566. */
  567. void adf_fbdev_destroy(struct adf_fbdev *fbdev)
  568. {
  569. unregister_framebuffer(fbdev->info);
  570. BUG_ON(fbdev->refcount);
  571. mutex_destroy(&fbdev->refcount_lock);
  572. framebuffer_release(fbdev->info);
  573. }
  574. EXPORT_SYMBOL(adf_fbdev_destroy);