ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / powergate-t20.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_AVPC          = 0,
24         MC_CLIENT_DC            = 1,
25         MC_CLIENT_DCB           = 2,
26         MC_CLIENT_EPP           = 3,
27         MC_CLIENT_G2            = 4,
28         MC_CLIENT_HC            = 5,
29         MC_CLIENT_ISP           = 6,
30         MC_CLIENT_MPCORE        = 7,
31         MC_CLIENT_MPEA          = 8,
32         MC_CLIENT_MPEB          = 9,
33         MC_CLIENT_MPEC          = 10,
34         MC_CLIENT_NV            = 11,
35         MC_CLIENT_PPCS          = 12,
36         MC_CLIENT_VDE           = 13,
37         MC_CLIENT_VI            = 14,
38         MC_CLIENT_LAST          = -1,
39         MC_CLIENT_AFI           = MC_CLIENT_LAST,
40 };
41
42 struct tegra2_powergate_mc_client_info {
43         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
44 };
45
46 static struct tegra2_powergate_mc_client_info tegra2_pg_mc_info[] = {
47         [TEGRA_POWERGATE_CPU] = {
48                 .hot_reset_clients = {
49                         [0] = MC_CLIENT_LAST,
50                 },
51         },
52         [TEGRA_POWERGATE_L2] = {
53                 .hot_reset_clients = {
54                         [0] = MC_CLIENT_LAST,
55                 },
56         },
57         [TEGRA_POWERGATE_3D] = {
58                 .hot_reset_clients = {
59                         [0] = MC_CLIENT_NV,
60                         [1] = MC_CLIENT_LAST,
61                 },
62         },
63 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
64         [TEGRA_POWERGATE_PCIE] = {
65                 .hot_reset_clients = {
66                         [0] = MC_CLIENT_AFI,
67                         [1] = MC_CLIENT_LAST,
68                 },
69         },
70 #endif
71         [TEGRA_POWERGATE_VDEC] = {
72                 .hot_reset_clients = {
73                         [0] = MC_CLIENT_VDE,
74                         [1] = MC_CLIENT_LAST,
75                 },
76         },
77         [TEGRA_POWERGATE_MPE] = {
78                 .hot_reset_clients = {
79                         [0] = MC_CLIENT_MPEA,
80                         [1] = MC_CLIENT_MPEB,
81                         [2] = MC_CLIENT_MPEC,
82                         [3] = 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_HEG] = {
93                 .hot_reset_clients = {
94                         [0] = MC_CLIENT_G2,
95                         [1] = MC_CLIENT_EPP,
96                         [2] = MC_CLIENT_HC,
97                         [3] = MC_CLIENT_LAST,
98                 },
99         },
100 };
101
102 static struct powergate_partition_info tegra2_powergate_partition_info[] = {
103         [TEGRA_POWERGATE_CPU] = { .name = "cpu0" },
104         [TEGRA_POWERGATE_L2] = { .name = "l2" },
105         [TEGRA_POWERGATE_3D] = {
106                 .name = "3d0",
107                 .clk_info = {
108                         [0] = { .clk_name = "3d", .clk_type = CLK_AND_RST },
109                 },
110         },
111 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
112         [TEGRA_POWERGATE_PCIE] = {
113                 .name = "pcie",
114                 .clk_info = {
115                         [0] = { .clk_name = "afi", .clk_type = CLK_AND_RST },
116                         [1] = { .clk_name = "pcie", .clk_type = CLK_AND_RST },
117                         [2] = { .clk_name = "pciex", .clk_type = RST_ONLY },
118                 },
119         },
120 #endif
121         [TEGRA_POWERGATE_VDEC] = {
122                 .name = "vde",
123                 .clk_info = {
124                         [0] = { .clk_name = "vde", .clk_type = CLK_AND_RST },
125                 },
126         },
127         [TEGRA_POWERGATE_MPE] = {
128                 .name = "mpe",
129                 .clk_info = {
130                         [0] = { .clk_name = "mpe", .clk_type = CLK_AND_RST },
131                 },
132         },
133         [TEGRA_POWERGATE_VENC] = {
134                 .name = "ve",
135                 .clk_info = {
136                         [0] = { .clk_name = "isp", .clk_type = CLK_AND_RST },
137                         [1] = { .clk_name = "vi", .clk_type = CLK_AND_RST },
138                         [2] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
139                 },
140         },
141         [TEGRA_POWERGATE_HEG] = {
142                 .name = "heg",
143                 .clk_info = {
144                         [0] = { .clk_name = "2d", .clk_type = CLK_AND_RST },
145                         [1] = { .clk_name = "epp", .clk_type = CLK_AND_RST },
146                         [2] = { .clk_name = "host1x", .clk_type = CLK_AND_RST },
147                 },
148         },
149 };
150
151 #define MC_CLIENT_CTRL          0x100
152 #define MC_CLIENT_HOTRESETN     0x104
153 #define MC_CLIENT_ORRC_BASE     0x140
154
155 static DEFINE_SPINLOCK(tegra2_powergate_lock);
156
157 int tegra2_powergate_partition(int id)
158 {
159         return tegraxx_powergate_partition(id,
160                 &tegra2_powergate_partition_info[id]);
161 }
162
163 int tegra2_unpowergate_partition(int id)
164 {
165         return tegraxx_unpowergate_partition(id,
166                 &tegra2_powergate_partition_info[id]);
167 }
168
169 int tegra2_powergate_partition_with_clk_off(int id)
170 {
171         /* Restrict functions use to selected partitions */
172         if (id != TEGRA_POWERGATE_PCIE) {
173                 WARN_ON(1);
174                 return -EINVAL;
175         }
176
177         return tegraxx_powergate_partition_with_clk_off(id,
178                 &tegra2_powergate_partition_info[id]);
179 }
180
181 int tegra2_unpowergate_partition_with_clk_on(int id)
182 {
183         /* Restrict this functions use to few partitions */
184         if (id != TEGRA_POWERGATE_PCIE) {
185                 WARN_ON(1);
186                 return -EINVAL;
187         }
188
189         return tegraxx_unpowergate_partition_with_clk_on(id,
190                 &tegra2_powergate_partition_info[id]);
191 }
192
193 int tegra2_powergate_mc_enable(int id)
194 {
195         u32 idx, clt_ctrl;
196         enum mc_client mcClientBit;
197         unsigned long flags;
198
199         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
200                 mcClientBit =
201                         tegra2_pg_mc_info[id].hot_reset_clients[idx];
202                 if (mcClientBit == MC_CLIENT_LAST)
203                         break;
204
205                 spin_lock_irqsave(&tegra2_powergate_lock, flags);
206
207                 /* enable client */
208                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
209                 clt_ctrl |= (1 << mcClientBit);
210                 mc_write(clt_ctrl, MC_CLIENT_CTRL);
211
212                 /* read back to flush write */
213                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
214
215                 spin_unlock_irqrestore(&tegra2_powergate_lock, flags);
216         }
217
218         return 0;
219 }
220
221 int tegra2_powergate_mc_disable(int id)
222 {
223         u32 idx, clt_ctrl, orrc_reg;
224         enum mc_client mcClientBit;
225         unsigned long flags;
226
227         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
228                 mcClientBit =
229                         tegra2_pg_mc_info[id].hot_reset_clients[idx];
230                 if (mcClientBit == MC_CLIENT_LAST)
231                         break;
232
233                 spin_lock_irqsave(&tegra2_powergate_lock, flags);
234
235                 /* clear client enable bit */
236                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
237                 clt_ctrl &= ~(1 << mcClientBit);
238                 mc_write(clt_ctrl, MC_CLIENT_CTRL);
239
240                 /* read back to flush write */
241                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
242
243                 spin_unlock_irqrestore(&tegra2_powergate_lock, flags);
244
245                 /* wait for outstanding requests to reach 0 */
246                 orrc_reg = MC_CLIENT_ORRC_BASE + (mcClientBit * 4);
247                 while (mc_read(orrc_reg) != 0)
248                         udelay(10);
249         }
250
251         return 0;
252 }
253
254 int tegra2_powergate_mc_flush(int id)
255 {
256         u32 idx, hot_rstn;
257         enum mc_client mcClientBit;
258         unsigned long flags;
259
260         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
261                 mcClientBit =
262                         tegra2_pg_mc_info[id].hot_reset_clients[idx];
263                 if (mcClientBit == MC_CLIENT_LAST)
264                         break;
265
266                 spin_lock_irqsave(&tegra2_powergate_lock, flags);
267
268                 /* assert hotreset (client module is currently in reset) */
269                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
270                 hot_rstn &= ~(1 << mcClientBit);
271                 mc_write(hot_rstn, MC_CLIENT_HOTRESETN);
272
273                 /* read back to flush write */
274                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
275
276                 spin_unlock_irqrestore(&tegra2_powergate_lock, flags);
277         }
278
279         return 0;
280 }
281
282 int tegra2_powergate_mc_flush_done(int id)
283 {
284         u32 idx, hot_rstn;
285         enum mc_client mcClientBit;
286         unsigned long flags;
287
288         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
289                 mcClientBit =
290                         tegra2_pg_mc_info[id].hot_reset_clients[idx];
291                 if (mcClientBit == MC_CLIENT_LAST)
292                         break;
293
294                 spin_lock_irqsave(&tegra2_powergate_lock, flags);
295
296                 /* deassert hotreset */
297                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
298                 hot_rstn |= (1 << mcClientBit);
299                 mc_write(hot_rstn, MC_CLIENT_HOTRESETN);
300
301                 /* read back to flush write */
302                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
303
304                 spin_unlock_irqrestore(&tegra2_powergate_lock, flags);
305         }
306
307         return 0;
308 }
309
310 const char *tegra2_get_powergate_domain_name(int id)
311 {
312         return tegra2_powergate_partition_info[id].name;
313 }
314
315 spinlock_t *tegra2_get_powergate_lock(void)
316 {
317         return &tegra2_powergate_lock;
318 }
319
320 static struct powergate_ops tegra2_powergate_ops = {
321         .soc_name = "tegra2",
322
323         .num_powerdomains = TEGRA_NUM_POWERGATE,
324         .num_cpu_domains = 0,
325         .cpu_domains = NULL,
326
327         .get_powergate_lock = tegra2_get_powergate_lock,
328
329         .get_powergate_domain_name = tegra2_get_powergate_domain_name,
330
331         .powergate_partition = tegra2_powergate_partition,
332         .unpowergate_partition = tegra2_unpowergate_partition,
333
334         .powergate_partition_with_clk_off = tegra2_powergate_partition_with_clk_off,
335         .unpowergate_partition_with_clk_on = tegra2_unpowergate_partition_with_clk_on,
336
337         .powergate_mc_enable = tegra2_powergate_mc_enable,
338         .powergate_mc_disable = tegra2_powergate_mc_disable,
339
340         .powergate_mc_flush = tegra2_powergate_mc_flush,
341         .powergate_mc_flush_done = tegra2_powergate_mc_flush_done,
342 };
343
344 struct powergate_ops *tegra2_powergate_init_chip_support(void)
345 {
346         return &tegra2_powergate_ops;
347 }