On Fri, Sep 18, 2015 at 06:12:02PM +0200, Philipp Zabel wrote: > From: CK Hu <ck.hu@xxxxxxxxxxxx> > > Add Mediatek legacy framebuffer support. > > Signed-off-by: CK Hu <ck.hu@xxxxxxxxxxxx> > Signed-off-by: YT Shen <yt.shen@xxxxxxxxxxxx> > --- > 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@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel