2 * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
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.
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.
15 #include <dt-bindings/clock/tegra210-car.h>
16 #include <linux/spinlock.h>
17 #include <linux/delay.h>
18 #include <linux/regulator/consumer.h>
19 #include <linux/tegra-powergate.h>
20 #include <linux/tegra-soc.h>
21 #include <linux/tegra_soctherm.h>
22 #include <soc/tegra/tegra-dvfs.h>
23 #include <trace/events/power.h>
25 #include "powergate-priv.h"
26 #include "powergate-ops-t1xx.h"
28 #define EMULATION_MC_FLUSH_TIMEOUT 100
42 MC_CLIENT_XUSB_HOST = 19,
43 MC_CLIENT_XUSB_DEV = 20,
46 MC_CLIENT_SDMMC1 = 29,
47 MC_CLIENT_SDMMC2 = 30,
48 MC_CLIENT_SDMMC3 = 31,
49 MC_CLIENT_SDMMC4 = 32,
60 struct tegra210_mc_client_info {
61 enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
64 static struct tegra210_mc_client_info tegra210_pg_mc_info[] = {
65 [TEGRA_POWERGATE_CRAIL] = {
66 .hot_reset_clients = {
70 [TEGRA_POWERGATE_VE] = {
71 .hot_reset_clients = {
77 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
78 [TEGRA_POWERGATE_PCIE] = {
79 .hot_reset_clients = {
85 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
86 [TEGRA_POWERGATE_SATA] = {
87 .hot_reset_clients = {
93 [TEGRA_POWERGATE_NVENC] = {
94 .hot_reset_clients = {
95 [0] = MC_CLIENT_NVENC,
99 [TEGRA_POWERGATE_SOR] = {
100 .hot_reset_clients = {
101 [0] = MC_CLIENT_LAST,
104 [TEGRA_POWERGATE_DISA] = {
105 .hot_reset_clients = {
107 [1] = MC_CLIENT_LAST,
110 [TEGRA_POWERGATE_DISB] = {
111 .hot_reset_clients = {
113 [1] = MC_CLIENT_LAST,
116 [TEGRA_POWERGATE_XUSBA] = {
117 .hot_reset_clients = {
118 [0] = MC_CLIENT_LAST,
121 [TEGRA_POWERGATE_XUSBB] = {
122 .hot_reset_clients = {
123 [0] = MC_CLIENT_XUSB_DEV,
124 [1] = MC_CLIENT_LAST,
127 [TEGRA_POWERGATE_XUSBC] = {
128 .hot_reset_clients = {
129 [0] = MC_CLIENT_XUSB_HOST,
130 [1] = MC_CLIENT_LAST,
133 #ifdef CONFIG_ARCH_TEGRA_VIC
134 [TEGRA_POWERGATE_VIC] = {
135 .hot_reset_clients = {
137 [1] = MC_CLIENT_LAST,
141 [TEGRA_POWERGATE_NVDEC] = {
142 .hot_reset_clients = {
143 [0] = MC_CLIENT_NVDEC,
144 [1] = MC_CLIENT_LAST,
147 [TEGRA_POWERGATE_NVJPG] = {
148 .hot_reset_clients = {
149 [0] = MC_CLIENT_NVJPG,
150 [1] = MC_CLIENT_LAST,
153 [TEGRA_POWERGATE_APE] = {
154 .hot_reset_clients = {
156 [1] = MC_CLIENT_LAST,
159 [TEGRA_POWERGATE_VE2] = {
160 .hot_reset_clients = {
161 [0] = MC_CLIENT_ISP2B,
162 [1] = MC_CLIENT_LAST,
165 [TEGRA_POWERGATE_GPU] = {
166 .hot_reset_clients = {
168 [1] = MC_CLIENT_LAST,
173 static struct powergate_partition_info tegra210_pg_partition_info[] = {
174 [TEGRA_POWERGATE_VE] = {
177 [0] = { .clk_name = "isp", .clk_type = CLK_ONLY },
178 [1] = { .clk_name = "vi", .clk_type = CLK_ONLY },
179 [2] = { .clk_name = "csi", .clk_type = CLK_ONLY },
180 [3] = { .clk_name = "vii2c", .clk_type = CLK_ONLY },
181 [4] = { .clk_name = "cilab", .clk_type = CLK_ONLY },
182 [5] = { .clk_name = "cilcd", .clk_type = CLK_ONLY },
183 [6] = { .clk_name = "cile", .clk_type = CLK_ONLY },
186 [0] = { .clk_name = "mc_capa" },
187 [1] = { .clk_name = "mc_cbpa" },
188 [2] = { .clk_name = "mc_ccpa" },
189 [3] = { .clk_name = "mc_cdpa" },
190 [4] = { .clk_name = "host1x" },
191 [5] = { .clk_name = "vi_slcg_ovr" },
192 [6] = { .clk_name = "ispa_slcg_ovr" },
194 .reset_id = { TEGRA210_CLK_ISP, TEGRA210_CLK_VI,
195 TEGRA210_CLK_CSI, TEGRA210_CLK_VI_I2C },
198 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
199 [TEGRA_POWERGATE_PCIE] = {
202 [0] = { .clk_name = "afi", .clk_type = CLK_ONLY },
203 [1] = { .clk_name = "pcie", .clk_type = CLK_ONLY },
205 .reset_id = { TEGRA210_CLK_AFI, TEGRA210_CLK_PCIE,
206 TEGRA210_CLK_PCIEX },
211 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
212 [TEGRA_POWERGATE_SATA] = {
214 .disable_after_boot = false,
216 [0] = { .clk_name = "sata_oob", .clk_type = CLK_ONLY },
217 [1] = { .clk_name = "cml1", .clk_type = CLK_ONLY },
218 [3] = { .clk_name = "sata_aux", .clk_type = CLK_ONLY },
219 [4] = { .clk_name = "sata", .clk_type = CLK_ONLY },
222 [0] = { .clk_name = "mc_capa" },
223 [1] = { .clk_name = "mc_cbpa" },
224 [2] = { .clk_name = "mc_ccpa" },
225 [3] = { .clk_name = "mc_cdpa" },
226 [4] = { .clk_name = "sata_slcg_fpci" },
227 [5] = { .clk_name = "sata_slcg_ipfs" },
228 [6] = { .clk_name = "sata_slcg_ovr" },
230 .reset_id = { TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_SATA_COLD,
235 [TEGRA_POWERGATE_NVENC] = {
238 [0] = { .clk_name = "nvenc.cbus", .clk_type = CLK_ONLY },
241 [0] = { .clk_name = "mc_capa" },
242 [1] = { .clk_name = "mc_cbpa" },
243 [2] = { .clk_name = "mc_ccpa" },
244 [3] = { .clk_name = "mc_cdpa" },
245 [4] = { .clk_name = "nvenc_slcg_ovr" },
247 .reset_id = { TEGRA210_CLK_NVENC },
250 [TEGRA_POWERGATE_SOR] = {
253 [0] = { .clk_name = "sor0", .clk_type = CLK_ONLY },
254 [1] = { .clk_name = "dsia", .clk_type = CLK_ONLY },
255 [2] = { .clk_name = "dsib", .clk_type = CLK_ONLY },
256 [3] = { .clk_name = "sor1", .clk_type = CLK_ONLY },
257 [4] = { .clk_name = "mipi-cal", .clk_type = CLK_ONLY },
258 [5] = { .clk_name = "dpaux", .clk_type = CLK_ONLY },
259 [6] = { .clk_name = "dpaux1", .clk_type = CLK_ONLY },
262 [0] = { .clk_name = "mc_capa" },
263 [1] = { .clk_name = "mc_cbpa" },
264 [2] = { .clk_name = "mc_ccpa" },
265 [3] = { .clk_name = "mc_cdpa" },
266 [4] = { .clk_name = "hda2hdmi" },
267 [5] = { .clk_name = "hda2codec_2x" },
268 [6] = { .clk_name = "disp1" },
269 [7] = { .clk_name = "disp2" },
270 [8] = { .clk_name = "disp1_slcg_ovr" },
271 [9] = { .clk_name = "disp2_slcg_ovr" },
273 .reset_id = { TEGRA210_CLK_SOR0, TEGRA210_CLK_DISP1,
274 TEGRA210_CLK_DSIB, TEGRA210_CLK_SOR1,
275 TEGRA210_CLK_MIPI_CAL },
278 [TEGRA_POWERGATE_DISA] = {
281 [0] = { .clk_name = "disp1", .clk_type = CLK_ONLY },
284 [0] = { .clk_name = "mc_capa" },
285 [1] = { .clk_name = "mc_cbpa" },
286 [2] = { .clk_name = "mc_ccpa" },
287 [3] = { .clk_name = "mc_cdpa" },
288 [4] = { .clk_name = "la" },
289 [5] = { .clk_name = "host1x" },
290 [6] = { .clk_name = "disp1_slcg_ovr" },
292 .reset_id = { TEGRA210_CLK_DISP1 },
295 [TEGRA_POWERGATE_DISB] = {
297 .disable_after_boot = true,
299 [0] = { .clk_name = "disp2", .clk_type = CLK_ONLY },
302 [0] = { .clk_name = "mc_capa" },
303 [1] = { .clk_name = "mc_cbpa" },
304 [2] = { .clk_name = "mc_ccpa" },
305 [3] = { .clk_name = "mc_cdpa" },
306 [4] = { .clk_name = "la" },
307 [5] = { .clk_name = "host1x" },
308 [6] = { .clk_name = "disp2_slcg_ovr" },
310 .reset_id = { TEGRA210_CLK_DISP2 },
313 [TEGRA_POWERGATE_XUSBA] = {
316 [0] = { .clk_name = "xusb_ss", .clk_type = CLK_ONLY },
317 [1] = { .clk_name = "xusb_ssp_src", .clk_type = CLK_ONLY },
318 [2] = { .clk_name = "xusb_hs_src", .clk_type = CLK_ONLY },
319 [3] = { .clk_name = "xusb_fs_src", .clk_type = CLK_ONLY },
320 [4] = { .clk_name = "xusb_dev_src", .clk_type = CLK_ONLY },
323 [0] = { .clk_name = "mc_capa" },
324 [1] = { .clk_name = "mc_cbpa" },
325 [2] = { .clk_name = "mc_ccpa" },
326 [3] = { .clk_name = "mc_cdpa" },
327 [4] = { .clk_name = "xusb_host" },
328 [5] = { .clk_name = "xusb_dev" },
329 [6] = { .clk_name = "xusb_host_slcg" },
330 [7] = { .clk_name = "xusb_dev_slcg" },
332 .reset_id = { TEGRA210_CLK_XUSB_SS },
335 [TEGRA_POWERGATE_XUSBB] = {
338 [0] = { .clk_name = "xusb_dev", .clk_type = CLK_ONLY },
341 [0] = { .clk_name = "mc_capa" },
342 [1] = { .clk_name = "mc_cbpa" },
343 [2] = { .clk_name = "mc_ccpa" },
344 [3] = { .clk_name = "mc_cdpa" },
345 [4] = { .clk_name = "xusb_ss" },
346 [5] = { .clk_name = "xusb_host" },
347 [6] = { .clk_name = "xusb_host_slcg" },
348 [7] = { .clk_name = "xusb_dev_slcg" },
353 [TEGRA_POWERGATE_XUSBC] = {
356 [0] = { .clk_name = "xusb_host", .clk_type = CLK_ONLY },
359 [0] = { .clk_name = "mc_capa" },
360 [1] = { .clk_name = "mc_cbpa" },
361 [2] = { .clk_name = "mc_ccpa" },
362 [3] = { .clk_name = "mc_cdpa" },
363 [4] = { .clk_name = "xusb_ss" },
364 [5] = { .clk_name = "xusb_dev" },
365 [6] = { .clk_name = "xusb_dev_slcg" },
366 [7] = { .clk_name = "xusb_host_slcg" },
368 .reset_id = { TEGRA210_CLK_XUSB_HOST },
371 #ifdef CONFIG_ARCH_TEGRA_VIC
372 [TEGRA_POWERGATE_VIC] = {
375 [0] = { .clk_name = "vic03.cbus", .clk_type = CLK_ONLY },
378 [0] = { .clk_name = "mc_capa" },
379 [1] = { .clk_name = "mc_cbpa" },
380 [2] = { .clk_name = "mc_ccpa" },
381 [3] = { .clk_name = "mc_cdpa" },
382 [4] = { .clk_name = "vic03_slcg_ovr" },
383 [5] = { .clk_name = "host1x" },
385 .reset_id = { TEGRA210_CLK_VIC03 },
389 [TEGRA_POWERGATE_NVDEC] = {
392 [0] = { .clk_name = "nvdec", .clk_type = CLK_ONLY },
395 [0] = { .clk_name = "mc_capa" },
396 [1] = { .clk_name = "mc_cbpa" },
397 [2] = { .clk_name = "mc_ccpa" },
398 [3] = { .clk_name = "mc_cdpa" },
399 [4] = { .clk_name = "nvdec_slcg_ovr" },
400 [5] = { .clk_name = "nvjpg" },
401 [6] = { .clk_name = "nvjpg_slcg_ovr" },
403 .reset_id = { TEGRA210_CLK_NVDEC },
406 [TEGRA_POWERGATE_NVJPG] = {
409 [0] = { .clk_name = "nvjpg", .clk_type = CLK_ONLY },
412 [0] = { .clk_name = "mc_capa" },
413 [1] = { .clk_name = "mc_cbpa" },
414 [2] = { .clk_name = "mc_ccpa" },
415 [3] = { .clk_name = "mc_cdpa" },
416 [4] = { .clk_name = "nvjpg_slcg_ovr" },
417 [5] = { .clk_name = "nvdec" },
418 [6] = { .clk_name = "nvdec_slcg_ovr" },
420 .reset_id = { TEGRA210_CLK_NVJPG },
423 [TEGRA_POWERGATE_APE] = {
426 [0] = { .clk_name = "ape", .clk_type = CLK_ONLY },
429 [0] = { .clk_name = "mc_capa" },
430 [1] = { .clk_name = "mc_cbpa" },
431 [2] = { .clk_name = "mc_ccpa" },
432 [3] = { .clk_name = "mc_cdpa" },
433 [4] = { .clk_name = "aclk" },
434 [5] = { .clk_name = "i2s0" },
435 [6] = { .clk_name = "i2s1" },
436 [7] = { .clk_name = "i2s2" },
437 [8] = { .clk_name = "i2s3" },
438 [9] = { .clk_name = "i2s4" },
439 [10] = { .clk_name = "spdif_out" },
440 [11] = { .clk_name = "d_audio" },
441 [12] = { .clk_name = "ape_slcg_ovr" },
442 [13] = { .clk_name = "aclk_slcg_ovr" },
443 [14] = { .clk_name = "daudio_slcg_ovr" },
446 .reset_id = { TEGRA210_CLK_APE },
449 [TEGRA_POWERGATE_VE2] = {
452 [0] = { .clk_name = "ispb", .clk_type = CLK_ONLY },
455 [0] = { .clk_name = "mc_capa" },
456 [1] = { .clk_name = "mc_cbpa" },
457 [2] = { .clk_name = "mc_ccpa" },
458 [3] = { .clk_name = "mc_cdpa" },
459 [4] = { .clk_name = "ispb_slcg_ovr" },
461 .reset_id = { TEGRA210_CLK_ISPB },
464 [TEGRA_POWERGATE_GPU] = {
467 [0] = { .clk_name = "gpu_gate", .clk_type = CLK_AND_RST },
468 [1] = { .clk_name = "gpu_ref", .clk_type = CLK_ONLY },
469 [2] = { .clk_name = "pll_p_out5", .clk_type = CLK_ONLY },
474 struct mc_client_hotreset_reg {
479 static struct mc_client_hotreset_reg tegra210_mc_reg[] = {
480 [0] = { .control_reg = 0x200, .status_reg = 0x204 },
481 [1] = { .control_reg = 0x970, .status_reg = 0x974 },
484 #define PMC_GPU_RG_CONTROL 0x2d4
486 static DEFINE_SPINLOCK(tegra210_pg_lock);
488 static struct dvfs_rail *gpu_rail;
490 #define HOTRESET_READ_COUNTS 5
492 static bool tegra210_pg_hotreset_check(u32 status_reg, u32 *status)
499 spin_lock_irqsave(&tegra210_pg_lock, flags);
500 prev_status = mc_read(status_reg);
501 for (i = 0; i < HOTRESET_READ_COUNTS; i++) {
502 curr_status = mc_read(status_reg);
503 if (curr_status != prev_status) {
504 spin_unlock_irqrestore(&tegra210_pg_lock, flags);
508 *status = curr_status;
509 spin_unlock_irqrestore(&tegra210_pg_lock, flags);
514 static int tegra210_pg_mc_flush(int id)
516 u32 idx, rst_control, rst_status;
517 u32 rst_control_reg, rst_status_reg;
518 enum mc_client mc_client_bit;
520 unsigned int timeout;
524 for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
525 mc_client_bit = tegra210_pg_mc_info[id].hot_reset_clients[idx];
526 if (mc_client_bit == MC_CLIENT_LAST)
529 reg_idx = mc_client_bit / 32;
531 rst_control_reg = tegra210_mc_reg[reg_idx].control_reg;
532 rst_status_reg = tegra210_mc_reg[reg_idx].status_reg;
534 spin_lock_irqsave(&tegra210_pg_lock, flags);
535 rst_control = mc_read(rst_control_reg);
536 rst_control |= (1 << mc_client_bit);
537 mc_write(rst_control, rst_control_reg);
538 spin_unlock_irqrestore(&tegra210_pg_lock, flags);
544 ret = tegra210_pg_hotreset_check(rst_status_reg,
546 if ((timeout++ > EMULATION_MC_FLUSH_TIMEOUT) &&
547 (tegra_platform_is_qt() ||
548 tegra_platform_is_fpga())) {
549 pr_warn("%s flush %d timeout\n", __func__, id);
554 } while (!(rst_status & (1 << mc_client_bit)));
560 static int tegra210_pg_mc_flush_done(int id)
562 u32 idx, rst_control, rst_control_reg;
563 enum mc_client mc_client_bit;
567 for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
568 mc_client_bit = tegra210_pg_mc_info[id].hot_reset_clients[idx];
569 if (mc_client_bit == MC_CLIENT_LAST)
572 reg_idx = mc_client_bit / 32;
574 rst_control_reg = tegra210_mc_reg[reg_idx].control_reg;
576 spin_lock_irqsave(&tegra210_pg_lock, flags);
577 rst_control = mc_read(rst_control_reg);
578 rst_control &= ~(1 << mc_client_bit);
579 mc_write(rst_control, rst_control_reg);
580 spin_unlock_irqrestore(&tegra210_pg_lock, flags);
588 static const char *tegra210_pg_get_name(int id)
590 return tegra210_pg_partition_info[id].name;
593 static int tegra210_pg_powergate(int id)
595 struct powergate_partition_info *partition =
596 &tegra210_pg_partition_info[id];
599 trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
600 mutex_lock(&partition->pg_mutex);
602 if (--partition->refcount > 0)
605 if ((partition->refcount < 0) || !tegra_powergate_is_powered(id)) {
606 WARN(1, "Partition %s already powergated, refcount and status mismatch\n",
611 ret = tegra1xx_powergate(id, partition);
614 mutex_unlock(&partition->pg_mutex);
615 trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
619 static int tegra210_pg_unpowergate(int id)
621 struct powergate_partition_info *partition =
622 &tegra210_pg_partition_info[id];
625 trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
626 mutex_lock(&partition->pg_mutex);
628 if (partition->refcount++ > 0)
631 if (tegra_powergate_is_powered(id)) {
632 WARN(1, "Partition %s is already unpowergated, refcount and status mismatch\n",
637 ret = tegra1xx_unpowergate(id, partition);
640 mutex_unlock(&partition->pg_mutex);
641 trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
645 static int tegra210_pg_gpu_powergate(int id)
648 struct powergate_partition_info *partition =
649 &tegra210_pg_partition_info[id];
651 trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
652 mutex_lock(&partition->pg_mutex);
654 if (--partition->refcount > 0)
657 if (!tegra_powergate_is_powered(id)) {
658 WARN(1, "GPU rail is already off, refcount and status mismatch\n");
662 if (!partition->clk_info[0].clk_ptr)
663 get_clk_info(partition);
665 tegra_powergate_mc_flush(id);
669 powergate_partition_assert_reset(partition);
673 pmc_write(0x1, PMC_GPU_RG_CONTROL);
674 pmc_read(PMC_GPU_RG_CONTROL);
678 partition_clk_disable(partition);
682 tegra_soctherm_gpu_tsens_invalidate(1);
685 ret = tegra_dvfs_rail_power_down(gpu_rail);
687 WARN(1, "Could not power down GPU rail\n");
691 pr_info("No GPU regulator?\n");
695 mutex_unlock(&partition->pg_mutex);
696 trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
700 static int tegra210_pg_gpu_unpowergate(int id)
704 struct powergate_partition_info *partition =
705 &tegra210_pg_partition_info[id];
707 trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
708 mutex_lock(&partition->pg_mutex);
710 if (partition->refcount++ > 0)
714 gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu");
715 if (IS_ERR_OR_NULL(gpu_rail)) {
716 WARN(1, "No GPU regulator?\n");
722 if (tegra_powergate_is_powered(id)) {
723 WARN(1, "GPU rail is already on, refcount and status mismatch\n");
727 ret = tegra_dvfs_rail_power_up(gpu_rail);
729 WARN(1, "Could not turn on GPU rail\n");
733 tegra_soctherm_gpu_tsens_invalidate(0);
735 if (!partition->clk_info[0].clk_ptr)
736 get_clk_info(partition);
739 ret = partition_clk_enable(partition);
741 WARN(1, "Could not turn on partition clocks\n");
748 powergate_partition_assert_reset(partition);
752 pmc_write(0, PMC_GPU_RG_CONTROL);
753 pmc_read(PMC_GPU_RG_CONTROL);
758 * Make sure all clok branches into GPU, except reference clock are
759 * gated across resert de-assertion.
761 clk_disable_unprepare(partition->clk_info[0].clk_ptr);
762 powergate_partition_deassert_reset(partition);
763 clk_prepare_enable(partition->clk_info[0].clk_ptr);
765 /* Flush MC after boot/railgate/SC7 */
766 tegra_powergate_mc_flush(id);
770 tegra_powergate_mc_flush_done(id);
775 mutex_unlock(&partition->pg_mutex);
776 trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
780 powergate_module(id);
782 mutex_unlock(&partition->pg_mutex);
784 trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
788 static int tegra210_pg_powergate_sor(int id)
792 ret = tegra210_pg_powergate(id);
796 ret = tegra_powergate_partition(TEGRA_POWERGATE_SOR);
803 static int tegra210_pg_unpowergate_sor(int id)
807 ret = tegra_unpowergate_partition(TEGRA_POWERGATE_SOR);
811 ret = tegra210_pg_unpowergate(id);
813 tegra_powergate_partition(TEGRA_POWERGATE_SOR);
820 static int tegra210_pg_nvdec_powergate(int id)
822 tegra210_pg_powergate(TEGRA_POWERGATE_NVDEC);
823 tegra_powergate_partition(TEGRA_POWERGATE_NVJPG);
828 static int tegra210_pg_nvdec_unpowergate(int id)
830 tegra_unpowergate_partition(TEGRA_POWERGATE_NVJPG);
831 tegra210_pg_unpowergate(TEGRA_POWERGATE_NVDEC);
836 static int tegra210_pg_sata_powergate(int id)
838 tegra210_set_sata_pll_seq_sw(true);
839 tegra210_pg_powergate(TEGRA_POWERGATE_SATA);
844 static int tegra210_pg_sata_unpowergate(int id)
846 tegra210_pg_unpowergate(TEGRA_POWERGATE_SATA);
847 tegra210_set_sata_pll_seq_sw(false);
852 static int tegra210_pg_powergate_partition(int id)
857 case TEGRA_POWERGATE_GPU:
858 ret = tegra210_pg_gpu_powergate(id);
860 case TEGRA_POWERGATE_DISA:
861 case TEGRA_POWERGATE_DISB:
862 case TEGRA_POWERGATE_VE:
863 ret = tegra210_pg_powergate_sor(id);
865 case TEGRA_POWERGATE_NVDEC:
866 ret = tegra210_pg_nvdec_powergate(id);
868 case TEGRA_POWERGATE_SATA:
869 ret = tegra210_pg_sata_powergate(id);
872 ret = tegra210_pg_powergate(id);
878 static int tegra210_pg_unpowergate_partition(int id)
883 case TEGRA_POWERGATE_GPU:
884 ret = tegra210_pg_gpu_unpowergate(id);
886 case TEGRA_POWERGATE_DISA:
887 case TEGRA_POWERGATE_DISB:
888 case TEGRA_POWERGATE_VE:
889 ret = tegra210_pg_unpowergate_sor(id);
891 case TEGRA_POWERGATE_NVDEC:
892 ret = tegra210_pg_nvdec_unpowergate(id);
894 case TEGRA_POWERGATE_SATA:
895 ret = tegra210_pg_sata_unpowergate(id);
898 ret = tegra210_pg_unpowergate(id);
904 static int tegra210_pg_powergate_clk_off(int id)
907 struct powergate_partition_info *partition =
908 &tegra210_pg_partition_info[id];
910 BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
912 trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
913 mutex_lock(&partition->pg_mutex);
915 if (--partition->refcount > 0)
918 if ((partition->refcount < 0) || !tegra_powergate_is_powered(id)) {
919 WARN(1, "Partition %s already powergated, refcount and status mismatch\n",
924 if (id == TEGRA_POWERGATE_SATA)
925 tegra210_set_sata_pll_seq_sw(true);
927 ret = tegra1xx_powergate_partition_with_clk_off(id,
928 &tegra210_pg_partition_info[id]);
931 mutex_unlock(&partition->pg_mutex);
932 trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
937 static int tegra210_pg_unpowergate_clk_on(int id)
940 struct powergate_partition_info *partition =
941 &tegra210_pg_partition_info[id];
943 BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
944 trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
945 mutex_lock(&partition->pg_mutex);
947 if (partition->refcount++ > 0)
950 ret = tegra1xx_unpowergate_partition_with_clk_on(id,
951 &tegra210_pg_partition_info[id]);
953 if (id == TEGRA_POWERGATE_SATA)
954 tegra210_set_sata_pll_seq_sw(false);
957 mutex_unlock(&partition->pg_mutex);
958 trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
963 static spinlock_t *tegra210_pg_get_lock(void)
965 return &tegra210_pg_lock;
968 static bool tegra210_pg_skip(int id)
971 case TEGRA_POWERGATE_GPU:
978 static bool tegra210_pg_is_powered(int id)
982 if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
984 status = tegra_dvfs_is_rail_up(gpu_rail);
986 status = pmc_read(PWRGATE_STATUS) & (1 << id);
992 static int tegra210_pg_init_refcount(void)
996 for (i = 0; i < TEGRA_NUM_POWERGATE; i++) {
997 if (tegra_powergate_is_powered(i))
998 tegra210_pg_partition_info[i].refcount = 1;
1000 tegra210_pg_partition_info[i].disable_after_boot = 0;
1002 mutex_init(&tegra210_pg_partition_info[i].pg_mutex);
1005 /* SOR refcount depends on other units */
1006 tegra210_pg_partition_info[TEGRA_POWERGATE_SOR].refcount =
1007 (tegra_powergate_is_powered(TEGRA_POWERGATE_DISA) ? 1 : 0) +
1008 (tegra_powergate_is_powered(TEGRA_POWERGATE_DISB) ? 1 : 0) +
1009 (tegra_powergate_is_powered(TEGRA_POWERGATE_VE) ? 1 : 0);
1011 tegra_powergate_partition(TEGRA_POWERGATE_XUSBA);
1012 tegra_powergate_partition(TEGRA_POWERGATE_XUSBB);
1013 tegra_powergate_partition(TEGRA_POWERGATE_XUSBC);
1018 static struct powergate_ops tegra210_pg_ops = {
1019 .soc_name = "tegra210",
1021 .num_powerdomains = TEGRA_NUM_POWERGATE,
1023 .get_powergate_lock = tegra210_pg_get_lock,
1024 .get_powergate_domain_name = tegra210_pg_get_name,
1026 .powergate_partition = tegra210_pg_powergate_partition,
1027 .unpowergate_partition = tegra210_pg_unpowergate_partition,
1029 .powergate_partition_with_clk_off = tegra210_pg_powergate_clk_off,
1030 .unpowergate_partition_with_clk_on = tegra210_pg_unpowergate_clk_on,
1032 .powergate_mc_flush = tegra210_pg_mc_flush,
1033 .powergate_mc_flush_done = tegra210_pg_mc_flush_done,
1035 .powergate_skip = tegra210_pg_skip,
1037 .powergate_is_powered = tegra210_pg_is_powered,
1039 .powergate_init_refcount = tegra210_pg_init_refcount,
1042 struct powergate_ops *tegra210_powergate_init_chip_support(void)
1044 if (tegra_platform_is_linsim())
1047 return &tegra210_pg_ops;
1050 int slcg_register_notifier(int id, struct notifier_block *nb)
1052 struct powergate_partition_info *pg_info = &tegra210_pg_partition_info[id];
1054 if (!pg_info || !nb)
1057 return raw_notifier_chain_register(&pg_info->slcg_notifier, nb);
1059 EXPORT_SYMBOL(slcg_register_notifier);
1061 int slcg_unregister_notifier(int id, struct notifier_block *nb)
1063 struct powergate_partition_info *pg_info =
1064 &tegra210_pg_partition_info[id];
1066 if (!pg_info || !nb)
1069 return raw_notifier_chain_unregister(&pg_info->slcg_notifier, nb);
1071 EXPORT_SYMBOL(slcg_unregister_notifier);
1073 static int __init tegra210_disable_boot_partitions(void)
1077 pr_info("Disable partitions left on by BL\n");
1078 for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
1079 if (tegra210_pg_partition_info[i].disable_after_boot &&
1080 (i != TEGRA_POWERGATE_GPU)) {
1081 pr_info(" %s\n", tegra210_pg_partition_info[i].name);
1082 tegra_powergate_partition(i);
1087 late_initcall(tegra210_disable_boot_partitions);