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