From patchwork Wed Jun 22 08:46:43 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kim Kukjin X-Patchwork-Id: 904172 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p5M8wlj9018071 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Wed, 22 Jun 2011 08:59:08 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QZJGR-0008Mn-Ii; Wed, 22 Jun 2011 08:58:24 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QZJGR-00034J-6U; Wed, 22 Jun 2011 08:58:23 +0000 Received: from ganesha.gnumonks.org ([2001:780:45:1d:2e0:81ff:fe28:898a]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QZJEy-0002oj-Np for linux-arm-kernel@lists.infradead.org; Wed, 22 Jun 2011 08:56:57 +0000 Received: from uucp by ganesha.gnumonks.org with local-bsmtp (Exim 4.72) (envelope-from ) id 1QZJEu-0005id-Ml; Wed, 22 Jun 2011 10:56:48 +0200 Received: from [12.23.102.184] (helo=starstone.dsn.sec.samsung.com) by jackpot.kr.gnumonks.org with esmtp (Exim 4.69) (envelope-from ) id 1QZISH-0002Wq-Ug; Wed, 22 Jun 2011 17:06:33 +0900 From: Kukjin Kim To: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org Subject: [PATCH 5/7] ARM: EXYNOS4: Add save/restore function for PLL Date: Wed, 22 Jun 2011 17:46:43 +0900 Message-Id: <1308732405-16664-6-git-send-email-kgene.kim@samsung.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1308732405-16664-1-git-send-email-kgene.kim@samsung.com> References: <1308732405-16664-1-git-send-email-kgene.kim@samsung.com> X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110622_045653_444768_A4CEB224 X-CRM114-Status: GOOD ( 19.92 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 RFC_ABUSE_POST Both abuse and postmaster missing on sender domain Cc: Jaecheol Lee , Kukjin Kim , ben-linux@fluff.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Wed, 22 Jun 2011 08:59:08 +0000 (UTC) From: Jaecheol Lee The PLL restore routine supports waiting pll locking. If PLL is enabled in restoring sequence, it should wait until PLL is locked. Signed-off-by: Jaecheol Lee Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/include/mach/regs-clock.h | 9 ++ arch/arm/mach-exynos4/pm.c | 96 ++++++++++++++++++++++- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-exynos4/include/mach/regs-clock.h b/arch/arm/mach-exynos4/include/mach/regs-clock.h index 6e311c1..64bdd24 100644 --- a/arch/arm/mach-exynos4/include/mach/regs-clock.h +++ b/arch/arm/mach-exynos4/include/mach/regs-clock.h @@ -25,6 +25,9 @@ #define S5P_CLKDIV_STAT_RIGHTBUS S5P_CLKREG(0x08600) #define S5P_CLKGATE_IP_RIGHTBUS S5P_CLKREG(0x08800) +#define S5P_EPLL_LOCK S5P_CLKREG(0x0C010) +#define S5P_VPLL_LOCK S5P_CLKREG(0x0C020) + #define S5P_EPLL_CON0 S5P_CLKREG(0x0C110) #define S5P_EPLL_CON1 S5P_CLKREG(0x0C114) #define S5P_VPLL_CON0 S5P_CLKREG(0x0C120) @@ -120,6 +123,12 @@ #define S5P_APLL_VAL_1000 ((250 << 16) | (6 << 8) | 1) #define S5P_APLL_VAL_800 ((200 << 16) | (6 << 8) | 1) +#define S5P_EPLLCON0_ENABLE_SHIFT (31) +#define S5P_EPLLCON0_LOCKED_SHIFT (29) + +#define S5P_VPLLCON0_ENABLE_SHIFT (31) +#define S5P_VPLLCON0_LOCKED_SHIFT (29) + #define S5P_CLKSRC_CPU_MUXCORE_SHIFT (16) #define S5P_CLKMUX_STATCPU_MUXCORE_MASK (0x7 << S5P_CLKSRC_CPU_MUXCORE_SHIFT) diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos4/pm.c index f4d52b5..b037fba 100644 --- a/arch/arm/mach-exynos4/pm.c +++ b/arch/arm/mach-exynos4/pm.c @@ -18,12 +18,15 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include @@ -45,16 +48,22 @@ static struct sleep_save exynos4_set_clksrc[] = { { .reg = S5P_CLKSRC_MASK_DMC , .val = 0x00010000, }, }; +static struct sleep_save exynos4_epll_save[] = { + SAVE_ITEM(S5P_EPLL_CON0), + SAVE_ITEM(S5P_EPLL_CON1), +}; + +static struct sleep_save exynos4_vpll_save[] = { + SAVE_ITEM(S5P_VPLL_CON0), + SAVE_ITEM(S5P_VPLL_CON1), +}; + static struct sleep_save exynos4_core_save[] = { /* CMU side */ SAVE_ITEM(S5P_CLKDIV_LEFTBUS), SAVE_ITEM(S5P_CLKGATE_IP_LEFTBUS), SAVE_ITEM(S5P_CLKDIV_RIGHTBUS), SAVE_ITEM(S5P_CLKGATE_IP_RIGHTBUS), - SAVE_ITEM(S5P_EPLL_CON0), - SAVE_ITEM(S5P_EPLL_CON1), - SAVE_ITEM(S5P_VPLL_CON0), - SAVE_ITEM(S5P_VPLL_CON1), SAVE_ITEM(S5P_CLKSRC_TOP0), SAVE_ITEM(S5P_CLKSRC_TOP1), SAVE_ITEM(S5P_CLKSRC_CAM), @@ -260,6 +269,8 @@ static void exynos4_pm_prepare(void) s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save)); s3c_pm_do_save(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save)); + s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); + s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); tmp = __raw_readl(S5P_INFORM1); @@ -307,12 +318,80 @@ void exynos4_scu_enable(void __iomem *scu_base) flush_cache_all(); } +static unsigned long pll_base_rate; + +static void exynos4_restore_pll(void) +{ + unsigned long pll_con, locktime, lockcnt; + unsigned long pll_in_rate; + unsigned int p_div, epll_wait = 0, vpll_wait = 0; + + if (pll_base_rate == 0) + return; + + pll_in_rate = pll_base_rate; + + /* EPLL */ + pll_con = exynos4_epll_save[0].val; + + if (pll_con & (1 << 31)) { + pll_con &= (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT); + p_div = (pll_con >> PLL46XX_PDIV_SHIFT); + + pll_in_rate /= 1000000; + + locktime = (3000 / pll_in_rate) * p_div; + lockcnt = locktime * 10000 / (10000 / pll_in_rate); + + __raw_writel(lockcnt, S5P_EPLL_LOCK); + + s3c_pm_do_restore_core(exynos4_epll_save, + ARRAY_SIZE(exynos4_epll_save)); + epll_wait = 1; + } + + pll_in_rate = pll_base_rate; + + /* VPLL */ + pll_con = exynos4_vpll_save[0].val; + + if (pll_con & (1 << 31)) { + pll_in_rate /= 1000000; + /* 750us */ + locktime = 750; + lockcnt = locktime * 10000 / (10000 / pll_in_rate); + + __raw_writel(lockcnt, S5P_VPLL_LOCK); + + s3c_pm_do_restore_core(exynos4_vpll_save, + ARRAY_SIZE(exynos4_vpll_save)); + vpll_wait = 1; + } + + /* Wait PLL locking */ + + do { + if (epll_wait) { + pll_con = __raw_readl(S5P_EPLL_CON0); + if (pll_con & (1 << S5P_EPLLCON0_LOCKED_SHIFT)) + epll_wait = 0; + } + + if (vpll_wait) { + pll_con = __raw_readl(S5P_VPLL_CON0); + if (pll_con & (1 << S5P_VPLLCON0_LOCKED_SHIFT)) + vpll_wait = 0; + } + } while (epll_wait || vpll_wait); +} + static struct sysdev_driver exynos4_pm_driver = { .add = exynos4_pm_add, }; static __init int exynos4_pm_drvinit(void) { + struct clk *pll_base; unsigned int tmp; s3c_pm_init(); @@ -323,6 +402,13 @@ static __init int exynos4_pm_drvinit(void) tmp |= ((0xFF << 8) | (0x1F << 1)); __raw_writel(tmp, S5P_WAKEUP_MASK); + pll_base = clk_get(NULL, "xtal"); + + if (!IS_ERR(pll_base)) { + pll_base_rate = clk_get_rate(pll_base); + clk_put(pll_base); + } + return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver); } arch_initcall(exynos4_pm_drvinit); @@ -357,6 +443,8 @@ static void exynos4_pm_resume(void) s3c_pm_do_restore_core(exynos4_core_save, ARRAY_SIZE(exynos4_core_save)); + exynos4_restore_pll(); + exynos4_scu_enable(S5P_VA_SCU); #ifdef CONFIG_CACHE_L2X0