1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2efc1bb8aSSekhar Nori /* 3efc1bb8aSSekhar Nori * DaVinci Power Management Routines 4efc1bb8aSSekhar Nori * 5efc1bb8aSSekhar Nori * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/ 6efc1bb8aSSekhar Nori */ 7efc1bb8aSSekhar Nori 8efc1bb8aSSekhar Nori #include <linux/pm.h> 9efc1bb8aSSekhar Nori #include <linux/suspend.h> 10efc1bb8aSSekhar Nori #include <linux/module.h> 11efc1bb8aSSekhar Nori #include <linux/platform_device.h> 12efc1bb8aSSekhar Nori #include <linux/clk.h> 13efc1bb8aSSekhar Nori #include <linux/spinlock.h> 14efc1bb8aSSekhar Nori 15efc1bb8aSSekhar Nori #include <asm/cacheflush.h> 16efc1bb8aSSekhar Nori #include <asm/delay.h> 17b7f080cfSAlexey Dobriyan #include <asm/io.h> 18efc1bb8aSSekhar Nori 19215a084dSSekhar Nori #include <mach/common.h> 20efc1bb8aSSekhar Nori #include <mach/da8xx.h> 21aa9aa1ecSKevin Hilman #include <mach/mux.h> 22efc1bb8aSSekhar Nori #include <mach/pm.h> 23efc1bb8aSSekhar Nori 24efc1bb8aSSekhar Nori #include "clock.h" 25aa9aa1ecSKevin Hilman #include "psc.h" 26aa9aa1ecSKevin Hilman #include "sram.h" 27efc1bb8aSSekhar Nori 28aa9aa1ecSKevin Hilman #define DA850_PLL1_BASE 0x01e1a000 29efc1bb8aSSekhar Nori #define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF 30aa9aa1ecSKevin Hilman #define DEEPSLEEP_SLEEPCOUNT 128 31efc1bb8aSSekhar Nori 32efc1bb8aSSekhar Nori static void (*davinci_sram_suspend) (struct davinci_pm_config *); 33aa9aa1ecSKevin Hilman static struct davinci_pm_config pm_config = { 34aa9aa1ecSKevin Hilman .sleepcount = DEEPSLEEP_SLEEPCOUNT, 35aa9aa1ecSKevin Hilman .ddrpsc_num = DA8XX_LPSC1_EMIF3C, 36aa9aa1ecSKevin Hilman }; 37aa9aa1ecSKevin Hilman 38efc1bb8aSSekhar Nori static void davinci_sram_push(void *dest, void *src, unsigned int size) 39efc1bb8aSSekhar Nori { 40efc1bb8aSSekhar Nori memcpy(dest, src, size); 41efc1bb8aSSekhar Nori flush_icache_range((unsigned long)dest, (unsigned long)(dest + size)); 42efc1bb8aSSekhar Nori } 43efc1bb8aSSekhar Nori 44efc1bb8aSSekhar Nori static void davinci_pm_suspend(void) 45efc1bb8aSSekhar Nori { 46efc1bb8aSSekhar Nori unsigned val; 47efc1bb8aSSekhar Nori 481428ed1aSKevin Hilman if (pm_config.cpupll_reg_base != pm_config.ddrpll_reg_base) { 49efc1bb8aSSekhar Nori 50efc1bb8aSSekhar Nori /* Switch CPU PLL to bypass mode */ 511428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 52efc1bb8aSSekhar Nori val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN); 531428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 54efc1bb8aSSekhar Nori 55efc1bb8aSSekhar Nori udelay(PLL_BYPASS_TIME); 56efc1bb8aSSekhar Nori 57efc1bb8aSSekhar Nori /* Powerdown CPU PLL */ 581428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 59efc1bb8aSSekhar Nori val |= PLLCTL_PLLPWRDN; 601428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 61efc1bb8aSSekhar Nori } 62efc1bb8aSSekhar Nori 63efc1bb8aSSekhar Nori /* Configure sleep count in deep sleep register */ 641428ed1aSKevin Hilman val = __raw_readl(pm_config.deepsleep_reg); 65efc1bb8aSSekhar Nori val &= ~DEEPSLEEP_SLEEPCOUNT_MASK, 661428ed1aSKevin Hilman val |= pm_config.sleepcount; 671428ed1aSKevin Hilman __raw_writel(val, pm_config.deepsleep_reg); 68efc1bb8aSSekhar Nori 69efc1bb8aSSekhar Nori /* System goes to sleep in this call */ 701428ed1aSKevin Hilman davinci_sram_suspend(&pm_config); 71efc1bb8aSSekhar Nori 721428ed1aSKevin Hilman if (pm_config.cpupll_reg_base != pm_config.ddrpll_reg_base) { 73efc1bb8aSSekhar Nori 74efc1bb8aSSekhar Nori /* put CPU PLL in reset */ 751428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 76efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLRST; 771428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 78efc1bb8aSSekhar Nori 79efc1bb8aSSekhar Nori /* put CPU PLL in power down */ 801428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 81efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLPWRDN; 821428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 83efc1bb8aSSekhar Nori 84efc1bb8aSSekhar Nori /* wait for CPU PLL reset */ 85efc1bb8aSSekhar Nori udelay(PLL_RESET_TIME); 86efc1bb8aSSekhar Nori 87efc1bb8aSSekhar Nori /* bring CPU PLL out of reset */ 881428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 89efc1bb8aSSekhar Nori val |= PLLCTL_PLLRST; 901428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 91efc1bb8aSSekhar Nori 92efc1bb8aSSekhar Nori /* Wait for CPU PLL to lock */ 93efc1bb8aSSekhar Nori udelay(PLL_LOCK_TIME); 94efc1bb8aSSekhar Nori 95efc1bb8aSSekhar Nori /* Remove CPU PLL from bypass mode */ 961428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 97efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLENSRC; 98efc1bb8aSSekhar Nori val |= PLLCTL_PLLEN; 991428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 100efc1bb8aSSekhar Nori } 101efc1bb8aSSekhar Nori } 102efc1bb8aSSekhar Nori 103efc1bb8aSSekhar Nori static int davinci_pm_enter(suspend_state_t state) 104efc1bb8aSSekhar Nori { 105efc1bb8aSSekhar Nori int ret = 0; 106efc1bb8aSSekhar Nori 107efc1bb8aSSekhar Nori switch (state) { 108efc1bb8aSSekhar Nori case PM_SUSPEND_MEM: 109efc1bb8aSSekhar Nori davinci_pm_suspend(); 110efc1bb8aSSekhar Nori break; 111efc1bb8aSSekhar Nori default: 112efc1bb8aSSekhar Nori ret = -EINVAL; 113efc1bb8aSSekhar Nori } 114efc1bb8aSSekhar Nori 115efc1bb8aSSekhar Nori return ret; 116efc1bb8aSSekhar Nori } 117efc1bb8aSSekhar Nori 1182f55ac07SLionel Debroux static const struct platform_suspend_ops davinci_pm_ops = { 119efc1bb8aSSekhar Nori .enter = davinci_pm_enter, 120efc1bb8aSSekhar Nori .valid = suspend_valid_only_mem, 121efc1bb8aSSekhar Nori }; 122efc1bb8aSSekhar Nori 123aa9aa1ecSKevin Hilman int __init davinci_pm_init(void) 124efc1bb8aSSekhar Nori { 125aa9aa1ecSKevin Hilman int ret; 126aa9aa1ecSKevin Hilman 127aa9aa1ecSKevin Hilman ret = davinci_cfg_reg(DA850_RTC_ALARM); 128aa9aa1ecSKevin Hilman if (ret) 129aa9aa1ecSKevin Hilman return ret; 130aa9aa1ecSKevin Hilman 1311428ed1aSKevin Hilman pm_config.ddr2_ctlr_base = da8xx_get_mem_ctlr(); 1321428ed1aSKevin Hilman pm_config.deepsleep_reg = DA8XX_SYSCFG1_VIRT(DA8XX_DEEPSLEEP_REG); 133aa9aa1ecSKevin Hilman 1341428ed1aSKevin Hilman pm_config.cpupll_reg_base = ioremap(DA8XX_PLL0_BASE, SZ_4K); 1351428ed1aSKevin Hilman if (!pm_config.cpupll_reg_base) 136aa9aa1ecSKevin Hilman return -ENOMEM; 137aa9aa1ecSKevin Hilman 1381428ed1aSKevin Hilman pm_config.ddrpll_reg_base = ioremap(DA850_PLL1_BASE, SZ_4K); 1391428ed1aSKevin Hilman if (!pm_config.ddrpll_reg_base) { 140aa9aa1ecSKevin Hilman ret = -ENOMEM; 141aa9aa1ecSKevin Hilman goto no_ddrpll_mem; 142aa9aa1ecSKevin Hilman } 143aa9aa1ecSKevin Hilman 1441428ed1aSKevin Hilman pm_config.ddrpsc_reg_base = ioremap(DA8XX_PSC1_BASE, SZ_4K); 1451428ed1aSKevin Hilman if (!pm_config.ddrpsc_reg_base) { 146aa9aa1ecSKevin Hilman ret = -ENOMEM; 147aa9aa1ecSKevin Hilman goto no_ddrpsc_mem; 148efc1bb8aSSekhar Nori } 149efc1bb8aSSekhar Nori 150efc1bb8aSSekhar Nori davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL); 151efc1bb8aSSekhar Nori if (!davinci_sram_suspend) { 152aa9aa1ecSKevin Hilman pr_err("PM: cannot allocate SRAM memory\n"); 153f3f6cc81SChristophe JAILLET ret = -ENOMEM; 154f3f6cc81SChristophe JAILLET goto no_sram_mem; 155efc1bb8aSSekhar Nori } 156efc1bb8aSSekhar Nori 157efc1bb8aSSekhar Nori davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend, 158efc1bb8aSSekhar Nori davinci_cpu_suspend_sz); 159efc1bb8aSSekhar Nori 160efc1bb8aSSekhar Nori suspend_set_ops(&davinci_pm_ops); 161efc1bb8aSSekhar Nori 16295d7c1f1SChristophe JAILLET return 0; 16395d7c1f1SChristophe JAILLET 164f3f6cc81SChristophe JAILLET no_sram_mem: 165f3f6cc81SChristophe JAILLET iounmap(pm_config.ddrpsc_reg_base); 166aa9aa1ecSKevin Hilman no_ddrpsc_mem: 1671428ed1aSKevin Hilman iounmap(pm_config.ddrpll_reg_base); 168aa9aa1ecSKevin Hilman no_ddrpll_mem: 1691428ed1aSKevin Hilman iounmap(pm_config.cpupll_reg_base); 170aa9aa1ecSKevin Hilman return ret; 171efc1bb8aSSekhar Nori } 172