ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / powergate-t11x.c
1 /*
2  * Copyright (c) 2012-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 #include <linux/tegra-powergate.h>
18
19 #include <asm/atomic.h>
20
21 #include "powergate-priv.h"
22 #include "powergate-ops-txx.h"
23 #include "powergate-ops-t1xx.h"
24
25 enum mc_client {
26         MC_CLIENT_AVPC          = 1,
27         MC_CLIENT_DC            = 2,
28         MC_CLIENT_DCB           = 3,
29         MC_CLIENT_EPP           = 4,
30         MC_CLIENT_G2            = 5,
31         MC_CLIENT_HC            = 6,
32         MC_CLIENT_HDA           = 7,
33         MC_CLIENT_ISP           = 8,
34         MC_CLIENT_MPCORE        = 9,
35         MC_CLIENT_MPCORELP      = 10,
36         MC_CLIENT_MSENC         = 11,
37         MC_CLIENT_NV            = 12,
38         MC_CLIENT_PPCS          = 14,
39         MC_CLIENT_VDE           = 16,
40         MC_CLIENT_VI            = 17,
41         MC_CLIENT_XUSB_HOST     = 19,
42         MC_CLIENT_XUSB_DEV      = 20,
43         MC_CLIENT_EMUCIF        = 21,
44         MC_CLIENT_TSEC          = 22,
45         MC_CLIENT_LAST          = -1,
46         MC_CLIENT_AFI           = MC_CLIENT_LAST,
47         MC_CLIENT_MPE           = MC_CLIENT_LAST,
48         MC_CLIENT_NV2           = MC_CLIENT_LAST,
49         MC_CLIENT_SATA          = MC_CLIENT_LAST,
50 };
51
52 struct tegra11x_powergate_mc_client_info {
53         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
54 };
55
56 static struct tegra11x_powergate_mc_client_info tegra11x_pg_mc_info[] = {
57         [TEGRA_POWERGATE_CRAIL] = {
58                 .hot_reset_clients = {
59                         [0] = MC_CLIENT_LAST,
60                 },
61         },
62         [TEGRA_POWERGATE_3D] = {
63                 .hot_reset_clients = {
64                         [0] = MC_CLIENT_NV,
65                         [1] = MC_CLIENT_LAST,
66                 },
67         },
68         [TEGRA_POWERGATE_VDEC] = {
69                 .hot_reset_clients = {
70                         [0] = MC_CLIENT_VDE,
71                         [1] = MC_CLIENT_LAST,
72                 },
73         },
74         [TEGRA_POWERGATE_MPE] = {
75                 .hot_reset_clients = {
76                         [0] = MC_CLIENT_MSENC,
77                         [1] = MC_CLIENT_LAST,
78                 },
79         },
80         [TEGRA_POWERGATE_VENC] = {
81                 .hot_reset_clients = {
82                         [0] = MC_CLIENT_ISP,
83                         [1] = MC_CLIENT_VI,
84                         [2] = MC_CLIENT_LAST,
85                 },
86         },
87         [TEGRA_POWERGATE_HEG] = {
88                 .hot_reset_clients = {
89                         [0] = MC_CLIENT_G2,
90                         [1] = MC_CLIENT_EPP,
91                         [2] = MC_CLIENT_LAST,
92                 },
93         },
94         [TEGRA_POWERGATE_CPU1] = {
95                 .hot_reset_clients = {
96                         [0] = MC_CLIENT_LAST,
97                 },
98         },
99         [TEGRA_POWERGATE_CPU2] = {
100                 .hot_reset_clients = {
101                         [0] = MC_CLIENT_LAST,
102                 },
103         },
104         [TEGRA_POWERGATE_CPU3] = {
105                 .hot_reset_clients = {
106                         [0] = MC_CLIENT_LAST,
107                 },
108         },
109         [TEGRA_POWERGATE_CELP] = {
110                 .hot_reset_clients = {
111                         [0] = MC_CLIENT_LAST,
112                 },
113         },
114         [TEGRA_POWERGATE_CPU0] = {
115                 .hot_reset_clients = {
116                         [0] = MC_CLIENT_LAST,
117                 },
118         },
119         [TEGRA_POWERGATE_C0NC] = {
120                 .hot_reset_clients = {
121                         [0] = MC_CLIENT_LAST,
122                 },
123         },
124         [TEGRA_POWERGATE_C1NC] = {
125                 .hot_reset_clients = {
126                         [0] = MC_CLIENT_LAST,
127                 },
128         },
129         [TEGRA_POWERGATE_DISA] = {
130                 .hot_reset_clients = {
131                         [0] = MC_CLIENT_DC,
132                         [1] = MC_CLIENT_LAST,
133                 },
134         },
135         [TEGRA_POWERGATE_DISB] = {
136                 .hot_reset_clients = {
137                         [0] = MC_CLIENT_DCB,
138                         [1] = MC_CLIENT_LAST,
139                 },
140         },
141         [TEGRA_POWERGATE_XUSBA] = {
142                 .hot_reset_clients = {
143                         [0] = MC_CLIENT_LAST,
144                 },
145         },
146         [TEGRA_POWERGATE_XUSBB] = {
147                 .hot_reset_clients = {
148                         [0] = MC_CLIENT_XUSB_DEV,
149                         [1] = MC_CLIENT_LAST
150                 },
151         },
152         [TEGRA_POWERGATE_XUSBC] = {
153                 .hot_reset_clients = {
154                         [0] = MC_CLIENT_XUSB_HOST,
155                         [1] = MC_CLIENT_LAST,
156                 },
157         },
158 };
159
160 static struct powergate_partition_info tegra11x_powergate_partition_info[] = {
161         [TEGRA_POWERGATE_CRAIL] = { .name = "crail" },
162         [TEGRA_POWERGATE_3D] = {
163                 .name = "3d",
164                 .clk_info = {
165                         [0] = { .clk_name = "3d", .clk_type = CLK_AND_RST },
166                 },
167         },
168         [TEGRA_POWERGATE_VDEC] = {
169                 .name = "vde",
170                 .clk_info = {
171                         [0] = { .clk_name = "vde", .clk_type = CLK_AND_RST },
172                 },
173         },
174         [TEGRA_POWERGATE_MPE] = {
175                 .name = "mpe",
176                 .clk_info = {
177                         [0] = { .clk_name = "msenc.cbus", .clk_type = CLK_AND_RST },
178                 },
179         },
180         [TEGRA_POWERGATE_VENC] = {
181                 .name = "ve",
182                 .clk_info = {
183                         [0] = { .clk_name = "isp", .clk_type = CLK_AND_RST },
184                         [1] = { .clk_name = "vi", .clk_type = CLK_AND_RST },
185                         [2] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
186                 },
187         },
188         [TEGRA_POWERGATE_HEG] = {
189                 .name = "heg",
190                 .clk_info = {
191                         [0] = { .clk_name = "2d.cbus", .clk_type = CLK_AND_RST },
192                         [1] = { .clk_name = "epp.cbus", .clk_type = CLK_AND_RST },
193                 },
194         },
195         [TEGRA_POWERGATE_CPU1] = { .name = "cpu1" },
196         [TEGRA_POWERGATE_CPU2] = { .name = "cpu2" },
197         [TEGRA_POWERGATE_CPU3] = { .name = "cpu3" },
198         [TEGRA_POWERGATE_CELP] = { .name = "celp" },
199         [TEGRA_POWERGATE_CPU0] = { .name = "cpu0" },
200         [TEGRA_POWERGATE_C0NC] = { .name = "c0nc" },
201         [TEGRA_POWERGATE_C1NC] = { .name = "c1nc" },
202         [TEGRA_POWERGATE_DISA] = {
203                 .name = "disa",
204                 .clk_info = {
205                         [0] = { .clk_name = "disp1", .clk_type = CLK_AND_RST },
206                         [1] = { .clk_name = "dsia", .clk_type = CLK_AND_RST },
207                         [2] = { .clk_name = "dsib", .clk_type = CLK_AND_RST },
208                         [3] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
209                         [4] = { .clk_name = "mipi-cal", .clk_type = CLK_AND_RST },
210                 },
211         },
212         [TEGRA_POWERGATE_DISB] = {
213                 .name = "disb",
214                 .clk_info = {
215                         [0] = { .clk_name = "disp2", .clk_type = CLK_AND_RST },
216                         [1] = { .clk_name = "hdmi", .clk_type = CLK_AND_RST },
217                 },
218         },
219         [TEGRA_POWERGATE_XUSBA] = {
220                 .name = "xusba",
221                 .clk_info = {
222                         [0] = { .clk_name = "xusb_ss", .clk_type = CLK_AND_RST },
223                 },
224         },
225         [TEGRA_POWERGATE_XUSBB] = {
226                 .name = "xusbb",
227                 .clk_info = {
228                         [0] = { .clk_name = "xusb_dev", .clk_type = CLK_AND_RST },
229                 },
230         },
231         [TEGRA_POWERGATE_XUSBC] = {
232                 .name = "xusbc",
233                 .clk_info = {
234                         [0] = { .clk_name = "xusb_host", .clk_type = CLK_AND_RST },
235                 },
236         },
237 };
238
239 static atomic_t ref_count_a = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISA */
240 static atomic_t ref_count_b = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISB */
241
242 static void __iomem *mipi_cal = IO_ADDRESS(TEGRA_MIPI_CAL_BASE);
243 static u32 mipi_cal_read(unsigned long reg)
244 {
245         return readl(mipi_cal + reg);
246 }
247
248 static void mipi_cal_write(u32 val, unsigned long reg)
249 {
250         writel_relaxed(val, mipi_cal + reg);
251 }
252
253 #define MC_CLIENT_HOTRESET_CTRL         0x200
254 #define MC_CLIENT_HOTRESET_STAT         0x204
255
256 static DEFINE_SPINLOCK(tegra11x_powergate_lock);
257
258 /* Forward Declarations */
259 int tegra11x_powergate_mc_flush(int id);
260 int tegra11x_powergate_mc_flush_done(int id);
261 int tegra11x_unpowergate_partition_with_clk_on(int id);
262 int tegra11x_powergate_partition_with_clk_off(int id);
263
264 bool tegra11x_powergate_check_clamping(int id)
265 {
266         u32 mask;
267         /*
268          * PCIE and VDE clamping masks are swapped with respect to their
269          * partition ids
270          */
271         if (id ==  TEGRA_POWERGATE_VDEC)
272                 mask = (1 << TEGRA_POWERGATE_PCIE);
273         else if (id == TEGRA_POWERGATE_PCIE)
274                 mask = (1 << TEGRA_POWERGATE_VDEC);
275         else
276                 mask = (1 << id);
277
278         return !!(pmc_read(PWRGATE_CLAMP_STATUS) & mask);
279 }
280
281 #define HOTRESET_READ_COUNT     5
282 static bool tegra11x_stable_hotreset_check(u32 *stat)
283 {
284         int i;
285         u32 cur_stat;
286         u32 prv_stat;
287         unsigned long flags;
288
289         spin_lock_irqsave(&tegra11x_powergate_lock, flags);
290         prv_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
291         for (i = 0; i < HOTRESET_READ_COUNT; i++) {
292                 cur_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
293                 if (cur_stat != prv_stat) {
294                         spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
295                         return false;
296                 }
297         }
298         *stat = cur_stat;
299         spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
300         return true;
301 }
302
303 /*
304  * FIXME: sw war for mipi-cal calibration when unpowergating DISA partition
305  */
306 static void tegra11x_mipical_calibrate(int id)
307 {
308         struct reg_offset_val {
309                 u32 offset;
310                 u32 por_value;
311         };
312         u32 status;
313         unsigned long flags;
314
315 #define MIPI_CAL_MIPI_CAL_CTRL_0                0x0
316 #define MIPI_CAL_CIL_MIPI_CAL_STATUS_0          0x8
317 #define MIPI_CAL_CILA_MIPI_CAL_CONFIG_0         0x14
318 #define MIPI_CAL_CILB_MIPI_CAL_CONFIG_0         0x18
319 #define MIPI_CAL_CILC_MIPI_CAL_CONFIG_0         0x1c
320 #define MIPI_CAL_CILD_MIPI_CAL_CONFIG_0         0x20
321 #define MIPI_CAL_CILE_MIPI_CAL_CONFIG_0         0x24
322 #define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_0         0x38
323 #define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_0         0x3c
324 #define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_0         0x40
325 #define MIPI_CAL_DSID_MIPI_CAL_CONFIG_0         0x44
326
327         static struct reg_offset_val mipi_cal_por_values[] = {
328                 { MIPI_CAL_MIPI_CAL_CTRL_0, 0x2a000000 },
329                 { MIPI_CAL_CILA_MIPI_CAL_CONFIG_0, 0x00200000 },
330                 { MIPI_CAL_CILB_MIPI_CAL_CONFIG_0, 0x00200000 },
331                 { MIPI_CAL_CILC_MIPI_CAL_CONFIG_0, 0x00200000 },
332                 { MIPI_CAL_CILD_MIPI_CAL_CONFIG_0, 0x00200000 },
333                 { MIPI_CAL_CILE_MIPI_CAL_CONFIG_0, 0x00000000 },
334                 { MIPI_CAL_DSIA_MIPI_CAL_CONFIG_0, 0x00200000 },
335                 { MIPI_CAL_DSIB_MIPI_CAL_CONFIG_0, 0x00200000 },
336                 { MIPI_CAL_DSIC_MIPI_CAL_CONFIG_0, 0x00200000 },
337                 { MIPI_CAL_DSID_MIPI_CAL_CONFIG_0, 0x00200000 },
338         };
339         int i;
340
341         if (id != TEGRA_POWERGATE_DISA)
342                 return;
343
344         spin_lock_irqsave(&tegra11x_powergate_lock, flags);
345
346         /* mipi cal por restore */
347         for (i = 0; i < ARRAY_SIZE(mipi_cal_por_values); i++) {
348                 mipi_cal_write(mipi_cal_por_values[i].por_value,
349                         mipi_cal_por_values[i].offset);
350         }
351
352         /* mipi cal status clear */
353         status = mipi_cal_read(MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
354         mipi_cal_write(status, MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
355
356         /* mipi cal status read - to flush writes */
357         status = mipi_cal_read(MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
358
359         spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
360 }
361
362 static int tegra11x_powergate_partition_internal(int id,
363         struct powergate_partition_info *pg_info)
364 {
365         int ret;
366
367         if (tegra_powergate_is_powered(id)) {
368                 ret = is_partition_clk_disabled(pg_info);
369                 if (ret < 0) {
370                         /* clock enabled */
371                         ret = tegra11x_powergate_partition_with_clk_off(id);
372                         if (ret < 0)
373                                 return ret;
374                 } else {
375                         ret = tegra_powergate_partition(id);
376                         if (ret < 0)
377                                 return ret;
378                 }
379         }
380         return 0;
381 }
382
383 static int tegra11x_unpowergate_partition_internal(int id,
384         struct powergate_partition_info *pg_info)
385 {
386         int ret;
387
388         if (!tegra_powergate_is_powered(id)) {
389                 ret = is_partition_clk_disabled(pg_info);
390                 if (ret) {
391                         /* clock disabled */
392                         ret = tegra11x_unpowergate_partition_with_clk_on(id);
393                         if (ret < 0)
394                                 return ret;
395                 } else {
396                         ret = tegra_unpowergate_partition(id);
397                         if (ret < 0)
398                                 return ret;
399                 }
400         }
401         return 0;
402 }
403
404 /*
405  * Tegra11x has powergate dependencies between partitions.
406  * This function captures the dependencies.
407  */
408 static int tegra11x_check_partition_pg_seq(int id,
409         struct powergate_partition_info *pg_info)
410 {
411         int ret;
412
413         if (id == TEGRA_POWERGATE_DISA) {
414                 ret = tegra11x_powergate_partition_internal(TEGRA_POWERGATE_VENC,
415                         pg_info);
416                 if (ret < 0)
417                         return ret;
418
419                 ret = tegra11x_powergate_partition_internal(TEGRA_POWERGATE_DISB,
420                         pg_info);
421                 if (ret < 0)
422                         return ret;
423         }
424
425         return 0;
426 }
427
428 /*
429  * This function captures power-ungate dependencies between tegra11x partitions
430  */
431 static int tegra11x_check_partition_pug_seq(int id,
432         struct powergate_partition_info *pg_info)
433 {
434         int ret;
435
436         switch (id) {
437         case TEGRA_POWERGATE_DISB:
438         case TEGRA_POWERGATE_VENC:
439                 ret = tegra11x_unpowergate_partition_internal(TEGRA_POWERGATE_DISA,
440                         pg_info);
441                 if (ret < 0)
442                         return ret;
443
444                 break;
445         }
446         return 0;
447 }
448
449 int tegra11x_powergate_mc_enable(int id)
450 {
451         return 0;
452 }
453
454 int tegra11x_powergate_mc_disable(int id)
455 {
456         return 0;
457 }
458
459 int tegra11x_powergate_mc_flush(int id)
460 {
461         u32 idx, rst_ctrl, rst_stat;
462         enum mc_client mcClientBit;
463         unsigned long flags;
464         bool ret;
465
466         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
467                 mcClientBit =
468                         tegra11x_pg_mc_info[id].hot_reset_clients[idx];
469                 if (mcClientBit == MC_CLIENT_LAST)
470                         break;
471
472                 spin_lock_irqsave(&tegra11x_powergate_lock, flags);
473                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
474                 rst_ctrl |= (1 << mcClientBit);
475                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
476
477                 spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
478
479                 do {
480                         udelay(10);
481                         rst_stat = 0;
482                         ret = tegra11x_stable_hotreset_check(&rst_stat);
483                         if (!ret)
484                                 continue;
485                 } while (!(rst_stat & (1 << mcClientBit)));
486         }
487
488         return 0;
489 }
490
491 int tegra11x_powergate_mc_flush_done(int id)
492 {
493         u32 idx, rst_ctrl;
494         enum mc_client mcClientBit;
495         unsigned long flags;
496
497         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
498                 mcClientBit =
499                         tegra11x_pg_mc_info[id].hot_reset_clients[idx];
500                 if (mcClientBit == MC_CLIENT_LAST)
501                         break;
502
503                 spin_lock_irqsave(&tegra11x_powergate_lock, flags);
504
505                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
506                 rst_ctrl &= ~(1 << mcClientBit);
507                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
508
509                 spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
510         }
511
512         wmb();
513
514         return 0;
515 }
516
517 static int tegra11x_unpowergate(int id,
518         struct powergate_partition_info *pg_info)
519 {
520         int ret;
521
522         /* If first clk_ptr is null, fill clk info for the partition */
523         if (!pg_info->clk_info[0].clk_ptr)
524                 get_clk_info(pg_info);
525
526         if (tegra_powergate_is_powered(id))
527                 return tegra_powergate_reset_module(pg_info);
528
529         ret = tegra_powergate_set(id, true);
530         if (ret)
531                 goto err_power;
532
533         udelay(10);
534
535         powergate_partition_assert_reset(pg_info);
536
537         udelay(10);
538
539         /* Un-Powergating fails if all clks are not enabled */
540         ret = partition_clk_enable(pg_info);
541         if (ret)
542                 goto err_clk_on;
543
544         udelay(10);
545
546         ret = tegra_powergate_remove_clamping(id);
547         if (ret)
548                 goto err_clamp;
549
550         udelay(10);
551
552         tegra11x_mipical_calibrate(id);
553
554         powergate_partition_deassert_reset(pg_info);
555
556         udelay(10);
557
558         tegra_powergate_mc_flush_done(id);
559
560         udelay(10);
561
562         /* Disable all clks enabled earlier. Drivers should enable clks */
563         partition_clk_disable(pg_info);
564
565         return 0;
566
567 err_clamp:
568         partition_clk_disable(pg_info);
569 err_clk_on:
570         powergate_module(id);
571 err_power:
572         WARN(1, "Could not Un-Powergate %d", id);
573         return ret;
574 }
575
576 void tegra11x_powergate_dis_partition(void)
577 {
578         tegra1xx_powergate(TEGRA_POWERGATE_DISB,
579                 &tegra11x_powergate_partition_info[TEGRA_POWERGATE_DISB]);
580
581         tegra11x_powergate_partition_internal(TEGRA_POWERGATE_VENC,
582                 &tegra11x_powergate_partition_info[TEGRA_POWERGATE_DISA]);
583
584         tegra1xx_powergate(TEGRA_POWERGATE_DISA,
585                 &tegra11x_powergate_partition_info[TEGRA_POWERGATE_DISA]);
586 }
587
588 /* The logic manages the ref-count for dis partitions. The dependency between
589  * disa and disb is hided from client. */
590 bool tegra11x_powergate_check_dis_refcount(int id, int op)
591 {
592         WARN_ONCE(atomic_read(&ref_count_a) < 0, "dis ref a count underflow");
593         WARN_ONCE(atomic_read(&ref_count_b) < 0, "dis ref b count underflow");
594
595         if (op && id == TEGRA_POWERGATE_DISA) {
596                 if (atomic_inc_return(&ref_count_a) != 1)
597                         return 0;
598         } else if (op && id == TEGRA_POWERGATE_DISB) {
599                 if (tegra_powergate_is_powered(TEGRA_POWERGATE_DISA))
600                         atomic_inc(&ref_count_a);
601                 if (atomic_inc_return(&ref_count_b) != 1)
602                         return 0;
603         } else if (!op && id == TEGRA_POWERGATE_DISA) {
604                 if (atomic_dec_return(&ref_count_a) != 0)
605                         return 0;
606         } else if (!op && id == TEGRA_POWERGATE_DISB) {
607                 atomic_dec(&ref_count_a);
608                 if (atomic_dec_return(&ref_count_b) != 0) {
609                         return 0;
610                 } else if (atomic_read(&ref_count_a) == 0) {
611                         tegra11x_powergate_dis_partition();
612                         return 0;
613                 }
614         }
615
616         return 1;
617 }
618
619 int tegra11x_powergate_partition(int id)
620 {
621         int ret;
622
623         if ((id == TEGRA_POWERGATE_DISA || id == TEGRA_POWERGATE_DISB) &&
624                         !tegra11x_powergate_check_dis_refcount(id, 0))
625                 return 0;
626
627         ret = tegra11x_check_partition_pg_seq(id,
628                 &tegra11x_powergate_partition_info[id]);
629         if (ret)
630                 return ret;
631
632         /* call common power-gate API for t1xx */
633         ret = tegra1xx_powergate(id,
634                 &tegra11x_powergate_partition_info[id]);
635
636         return ret;
637 }
638
639 int tegra11x_unpowergate_partition(int id)
640 {
641         int ret;
642
643         if ((id == TEGRA_POWERGATE_DISA || id == TEGRA_POWERGATE_DISB) &&
644                         !tegra11x_powergate_check_dis_refcount(id, 1))
645                 return 0;
646
647         ret = tegra11x_check_partition_pug_seq(id,
648                 &tegra11x_powergate_partition_info[id]);
649         if (ret)
650                 return ret;
651
652         /* t11x needs to calibrate mipi in un-power-gate sequence
653          * hence it cannot use common un-power-gate api tegra1xx_unpowergate */
654         ret = tegra11x_unpowergate(id,
655                 &tegra11x_powergate_partition_info[id]);
656
657         return ret;
658 }
659
660 int tegra11x_powergate_partition_with_clk_off(int id)
661 {
662         return tegraxx_powergate_partition_with_clk_off(id,
663                 &tegra11x_powergate_partition_info[id]);
664 }
665
666 int tegra11x_unpowergate_partition_with_clk_on(int id)
667 {
668         return tegraxx_unpowergate_partition_with_clk_on(id,
669                 &tegra11x_powergate_partition_info[id]);
670 }
671
672 const char *tegra11x_get_powergate_domain_name(int id)
673 {
674         return tegra11x_powergate_partition_info[id].name;
675 }
676
677 spinlock_t *tegra11x_get_powergate_lock(void)
678 {
679         return &tegra11x_powergate_lock;
680 }
681
682 int tegra11x_powergate_init_refcount(void)
683 {
684         if (tegra_powergate_is_powered(TEGRA_POWERGATE_DISA))
685                         atomic_set(&ref_count_a, 1);
686         else
687                         atomic_set(&ref_count_a, 0);
688
689         if (tegra_powergate_is_powered(TEGRA_POWERGATE_DISB))
690                         atomic_set(&ref_count_b, 1);
691         else
692                         atomic_set(&ref_count_b, 0);
693         return 0;
694 }
695
696 static struct powergate_ops tegra11x_powergate_ops = {
697         .soc_name = "tegra11x",
698
699         .num_powerdomains = TEGRA_NUM_POWERGATE,
700
701         .get_powergate_lock = tegra11x_get_powergate_lock,
702         .get_powergate_domain_name = tegra11x_get_powergate_domain_name,
703
704         .powergate_partition = tegra11x_powergate_partition,
705         .unpowergate_partition = tegra11x_unpowergate_partition,
706
707         .powergate_partition_with_clk_off =  tegra11x_powergate_partition_with_clk_off,
708         .unpowergate_partition_with_clk_on = tegra11x_unpowergate_partition_with_clk_on,
709
710         .powergate_mc_enable = tegra11x_powergate_mc_enable,
711         .powergate_mc_disable = tegra11x_powergate_mc_disable,
712
713         .powergate_mc_flush = tegra11x_powergate_mc_flush,
714         .powergate_mc_flush_done = tegra11x_powergate_mc_flush_done,
715
716         .powergate_init_refcount = tegra11x_powergate_init_refcount,
717         .powergate_check_clamping = tegra11x_powergate_check_clamping,
718 };
719
720 struct powergate_ops *tegra11x_powergate_init_chip_support(void)
721 {
722         return &tegra11x_powergate_ops;
723 }