ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / powergate-t30.c
1 /*
2  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14
15 #include <linux/spinlock.h>
16 #include <linux/delay.h>
17 #include <linux/tegra-powergate.h>
18
19 #include "powergate-priv.h"
20 #include "powergate-ops-txx.h"
21
22 enum mc_client {
23         MC_CLIENT_AFI           = 0,
24         MC_CLIENT_AVPC          = 1,
25         MC_CLIENT_DC            = 2,
26         MC_CLIENT_DCB           = 3,
27         MC_CLIENT_EPP           = 4,
28         MC_CLIENT_G2            = 5,
29         MC_CLIENT_HC            = 6,
30         MC_CLIENT_HDA           = 7,
31         MC_CLIENT_ISP           = 8,
32         MC_CLIENT_MPCORE        = 9,
33         MC_CLIENT_MPCORELP      = 10,
34         MC_CLIENT_MPE           = 11,
35         MC_CLIENT_NV            = 12,
36         MC_CLIENT_NV2           = 13,
37         MC_CLIENT_PPCS          = 14,
38         MC_CLIENT_SATA          = 15,
39         MC_CLIENT_VDE           = 16,
40         MC_CLIENT_VI            = 17,
41         MC_CLIENT_LAST          = -1,
42 };
43
44 struct tegra3_powergate_mc_client_info {
45         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
46 };
47
48 static struct tegra3_powergate_mc_client_info tegra3_pg_mc_info[] = {
49         [TEGRA_POWERGATE_CPU] = {
50                 .hot_reset_clients = {
51                         [0] = MC_CLIENT_LAST,
52                 },
53         },
54         [TEGRA_POWERGATE_L2] = {
55                 .hot_reset_clients = {
56                         [0] = MC_CLIENT_LAST,
57                 },
58         },
59         [TEGRA_POWERGATE_3D] = {
60                 .hot_reset_clients = {
61                         [0] = MC_CLIENT_NV,
62                         [1] = MC_CLIENT_LAST,
63                 },
64         },
65 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
66         [TEGRA_POWERGATE_PCIE] = {
67                 .hot_reset_clients ={
68                         [0] = MC_CLIENT_AFI,
69                         [1] = MC_CLIENT_LAST,
70                 },
71         },
72 #endif
73         [TEGRA_POWERGATE_VDEC] = {
74                 .hot_reset_clients = {
75                         [0] = MC_CLIENT_VDE,
76                         [1] = MC_CLIENT_LAST,
77                 },
78         },
79         [TEGRA_POWERGATE_MPE] = {
80                 .hot_reset_clients = {
81                         [0] = MC_CLIENT_MPE,
82                         [1] = MC_CLIENT_LAST,
83                 },
84         },
85         [TEGRA_POWERGATE_VENC] = {
86                 .hot_reset_clients = {
87                         [0] = MC_CLIENT_ISP,
88                         [1] = MC_CLIENT_VI,
89                         [2] = MC_CLIENT_LAST,
90                 },
91         },
92         [TEGRA_POWERGATE_CPU1] = {
93                 .hot_reset_clients = {
94                         [0] = MC_CLIENT_LAST,
95                 },
96         },
97         [TEGRA_POWERGATE_CPU2] = {
98                 .hot_reset_clients = {
99                         [0] = MC_CLIENT_LAST,
100                 },
101         },
102         [TEGRA_POWERGATE_CPU3] = {
103                 .hot_reset_clients = {
104                         [0] = MC_CLIENT_LAST,
105                 },
106         },
107         [TEGRA_POWERGATE_CELP] = {
108                 .hot_reset_clients = {
109                         [0] = MC_CLIENT_LAST,
110                 },
111         },
112 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
113         [TEGRA_POWERGATE_SATA] = {
114                 .hot_reset_clients ={
115                         [0] = MC_CLIENT_SATA,
116                         [1] = MC_CLIENT_LAST
117                 },
118         },
119 #endif
120 #ifdef CONFIG_ARCH_TEGRA_HAS_DUAL_3D
121         [TEGRA_POWERGATE_3D1] = {
122                 .hot_reset_clients = {
123                         [0] = MC_CLIENT_NV2,
124                         [1] = MC_CLIENT_LAST
125                 },
126         },
127 #endif
128         [TEGRA_POWERGATE_HEG] = {
129                 .hot_reset_clients = {
130                         [0] = MC_CLIENT_G2,
131                         [1] = MC_CLIENT_EPP,
132                         [2] = MC_CLIENT_HC,
133                         [3] = MC_CLIENT_LAST
134                 },
135         },
136 };
137
138 static struct powergate_partition_info tegra3_powergate_partition_info[] = {
139         [TEGRA_POWERGATE_CPU] = { .name = "cpu0" },
140         [TEGRA_POWERGATE_L2] = { .name = "l2" },
141         [TEGRA_POWERGATE_3D] = {
142                 .name = "3d0",
143                 .clk_info = {
144                         [0] = { .clk_name = "3d", .clk_type = CLK_AND_RST },
145                 },
146         },
147 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
148         [TEGRA_POWERGATE_PCIE] = {
149                 .name = "pcie",
150                 .clk_info = {
151                         [0] = { .clk_name = "afi", .clk_type = CLK_AND_RST },
152                         [1] = { .clk_name = "pcie", .clk_type = CLK_AND_RST },
153                         [2] = { .clk_name = "cml0", .clk_type = CLK_ONLY },
154                         [3] = { .clk_name = "pciex", .clk_type = RST_ONLY },
155                 },
156         },
157 #endif
158         [TEGRA_POWERGATE_VDEC] = {
159                 .name = "vde",
160                 .clk_info = {
161                         [0] = { .clk_name = "vde", .clk_type = CLK_AND_RST },
162                 },
163         },
164         [TEGRA_POWERGATE_MPE] = {
165                 .name = "mpe",
166                 .clk_info = {
167                         [0] = { .clk_name = "mpe.cbus", CLK_AND_RST },
168                 },
169         },
170         [TEGRA_POWERGATE_VENC] = {
171                 .name = "ve",
172                 .clk_info = {
173                         [0] = { .clk_name = "isp", .clk_type = CLK_AND_RST },
174                         [1] = { .clk_name = "vi", .clk_type = CLK_AND_RST },
175                         [2] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
176                 },
177         },
178         [TEGRA_POWERGATE_CPU1] = { .name = "cpu1" },
179         [TEGRA_POWERGATE_CPU2] = { .name = "cpu2" },
180         [TEGRA_POWERGATE_CPU3] = { .name = "cpu3" },
181         [TEGRA_POWERGATE_CELP] = { .name = "celp" },
182 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
183         [TEGRA_POWERGATE_SATA] = {
184                 .name = "sata",
185                 .clk_info = {
186                         [0] = { .clk_name = "sata", .clk_type = CLK_AND_RST },
187                         [1] = { .clk_name = "sata_oob", .clk_type = CLK_AND_RST },
188                         [2] = { .clk_name = "cml1", .clk_type = CLK_ONLY },
189                         [3] = { .clk_name = "sata_cold", .clk_type = RST_ONLY },
190                 },
191         },
192 #endif
193 #ifdef CONFIG_ARCH_TEGRA_HAS_DUAL_3D
194         [TEGRA_POWERGATE_3D1] = {
195                 .name = "3d1",
196                 .clk_info = {
197                         [0] = { .clk_name = "3d2", .clk_type = CLK_AND_RST },
198                 },
199         },
200 #endif
201         [TEGRA_POWERGATE_HEG] = {
202                 .name = "heg",
203                 .clk_info = {
204                         [0] = { .clk_name = "2d.cbus", .clk_type = CLK_AND_RST },
205                         [1] = { .clk_name = "epp.cbus", .clk_type = CLK_AND_RST },
206                         [2] = { .clk_name = "host1x.cbus", .clk_type = CLK_AND_RST },
207                 },
208         },
209 };
210
211 static u8 tegra3_quad_cpu_domains[] = {
212         TEGRA_POWERGATE_CPU0,
213         TEGRA_POWERGATE_CPU1,
214         TEGRA_POWERGATE_CPU2,
215         TEGRA_POWERGATE_CPU3,
216 };
217
218 #define MC_CLIENT_HOTRESET_CTRL         0x200
219 #define MC_CLIENT_HOTRESET_STAT         0x204
220
221 static DEFINE_SPINLOCK(tegra3_powergate_lock);
222
223 int tegra3_powergate_partition(int id)
224 {
225         return tegraxx_powergate_partition(id,
226                 &tegra3_powergate_partition_info[id]);
227 }
228
229 int tegra3_unpowergate_partition(int id)
230 {
231         return tegraxx_unpowergate_partition(id,
232                 &tegra3_powergate_partition_info[id]);
233 }
234
235 int tegra3_powergate_partition_with_clk_off(int id)
236 {
237         if (id != TEGRA_POWERGATE_PCIE && id != TEGRA_POWERGATE_SATA) {
238                 WARN_ON(1);
239                 return -EINVAL;
240         }
241
242         return tegraxx_powergate_partition_with_clk_off(id,
243                 &tegra3_powergate_partition_info[id]);
244 }
245
246 int tegra3_unpowergate_partition_with_clk_on(int id)
247 {
248         if (id != TEGRA_POWERGATE_SATA && id != TEGRA_POWERGATE_PCIE) {
249                 WARN_ON(1);
250                 return -EINVAL;
251         }
252
253         return tegraxx_unpowergate_partition_with_clk_on(id,
254                 &tegra3_powergate_partition_info[id]);
255 }
256
257 int tegra3_powergate_mc_enable(int id)
258 {
259         return 0;
260 }
261
262 int tegra3_powergate_mc_disable(int id)
263 {
264         return 0;
265 }
266
267 int tegra3_powergate_mc_flush(int id)
268 {
269         u32 idx, rst_ctrl, rst_stat;
270         enum mc_client mcClientBit;
271         unsigned long flags;
272
273         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
274                 mcClientBit =
275                         tegra3_pg_mc_info[id].hot_reset_clients[idx];
276                 if (mcClientBit == MC_CLIENT_LAST)
277                         break;
278
279                 spin_lock_irqsave(&tegra3_powergate_lock, flags);
280                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
281                 rst_ctrl |= (1 << mcClientBit);
282                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
283                 spin_unlock_irqrestore(&tegra3_powergate_lock, flags);
284
285                 do {
286                         udelay(10);
287                         rst_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
288                 } while (!(rst_stat & (1 << mcClientBit)));
289         }
290
291         return 0;
292 }
293
294 int tegra3_powergate_mc_flush_done(int id)
295 {
296         u32 idx, rst_ctrl;
297         enum mc_client mcClientBit;
298         unsigned long flags;
299
300         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
301                 mcClientBit =
302                         tegra3_pg_mc_info[id].hot_reset_clients[idx];
303                 if (mcClientBit == MC_CLIENT_LAST)
304                         break;
305
306                 spin_lock_irqsave(&tegra3_powergate_lock, flags);
307
308                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
309                 rst_ctrl &= ~(1 << mcClientBit);
310                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
311
312                 spin_unlock_irqrestore(&tegra3_powergate_lock, flags);
313         }
314
315         wmb();
316
317         return 0;
318 }
319
320 const char *tegra3_get_powergate_domain_name(int id)
321 {
322         return tegra3_powergate_partition_info[id].name;
323 }
324
325 spinlock_t *tegra3_get_powergate_lock(void)
326 {
327         return &tegra3_powergate_lock;
328 }
329
330 static struct powergate_ops tegra3_powergate_ops = {
331         .soc_name = "tegra3",
332
333         .num_powerdomains = TEGRA_NUM_POWERGATE,
334         .num_cpu_domains = 4,
335         .cpu_domains = tegra3_quad_cpu_domains,
336
337         .get_powergate_lock = tegra3_get_powergate_lock,
338
339         .get_powergate_domain_name = tegra3_get_powergate_domain_name,
340
341         .powergate_partition = tegra3_powergate_partition,
342         .unpowergate_partition = tegra3_unpowergate_partition,
343
344         .powergate_partition_with_clk_off = tegra3_powergate_partition_with_clk_off,
345         .unpowergate_partition_with_clk_on = tegra3_unpowergate_partition_with_clk_on,
346
347         .powergate_mc_enable = tegra3_powergate_mc_enable,
348         .powergate_mc_disable = tegra3_powergate_mc_disable,
349
350         .powergate_mc_flush = tegra3_powergate_mc_flush,
351         .powergate_mc_flush_done = tegra3_powergate_mc_flush_done,
352 };
353
354 struct powergate_ops *tegra3_powergate_init_chip_support(void)
355 {
356         return &tegra3_powergate_ops;
357 }