mgag200_fb.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Copyright 2010 Matt Turner.
  3. * Copyright 2012 Red Hat
  4. *
  5. * This file is subject to the terms and conditions of the GNU General
  6. * Public License version 2. See the file COPYING in the main
  7. * directory of this archive for more details.
  8. *
  9. * Authors: Matthew Garrett
  10. * Matt Turner
  11. * Dave Airlie
  12. */
  13. #include <linux/module.h>
  14. #include <drm/drmP.h>
  15. #include <drm/drm_fb_helper.h>
  16. #include <drm/drm_crtc_helper.h>
  17. #include <linux/fb.h>
  18. #include "mgag200_drv.h"
  19. static void mga_dirty_update(struct mga_fbdev *mfbdev,
  20. int x, int y, int width, int height)
  21. {
  22. int i;
  23. struct drm_gem_object *obj;
  24. struct mgag200_bo *bo;
  25. int src_offset, dst_offset;
  26. int bpp = (mfbdev->mfb.base.bits_per_pixel + 7)/8;
  27. int ret = -EBUSY;
  28. bool unmap = false;
  29. bool store_for_later = false;
  30. int x2, y2;
  31. unsigned long flags;
  32. obj = mfbdev->mfb.obj;
  33. bo = gem_to_mga_bo(obj);
  34. /*
  35. * try and reserve the BO, if we fail with busy
  36. * then the BO is being moved and we should
  37. * store up the damage until later.
  38. */
  39. if (drm_can_sleep())
  40. ret = mgag200_bo_reserve(bo, true);
  41. if (ret) {
  42. if (ret != -EBUSY)
  43. return;
  44. store_for_later = true;
  45. }
  46. x2 = x + width - 1;
  47. y2 = y + height - 1;
  48. spin_lock_irqsave(&mfbdev->dirty_lock, flags);
  49. if (mfbdev->y1 < y)
  50. y = mfbdev->y1;
  51. if (mfbdev->y2 > y2)
  52. y2 = mfbdev->y2;
  53. if (mfbdev->x1 < x)
  54. x = mfbdev->x1;
  55. if (mfbdev->x2 > x2)
  56. x2 = mfbdev->x2;
  57. if (store_for_later) {
  58. mfbdev->x1 = x;
  59. mfbdev->x2 = x2;
  60. mfbdev->y1 = y;
  61. mfbdev->y2 = y2;
  62. spin_unlock_irqrestore(&mfbdev->dirty_lock, flags);
  63. return;
  64. }
  65. mfbdev->x1 = mfbdev->y1 = INT_MAX;
  66. mfbdev->x2 = mfbdev->y2 = 0;
  67. spin_unlock_irqrestore(&mfbdev->dirty_lock, flags);
  68. if (!bo->kmap.virtual) {
  69. ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
  70. if (ret) {
  71. DRM_ERROR("failed to kmap fb updates\n");
  72. mgag200_bo_unreserve(bo);
  73. return;
  74. }
  75. unmap = true;
  76. }
  77. for (i = y; i <= y2; i++) {
  78. /* assume equal stride for now */
  79. src_offset = dst_offset = i * mfbdev->mfb.base.pitches[0] + (x * bpp);
  80. memcpy_toio(bo->kmap.virtual + src_offset, mfbdev->sysram + src_offset, (x2 - x + 1) * bpp);
  81. }
  82. if (unmap)
  83. ttm_bo_kunmap(&bo->kmap);
  84. mgag200_bo_unreserve(bo);
  85. }
  86. static void mga_fillrect(struct fb_info *info,
  87. const struct fb_fillrect *rect)
  88. {
  89. struct mga_fbdev *mfbdev = info->par;
  90. drm_fb_helper_sys_fillrect(info, rect);
  91. mga_dirty_update(mfbdev, rect->dx, rect->dy, rect->width,
  92. rect->height);
  93. }
  94. static void mga_copyarea(struct fb_info *info,
  95. const struct fb_copyarea *area)
  96. {
  97. struct mga_fbdev *mfbdev = info->par;
  98. drm_fb_helper_sys_copyarea(info, area);
  99. mga_dirty_update(mfbdev, area->dx, area->dy, area->width,
  100. area->height);
  101. }
  102. static void mga_imageblit(struct fb_info *info,
  103. const struct fb_image *image)
  104. {
  105. struct mga_fbdev *mfbdev = info->par;
  106. drm_fb_helper_sys_imageblit(info, image);
  107. mga_dirty_update(mfbdev, image->dx, image->dy, image->width,
  108. image->height);
  109. }
  110. static struct fb_ops mgag200fb_ops = {
  111. .owner = THIS_MODULE,
  112. .fb_check_var = drm_fb_helper_check_var,
  113. .fb_set_par = drm_fb_helper_set_par,
  114. .fb_fillrect = mga_fillrect,
  115. .fb_copyarea = mga_copyarea,
  116. .fb_imageblit = mga_imageblit,
  117. .fb_pan_display = drm_fb_helper_pan_display,
  118. .fb_blank = drm_fb_helper_blank,
  119. .fb_setcmap = drm_fb_helper_setcmap,
  120. };
  121. static int mgag200fb_create_object(struct mga_fbdev *afbdev,
  122. struct drm_mode_fb_cmd2 *mode_cmd,
  123. struct drm_gem_object **gobj_p)
  124. {
  125. struct drm_device *dev = afbdev->helper.dev;
  126. u32 size;
  127. struct drm_gem_object *gobj;
  128. int ret = 0;
  129. size = mode_cmd->pitches[0] * mode_cmd->height;
  130. ret = mgag200_gem_create(dev, size, true, &gobj);
  131. if (ret)
  132. return ret;
  133. *gobj_p = gobj;
  134. return ret;
  135. }
  136. static int mgag200fb_create(struct drm_fb_helper *helper,
  137. struct drm_fb_helper_surface_size *sizes)
  138. {
  139. struct mga_fbdev *mfbdev =
  140. container_of(helper, struct mga_fbdev, helper);
  141. struct drm_device *dev = mfbdev->helper.dev;
  142. struct drm_mode_fb_cmd2 mode_cmd;
  143. struct mga_device *mdev = dev->dev_private;
  144. struct fb_info *info;
  145. struct drm_framebuffer *fb;
  146. struct drm_gem_object *gobj = NULL;
  147. int ret;
  148. void *sysram;
  149. int size;
  150. mode_cmd.width = sizes->surface_width;
  151. mode_cmd.height = sizes->surface_height;
  152. mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
  153. mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
  154. sizes->surface_depth);
  155. size = mode_cmd.pitches[0] * mode_cmd.height;
  156. ret = mgag200fb_create_object(mfbdev, &mode_cmd, &gobj);
  157. if (ret) {
  158. DRM_ERROR("failed to create fbcon backing object %d\n", ret);
  159. return ret;
  160. }
  161. sysram = vmalloc(size);
  162. if (!sysram)
  163. goto err_sysram;
  164. info = drm_fb_helper_alloc_fbi(helper);
  165. if (IS_ERR(info)) {
  166. ret = PTR_ERR(info);
  167. goto err_alloc_fbi;
  168. }
  169. info->par = mfbdev;
  170. ret = mgag200_framebuffer_init(dev, &mfbdev->mfb, &mode_cmd, gobj);
  171. if (ret)
  172. goto err_framebuffer_init;
  173. mfbdev->sysram = sysram;
  174. mfbdev->size = size;
  175. fb = &mfbdev->mfb.base;
  176. /* setup helper */
  177. mfbdev->helper.fb = fb;
  178. strcpy(info->fix.id, "mgadrmfb");
  179. info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
  180. info->fbops = &mgag200fb_ops;
  181. /* setup aperture base/size for vesafb takeover */
  182. info->apertures->ranges[0].base = mdev->dev->mode_config.fb_base;
  183. info->apertures->ranges[0].size = mdev->mc.vram_size;
  184. drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
  185. drm_fb_helper_fill_var(info, &mfbdev->helper, sizes->fb_width,
  186. sizes->fb_height);
  187. info->screen_base = sysram;
  188. info->screen_size = size;
  189. info->pixmap.flags = FB_PIXMAP_SYSTEM;
  190. DRM_DEBUG_KMS("allocated %dx%d\n",
  191. fb->width, fb->height);
  192. return 0;
  193. err_framebuffer_init:
  194. drm_fb_helper_release_fbi(helper);
  195. err_alloc_fbi:
  196. vfree(sysram);
  197. err_sysram:
  198. drm_gem_object_unreference_unlocked(gobj);
  199. return ret;
  200. }
  201. static int mga_fbdev_destroy(struct drm_device *dev,
  202. struct mga_fbdev *mfbdev)
  203. {
  204. struct mga_framebuffer *mfb = &mfbdev->mfb;
  205. drm_fb_helper_unregister_fbi(&mfbdev->helper);
  206. drm_fb_helper_release_fbi(&mfbdev->helper);
  207. if (mfb->obj) {
  208. drm_gem_object_unreference_unlocked(mfb->obj);
  209. mfb->obj = NULL;
  210. }
  211. drm_fb_helper_fini(&mfbdev->helper);
  212. vfree(mfbdev->sysram);
  213. drm_framebuffer_unregister_private(&mfb->base);
  214. drm_framebuffer_cleanup(&mfb->base);
  215. return 0;
  216. }
  217. static const struct drm_fb_helper_funcs mga_fb_helper_funcs = {
  218. .gamma_set = mga_crtc_fb_gamma_set,
  219. .gamma_get = mga_crtc_fb_gamma_get,
  220. .fb_probe = mgag200fb_create,
  221. };
  222. int mgag200_fbdev_init(struct mga_device *mdev)
  223. {
  224. struct mga_fbdev *mfbdev;
  225. int ret;
  226. int bpp_sel = 32;
  227. /* prefer 16bpp on low end gpus with limited VRAM */
  228. if (IS_G200_SE(mdev) && mdev->mc.vram_size < (2048*1024))
  229. bpp_sel = 16;
  230. mfbdev = devm_kzalloc(mdev->dev->dev, sizeof(struct mga_fbdev), GFP_KERNEL);
  231. if (!mfbdev)
  232. return -ENOMEM;
  233. mdev->mfbdev = mfbdev;
  234. spin_lock_init(&mfbdev->dirty_lock);
  235. drm_fb_helper_prepare(mdev->dev, &mfbdev->helper, &mga_fb_helper_funcs);
  236. ret = drm_fb_helper_init(mdev->dev, &mfbdev->helper,
  237. mdev->num_crtc, MGAG200FB_CONN_LIMIT);
  238. if (ret)
  239. goto err_fb_helper;
  240. ret = drm_fb_helper_single_add_all_connectors(&mfbdev->helper);
  241. if (ret)
  242. goto err_fb_setup;
  243. /* disable all the possible outputs/crtcs before entering KMS mode */
  244. drm_helper_disable_unused_functions(mdev->dev);
  245. ret = drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel);
  246. if (ret)
  247. goto err_fb_setup;
  248. return 0;
  249. err_fb_setup:
  250. drm_fb_helper_fini(&mfbdev->helper);
  251. err_fb_helper:
  252. mdev->mfbdev = NULL;
  253. return ret;
  254. }
  255. void mgag200_fbdev_fini(struct mga_device *mdev)
  256. {
  257. if (!mdev->mfbdev)
  258. return;
  259. mga_fbdev_destroy(mdev->dev, mdev->mfbdev);
  260. }