diff options
author | Joseph Lo <josephl@nvidia.com> | 2013-01-15 17:10:48 -0500 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2013-01-28 13:20:38 -0500 |
commit | 4a2e32794e71db679b91df1d9c98921b2e32ec4e (patch) | |
tree | 1c8884f7e7b18278837f483e07dbe1e63f726e60 /drivers/clk/tegra | |
parent | 5c1350bdfcebf47b3b6f83d62e5860259858a54a (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.c | 93 |
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 | ||
181 | static 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 | |||
172 | static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; | 191 | static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; |
173 | 192 | ||
174 | static void __iomem *clk_base; | 193 | static 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 | ||
1159 | static 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 | |||
1169 | static 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 | |||
1186 | static 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 | |||
1139 | static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { | 1227 | static 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 | ||
1147 | static __initdata struct tegra_clk_init_table init_table[] = { | 1240 | static __initdata struct tegra_clk_init_table init_table[] = { |