From patchwork Wed Mar 20 13:07:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrzej Hajda X-Patchwork-Id: 10861599 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 7A7D018EC for ; Wed, 20 Mar 2019 13:07:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6074529BD8 for ; Wed, 20 Mar 2019 13:07:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5E52A28BA9; Wed, 20 Mar 2019 13:07:25 +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 6323629A8A for ; Wed, 20 Mar 2019 13:07:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727663AbfCTNHY (ORCPT ); Wed, 20 Mar 2019 09:07:24 -0400 Received: from mailout2.w1.samsung.com ([210.118.77.12]:58261 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727359AbfCTNHX (ORCPT ); Wed, 20 Mar 2019 09:07:23 -0400 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20190320130721euoutp025d2ead20fb9ac48a4f5e3290cf6dc052~NrJ4D5N081535315353euoutp02N; Wed, 20 Mar 2019 13:07:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20190320130721euoutp025d2ead20fb9ac48a4f5e3290cf6dc052~NrJ4D5N081535315353euoutp02N DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1553087241; bh=D/Q3pJwahUPY+c5OphoLI+w4qUa7jWUNPKnp2UOn9F4=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=CKIXAYNksIhHWd8bM6Cf45wO4hUUbKdy4q//7IDf43jFJ1cUYjOLX4fGwEfyp+0Kh jwkOHAKq3vk2EmdICacLcLcBg3thuj9Jc7xxeWlyFy60aEIaV0BieBvYQ9fia8FxGA rztXVILnKsjE8CRjG2b7Dd5UGKPE5i5R8b9qLtEs= Received: from eusmges1new.samsung.com (unknown [203.254.199.242]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20190320130720eucas1p1e5cb7e4af372cd5edcf3ef20d5564a38~NrJ3vPrQ52303723037eucas1p1H; Wed, 20 Mar 2019 13:07:20 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges1new.samsung.com (EUCPMTA) with SMTP id 5E.35.04441.80B329C5; Wed, 20 Mar 2019 13:07:20 +0000 (GMT) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20190320130720eucas1p1b6f2351c2262d2c89a464fdc10a6a607~NrJ3NtOkO2442724427eucas1p19; Wed, 20 Mar 2019 13:07:20 +0000 (GMT) X-AuditID: cbfec7f2-5c9ff70000001159-b9-5c923b08ab64 Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 7E.DA.04128.80B329C5; Wed, 20 Mar 2019 13:07:20 +0000 (GMT) Received: from AMDC3748.DIGITAL.local ([106.120.43.17]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0POO004P71RZN460@eusync1.samsung.com>; Wed, 20 Mar 2019 13:07:20 +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, Krzysztof Kozlowski Subject: [PATCH v2 RESEND 20/24] drm/exynos/gscaler: add local path support Date: Wed, 20 Mar 2019 14:07:03 +0100 Message-id: <20190320130707.25161-21-a.hajda@samsung.com> X-Mailer: git-send-email 2.17.1 In-reply-to: <20190320130707.25161-1-a.hajda@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprJIsWRmVeSWpSXmKPExsWy7djP87oc1pNiDH4dV7G4te4cq8XGGetZ La58fc9mMen+BBaL8+c3sFvMOL+PyWLtkbvsDuwem1Z1snnc7z7O5NG3ZRWjx+dNcgEsUVw2 Kak5mWWpRfp2CVwZPy52MhXcC6tYt+kfewPjBo8uRk4OCQETib6LF1lAbCGBFYwS7W3mXYxc QPZnRonmpWsYYYpWLFnHBJFYxiixfeZcRgjnP6PE/rvv2ECq2AQ0Jf5uvglmiwgoS6za184O UsQs8JtRYvrybewgCWEBb4mdM1uZQGwWAVWJ/f+Og9m8ApYSl3/MZIZYJy+xesMBMJsTKP5w zn+wQRICf1klehd9hbrJReLykUVQtozE5cndLBB2vcT9FS3MEA0djBJbN+yEmmotcfj4RVYQ m1mAT2LStulAcQ6gOK9ER5sQRImHxO3uU8wQr/UwSpzd8ZZpAqPEAkaGVYziqaXFuempxYZ5 qeV6xYm5xaV56XrJ+bmbGIERdvrf8U87GL9eSjrEKMDBqMTD2/BmQowQa2JZcWXuIUYJDmYl Ed4IpUkxQrwpiZVVqUX58UWlOanFhxilOViUxHmrGR5ECwmkJ5akZqemFqQWwWSZODilGhhN JjbrJextvSvF3HmvyPt9pMwB6Xds8YW3vtpO2fEz6uamQmGhf7oF0yqWpczOm5HD+ER82Qv9 z98zs1gnuPptV3ms4vqpSL12OfPqC9wPVga36LsrzNPmYDWetv6uZMapdbs9mz8bX8raf3DW IgbNaetePAq/bnBz2fz+qqiq6++cI2cIT3mjxFKckWioxVxUnAgA/xbUVKwCAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpmluLIzCtJLcpLzFFi42I5/e/4ZV0O60kxBo/381ncWneO1WLjjPWs Fle+vmezmHR/AovF+fMb2C1mnN/HZLH2yF12B3aPTas62Tzudx9n8ujbsorR4/MmuQCWKC6b lNSczLLUIn27BK6MHxc7mQruhVWs2/SPvYFxg0cXIyeHhICJxIol65i6GLk4hASWMEo8f9QL 5TQySfxduogFpIpNQFPi7+abbCC2iICyxKp97ewgRcwCvxklPs/4ygySEBbwltg5s5UJxGYR UJXY/+84mM0rYClx+cdMZoh18hKrNxwAszmB4g/n/GcHsYUELCQWn7jLOIGRZwEjwypGkdTS 4tz03GIjveLE3OLSvHS95PzcTYzAoNl27OeWHYxd74IPMQpwMCrx8FY8nRAjxJpYVlyZe4hR goNZSYQ3QmlSjBBvSmJlVWpRfnxRaU5q8SFGaQ4WJXHe8waVUUIC6YklqdmpqQWpRTBZJg5O qQbGWr1205N5T6rO/TkrqlS0W/PQzFAZPYOrb+zK5lqGHHzouLxFvm7SgqNzw79pv5eexxTX vmzCDj8HrhSJ+5tUvydf8t/ZKJf+vczg05PdZ80uTTq38tHnp0cDd529wlFkUMtgrp690dnW /Uk0W2Ng9iMREUXFzjfXNusla4eb32kInRvOtmCSEktxRqKhFnNRcSIA8wJjABYCAAA= X-CMS-MailID: 20190320130720eucas1p1b6f2351c2262d2c89a464fdc10a6a607 CMS-TYPE: 201P X-CMS-RootMailID: 20190320130720eucas1p1b6f2351c2262d2c89a464fdc10a6a607 References: <20190320130707.25161-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