From patchwork Fri Aug 4 09:34:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 109391 Delivered-To: patch@linaro.org Received: by 10.182.109.195 with SMTP id hu3csp1121310obb; Fri, 4 Aug 2017 02:35:32 -0700 (PDT) X-Received: by 10.99.178.24 with SMTP id x24mr1697622pge.292.1501839332038; Fri, 04 Aug 2017 02:35:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1501839332; cv=none; d=google.com; s=arc-20160816; b=bA1/EvL7q6RZ3l5PaaBUB+iexAsMyV8OmbY41RJllXyEGmyzCLL9Kqi0pDdnBh9K/2 w9MuPaJjkuctP2JhsSIdDJ7ZSrsslz+koWumxMhxxy2afZgAjljA9JRy++uvnsfJwxDv ejsCyY1ZzA8xKZW76HZQtsYoTkz9a0M66dqfgaVwnIM1rNqQ9TEm7KGL4dKmbUquwpqo AMH0VVRxTfRN8bMlxqZqmrxR8mYYyefWtp/BRmHX+VbgkL9pcLcLV+j0E511fDJ+8huj 4YaUyasxjFrFPNtMEAkDdi/JjpCGHyQWtFIH8WS0jeC8irYyL48N6OHg/RYdwc2n2DNu Kwtg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:cms-type:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=8Zv6oCmtZk4KMxn97Hf14kcTgOnM4IqvoL7SHlGb69Y=; b=kjpG0zyY0ebdjr/ARms0ImTTEvzSeHUG7R9WdrBT7l24VGEuLQJyKtKKcNM5Dp3apT xAuzgrpVgZiIgLmCcCKuvASW39vLjup8RiEECLWTm5jR5TfqCexHAEABYAsCtXpyHNyM 1FNbWHiGGHBHdUF1jJuajZMc0pPa29ZoFhjWTX3qsQM56xpZAhN0b8PzeUkaHlfylgEg W17F3IM7eEvU85a1W65IUQ6gLVhq9mhFxaw4dQnCwxxG0/+0ucltxE6cDSRGGGo7B9ze M9oWLomVKogdZgPck789M0UMoRhtNbSiOVJ6wpUVHkT46fwiC8zNLHf/kc+IVAmIqtpZ IZaQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-samsung-soc-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-samsung-soc-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=samsung.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k2si735480pgs.179.2017.08.04.02.35.31; Fri, 04 Aug 2017 02:35:32 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-samsung-soc-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-samsung-soc-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-samsung-soc-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=samsung.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752108AbdHDJfa (ORCPT + 4 others); Fri, 4 Aug 2017 05:35:30 -0400 Received: from mailout3.w1.samsung.com ([210.118.77.13]:15761 "EHLO mailout3.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752098AbdHDJf0 (ORCPT ); Fri, 4 Aug 2017 05:35:26 -0400 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout3.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0OU500F4QMMTJX50@mailout3.w1.samsung.com>; Fri, 04 Aug 2017 10:35:18 +0100 (BST) Received: from eusmges3.samsung.com (unknown [203.254.199.242]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20170804093516eucas1p160e225fb069ed7455d0a5e20b564f40c~XmubVOMz22003320033eucas1p1N; Fri, 4 Aug 2017 09:35:16 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges3.samsung.com (EUCPMTA) with SMTP id ED.56.17464.4DF34895; Fri, 4 Aug 2017 10:35:16 +0100 (BST) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20170804093516eucas1p2267f819dad7c2e84eeca81a81d2687f2~XmuarrnF-0093700937eucas1p2P; Fri, 4 Aug 2017 09:35:16 +0000 (GMT) X-AuditID: cbfec7f2-f797e6d000004438-56-59843fd4a586 Received: from eusync3.samsung.com ( [203.254.199.213]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id AC.2F.17452.4DF34895; Fri, 4 Aug 2017 10:35:16 +0100 (BST) Received: from AMDC2765.digital.local ([106.116.147.25]) by eusync3.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OU50004IMMJTPA0@eusync3.samsung.com>; Fri, 04 Aug 2017 10:35:16 +0100 (BST) From: Marek Szyprowski To: linux-clk@vger.kernel.org, linux-pm@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: Marek Szyprowski , Stephen Boyd , Michael Turquette , Ulf Hansson , Sylwester Nawrocki , Chanwoo Choi , Inki Dae , Krzysztof Kozlowski , Bartlomiej Zolnierkiewicz Subject: [PATCH v7 3/4] clk: samsung: exynos5433: Add runtime PM support Date: Fri, 04 Aug 2017 11:34:53 +0200 Message-id: <1501839294-478-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1501839294-478-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrAIsWRmVeSWpSXmKPExsWy7djPc7pX7FsiDQ5u0bTYOGM9q8X1L89Z LSbdn8Bicf78BnaLTY+vsVp87LnHavG59wijxYzz+5gs1h65y25x8ZSrxeE37awWP850s1gc XxvuwOvx/kYru8flvl4mj02rOtk87lzbw+axeUm9R9+WVYwenzfJBbBHcdmkpOZklqUW6dsl cGUsu7CFvaDhEGPFpcXvGBsYVy9g7GLk5JAQMJFo+LaMHcIWk7hwbz1bFyMXh5DAUkaJX0fu MkI4nxklTp9oYofp2PqrkwUisYxR4vK206wQTgOTRHv3PbC5bAKGEl1vu8BmiQg0MUpM3LAe rIpZoIlZYtq+iUwgVcICHhIbd55gAbFZBFQlPv35ANTBwcEr4CZx7bw2xDo5iZPHJrOC2JwC 7hIzfzWCDZUQWMcuMe3rc2aQegkBWYlNB5gh6l0k9vd8hrKFJV4d3wJ1toxEZ8dBJgi7n1Gi qRVq/gxGiXNveSFsa4nDxy+C7WIW4JOYtG061HheiY42IYgSD4lZGw5ChR0lzswSgPh9FqPE rbZd7BMYZRYwMqxiFEktLc5NTy021itOzC0uzUvXS87P3cQITAen/x3/tIPx6wmrQ4wCHIxK PLwGM5ojhVgTy4orcw8xSnAwK4nwMqq0RArxpiRWVqUW5ccXleakFh9ilOZgURLn5Tp1LUJI ID2xJDU7NbUgtQgmy8TBKdXA2PtAaYrIFsa+0MNck+4I7YxzNtnwRP4G/+/4toJnu/MNRHIZ OkS716/Uj3SoeFn2RVKR3VTi4IFgfcu16xT+L129JMXgUM2j9Xc+5l5vFQs7uW97lMKlKfNj /c86m/sw86aIXN47M++tut8s8/29L96ncW1sLvry10v7taBp8FuVr3smiQVuUWIpzkg01GIu Kk4EADNyjQsDAwAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprAIsWRmVeSWpSXmKPExsVy+t/xq7pX7FsiDb4u5bPYOGM9q8X1L89Z LSbdn8Bicf78BnaLTY+vsVp87LnHavG59wijxYzz+5gs1h65y25x8ZSrxeE37awWP850s1gc XxvuwOvx/kYru8flvl4mj02rOtk87lzbw+axeUm9R9+WVYwenzfJBbBHudlkpCampBYppOYl 56dk5qXbKoWGuOlaKCnkJeam2ipF6PqGBCkplCXmlAJ5RgZowME5wD1YSd8uwS1j2YUt7AUN hxgrLi1+x9jAuHoBYxcjJ4eEgInE1l+dLBC2mMSFe+vZuhi5OIQEljBKnJw6C6xISKCJSeLn TGMQm03AUKLrbRdYkYhAE6PEk75p7CAOs0Abs8T/jq9gHcICHhIbd54AG8sioCrx6c8HoA4O Dl4BN4lr57UhtslJnDw2mRXE5hRwl5j5q5ENYpmbxKYLDxgnMPIuYGRYxSiSWlqcm55bbKhX nJhbXJqXrpecn7uJERgb24793LyD8dLG4EOMAhyMSjy8BjOaI4VYE8uKK3MPMUpwMCuJ8DKq tEQK8aYkVlalFuXHF5XmpBYfYjQFumkis5Rocj4wbvNK4g1NDM0tDY2MLSzMjYyUxHnVLzdF CgmkJ5akZqemFqQWwfQxcXBKNTAqSLCt25z+oWan1/2ge5POZ7VEXhRlni6wc5ror/X7Zbt9 z/y7Unz2j9nKLWcnzKid/HA6dzBL9ek1pf0nAm7LO31++mfb8TTJdrWWZ7GlR4Sk/4TwrAg8 Y3fNX0EgeMm+vm/Bl6sXZGks7W68Xb9aalut9LPFpUYTIzlNGevNO+qL7oWumnFFiaU4I9FQ i7moOBEAgVINy6MCAAA= X-MTR: 20000000000000000@CPGS X-CMS-MailID: 20170804093516eucas1p2267f819dad7c2e84eeca81a81d2687f2 X-Msg-Generator: CA X-Sender-IP: 182.198.249.179 X-Local-Sender: =?utf-8?q?Marek_Szyprowski=1BSRPOL-Kernel_=28TP=29=1B?= =?utf-8?b?7IK87ISx7KCE7J6QG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Global-Sender: =?utf-8?q?Marek_Szyprowski=1BSRPOL-Kernel_=28TP=29=1BSam?= =?utf-8?q?sung_Electronics=1BSenior_Software_Engineer?= X-Sender-Code: =?utf-8?q?C10=1BEHQ=1BC10CD02CD027392?= CMS-TYPE: 201P X-HopCount: 7 X-CMS-RootMailID: 20170804093516eucas1p2267f819dad7c2e84eeca81a81d2687f2 X-RootMTR: 20170804093516eucas1p2267f819dad7c2e84eeca81a81d2687f2 References: <1501839294-478-1-git-send-email-m.szyprowski@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org Add runtime pm support for all clock controller units (CMU), which belongs to power domains and require special handling during on/off operations. Typically special values has to be written to MUX registers to change internal clocks parents to OSC clock before turning power off. During such operation all clocks, which enters CMU has to be enabled to let MUX to stabilize. Also for each CMU there is one special parent clock, which has to be enabled all the time when any access to CMU registers is done. This patch solves most of the mysterious external abort and freeze issues caused by a lack of proper parent CMU clock enabled or incorrect turn off procedure. Signed-off-by: Marek Szyprowski Reviewed-by: Ulf Hansson --- .../devicetree/bindings/clock/exynos5433-clock.txt | 16 + drivers/clk/samsung/clk-exynos5433.c | 409 ++++++++++++++++----- drivers/clk/samsung/clk.h | 6 + 3 files changed, 346 insertions(+), 85 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Reviewed-by: Chanwoo Choi Tested-by: Chanwoo Choi diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 1dc80f8811fe..5c7dd12e667a 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -168,6 +168,11 @@ Required Properties: - aclk_cam1_400 - aclk_cam1_552 +Optional properties: + - power-domains: a phandle to respective power domain node as described by + generic PM domain bindings (see power/power_domain.txt for more + information). + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -270,6 +275,7 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_top CLK_ACLK_G2D_266>, <&cmu_top CLK_ACLK_G2D_400>; + power-domains = <&pd_g2d>; }; cmu_disp: clock-controller@13b90000 { @@ -295,6 +301,7 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_mif CLK_SCLK_DECON_ECLK_DISP>, <&cmu_mif CLK_SCLK_DECON_TV_VCLK_DISP>, <&cmu_mif CLK_ACLK_DISP_333>; + power-domains = <&pd_disp>; }; cmu_aud: clock-controller@114c0000 { @@ -304,6 +311,7 @@ Example 2: Examples of clock controller nodes are listed below. clock-names = "oscclk", "fout_aud_pll"; clocks = <&xxti>, <&cmu_top CLK_FOUT_AUD_PLL>; + power-domains = <&pd_aud>; }; cmu_bus0: clock-controller@13600000 { @@ -340,6 +348,7 @@ Example 2: Examples of clock controller nodes are listed below. clock-names = "oscclk", "aclk_g3d_400"; clocks = <&xxti>, <&cmu_top CLK_ACLK_G3D_400>; + power-domains = <&pd_g3d>; }; cmu_gscl: clock-controller@13cf0000 { @@ -353,6 +362,7 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_top CLK_ACLK_GSCL_111>, <&cmu_top CLK_ACLK_GSCL_333>; + power-domains = <&pd_gscl>; }; cmu_apollo: clock-controller@11900000 { @@ -384,6 +394,7 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_top CLK_SCLK_JPEG_MSCL>, <&cmu_top CLK_ACLK_MSCL_400>; + power-domains = <&pd_mscl>; }; cmu_mfc: clock-controller@15280000 { @@ -393,6 +404,7 @@ Example 2: Examples of clock controller nodes are listed below. clock-names = "oscclk", "aclk_mfc_400"; clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>; + power-domains = <&pd_mfc>; }; cmu_hevc: clock-controller@14f80000 { @@ -402,6 +414,7 @@ Example 2: Examples of clock controller nodes are listed below. clock-names = "oscclk", "aclk_hevc_400"; clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>; + power-domains = <&pd_hevc>; }; cmu_isp: clock-controller@146d0000 { @@ -415,6 +428,7 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_top CLK_ACLK_ISP_DIS_400>, <&cmu_top CLK_ACLK_ISP_400>; + power-domains = <&pd_isp>; }; cmu_cam0: clock-controller@120d0000 { @@ -430,6 +444,7 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_CAM0_333>, <&cmu_top CLK_ACLK_CAM0_400>, <&cmu_top CLK_ACLK_CAM0_552>; + power-domains = <&pd_cam0>; }; cmu_cam1: clock-controller@145d0000 { @@ -451,6 +466,7 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_CAM1_333>, <&cmu_top CLK_ACLK_CAM1_400>, <&cmu_top CLK_ACLK_CAM1_552>; + power-domains = <&pd_cam1>; }; Example 3: UART controller node that consumes the clock generated by the clock diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 11343a597093..7ae9bccb1192 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -9,9 +9,14 @@ * Common Clock Framework support for Exynos5433 SoC. */ +#include #include #include #include +#include +#include +#include +#include #include @@ -1991,6 +1996,14 @@ static void __init exynos5433_cmu_peris_init(struct device_node *np) ENABLE_IP_FSYS1, }; +static const struct samsung_clk_reg_dump fsys_suspend_regs[] = { + { MUX_SEL_FSYS0, 0 }, + { MUX_SEL_FSYS1, 0 }, + { MUX_SEL_FSYS2, 0 }, + { MUX_SEL_FSYS3, 0 }, + { MUX_SEL_FSYS4, 0 }, +}; + static const struct samsung_fixed_rate_clock fsys_fixed_clks[] __initconst = { /* PHY clocks from USBDRD30_PHY */ FRATE(CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_PHY, @@ -2296,16 +2309,11 @@ static void __init exynos5433_cmu_peris_init(struct device_node *np) .nr_clk_ids = FSYS_NR_CLK, .clk_regs = fsys_clk_regs, .nr_clk_regs = ARRAY_SIZE(fsys_clk_regs), + .suspend_regs = fsys_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(fsys_suspend_regs), + .clk_name = "aclk_fsys_200", }; -static void __init exynos5433_cmu_fsys_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &fsys_cmu_info); -} - -CLK_OF_DECLARE(exynos5433_cmu_fsys, "samsung,exynos5433-cmu-fsys", - exynos5433_cmu_fsys_init); - /* * Register offset definitions for CMU_G2D */ @@ -2335,6 +2343,10 @@ static void __init exynos5433_cmu_fsys_init(struct device_node *np) DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D, }; +static const struct samsung_clk_reg_dump g2d_suspend_regs[] = { + { MUX_SEL_G2D0, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_aclk_g2d_266_user_p) = { "oscclk", "aclk_g2d_266", }; PNAME(mout_aclk_g2d_400_user_p) = { "oscclk", "aclk_g2d_400", }; @@ -2420,16 +2432,11 @@ static void __init exynos5433_cmu_fsys_init(struct device_node *np) .nr_clk_ids = G2D_NR_CLK, .clk_regs = g2d_clk_regs, .nr_clk_regs = ARRAY_SIZE(g2d_clk_regs), + .suspend_regs = g2d_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(g2d_suspend_regs), + .clk_name = "aclk_g2d_400", }; -static void __init exynos5433_cmu_g2d_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &g2d_cmu_info); -} - -CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d", - exynos5433_cmu_g2d_init); - /* * Register offset definitions for CMU_DISP */ @@ -2494,6 +2501,18 @@ static void __init exynos5433_cmu_g2d_init(struct device_node *np) CLKOUT_CMU_DISP_DIV_STAT, }; +static const struct samsung_clk_reg_dump disp_suspend_regs[] = { + /* PLL has to be enabled for suspend */ + { DISP_PLL_CON0, 0x85f40502 }, + /* ignore status of external PHY muxes during suspend to avoid hangs */ + { MUX_IGNORE_DISP2, 0x00111111 }, + { MUX_SEL_DISP0, 0 }, + { MUX_SEL_DISP1, 0 }, + { MUX_SEL_DISP2, 0 }, + { MUX_SEL_DISP3, 0 }, + { MUX_SEL_DISP4, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_disp_pll_p) = { "oscclk", "fout_disp_pll", }; PNAME(mout_sclk_dsim1_user_p) = { "oscclk", "sclk_dsim1_disp", }; @@ -2841,16 +2860,11 @@ static void __init exynos5433_cmu_g2d_init(struct device_node *np) .nr_clk_ids = DISP_NR_CLK, .clk_regs = disp_clk_regs, .nr_clk_regs = ARRAY_SIZE(disp_clk_regs), + .suspend_regs = disp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(disp_suspend_regs), + .clk_name = "aclk_disp_333", }; -static void __init exynos5433_cmu_disp_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &disp_cmu_info); -} - -CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp", - exynos5433_cmu_disp_init); - /* * Register offset definitions for CMU_AUD */ @@ -2885,6 +2899,11 @@ static void __init exynos5433_cmu_disp_init(struct device_node *np) ENABLE_IP_AUD1, }; +static const struct samsung_clk_reg_dump aud_suspend_regs[] = { + { MUX_SEL_AUD0, 0 }, + { MUX_SEL_AUD1, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_aud_pll_user_aud_p) = { "oscclk", "fout_aud_pll", }; PNAME(mout_sclk_aud_pcm_p) = { "mout_aud_pll_user", "ioclk_audiocdclk0",}; @@ -3011,16 +3030,11 @@ static void __init exynos5433_cmu_disp_init(struct device_node *np) .nr_clk_ids = AUD_NR_CLK, .clk_regs = aud_clk_regs, .nr_clk_regs = ARRAY_SIZE(aud_clk_regs), + .suspend_regs = aud_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(aud_suspend_regs), + .clk_name = "fout_aud_pll", }; -static void __init exynos5433_cmu_aud_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &aud_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud", - exynos5433_cmu_aud_init); - - /* * Register offset definitions for CMU_BUS{0|1|2} */ @@ -3222,6 +3236,10 @@ static void __init exynos5433_cmu_aud_init(struct device_node *np) CLK_STOPCTRL, }; +static const struct samsung_clk_reg_dump g3d_suspend_regs[] = { + { MUX_SEL_G3D, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_aclk_g3d_400_p) = { "mout_g3d_pll", "aclk_g3d_400", }; PNAME(mout_g3d_pll_p) = { "oscclk", "fout_g3d_pll", }; @@ -3295,15 +3313,11 @@ static void __init exynos5433_cmu_aud_init(struct device_node *np) .nr_clk_ids = G3D_NR_CLK, .clk_regs = g3d_clk_regs, .nr_clk_regs = ARRAY_SIZE(g3d_clk_regs), + .suspend_regs = g3d_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(g3d_suspend_regs), + .clk_name = "aclk_g3d_400", }; -static void __init exynos5433_cmu_g3d_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &g3d_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d", - exynos5433_cmu_g3d_init); - /* * Register offset definitions for CMU_GSCL */ @@ -3342,6 +3356,12 @@ static void __init exynos5433_cmu_g3d_init(struct device_node *np) ENABLE_IP_GSCL_SECURE_SMMU_GSCL2, }; +static const struct samsung_clk_reg_dump gscl_suspend_regs[] = { + { MUX_SEL_GSCL, 0 }, + { ENABLE_ACLK_GSCL, 0xfff }, + { ENABLE_PCLK_GSCL, 0xff }, +}; + /* list of all parent clock list */ PNAME(aclk_gscl_111_user_p) = { "oscclk", "aclk_gscl_111", }; PNAME(aclk_gscl_333_user_p) = { "oscclk", "aclk_gscl_333", }; @@ -3436,15 +3456,11 @@ static void __init exynos5433_cmu_g3d_init(struct device_node *np) .nr_clk_ids = GSCL_NR_CLK, .clk_regs = gscl_clk_regs, .nr_clk_regs = ARRAY_SIZE(gscl_clk_regs), + .suspend_regs = gscl_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(gscl_suspend_regs), + .clk_name = "aclk_gscl_111", }; -static void __init exynos5433_cmu_gscl_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &gscl_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl", - exynos5433_cmu_gscl_init); - /* * Register offset definitions for CMU_APOLLO */ @@ -3970,6 +3986,11 @@ static void __init exynos5433_cmu_atlas_init(struct device_node *np) ENABLE_IP_MSCL_SECURE_SMMU_JPEG, }; +static const struct samsung_clk_reg_dump mscl_suspend_regs[] = { + { MUX_SEL_MSCL0, 0 }, + { MUX_SEL_MSCL1, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_sclk_jpeg_user_p) = { "oscclk", "sclk_jpeg_mscl", }; PNAME(mout_aclk_mscl_400_user_p) = { "oscclk", "aclk_mscl_400", }; @@ -4082,15 +4103,11 @@ static void __init exynos5433_cmu_atlas_init(struct device_node *np) .nr_clk_ids = MSCL_NR_CLK, .clk_regs = mscl_clk_regs, .nr_clk_regs = ARRAY_SIZE(mscl_clk_regs), + .suspend_regs = mscl_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(mscl_suspend_regs), + .clk_name = "aclk_mscl_400", }; -static void __init exynos5433_cmu_mscl_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &mscl_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl", - exynos5433_cmu_mscl_init); - /* * Register offset definitions for CMU_MFC */ @@ -4120,6 +4137,10 @@ static void __init exynos5433_cmu_mscl_init(struct device_node *np) ENABLE_IP_MFC_SECURE_SMMU_MFC, }; +static const struct samsung_clk_reg_dump mfc_suspend_regs[] = { + { MUX_SEL_MFC, 0 }, +}; + PNAME(mout_aclk_mfc_400_user_p) = { "oscclk", "aclk_mfc_400", }; static const struct samsung_mux_clock mfc_mux_clks[] __initconst = { @@ -4190,15 +4211,11 @@ static void __init exynos5433_cmu_mscl_init(struct device_node *np) .nr_clk_ids = MFC_NR_CLK, .clk_regs = mfc_clk_regs, .nr_clk_regs = ARRAY_SIZE(mfc_clk_regs), + .suspend_regs = mfc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(mfc_suspend_regs), + .clk_name = "aclk_mfc_400", }; -static void __init exynos5433_cmu_mfc_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &mfc_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc", - exynos5433_cmu_mfc_init); - /* * Register offset definitions for CMU_HEVC */ @@ -4228,6 +4245,10 @@ static void __init exynos5433_cmu_mfc_init(struct device_node *np) ENABLE_IP_HEVC_SECURE_SMMU_HEVC, }; +static const struct samsung_clk_reg_dump hevc_suspend_regs[] = { + { MUX_SEL_HEVC, 0 }, +}; + PNAME(mout_aclk_hevc_400_user_p) = { "oscclk", "aclk_hevc_400", }; static const struct samsung_mux_clock hevc_mux_clks[] __initconst = { @@ -4300,15 +4321,11 @@ static void __init exynos5433_cmu_mfc_init(struct device_node *np) .nr_clk_ids = HEVC_NR_CLK, .clk_regs = hevc_clk_regs, .nr_clk_regs = ARRAY_SIZE(hevc_clk_regs), + .suspend_regs = hevc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(hevc_suspend_regs), + .clk_name = "aclk_hevc_400", }; -static void __init exynos5433_cmu_hevc_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &hevc_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc", - exynos5433_cmu_hevc_init); - /* * Register offset definitions for CMU_ISP */ @@ -4342,6 +4359,10 @@ static void __init exynos5433_cmu_hevc_init(struct device_node *np) ENABLE_IP_ISP3, }; +static const struct samsung_clk_reg_dump isp_suspend_regs[] = { + { MUX_SEL_ISP, 0 }, +}; + PNAME(mout_aclk_isp_dis_400_user_p) = { "oscclk", "aclk_isp_dis_400", }; PNAME(mout_aclk_isp_400_user_p) = { "oscclk", "aclk_isp_400", }; @@ -4553,15 +4574,11 @@ static void __init exynos5433_cmu_hevc_init(struct device_node *np) .nr_clk_ids = ISP_NR_CLK, .clk_regs = isp_clk_regs, .nr_clk_regs = ARRAY_SIZE(isp_clk_regs), + .suspend_regs = isp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(isp_suspend_regs), + .clk_name = "aclk_isp_400", }; -static void __init exynos5433_cmu_isp_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &isp_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp", - exynos5433_cmu_isp_init); - /* * Register offset definitions for CMU_CAM0 */ @@ -4625,6 +4642,15 @@ static void __init exynos5433_cmu_isp_init(struct device_node *np) ENABLE_IP_CAM02, ENABLE_IP_CAM03, }; + +static const struct samsung_clk_reg_dump cam0_suspend_regs[] = { + { MUX_SEL_CAM00, 0 }, + { MUX_SEL_CAM01, 0 }, + { MUX_SEL_CAM02, 0 }, + { MUX_SEL_CAM03, 0 }, + { MUX_SEL_CAM04, 0 }, +}; + PNAME(mout_aclk_cam0_333_user_p) = { "oscclk", "aclk_cam0_333", }; PNAME(mout_aclk_cam0_400_user_p) = { "oscclk", "aclk_cam0_400", }; PNAME(mout_aclk_cam0_552_user_p) = { "oscclk", "aclk_cam0_552", }; @@ -5030,15 +5056,11 @@ static void __init exynos5433_cmu_isp_init(struct device_node *np) .nr_clk_ids = CAM0_NR_CLK, .clk_regs = cam0_clk_regs, .nr_clk_regs = ARRAY_SIZE(cam0_clk_regs), + .suspend_regs = cam0_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(cam0_suspend_regs), + .clk_name = "aclk_cam0_400", }; -static void __init exynos5433_cmu_cam0_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &cam0_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0", - exynos5433_cmu_cam0_init); - /* * Register offset definitions for CMU_CAM1 */ @@ -5085,6 +5107,12 @@ static void __init exynos5433_cmu_cam0_init(struct device_node *np) ENABLE_IP_CAM12, }; +static const struct samsung_clk_reg_dump cam1_suspend_regs[] = { + { MUX_SEL_CAM10, 0 }, + { MUX_SEL_CAM11, 0 }, + { MUX_SEL_CAM12, 0 }, +}; + PNAME(mout_sclk_isp_uart_user_p) = { "oscclk", "sclk_isp_uart_cam1", }; PNAME(mout_sclk_isp_spi1_user_p) = { "oscclk", "sclk_isp_spi1_cam1", }; PNAME(mout_sclk_isp_spi0_user_p) = { "oscclk", "sclk_isp_spi0_cam1", }; @@ -5403,11 +5431,222 @@ static void __init exynos5433_cmu_cam0_init(struct device_node *np) .nr_clk_ids = CAM1_NR_CLK, .clk_regs = cam1_clk_regs, .nr_clk_regs = ARRAY_SIZE(cam1_clk_regs), + .suspend_regs = cam1_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(cam1_suspend_regs), + .clk_name = "aclk_cam1_400", +}; + + +struct exynos5433_cmu_data { + struct samsung_clk_reg_dump *clk_save; + unsigned int nr_clk_save; + const struct samsung_clk_reg_dump *clk_suspend; + unsigned int nr_clk_suspend; + + struct clk *clk; + struct clk **pclks; + int nr_pclks; + + /* must be the last entry */ + struct samsung_clk_provider ctx; +}; + +static int exynos5433_cmu_suspend(struct device *dev) +{ + struct exynos5433_cmu_data *data = dev_get_drvdata(dev); + int i; + + samsung_clk_save(data->ctx.reg_base, data->clk_save, + data->nr_clk_save); + + for (i = 0; i < data->nr_pclks; i++) + clk_prepare_enable(data->pclks[i]); + + samsung_clk_restore(data->ctx.reg_base, data->clk_suspend, + data->nr_clk_suspend); + + for (i = 0; i < data->nr_pclks; i++) + clk_disable_unprepare(data->pclks[i]); + + clk_disable_unprepare(data->clk); + + return 0; +} + +static int exynos5433_cmu_resume(struct device *dev) +{ + struct exynos5433_cmu_data *data = dev_get_drvdata(dev); + int i; + + clk_prepare_enable(data->clk); + + for (i = 0; i < data->nr_pclks; i++) + clk_prepare_enable(data->pclks[i]); + + samsung_clk_restore(data->ctx.reg_base, data->clk_save, + data->nr_clk_save); + + for (i = 0; i < data->nr_pclks; i++) + clk_disable_unprepare(data->pclks[i]); + + return 0; +} + +static int __init exynos5433_cmu_probe(struct platform_device *pdev) +{ + const struct samsung_cmu_info *info; + struct exynos5433_cmu_data *data; + struct samsung_clk_provider *ctx; + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *reg_base; + int i; + + info = of_device_get_match_data(dev); + + data = devm_kzalloc(dev, sizeof(*data) + + sizeof(*data->ctx.clk_data.hws) * info->nr_clk_ids, + GFP_KERNEL); + if (!data) + return -ENOMEM; + ctx = &data->ctx; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(reg_base)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(reg_base); + } + + for (i = 0; i < info->nr_clk_ids; ++i) + ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); + + ctx->clk_data.num = info->nr_clk_ids; + ctx->reg_base = reg_base; + ctx->dev = dev; + spin_lock_init(&ctx->lock); + + data->clk_save = samsung_clk_alloc_reg_dump(info->clk_regs, + info->nr_clk_regs); + data->nr_clk_save = info->nr_clk_regs; + data->clk_suspend = info->suspend_regs; + data->nr_clk_suspend = info->nr_suspend_regs; + data->nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks", + "#clock-cells"); + if (data->nr_pclks > 0) { + data->pclks = devm_kcalloc(dev, sizeof(struct clk *), + data->nr_pclks, GFP_KERNEL); + + for (i = 0; i < data->nr_pclks; i++) { + struct clk *clk = of_clk_get(dev->of_node, i); + + if (IS_ERR(clk)) + return PTR_ERR(clk); + data->pclks[i] = clk; + } + } + + if (info->clk_name) + data->clk = clk_get(dev, info->clk_name); + clk_prepare_enable(data->clk); + + platform_set_drvdata(pdev, data); + + /* + * Enable runtime PM here to allow the clock core using runtime PM + * for the registered clocks. Additionally, we increase the runtime + * PM usage count before registering the clocks, to prevent the + * clock core from runtime suspending the device. + */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + if (info->pll_clks) + samsung_clk_register_pll(ctx, info->pll_clks, info->nr_pll_clks, + reg_base); + if (info->mux_clks) + samsung_clk_register_mux(ctx, info->mux_clks, + info->nr_mux_clks); + if (info->div_clks) + samsung_clk_register_div(ctx, info->div_clks, + info->nr_div_clks); + if (info->gate_clks) + samsung_clk_register_gate(ctx, info->gate_clks, + info->nr_gate_clks); + if (info->fixed_clks) + samsung_clk_register_fixed_rate(ctx, info->fixed_clks, + info->nr_fixed_clks); + if (info->fixed_factor_clks) + samsung_clk_register_fixed_factor(ctx, info->fixed_factor_clks, + info->nr_fixed_factor_clks); + + samsung_clk_of_add_provider(dev->of_node, ctx); + pm_runtime_put_sync(dev); + + return 0; +} + +static const struct of_device_id exynos5433_cmu_of_match[] = { + { + .compatible = "samsung,exynos5433-cmu-aud", + .data = &aud_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-cam0", + .data = &cam0_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-cam1", + .data = &cam1_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-disp", + .data = &disp_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-g2d", + .data = &g2d_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-g3d", + .data = &g3d_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-fsys", + .data = &fsys_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-gscl", + .data = &gscl_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-mfc", + .data = &mfc_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-hevc", + .data = &hevc_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-isp", + .data = &isp_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-mscl", + .data = &mscl_cmu_info, + }, { + }, +}; + +static const struct dev_pm_ops exynos5433_cmu_pm_ops = { + SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume, + NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver exynos5433_cmu_driver __refdata = { + .driver = { + .name = "exynos5433-cmu", + .of_match_table = exynos5433_cmu_of_match, + .suppress_bind_attrs = true, + .pm = &exynos5433_cmu_pm_ops, + }, + .probe = exynos5433_cmu_probe, }; -static void __init exynos5433_cmu_cam1_init(struct device_node *np) +static int __init exynos5433_cmu_init(void) { - samsung_cmu_register_one(np, &cam1_cmu_info); + return platform_driver_register(&exynos5433_cmu_driver); } -CLK_OF_DECLARE(exynos5433_cmu_cam1, "samsung,exynos5433-cmu-cam1", - exynos5433_cmu_cam1_init); +core_initcall(exynos5433_cmu_init); diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index f0acae4f5d1b..d93031e94387 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -353,6 +353,12 @@ struct samsung_cmu_info { /* list and number of clocks registers */ const unsigned long *clk_regs; unsigned int nr_clk_regs; + + /* list and number of clocks registers to set before suspend */ + const struct samsung_clk_reg_dump *suspend_regs; + unsigned int nr_suspend_regs; + /* name of the parent clock needed for CMU register access */ + const char *clk_name; }; extern struct samsung_clk_provider *__init samsung_clk_init(