hibmc_drm_fbdev.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /* Hisilicon Hibmc SoC drm driver
  2. *
  3. * Based on the bochs drm driver.
  4. *
  5. * Copyright (c) 2016 Huawei Limited.
  6. *
  7. * Author:
  8. * Rongrong Zou <zourongrong@huawei.com>
  9. * Rongrong Zou <zourongrong@gmail.com>
  10. * Jianhua Li <lijianhua@huawei.com>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. */
  18. #include <drm/drm_crtc.h>
  19. #include <drm/drm_crtc_helper.h>
  20. #include <drm/drm_fb_helper.h>
  21. #include "hibmc_drm_drv.h"
  22. static int hibmcfb_create_object(
  23. struct hibmc_drm_private *priv,
  24. const struct drm_mode_fb_cmd2 *mode_cmd,
  25. struct drm_gem_object **gobj_p)
  26. {
  27. struct drm_gem_object *gobj;
  28. struct drm_device *dev = priv->dev;
  29. u32 size;
  30. int ret = 0;
  31. size = mode_cmd->pitches[0] * mode_cmd->height;
  32. ret = hibmc_gem_create(dev, size, true, &gobj);
  33. if (ret)
  34. return ret;
  35. *gobj_p = gobj;
  36. return ret;
  37. }
  38. static struct fb_ops hibmc_drm_fb_ops = {
  39. .owner = THIS_MODULE,
  40. .fb_check_var = drm_fb_helper_check_var,
  41. .fb_set_par = drm_fb_helper_set_par,
  42. .fb_fillrect = drm_fb_helper_sys_fillrect,
  43. .fb_copyarea = drm_fb_helper_sys_copyarea,
  44. .fb_imageblit = drm_fb_helper_sys_imageblit,
  45. .fb_pan_display = drm_fb_helper_pan_display,
  46. .fb_blank = drm_fb_helper_blank,
  47. .fb_setcmap = drm_fb_helper_setcmap,
  48. };
  49. static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
  50. struct drm_fb_helper_surface_size *sizes)
  51. {
  52. struct hibmc_fbdev *hi_fbdev =
  53. container_of(helper, struct hibmc_fbdev, helper);
  54. struct hibmc_drm_private *priv = helper->dev->dev_private;
  55. struct fb_info *info;
  56. struct drm_mode_fb_cmd2 mode_cmd;
  57. struct drm_gem_object *gobj = NULL;
  58. int ret = 0;
  59. int ret1;
  60. size_t size;
  61. unsigned int bytes_per_pixel;
  62. struct hibmc_bo *bo = NULL;
  63. DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
  64. sizes->surface_width, sizes->surface_height,
  65. sizes->surface_bpp);
  66. sizes->surface_depth = 32;
  67. bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
  68. mode_cmd.width = sizes->surface_width;
  69. mode_cmd.height = sizes->surface_height;
  70. mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
  71. mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
  72. sizes->surface_depth);
  73. size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height);
  74. ret = hibmcfb_create_object(priv, &mode_cmd, &gobj);
  75. if (ret) {
  76. DRM_ERROR("failed to create fbcon backing object: %d\n", ret);
  77. return -ENOMEM;
  78. }
  79. bo = gem_to_hibmc_bo(gobj);
  80. ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
  81. if (ret) {
  82. DRM_ERROR("failed to reserve ttm_bo: %d\n", ret);
  83. goto out_unref_gem;
  84. }
  85. ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
  86. if (ret) {
  87. DRM_ERROR("failed to pin fbcon: %d\n", ret);
  88. goto out_unreserve_ttm_bo;
  89. }
  90. ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
  91. if (ret) {
  92. DRM_ERROR("failed to kmap fbcon: %d\n", ret);
  93. goto out_unpin_bo;
  94. }
  95. ttm_bo_unreserve(&bo->bo);
  96. info = drm_fb_helper_alloc_fbi(helper);
  97. if (IS_ERR(info)) {
  98. ret = PTR_ERR(info);
  99. DRM_ERROR("failed to allocate fbi: %d\n", ret);
  100. goto out_release_fbi;
  101. }
  102. info->par = hi_fbdev;
  103. hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
  104. if (IS_ERR(hi_fbdev->fb)) {
  105. ret = PTR_ERR(info);
  106. DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
  107. goto out_release_fbi;
  108. }
  109. priv->fbdev->size = size;
  110. hi_fbdev->helper.fb = &hi_fbdev->fb->fb;
  111. strcpy(info->fix.id, "hibmcdrmfb");
  112. info->flags = FBINFO_DEFAULT;
  113. info->fbops = &hibmc_drm_fb_ops;
  114. drm_fb_helper_fill_fix(info, hi_fbdev->fb->fb.pitches[0],
  115. hi_fbdev->fb->fb.format->depth);
  116. drm_fb_helper_fill_var(info, &priv->fbdev->helper, sizes->fb_width,
  117. sizes->fb_height);
  118. info->screen_base = bo->kmap.virtual;
  119. info->screen_size = size;
  120. info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base;
  121. info->fix.smem_len = size;
  122. return 0;
  123. out_release_fbi:
  124. drm_fb_helper_release_fbi(helper);
  125. ret1 = ttm_bo_reserve(&bo->bo, true, false, NULL);
  126. if (ret1) {
  127. DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1);
  128. goto out_unref_gem;
  129. }
  130. ttm_bo_kunmap(&bo->kmap);
  131. out_unpin_bo:
  132. hibmc_bo_unpin(bo);
  133. out_unreserve_ttm_bo:
  134. ttm_bo_unreserve(&bo->bo);
  135. out_unref_gem:
  136. drm_gem_object_unreference_unlocked(gobj);
  137. return ret;
  138. }
  139. static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
  140. {
  141. struct hibmc_framebuffer *gfb = fbdev->fb;
  142. struct drm_fb_helper *fbh = &fbdev->helper;
  143. drm_fb_helper_unregister_fbi(fbh);
  144. drm_fb_helper_release_fbi(fbh);
  145. drm_fb_helper_fini(fbh);
  146. if (gfb)
  147. drm_framebuffer_unreference(&gfb->fb);
  148. }
  149. static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
  150. .fb_probe = hibmc_drm_fb_create,
  151. };
  152. int hibmc_fbdev_init(struct hibmc_drm_private *priv)
  153. {
  154. int ret;
  155. struct fb_var_screeninfo *var;
  156. struct fb_fix_screeninfo *fix;
  157. struct hibmc_fbdev *hifbdev;
  158. hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL);
  159. if (!hifbdev) {
  160. DRM_ERROR("failed to allocate hibmc_fbdev\n");
  161. return -ENOMEM;
  162. }
  163. priv->fbdev = hifbdev;
  164. drm_fb_helper_prepare(priv->dev, &hifbdev->helper,
  165. &hibmc_fbdev_helper_funcs);
  166. /* Now just one crtc and one channel */
  167. ret = drm_fb_helper_init(priv->dev,
  168. &hifbdev->helper, 1, 1);
  169. if (ret) {
  170. DRM_ERROR("failed to initialize fb helper: %d\n", ret);
  171. return ret;
  172. }
  173. ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
  174. if (ret) {
  175. DRM_ERROR("failed to add all connectors: %d\n", ret);
  176. goto fini;
  177. }
  178. ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
  179. if (ret) {
  180. DRM_ERROR("failed to setup initial conn config: %d\n", ret);
  181. goto fini;
  182. }
  183. var = &hifbdev->helper.fbdev->var;
  184. fix = &hifbdev->helper.fbdev->fix;
  185. DRM_DEBUG_DRIVER("Member of info->var is :\n"
  186. "xres=%d\n"
  187. "yres=%d\n"
  188. "xres_virtual=%d\n"
  189. "yres_virtual=%d\n"
  190. "xoffset=%d\n"
  191. "yoffset=%d\n"
  192. "bits_per_pixel=%d\n"
  193. "...\n", var->xres, var->yres, var->xres_virtual,
  194. var->yres_virtual, var->xoffset, var->yoffset,
  195. var->bits_per_pixel);
  196. DRM_DEBUG_DRIVER("Member of info->fix is :\n"
  197. "smem_start=%lx\n"
  198. "smem_len=%d\n"
  199. "type=%d\n"
  200. "type_aux=%d\n"
  201. "visual=%d\n"
  202. "xpanstep=%d\n"
  203. "ypanstep=%d\n"
  204. "ywrapstep=%d\n"
  205. "line_length=%d\n"
  206. "accel=%d\n"
  207. "capabilities=%d\n"
  208. "...\n", fix->smem_start, fix->smem_len, fix->type,
  209. fix->type_aux, fix->visual, fix->xpanstep,
  210. fix->ypanstep, fix->ywrapstep, fix->line_length,
  211. fix->accel, fix->capabilities);
  212. return 0;
  213. fini:
  214. drm_fb_helper_fini(&hifbdev->helper);
  215. return ret;
  216. }
  217. void hibmc_fbdev_fini(struct hibmc_drm_private *priv)
  218. {
  219. if (!priv->fbdev)
  220. return;
  221. hibmc_fbdev_destroy(priv->fbdev);
  222. priv->fbdev = NULL;
  223. }