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