diff options
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra20_clocks.c | 70 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra20_clocks_data.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra30_clocks.c | 72 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra30_clocks_data.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra_cpu_car.h | 87 |
6 files changed, 238 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 632133fc985b..fd82085eca5d 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c | |||
@@ -31,6 +31,10 @@ | |||
31 | 31 | ||
32 | #include "board.h" | 32 | #include "board.h" |
33 | #include "clock.h" | 33 | #include "clock.h" |
34 | #include "tegra_cpu_car.h" | ||
35 | |||
36 | /* Global data of Tegra CPU CAR ops */ | ||
37 | struct tegra_cpu_car_ops *tegra_cpu_car_ops; | ||
34 | 38 | ||
35 | /* | 39 | /* |
36 | * Locking: | 40 | * Locking: |
diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c index 840ab262272a..9273b0dffc66 100644 --- a/arch/arm/mach-tegra/tegra20_clocks.c +++ b/arch/arm/mach-tegra/tegra20_clocks.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "clock.h" | 33 | #include "clock.h" |
34 | #include "fuse.h" | 34 | #include "fuse.h" |
35 | #include "tegra2_emc.h" | 35 | #include "tegra2_emc.h" |
36 | #include "tegra_cpu_car.h" | ||
36 | 37 | ||
37 | #define RST_DEVICES 0x004 | 38 | #define RST_DEVICES 0x004 |
38 | #define RST_DEVICES_SET 0x300 | 39 | #define RST_DEVICES_SET 0x300 |
@@ -152,6 +153,14 @@ | |||
152 | #define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16 | 153 | #define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16 |
153 | #define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff | 154 | #define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff |
154 | 155 | ||
156 | /* Tegra CPU clock and reset control regs */ | ||
157 | #define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c | ||
158 | #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 | ||
159 | #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 | ||
160 | |||
161 | #define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) | ||
162 | #define CPU_RESET(cpu) (0x1111ul << (cpu)) | ||
163 | |||
155 | static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); | 164 | static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); |
156 | static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); | 165 | static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); |
157 | 166 | ||
@@ -1553,3 +1562,64 @@ struct clk_ops tegra_cdev_clk_ops = { | |||
1553 | .disable = tegra20_cdev_clk_disable, | 1562 | .disable = tegra20_cdev_clk_disable, |
1554 | .recalc_rate = tegra20_cdev_recalc_rate, | 1563 | .recalc_rate = tegra20_cdev_recalc_rate, |
1555 | }; | 1564 | }; |
1565 | |||
1566 | /* Tegra20 CPU clock and reset control functions */ | ||
1567 | static void tegra20_wait_cpu_in_reset(u32 cpu) | ||
1568 | { | ||
1569 | unsigned int reg; | ||
1570 | |||
1571 | do { | ||
1572 | reg = readl(reg_clk_base + | ||
1573 | TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); | ||
1574 | cpu_relax(); | ||
1575 | } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ | ||
1576 | |||
1577 | return; | ||
1578 | } | ||
1579 | |||
1580 | static void tegra20_put_cpu_in_reset(u32 cpu) | ||
1581 | { | ||
1582 | writel(CPU_RESET(cpu), | ||
1583 | reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); | ||
1584 | dmb(); | ||
1585 | } | ||
1586 | |||
1587 | static void tegra20_cpu_out_of_reset(u32 cpu) | ||
1588 | { | ||
1589 | writel(CPU_RESET(cpu), | ||
1590 | reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); | ||
1591 | wmb(); | ||
1592 | } | ||
1593 | |||
1594 | static void tegra20_enable_cpu_clock(u32 cpu) | ||
1595 | { | ||
1596 | unsigned int reg; | ||
1597 | |||
1598 | reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
1599 | writel(reg & ~CPU_CLOCK(cpu), | ||
1600 | reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
1601 | barrier(); | ||
1602 | reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
1603 | } | ||
1604 | |||
1605 | static void tegra20_disable_cpu_clock(u32 cpu) | ||
1606 | { | ||
1607 | unsigned int reg; | ||
1608 | |||
1609 | reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
1610 | writel(reg | CPU_CLOCK(cpu), | ||
1611 | reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
1612 | } | ||
1613 | |||
1614 | static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { | ||
1615 | .wait_for_reset = tegra20_wait_cpu_in_reset, | ||
1616 | .put_in_reset = tegra20_put_cpu_in_reset, | ||
1617 | .out_of_reset = tegra20_cpu_out_of_reset, | ||
1618 | .enable_clock = tegra20_enable_cpu_clock, | ||
1619 | .disable_clock = tegra20_disable_cpu_clock, | ||
1620 | }; | ||
1621 | |||
1622 | void __init tegra20_cpu_car_ops_init(void) | ||
1623 | { | ||
1624 | tegra_cpu_car_ops = &tegra20_cpu_car_ops; | ||
1625 | } | ||
diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c index 1a35c003fba8..e81dcd239c95 100644 --- a/arch/arm/mach-tegra/tegra20_clocks_data.c +++ b/arch/arm/mach-tegra/tegra20_clocks_data.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "fuse.h" | 34 | #include "fuse.h" |
35 | #include "tegra2_emc.h" | 35 | #include "tegra2_emc.h" |
36 | #include "tegra20_clocks.h" | 36 | #include "tegra20_clocks.h" |
37 | #include "tegra_cpu_car.h" | ||
37 | 38 | ||
38 | /* Clock definitions */ | 39 | /* Clock definitions */ |
39 | 40 | ||
@@ -1139,4 +1140,5 @@ void __init tegra2_init_clocks(void) | |||
1139 | } | 1140 | } |
1140 | 1141 | ||
1141 | init_audio_sync_clock_mux(); | 1142 | init_audio_sync_clock_mux(); |
1143 | tegra20_cpu_car_ops_init(); | ||
1142 | } | 1144 | } |
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index 63615dadfbb2..5cd502c27163 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c | |||
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | #include "clock.h" | 36 | #include "clock.h" |
37 | #include "fuse.h" | 37 | #include "fuse.h" |
38 | #include "tegra_cpu_car.h" | ||
38 | 39 | ||
39 | #define USE_PLL_LOCK_BITS 0 | 40 | #define USE_PLL_LOCK_BITS 0 |
40 | 41 | ||
@@ -299,6 +300,16 @@ | |||
299 | /* FIXME: recommended safety delay after lock is detected */ | 300 | /* FIXME: recommended safety delay after lock is detected */ |
300 | #define PLL_POST_LOCK_DELAY 100 | 301 | #define PLL_POST_LOCK_DELAY 100 |
301 | 302 | ||
303 | /* Tegra CPU clock and reset control regs */ | ||
304 | #define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c | ||
305 | #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 | ||
306 | #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 | ||
307 | #define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR 0x34c | ||
308 | #define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 | ||
309 | |||
310 | #define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) | ||
311 | #define CPU_RESET(cpu) (0x1111ul << (cpu)) | ||
312 | |||
302 | /** | 313 | /** |
303 | * Structure defining the fields for USB UTMI clocks Parameters. | 314 | * Structure defining the fields for USB UTMI clocks Parameters. |
304 | */ | 315 | */ |
@@ -2221,3 +2232,64 @@ struct clk_ops tegra_cml_clk_ops = { | |||
2221 | struct clk_ops tegra_pciex_clk_ops = { | 2232 | struct clk_ops tegra_pciex_clk_ops = { |
2222 | .recalc_rate = tegra30_clk_fixed_recalc_rate, | 2233 | .recalc_rate = tegra30_clk_fixed_recalc_rate, |
2223 | }; | 2234 | }; |
2235 | |||
2236 | /* Tegra30 CPU clock and reset control functions */ | ||
2237 | static void tegra30_wait_cpu_in_reset(u32 cpu) | ||
2238 | { | ||
2239 | unsigned int reg; | ||
2240 | |||
2241 | do { | ||
2242 | reg = readl(reg_clk_base + | ||
2243 | TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); | ||
2244 | cpu_relax(); | ||
2245 | } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ | ||
2246 | |||
2247 | return; | ||
2248 | } | ||
2249 | |||
2250 | static void tegra30_put_cpu_in_reset(u32 cpu) | ||
2251 | { | ||
2252 | writel(CPU_RESET(cpu), | ||
2253 | reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); | ||
2254 | dmb(); | ||
2255 | } | ||
2256 | |||
2257 | static void tegra30_cpu_out_of_reset(u32 cpu) | ||
2258 | { | ||
2259 | writel(CPU_RESET(cpu), | ||
2260 | reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); | ||
2261 | wmb(); | ||
2262 | } | ||
2263 | |||
2264 | static void tegra30_enable_cpu_clock(u32 cpu) | ||
2265 | { | ||
2266 | unsigned int reg; | ||
2267 | |||
2268 | writel(CPU_CLOCK(cpu), | ||
2269 | reg_clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); | ||
2270 | reg = readl(reg_clk_base + | ||
2271 | TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); | ||
2272 | } | ||
2273 | |||
2274 | static void tegra30_disable_cpu_clock(u32 cpu) | ||
2275 | { | ||
2276 | |||
2277 | unsigned int reg; | ||
2278 | |||
2279 | reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
2280 | writel(reg | CPU_CLOCK(cpu), | ||
2281 | reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
2282 | } | ||
2283 | |||
2284 | static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { | ||
2285 | .wait_for_reset = tegra30_wait_cpu_in_reset, | ||
2286 | .put_in_reset = tegra30_put_cpu_in_reset, | ||
2287 | .out_of_reset = tegra30_cpu_out_of_reset, | ||
2288 | .enable_clock = tegra30_enable_cpu_clock, | ||
2289 | .disable_clock = tegra30_disable_cpu_clock, | ||
2290 | }; | ||
2291 | |||
2292 | void __init tegra30_cpu_car_ops_init(void) | ||
2293 | { | ||
2294 | tegra_cpu_car_ops = &tegra30_cpu_car_ops; | ||
2295 | } | ||
diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c index 34b61a4934a3..c10449603df0 100644 --- a/arch/arm/mach-tegra/tegra30_clocks_data.c +++ b/arch/arm/mach-tegra/tegra30_clocks_data.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "clock.h" | 32 | #include "clock.h" |
33 | #include "fuse.h" | 33 | #include "fuse.h" |
34 | #include "tegra30_clocks.h" | 34 | #include "tegra30_clocks.h" |
35 | #include "tegra_cpu_car.h" | ||
35 | 36 | ||
36 | #define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ | 37 | #define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ |
37 | _parent_names, _parents, _parent) \ | 38 | _parent_names, _parents, _parent) \ |
@@ -1366,4 +1367,6 @@ void __init tegra30_init_clocks(void) | |||
1366 | 1367 | ||
1367 | for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) | 1368 | for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) |
1368 | tegra30_init_one_clock(tegra_clk_out_list[i]); | 1369 | tegra30_init_one_clock(tegra_clk_out_list[i]); |
1370 | |||
1371 | tegra30_cpu_car_ops_init(); | ||
1369 | } | 1372 | } |
diff --git a/arch/arm/mach-tegra/tegra_cpu_car.h b/arch/arm/mach-tegra/tegra_cpu_car.h new file mode 100644 index 000000000000..30d063ad2bef --- /dev/null +++ b/arch/arm/mach-tegra/tegra_cpu_car.h | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef __MACH_TEGRA_CPU_CAR_H | ||
18 | #define __MACH_TEGRA_CPU_CAR_H | ||
19 | |||
20 | /* | ||
21 | * Tegra CPU clock and reset control ops | ||
22 | * | ||
23 | * wait_for_reset: | ||
24 | * keep waiting until the CPU in reset state | ||
25 | * put_in_reset: | ||
26 | * put the CPU in reset state | ||
27 | * out_of_reset: | ||
28 | * release the CPU from reset state | ||
29 | * enable_clock: | ||
30 | * CPU clock un-gate | ||
31 | * disable_clock: | ||
32 | * CPU clock gate | ||
33 | */ | ||
34 | struct tegra_cpu_car_ops { | ||
35 | void (*wait_for_reset)(u32 cpu); | ||
36 | void (*put_in_reset)(u32 cpu); | ||
37 | void (*out_of_reset)(u32 cpu); | ||
38 | void (*enable_clock)(u32 cpu); | ||
39 | void (*disable_clock)(u32 cpu); | ||
40 | }; | ||
41 | |||
42 | extern struct tegra_cpu_car_ops *tegra_cpu_car_ops; | ||
43 | |||
44 | static inline void tegra_wait_cpu_in_reset(u32 cpu) | ||
45 | { | ||
46 | if (WARN_ON(!tegra_cpu_car_ops->wait_for_reset)) | ||
47 | return; | ||
48 | |||
49 | tegra_cpu_car_ops->wait_for_reset(cpu); | ||
50 | } | ||
51 | |||
52 | static inline void tegra_put_cpu_in_reset(u32 cpu) | ||
53 | { | ||
54 | if (WARN_ON(!tegra_cpu_car_ops->put_in_reset)) | ||
55 | return; | ||
56 | |||
57 | tegra_cpu_car_ops->put_in_reset(cpu); | ||
58 | } | ||
59 | |||
60 | static inline void tegra_cpu_out_of_reset(u32 cpu) | ||
61 | { | ||
62 | if (WARN_ON(!tegra_cpu_car_ops->out_of_reset)) | ||
63 | return; | ||
64 | |||
65 | tegra_cpu_car_ops->out_of_reset(cpu); | ||
66 | } | ||
67 | |||
68 | static inline void tegra_enable_cpu_clock(u32 cpu) | ||
69 | { | ||
70 | if (WARN_ON(!tegra_cpu_car_ops->enable_clock)) | ||
71 | return; | ||
72 | |||
73 | tegra_cpu_car_ops->enable_clock(cpu); | ||
74 | } | ||
75 | |||
76 | static inline void tegra_disable_cpu_clock(u32 cpu) | ||
77 | { | ||
78 | if (WARN_ON(!tegra_cpu_car_ops->disable_clock)) | ||
79 | return; | ||
80 | |||
81 | tegra_cpu_car_ops->disable_clock(cpu); | ||
82 | } | ||
83 | |||
84 | void tegra20_cpu_car_ops_init(void); | ||
85 | void tegra30_cpu_car_ops_init(void); | ||
86 | |||
87 | #endif /* __MACH_TEGRA_CPU_CAR_H */ | ||