From patchwork Tue Apr 16 17:31:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Sylwester Nawrocki/Kernel \\(PLT\\) /SRPOL/Staff Engineer/Samsung Electronics" X-Patchwork-Id: 2450271 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id 74AFE3FD40 for ; Tue, 16 Apr 2013 17:34:20 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 26B61E64FC for ; Tue, 16 Apr 2013 10:34:20 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mailout4.samsung.com (mailout4.samsung.com [203.254.224.34]) by gabe.freedesktop.org (Postfix) with ESMTP id EDF8AE64EA for ; Tue, 16 Apr 2013 10:33:19 -0700 (PDT) Received: from epcpsbgm1.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout4.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MLC002GLZFI0230@mailout4.samsung.com> for dri-devel@lists.freedesktop.org; Wed, 17 Apr 2013 02:33:18 +0900 (KST) X-AuditID: cbfee61a-b7fa86d0000045ae-71-516d8b5eba8f Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 61.F7.17838.E5B8D615; Wed, 17 Apr 2013 02:33:18 +0900 (KST) Received: from amdc1344.digital.local ([106.116.147.32]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MLC00F3DZCLP530@mmp1.samsung.com>; Wed, 17 Apr 2013 02:33:18 +0900 (KST) From: Sylwester Nawrocki To: inki.dae@samsung.com Subject: [PATCH 2/3] drm/exynos: Rework fimc clocks handling Date: Tue, 16 Apr 2013 19:31:25 +0200 Message-id: <1366133486-22973-3-git-send-email-s.nawrocki@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1366133486-22973-1-git-send-email-s.nawrocki@samsung.com> References: <1366133486-22973-1-git-send-email-s.nawrocki@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupiluLIzCtJLcpLzFFi42I5/e+xgG5cd26gwZKZphYHZj9ktbjy9T2b xaT7E1gszja9YbeYcX4fk8XhN+2sDmwe97uPM3mcn7GQ0aNvyypGj8+b5AJYorhsUlJzMstS i/TtErgy3nV2Mhb8tq9YuWU+SwPjIpMuRk4OCQETifUf7rFD2GISF+6tZ+ti5OIQEljEKLGs +S4rhNPBJDFx3wOwKjYBQ4neo32MILaIgITEzFcXmUCKmAW2M0pM/3GEBSQhLGAjsbV3IxOI zSKgKnHi2lMwm1fATWJC01cgmwNonYLEnEk2IGFOAXeJb+v3gpUIAZXs77jKOoGRdwEjwypG 0dSC5ILipPRcQ73ixNzi0rx0veT83E2M4BB6JrWDcWWDxSFGAQ5GJR7eCwW5gUKsiWXFlbmH GCU4mJVEeM86AoV4UxIrq1KL8uOLSnNSiw8xSnOwKInzHmi1DhQSSE8sSc1OTS1ILYLJMnFw SjUwXjJN2ZJnZRt/Y1H0LKV8hys9s2Y9DdlcfjX4kvzC6BaLx57JUQr3aw3sBacl6sz0vlF/ pjDzw5Ufe/TOTtebyLXt7g/9NUG7likfdM234p5p2bbT4fuS9HvlyVu+FR7+LfbW82PED4v3 jAu4PJ7kRhvtryzXUDtvHHfkAe/u5MvFnP2cketXK7EUZyQaajEXFScCAN7pBp4dAgAA Cc: Sylwester Nawrocki , kyungmin.park@samsung.com, linux-samsung-soc@vger.kernel.org, devicetree-discuss@lists.ozlabs.org, dri-devel@lists.freedesktop.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org The clocks handling is refactored and a "mux" clock handling is added to account for changes in the clocks driver. After switching to the common clock framework the sclk_fimc clock is now split into two clocks: a gate and a mux clock. In order to retain the exisiting functionality two additional consumer clocks are passed to the driver from device tree: "mux" and "parent". Then the driver sets "parent" clock as a parent clock of the "mux" clock. These two additional clocks are optional, and should go away when there is a standard way of setting up parent clocks on DT platforms. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_fimc.c | 168 +++++++++++++++++------------- 1 file changed, 98 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index d812c57..9bea585 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -76,6 +76,27 @@ enum fimc_wb { FIMC_WB_B, }; +enum { + FIMC_CLK_LCLK, + FIMC_CLK_GATE, + FIMC_CLK_WB_A, + FIMC_CLK_WB_B, + FIMC_CLK_MUX, + FIMC_CLK_PARENT, + FIMC_CLKS_MAX +}; + +static const char * fimc_clock_names[] = { + [FIMC_CLK_LCLK] = "sclk_fimc", + [FIMC_CLK_GATE] = "fimc", + [FIMC_CLK_WB_A] = "pxl_async0", + [FIMC_CLK_WB_B] = "pxl_async1", + [FIMC_CLK_MUX] = "mux", + [FIMC_CLK_PARENT] = "parent", +}; + +#define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL + /* * A structure of scaler. * @@ -132,15 +153,12 @@ struct fimc_driverdata { * * @ippdrv: prepare initialization using ippdrv. * @regs_res: register resources. + * @dev: pointer to the fimc device structure. * @regs: memory mapped io registers. * @lock: locking of operations. - * @sclk_fimc_clk: fimc source clock. - * @fimc_clk: fimc clock. - * @wb_clk: writeback a clock. - * @wb_b_clk: writeback b clock. + * @clocks: fimc clocks. + * @clk_frequency: LCLK clock frequency. * @sc: scaler infomations. - * @odr: ordering of YUV. - * @ver: fimc version. * @pol: porarity of writeback. * @id: fimc id. * @irq: irq number. @@ -148,13 +166,12 @@ struct fimc_driverdata { */ struct fimc_context { struct exynos_drm_ippdrv ippdrv; + struct device *dev; struct resource *regs_res; void __iomem *regs; struct mutex lock; - struct clk *sclk_fimc_clk; - struct clk *fimc_clk; - struct clk *wb_clk; - struct clk *wb_b_clk; + struct clk *clocks[FIMC_CLKS_MAX]; + u32 clk_frequency; struct fimc_scaler sc; struct fimc_driverdata *ddata; struct exynos_drm_ipp_pol pol; @@ -1301,14 +1318,12 @@ static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable) DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable); if (enable) { - clk_enable(ctx->sclk_fimc_clk); - clk_enable(ctx->fimc_clk); - clk_enable(ctx->wb_clk); + clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]); + clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]); ctx->suspended = false; } else { - clk_disable(ctx->sclk_fimc_clk); - clk_disable(ctx->fimc_clk); - clk_disable(ctx->wb_clk); + clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]); + clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]); ctx->suspended = true; } @@ -1713,11 +1728,66 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd) fimc_write(cfg, EXYNOS_CIGCTRL); } +static void fimc_put_clocks(struct fimc_context *ctx) +{ + int i; + + for (i = 0; i < FIMC_CLKS_MAX; i++) { + if (IS_ERR(ctx->clocks[i])) + continue; + clk_put(ctx->clocks[i]); + ctx->clocks[i] = ERR_PTR(-EINVAL); + } +} + +static int fimc_setup_clocks(struct fimc_context *ctx) +{ + struct device *dev; + int ret, i; + + for (i = 0; i < FIMC_CLKS_MAX; i++) + ctx->clocks[i] = ERR_PTR(-EINVAL); + + for (i = 0; i < FIMC_CLKS_MAX; i++) { + if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B) + dev = ctx->dev->parent; + else + dev = ctx->dev; + + ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]); + if (IS_ERR(ctx->clocks[i])) { + if (i >= FIMC_CLK_MUX) + break; + ret = PTR_ERR(ctx->clocks[i]); + goto e_clk_free; + } + } + + if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) { + ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX], + ctx->clocks[FIMC_CLK_PARENT]); + if (ret < 0) { + dev_err(ctx->dev, "failed to set parent: %d\n", ret); + return ret; + } + } + + ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency); + if (ret < 0) + return ret; + + return clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]); + +e_clk_free: + dev_err(ctx->dev, "failed to get clock: %s\n", fimc_clock_names[i]); + fimc_put_clocks(ctx); + return ret; +} + static int fimc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fimc_context *ctx; - struct clk *parent_clk; struct resource *res; struct exynos_drm_ippdrv *ippdrv; struct exynos_drm_fimc_pdata *pdata; @@ -1734,55 +1804,6 @@ static int fimc_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ddata = (struct fimc_driverdata *) - platform_get_device_id(pdev)->driver_data; - - /* clock control */ - ctx->sclk_fimc_clk = devm_clk_get(dev, "sclk_fimc"); - if (IS_ERR(ctx->sclk_fimc_clk)) { - dev_err(dev, "failed to get src fimc clock.\n"); - return PTR_ERR(ctx->sclk_fimc_clk); - } - clk_enable(ctx->sclk_fimc_clk); - - ctx->fimc_clk = devm_clk_get(dev, "fimc"); - if (IS_ERR(ctx->fimc_clk)) { - dev_err(dev, "failed to get fimc clock.\n"); - clk_disable(ctx->sclk_fimc_clk); - return PTR_ERR(ctx->fimc_clk); - } - - ctx->wb_clk = devm_clk_get(dev, "pxl_async0"); - if (IS_ERR(ctx->wb_clk)) { - dev_err(dev, "failed to get writeback a clock.\n"); - clk_disable(ctx->sclk_fimc_clk); - return PTR_ERR(ctx->wb_clk); - } - - ctx->wb_b_clk = devm_clk_get(dev, "pxl_async1"); - if (IS_ERR(ctx->wb_b_clk)) { - dev_err(dev, "failed to get writeback b clock.\n"); - clk_disable(ctx->sclk_fimc_clk); - return PTR_ERR(ctx->wb_b_clk); - } - - parent_clk = devm_clk_get(dev, ddata->parent_clk); - - if (IS_ERR(parent_clk)) { - dev_err(dev, "failed to get parent clock.\n"); - clk_disable(ctx->sclk_fimc_clk); - return PTR_ERR(parent_clk); - } - - if (clk_set_parent(ctx->sclk_fimc_clk, parent_clk)) { - dev_err(dev, "failed to set parent.\n"); - clk_disable(ctx->sclk_fimc_clk); - return -EINVAL; - } - - devm_clk_put(dev, parent_clk); - clk_set_rate(ctx->sclk_fimc_clk, pdata->clk_rate); - /* resource memory */ ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ctx->regs = devm_ioremap_resource(dev, ctx->regs_res); @@ -1804,6 +1825,9 @@ static int fimc_probe(struct platform_device *pdev) return ret; } + ret = fimc_setup_clocks(ctx); + if (ret < 0) + goto err_free_irq; /* context initailization */ ctx->id = pdev->id; ctx->pol = pdata->pol; @@ -1820,7 +1844,7 @@ static int fimc_probe(struct platform_device *pdev) ret = fimc_init_prop_list(ippdrv); if (ret < 0) { dev_err(dev, "failed to init property list.\n"); - goto err_get_irq; + goto err_put_clk; } DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id, @@ -1835,16 +1859,19 @@ static int fimc_probe(struct platform_device *pdev) ret = exynos_drm_ippdrv_register(ippdrv); if (ret < 0) { dev_err(dev, "failed to register drm fimc device.\n"); - goto err_ippdrv_register; + goto err_pm_dis; } dev_info(&pdev->dev, "drm fimc registered successfully.\n"); return 0; -err_ippdrv_register: +err_pm_dis: + devm_kfree(dev, ippdrv->prop_list); pm_runtime_disable(dev); -err_get_irq: +err_put_clk: + fimc_put_clocks(ctx); +err_free_irq: free_irq(ctx->irq, ctx); return ret; @@ -1859,6 +1886,7 @@ static int fimc_remove(struct platform_device *pdev) exynos_drm_ippdrv_unregister(ippdrv); mutex_destroy(&ctx->lock); + fimc_put_clocks(ctx); pm_runtime_set_suspended(dev); pm_runtime_disable(dev);