Created
October 18, 2017 13:56
-
-
Save notro/d7fc2809736cdddb68a644b589a86ee1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------- | |
max_conn_count = AMDGPUFB_CONN_LIMIT == 4 | |
bpp_sel = 32 or 8 | |
struct amdgpu_fbdev { | |
struct drm_fb_helper helper; | |
struct amdgpu_framebuffer rfb; | |
struct amdgpu_device *adev; | |
}; | |
int amdgpu_fbdev_init(struct amdgpu_device *adev) | |
{ | |
struct amdgpu_fbdev *rfbdev; | |
int bpp_sel = 32; | |
int ret; | |
/* don't init fbdev on hw without DCE */ | |
if (!adev->mode_info.mode_config_initialized) | |
return 0; | |
/* don't init fbdev if there are no connectors */ | |
if (list_empty(&adev->ddev->mode_config.connector_list)) | |
return 0; | |
/* select 8 bpp console on low vram cards */ | |
if (adev->mc.real_vram_size <= (32*1024*1024)) | |
bpp_sel = 8; | |
rfbdev = kzalloc(sizeof(struct amdgpu_fbdev), GFP_KERNEL); | |
if (!rfbdev) | |
return -ENOMEM; | |
rfbdev->adev = adev; | |
adev->mode_info.rfbdev = rfbdev; | |
drm_fb_helper_prepare(adev->ddev, &rfbdev->helper, | |
&amdgpu_fb_helper_funcs); | |
ret = drm_fb_helper_init(adev->ddev, &rfbdev->helper, | |
AMDGPUFB_CONN_LIMIT); | |
if (ret) { | |
kfree(rfbdev); | |
return ret; | |
} | |
drm_fb_helper_single_add_all_connectors(&rfbdev->helper); | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
drm_helper_disable_unused_functions(adev->ddev); | |
drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); | |
return 0; | |
} | |
static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfbdev) | |
{ | |
struct amdgpu_framebuffer *rfb = &rfbdev->rfb; | |
drm_fb_helper_unregister_fbi(&rfbdev->helper); | |
if (rfb->obj) { | |
amdgpufb_destroy_pinned_object(rfb->obj); | |
rfb->obj = NULL; | |
} | |
drm_fb_helper_fini(&rfbdev->helper); | |
drm_framebuffer_unregister_private(&rfb->base); | |
drm_framebuffer_cleanup(&rfb->base); | |
return 0; | |
} | |
void amdgpu_fbdev_fini(struct amdgpu_device *adev) | |
{ | |
if (!adev->mode_info.rfbdev) | |
return; | |
amdgpu_fbdev_destroy(adev->ddev, adev->mode_info.rfbdev); | |
kfree(adev->mode_info.rfbdev); | |
adev->mode_info.rfbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = 1 | |
bpp_sel = 32 | |
int armada_fbdev_init(struct drm_device *dev) | |
{ | |
struct armada_private *priv = dev->dev_private; | |
struct drm_fb_helper *fbh; | |
int ret; | |
fbh = devm_kzalloc(dev->dev, sizeof(*fbh), GFP_KERNEL); | |
if (!fbh) | |
return -ENOMEM; | |
priv->fbdev = fbh; | |
drm_fb_helper_prepare(dev, fbh, &armada_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, fbh, 1); | |
if (ret) { | |
DRM_ERROR("failed to initialize drm fb helper\n"); | |
goto err_fb_helper; | |
} | |
ret = drm_fb_helper_single_add_all_connectors(fbh); | |
if (ret) { | |
DRM_ERROR("failed to add fb connectors\n"); | |
goto err_fb_setup; | |
} | |
ret = drm_fb_helper_initial_config(fbh, 32); | |
if (ret) { | |
DRM_ERROR("failed to set initial config\n"); | |
goto err_fb_setup; | |
} | |
return 0; | |
err_fb_setup: | |
drm_fb_helper_fini(fbh); | |
err_fb_helper: | |
priv->fbdev = NULL; | |
return ret; | |
} | |
void armada_fbdev_fini(struct drm_device *dev) | |
{ | |
struct armada_private *priv = dev->dev_private; | |
struct drm_fb_helper *fbh = priv->fbdev; | |
if (fbh) { | |
drm_fb_helper_unregister_fbi(fbh); | |
drm_fb_helper_fini(fbh); | |
if (fbh->fb) | |
fbh->fb->funcs->destroy(fbh->fb); | |
priv->fbdev = NULL; | |
} | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = 1 | |
bpp_sel = 32 | |
struct ast_fbdev { | |
struct drm_fb_helper helper; | |
struct ast_framebuffer afb; | |
void *sysram; | |
int size; | |
struct ttm_bo_kmap_obj mapping; | |
int x1, y1, x2, y2; /* dirty rect */ | |
spinlock_t dirty_lock; | |
}; | |
int ast_fbdev_init(struct drm_device *dev) | |
{ | |
struct ast_private *ast = dev->dev_private; | |
struct ast_fbdev *afbdev; | |
int ret; | |
afbdev = kzalloc(sizeof(struct ast_fbdev), GFP_KERNEL); | |
if (!afbdev) | |
return -ENOMEM; | |
ast->fbdev = afbdev; | |
spin_lock_init(&afbdev->dirty_lock); | |
drm_fb_helper_prepare(dev, &afbdev->helper, &ast_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, &afbdev->helper, 1); | |
if (ret) | |
goto free; | |
ret = drm_fb_helper_single_add_all_connectors(&afbdev->helper); | |
if (ret) | |
goto fini; | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
drm_helper_disable_unused_functions(dev); | |
ret = drm_fb_helper_initial_config(&afbdev->helper, 32); | |
if (ret) | |
goto fini; | |
return 0; | |
fini: | |
drm_fb_helper_fini(&afbdev->helper); | |
free: | |
kfree(afbdev); | |
return ret; | |
} | |
void ast_fbdev_fini(struct drm_device *dev) | |
{ | |
struct ast_private *ast = dev->dev_private; | |
if (!ast->fbdev) | |
return; | |
ast_fbdev_destroy(dev, ast->fbdev); | |
kfree(ast->fbdev); | |
ast->fbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = 1 | |
bpp_sel = 32 | |
struct bochs_device { | |
... | |
/* fbdev */ | |
struct { | |
struct bochs_framebuffer gfb; | |
struct drm_fb_helper helper; | |
int size; | |
bool initialized; | |
} fb; | |
}; | |
int bochs_fbdev_init(struct bochs_device *bochs) | |
{ | |
int ret; | |
drm_fb_helper_prepare(bochs->dev, &bochs->fb.helper, | |
&bochs_fb_helper_funcs); | |
ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper, 1); | |
if (ret) | |
return ret; | |
ret = drm_fb_helper_single_add_all_connectors(&bochs->fb.helper); | |
if (ret) | |
goto fini; | |
drm_helper_disable_unused_functions(bochs->dev); | |
ret = drm_fb_helper_initial_config(&bochs->fb.helper, 32); | |
if (ret) | |
goto fini; | |
return 0; | |
fini: | |
drm_fb_helper_fini(&bochs->fb.helper); | |
return ret; | |
} | |
void bochs_fbdev_fini(struct bochs_device *bochs) | |
{ | |
if (bochs->fb.initialized) | |
bochs_fbdev_destroy(bochs); | |
if (bochs->fb.helper.fbdev) | |
drm_fb_helper_fini(&bochs->fb.helper); | |
bochs->fb.initialized = false; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = CIRRUSFB_CONN_LIMIT == 1 | |
bpp_sel = 24 | |
struct cirrus_fbdev { | |
struct drm_fb_helper helper; | |
struct cirrus_framebuffer gfb; | |
void *sysram; | |
int size; | |
int x1, y1, x2, y2; /* dirty rect */ | |
spinlock_t dirty_lock; | |
}; | |
int cirrus_fbdev_init(struct cirrus_device *cdev) | |
{ | |
struct cirrus_fbdev *gfbdev; | |
int ret; | |
int bpp_sel = 24; | |
/*bpp_sel = 8;*/ | |
gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL); | |
if (!gfbdev) | |
return -ENOMEM; | |
cdev->mode_info.gfbdev = gfbdev; | |
spin_lock_init(&gfbdev->dirty_lock); | |
drm_fb_helper_prepare(cdev->dev, &gfbdev->helper, | |
&cirrus_fb_helper_funcs); | |
ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, | |
CIRRUSFB_CONN_LIMIT); | |
if (ret) | |
return ret; | |
ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper); | |
if (ret) | |
return ret; | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
drm_helper_disable_unused_functions(cdev->dev); | |
return drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel); | |
} | |
void cirrus_fbdev_fini(struct cirrus_device *cdev) | |
{ | |
if (!cdev->mode_info.gfbdev) | |
return; | |
cirrus_fbdev_destroy(cdev->dev, cdev->mode_info.gfbdev); | |
kfree(cdev->mode_info.gfbdev); | |
cdev->mode_info.gfbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = max_conn_count argument | |
bpp_sel = preferred_bpp argument | |
struct drm_fbdev_cma { | |
struct drm_fb_helper fb_helper; | |
const struct drm_framebuffer_funcs *fb_funcs; | |
}; | |
struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, | |
unsigned int preferred_bpp, unsigned int max_conn_count, | |
const struct drm_framebuffer_funcs *funcs) | |
{ | |
struct drm_fbdev_cma *fbdev_cma; | |
struct drm_fb_helper *helper; | |
int ret; | |
fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL); | |
if (!fbdev_cma) { | |
dev_err(dev->dev, "Failed to allocate drm fbdev.\n"); | |
return ERR_PTR(-ENOMEM); | |
} | |
fbdev_cma->fb_funcs = funcs; | |
helper = &fbdev_cma->fb_helper; | |
drm_fb_helper_prepare(dev, helper, &drm_fb_cma_helper_funcs); | |
ret = drm_fb_helper_init(dev, helper, max_conn_count); | |
if (ret < 0) { | |
dev_err(dev->dev, "Failed to initialize drm fb helper.\n"); | |
goto err_free; | |
} | |
ret = drm_fb_helper_single_add_all_connectors(helper); | |
if (ret < 0) { | |
dev_err(dev->dev, "Failed to add connectors.\n"); | |
goto err_drm_fb_helper_fini; | |
} | |
ret = drm_fb_helper_initial_config(helper, preferred_bpp); | |
if (ret < 0) { | |
dev_err(dev->dev, "Failed to set initial hw configuration.\n"); | |
goto err_drm_fb_helper_fini; | |
} | |
return fbdev_cma; | |
err_drm_fb_helper_fini: | |
drm_fb_helper_fini(helper); | |
err_free: | |
kfree(fbdev_cma); | |
return ERR_PTR(ret); | |
} | |
EXPORT_SYMBOL_GPL(drm_fbdev_cma_init_with_funcs); | |
void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) | |
{ | |
drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper); | |
if (fbdev_cma->fb_helper.fbdev) | |
drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev); | |
if (fbdev_cma->fb_helper.fb) | |
drm_framebuffer_remove(fbdev_cma->fb_helper.fb); | |
drm_fb_helper_fini(&fbdev_cma->fb_helper); | |
kfree(fbdev_cma); | |
} | |
EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini); | |
------------------------------------------------------------------------------- | |
max_conn_count = MAX_CONNECTOR == 4 | |
bpp_sel = PREFERRED_BPP == 32 | |
struct exynos_drm_fbdev { | |
struct drm_fb_helper drm_fb_helper; | |
struct exynos_drm_gem *exynos_gem; | |
}; | |
int exynos_drm_fbdev_init(struct drm_device *dev) | |
{ | |
struct exynos_drm_fbdev *fbdev; | |
struct exynos_drm_private *private = dev->dev_private; | |
struct drm_fb_helper *helper; | |
int ret; | |
if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector) | |
return 0; | |
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); | |
if (!fbdev) | |
return -ENOMEM; | |
private->fb_helper = helper = &fbdev->drm_fb_helper; | |
drm_fb_helper_prepare(dev, helper, &exynos_drm_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, helper, MAX_CONNECTOR); | |
if (ret < 0) { | |
DRM_ERROR("failed to initialize drm fb helper.\n"); | |
goto err_init; | |
} | |
ret = drm_fb_helper_single_add_all_connectors(helper); | |
if (ret < 0) { | |
DRM_ERROR("failed to register drm_fb_helper_connector.\n"); | |
goto err_setup; | |
} | |
ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); | |
if (ret < 0) { | |
DRM_ERROR("failed to set up hw configuration.\n"); | |
goto err_setup; | |
} | |
return 0; | |
err_setup: | |
drm_fb_helper_fini(helper); | |
err_init: | |
private->fb_helper = NULL; | |
kfree(fbdev); | |
return ret; | |
} | |
static void exynos_drm_fbdev_destroy(struct drm_device *dev, | |
struct drm_fb_helper *fb_helper) | |
{ | |
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper); | |
struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem; | |
struct drm_framebuffer *fb; | |
vunmap(exynos_gem->kvaddr); | |
/* release drm framebuffer and real buffer */ | |
if (fb_helper->fb && fb_helper->fb->funcs) { | |
fb = fb_helper->fb; | |
if (fb) | |
drm_framebuffer_remove(fb); | |
} | |
drm_fb_helper_unregister_fbi(fb_helper); | |
drm_fb_helper_fini(fb_helper); | |
} | |
void exynos_drm_fbdev_fini(struct drm_device *dev) | |
{ | |
struct exynos_drm_private *private = dev->dev_private; | |
struct exynos_drm_fbdev *fbdev; | |
if (!private || !private->fb_helper) | |
return; | |
fbdev = to_exynos_fbdev(private->fb_helper); | |
exynos_drm_fbdev_destroy(dev, private->fb_helper); | |
kfree(fbdev); | |
private->fb_helper = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = INTELFB_CONN_LIMIT == 4 | |
bpp_sel = 32 | |
struct psb_fbdev { | |
struct drm_fb_helper psb_fb_helper; | |
struct psb_framebuffer pfb; | |
}; | |
int psb_fbdev_init(struct drm_device *dev) | |
{ | |
struct psb_fbdev *fbdev; | |
struct drm_psb_private *dev_priv = dev->dev_private; | |
int ret; | |
fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL); | |
if (!fbdev) { | |
dev_err(dev->dev, "no memory\n"); | |
return -ENOMEM; | |
} | |
dev_priv->fbdev = fbdev; | |
drm_fb_helper_prepare(dev, &fbdev->psb_fb_helper, &psb_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, &fbdev->psb_fb_helper, | |
INTELFB_CONN_LIMIT); | |
if (ret) | |
goto free; | |
ret = drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper); | |
if (ret) | |
goto fini; | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
drm_helper_disable_unused_functions(dev); | |
ret = drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32); | |
if (ret) | |
goto fini; | |
return 0; | |
fini: | |
drm_fb_helper_fini(&fbdev->psb_fb_helper); | |
free: | |
kfree(fbdev); | |
return ret; | |
} | |
static void psb_fbdev_fini(struct drm_device *dev) | |
{ | |
struct drm_psb_private *dev_priv = dev->dev_private; | |
if (!dev_priv->fbdev) | |
return; | |
psb_fbdev_destroy(dev, dev_priv->fbdev); | |
kfree(dev_priv->fbdev); | |
dev_priv->fbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = 1 | |
bpp_sel = 16 | |
struct hibmc_fbdev { | |
struct drm_fb_helper helper; | |
struct hibmc_framebuffer *fb; | |
int size; | |
}; | |
int hibmc_fbdev_init(struct hibmc_drm_private *priv) | |
{ | |
int ret; | |
struct fb_var_screeninfo *var; | |
struct fb_fix_screeninfo *fix; | |
struct hibmc_fbdev *hifbdev; | |
hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL); | |
if (!hifbdev) { | |
DRM_ERROR("failed to allocate hibmc_fbdev\n"); | |
return -ENOMEM; | |
} | |
priv->fbdev = hifbdev; | |
drm_fb_helper_prepare(priv->dev, &hifbdev->helper, | |
&hibmc_fbdev_helper_funcs); | |
/* Now just one crtc and one channel */ | |
ret = drm_fb_helper_init(priv->dev, &hifbdev->helper, 1); | |
if (ret) { | |
DRM_ERROR("failed to initialize fb helper: %d\n", ret); | |
return ret; | |
} | |
ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper); | |
if (ret) { | |
DRM_ERROR("failed to add all connectors: %d\n", ret); | |
goto fini; | |
} | |
ret = drm_fb_helper_initial_config(&hifbdev->helper, 16); | |
if (ret) { | |
DRM_ERROR("failed to setup initial conn config: %d\n", ret); | |
goto fini; | |
} | |
var = &hifbdev->helper.fbdev->var; | |
fix = &hifbdev->helper.fbdev->fix; | |
DRM_DEBUG_DRIVER("Member of info->var is :\n" | |
... | |
DRM_DEBUG_DRIVER("Member of info->fix is :\n" | |
... | |
return 0; | |
fini: | |
drm_fb_helper_fini(&hifbdev->helper); | |
return ret; | |
} | |
static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev) | |
{ | |
struct hibmc_framebuffer *gfb = fbdev->fb; | |
struct drm_fb_helper *fbh = &fbdev->helper; | |
drm_fb_helper_unregister_fbi(fbh); | |
drm_fb_helper_fini(fbh); | |
if (gfb) | |
drm_framebuffer_put(&gfb->fb); | |
} | |
void hibmc_fbdev_fini(struct hibmc_drm_private *priv) | |
{ | |
if (!priv->fbdev) | |
return; | |
hibmc_fbdev_destroy(priv->fbdev); | |
priv->fbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = 4 | |
bpp_sel = ifbdev->preferred_bpp | |
struct intel_fbdev { | |
struct drm_fb_helper helper; | |
struct intel_framebuffer *fb; | |
struct i915_vma *vma; | |
async_cookie_t cookie; | |
int preferred_bpp; | |
}; | |
int intel_fbdev_init(struct drm_device *dev) | |
{ | |
struct drm_i915_private *dev_priv = to_i915(dev); | |
struct intel_fbdev *ifbdev; | |
int ret; | |
if (WARN_ON(INTEL_INFO(dev_priv)->num_pipes == 0)) | |
return -ENODEV; | |
ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); | |
if (ifbdev == NULL) | |
return -ENOMEM; | |
drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs); | |
if (!intel_fbdev_init_bios(dev, ifbdev)) | |
ifbdev->preferred_bpp = 32; | |
ret = drm_fb_helper_init(dev, &ifbdev->helper, 4); | |
if (ret) { | |
kfree(ifbdev); | |
return ret; | |
} | |
dev_priv->fbdev = ifbdev; | |
INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker); | |
drm_fb_helper_single_add_all_connectors(&ifbdev->helper); | |
return 0; | |
} | |
static void intel_fbdev_initial_config(void *data, async_cookie_t cookie) | |
{ | |
struct intel_fbdev *ifbdev = data; | |
/* Due to peculiar init order wrt to hpd handling this is separate. */ | |
if (drm_fb_helper_initial_config(&ifbdev->helper, | |
ifbdev->preferred_bpp)) { | |
intel_fbdev_unregister(to_i915(ifbdev->helper.dev)); | |
intel_fbdev_fini(to_i915(ifbdev->helper.dev)); | |
} | |
} | |
void intel_fbdev_unregister(struct drm_i915_private *dev_priv) | |
{ | |
struct intel_fbdev *ifbdev = dev_priv->fbdev; | |
if (!ifbdev) | |
return; | |
cancel_work_sync(&dev_priv->fbdev_suspend_work); | |
if (!current_is_async()) | |
intel_fbdev_sync(ifbdev); | |
drm_fb_helper_unregister_fbi(&ifbdev->helper); | |
} | |
void intel_fbdev_fini(struct drm_i915_private *dev_priv) | |
{ | |
struct intel_fbdev *ifbdev = fetch_and_zero(&dev_priv->fbdev); | |
if (!ifbdev) | |
return; | |
intel_fbdev_destroy(ifbdev); | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = 1 | |
bpp_sel = 32 or 16 | |
struct mga_fbdev { | |
struct drm_fb_helper helper; | |
struct mga_framebuffer mfb; | |
void *sysram; | |
int size; | |
struct ttm_bo_kmap_obj mapping; | |
int x1, y1, x2, y2; /* dirty rect */ | |
spinlock_t dirty_lock; | |
}; | |
int mgag200_fbdev_init(struct mga_device *mdev) | |
{ | |
struct mga_fbdev *mfbdev; | |
int ret; | |
int bpp_sel = 32; | |
/* prefer 16bpp on low end gpus with limited VRAM */ | |
if (IS_G200_SE(mdev) && mdev->mc.vram_size < (2048*1024)) | |
bpp_sel = 16; | |
mfbdev = devm_kzalloc(mdev->dev->dev, sizeof(struct mga_fbdev), GFP_KERNEL); | |
if (!mfbdev) | |
return -ENOMEM; | |
mdev->mfbdev = mfbdev; | |
spin_lock_init(&mfbdev->dirty_lock); | |
drm_fb_helper_prepare(mdev->dev, &mfbdev->helper, &mga_fb_helper_funcs); | |
ret = drm_fb_helper_init(mdev->dev, &mfbdev->helper, | |
MGAG200FB_CONN_LIMIT); | |
if (ret) | |
goto err_fb_helper; | |
ret = drm_fb_helper_single_add_all_connectors(&mfbdev->helper); | |
if (ret) | |
goto err_fb_setup; | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
drm_helper_disable_unused_functions(mdev->dev); | |
ret = drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel); | |
if (ret) | |
goto err_fb_setup; | |
return 0; | |
err_fb_setup: | |
drm_fb_helper_fini(&mfbdev->helper); | |
err_fb_helper: | |
mdev->mfbdev = NULL; | |
return ret; | |
} | |
static int mga_fbdev_destroy(struct drm_device *dev, | |
struct mga_fbdev *mfbdev) | |
{ | |
struct mga_framebuffer *mfb = &mfbdev->mfb; | |
drm_fb_helper_unregister_fbi(&mfbdev->helper); | |
if (mfb->obj) { | |
drm_gem_object_put_unlocked(mfb->obj); | |
mfb->obj = NULL; | |
} | |
drm_fb_helper_fini(&mfbdev->helper); | |
vfree(mfbdev->sysram); | |
drm_framebuffer_unregister_private(&mfb->base); | |
drm_framebuffer_cleanup(&mfb->base); | |
return 0; | |
} | |
void mgag200_fbdev_fini(struct mga_device *mdev) | |
{ | |
if (!mdev->mfbdev) | |
return; | |
mga_fbdev_destroy(mdev->dev, mdev->mfbdev); | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = priv->num_connectors | |
bpp_sel = 32 | |
struct msm_fbdev { | |
struct drm_fb_helper base; | |
struct drm_framebuffer *fb; | |
}; | |
struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) | |
{ | |
struct msm_drm_private *priv = dev->dev_private; | |
struct msm_fbdev *fbdev = NULL; | |
struct drm_fb_helper *helper; | |
int ret; | |
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); | |
if (!fbdev) | |
goto fail; | |
helper = &fbdev->base; | |
drm_fb_helper_prepare(dev, helper, &msm_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, helper, priv->num_connectors); | |
if (ret) { | |
dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret); | |
goto fail; | |
} | |
ret = drm_fb_helper_single_add_all_connectors(helper); | |
if (ret) | |
goto fini; | |
ret = drm_fb_helper_initial_config(helper, 32); | |
if (ret) | |
goto fini; | |
priv->fbdev = helper; | |
return helper; | |
fini: | |
drm_fb_helper_fini(helper); | |
fail: | |
kfree(fbdev); | |
return NULL; | |
} | |
void msm_fbdev_free(struct drm_device *dev) | |
{ | |
struct msm_drm_private *priv = dev->dev_private; | |
struct drm_fb_helper *helper = priv->fbdev; | |
struct msm_fbdev *fbdev; | |
DBG(); | |
drm_fb_helper_unregister_fbi(helper); | |
drm_fb_helper_fini(helper); | |
fbdev = to_msm_fbdev(priv->fbdev); | |
/* this will free the backing object */ | |
if (fbdev->fb) { | |
struct drm_gem_object *bo = | |
msm_framebuffer_bo(fbdev->fb, 0); | |
msm_gem_put_vaddr(bo); | |
drm_framebuffer_remove(fbdev->fb); | |
} | |
kfree(fbdev); | |
priv->fbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = 4 | |
bpp_sel = 8, 16, 32 | |
struct nouveau_fbdev { | |
struct drm_fb_helper helper; | |
unsigned int saved_flags; | |
struct nvif_object surf2d; | |
struct nvif_object clip; | |
struct nvif_object rop; | |
struct nvif_object patt; | |
struct nvif_object gdi; | |
struct nvif_object blit; | |
struct nvif_object twod; | |
}; | |
int | |
nouveau_fbcon_init(struct drm_device *dev) | |
{ | |
struct nouveau_drm *drm = nouveau_drm(dev); | |
struct nouveau_fbdev *fbcon; | |
int preferred_bpp; | |
int ret; | |
if (!dev->mode_config.num_crtc || | |
(dev->pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) | |
return 0; | |
fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); | |
if (!fbcon) | |
return -ENOMEM; | |
drm->fbcon = fbcon; | |
INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work); | |
drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); | |
ret = drm_fb_helper_init(dev, &fbcon->helper, 4); | |
if (ret) | |
goto free; | |
ret = drm_fb_helper_single_add_all_connectors(&fbcon->helper); | |
if (ret) | |
goto fini; | |
if (drm->client.device.info.ram_size <= 32 * 1024 * 1024) | |
preferred_bpp = 8; | |
else | |
if (drm->client.device.info.ram_size <= 64 * 1024 * 1024) | |
preferred_bpp = 16; | |
else | |
preferred_bpp = 32; | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
if (!drm_drv_uses_atomic_modeset(dev)) | |
drm_helper_disable_unused_functions(dev); | |
ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); | |
if (ret) | |
goto fini; | |
if (fbcon->helper.fbdev) | |
fbcon->helper.fbdev->pixmap.buf_align = 4; | |
return 0; | |
fini: | |
drm_fb_helper_fini(&fbcon->helper); | |
free: | |
kfree(fbcon); | |
return ret; | |
} | |
void | |
nouveau_fbcon_fini(struct drm_device *dev) | |
{ | |
struct nouveau_drm *drm = nouveau_drm(dev); | |
if (!drm->fbcon) | |
return; | |
nouveau_fbcon_accel_fini(dev); | |
nouveau_fbcon_destroy(dev, drm->fbcon); | |
kfree(drm->fbcon); | |
drm->fbcon = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = priv->num_connectors | |
bpp_sel = 32 | |
struct omap_fbdev { | |
struct drm_fb_helper base; | |
struct drm_framebuffer *fb; | |
struct drm_gem_object *bo; | |
bool ywrap_enabled; | |
/* for deferred dmm roll when getting called in atomic ctx */ | |
struct work_struct work; | |
}; | |
struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) | |
{ | |
struct omap_drm_private *priv = dev->dev_private; | |
struct omap_fbdev *fbdev = NULL; | |
struct drm_fb_helper *helper; | |
int ret = 0; | |
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); | |
if (!fbdev) | |
goto fail; | |
INIT_WORK(&fbdev->work, pan_worker); | |
helper = &fbdev->base; | |
drm_fb_helper_prepare(dev, helper, &omap_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, helper, priv->num_connectors); | |
if (ret) { | |
dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret); | |
goto fail; | |
} | |
ret = drm_fb_helper_single_add_all_connectors(helper); | |
if (ret) | |
goto fini; | |
ret = drm_fb_helper_initial_config(helper, 32); | |
if (ret) | |
goto fini; | |
priv->fbdev = helper; | |
return helper; | |
fini: | |
drm_fb_helper_fini(helper); | |
fail: | |
kfree(fbdev); | |
dev_warn(dev->dev, "omap_fbdev_init failed\n"); | |
/* well, limp along without an fbdev.. maybe X11 will work? */ | |
return NULL; | |
} | |
void omap_fbdev_free(struct drm_device *dev) | |
{ | |
struct omap_drm_private *priv = dev->dev_private; | |
struct drm_fb_helper *helper = priv->fbdev; | |
struct omap_fbdev *fbdev; | |
DBG(); | |
drm_fb_helper_unregister_fbi(helper); | |
drm_fb_helper_fini(helper); | |
fbdev = to_omap_fbdev(priv->fbdev); | |
/* unpin the GEM object pinned in omap_fbdev_create() */ | |
omap_gem_unpin(fbdev->bo); | |
/* this will free the backing object */ | |
if (fbdev->fb) | |
drm_framebuffer_remove(fbdev->fb); | |
kfree(fbdev); | |
priv->fbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = QXLFB_CONN_LIMIT == 1 | |
bpp_sel = 32 | |
struct qxl_fbdev { | |
struct drm_fb_helper helper; | |
struct qxl_framebuffer qfb; | |
struct qxl_device *qdev; | |
spinlock_t delayed_ops_lock; | |
struct list_head delayed_ops; | |
void *shadow; | |
int size; | |
}; | |
int qxl_fbdev_init(struct qxl_device *qdev) | |
{ | |
int ret = 0; | |
#ifdef CONFIG_DRM_FBDEV_EMULATION | |
struct qxl_fbdev *qfbdev; | |
int bpp_sel = 32; /* TODO: parameter from somewhere? */ | |
qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL); | |
if (!qfbdev) | |
return -ENOMEM; | |
qfbdev->qdev = qdev; | |
qdev->mode_info.qfbdev = qfbdev; | |
spin_lock_init(&qfbdev->delayed_ops_lock); | |
INIT_LIST_HEAD(&qfbdev->delayed_ops); | |
drm_fb_helper_prepare(&qdev->ddev, &qfbdev->helper, | |
&qxl_fb_helper_funcs); | |
ret = drm_fb_helper_init(&qdev->ddev, &qfbdev->helper, | |
QXLFB_CONN_LIMIT); | |
if (ret) | |
goto free; | |
ret = drm_fb_helper_single_add_all_connectors(&qfbdev->helper); | |
if (ret) | |
goto fini; | |
ret = drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel); | |
if (ret) | |
goto fini; | |
return 0; | |
fini: | |
drm_fb_helper_fini(&qfbdev->helper); | |
free: | |
kfree(qfbdev); | |
#endif | |
return ret; | |
} | |
static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev) | |
{ | |
struct qxl_framebuffer *qfb = &qfbdev->qfb; | |
drm_fb_helper_unregister_fbi(&qfbdev->helper); | |
if (qfb->obj) { | |
qxlfb_destroy_pinned_object(qfb->obj); | |
qfb->obj = NULL; | |
} | |
drm_fb_helper_fini(&qfbdev->helper); | |
vfree(qfbdev->shadow); | |
drm_framebuffer_cleanup(&qfb->base); | |
return 0; | |
} | |
void qxl_fbdev_fini(struct qxl_device *qdev) | |
{ | |
if (!qdev->mode_info.qfbdev) | |
return; | |
qxl_fbdev_destroy(&qdev->ddev, qdev->mode_info.qfbdev); | |
kfree(qdev->mode_info.qfbdev); | |
qdev->mode_info.qfbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = RADEONFB_CONN_LIMIT == 4 | |
bpp_sel = 8, 16, 32 | |
struct radeon_fbdev { | |
struct drm_fb_helper helper; | |
struct radeon_framebuffer rfb; | |
struct radeon_device *rdev; | |
}; | |
int radeon_fbdev_init(struct radeon_device *rdev) | |
{ | |
struct radeon_fbdev *rfbdev; | |
int bpp_sel = 32; | |
int ret; | |
/* don't enable fbdev if no connectors */ | |
if (list_empty(&rdev->ddev->mode_config.connector_list)) | |
return 0; | |
/* select 8 bpp console on 8MB cards, or 16 bpp on RN50 or 32MB */ | |
if (rdev->mc.real_vram_size <= (8*1024*1024)) | |
bpp_sel = 8; | |
else if (ASIC_IS_RN50(rdev) || | |
rdev->mc.real_vram_size <= (32*1024*1024)) | |
bpp_sel = 16; | |
rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL); | |
if (!rfbdev) | |
return -ENOMEM; | |
rfbdev->rdev = rdev; | |
rdev->mode_info.rfbdev = rfbdev; | |
drm_fb_helper_prepare(rdev->ddev, &rfbdev->helper, | |
&radeon_fb_helper_funcs); | |
ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper, | |
RADEONFB_CONN_LIMIT); | |
if (ret) | |
goto free; | |
ret = drm_fb_helper_single_add_all_connectors(&rfbdev->helper); | |
if (ret) | |
goto fini; | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
drm_helper_disable_unused_functions(rdev->ddev); | |
ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); | |
if (ret) | |
goto fini; | |
return 0; | |
fini: | |
drm_fb_helper_fini(&rfbdev->helper); | |
free: | |
kfree(rfbdev); | |
return ret; | |
} | |
static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) | |
{ | |
struct radeon_framebuffer *rfb = &rfbdev->rfb; | |
drm_fb_helper_unregister_fbi(&rfbdev->helper); | |
if (rfb->obj) { | |
radeonfb_destroy_pinned_object(rfb->obj); | |
rfb->obj = NULL; | |
} | |
drm_fb_helper_fini(&rfbdev->helper); | |
drm_framebuffer_unregister_private(&rfb->base); | |
drm_framebuffer_cleanup(&rfb->base); | |
return 0; | |
} | |
void radeon_fbdev_fini(struct radeon_device *rdev) | |
{ | |
if (!rdev->mode_info.rfbdev) | |
return; | |
radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); | |
kfree(rdev->mode_info.rfbdev); | |
rdev->mode_info.rfbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = ROCKCHIP_MAX_CONNECTOR == 2 | |
bpp_sel = PREFERRED_BPP == 32 | |
int rockchip_drm_fbdev_init(struct drm_device *dev) | |
{ | |
struct rockchip_drm_private *private = dev->dev_private; | |
struct drm_fb_helper *helper; | |
int ret; | |
if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector) | |
return -EINVAL; | |
helper = &private->fbdev_helper; | |
drm_fb_helper_prepare(dev, helper, &rockchip_drm_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, helper, ROCKCHIP_MAX_CONNECTOR); | |
if (ret < 0) { | |
dev_err(dev->dev, "Failed to initialize drm fb helper - %d.\n", | |
ret); | |
return ret; | |
} | |
ret = drm_fb_helper_single_add_all_connectors(helper); | |
if (ret < 0) { | |
dev_err(dev->dev, "Failed to add connectors - %d.\n", ret); | |
goto err_drm_fb_helper_fini; | |
} | |
ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); | |
if (ret < 0) { | |
dev_err(dev->dev, "Failed to set initial hw config - %d.\n", | |
ret); | |
goto err_drm_fb_helper_fini; | |
} | |
return 0; | |
err_drm_fb_helper_fini: | |
drm_fb_helper_fini(helper); | |
return ret; | |
} | |
void rockchip_drm_fbdev_fini(struct drm_device *dev) | |
{ | |
struct rockchip_drm_private *private = dev->dev_private; | |
struct drm_fb_helper *helper; | |
helper = &private->fbdev_helper; | |
drm_fb_helper_unregister_fbi(helper); | |
if (helper->fb) | |
drm_framebuffer_put(helper->fb); | |
drm_fb_helper_fini(helper); | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = drm->mode_config.num_connector | |
bpp_sel = 32 | |
struct tegra_fbdev { | |
struct drm_fb_helper base; | |
struct tegra_fb *fb; | |
}; | |
static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm) | |
{ | |
struct tegra_fbdev *fbdev; | |
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); | |
if (!fbdev) { | |
dev_err(drm->dev, "failed to allocate DRM fbdev\n"); | |
return ERR_PTR(-ENOMEM); | |
} | |
drm_fb_helper_prepare(drm, &fbdev->base, &tegra_fb_helper_funcs); | |
return fbdev; | |
} | |
static void tegra_fbdev_free(struct tegra_fbdev *fbdev) | |
{ | |
kfree(fbdev); | |
} | |
static int tegra_fbdev_init(struct tegra_fbdev *fbdev, | |
unsigned int preferred_bpp, | |
unsigned int num_crtc, | |
unsigned int max_connectors) | |
{ | |
struct drm_device *drm = fbdev->base.dev; | |
int err; | |
err = drm_fb_helper_init(drm, &fbdev->base, max_connectors); | |
if (err < 0) { | |
dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", | |
err); | |
return err; | |
} | |
err = drm_fb_helper_single_add_all_connectors(&fbdev->base); | |
if (err < 0) { | |
dev_err(drm->dev, "failed to add connectors: %d\n", err); | |
goto fini; | |
} | |
err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp); | |
if (err < 0) { | |
dev_err(drm->dev, "failed to set initial configuration: %d\n", | |
err); | |
goto fini; | |
} | |
return 0; | |
fini: | |
drm_fb_helper_fini(&fbdev->base); | |
return err; | |
} | |
static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) | |
{ | |
drm_fb_helper_unregister_fbi(&fbdev->base); | |
if (fbdev->fb) | |
drm_framebuffer_remove(&fbdev->fb->base); | |
drm_fb_helper_fini(&fbdev->base); | |
tegra_fbdev_free(fbdev); | |
} | |
void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev) | |
{ | |
if (fbdev) | |
drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev->base); | |
} | |
void tegra_fb_output_poll_changed(struct drm_device *drm) | |
{ | |
struct tegra_drm *tegra = drm->dev_private; | |
if (tegra->fbdev) | |
drm_fb_helper_hotplug_event(&tegra->fbdev->base); | |
} | |
#endif | |
int tegra_drm_fb_prepare(struct drm_device *drm) | |
{ | |
#ifdef CONFIG_DRM_FBDEV_EMULATION | |
struct tegra_drm *tegra = drm->dev_private; | |
tegra->fbdev = tegra_fbdev_create(drm); | |
if (IS_ERR(tegra->fbdev)) | |
return PTR_ERR(tegra->fbdev); | |
#endif | |
return 0; | |
} | |
void tegra_drm_fb_free(struct drm_device *drm) | |
{ | |
#ifdef CONFIG_DRM_FBDEV_EMULATION | |
struct tegra_drm *tegra = drm->dev_private; | |
tegra_fbdev_free(tegra->fbdev); | |
#endif | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = 1 | |
bpp_sel = fb_bpp (module parameter) | |
struct udl_fbdev { | |
struct drm_fb_helper helper; | |
struct udl_framebuffer ufb; | |
int fb_count; | |
}; | |
int udl_fbdev_init(struct drm_device *dev) | |
{ | |
struct udl_device *udl = dev->dev_private; | |
int bpp_sel = fb_bpp; | |
struct udl_fbdev *ufbdev; | |
int ret; | |
ufbdev = kzalloc(sizeof(struct udl_fbdev), GFP_KERNEL); | |
if (!ufbdev) | |
return -ENOMEM; | |
udl->fbdev = ufbdev; | |
drm_fb_helper_prepare(dev, &ufbdev->helper, &udl_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, &ufbdev->helper, 1); | |
if (ret) | |
goto free; | |
ret = drm_fb_helper_single_add_all_connectors(&ufbdev->helper); | |
if (ret) | |
goto fini; | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
drm_helper_disable_unused_functions(dev); | |
ret = drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel); | |
if (ret) | |
goto fini; | |
return 0; | |
fini: | |
drm_fb_helper_fini(&ufbdev->helper); | |
free: | |
kfree(ufbdev); | |
return ret; | |
} | |
void udl_fbdev_cleanup(struct drm_device *dev) | |
{ | |
struct udl_device *udl = dev->dev_private; | |
if (!udl->fbdev) | |
return; | |
udl_fbdev_destroy(dev, udl->fbdev); | |
kfree(udl->fbdev); | |
udl->fbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = VIRTIO_GPUFB_CONN_LIMIT == 1 | |
bpp_sel = 32 | |
struct virtio_gpu_fbdev { | |
struct drm_fb_helper helper; | |
struct virtio_gpu_framebuffer vgfb; | |
struct virtio_gpu_device *vgdev; | |
struct delayed_work work; | |
}; | |
int virtio_gpu_fbdev_init(struct virtio_gpu_device *vgdev) | |
{ | |
struct virtio_gpu_fbdev *vgfbdev; | |
int bpp_sel = 32; /* TODO: parameter from somewhere? */ | |
int ret; | |
vgfbdev = kzalloc(sizeof(struct virtio_gpu_fbdev), GFP_KERNEL); | |
if (!vgfbdev) | |
return -ENOMEM; | |
vgfbdev->vgdev = vgdev; | |
vgdev->vgfbdev = vgfbdev; | |
INIT_DELAYED_WORK(&vgfbdev->work, virtio_gpu_fb_dirty_work); | |
drm_fb_helper_prepare(vgdev->ddev, &vgfbdev->helper, | |
&virtio_gpu_fb_helper_funcs); | |
ret = drm_fb_helper_init(vgdev->ddev, &vgfbdev->helper, | |
VIRTIO_GPUFB_CONN_LIMIT); | |
if (ret) { | |
kfree(vgfbdev); | |
return ret; | |
} | |
drm_fb_helper_single_add_all_connectors(&vgfbdev->helper); | |
drm_fb_helper_initial_config(&vgfbdev->helper, bpp_sel); | |
return 0; | |
} | |
static int virtio_gpu_fbdev_destroy(struct drm_device *dev, | |
struct virtio_gpu_fbdev *vgfbdev) | |
{ | |
struct virtio_gpu_framebuffer *vgfb = &vgfbdev->vgfb; | |
drm_fb_helper_unregister_fbi(&vgfbdev->helper); | |
if (vgfb->obj) | |
vgfb->obj = NULL; | |
drm_fb_helper_fini(&vgfbdev->helper); | |
drm_framebuffer_cleanup(&vgfb->base); | |
return 0; | |
} | |
void virtio_gpu_fbdev_fini(struct virtio_gpu_device *vgdev) | |
{ | |
if (!vgdev->vgfbdev) | |
return; | |
virtio_gpu_fbdev_destroy(vgdev->ddev, vgdev->vgfbdev); | |
kfree(vgdev->vgfbdev); | |
vgdev->vgfbdev = NULL; | |
} | |
------------------------------------------------------------------------------- | |
max_conn_count = vbox->num_crtcs | |
bpp_sel = 32 | |
struct vbox_fbdev { | |
struct drm_fb_helper helper; | |
struct vbox_framebuffer afb; | |
int size; | |
struct ttm_bo_kmap_obj mapping; | |
int x1, y1, x2, y2; /* dirty rect */ | |
spinlock_t dirty_lock; | |
}; | |
int vbox_fbdev_init(struct drm_device *dev) | |
{ | |
struct vbox_private *vbox = dev->dev_private; | |
struct vbox_fbdev *fbdev; | |
int ret; | |
fbdev = devm_kzalloc(dev->dev, sizeof(*fbdev), GFP_KERNEL); | |
if (!fbdev) | |
return -ENOMEM; | |
vbox->fbdev = fbdev; | |
spin_lock_init(&fbdev->dirty_lock); | |
drm_fb_helper_prepare(dev, &fbdev->helper, &vbox_fb_helper_funcs); | |
ret = drm_fb_helper_init(dev, &fbdev->helper, vbox->num_crtcs); | |
if (ret) | |
return ret; | |
ret = drm_fb_helper_single_add_all_connectors(&fbdev->helper); | |
if (ret) | |
goto err_fini; | |
/* disable all the possible outputs/crtcs before entering KMS mode */ | |
drm_helper_disable_unused_functions(dev); | |
ret = drm_fb_helper_initial_config(&fbdev->helper, 32); | |
if (ret) | |
goto err_fini; | |
return 0; | |
err_fini: | |
drm_fb_helper_fini(&fbdev->helper); | |
return ret; | |
} | |
void vbox_fbdev_fini(struct drm_device *dev) | |
{ | |
struct vbox_private *vbox = dev->dev_private; | |
struct vbox_fbdev *fbdev = vbox->fbdev; | |
struct vbox_framebuffer *afb = &fbdev->afb; | |
#ifdef CONFIG_DRM_KMS_FB_HELPER | |
if (fbdev->helper.fbdev && fbdev->helper.fbdev->fbdefio) | |
fb_deferred_io_cleanup(fbdev->helper.fbdev); | |
#endif | |
drm_fb_helper_unregister_fbi(&fbdev->helper); | |
if (afb->obj) { | |
struct vbox_bo *bo = gem_to_vbox_bo(afb->obj); | |
if (!vbox_bo_reserve(bo, false)) { | |
if (bo->kmap.virtual) | |
ttm_bo_kunmap(&bo->kmap); | |
/* | |
* QXL does this, but is it really needed before | |
* freeing? | |
*/ | |
if (bo->pin_count) | |
vbox_bo_unpin(bo); | |
vbox_bo_unreserve(bo); | |
} | |
drm_gem_object_put_unlocked(afb->obj); | |
afb->obj = NULL; | |
} | |
drm_fb_helper_fini(&fbdev->helper); | |
drm_framebuffer_unregister_private(&afb->base); | |
drm_framebuffer_cleanup(&afb->base); | |
} | |
------------------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment