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> 24aa9aa1ecSKevin Hilman #include <mach/mux.h> 25efc1bb8aSSekhar Nori #include <mach/pm.h> 26efc1bb8aSSekhar Nori 27efc1bb8aSSekhar Nori #include "clock.h" 28aa9aa1ecSKevin Hilman #include "psc.h" 29aa9aa1ecSKevin Hilman #include "sram.h" 30efc1bb8aSSekhar Nori 31aa9aa1ecSKevin Hilman #define DA850_PLL1_BASE 0x01e1a000 32efc1bb8aSSekhar Nori #define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF 33aa9aa1ecSKevin Hilman #define DEEPSLEEP_SLEEPCOUNT 128 34efc1bb8aSSekhar Nori 35efc1bb8aSSekhar Nori static void (*davinci_sram_suspend) (struct davinci_pm_config *); 36aa9aa1ecSKevin Hilman static struct davinci_pm_config pm_config = { 37aa9aa1ecSKevin Hilman .sleepcount = DEEPSLEEP_SLEEPCOUNT, 38aa9aa1ecSKevin Hilman .ddrpsc_num = DA8XX_LPSC1_EMIF3C, 39aa9aa1ecSKevin Hilman }; 40aa9aa1ecSKevin Hilman 41efc1bb8aSSekhar Nori static void davinci_sram_push(void *dest, void *src, unsigned int size) 42efc1bb8aSSekhar Nori { 43efc1bb8aSSekhar Nori memcpy(dest, src, size); 44efc1bb8aSSekhar Nori flush_icache_range((unsigned long)dest, (unsigned long)(dest + size)); 45efc1bb8aSSekhar Nori } 46efc1bb8aSSekhar Nori 47efc1bb8aSSekhar Nori static void davinci_pm_suspend(void) 48efc1bb8aSSekhar Nori { 49efc1bb8aSSekhar Nori unsigned val; 50efc1bb8aSSekhar Nori 511428ed1aSKevin Hilman if (pm_config.cpupll_reg_base != pm_config.ddrpll_reg_base) { 52efc1bb8aSSekhar Nori 53efc1bb8aSSekhar Nori /* Switch CPU PLL to bypass mode */ 541428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 55efc1bb8aSSekhar Nori val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN); 561428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 57efc1bb8aSSekhar Nori 58efc1bb8aSSekhar Nori udelay(PLL_BYPASS_TIME); 59efc1bb8aSSekhar Nori 60efc1bb8aSSekhar Nori /* Powerdown CPU PLL */ 611428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 62efc1bb8aSSekhar Nori val |= PLLCTL_PLLPWRDN; 631428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 64efc1bb8aSSekhar Nori } 65efc1bb8aSSekhar Nori 66efc1bb8aSSekhar Nori /* Configure sleep count in deep sleep register */ 671428ed1aSKevin Hilman val = __raw_readl(pm_config.deepsleep_reg); 68efc1bb8aSSekhar Nori val &= ~DEEPSLEEP_SLEEPCOUNT_MASK, 691428ed1aSKevin Hilman val |= pm_config.sleepcount; 701428ed1aSKevin Hilman __raw_writel(val, pm_config.deepsleep_reg); 71efc1bb8aSSekhar Nori 72efc1bb8aSSekhar Nori /* System goes to sleep in this call */ 731428ed1aSKevin Hilman davinci_sram_suspend(&pm_config); 74efc1bb8aSSekhar Nori 751428ed1aSKevin Hilman if (pm_config.cpupll_reg_base != pm_config.ddrpll_reg_base) { 76efc1bb8aSSekhar Nori 77efc1bb8aSSekhar Nori /* put CPU PLL in reset */ 781428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 79efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLRST; 801428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 81efc1bb8aSSekhar Nori 82efc1bb8aSSekhar Nori /* put CPU PLL in power down */ 831428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 84efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLPWRDN; 851428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 86efc1bb8aSSekhar Nori 87efc1bb8aSSekhar Nori /* wait for CPU PLL reset */ 88efc1bb8aSSekhar Nori udelay(PLL_RESET_TIME); 89efc1bb8aSSekhar Nori 90efc1bb8aSSekhar Nori /* bring CPU PLL out of reset */ 911428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 92efc1bb8aSSekhar Nori val |= PLLCTL_PLLRST; 931428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 94efc1bb8aSSekhar Nori 95efc1bb8aSSekhar Nori /* Wait for CPU PLL to lock */ 96efc1bb8aSSekhar Nori udelay(PLL_LOCK_TIME); 97efc1bb8aSSekhar Nori 98efc1bb8aSSekhar Nori /* Remove CPU PLL from bypass mode */ 991428ed1aSKevin Hilman val = __raw_readl(pm_config.cpupll_reg_base + PLLCTL); 100efc1bb8aSSekhar Nori val &= ~PLLCTL_PLLENSRC; 101efc1bb8aSSekhar Nori val |= PLLCTL_PLLEN; 1021428ed1aSKevin Hilman __raw_writel(val, pm_config.cpupll_reg_base + PLLCTL); 103efc1bb8aSSekhar Nori } 104efc1bb8aSSekhar Nori } 105efc1bb8aSSekhar Nori 106efc1bb8aSSekhar Nori static int davinci_pm_enter(suspend_state_t state) 107efc1bb8aSSekhar Nori { 108efc1bb8aSSekhar Nori int ret = 0; 109efc1bb8aSSekhar Nori 110efc1bb8aSSekhar Nori switch (state) { 111efc1bb8aSSekhar Nori case PM_SUSPEND_MEM: 112efc1bb8aSSekhar Nori davinci_pm_suspend(); 113efc1bb8aSSekhar Nori break; 114efc1bb8aSSekhar Nori default: 115efc1bb8aSSekhar Nori ret = -EINVAL; 116efc1bb8aSSekhar Nori } 117efc1bb8aSSekhar Nori 118efc1bb8aSSekhar Nori return ret; 119efc1bb8aSSekhar Nori } 120efc1bb8aSSekhar Nori 1212f55ac07SLionel Debroux static const struct platform_suspend_ops davinci_pm_ops = { 122efc1bb8aSSekhar Nori .enter = davinci_pm_enter, 123efc1bb8aSSekhar Nori .valid = suspend_valid_only_mem, 124efc1bb8aSSekhar Nori }; 125efc1bb8aSSekhar Nori 126aa9aa1ecSKevin Hilman int __init davinci_pm_init(void) 127efc1bb8aSSekhar Nori { 128aa9aa1ecSKevin Hilman int ret; 129aa9aa1ecSKevin Hilman 130aa9aa1ecSKevin Hilman ret = davinci_cfg_reg(DA850_RTC_ALARM); 131aa9aa1ecSKevin Hilman if (ret) 132aa9aa1ecSKevin Hilman return ret; 133aa9aa1ecSKevin Hilman 1341428ed1aSKevin Hilman pm_config.ddr2_ctlr_base = da8xx_get_mem_ctlr(); 1351428ed1aSKevin Hilman pm_config.deepsleep_reg = DA8XX_SYSCFG1_VIRT(DA8XX_DEEPSLEEP_REG); 136aa9aa1ecSKevin Hilman 1371428ed1aSKevin Hilman pm_config.cpupll_reg_base = ioremap(DA8XX_PLL0_BASE, SZ_4K); 1381428ed1aSKevin Hilman if (!pm_config.cpupll_reg_base) 139aa9aa1ecSKevin Hilman return -ENOMEM; 140aa9aa1ecSKevin Hilman 1411428ed1aSKevin Hilman pm_config.ddrpll_reg_base = ioremap(DA850_PLL1_BASE, SZ_4K); 1421428ed1aSKevin Hilman if (!pm_config.ddrpll_reg_base) { 143aa9aa1ecSKevin Hilman ret = -ENOMEM; 144aa9aa1ecSKevin Hilman goto no_ddrpll_mem; 145aa9aa1ecSKevin Hilman } 146aa9aa1ecSKevin Hilman 1471428ed1aSKevin Hilman pm_config.ddrpsc_reg_base = ioremap(DA8XX_PSC1_BASE, SZ_4K); 1481428ed1aSKevin Hilman if (!pm_config.ddrpsc_reg_base) { 149aa9aa1ecSKevin Hilman ret = -ENOMEM; 150aa9aa1ecSKevin Hilman goto no_ddrpsc_mem; 151efc1bb8aSSekhar Nori } 152efc1bb8aSSekhar Nori 153efc1bb8aSSekhar Nori davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL); 154efc1bb8aSSekhar Nori if (!davinci_sram_suspend) { 155aa9aa1ecSKevin Hilman pr_err("PM: cannot allocate SRAM memory\n"); 156f3f6cc81SChristophe JAILLET ret = -ENOMEM; 157f3f6cc81SChristophe JAILLET goto no_sram_mem; 158efc1bb8aSSekhar Nori } 159efc1bb8aSSekhar Nori 160efc1bb8aSSekhar Nori davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend, 161efc1bb8aSSekhar Nori davinci_cpu_suspend_sz); 162efc1bb8aSSekhar Nori 163efc1bb8aSSekhar Nori suspend_set_ops(&davinci_pm_ops); 164efc1bb8aSSekhar Nori 165*95d7c1f1SChristophe JAILLET return 0; 166*95d7c1f1SChristophe JAILLET 167f3f6cc81SChristophe JAILLET no_sram_mem: 168f3f6cc81SChristophe JAILLET iounmap(pm_config.ddrpsc_reg_base); 169aa9aa1ecSKevin Hilman no_ddrpsc_mem: 1701428ed1aSKevin Hilman iounmap(pm_config.ddrpll_reg_base); 171aa9aa1ecSKevin Hilman no_ddrpll_mem: 1721428ed1aSKevin Hilman iounmap(pm_config.cpupll_reg_base); 173aa9aa1ecSKevin Hilman return ret; 174efc1bb8aSSekhar Nori } 175