ARM: tegra: add support for powergate skip list
[linux-3.10.git] / arch / arm / mach-tegra / powergate-t12x.c
1 /*
2  * Copyright (c) 2013, 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
18 #include <asm/atomic.h>
19
20 #include <mach/powergate.h>
21
22 #include "powergate-priv.h"
23 #include "powergate-ops-txx.h"
24 #include "powergate-ops-t1xx.h"
25
26 enum mc_client {
27         MC_CLIENT_AFI           = 0,
28         MC_CLIENT_DC            = 2,
29         MC_CLIENT_DCB           = 3,
30         MC_CLIENT_ISP           = 8,
31         MC_CLIENT_MSENC         = 11,
32         MC_CLIENT_SATA          = 15,
33         MC_CLIENT_VDE           = 16,
34         MC_CLIENT_VI            = 17,
35         MC_CLIENT_VIC           = 18,
36         MC_CLIENT_XUSB_HOST     = 19,
37         MC_CLIENT_XUSB_DEV      = 20,
38         MC_CLIENT_GPU           = 34,
39         MC_CLIENT_LAST          = -1,
40 };
41
42 struct tegra12x_powergate_mc_client_info {
43         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
44 };
45
46 static struct tegra12x_powergate_mc_client_info tegra12x_pg_mc_info[] = {
47         [TEGRA_POWERGATE_GPU] = {
48                 .hot_reset_clients = {
49                         [0] = MC_CLIENT_GPU,
50                         [1] = MC_CLIENT_LAST,
51                 },
52         },
53         [TEGRA_POWERGATE_VDEC] = {
54                 .hot_reset_clients = {
55                         [0] = MC_CLIENT_VDE,
56                         [1] = MC_CLIENT_LAST,
57                 },
58         },
59         [TEGRA_POWERGATE_MPE] = {
60                 .hot_reset_clients = {
61                         [0] = MC_CLIENT_MSENC,
62                         [1] = MC_CLIENT_LAST,
63                 },
64         },
65         [TEGRA_POWERGATE_VENC] = {
66                 .hot_reset_clients = {
67                         [0] = MC_CLIENT_ISP,
68                         [1] = MC_CLIENT_VI,
69                         [2] = MC_CLIENT_LAST,
70                 },
71         },
72         [TEGRA_POWERGATE_DISA] = {
73                 .hot_reset_clients = {
74                         [0] = MC_CLIENT_DC,
75                         [1] = MC_CLIENT_LAST,
76                 },
77         },
78         [TEGRA_POWERGATE_DISB] = {
79                 .hot_reset_clients = {
80                         [0] = MC_CLIENT_DCB,
81                         [1] = MC_CLIENT_LAST,
82                 },
83         },
84         [TEGRA_POWERGATE_XUSBA] = {
85                 .hot_reset_clients = {
86                         [0] = MC_CLIENT_LAST,
87                 },
88         },
89         [TEGRA_POWERGATE_XUSBB] = {
90                 .hot_reset_clients = {
91                         [0] = MC_CLIENT_XUSB_DEV,
92                         [1] = MC_CLIENT_LAST
93                 },
94         },
95         [TEGRA_POWERGATE_XUSBC] = {
96                 .hot_reset_clients = {
97                         [0] = MC_CLIENT_XUSB_HOST,
98                         [1] = MC_CLIENT_LAST,
99                 },
100         },
101 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
102         [TEGRA_POWERGATE_PCIE] = {
103                 .hot_reset_clients = {
104                         [0] = MC_CLIENT_AFI,
105                         [1] = MC_CLIENT_LAST,
106                 },
107         },
108 #endif
109 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
110         [TEGRA_POWERGATE_SATA] = {
111                 .hot_reset_clients = {
112                         [0] = MC_CLIENT_SATA,
113                         [1] = MC_CLIENT_LAST,
114                 },
115         },
116 #endif
117         [TEGRA_POWERGATE_SOR] = {
118                 .hot_reset_clients = {
119                         [0] = MC_CLIENT_LAST,
120                 },
121         },
122 #ifdef CONFIG_ARCH_TEGRA_VIC
123         [TEGRA_POWERGATE_VIC] = {
124                 .hot_reset_clients = {
125                         [0] = MC_CLIENT_VIC,
126                         [1] = MC_CLIENT_LAST,
127                 },
128         },
129 #endif
130 };
131
132 static struct powergate_partition_info tegra12x_powergate_partition_info[] = {
133         [TEGRA_POWERGATE_GPU] = {
134                 .name = "gpu",
135                 .clk_info = {
136                         [0] = { .clk_name = "gpu", .clk_type = CLK_AND_RST },
137                 },
138         },
139         [TEGRA_POWERGATE_VDEC] = {
140                 .name = "vde",
141                 .clk_info = {
142                         [0] = { .clk_name = "vde", .clk_type = CLK_AND_RST },
143                 },
144         },
145         [TEGRA_POWERGATE_MPE] = {
146                 .name = "mpe",
147                 .clk_info = {
148                         [0] = { .clk_name = "msenc.cbus", .clk_type = CLK_AND_RST },
149                 },
150         },
151         [TEGRA_POWERGATE_VENC] = {
152                 .name = "ve",
153                 .clk_info = {
154                         [0] = { .clk_name = "isp", .clk_type = CLK_AND_RST },
155                         [1] = { .clk_name = "vi", .clk_type = CLK_AND_RST },
156                         [2] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
157                 },
158         },
159         [TEGRA_POWERGATE_DISA] = {
160                 .name = "disa",
161                 .clk_info = {
162                         [0] = { .clk_name = "disp1", .clk_type = CLK_AND_RST },
163                         [1] = { .clk_name = "dsia", .clk_type = CLK_AND_RST },
164                         [2] = { .clk_name = "dsib", .clk_type = CLK_AND_RST },
165                         [3] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
166                         [4] = { .clk_name = "mipi-cal", .clk_type = CLK_AND_RST },
167                 },
168         },
169         [TEGRA_POWERGATE_DISB] = {
170                 .name = "disb",
171                 .clk_info = {
172                         [0] = { .clk_name = "disp2", .clk_type = CLK_AND_RST },
173                         [1] = { .clk_name = "hdmi", .clk_type = CLK_AND_RST },
174                 },
175         },
176         [TEGRA_POWERGATE_XUSBA] = {
177                 .name = "xusba",
178                 .clk_info = {
179                         [0] = { .clk_name = "xusb_ss", .clk_type = CLK_AND_RST },
180                 },
181         },
182         [TEGRA_POWERGATE_XUSBB] = {
183                 .name = "xusbb",
184                 .clk_info = {
185                         [0] = { .clk_name = "xusb_dev", .clk_type = CLK_AND_RST },
186                 },
187         },
188         [TEGRA_POWERGATE_XUSBC] = {
189                 .name = "xusbc",
190                 .clk_info = {
191                         [0] = { .clk_name = "xusb_host", .clk_type = CLK_AND_RST },
192                 },
193         },
194 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
195         [TEGRA_POWERGATE_PCIE] = {
196                 .name = "pcie",
197                 .clk_info = {
198                         [0] = { .clk_name = "afi", .clk_type = CLK_AND_RST },
199                         [1] = { .clk_name = "pcie", .clk_type = CLK_AND_RST },
200                         [2] = { .clk_name = "cml0", .clk_type = CLK_ONLY },
201                         [3] = { .clk_name = "pciex", .clk_type = RST_ONLY },
202                 },
203         },
204 #endif
205 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
206         [TEGRA_POWERGATE_SATA] = {
207                 .name = "sata",
208                 .clk_info = {
209                         [0] = { .clk_name = "sata", .clk_type = CLK_AND_RST },
210                         [1] = { .clk_name = "sata_oob", .clk_type = CLK_AND_RST },
211                         [2] = { .clk_name = "cml1", .clk_type = CLK_ONLY },
212                         [3] = { .clk_name = "sata_cold", .clk_type = RST_ONLY },
213                 },
214         },
215 #endif
216         [TEGRA_POWERGATE_SOR] = {
217                 .name = "sor",
218                 .clk_info = {
219                         [0] = { .clk_name = "sor0", .clk_type = CLK_AND_RST },
220                 },
221         },
222 #ifdef CONFIG_ARCH_TEGRA_VIC
223         [TEGRA_POWERGATE_VIC] = {
224                 .name = "vic",
225                 .clk_info = {
226                         [0] = { .clk_name = "vic03.cbus", .clk_type = CLK_AND_RST },
227                 },
228         },
229 #endif
230 };
231
232 static atomic_t ref_count_a = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISA */
233 static atomic_t ref_count_b = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISB */
234
235 #define MC_CLIENT_HOTRESET_CTRL         0x200
236 #define MC_CLIENT_HOTRESET_STAT         0x204
237 #define MC_CLIENT_HOTRESET_CTRL_1       0x970
238 #define MC_CLIENT_HOTRESET_STAT_1       0x974
239
240 #define PMC_GPU_RG_CNTRL_0              0x2d4
241
242 static DEFINE_SPINLOCK(tegra12x_powergate_lock);
243
244 #define HOTRESET_READ_COUNT     5
245 static bool tegra12x_stable_hotreset_check(u32 stat_reg, u32 *stat)
246 {
247         int i;
248         u32 cur_stat;
249         u32 prv_stat;
250         unsigned long flags;
251
252         spin_lock_irqsave(&tegra12x_powergate_lock, flags);
253         prv_stat = mc_read(stat_reg);
254         for (i = 0; i < HOTRESET_READ_COUNT; i++) {
255                 cur_stat = mc_read(stat_reg);
256                 if (cur_stat != prv_stat) {
257                         spin_unlock_irqrestore(&tegra12x_powergate_lock, flags);
258                         return false;
259                 }
260         }
261         *stat = cur_stat;
262         spin_unlock_irqrestore(&tegra12x_powergate_lock, flags);
263         return true;
264 }
265
266 int tegra12x_powergate_mc_enable(int id)
267 {
268         return 0;
269 }
270
271 int tegra12x_powergate_mc_disable(int id)
272 {
273         return 0;
274 }
275
276 int tegra12x_powergate_mc_flush(int id)
277 {
278         u32 idx, rst_ctrl, rst_stat;
279         u32 rst_ctrl_reg, rst_stat_reg;
280         enum mc_client mcClientBit;
281         unsigned long flags;
282         bool ret;
283
284         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
285                 mcClientBit =
286                         tegra12x_pg_mc_info[id].hot_reset_clients[idx];
287                 if (mcClientBit == MC_CLIENT_LAST)
288                         break;
289
290                 if (mcClientBit < 32) {
291                         rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL;
292                         rst_stat_reg = MC_CLIENT_HOTRESET_STAT;
293                 } else {
294                         mcClientBit %= 32;
295                         rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL_1;
296                         rst_stat_reg = MC_CLIENT_HOTRESET_STAT_1;
297                 }
298
299                 spin_lock_irqsave(&tegra12x_powergate_lock, flags);
300
301                 rst_ctrl = mc_read(rst_ctrl_reg);
302                 rst_ctrl |= (1 << mcClientBit);
303                 mc_write(rst_ctrl, rst_ctrl_reg);
304
305                 spin_unlock_irqrestore(&tegra12x_powergate_lock, flags);
306
307                 do {
308                         udelay(10);
309                         rst_stat = 0;
310                         ret = tegra12x_stable_hotreset_check(rst_stat_reg, &rst_stat);
311                         if (!ret)
312                                 continue;
313                 } while (!(rst_stat & (1 << mcClientBit)));
314         }
315
316         return 0;
317 }
318
319 int tegra12x_powergate_mc_flush_done(int id)
320 {
321         u32 idx, rst_ctrl, rst_ctrl_reg;
322         enum mc_client mcClientBit;
323         unsigned long flags;
324
325         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
326                 mcClientBit =
327                         tegra12x_pg_mc_info[id].hot_reset_clients[idx];
328                 if (mcClientBit == MC_CLIENT_LAST)
329                         break;
330
331                 if (mcClientBit < 32)
332                         rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL;
333                 else {
334                         mcClientBit %= 32;
335                         rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL_1;
336                 }
337
338                 spin_lock_irqsave(&tegra12x_powergate_lock, flags);
339
340                 rst_ctrl = mc_read(rst_ctrl_reg);
341                 rst_ctrl &= ~(1 << mcClientBit);
342                 mc_write(rst_ctrl, rst_ctrl_reg);
343
344                 spin_unlock_irqrestore(&tegra12x_powergate_lock, flags);
345         }
346
347         wmb();
348
349         return 0;
350 }
351
352 static int tegra12x_gpu_powergate(int id, struct powergate_partition_info *pg_info)
353 {
354         int ret;
355
356         /* If first clk_ptr is null, fill clk info for the partition */
357         if (!pg_info->clk_info[0].clk_ptr)
358                 get_clk_info(pg_info);
359
360         ret = partition_clk_enable(pg_info);
361         if (ret)
362                 WARN(1, "Couldn't enable clock");
363
364         udelay(10);
365
366         tegra_powergate_mc_flush(id);
367
368         udelay(10);
369
370         /* enable clamp */
371         pmc_write(0x1, PMC_GPU_RG_CNTRL_0);
372
373         udelay(10);
374
375         powergate_partition_assert_reset(pg_info);
376
377         udelay(10);
378
379         /* Powergating is done only if refcnt of all clks is 0 */
380         partition_clk_disable(pg_info);
381
382         udelay(10);
383
384         /* TBD: call regulator api to turn off VDD_GPU */
385         if (0)
386                 goto err_power_off;
387
388         return 0;
389
390 err_power_off:
391         WARN(1, "Could not Railgate Partition %d", id);
392         return ret;
393 }
394
395 static int tegra12x_gpu_unpowergate(int id, struct powergate_partition_info *pg_info)
396 {
397         int ret;
398
399         /* TBD: call regulator api to turn on VDD_GPU */
400         if (0)
401                 goto err_power;
402
403         /* If first clk_ptr is null, fill clk info for the partition */
404         if (!pg_info->clk_info[0].clk_ptr)
405                 get_clk_info(pg_info);
406
407         /* Un-Powergating fails if all clks are not enabled */
408         ret = partition_clk_enable(pg_info);
409         if (ret)
410                 goto err_clk_on;
411
412         udelay(10);
413
414         /* disable clamp */
415         pmc_write(0, PMC_GPU_RG_CNTRL_0);
416
417         udelay(10);
418
419         powergate_partition_deassert_reset(pg_info);
420
421         udelay(10);
422
423         tegra_powergate_mc_flush_done(id);
424
425         udelay(10);
426
427         /* Disable all clks enabled earlier. Drivers should enable clks */
428         partition_clk_disable(pg_info);
429
430         return 0;
431
432 err_clk_on:
433         powergate_module(id);
434 err_power:
435         WARN(1, "Could not Un-Railgate %d", id);
436         return ret;
437 }
438
439 int tegra12x_powergate_partition(int id)
440 {
441         int ret;
442
443         WARN_ONCE(atomic_read(&ref_count_a) < 0, "ref count A underflow");
444         WARN_ONCE(atomic_read(&ref_count_b) < 0, "ref count B underflow");
445
446         if (id == TEGRA_POWERGATE_DISA && atomic_dec_return(&ref_count_a) != 0)
447                 return 0;
448         else if (id == TEGRA_POWERGATE_DISB &&
449                 atomic_dec_return(&ref_count_b) != 0)
450                 return 0;
451
452         if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
453                 ret = tegra12x_gpu_powergate(id,
454                         &tegra12x_powergate_partition_info[id]);
455         } else {
456                 /* call common power-gate API for t1xx */
457                 ret = tegra1xx_powergate(id,
458                         &tegra12x_powergate_partition_info[id]);
459         }
460
461         return ret;
462 }
463
464 int tegra12x_unpowergate_partition(int id)
465 {
466         int ret;
467
468         WARN_ONCE(atomic_read(&ref_count_a) < 0, "ref count A underflow");
469         WARN_ONCE(atomic_read(&ref_count_b) < 0, "ref count B underflow");
470
471         if (id == TEGRA_POWERGATE_DISA && atomic_inc_return(&ref_count_a) != 1)
472                 return 0;
473         else if (id == TEGRA_POWERGATE_DISB &&
474                 atomic_inc_return(&ref_count_b) != 1)
475                 return 0;
476
477         if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
478                 ret = tegra12x_gpu_unpowergate(id,
479                         &tegra12x_powergate_partition_info[id]);
480         } else {
481                 ret = tegra1xx_unpowergate(id,
482                         &tegra12x_powergate_partition_info[id]);
483         }
484
485         return ret;
486 }
487
488 int tegra12x_powergate_partition_with_clk_off(int id)
489 {
490         BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
491
492         return tegraxx_powergate_partition_with_clk_off(id,
493                 &tegra12x_powergate_partition_info[id]);
494 }
495
496 int tegra12x_unpowergate_partition_with_clk_on(int id)
497 {
498         BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
499
500         return tegraxx_unpowergate_partition_with_clk_on(id,
501                 &tegra12x_powergate_partition_info[id]);
502 }
503
504 const char *tegra12x_get_powergate_domain_name(int id)
505 {
506         return tegra12x_powergate_partition_info[id].name;
507 }
508
509 spinlock_t *tegra12x_get_powergate_lock(void)
510 {
511         return &tegra12x_powergate_lock;
512 }
513
514 bool tegra12x_powergate_skip(int id)
515 {
516         switch (id) {
517         case TEGRA_POWERGATE_VDEC:
518         case TEGRA_POWERGATE_VENC:
519         case TEGRA_POWERGATE_DISA:
520         case TEGRA_POWERGATE_DISB:
521         case TEGRA_POWERGATE_XUSBA:
522         case TEGRA_POWERGATE_XUSBB:
523         case TEGRA_POWERGATE_XUSBC:
524 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
525         case TEGRA_POWERGATE_PCIE:
526 #endif
527 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
528         case TEGRA_POWERGATE_SATA:
529 #endif
530         case TEGRA_POWERGATE_SOR:
531                 return true;
532
533         default:
534                 return false;
535         }
536 }
537
538 static struct powergate_ops tegra12x_powergate_ops = {
539         .soc_name = "tegra12x",
540
541         .num_powerdomains = TEGRA_NUM_POWERGATE,
542
543         .get_powergate_lock = tegra12x_get_powergate_lock,
544         .get_powergate_domain_name = tegra12x_get_powergate_domain_name,
545
546         .powergate_partition = tegra12x_powergate_partition,
547         .unpowergate_partition = tegra12x_unpowergate_partition,
548
549         .powergate_partition_with_clk_off =  tegra12x_powergate_partition_with_clk_off,
550         .unpowergate_partition_with_clk_on = tegra12x_unpowergate_partition_with_clk_on,
551
552         .powergate_mc_enable = tegra12x_powergate_mc_enable,
553         .powergate_mc_disable = tegra12x_powergate_mc_disable,
554
555         .powergate_mc_flush = tegra12x_powergate_mc_flush,
556         .powergate_mc_flush_done = tegra12x_powergate_mc_flush_done,
557
558         .powergate_skip = tegra12x_powergate_skip,
559 };
560
561 struct powergate_ops *tegra12x_powergate_init_chip_support(void)
562 {
563         return &tegra12x_powergate_ops;
564 }