From patchwork Fri Sep 18 16:12:02 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philipp Zabel X-Patchwork-Id: 7218711 Return-Path: X-Original-To: patchwork-linux-mediatek@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id CD888BEEC1 for ; Fri, 18 Sep 2015 16:13:04 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A44AF2091D for ; Fri, 18 Sep 2015 16:13:03 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7FFE020914 for ; Fri, 18 Sep 2015 16:13:00 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZcyHU-0000Z5-50; Fri, 18 Sep 2015 16:13:00 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZcyHR-0000O4-3P for linux-mediatek@lists.infradead.org; Fri, 18 Sep 2015 16:12:58 +0000 Received: from dude.hi.4.pengutronix.de ([10.1.0.7] helo=dude.pengutronix.de.) by metis.ext.pengutronix.de with esmtp (Exim 4.80) (envelope-from ) id 1ZcyGv-0003xQ-9C; Fri, 18 Sep 2015 18:12:25 +0200 From: Philipp Zabel To: dri-devel@lists.freedesktop.org Subject: [RFC v2 4/4] drm/mediatek: Add DRM-based framebuffer device Date: Fri, 18 Sep 2015 18:12:02 +0200 Message-Id: <1442592722-29004-5-git-send-email-p.zabel@pengutronix.de> X-Mailer: git-send-email 2.5.1 In-Reply-To: <1442592722-29004-1-git-send-email-p.zabel@pengutronix.de> References: <1442592722-29004-1-git-send-email-p.zabel@pengutronix.de> X-SA-Exim-Connect-IP: 10.1.0.7 X-SA-Exim-Mail-From: p.zabel@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-mediatek@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150918_091257_359012_521BC5F2 X-CRM114-Status: GOOD ( 16.33 ) X-Spam-Score: -1.9 (-) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , devicetree@vger.kernel.org, Paul Bolle , YT Shen , Jitao Shi , Pawel Moll , Ian Campbell , Cawa Cheng , Daniel Stone , CK Hu , Rob Herring , linux-mediatek@lists.infradead.org, kernel@pengutronix.de, Kumar Gala , Matthias Brugger , Dave Airlie MIME-Version: 1.0 Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: CK Hu Add Mediatek legacy framebuffer support. Signed-off-by: CK Hu Signed-off-by: YT Shen --- 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. 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);