From patchwork Fri Mar 1 12:20:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrzej Hajda X-Patchwork-Id: 10835089 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C2E62922 for ; Fri, 1 Mar 2019 12:21:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF75D2D900 for ; Fri, 1 Mar 2019 12:21:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A05CF2D964; Fri, 1 Mar 2019 12:21:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C748F2D900 for ; Fri, 1 Mar 2019 12:21:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388177AbfCAMVR (ORCPT ); Fri, 1 Mar 2019 07:21:17 -0500 Received: from mailout2.w1.samsung.com ([210.118.77.12]:39183 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388125AbfCAMVQ (ORCPT ); Fri, 1 Mar 2019 07:21:16 -0500 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20190301122114euoutp02e3eef106989b39c99a0cb14a93b589e8~H1RMBcTmC2132421324euoutp02V; Fri, 1 Mar 2019 12:21:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20190301122114euoutp02e3eef106989b39c99a0cb14a93b589e8~H1RMBcTmC2132421324euoutp02V DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1551442874; bh=D/Q3pJwahUPY+c5OphoLI+w4qUa7jWUNPKnp2UOn9F4=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=LV0fvL7f3tDIaLyPID1eph9g8i2gBEZaX2j5iXyOIpnPybc2vpDB1y6S1ulSSYc8i F0EMZbIeFPK/norM2oqhWDhSL6Y8K1Bz0S6+WEJ4j9FRW0NqsCi7gU7/Yp6EF9DO2S hLfDZZnwdjT8D9PgbdB4l8m4HSqVioAP+lLtHN+c= Received: from eusmges1new.samsung.com (unknown [203.254.199.242]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20190301122113eucas1p1095b5db76db21365ab57421dfb6e3cb5~H1RLfIsJa3036530365eucas1p1Z; Fri, 1 Mar 2019 12:21:13 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges1new.samsung.com (EUCPMTA) with SMTP id C5.5E.04441.9B3297C5; Fri, 1 Mar 2019 12:21:13 +0000 (GMT) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20190301122113eucas1p2c3cce6f8651859bdef9785e3c7042efc~H1RK2poBZ1653516535eucas1p2f; Fri, 1 Mar 2019 12:21:13 +0000 (GMT) X-AuditID: cbfec7f2-5e3ff70000001159-6a-5c7923b9cffe Received: from eusync3.samsung.com ( [203.254.199.213]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 89.6C.04128.8B3297C5; Fri, 1 Mar 2019 12:21:12 +0000 (GMT) Received: from AMDC3748.DIGITAL.local ([106.120.43.17]) by eusync3.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0PNO007ENSZ56Z20@eusync3.samsung.com>; Fri, 01 Mar 2019 12:21:12 +0000 (GMT) From: Andrzej Hajda To: Inki Dae Cc: Andrzej Hajda , Bartlomiej Zolnierkiewicz , Marek Szyprowski , dri-devel@lists.freedesktop.org, linux-samsung-soc@vger.kernel.org Subject: [PATCH 19/23] drm/exynos/gscaler: add local path support Date: Fri, 01 Mar 2019 13:20:51 +0100 Message-id: <20190301122055.7135-20-a.hajda@samsung.com> X-Mailer: git-send-email 2.17.1 In-reply-to: <20190301122055.7135-1-a.hajda@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupjkeLIzCtJLcpLzFFi42LZduzned2dypUxBis2SlncWneO1WLjjPWs Fle+vmezmHR/AovFjPP7mCzWHrnL7sDmcb/7OJNH35ZVjB6fN8kFMEdx2aSk5mSWpRbp2yVw Zfy42MlUcC+sYt2mf+wNjBs8uhg5OSQETCQu7/jA1MXIxSEksIJRYuGcbYwgCSGBz4wSWx5l wxS9PvQfKr6MUaJzYQxEw39Gic3THjKBJNgENCX+br7JBmKLCChLrNrXzg5SxCxwiVHi9clu sG5hAUeJyW0nmEFsFgFViTevX7GD2LwCFhLTn5xjh9gmL7F6wwGwGk6g+MGVEIMkBN6ySvTP 6GWDKHKR6Fy2DcqWkbg8uZsFwq6XaJp5hRmioYNR4sTi5VBF1hKHj19kBbGZBfgkJm2bDlTE ARTnlehoE4Io8ZDYsmU6NCy6GSVuL29hnMAosYCRYRWjeGppcW56arFhXmq5XnFibnFpXrpe cn7uJkZgLJ3+d/zTDsavl5IOMQpwMCrx8Ca8LI8RYk0sK67MPcQowcGsJMLLx1AZI8SbklhZ lVqUH19UmpNafIhRmoNFSZy3muFBtJBAemJJanZqakFqEUyWiYNTqoFRJu9Ju9zFSWvaFjsV nD5dLqnNF+5xnf9p95RNl2TmXZvpsfl/2/yHbjYuQp8L5ntMWWX6aWvv306O+KlrHu+/I9G+ P4DHkFcoNln5hJ2Hv/0HuSMTYv9KeYm87b2Z0LZPUEvS/UI047Kte935Uz9xbHE5bDn3wiuT U1v8Cq2iV/ZsMVs5dwGbEktxRqKhFnNRcSIAEmI6XqECAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrBJMWRmVeSWpSXmKPExsVy+t/xq7o7lCtjDI4usrG4te4cq8XGGetZ La58fc9mMen+BBaLGef3MVmsPXKX3YHN4373cSaPvi2rGD0+b5ILYI7isklJzcksSy3St0vg yvhxsZOp4F5YxbpN/9gbGDd4dDFyckgImEi8PvSfsYuRi0NIYAmjROuBc2wQTiOTxM1rG5hB qtgENCX+br7JBmKLCChLrNrXzg5SxCxwhVGi/VsXO0hCWMBRYnLbCbAGFgFViTevX4HFeQUs JKY/OccOsU5eYvWGA2A1nEDxgytBBnEAbTOX2HQ6agIjzwJGhlWMIqmlxbnpucVGesWJucWl eel6yfm5mxiB4bHt2M8tOxi73gUfYhTgYFTi4U14WR4jxJpYVlyZe4hRgoNZSYSXj6EyRog3 JbGyKrUoP76oNCe1+BCjNAeLkjjveYPKKCGB9MSS1OzU1ILUIpgsEwenVAPjDMHZLD9z3rQp HFXdcWHKp8tMdo/PKCwri+0KZHj06dtCPneJj7t/JX12qlsUMvX1Z8Uzfjb9H7pexDGEGZfw /DnE802ZTZ57vu3n09MunfCccFWoJuft07s8fpVF7z39XzKfWfpQi2OD8RRmq2emW3kEdIIL FC4tb2NozZulbSxx4jL7c59SJZbijERDLeai4kQA8e7xvQsCAAA= X-CMS-MailID: 20190301122113eucas1p2c3cce6f8651859bdef9785e3c7042efc CMS-TYPE: 201P X-CMS-RootMailID: 20190301122113eucas1p2c3cce6f8651859bdef9785e3c7042efc References: <20190301122055.7135-1-a.hajda@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP GSCALERs in Exynos5433 have local path to DECON and DECON_TV. They can be used as extra planes with support for non-RGB formats and scaling. To enable it GSCALER must expose exynos_plane with associated plane callbacks and bind it to DECONs CRTCs. Moreover device locking should be added to prevent simultanous device usage by IPP and DRM. Signed-off-by: Andrzej Hajda --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 179 ++++++++++++++++++++---- drivers/gpu/drm/exynos/regs-gsc.h | 6 + 2 files changed, 156 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 8d5aa70c8ab8..28a738a68a82 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -16,14 +16,16 @@ #include #include #include -#include #include #include +#include #include #include #include "regs-gsc.h" +#include "exynos_drm_crtc.h" #include "exynos_drm_drv.h" +#include "exynos_drm_fb.h" #include "exynos_drm_ipp.h" /* @@ -98,11 +100,13 @@ struct gsc_scaler { */ struct gsc_context { struct exynos_drm_ipp ipp; + struct exynos_drm_plane plane; struct drm_device *drm_dev; struct device *dev; struct exynos_drm_ipp_task *task; struct exynos_drm_ipp_formats *formats; unsigned int num_formats; + struct spinlock lock; struct resource *regs_res; void __iomem *regs; @@ -113,8 +117,12 @@ struct gsc_context { int id; int irq; bool rotation; + bool enabled; + bool use_local_path; }; +#define to_gsc(ptr) container_of(ptr, struct gsc_context, ptr) + /** * struct gsc_driverdata - per device type driver data for init time. * @@ -127,6 +135,7 @@ struct gsc_driverdata { int num_limits; const char *clk_names[GSC_MAX_CLOCKS]; int num_clocks; + bool use_local_path; }; /* 8-tap Filter Coefficient */ @@ -377,6 +386,32 @@ static const int v_coef_4t[GSC_COEF_RATIO][GSC_COEF_ATTR][GSC_COEF_V_4T] = { } }; +static int gsc_dev_lock(struct gsc_context *ctx, void *task) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&ctx->lock, flags); + if (ctx->task) + ret = -EBUSY; + else + ctx->task = task; + spin_unlock_irqrestore(&ctx->lock, flags); + return ret; +} + +static void *gsc_dev_unlock(struct gsc_context *ctx) +{ + unsigned long flags; + void *task; + + spin_lock_irqsave(&ctx->lock, flags); + task = ctx->task; + ctx->task = NULL; + spin_unlock_irqrestore(&ctx->lock, flags); + return task; +} + static int gsc_sw_reset(struct gsc_context *ctx) { u32 cfg; @@ -1021,6 +1056,7 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx) static irqreturn_t gsc_irq_handler(int irq, void *dev_id) { struct gsc_context *ctx = dev_id; + struct exynos_drm_ipp_task *task; u32 status; int err = 0; @@ -1049,10 +1085,8 @@ static irqreturn_t gsc_irq_handler(int irq, void *dev_id) err = -EINVAL; } - if (ctx->task) { - struct exynos_drm_ipp_task *task = ctx->task; - - ctx->task = NULL; + task = gsc_dev_unlock(ctx); + if (!IS_ERR_OR_NULL(task)) { pm_runtime_mark_last_busy(ctx->dev); pm_runtime_put_autosuspend(ctx->dev); exynos_drm_ipp_task_done(task, err); @@ -1117,13 +1151,15 @@ static int gsc_commit(struct exynos_drm_ipp *ipp, struct gsc_context *ctx = container_of(ipp, struct gsc_context, ipp); int ret; - pm_runtime_get_sync(ctx->dev); - ctx->task = task; + ret = gsc_dev_lock(ctx, task); + if (ret) + return ret; + pm_runtime_get_sync(ctx->dev); ret = gsc_reset(ctx); if (ret) { pm_runtime_put_autosuspend(ctx->dev); - ctx->task = NULL; + gsc_dev_unlock(ctx); return ret; } @@ -1147,10 +1183,8 @@ static void gsc_abort(struct exynos_drm_ipp *ipp, container_of(ipp, struct gsc_context, ipp); gsc_reset(ctx); - if (ctx->task) { - struct exynos_drm_ipp_task *task = ctx->task; - - ctx->task = NULL; + task = gsc_dev_unlock(ctx); + if (!IS_ERR_OR_NULL(task)) { pm_runtime_mark_last_busy(ctx->dev); pm_runtime_put_autosuspend(ctx->dev); exynos_drm_ipp_task_done(task, -EIO); @@ -1162,11 +1196,97 @@ static struct exynos_drm_ipp_funcs ipp_funcs = { .abort = gsc_abort, }; +static const unsigned int gsc_formats[] = { + DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61, + DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, + DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422, +}; + +static const unsigned int gsc_tiled_formats[] = { + DRM_FORMAT_NV12, DRM_FORMAT_NV21, +}; + +static void gsc_update_plane(struct exynos_drm_plane *plane) +{ + struct gsc_context *ctx = to_gsc(plane); + struct exynos_drm_plane_state *state = + to_exynos_plane_state(plane->base.state); + struct drm_framebuffer *fb = plane->base.state->fb; + u32 src_w = fb->pitches[0] / fb->format->cpp[0], src_h = state->src.h; + u32 src_x = state->src.x, src_y = state->src.y; + u32 cropped_w = state->src.w, cropped_h = state->src.h; + u32 scaled_w = state->crtc.w, scaled_h = state->crtc.h; + int i; + + if (!ctx->enabled) { + while (gsc_dev_lock(ctx, ERR_PTR(-EBUSY)) < 0) + usleep_range(1000, 2000); + pm_runtime_get_sync(ctx->dev); + gsc_sw_reset(ctx); + gsc_src_set_buf_seq(ctx, 0, true); + gsc_write(GSC_SMART_IF_EN | GSC_HIERARCHICAL_MODE, GSC_SMART_IF_CON); + ctx->enabled = true; + } + gsc_write(GSC_POINT(src_x, src_y), GSC_SRCIMG_OFFSET); + gsc_write(GSC_POINT(src_w, src_h), GSC_SRCIMG_SIZE); + gsc_write(GSC_POINT(cropped_w, cropped_h), GSC_CROPPED_SIZE); + gsc_write(GSC_POINT(scaled_w, scaled_h), GSC_SCALED_SIZE); + gsc_write(GSC_OUT_PATH_LOCAL | GSC_OUT_RGB_HD_WIDE, GSC_OUT_CON); + gsc_write(GSC_POINT(1, 1), GSC_PRE_SCALE_RATIO); + gsc_write(BIT(16) * cropped_w / scaled_w, GSC_MAIN_H_RATIO); + gsc_write(BIT(16) * cropped_h / scaled_h, GSC_MAIN_V_RATIO); + gsc_write(exynos_drm_fb_dma_addr(fb, 0), GSC_IN_BASE_ADDR_Y(0)); + if (fb->format->num_planes > 1) + gsc_write(exynos_drm_fb_dma_addr(fb, 1), GSC_IN_BASE_ADDR_CB(0)); + if (fb->format->num_planes > 2) + gsc_write(exynos_drm_fb_dma_addr(fb, 2), GSC_IN_BASE_ADDR_CR(0)); + gsc_src_set_fmt(ctx, fb->format->format, fb->modifier); + gsc_write(scaled_w * scaled_h, GSC_SMART_IF_PIXEL_NUM); + gsc_write(GSC_ENABLE_SFR_UPDATE | GSC_ENABLE_ON, GSC_ENABLE); +} + +static void gsc_disable_plane(struct exynos_drm_plane *plane) +{ + struct gsc_context *ctx = to_gsc(plane); + u32 val; + + val = gsc_read(GSC_ENABLE); + val |= GSC_ENABLE_SFR_UPDATE; + val &= ~GSC_ENABLE_ON; + gsc_write(val, GSC_ENABLE); + pm_runtime_mark_last_busy(ctx->dev); + pm_runtime_put_autosuspend(ctx->dev); + ctx->enabled = false; + gsc_dev_unlock(ctx); +} + +const struct exynos_drm_plane_ops gsc_plane_ops = { + .update_plane = gsc_update_plane, + .disable_plane = gsc_disable_plane +}; + +static void gsc_set_possible_crtcs(struct gsc_context *ctx) +{ + struct exynos_drm_crtc *crtc; + u32 mask = 0; + + crtc = exynos_drm_crtc_get_by_type(ctx->drm_dev, EXYNOS_DISPLAY_TYPE_HDMI); + if (crtc) + mask |= drm_crtc_mask(&crtc->base); + crtc = exynos_drm_crtc_get_by_type(ctx->drm_dev, EXYNOS_DISPLAY_TYPE_LCD); + if (crtc) + mask |= drm_crtc_mask(&crtc->base); + ctx->plane.base.possible_crtcs = mask; +} + static int gsc_bind(struct device *dev, struct device *master, void *data) { struct gsc_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; struct exynos_drm_ipp *ipp = &ctx->ipp; + int ret; ctx->drm_dev = drm_dev; exynos_drm_register_dma(drm_dev, dev); @@ -1176,9 +1296,19 @@ static int gsc_bind(struct device *dev, struct device *master, void *data) DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT, ctx->formats, ctx->num_formats, "gsc"); - dev_info(dev, "The exynos gscaler has been probed successfully\n"); - - return 0; + if (!ctx->use_local_path) + return 0; + + ctx->plane.index = ctx->id; + ctx->plane.capabilities = EXYNOS_DRM_PLANE_CAP_GSCALER | + EXYNOS_DRM_PLANE_CAP_ZPOS | + EXYNOS_DRM_PLANE_CAP_SCALE | + EXYNOS_DRM_PLANE_CAP_WIN_BLEND; + ctx->plane.ops = &gsc_plane_ops; + ret = exynos_plane_init(drm_dev, &ctx->plane, gsc_formats, + ARRAY_SIZE(gsc_formats), 0); + gsc_set_possible_crtcs(ctx); + return ret; } static void gsc_unbind(struct device *dev, struct device *master, @@ -1197,18 +1327,6 @@ static const struct component_ops gsc_component_ops = { .unbind = gsc_unbind, }; -static const unsigned int gsc_formats[] = { - DRM_FORMAT_ARGB8888, - DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_BGRX8888, - DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61, - DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, - DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422, -}; - -static const unsigned int gsc_tiled_formats[] = { - DRM_FORMAT_NV12, DRM_FORMAT_NV21, -}; - static int gsc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1226,6 +1344,8 @@ static int gsc_probe(struct platform_device *pdev) ctx->dev = dev; ctx->num_clocks = driver_data->num_clocks; ctx->clk_names = driver_data->clk_names; + ctx->use_local_path = driver_data->use_local_path; + spin_lock_init(&ctx->lock); /* construct formats/limits array */ num_formats = ARRAY_SIZE(gsc_formats) + ARRAY_SIZE(gsc_tiled_formats); @@ -1395,10 +1515,11 @@ static struct gsc_driverdata gsc_exynos5420_drvdata = { }; static struct gsc_driverdata gsc_exynos5433_drvdata = { - .clk_names = {"pclk", "aclk", "aclk_xiu", "aclk_gsclbend"}, - .num_clocks = 4, + .clk_names = {"pclk", "aclk", "aclk_xiu", "aclk_gsclbend", "gsd"}, + .num_clocks = 5, .limits = gsc_5433_limits, .num_limits = ARRAY_SIZE(gsc_5433_limits), + .use_local_path = true, }; static const struct of_device_id exynos_drm_gsc_of_match[] = { diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h index 16b39734115c..7c23a79085e2 100644 --- a/drivers/gpu/drm/exynos/regs-gsc.h +++ b/drivers/gpu/drm/exynos/regs-gsc.h @@ -91,6 +91,7 @@ #define GSC_IN_PATH_LOCAL (1 << 0) #define GSC_IN_PATH_MEMORY (0 << 0) +#define GSC_POINT(x, y) ((x) + ((y) << 16)) /* G-Scaler source image size */ #define GSC_SRCIMG_SIZE 0x14 #define GSC_SRCIMG_HEIGHT_MASK (0x1fff << 16) @@ -264,6 +265,11 @@ #define GSC_VPOSITION 0xA7C #define GSC_VPOS_F(x) ((x) << 0) +#define GSC_SMART_IF_PIXEL_NUM 0xAF0 + +#define GSC_SMART_IF_CON 0xAF4 +#define GSC_SMART_IF_EN (1 << 0) +#define GSC_HIERARCHICAL_MODE (0x3 << 1) /* G-Scaler clock initial count */ #define GSC_CLK_INIT_COUNT 0xC00