Message ID | 1442592722-29004-5-git-send-email-p.zabel@pengutronix.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Sep 18, 2015 at 06:12:02PM +0200, Philipp Zabel wrote: > From: CK Hu <ck.hu@mediatek.com> > > Add Mediatek legacy framebuffer support. > > Signed-off-by: CK Hu <ck.hu@mediatek.com> > Signed-off-by: YT Shen <yt.shen@mediatek.com> > --- > drivers/gpu/drm/mediatek/Kconfig | 12 +++ > drivers/gpu/drm/mediatek/mtk_drm_drv.c | 13 +++ > drivers/gpu/drm/mediatek/mtk_drm_fb.c | 192 +++++++++++++++++++++++++++++++++ > drivers/gpu/drm/mediatek/mtk_drm_fb.h | 1 + > 4 files changed, 218 insertions(+) > > diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig > index 5343cf1..fa581fb 100644 > --- a/drivers/gpu/drm/mediatek/Kconfig > +++ b/drivers/gpu/drm/mediatek/Kconfig > @@ -14,3 +14,15 @@ config DRM_MEDIATEK > This driver provides kernel mode setting and > buffer management to userspace. > > +config DRM_MEDIATEK_FBDEV > + bool "Enable legacy fbdev support for Mediatek DRM" > + depends on DRM_MEDIATEK > + select FB_SYS_FILLRECT > + select FB_SYS_COPYAREA > + select FB_SYS_IMAGEBLIT > + select DRM_KMS_FB_HELPER > + help > + Choose this option if you have a need for the legacy > + fbdev support. Note that this support also provides > + the Linux console on top of the Mediatek DRM mode > + setting driver. With the new Kconfig for fbdev emulation in 4.3 and the module option to disable it queued up for 4.4 driver-private Kconfig entries for fbdev aren't needed any more. -Daniel > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c > index fc071fe..b67c582 100644 > --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c > +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c > @@ -46,6 +46,9 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = { > .fb_create = mtk_drm_mode_fb_create, > .atomic_check = drm_atomic_helper_check, > .atomic_commit = mtk_atomic_commit, > +#ifdef CONFIG_DRM_MEDIATEK_FBDEV > + .output_poll_changed = mtk_drm_mode_output_poll_changed, > +#endif > }; > > static const enum mtk_ddp_comp_type mtk_ddp_main[] = { > @@ -140,6 +143,12 @@ static int mtk_drm_kms_init(struct drm_device *dev) > drm_kms_helper_poll_init(dev); > drm_mode_config_reset(dev); > > +#ifdef CONFIG_DRM_MEDIATEK_FBDEV > + err = mtk_fbdev_create(dev); > + if (err) > + goto err_larb_get; > +#endif > + > return 0; > > err_larb_get: > @@ -160,6 +169,10 @@ static void mtk_drm_kms_deinit(struct drm_device *dev) > { > drm_kms_helper_poll_fini(dev); > > +#ifdef CONFIG_DRM_MEDIATEK_FBDEV > + mtk_fbdev_destroy(dev); > +#endif > + > drm_vblank_cleanup(dev); > drm_mode_config_cleanup(dev); > } > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c > index dfa931b..9295ad3 100644 > --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c > +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.c > @@ -102,6 +102,198 @@ static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, > return mtk_fb; > } > > +#ifdef CONFIG_DRM_MEDIATEK_FBDEV > +static int mtk_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) > +{ > + struct drm_fb_helper *helper = info->par; > + struct mtk_drm_fb *mtk_fb = to_mtk_fb(helper->fb); > + > + return mtk_drm_gem_mmap_buf(mtk_fb->gem_obj[0], vma); > +} > + > +static struct fb_ops mtk_fb_ops = { > + .owner = THIS_MODULE, > + .fb_fillrect = sys_fillrect, > + .fb_copyarea = sys_copyarea, > + .fb_imageblit = sys_imageblit, > + .fb_check_var = drm_fb_helper_check_var, > + .fb_set_par = drm_fb_helper_set_par, > + .fb_blank = drm_fb_helper_blank, > + .fb_pan_display = drm_fb_helper_pan_display, > + .fb_setcmap = drm_fb_helper_setcmap, > + .fb_mmap = mtk_drm_fb_mmap, > +}; > + > +static int mtk_fbdev_probe(struct drm_fb_helper *helper, > + struct drm_fb_helper_surface_size *sizes) > +{ > + struct drm_device *dev = helper->dev; > + struct drm_mode_fb_cmd2 mode = { 0 }; > + struct mtk_drm_fb *mtk_fb; > + struct mtk_drm_gem_obj *mtk_gem; > + struct drm_gem_object *gem; > + struct fb_info *info; > + struct drm_framebuffer *fb; > + unsigned long offset; > + size_t size; > + int err; > + > + mode.width = sizes->surface_width; > + mode.height = sizes->surface_height; > + mode.pitches[0] = sizes->surface_width * ((sizes->surface_bpp + 7) / 8); > + mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, > + sizes->surface_depth); > + > + mode.height = mode.height;/* << 1; for fb use? */ > + size = mode.pitches[0] * mode.height; > + dev_info(dev->dev, "mtk_fbdev_probe %dx%d bpp %d pitch %d size %zu\n", > + mode.width, mode.height, sizes->surface_bpp, mode.pitches[0], > + size); > + > + mtk_gem = mtk_drm_gem_create(dev, size, true); > + if (IS_ERR(mtk_gem)) { > + err = PTR_ERR(mtk_gem); > + goto fini; > + } > + > + gem = &mtk_gem->base; > + > + mtk_fb = mtk_drm_framebuffer_init(dev, &mode, &gem); > + if (IS_ERR(mtk_fb)) { > + dev_err(dev->dev, "failed to allocate DRM framebuffer\n"); > + err = PTR_ERR(mtk_fb); > + goto free; > + } > + fb = &mtk_fb->base; > + > + info = framebuffer_alloc(0, dev->dev); > + if (!info) { > + dev_err(dev->dev, "failed to allocate framebuffer info\n"); > + err = PTR_ERR(info); > + goto release; > + } > + > + helper->fb = fb; > + helper->fbdev = info; > + > + info->par = helper; > + info->flags = FBINFO_FLAG_DEFAULT; > + info->fbops = &mtk_fb_ops; > + > + err = fb_alloc_cmap(&info->cmap, 256, 0); > + if (err < 0) { > + dev_err(dev->dev, "failed to allocate color map: %d\n", err); > + goto destroy; > + } > + > + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); > + drm_fb_helper_fill_var(info, helper, fb->width, fb->height); > + > + offset = info->var.xoffset * (fb->bits_per_pixel + 7) / 8; > + offset += info->var.yoffset * fb->pitches[0]; > + > + strcpy(info->fix.id, "mtk"); > + /* dev->mode_config.fb_base = (resource_size_t)bo->paddr; */ > + info->var.yres = info->var.yres_virtual;/* >> 1; for fb use? */ > + info->fix.smem_start = mtk_gem->dma_addr + offset; > + info->fix.smem_len = size; > + info->screen_base = mtk_gem->kvaddr + offset; > + info->screen_size = size; > + > + return 0; > + > +destroy: > + drm_framebuffer_unregister_private(fb); > + mtk_drm_fb_destroy(fb); > +release: > + framebuffer_release(info); > +free: > + mtk_drm_gem_free_object(&mtk_gem->base); > +fini: > + dev_err(dev->dev, "mtk_fbdev_probe fail\n"); > + return err; > +} > + > +static const struct drm_fb_helper_funcs mtk_drm_fb_helper_funcs = { > + .fb_probe = mtk_fbdev_probe, > +}; > + > +int mtk_fbdev_create(struct drm_device *dev) > +{ > + struct mtk_drm_private *priv = dev->dev_private; > + struct drm_fb_helper *fbdev; > + int ret; > + > + fbdev = devm_kzalloc(dev->dev, sizeof(*fbdev), GFP_KERNEL); > + if (!fbdev) > + return -ENOMEM; > + > + drm_fb_helper_prepare(dev, fbdev, &mtk_drm_fb_helper_funcs); > + > + ret = drm_fb_helper_init(dev, fbdev, dev->mode_config.num_crtc, > + dev->mode_config.num_connector); > + if (ret) { > + dev_err(dev->dev, "failed to initialize DRM FB helper\n"); > + goto fini; > + } > + > + ret = drm_fb_helper_single_add_all_connectors(fbdev); > + if (ret) { > + dev_err(dev->dev, "failed to add connectors\n"); > + goto fini; > + } > + > + ret = drm_fb_helper_initial_config(fbdev, FBDEV_BPP); > + if (ret) { > + dev_err(dev->dev, "failed to set initial configuration\n"); > + goto fini; > + } > + priv->fb_helper = fbdev; > + > + return 0; > + > +fini: > + drm_fb_helper_fini(fbdev); > + > + return ret; > +} > + > +void mtk_fbdev_destroy(struct drm_device *dev) > +{ > + struct mtk_drm_private *priv = dev->dev_private; > + struct drm_fb_helper *helper = priv->fb_helper; > + struct fb_info *info = helper->fbdev; > + > + if (info) { > + int err; > + > + err = unregister_framebuffer(info); > + if (err < 0) > + DRM_DEBUG_KMS("failed to unregister framebuffer\n"); > + > + if (info->cmap.len) > + fb_dealloc_cmap(&info->cmap); > + > + framebuffer_release(info); > + } > + > + if (helper->fb) { > + drm_framebuffer_unregister_private(helper->fb); > + mtk_drm_fb_destroy(helper->fb); > + } > + > + drm_fb_helper_fini(helper); > +} > + > +void mtk_drm_mode_output_poll_changed(struct drm_device *dev) > +{ > + struct mtk_drm_private *priv = dev->dev_private; > + > + if (priv->fb_helper) > + drm_fb_helper_hotplug_event(priv->fb_helper); > +} > +#endif > + > struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, > struct drm_file *file, > struct drm_mode_fb_cmd2 *cmd) > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.h b/drivers/gpu/drm/mediatek/mtk_drm_fb.h > index 9ce7307..acbfecf 100644 > --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.h > +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.h > @@ -15,6 +15,7 @@ > #define MTK_DRM_FB_H > > #define MAX_FB_OBJ 3 > +#define FBDEV_BPP 16 > > struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb, > unsigned int plane); > -- > 2.5.1 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel
Hi Daniel, Am Dienstag, den 22.09.2015, 11:29 +0200 schrieb Daniel Vetter: > > diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig > > index 5343cf1..fa581fb 100644 > > --- a/drivers/gpu/drm/mediatek/Kconfig > > +++ b/drivers/gpu/drm/mediatek/Kconfig > > @@ -14,3 +14,15 @@ config DRM_MEDIATEK > > This driver provides kernel mode setting and > > buffer management to userspace. > > > > +config DRM_MEDIATEK_FBDEV > > + bool "Enable legacy fbdev support for Mediatek DRM" > > + depends on DRM_MEDIATEK > > + select FB_SYS_FILLRECT > > + select FB_SYS_COPYAREA > > + select FB_SYS_IMAGEBLIT > > + select DRM_KMS_FB_HELPER > > + help > > + Choose this option if you have a need for the legacy > > + fbdev support. Note that this support also provides > > + the Linux console on top of the Mediatek DRM mode > > + setting driver. > > With the new Kconfig for fbdev emulation in 4.3 and the module option to > disable it queued up for 4.4 driver-private Kconfig entries for fbdev > aren't needed any more. > -Daniel I'll drop it for the next patch submission, thanks. regards Philipp
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig index 5343cf1..fa581fb 100644 --- a/drivers/gpu/drm/mediatek/Kconfig +++ b/drivers/gpu/drm/mediatek/Kconfig @@ -14,3 +14,15 @@ config DRM_MEDIATEK This driver provides kernel mode setting and buffer management to userspace. +config DRM_MEDIATEK_FBDEV + bool "Enable legacy fbdev support for Mediatek DRM" + depends on DRM_MEDIATEK + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select DRM_KMS_FB_HELPER + help + Choose this option if you have a need for the legacy + fbdev support. Note that this support also provides + the Linux console on top of the Mediatek DRM mode + setting driver. diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index fc071fe..b67c582 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -46,6 +46,9 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = { .fb_create = mtk_drm_mode_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = mtk_atomic_commit, +#ifdef CONFIG_DRM_MEDIATEK_FBDEV + .output_poll_changed = mtk_drm_mode_output_poll_changed, +#endif }; static const enum mtk_ddp_comp_type mtk_ddp_main[] = { @@ -140,6 +143,12 @@ static int mtk_drm_kms_init(struct drm_device *dev) drm_kms_helper_poll_init(dev); drm_mode_config_reset(dev); +#ifdef CONFIG_DRM_MEDIATEK_FBDEV + err = mtk_fbdev_create(dev); + if (err) + goto err_larb_get; +#endif + return 0; err_larb_get: @@ -160,6 +169,10 @@ static void mtk_drm_kms_deinit(struct drm_device *dev) { drm_kms_helper_poll_fini(dev); +#ifdef CONFIG_DRM_MEDIATEK_FBDEV + mtk_fbdev_destroy(dev); +#endif + drm_vblank_cleanup(dev); drm_mode_config_cleanup(dev); } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c index dfa931b..9295ad3 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.c @@ -102,6 +102,198 @@ static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, return mtk_fb; } +#ifdef CONFIG_DRM_MEDIATEK_FBDEV +static int mtk_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *helper = info->par; + struct mtk_drm_fb *mtk_fb = to_mtk_fb(helper->fb); + + return mtk_drm_gem_mmap_buf(mtk_fb->gem_obj[0], vma); +} + +static struct fb_ops mtk_fb_ops = { + .owner = THIS_MODULE, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_blank = drm_fb_helper_blank, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_setcmap = drm_fb_helper_setcmap, + .fb_mmap = mtk_drm_fb_mmap, +}; + +static int mtk_fbdev_probe(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_device *dev = helper->dev; + struct drm_mode_fb_cmd2 mode = { 0 }; + struct mtk_drm_fb *mtk_fb; + struct mtk_drm_gem_obj *mtk_gem; + struct drm_gem_object *gem; + struct fb_info *info; + struct drm_framebuffer *fb; + unsigned long offset; + size_t size; + int err; + + mode.width = sizes->surface_width; + mode.height = sizes->surface_height; + mode.pitches[0] = sizes->surface_width * ((sizes->surface_bpp + 7) / 8); + mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + + mode.height = mode.height;/* << 1; for fb use? */ + size = mode.pitches[0] * mode.height; + dev_info(dev->dev, "mtk_fbdev_probe %dx%d bpp %d pitch %d size %zu\n", + mode.width, mode.height, sizes->surface_bpp, mode.pitches[0], + size); + + mtk_gem = mtk_drm_gem_create(dev, size, true); + if (IS_ERR(mtk_gem)) { + err = PTR_ERR(mtk_gem); + goto fini; + } + + gem = &mtk_gem->base; + + mtk_fb = mtk_drm_framebuffer_init(dev, &mode, &gem); + if (IS_ERR(mtk_fb)) { + dev_err(dev->dev, "failed to allocate DRM framebuffer\n"); + err = PTR_ERR(mtk_fb); + goto free; + } + fb = &mtk_fb->base; + + info = framebuffer_alloc(0, dev->dev); + if (!info) { + dev_err(dev->dev, "failed to allocate framebuffer info\n"); + err = PTR_ERR(info); + goto release; + } + + helper->fb = fb; + helper->fbdev = info; + + info->par = helper; + info->flags = FBINFO_FLAG_DEFAULT; + info->fbops = &mtk_fb_ops; + + err = fb_alloc_cmap(&info->cmap, 256, 0); + if (err < 0) { + dev_err(dev->dev, "failed to allocate color map: %d\n", err); + goto destroy; + } + + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); + drm_fb_helper_fill_var(info, helper, fb->width, fb->height); + + offset = info->var.xoffset * (fb->bits_per_pixel + 7) / 8; + offset += info->var.yoffset * fb->pitches[0]; + + strcpy(info->fix.id, "mtk"); + /* dev->mode_config.fb_base = (resource_size_t)bo->paddr; */ + info->var.yres = info->var.yres_virtual;/* >> 1; for fb use? */ + info->fix.smem_start = mtk_gem->dma_addr + offset; + info->fix.smem_len = size; + info->screen_base = mtk_gem->kvaddr + offset; + info->screen_size = size; + + return 0; + +destroy: + drm_framebuffer_unregister_private(fb); + mtk_drm_fb_destroy(fb); +release: + framebuffer_release(info); +free: + mtk_drm_gem_free_object(&mtk_gem->base); +fini: + dev_err(dev->dev, "mtk_fbdev_probe fail\n"); + return err; +} + +static const struct drm_fb_helper_funcs mtk_drm_fb_helper_funcs = { + .fb_probe = mtk_fbdev_probe, +}; + +int mtk_fbdev_create(struct drm_device *dev) +{ + struct mtk_drm_private *priv = dev->dev_private; + struct drm_fb_helper *fbdev; + int ret; + + fbdev = devm_kzalloc(dev->dev, sizeof(*fbdev), GFP_KERNEL); + if (!fbdev) + return -ENOMEM; + + drm_fb_helper_prepare(dev, fbdev, &mtk_drm_fb_helper_funcs); + + ret = drm_fb_helper_init(dev, fbdev, dev->mode_config.num_crtc, + dev->mode_config.num_connector); + if (ret) { + dev_err(dev->dev, "failed to initialize DRM FB helper\n"); + goto fini; + } + + ret = drm_fb_helper_single_add_all_connectors(fbdev); + if (ret) { + dev_err(dev->dev, "failed to add connectors\n"); + goto fini; + } + + ret = drm_fb_helper_initial_config(fbdev, FBDEV_BPP); + if (ret) { + dev_err(dev->dev, "failed to set initial configuration\n"); + goto fini; + } + priv->fb_helper = fbdev; + + return 0; + +fini: + drm_fb_helper_fini(fbdev); + + return ret; +} + +void mtk_fbdev_destroy(struct drm_device *dev) +{ + struct mtk_drm_private *priv = dev->dev_private; + struct drm_fb_helper *helper = priv->fb_helper; + struct fb_info *info = helper->fbdev; + + if (info) { + int err; + + err = unregister_framebuffer(info); + if (err < 0) + DRM_DEBUG_KMS("failed to unregister framebuffer\n"); + + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); + + framebuffer_release(info); + } + + if (helper->fb) { + drm_framebuffer_unregister_private(helper->fb); + mtk_drm_fb_destroy(helper->fb); + } + + drm_fb_helper_fini(helper); +} + +void mtk_drm_mode_output_poll_changed(struct drm_device *dev) +{ + struct mtk_drm_private *priv = dev->dev_private; + + if (priv->fb_helper) + drm_fb_helper_hotplug_event(priv->fb_helper); +} +#endif + struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, struct drm_file *file, struct drm_mode_fb_cmd2 *cmd) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.h b/drivers/gpu/drm/mediatek/mtk_drm_fb.h index 9ce7307..acbfecf 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.h @@ -15,6 +15,7 @@ #define MTK_DRM_FB_H #define MAX_FB_OBJ 3 +#define FBDEV_BPP 16 struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane);