Skip to content

Instantly share code, notes, and snippets.

@notro
Created October 18, 2017 13:56
Show Gist options
  • Save notro/d7fc2809736cdddb68a644b589a86ee1 to your computer and use it in GitHub Desktop.
Save notro/d7fc2809736cdddb68a644b589a86ee1 to your computer and use it in GitHub Desktop.
-------------------------------------------------------------------------------
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