aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/tegra
diff options
context:
space:
mode:
authorJoseph Lo <josephl@nvidia.com>2013-01-15 17:10:48 -0500
committerStephen Warren <swarren@nvidia.com>2013-01-28 13:20:38 -0500
commit4a2e32794e71db679b91df1d9c98921b2e32ec4e (patch)
tree1c8884f7e7b18278837f483e07dbe1e63f726e60 /drivers/clk/tegra
parent5c1350bdfcebf47b3b6f83d62e5860259858a54a (diff)
clk: tegra20: Implementing CPU low-power function for tegra_cpu_car_ops
Implementing suspend, resume and rail_off_ready API for tegra_cpu_car_ops. These functions were used for CPU powered-down state maintenance. Signed-off-by: Joseph Lo <josephl@nvidia.com> Signed-off-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'drivers/clk/tegra')
-rw-r--r--drivers/clk/tegra/clk-tegra20.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 077d5b9ffe22..5d41569883a7 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -21,6 +21,7 @@
21#include <linux/of.h> 21#include <linux/of.h>
22#include <linux/of_address.h> 22#include <linux/of_address.h>
23#include <linux/clk/tegra.h> 23#include <linux/clk/tegra.h>
24#include <linux/delay.h>
24 25
25#include "clk.h" 26#include "clk.h"
26 27
@@ -104,6 +105,13 @@
104#define SUPER_SCLK_DIVIDER 0x2c 105#define SUPER_SCLK_DIVIDER 0x2c
105#define CLK_SYSTEM_RATE 0x30 106#define CLK_SYSTEM_RATE 0x30
106 107
108#define CCLK_BURST_POLICY_SHIFT 28
109#define CCLK_RUN_POLICY_SHIFT 4
110#define CCLK_IDLE_POLICY_SHIFT 0
111#define CCLK_IDLE_POLICY 1
112#define CCLK_RUN_POLICY 2
113#define CCLK_BURST_POLICY_PLLX 8
114
107#define CLK_SOURCE_I2S1 0x100 115#define CLK_SOURCE_I2S1 0x100
108#define CLK_SOURCE_I2S2 0x104 116#define CLK_SOURCE_I2S2 0x104
109#define CLK_SOURCE_SPDIF_OUT 0x108 117#define CLK_SOURCE_SPDIF_OUT 0x108
@@ -169,6 +177,17 @@
169#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) 177#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
170#define CPU_RESET(cpu) (0x1111ul << (cpu)) 178#define CPU_RESET(cpu) (0x1111ul << (cpu))
171 179
180#ifdef CONFIG_PM_SLEEP
181static struct cpu_clk_suspend_context {
182 u32 pllx_misc;
183 u32 pllx_base;
184
185 u32 cpu_burst;
186 u32 clk_csite_src;
187 u32 cclk_divider;
188} tegra20_cpu_clk_sctx;
189#endif
190
172static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; 191static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32];
173 192
174static void __iomem *clk_base; 193static void __iomem *clk_base;
@@ -1136,12 +1155,86 @@ static void tegra20_disable_cpu_clock(u32 cpu)
1136 clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); 1155 clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1137} 1156}
1138 1157
1158#ifdef CONFIG_PM_SLEEP
1159static bool tegra20_cpu_rail_off_ready(void)
1160{
1161 unsigned int cpu_rst_status;
1162
1163 cpu_rst_status = readl(clk_base +
1164 TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
1165
1166 return !!(cpu_rst_status & 0x2);
1167}
1168
1169static void tegra20_cpu_clock_suspend(void)
1170{
1171 /* switch coresite to clk_m, save off original source */
1172 tegra20_cpu_clk_sctx.clk_csite_src =
1173 readl(clk_base + CLK_SOURCE_CSITE);
1174 writel(3<<30, clk_base + CLK_SOURCE_CSITE);
1175
1176 tegra20_cpu_clk_sctx.cpu_burst =
1177 readl(clk_base + CCLK_BURST_POLICY);
1178 tegra20_cpu_clk_sctx.pllx_base =
1179 readl(clk_base + PLLX_BASE);
1180 tegra20_cpu_clk_sctx.pllx_misc =
1181 readl(clk_base + PLLX_MISC);
1182 tegra20_cpu_clk_sctx.cclk_divider =
1183 readl(clk_base + SUPER_CCLK_DIVIDER);
1184}
1185
1186static void tegra20_cpu_clock_resume(void)
1187{
1188 unsigned int reg, policy;
1189
1190 /* Is CPU complex already running on PLLX? */
1191 reg = readl(clk_base + CCLK_BURST_POLICY);
1192 policy = (reg >> CCLK_BURST_POLICY_SHIFT) & 0xF;
1193
1194 if (policy == CCLK_IDLE_POLICY)
1195 reg = (reg >> CCLK_IDLE_POLICY_SHIFT) & 0xF;
1196 else if (policy == CCLK_RUN_POLICY)
1197 reg = (reg >> CCLK_RUN_POLICY_SHIFT) & 0xF;
1198 else
1199 BUG();
1200
1201 if (reg != CCLK_BURST_POLICY_PLLX) {
1202 /* restore PLLX settings if CPU is on different PLL */
1203 writel(tegra20_cpu_clk_sctx.pllx_misc,
1204 clk_base + PLLX_MISC);
1205 writel(tegra20_cpu_clk_sctx.pllx_base,
1206 clk_base + PLLX_BASE);
1207
1208 /* wait for PLL stabilization if PLLX was enabled */
1209 if (tegra20_cpu_clk_sctx.pllx_base & (1 << 30))
1210 udelay(300);
1211 }
1212
1213 /*
1214 * Restore original burst policy setting for calls resulting from CPU
1215 * LP2 in idle or system suspend.
1216 */
1217 writel(tegra20_cpu_clk_sctx.cclk_divider,
1218 clk_base + SUPER_CCLK_DIVIDER);
1219 writel(tegra20_cpu_clk_sctx.cpu_burst,
1220 clk_base + CCLK_BURST_POLICY);
1221
1222 writel(tegra20_cpu_clk_sctx.clk_csite_src,
1223 clk_base + CLK_SOURCE_CSITE);
1224}
1225#endif
1226
1139static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { 1227static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
1140 .wait_for_reset = tegra20_wait_cpu_in_reset, 1228 .wait_for_reset = tegra20_wait_cpu_in_reset,
1141 .put_in_reset = tegra20_put_cpu_in_reset, 1229 .put_in_reset = tegra20_put_cpu_in_reset,
1142 .out_of_reset = tegra20_cpu_out_of_reset, 1230 .out_of_reset = tegra20_cpu_out_of_reset,
1143 .enable_clock = tegra20_enable_cpu_clock, 1231 .enable_clock = tegra20_enable_cpu_clock,
1144 .disable_clock = tegra20_disable_cpu_clock, 1232 .disable_clock = tegra20_disable_cpu_clock,
1233#ifdef CONFIG_PM_SLEEP
1234 .rail_off_ready = tegra20_cpu_rail_off_ready,
1235 .suspend = tegra20_cpu_clock_suspend,
1236 .resume = tegra20_cpu_clock_resume,
1237#endif
1145}; 1238};
1146 1239
1147static __initdata struct tegra_clk_init_table init_table[] = { 1240static __initdata struct tegra_clk_init_table init_table[] = {