1efc1bb8aSSekhar Nori /* 2efc1bb8aSSekhar Nori * DaVinci Power Management Routines 3efc1bb8aSSekhar Nori * 4efc1bb8aSSekhar Nori * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/ 5efc1bb8aSSekhar Nori * 6efc1bb8aSSekhar Nori * This program is free software; you can redistribute it and/or modify 7efc1bb8aSSekhar Nori * it under the terms of the GNU General Public License version 2 as 8efc1bb8aSSekhar Nori * published by the Free Software Foundation. 9efc1bb8aSSekhar Nori */ 10efc1bb8aSSekhar Nori 11efc1bb8aSSekhar Nori #include <linux/pm.h> 12efc1bb8aSSekhar Nori #include <linux/suspend.h> 13efc1bb8aSSekhar Nori #include <linux/module.h> 14efc1bb8aSSekhar Nori #include <linux/platform_device.h> 15efc1bb8aSSekhar Nori #include <linux/clk.h> 16efc1bb8aSSekhar Nori #include <linux/spinlock.h> 17efc1bb8aSSekhar Nori 18efc1bb8aSSekhar Nori #include <asm/cacheflush.h> 19efc1bb8aSSekhar Nori #include <asm/delay.h> 20b7f080cfSAlexey Dobriyan #include <asm/io.h> 21efc1bb8aSSekhar Nori 22215a084dSSekhar Nori #include <mach/common.h> 23efc1bb8aSSekhar Nori #include <mach/da8xx.h> 24*aa9aa1ecSKevin Hilman #include <mach/mux.h> 25efc1bb8aSSekhar Nori #include <mach/pm.h> 26efc1bb8aSSekhar Nori 27efc1bb8aSSekhar Nori #include "clock.h" 28*aa9aa1ecSKevin Hilman #include "psc.h" 29*aa9aa1ecSKevin Hilman #include "sram.h" 30efc1bb8aSSekhar Nori 31*aa9aa1ecSKevin Hilman #define DA850_PLL1_BASE 0x01e1a000 32efc1bb8aSSekhar Nori #define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF 33*aa9aa1ecSKevin Hilman #define DEEPSLEEP_SLEEPCOUNT 128 34efc1bb8aSSekhar Nori 35efc1bb8aSSekhar Nori static void (*davinci_sram_suspend) (struct davinci_pm_config *); 36*aa9aa1ecSKevin Hilman static struct davinci_pm_config pm_config = { 37*aa9aa1ecSKevin Hilman .sleepcount = DEEPSLEEP_SLEEPCOUNT, 38*aa9aa1ecSKevin Hilman .ddrpsc_num = DA8XX_LPSC1_EMIF3C, 39*aa9aa1ecSKevin Hilman }; 40*aa9aa1ecSKevin Hilman 41*aa9aa1ecSKevin Hilman static struct davinci_pm_config *pdata = &pm_config; 42efc1bb8aSSekhar Nori 43efc1bb8aSSekhar Nori static void davinci_sram_push(void *dest, void *src, unsigned int size) 44efc1bb8aSSekhar Nori { 45efc1bb8aSSekhar Nori memcpy(dest, src, size); 46efc1bb8aSSekhar Nori flush_icache_range((unsigned long)dest, (unsigned long)(dest + size)); 47efc1bb8aSSekhar Nori } 48efc1bb8aSSekhar Nori 49efc1bb8aSSekhar Nori static void davinci_pm_suspend(void) 50efc1bb8aSSekhar Nori { 51efc1bb8aSSekhar Nori unsigned val; 52efc1bb8aSSekhar Nori 53efc1bb8aSSekhar Nori if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) { 54efc1bb8aSSekhar Nori 55efc1bb8aSSekhar Nori /* Switch CPU PLL to bypass mode */ 56efc1bb8aSSekhar Nori val = __raw_readl(pdata->cpupll_reg_base + PLLCTL); 57efc1bb8aSSekhar Nori val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN); 58efc1bb8aSSekhar Nori __raw_writel(val, pdata->cpupll_reg_base + PLLCTL); 59efc1bb8aSSekhar Nori 60efc1bb8aSSekhar Nori udelay(PLL_BYPASS_TIME); 61efc1bb8aSSekhar Nori 62efc1bb8aSSekhar Nori /* Powerdown CPU PLL */ 63efc1bb8aSSekhar Nori val = __raw_readl(pdata->cpupll_reg_base + PLLCTL); 64efc1bb8aSSekhar Nori val |= PLLCTL_PLLPWRDN; 65efc1bb8aSSekhar Nori __raw_writel(val, pdata->cpupll_reg_base + PLLCTL); 66efc1bb8aSSekhar Nori } 67efc1bb8aSSekhar Nori 68efc1bb8aSSekhar Nori /* Configure sleep count in deep sleep register */ 69efc1bb8aSSekhar Nori val = __raw_readl(pdata->deepsleep_reg); 70efc1bb8aSSekhar Nori val &= ~DEEPSLEEP_SLEEPCOUNT_MASK, 71efc1bb8aSSekhar Nori val |= pdata->sleepcount; 72efc1bb8aSSekhar Nori __raw_writel(val, pdata->deepsleep_reg); 73efc1bb8aSSekhar Nori 74efc1bb8aSSekhar Nori /* System goes to sleep in this call */ 75efc1bb8aSSekhar Nori davinci_sram_suspend(pdata); 76efc1bb8aSSekhar Nori 77efc1bb8aSSekhar Nori if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) { 78efc1bb8aSSekhar Nori 79efc1bb8aSSekhar Nori /* put CPU PLL in reset */ 80efc1bb8aSSekhar Nori val = __raw_readl(pdata->cpupll_reg_base + PLLCTL); 81efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLRST; 82efc1bb8aSSekhar Nori __raw_writel(val, pdata->cpupll_reg_base + PLLCTL); 83efc1bb8aSSekhar Nori 84efc1bb8aSSekhar Nori /* put CPU PLL in power down */ 85efc1bb8aSSekhar Nori val = __raw_readl(pdata->cpupll_reg_base + PLLCTL); 86efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLPWRDN; 87efc1bb8aSSekhar Nori __raw_writel(val, pdata->cpupll_reg_base + PLLCTL); 88efc1bb8aSSekhar Nori 89efc1bb8aSSekhar Nori /* wait for CPU PLL reset */ 90efc1bb8aSSekhar Nori udelay(PLL_RESET_TIME); 91efc1bb8aSSekhar Nori 92efc1bb8aSSekhar Nori /* bring CPU PLL out of reset */ 93efc1bb8aSSekhar Nori val = __raw_readl(pdata->cpupll_reg_base + PLLCTL); 94efc1bb8aSSekhar Nori val |= PLLCTL_PLLRST; 95efc1bb8aSSekhar Nori __raw_writel(val, pdata->cpupll_reg_base + PLLCTL); 96efc1bb8aSSekhar Nori 97efc1bb8aSSekhar Nori /* Wait for CPU PLL to lock */ 98efc1bb8aSSekhar Nori udelay(PLL_LOCK_TIME); 99efc1bb8aSSekhar Nori 100efc1bb8aSSekhar Nori /* Remove CPU PLL from bypass mode */ 101efc1bb8aSSekhar Nori val = __raw_readl(pdata->cpupll_reg_base + PLLCTL); 102efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLENSRC; 103efc1bb8aSSekhar Nori val |= PLLCTL_PLLEN; 104efc1bb8aSSekhar Nori __raw_writel(val, pdata->cpupll_reg_base + PLLCTL); 105efc1bb8aSSekhar Nori } 106efc1bb8aSSekhar Nori } 107efc1bb8aSSekhar Nori 108efc1bb8aSSekhar Nori static int davinci_pm_enter(suspend_state_t state) 109efc1bb8aSSekhar Nori { 110efc1bb8aSSekhar Nori int ret = 0; 111efc1bb8aSSekhar Nori 112efc1bb8aSSekhar Nori switch (state) { 113efc1bb8aSSekhar Nori case PM_SUSPEND_STANDBY: 114efc1bb8aSSekhar Nori case PM_SUSPEND_MEM: 115efc1bb8aSSekhar Nori davinci_pm_suspend(); 116efc1bb8aSSekhar Nori break; 117efc1bb8aSSekhar Nori default: 118efc1bb8aSSekhar Nori ret = -EINVAL; 119efc1bb8aSSekhar Nori } 120efc1bb8aSSekhar Nori 121efc1bb8aSSekhar Nori return ret; 122efc1bb8aSSekhar Nori } 123efc1bb8aSSekhar Nori 1242f55ac07SLionel Debroux static const struct platform_suspend_ops davinci_pm_ops = { 125efc1bb8aSSekhar Nori .enter = davinci_pm_enter, 126efc1bb8aSSekhar Nori .valid = suspend_valid_only_mem, 127efc1bb8aSSekhar Nori }; 128efc1bb8aSSekhar Nori 129*aa9aa1ecSKevin Hilman int __init davinci_pm_init(void) 130efc1bb8aSSekhar Nori { 131*aa9aa1ecSKevin Hilman int ret; 132*aa9aa1ecSKevin Hilman 133*aa9aa1ecSKevin Hilman ret = davinci_cfg_reg(DA850_RTC_ALARM); 134*aa9aa1ecSKevin Hilman if (ret) 135*aa9aa1ecSKevin Hilman return ret; 136*aa9aa1ecSKevin Hilman 137*aa9aa1ecSKevin Hilman pdata->ddr2_ctlr_base = da8xx_get_mem_ctlr(); 138*aa9aa1ecSKevin Hilman pdata->deepsleep_reg = DA8XX_SYSCFG1_VIRT(DA8XX_DEEPSLEEP_REG); 139*aa9aa1ecSKevin Hilman 140*aa9aa1ecSKevin Hilman pdata->cpupll_reg_base = ioremap(DA8XX_PLL0_BASE, SZ_4K); 141*aa9aa1ecSKevin Hilman if (!pdata->cpupll_reg_base) 142*aa9aa1ecSKevin Hilman return -ENOMEM; 143*aa9aa1ecSKevin Hilman 144*aa9aa1ecSKevin Hilman pdata->ddrpll_reg_base = ioremap(DA850_PLL1_BASE, SZ_4K); 145*aa9aa1ecSKevin Hilman if (!pdata->ddrpll_reg_base) { 146*aa9aa1ecSKevin Hilman ret = -ENOMEM; 147*aa9aa1ecSKevin Hilman goto no_ddrpll_mem; 148*aa9aa1ecSKevin Hilman } 149*aa9aa1ecSKevin Hilman 150*aa9aa1ecSKevin Hilman pdata->ddrpsc_reg_base = ioremap(DA8XX_PSC1_BASE, SZ_4K); 151*aa9aa1ecSKevin Hilman if (!pdata->ddrpsc_reg_base) { 152*aa9aa1ecSKevin Hilman ret = -ENOMEM; 153*aa9aa1ecSKevin Hilman goto no_ddrpsc_mem; 154efc1bb8aSSekhar Nori } 155efc1bb8aSSekhar Nori 156efc1bb8aSSekhar Nori davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL); 157efc1bb8aSSekhar Nori if (!davinci_sram_suspend) { 158*aa9aa1ecSKevin Hilman pr_err("PM: cannot allocate SRAM memory\n"); 159efc1bb8aSSekhar Nori return -ENOMEM; 160efc1bb8aSSekhar Nori } 161efc1bb8aSSekhar Nori 162efc1bb8aSSekhar Nori davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend, 163efc1bb8aSSekhar Nori davinci_cpu_suspend_sz); 164efc1bb8aSSekhar Nori 165efc1bb8aSSekhar Nori suspend_set_ops(&davinci_pm_ops); 166efc1bb8aSSekhar Nori 167*aa9aa1ecSKevin Hilman no_ddrpsc_mem: 168*aa9aa1ecSKevin Hilman iounmap(pdata->ddrpll_reg_base); 169*aa9aa1ecSKevin Hilman no_ddrpll_mem: 170*aa9aa1ecSKevin Hilman iounmap(pdata->cpupll_reg_base); 171*aa9aa1ecSKevin Hilman return ret; 172efc1bb8aSSekhar Nori } 173