17232398abc6a7186e315425638c367d50c674718Thierry Reding/*
27232398abc6a7186e315425638c367d50c674718Thierry Reding * drivers/soc/tegra/pmc.c
37232398abc6a7186e315425638c367d50c674718Thierry Reding *
47232398abc6a7186e315425638c367d50c674718Thierry Reding * Copyright (c) 2010 Google, Inc
57232398abc6a7186e315425638c367d50c674718Thierry Reding *
67232398abc6a7186e315425638c367d50c674718Thierry Reding * Author:
77232398abc6a7186e315425638c367d50c674718Thierry Reding *	Colin Cross <ccross@google.com>
87232398abc6a7186e315425638c367d50c674718Thierry Reding *
97232398abc6a7186e315425638c367d50c674718Thierry Reding * This software is licensed under the terms of the GNU General Public
107232398abc6a7186e315425638c367d50c674718Thierry Reding * License version 2, as published by the Free Software Foundation, and
117232398abc6a7186e315425638c367d50c674718Thierry Reding * may be copied, distributed, and modified under those terms.
127232398abc6a7186e315425638c367d50c674718Thierry Reding *
137232398abc6a7186e315425638c367d50c674718Thierry Reding * This program is distributed in the hope that it will be useful,
147232398abc6a7186e315425638c367d50c674718Thierry Reding * but WITHOUT ANY WARRANTY; without even the implied warranty of
157232398abc6a7186e315425638c367d50c674718Thierry Reding * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
167232398abc6a7186e315425638c367d50c674718Thierry Reding * GNU General Public License for more details.
177232398abc6a7186e315425638c367d50c674718Thierry Reding *
187232398abc6a7186e315425638c367d50c674718Thierry Reding */
197232398abc6a7186e315425638c367d50c674718Thierry Reding
207232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/kernel.h>
217232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/clk.h>
227232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/clk/tegra.h>
237232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/debugfs.h>
247232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/delay.h>
257232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/err.h>
267232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/export.h>
277232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/init.h>
287232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/io.h>
297232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/of.h>
307232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/of_address.h>
317232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/platform_device.h>
327232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/reboot.h>
337232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/reset.h>
347232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/seq_file.h>
357232398abc6a7186e315425638c367d50c674718Thierry Reding#include <linux/spinlock.h>
367232398abc6a7186e315425638c367d50c674718Thierry Reding
377232398abc6a7186e315425638c367d50c674718Thierry Reding#include <soc/tegra/common.h>
387232398abc6a7186e315425638c367d50c674718Thierry Reding#include <soc/tegra/fuse.h>
397232398abc6a7186e315425638c367d50c674718Thierry Reding#include <soc/tegra/pmc.h>
407232398abc6a7186e315425638c367d50c674718Thierry Reding
417232398abc6a7186e315425638c367d50c674718Thierry Reding#define PMC_CNTRL			0x0
427232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_CNTRL_SYSCLK_POLARITY	(1 << 10)  /* sys clk polarity */
437232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_CNTRL_SYSCLK_OE		(1 << 11)  /* system clock enable */
447232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_CNTRL_SIDE_EFFECT_LP0	(1 << 14)  /* LP0 when CPU pwr gated */
457232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_CNTRL_CPU_PWRREQ_POLARITY	(1 << 15)  /* CPU pwr req polarity */
467232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_CNTRL_CPU_PWRREQ_OE	(1 << 16)  /* CPU pwr req enable */
477232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_CNTRL_INTR_POLARITY	(1 << 17)  /* inverts INTR polarity */
487232398abc6a7186e315425638c367d50c674718Thierry Reding
497232398abc6a7186e315425638c367d50c674718Thierry Reding#define DPD_SAMPLE			0x020
507232398abc6a7186e315425638c367d50c674718Thierry Reding#define  DPD_SAMPLE_ENABLE		(1 << 0)
517232398abc6a7186e315425638c367d50c674718Thierry Reding#define  DPD_SAMPLE_DISABLE		(0 << 0)
527232398abc6a7186e315425638c367d50c674718Thierry Reding
537232398abc6a7186e315425638c367d50c674718Thierry Reding#define PWRGATE_TOGGLE			0x30
547232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PWRGATE_TOGGLE_START		(1 << 8)
557232398abc6a7186e315425638c367d50c674718Thierry Reding
567232398abc6a7186e315425638c367d50c674718Thierry Reding#define REMOVE_CLAMPING			0x34
577232398abc6a7186e315425638c367d50c674718Thierry Reding
587232398abc6a7186e315425638c367d50c674718Thierry Reding#define PWRGATE_STATUS			0x38
597232398abc6a7186e315425638c367d50c674718Thierry Reding
607232398abc6a7186e315425638c367d50c674718Thierry Reding#define PMC_SCRATCH0			0x50
617232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_SCRATCH0_MODE_RECOVERY	(1 << 31)
627232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_SCRATCH0_MODE_BOOTLOADER	(1 << 30)
637232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_SCRATCH0_MODE_RCM		(1 << 1)
647232398abc6a7186e315425638c367d50c674718Thierry Reding#define  PMC_SCRATCH0_MODE_MASK		(PMC_SCRATCH0_MODE_RECOVERY | \
657232398abc6a7186e315425638c367d50c674718Thierry Reding					 PMC_SCRATCH0_MODE_BOOTLOADER | \
667232398abc6a7186e315425638c367d50c674718Thierry Reding					 PMC_SCRATCH0_MODE_RCM)
677232398abc6a7186e315425638c367d50c674718Thierry Reding
687232398abc6a7186e315425638c367d50c674718Thierry Reding#define PMC_CPUPWRGOOD_TIMER		0xc8
697232398abc6a7186e315425638c367d50c674718Thierry Reding#define PMC_CPUPWROFF_TIMER		0xcc
707232398abc6a7186e315425638c367d50c674718Thierry Reding
717232398abc6a7186e315425638c367d50c674718Thierry Reding#define PMC_SCRATCH41			0x140
727232398abc6a7186e315425638c367d50c674718Thierry Reding
737232398abc6a7186e315425638c367d50c674718Thierry Reding#define IO_DPD_REQ			0x1b8
747232398abc6a7186e315425638c367d50c674718Thierry Reding#define  IO_DPD_REQ_CODE_IDLE		(0 << 30)
757232398abc6a7186e315425638c367d50c674718Thierry Reding#define  IO_DPD_REQ_CODE_OFF		(1 << 30)
767232398abc6a7186e315425638c367d50c674718Thierry Reding#define  IO_DPD_REQ_CODE_ON		(2 << 30)
777232398abc6a7186e315425638c367d50c674718Thierry Reding#define  IO_DPD_REQ_CODE_MASK		(3 << 30)
787232398abc6a7186e315425638c367d50c674718Thierry Reding
797232398abc6a7186e315425638c367d50c674718Thierry Reding#define IO_DPD_STATUS			0x1bc
807232398abc6a7186e315425638c367d50c674718Thierry Reding#define IO_DPD2_REQ			0x1c0
817232398abc6a7186e315425638c367d50c674718Thierry Reding#define IO_DPD2_STATUS			0x1c4
827232398abc6a7186e315425638c367d50c674718Thierry Reding#define SEL_DPD_TIM			0x1c8
837232398abc6a7186e315425638c367d50c674718Thierry Reding
847232398abc6a7186e315425638c367d50c674718Thierry Reding#define GPU_RG_CNTRL			0x2d4
857232398abc6a7186e315425638c367d50c674718Thierry Reding
867232398abc6a7186e315425638c367d50c674718Thierry Redingstruct tegra_pmc_soc {
877232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned int num_powergates;
887232398abc6a7186e315425638c367d50c674718Thierry Reding	const char *const *powergates;
897232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned int num_cpu_powergates;
907232398abc6a7186e315425638c367d50c674718Thierry Reding	const u8 *cpu_powergates;
917232398abc6a7186e315425638c367d50c674718Thierry Reding};
927232398abc6a7186e315425638c367d50c674718Thierry Reding
937232398abc6a7186e315425638c367d50c674718Thierry Reding/**
947232398abc6a7186e315425638c367d50c674718Thierry Reding * struct tegra_pmc - NVIDIA Tegra PMC
957232398abc6a7186e315425638c367d50c674718Thierry Reding * @base: pointer to I/O remapped register region
967232398abc6a7186e315425638c367d50c674718Thierry Reding * @clk: pointer to pclk clock
977232398abc6a7186e315425638c367d50c674718Thierry Reding * @rate: currently configured rate of pclk
987232398abc6a7186e315425638c367d50c674718Thierry Reding * @suspend_mode: lowest suspend mode available
997232398abc6a7186e315425638c367d50c674718Thierry Reding * @cpu_good_time: CPU power good time (in microseconds)
1007232398abc6a7186e315425638c367d50c674718Thierry Reding * @cpu_off_time: CPU power off time (in microsecends)
1017232398abc6a7186e315425638c367d50c674718Thierry Reding * @core_osc_time: core power good OSC time (in microseconds)
1027232398abc6a7186e315425638c367d50c674718Thierry Reding * @core_pmu_time: core power good PMU time (in microseconds)
1037232398abc6a7186e315425638c367d50c674718Thierry Reding * @core_off_time: core power off time (in microseconds)
1047232398abc6a7186e315425638c367d50c674718Thierry Reding * @corereq_high: core power request is active-high
1057232398abc6a7186e315425638c367d50c674718Thierry Reding * @sysclkreq_high: system clock request is active-high
1067232398abc6a7186e315425638c367d50c674718Thierry Reding * @combined_req: combined power request for CPU & core
1077232398abc6a7186e315425638c367d50c674718Thierry Reding * @cpu_pwr_good_en: CPU power good signal is enabled
1087232398abc6a7186e315425638c367d50c674718Thierry Reding * @lp0_vec_phys: physical base address of the LP0 warm boot code
1097232398abc6a7186e315425638c367d50c674718Thierry Reding * @lp0_vec_size: size of the LP0 warm boot code
1107232398abc6a7186e315425638c367d50c674718Thierry Reding * @powergates_lock: mutex for power gate register access
1117232398abc6a7186e315425638c367d50c674718Thierry Reding */
1127232398abc6a7186e315425638c367d50c674718Thierry Redingstruct tegra_pmc {
1137232398abc6a7186e315425638c367d50c674718Thierry Reding	void __iomem *base;
1147232398abc6a7186e315425638c367d50c674718Thierry Reding	struct clk *clk;
1157232398abc6a7186e315425638c367d50c674718Thierry Reding
1167232398abc6a7186e315425638c367d50c674718Thierry Reding	const struct tegra_pmc_soc *soc;
1177232398abc6a7186e315425638c367d50c674718Thierry Reding
1187232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned long rate;
1197232398abc6a7186e315425638c367d50c674718Thierry Reding
1207232398abc6a7186e315425638c367d50c674718Thierry Reding	enum tegra_suspend_mode suspend_mode;
1217232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 cpu_good_time;
1227232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 cpu_off_time;
1237232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 core_osc_time;
1247232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 core_pmu_time;
1257232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 core_off_time;
1267232398abc6a7186e315425638c367d50c674718Thierry Reding	bool corereq_high;
1277232398abc6a7186e315425638c367d50c674718Thierry Reding	bool sysclkreq_high;
1287232398abc6a7186e315425638c367d50c674718Thierry Reding	bool combined_req;
1297232398abc6a7186e315425638c367d50c674718Thierry Reding	bool cpu_pwr_good_en;
1307232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 lp0_vec_phys;
1317232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 lp0_vec_size;
1327232398abc6a7186e315425638c367d50c674718Thierry Reding
1337232398abc6a7186e315425638c367d50c674718Thierry Reding	struct mutex powergates_lock;
1347232398abc6a7186e315425638c367d50c674718Thierry Reding};
1357232398abc6a7186e315425638c367d50c674718Thierry Reding
1367232398abc6a7186e315425638c367d50c674718Thierry Redingstatic struct tegra_pmc *pmc = &(struct tegra_pmc) {
1377232398abc6a7186e315425638c367d50c674718Thierry Reding	.base = NULL,
1387232398abc6a7186e315425638c367d50c674718Thierry Reding	.suspend_mode = TEGRA_SUSPEND_NONE,
1397232398abc6a7186e315425638c367d50c674718Thierry Reding};
1407232398abc6a7186e315425638c367d50c674718Thierry Reding
1417232398abc6a7186e315425638c367d50c674718Thierry Redingstatic u32 tegra_pmc_readl(unsigned long offset)
1427232398abc6a7186e315425638c367d50c674718Thierry Reding{
1437232398abc6a7186e315425638c367d50c674718Thierry Reding	return readl(pmc->base + offset);
1447232398abc6a7186e315425638c367d50c674718Thierry Reding}
1457232398abc6a7186e315425638c367d50c674718Thierry Reding
1467232398abc6a7186e315425638c367d50c674718Thierry Redingstatic void tegra_pmc_writel(u32 value, unsigned long offset)
1477232398abc6a7186e315425638c367d50c674718Thierry Reding{
1487232398abc6a7186e315425638c367d50c674718Thierry Reding	writel(value, pmc->base + offset);
1497232398abc6a7186e315425638c367d50c674718Thierry Reding}
1507232398abc6a7186e315425638c367d50c674718Thierry Reding
1517232398abc6a7186e315425638c367d50c674718Thierry Reding/**
1527232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_powergate_set() - set the state of a partition
1537232398abc6a7186e315425638c367d50c674718Thierry Reding * @id: partition ID
1547232398abc6a7186e315425638c367d50c674718Thierry Reding * @new_state: new state of the partition
1557232398abc6a7186e315425638c367d50c674718Thierry Reding */
1567232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_powergate_set(int id, bool new_state)
1577232398abc6a7186e315425638c367d50c674718Thierry Reding{
1587232398abc6a7186e315425638c367d50c674718Thierry Reding	bool status;
1597232398abc6a7186e315425638c367d50c674718Thierry Reding
1607232398abc6a7186e315425638c367d50c674718Thierry Reding	mutex_lock(&pmc->powergates_lock);
1617232398abc6a7186e315425638c367d50c674718Thierry Reding
1627232398abc6a7186e315425638c367d50c674718Thierry Reding	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
1637232398abc6a7186e315425638c367d50c674718Thierry Reding
1647232398abc6a7186e315425638c367d50c674718Thierry Reding	if (status == new_state) {
1657232398abc6a7186e315425638c367d50c674718Thierry Reding		mutex_unlock(&pmc->powergates_lock);
1667232398abc6a7186e315425638c367d50c674718Thierry Reding		return 0;
1677232398abc6a7186e315425638c367d50c674718Thierry Reding	}
1687232398abc6a7186e315425638c367d50c674718Thierry Reding
1697232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
1707232398abc6a7186e315425638c367d50c674718Thierry Reding
1717232398abc6a7186e315425638c367d50c674718Thierry Reding	mutex_unlock(&pmc->powergates_lock);
1727232398abc6a7186e315425638c367d50c674718Thierry Reding
1737232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
1747232398abc6a7186e315425638c367d50c674718Thierry Reding}
1757232398abc6a7186e315425638c367d50c674718Thierry Reding
1767232398abc6a7186e315425638c367d50c674718Thierry Reding/**
1777232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_powergate_power_on() - power on partition
1787232398abc6a7186e315425638c367d50c674718Thierry Reding * @id: partition ID
1797232398abc6a7186e315425638c367d50c674718Thierry Reding */
1807232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_powergate_power_on(int id)
1817232398abc6a7186e315425638c367d50c674718Thierry Reding{
1827232398abc6a7186e315425638c367d50c674718Thierry Reding	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
1837232398abc6a7186e315425638c367d50c674718Thierry Reding		return -EINVAL;
1847232398abc6a7186e315425638c367d50c674718Thierry Reding
1857232398abc6a7186e315425638c367d50c674718Thierry Reding	return tegra_powergate_set(id, true);
1867232398abc6a7186e315425638c367d50c674718Thierry Reding}
1877232398abc6a7186e315425638c367d50c674718Thierry Reding
1887232398abc6a7186e315425638c367d50c674718Thierry Reding/**
1897232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_powergate_power_off() - power off partition
1907232398abc6a7186e315425638c367d50c674718Thierry Reding * @id: partition ID
1917232398abc6a7186e315425638c367d50c674718Thierry Reding */
1927232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_powergate_power_off(int id)
1937232398abc6a7186e315425638c367d50c674718Thierry Reding{
1947232398abc6a7186e315425638c367d50c674718Thierry Reding	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
1957232398abc6a7186e315425638c367d50c674718Thierry Reding		return -EINVAL;
1967232398abc6a7186e315425638c367d50c674718Thierry Reding
1977232398abc6a7186e315425638c367d50c674718Thierry Reding	return tegra_powergate_set(id, false);
1987232398abc6a7186e315425638c367d50c674718Thierry Reding}
1997232398abc6a7186e315425638c367d50c674718Thierry RedingEXPORT_SYMBOL(tegra_powergate_power_off);
2007232398abc6a7186e315425638c367d50c674718Thierry Reding
2017232398abc6a7186e315425638c367d50c674718Thierry Reding/**
2027232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_powergate_is_powered() - check if partition is powered
2037232398abc6a7186e315425638c367d50c674718Thierry Reding * @id: partition ID
2047232398abc6a7186e315425638c367d50c674718Thierry Reding */
2057232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_powergate_is_powered(int id)
2067232398abc6a7186e315425638c367d50c674718Thierry Reding{
2077232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 status;
2087232398abc6a7186e315425638c367d50c674718Thierry Reding
2097232398abc6a7186e315425638c367d50c674718Thierry Reding	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
2107232398abc6a7186e315425638c367d50c674718Thierry Reding		return -EINVAL;
2117232398abc6a7186e315425638c367d50c674718Thierry Reding
2127232398abc6a7186e315425638c367d50c674718Thierry Reding	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
2137232398abc6a7186e315425638c367d50c674718Thierry Reding	return !!status;
2147232398abc6a7186e315425638c367d50c674718Thierry Reding}
2157232398abc6a7186e315425638c367d50c674718Thierry Reding
2167232398abc6a7186e315425638c367d50c674718Thierry Reding/**
2177232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_powergate_remove_clamping() - remove power clamps for partition
2187232398abc6a7186e315425638c367d50c674718Thierry Reding * @id: partition ID
2197232398abc6a7186e315425638c367d50c674718Thierry Reding */
2207232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_powergate_remove_clamping(int id)
2217232398abc6a7186e315425638c367d50c674718Thierry Reding{
2227232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 mask;
2237232398abc6a7186e315425638c367d50c674718Thierry Reding
2247232398abc6a7186e315425638c367d50c674718Thierry Reding	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
2257232398abc6a7186e315425638c367d50c674718Thierry Reding		return -EINVAL;
2267232398abc6a7186e315425638c367d50c674718Thierry Reding
2277232398abc6a7186e315425638c367d50c674718Thierry Reding	/*
2287232398abc6a7186e315425638c367d50c674718Thierry Reding	 * The Tegra124 GPU has a separate register (with different semantics)
2297232398abc6a7186e315425638c367d50c674718Thierry Reding	 * to remove clamps.
2307232398abc6a7186e315425638c367d50c674718Thierry Reding	 */
2317232398abc6a7186e315425638c367d50c674718Thierry Reding	if (tegra_get_chip_id() == TEGRA124) {
2327232398abc6a7186e315425638c367d50c674718Thierry Reding		if (id == TEGRA_POWERGATE_3D) {
2337232398abc6a7186e315425638c367d50c674718Thierry Reding			tegra_pmc_writel(0, GPU_RG_CNTRL);
2347232398abc6a7186e315425638c367d50c674718Thierry Reding			return 0;
2357232398abc6a7186e315425638c367d50c674718Thierry Reding		}
2367232398abc6a7186e315425638c367d50c674718Thierry Reding	}
2377232398abc6a7186e315425638c367d50c674718Thierry Reding
2387232398abc6a7186e315425638c367d50c674718Thierry Reding	/*
2397232398abc6a7186e315425638c367d50c674718Thierry Reding	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
2407232398abc6a7186e315425638c367d50c674718Thierry Reding	 * swapped relatively to the partition ids
2417232398abc6a7186e315425638c367d50c674718Thierry Reding	 */
2427232398abc6a7186e315425638c367d50c674718Thierry Reding	if (id == TEGRA_POWERGATE_VDEC)
2437232398abc6a7186e315425638c367d50c674718Thierry Reding		mask = (1 << TEGRA_POWERGATE_PCIE);
2447232398abc6a7186e315425638c367d50c674718Thierry Reding	else if (id == TEGRA_POWERGATE_PCIE)
2457232398abc6a7186e315425638c367d50c674718Thierry Reding		mask = (1 << TEGRA_POWERGATE_VDEC);
2467232398abc6a7186e315425638c367d50c674718Thierry Reding	else
2477232398abc6a7186e315425638c367d50c674718Thierry Reding		mask = (1 << id);
2487232398abc6a7186e315425638c367d50c674718Thierry Reding
2497232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(mask, REMOVE_CLAMPING);
2507232398abc6a7186e315425638c367d50c674718Thierry Reding
2517232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
2527232398abc6a7186e315425638c367d50c674718Thierry Reding}
2537232398abc6a7186e315425638c367d50c674718Thierry RedingEXPORT_SYMBOL(tegra_powergate_remove_clamping);
2547232398abc6a7186e315425638c367d50c674718Thierry Reding
2557232398abc6a7186e315425638c367d50c674718Thierry Reding/**
2567232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_powergate_sequence_power_up() - power up partition
2577232398abc6a7186e315425638c367d50c674718Thierry Reding * @id: partition ID
2587232398abc6a7186e315425638c367d50c674718Thierry Reding * @clk: clock for partition
2597232398abc6a7186e315425638c367d50c674718Thierry Reding * @rst: reset for partition
2607232398abc6a7186e315425638c367d50c674718Thierry Reding *
2617232398abc6a7186e315425638c367d50c674718Thierry Reding * Must be called with clk disabled, and returns with clk enabled.
2627232398abc6a7186e315425638c367d50c674718Thierry Reding */
2637232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_powergate_sequence_power_up(int id, struct clk *clk,
2647232398abc6a7186e315425638c367d50c674718Thierry Reding				      struct reset_control *rst)
2657232398abc6a7186e315425638c367d50c674718Thierry Reding{
2667232398abc6a7186e315425638c367d50c674718Thierry Reding	int ret;
2677232398abc6a7186e315425638c367d50c674718Thierry Reding
2687232398abc6a7186e315425638c367d50c674718Thierry Reding	reset_control_assert(rst);
2697232398abc6a7186e315425638c367d50c674718Thierry Reding
2707232398abc6a7186e315425638c367d50c674718Thierry Reding	ret = tegra_powergate_power_on(id);
2717232398abc6a7186e315425638c367d50c674718Thierry Reding	if (ret)
2727232398abc6a7186e315425638c367d50c674718Thierry Reding		goto err_power;
2737232398abc6a7186e315425638c367d50c674718Thierry Reding
2747232398abc6a7186e315425638c367d50c674718Thierry Reding	ret = clk_prepare_enable(clk);
2757232398abc6a7186e315425638c367d50c674718Thierry Reding	if (ret)
2767232398abc6a7186e315425638c367d50c674718Thierry Reding		goto err_clk;
2777232398abc6a7186e315425638c367d50c674718Thierry Reding
2787232398abc6a7186e315425638c367d50c674718Thierry Reding	usleep_range(10, 20);
2797232398abc6a7186e315425638c367d50c674718Thierry Reding
2807232398abc6a7186e315425638c367d50c674718Thierry Reding	ret = tegra_powergate_remove_clamping(id);
2817232398abc6a7186e315425638c367d50c674718Thierry Reding	if (ret)
2827232398abc6a7186e315425638c367d50c674718Thierry Reding		goto err_clamp;
2837232398abc6a7186e315425638c367d50c674718Thierry Reding
2847232398abc6a7186e315425638c367d50c674718Thierry Reding	usleep_range(10, 20);
2857232398abc6a7186e315425638c367d50c674718Thierry Reding	reset_control_deassert(rst);
2867232398abc6a7186e315425638c367d50c674718Thierry Reding
2877232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
2887232398abc6a7186e315425638c367d50c674718Thierry Reding
2897232398abc6a7186e315425638c367d50c674718Thierry Redingerr_clamp:
2907232398abc6a7186e315425638c367d50c674718Thierry Reding	clk_disable_unprepare(clk);
2917232398abc6a7186e315425638c367d50c674718Thierry Redingerr_clk:
2927232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_powergate_power_off(id);
2937232398abc6a7186e315425638c367d50c674718Thierry Redingerr_power:
2947232398abc6a7186e315425638c367d50c674718Thierry Reding	return ret;
2957232398abc6a7186e315425638c367d50c674718Thierry Reding}
2967232398abc6a7186e315425638c367d50c674718Thierry RedingEXPORT_SYMBOL(tegra_powergate_sequence_power_up);
2977232398abc6a7186e315425638c367d50c674718Thierry Reding
2987232398abc6a7186e315425638c367d50c674718Thierry Reding#ifdef CONFIG_SMP
2997232398abc6a7186e315425638c367d50c674718Thierry Reding/**
3007232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
3017232398abc6a7186e315425638c367d50c674718Thierry Reding * @cpuid: CPU partition ID
3027232398abc6a7186e315425638c367d50c674718Thierry Reding *
3037232398abc6a7186e315425638c367d50c674718Thierry Reding * Returns the partition ID corresponding to the CPU partition ID or a
3047232398abc6a7186e315425638c367d50c674718Thierry Reding * negative error code on failure.
3057232398abc6a7186e315425638c367d50c674718Thierry Reding */
3067232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_get_cpu_powergate_id(int cpuid)
3077232398abc6a7186e315425638c367d50c674718Thierry Reding{
3087232398abc6a7186e315425638c367d50c674718Thierry Reding	if (pmc->soc && cpuid > 0 && cpuid < pmc->soc->num_cpu_powergates)
3097232398abc6a7186e315425638c367d50c674718Thierry Reding		return pmc->soc->cpu_powergates[cpuid];
3107232398abc6a7186e315425638c367d50c674718Thierry Reding
3117232398abc6a7186e315425638c367d50c674718Thierry Reding	return -EINVAL;
3127232398abc6a7186e315425638c367d50c674718Thierry Reding}
3137232398abc6a7186e315425638c367d50c674718Thierry Reding
3147232398abc6a7186e315425638c367d50c674718Thierry Reding/**
3157232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
3167232398abc6a7186e315425638c367d50c674718Thierry Reding * @cpuid: CPU partition ID
3177232398abc6a7186e315425638c367d50c674718Thierry Reding */
3187232398abc6a7186e315425638c367d50c674718Thierry Redingbool tegra_pmc_cpu_is_powered(int cpuid)
3197232398abc6a7186e315425638c367d50c674718Thierry Reding{
3207232398abc6a7186e315425638c367d50c674718Thierry Reding	int id;
3217232398abc6a7186e315425638c367d50c674718Thierry Reding
3227232398abc6a7186e315425638c367d50c674718Thierry Reding	id = tegra_get_cpu_powergate_id(cpuid);
3237232398abc6a7186e315425638c367d50c674718Thierry Reding	if (id < 0)
3247232398abc6a7186e315425638c367d50c674718Thierry Reding		return false;
3257232398abc6a7186e315425638c367d50c674718Thierry Reding
3267232398abc6a7186e315425638c367d50c674718Thierry Reding	return tegra_powergate_is_powered(id);
3277232398abc6a7186e315425638c367d50c674718Thierry Reding}
3287232398abc6a7186e315425638c367d50c674718Thierry Reding
3297232398abc6a7186e315425638c367d50c674718Thierry Reding/**
3307232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_pmc_cpu_power_on() - power on CPU partition
3317232398abc6a7186e315425638c367d50c674718Thierry Reding * @cpuid: CPU partition ID
3327232398abc6a7186e315425638c367d50c674718Thierry Reding */
3337232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_pmc_cpu_power_on(int cpuid)
3347232398abc6a7186e315425638c367d50c674718Thierry Reding{
3357232398abc6a7186e315425638c367d50c674718Thierry Reding	int id;
3367232398abc6a7186e315425638c367d50c674718Thierry Reding
3377232398abc6a7186e315425638c367d50c674718Thierry Reding	id = tegra_get_cpu_powergate_id(cpuid);
3387232398abc6a7186e315425638c367d50c674718Thierry Reding	if (id < 0)
3397232398abc6a7186e315425638c367d50c674718Thierry Reding		return id;
3407232398abc6a7186e315425638c367d50c674718Thierry Reding
3417232398abc6a7186e315425638c367d50c674718Thierry Reding	return tegra_powergate_set(id, true);
3427232398abc6a7186e315425638c367d50c674718Thierry Reding}
3437232398abc6a7186e315425638c367d50c674718Thierry Reding
3447232398abc6a7186e315425638c367d50c674718Thierry Reding/**
3457232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
3467232398abc6a7186e315425638c367d50c674718Thierry Reding * @cpuid: CPU partition ID
3477232398abc6a7186e315425638c367d50c674718Thierry Reding */
3487232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_pmc_cpu_remove_clamping(int cpuid)
3497232398abc6a7186e315425638c367d50c674718Thierry Reding{
3507232398abc6a7186e315425638c367d50c674718Thierry Reding	int id;
3517232398abc6a7186e315425638c367d50c674718Thierry Reding
3527232398abc6a7186e315425638c367d50c674718Thierry Reding	id = tegra_get_cpu_powergate_id(cpuid);
3537232398abc6a7186e315425638c367d50c674718Thierry Reding	if (id < 0)
3547232398abc6a7186e315425638c367d50c674718Thierry Reding		return id;
3557232398abc6a7186e315425638c367d50c674718Thierry Reding
3567232398abc6a7186e315425638c367d50c674718Thierry Reding	return tegra_powergate_remove_clamping(id);
3577232398abc6a7186e315425638c367d50c674718Thierry Reding}
3587232398abc6a7186e315425638c367d50c674718Thierry Reding#endif /* CONFIG_SMP */
3597232398abc6a7186e315425638c367d50c674718Thierry Reding
3607232398abc6a7186e315425638c367d50c674718Thierry Reding/**
3617232398abc6a7186e315425638c367d50c674718Thierry Reding * tegra_pmc_restart() - reboot the system
3627232398abc6a7186e315425638c367d50c674718Thierry Reding * @mode: which mode to reboot in
3637232398abc6a7186e315425638c367d50c674718Thierry Reding * @cmd: reboot command
3647232398abc6a7186e315425638c367d50c674718Thierry Reding */
3657232398abc6a7186e315425638c367d50c674718Thierry Redingvoid tegra_pmc_restart(enum reboot_mode mode, const char *cmd)
3667232398abc6a7186e315425638c367d50c674718Thierry Reding{
3677232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 value;
3687232398abc6a7186e315425638c367d50c674718Thierry Reding
3697232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(PMC_SCRATCH0);
3707232398abc6a7186e315425638c367d50c674718Thierry Reding	value &= ~PMC_SCRATCH0_MODE_MASK;
3717232398abc6a7186e315425638c367d50c674718Thierry Reding
3727232398abc6a7186e315425638c367d50c674718Thierry Reding	if (cmd) {
3737232398abc6a7186e315425638c367d50c674718Thierry Reding		if (strcmp(cmd, "recovery") == 0)
3747232398abc6a7186e315425638c367d50c674718Thierry Reding			value |= PMC_SCRATCH0_MODE_RECOVERY;
3757232398abc6a7186e315425638c367d50c674718Thierry Reding
3767232398abc6a7186e315425638c367d50c674718Thierry Reding		if (strcmp(cmd, "bootloader") == 0)
3777232398abc6a7186e315425638c367d50c674718Thierry Reding			value |= PMC_SCRATCH0_MODE_BOOTLOADER;
3787232398abc6a7186e315425638c367d50c674718Thierry Reding
3797232398abc6a7186e315425638c367d50c674718Thierry Reding		if (strcmp(cmd, "forced-recovery") == 0)
3807232398abc6a7186e315425638c367d50c674718Thierry Reding			value |= PMC_SCRATCH0_MODE_RCM;
3817232398abc6a7186e315425638c367d50c674718Thierry Reding	}
3827232398abc6a7186e315425638c367d50c674718Thierry Reding
3837232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, PMC_SCRATCH0);
3847232398abc6a7186e315425638c367d50c674718Thierry Reding
3857232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(0);
3867232398abc6a7186e315425638c367d50c674718Thierry Reding	value |= 0x10;
3877232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, 0);
3887232398abc6a7186e315425638c367d50c674718Thierry Reding}
3897232398abc6a7186e315425638c367d50c674718Thierry Reding
3907232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int powergate_show(struct seq_file *s, void *data)
3917232398abc6a7186e315425638c367d50c674718Thierry Reding{
3927232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned int i;
3937232398abc6a7186e315425638c367d50c674718Thierry Reding
3947232398abc6a7186e315425638c367d50c674718Thierry Reding	seq_printf(s, " powergate powered\n");
3957232398abc6a7186e315425638c367d50c674718Thierry Reding	seq_printf(s, "------------------\n");
3967232398abc6a7186e315425638c367d50c674718Thierry Reding
3977232398abc6a7186e315425638c367d50c674718Thierry Reding	for (i = 0; i < pmc->soc->num_powergates; i++) {
3987232398abc6a7186e315425638c367d50c674718Thierry Reding		if (!pmc->soc->powergates[i])
3997232398abc6a7186e315425638c367d50c674718Thierry Reding			continue;
4007232398abc6a7186e315425638c367d50c674718Thierry Reding
4017232398abc6a7186e315425638c367d50c674718Thierry Reding		seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i],
4027232398abc6a7186e315425638c367d50c674718Thierry Reding			   tegra_powergate_is_powered(i) ? "yes" : "no");
4037232398abc6a7186e315425638c367d50c674718Thierry Reding	}
4047232398abc6a7186e315425638c367d50c674718Thierry Reding
4057232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
4067232398abc6a7186e315425638c367d50c674718Thierry Reding}
4077232398abc6a7186e315425638c367d50c674718Thierry Reding
4087232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int powergate_open(struct inode *inode, struct file *file)
4097232398abc6a7186e315425638c367d50c674718Thierry Reding{
4107232398abc6a7186e315425638c367d50c674718Thierry Reding	return single_open(file, powergate_show, inode->i_private);
4117232398abc6a7186e315425638c367d50c674718Thierry Reding}
4127232398abc6a7186e315425638c367d50c674718Thierry Reding
4137232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const struct file_operations powergate_fops = {
4147232398abc6a7186e315425638c367d50c674718Thierry Reding	.open = powergate_open,
4157232398abc6a7186e315425638c367d50c674718Thierry Reding	.read = seq_read,
4167232398abc6a7186e315425638c367d50c674718Thierry Reding	.llseek = seq_lseek,
4177232398abc6a7186e315425638c367d50c674718Thierry Reding	.release = single_release,
4187232398abc6a7186e315425638c367d50c674718Thierry Reding};
4197232398abc6a7186e315425638c367d50c674718Thierry Reding
4207232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_powergate_debugfs_init(void)
4217232398abc6a7186e315425638c367d50c674718Thierry Reding{
4227232398abc6a7186e315425638c367d50c674718Thierry Reding	struct dentry *d;
4237232398abc6a7186e315425638c367d50c674718Thierry Reding
4247232398abc6a7186e315425638c367d50c674718Thierry Reding	d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
4257232398abc6a7186e315425638c367d50c674718Thierry Reding				&powergate_fops);
4267232398abc6a7186e315425638c367d50c674718Thierry Reding	if (!d)
4277232398abc6a7186e315425638c367d50c674718Thierry Reding		return -ENOMEM;
4287232398abc6a7186e315425638c367d50c674718Thierry Reding
4297232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
4307232398abc6a7186e315425638c367d50c674718Thierry Reding}
4317232398abc6a7186e315425638c367d50c674718Thierry Reding
4327232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_io_rail_prepare(int id, unsigned long *request,
4337232398abc6a7186e315425638c367d50c674718Thierry Reding				 unsigned long *status, unsigned int *bit)
4347232398abc6a7186e315425638c367d50c674718Thierry Reding{
4357232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned long rate, value;
4367232398abc6a7186e315425638c367d50c674718Thierry Reding	struct clk *clk;
4377232398abc6a7186e315425638c367d50c674718Thierry Reding
4387232398abc6a7186e315425638c367d50c674718Thierry Reding	*bit = id % 32;
4397232398abc6a7186e315425638c367d50c674718Thierry Reding
4407232398abc6a7186e315425638c367d50c674718Thierry Reding	/*
4417232398abc6a7186e315425638c367d50c674718Thierry Reding	 * There are two sets of 30 bits to select IO rails, but bits 30 and
4427232398abc6a7186e315425638c367d50c674718Thierry Reding	 * 31 are control bits rather than IO rail selection bits.
4437232398abc6a7186e315425638c367d50c674718Thierry Reding	 */
4447232398abc6a7186e315425638c367d50c674718Thierry Reding	if (id > 63 || *bit == 30 || *bit == 31)
4457232398abc6a7186e315425638c367d50c674718Thierry Reding		return -EINVAL;
4467232398abc6a7186e315425638c367d50c674718Thierry Reding
4477232398abc6a7186e315425638c367d50c674718Thierry Reding	if (id < 32) {
4487232398abc6a7186e315425638c367d50c674718Thierry Reding		*status = IO_DPD_STATUS;
4497232398abc6a7186e315425638c367d50c674718Thierry Reding		*request = IO_DPD_REQ;
4507232398abc6a7186e315425638c367d50c674718Thierry Reding	} else {
4517232398abc6a7186e315425638c367d50c674718Thierry Reding		*status = IO_DPD2_STATUS;
4527232398abc6a7186e315425638c367d50c674718Thierry Reding		*request = IO_DPD2_REQ;
4537232398abc6a7186e315425638c367d50c674718Thierry Reding	}
4547232398abc6a7186e315425638c367d50c674718Thierry Reding
4557232398abc6a7186e315425638c367d50c674718Thierry Reding	clk = clk_get_sys(NULL, "pclk");
4567232398abc6a7186e315425638c367d50c674718Thierry Reding	if (IS_ERR(clk))
4577232398abc6a7186e315425638c367d50c674718Thierry Reding		return PTR_ERR(clk);
4587232398abc6a7186e315425638c367d50c674718Thierry Reding
4597232398abc6a7186e315425638c367d50c674718Thierry Reding	rate = clk_get_rate(clk);
4607232398abc6a7186e315425638c367d50c674718Thierry Reding	clk_put(clk);
4617232398abc6a7186e315425638c367d50c674718Thierry Reding
4627232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE);
4637232398abc6a7186e315425638c367d50c674718Thierry Reding
4647232398abc6a7186e315425638c367d50c674718Thierry Reding	/* must be at least 200 ns, in APB (PCLK) clock cycles */
4657232398abc6a7186e315425638c367d50c674718Thierry Reding	value = DIV_ROUND_UP(1000000000, rate);
4667232398abc6a7186e315425638c367d50c674718Thierry Reding	value = DIV_ROUND_UP(200, value);
4677232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, SEL_DPD_TIM);
4687232398abc6a7186e315425638c367d50c674718Thierry Reding
4697232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
4707232398abc6a7186e315425638c367d50c674718Thierry Reding}
4717232398abc6a7186e315425638c367d50c674718Thierry Reding
4727232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
4737232398abc6a7186e315425638c367d50c674718Thierry Reding			      unsigned long val, unsigned long timeout)
4747232398abc6a7186e315425638c367d50c674718Thierry Reding{
4757232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned long value;
4767232398abc6a7186e315425638c367d50c674718Thierry Reding
4777232398abc6a7186e315425638c367d50c674718Thierry Reding	timeout = jiffies + msecs_to_jiffies(timeout);
4787232398abc6a7186e315425638c367d50c674718Thierry Reding
4797232398abc6a7186e315425638c367d50c674718Thierry Reding	while (time_after(timeout, jiffies)) {
4807232398abc6a7186e315425638c367d50c674718Thierry Reding		value = tegra_pmc_readl(offset);
4817232398abc6a7186e315425638c367d50c674718Thierry Reding		if ((value & mask) == val)
4827232398abc6a7186e315425638c367d50c674718Thierry Reding			return 0;
4837232398abc6a7186e315425638c367d50c674718Thierry Reding
4847232398abc6a7186e315425638c367d50c674718Thierry Reding		usleep_range(250, 1000);
4857232398abc6a7186e315425638c367d50c674718Thierry Reding	}
4867232398abc6a7186e315425638c367d50c674718Thierry Reding
4877232398abc6a7186e315425638c367d50c674718Thierry Reding	return -ETIMEDOUT;
4887232398abc6a7186e315425638c367d50c674718Thierry Reding}
4897232398abc6a7186e315425638c367d50c674718Thierry Reding
4907232398abc6a7186e315425638c367d50c674718Thierry Redingstatic void tegra_io_rail_unprepare(void)
4917232398abc6a7186e315425638c367d50c674718Thierry Reding{
4927232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
4937232398abc6a7186e315425638c367d50c674718Thierry Reding}
4947232398abc6a7186e315425638c367d50c674718Thierry Reding
4957232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_io_rail_power_on(int id)
4967232398abc6a7186e315425638c367d50c674718Thierry Reding{
4977232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned long request, status, value;
4987232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned int bit, mask;
4997232398abc6a7186e315425638c367d50c674718Thierry Reding	int err;
5007232398abc6a7186e315425638c367d50c674718Thierry Reding
5017232398abc6a7186e315425638c367d50c674718Thierry Reding	err = tegra_io_rail_prepare(id, &request, &status, &bit);
5027232398abc6a7186e315425638c367d50c674718Thierry Reding	if (err < 0)
5037232398abc6a7186e315425638c367d50c674718Thierry Reding		return err;
5047232398abc6a7186e315425638c367d50c674718Thierry Reding
5057232398abc6a7186e315425638c367d50c674718Thierry Reding	mask = 1 << bit;
5067232398abc6a7186e315425638c367d50c674718Thierry Reding
5077232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(request);
5087232398abc6a7186e315425638c367d50c674718Thierry Reding	value |= mask;
5097232398abc6a7186e315425638c367d50c674718Thierry Reding	value &= ~IO_DPD_REQ_CODE_MASK;
5107232398abc6a7186e315425638c367d50c674718Thierry Reding	value |= IO_DPD_REQ_CODE_OFF;
5117232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, request);
5127232398abc6a7186e315425638c367d50c674718Thierry Reding
5137232398abc6a7186e315425638c367d50c674718Thierry Reding	err = tegra_io_rail_poll(status, mask, 0, 250);
5147232398abc6a7186e315425638c367d50c674718Thierry Reding	if (err < 0)
5157232398abc6a7186e315425638c367d50c674718Thierry Reding		return err;
5167232398abc6a7186e315425638c367d50c674718Thierry Reding
5177232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_io_rail_unprepare();
5187232398abc6a7186e315425638c367d50c674718Thierry Reding
5197232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
5207232398abc6a7186e315425638c367d50c674718Thierry Reding}
5217232398abc6a7186e315425638c367d50c674718Thierry RedingEXPORT_SYMBOL(tegra_io_rail_power_on);
5227232398abc6a7186e315425638c367d50c674718Thierry Reding
5237232398abc6a7186e315425638c367d50c674718Thierry Redingint tegra_io_rail_power_off(int id)
5247232398abc6a7186e315425638c367d50c674718Thierry Reding{
5257232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned long request, status, value;
5267232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned int bit, mask;
5277232398abc6a7186e315425638c367d50c674718Thierry Reding	int err;
5287232398abc6a7186e315425638c367d50c674718Thierry Reding
5297232398abc6a7186e315425638c367d50c674718Thierry Reding	err = tegra_io_rail_prepare(id, &request, &status, &bit);
5307232398abc6a7186e315425638c367d50c674718Thierry Reding	if (err < 0)
5317232398abc6a7186e315425638c367d50c674718Thierry Reding		return err;
5327232398abc6a7186e315425638c367d50c674718Thierry Reding
5337232398abc6a7186e315425638c367d50c674718Thierry Reding	mask = 1 << bit;
5347232398abc6a7186e315425638c367d50c674718Thierry Reding
5357232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(request);
5367232398abc6a7186e315425638c367d50c674718Thierry Reding	value |= mask;
5377232398abc6a7186e315425638c367d50c674718Thierry Reding	value &= ~IO_DPD_REQ_CODE_MASK;
5387232398abc6a7186e315425638c367d50c674718Thierry Reding	value |= IO_DPD_REQ_CODE_ON;
5397232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, request);
5407232398abc6a7186e315425638c367d50c674718Thierry Reding
5417232398abc6a7186e315425638c367d50c674718Thierry Reding	err = tegra_io_rail_poll(status, mask, mask, 250);
5427232398abc6a7186e315425638c367d50c674718Thierry Reding	if (err < 0)
5437232398abc6a7186e315425638c367d50c674718Thierry Reding		return err;
5447232398abc6a7186e315425638c367d50c674718Thierry Reding
5457232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_io_rail_unprepare();
5467232398abc6a7186e315425638c367d50c674718Thierry Reding
5477232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
5487232398abc6a7186e315425638c367d50c674718Thierry Reding}
5497232398abc6a7186e315425638c367d50c674718Thierry RedingEXPORT_SYMBOL(tegra_io_rail_power_off);
5507232398abc6a7186e315425638c367d50c674718Thierry Reding
5517232398abc6a7186e315425638c367d50c674718Thierry Reding#ifdef CONFIG_PM_SLEEP
5527232398abc6a7186e315425638c367d50c674718Thierry Redingenum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
5537232398abc6a7186e315425638c367d50c674718Thierry Reding{
5547232398abc6a7186e315425638c367d50c674718Thierry Reding	return pmc->suspend_mode;
5557232398abc6a7186e315425638c367d50c674718Thierry Reding}
5567232398abc6a7186e315425638c367d50c674718Thierry Reding
5577232398abc6a7186e315425638c367d50c674718Thierry Redingvoid tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
5587232398abc6a7186e315425638c367d50c674718Thierry Reding{
5597232398abc6a7186e315425638c367d50c674718Thierry Reding	if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
5607232398abc6a7186e315425638c367d50c674718Thierry Reding		return;
5617232398abc6a7186e315425638c367d50c674718Thierry Reding
5627232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->suspend_mode = mode;
5637232398abc6a7186e315425638c367d50c674718Thierry Reding}
5647232398abc6a7186e315425638c367d50c674718Thierry Reding
5657232398abc6a7186e315425638c367d50c674718Thierry Redingvoid tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
5667232398abc6a7186e315425638c367d50c674718Thierry Reding{
5677232398abc6a7186e315425638c367d50c674718Thierry Reding	unsigned long long rate = 0;
5687232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 value;
5697232398abc6a7186e315425638c367d50c674718Thierry Reding
5707232398abc6a7186e315425638c367d50c674718Thierry Reding	switch (mode) {
5717232398abc6a7186e315425638c367d50c674718Thierry Reding	case TEGRA_SUSPEND_LP1:
5727232398abc6a7186e315425638c367d50c674718Thierry Reding		rate = 32768;
5737232398abc6a7186e315425638c367d50c674718Thierry Reding		break;
5747232398abc6a7186e315425638c367d50c674718Thierry Reding
5757232398abc6a7186e315425638c367d50c674718Thierry Reding	case TEGRA_SUSPEND_LP2:
5767232398abc6a7186e315425638c367d50c674718Thierry Reding		rate = clk_get_rate(pmc->clk);
5777232398abc6a7186e315425638c367d50c674718Thierry Reding		break;
5787232398abc6a7186e315425638c367d50c674718Thierry Reding
5797232398abc6a7186e315425638c367d50c674718Thierry Reding	default:
5807232398abc6a7186e315425638c367d50c674718Thierry Reding		break;
5817232398abc6a7186e315425638c367d50c674718Thierry Reding	}
5827232398abc6a7186e315425638c367d50c674718Thierry Reding
5837232398abc6a7186e315425638c367d50c674718Thierry Reding	if (WARN_ON_ONCE(rate == 0))
5847232398abc6a7186e315425638c367d50c674718Thierry Reding		rate = 100000000;
5857232398abc6a7186e315425638c367d50c674718Thierry Reding
5867232398abc6a7186e315425638c367d50c674718Thierry Reding	if (rate != pmc->rate) {
5877232398abc6a7186e315425638c367d50c674718Thierry Reding		u64 ticks;
5887232398abc6a7186e315425638c367d50c674718Thierry Reding
5897232398abc6a7186e315425638c367d50c674718Thierry Reding		ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
5907232398abc6a7186e315425638c367d50c674718Thierry Reding		do_div(ticks, USEC_PER_SEC);
5917232398abc6a7186e315425638c367d50c674718Thierry Reding		tegra_pmc_writel(ticks, PMC_CPUPWRGOOD_TIMER);
5927232398abc6a7186e315425638c367d50c674718Thierry Reding
5937232398abc6a7186e315425638c367d50c674718Thierry Reding		ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
5947232398abc6a7186e315425638c367d50c674718Thierry Reding		do_div(ticks, USEC_PER_SEC);
5957232398abc6a7186e315425638c367d50c674718Thierry Reding		tegra_pmc_writel(ticks, PMC_CPUPWROFF_TIMER);
5967232398abc6a7186e315425638c367d50c674718Thierry Reding
5977232398abc6a7186e315425638c367d50c674718Thierry Reding		wmb();
5987232398abc6a7186e315425638c367d50c674718Thierry Reding
5997232398abc6a7186e315425638c367d50c674718Thierry Reding		pmc->rate = rate;
6007232398abc6a7186e315425638c367d50c674718Thierry Reding	}
6017232398abc6a7186e315425638c367d50c674718Thierry Reding
6027232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(PMC_CNTRL);
6037232398abc6a7186e315425638c367d50c674718Thierry Reding	value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
6047232398abc6a7186e315425638c367d50c674718Thierry Reding	value |= PMC_CNTRL_CPU_PWRREQ_OE;
6057232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, PMC_CNTRL);
6067232398abc6a7186e315425638c367d50c674718Thierry Reding}
6077232398abc6a7186e315425638c367d50c674718Thierry Reding#endif
6087232398abc6a7186e315425638c367d50c674718Thierry Reding
6097232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
6107232398abc6a7186e315425638c367d50c674718Thierry Reding{
6117232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 value, values[2];
6127232398abc6a7186e315425638c367d50c674718Thierry Reding
6137232398abc6a7186e315425638c367d50c674718Thierry Reding	if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) {
6147232398abc6a7186e315425638c367d50c674718Thierry Reding	} else {
6157232398abc6a7186e315425638c367d50c674718Thierry Reding		switch (value) {
6167232398abc6a7186e315425638c367d50c674718Thierry Reding		case 0:
6177232398abc6a7186e315425638c367d50c674718Thierry Reding			pmc->suspend_mode = TEGRA_SUSPEND_LP0;
6187232398abc6a7186e315425638c367d50c674718Thierry Reding			break;
6197232398abc6a7186e315425638c367d50c674718Thierry Reding
6207232398abc6a7186e315425638c367d50c674718Thierry Reding		case 1:
6217232398abc6a7186e315425638c367d50c674718Thierry Reding			pmc->suspend_mode = TEGRA_SUSPEND_LP1;
6227232398abc6a7186e315425638c367d50c674718Thierry Reding			break;
6237232398abc6a7186e315425638c367d50c674718Thierry Reding
6247232398abc6a7186e315425638c367d50c674718Thierry Reding		case 2:
6257232398abc6a7186e315425638c367d50c674718Thierry Reding			pmc->suspend_mode = TEGRA_SUSPEND_LP2;
6267232398abc6a7186e315425638c367d50c674718Thierry Reding			break;
6277232398abc6a7186e315425638c367d50c674718Thierry Reding
6287232398abc6a7186e315425638c367d50c674718Thierry Reding		default:
6297232398abc6a7186e315425638c367d50c674718Thierry Reding			pmc->suspend_mode = TEGRA_SUSPEND_NONE;
6307232398abc6a7186e315425638c367d50c674718Thierry Reding			break;
6317232398abc6a7186e315425638c367d50c674718Thierry Reding		}
6327232398abc6a7186e315425638c367d50c674718Thierry Reding	}
6337232398abc6a7186e315425638c367d50c674718Thierry Reding
6347232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->suspend_mode = tegra_pm_validate_suspend_mode(pmc->suspend_mode);
6357232398abc6a7186e315425638c367d50c674718Thierry Reding
6367232398abc6a7186e315425638c367d50c674718Thierry Reding	if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &value))
6377232398abc6a7186e315425638c367d50c674718Thierry Reding		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
6387232398abc6a7186e315425638c367d50c674718Thierry Reding
6397232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->cpu_good_time = value;
6407232398abc6a7186e315425638c367d50c674718Thierry Reding
6417232398abc6a7186e315425638c367d50c674718Thierry Reding	if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &value))
6427232398abc6a7186e315425638c367d50c674718Thierry Reding		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
6437232398abc6a7186e315425638c367d50c674718Thierry Reding
6447232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->cpu_off_time = value;
6457232398abc6a7186e315425638c367d50c674718Thierry Reding
6467232398abc6a7186e315425638c367d50c674718Thierry Reding	if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time",
6477232398abc6a7186e315425638c367d50c674718Thierry Reding				       values, ARRAY_SIZE(values)))
6487232398abc6a7186e315425638c367d50c674718Thierry Reding		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
6497232398abc6a7186e315425638c367d50c674718Thierry Reding
6507232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->core_osc_time = values[0];
6517232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->core_pmu_time = values[1];
6527232398abc6a7186e315425638c367d50c674718Thierry Reding
6537232398abc6a7186e315425638c367d50c674718Thierry Reding	if (of_property_read_u32(np, "nvidia,core-pwr-off-time", &value))
6547232398abc6a7186e315425638c367d50c674718Thierry Reding		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
6557232398abc6a7186e315425638c367d50c674718Thierry Reding
6567232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->core_off_time = value;
6577232398abc6a7186e315425638c367d50c674718Thierry Reding
6587232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->corereq_high = of_property_read_bool(np,
6597232398abc6a7186e315425638c367d50c674718Thierry Reding				"nvidia,core-power-req-active-high");
6607232398abc6a7186e315425638c367d50c674718Thierry Reding
6617232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->sysclkreq_high = of_property_read_bool(np,
6627232398abc6a7186e315425638c367d50c674718Thierry Reding				"nvidia,sys-clock-req-active-high");
6637232398abc6a7186e315425638c367d50c674718Thierry Reding
6647232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->combined_req = of_property_read_bool(np,
6657232398abc6a7186e315425638c367d50c674718Thierry Reding				"nvidia,combined-power-req");
6667232398abc6a7186e315425638c367d50c674718Thierry Reding
6677232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->cpu_pwr_good_en = of_property_read_bool(np,
6687232398abc6a7186e315425638c367d50c674718Thierry Reding				"nvidia,cpu-pwr-good-en");
6697232398abc6a7186e315425638c367d50c674718Thierry Reding
6707232398abc6a7186e315425638c367d50c674718Thierry Reding	if (of_property_read_u32_array(np, "nvidia,lp0-vec", values,
6717232398abc6a7186e315425638c367d50c674718Thierry Reding				       ARRAY_SIZE(values)))
6727232398abc6a7186e315425638c367d50c674718Thierry Reding		if (pmc->suspend_mode == TEGRA_SUSPEND_LP0)
6737232398abc6a7186e315425638c367d50c674718Thierry Reding			pmc->suspend_mode = TEGRA_SUSPEND_LP1;
6747232398abc6a7186e315425638c367d50c674718Thierry Reding
6757232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->lp0_vec_phys = values[0];
6767232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->lp0_vec_size = values[1];
6777232398abc6a7186e315425638c367d50c674718Thierry Reding
6787232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
6797232398abc6a7186e315425638c367d50c674718Thierry Reding}
6807232398abc6a7186e315425638c367d50c674718Thierry Reding
6817232398abc6a7186e315425638c367d50c674718Thierry Redingstatic void tegra_pmc_init(struct tegra_pmc *pmc)
6827232398abc6a7186e315425638c367d50c674718Thierry Reding{
6837232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 value;
6847232398abc6a7186e315425638c367d50c674718Thierry Reding
6857232398abc6a7186e315425638c367d50c674718Thierry Reding	/* Always enable CPU power request */
6867232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(PMC_CNTRL);
6877232398abc6a7186e315425638c367d50c674718Thierry Reding	value |= PMC_CNTRL_CPU_PWRREQ_OE;
6887232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, PMC_CNTRL);
6897232398abc6a7186e315425638c367d50c674718Thierry Reding
6907232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(PMC_CNTRL);
6917232398abc6a7186e315425638c367d50c674718Thierry Reding
6927232398abc6a7186e315425638c367d50c674718Thierry Reding	if (pmc->sysclkreq_high)
6937232398abc6a7186e315425638c367d50c674718Thierry Reding		value &= ~PMC_CNTRL_SYSCLK_POLARITY;
6947232398abc6a7186e315425638c367d50c674718Thierry Reding	else
6957232398abc6a7186e315425638c367d50c674718Thierry Reding		value |= PMC_CNTRL_SYSCLK_POLARITY;
6967232398abc6a7186e315425638c367d50c674718Thierry Reding
6977232398abc6a7186e315425638c367d50c674718Thierry Reding	/* configure the output polarity while the request is tristated */
6987232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, PMC_CNTRL);
6997232398abc6a7186e315425638c367d50c674718Thierry Reding
7007232398abc6a7186e315425638c367d50c674718Thierry Reding	/* now enable the request */
7017232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(PMC_CNTRL);
7027232398abc6a7186e315425638c367d50c674718Thierry Reding	value |= PMC_CNTRL_SYSCLK_OE;
7037232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, PMC_CNTRL);
7047232398abc6a7186e315425638c367d50c674718Thierry Reding}
7057232398abc6a7186e315425638c367d50c674718Thierry Reding
7067232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_pmc_probe(struct platform_device *pdev)
7077232398abc6a7186e315425638c367d50c674718Thierry Reding{
7087232398abc6a7186e315425638c367d50c674718Thierry Reding	void __iomem *base = pmc->base;
7097232398abc6a7186e315425638c367d50c674718Thierry Reding	struct resource *res;
7107232398abc6a7186e315425638c367d50c674718Thierry Reding	int err;
7117232398abc6a7186e315425638c367d50c674718Thierry Reding
7127232398abc6a7186e315425638c367d50c674718Thierry Reding	err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node);
7137232398abc6a7186e315425638c367d50c674718Thierry Reding	if (err < 0)
7147232398abc6a7186e315425638c367d50c674718Thierry Reding		return err;
7157232398abc6a7186e315425638c367d50c674718Thierry Reding
7167232398abc6a7186e315425638c367d50c674718Thierry Reding	/* take over the memory region from the early initialization */
7177232398abc6a7186e315425638c367d50c674718Thierry Reding	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
7187232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->base = devm_ioremap_resource(&pdev->dev, res);
7197232398abc6a7186e315425638c367d50c674718Thierry Reding	if (IS_ERR(pmc->base))
7207232398abc6a7186e315425638c367d50c674718Thierry Reding		return PTR_ERR(pmc->base);
7217232398abc6a7186e315425638c367d50c674718Thierry Reding
7227232398abc6a7186e315425638c367d50c674718Thierry Reding	iounmap(base);
7237232398abc6a7186e315425638c367d50c674718Thierry Reding
7247232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->clk = devm_clk_get(&pdev->dev, "pclk");
7257232398abc6a7186e315425638c367d50c674718Thierry Reding	if (IS_ERR(pmc->clk)) {
7267232398abc6a7186e315425638c367d50c674718Thierry Reding		err = PTR_ERR(pmc->clk);
7277232398abc6a7186e315425638c367d50c674718Thierry Reding		dev_err(&pdev->dev, "failed to get pclk: %d\n", err);
7287232398abc6a7186e315425638c367d50c674718Thierry Reding		return err;
7297232398abc6a7186e315425638c367d50c674718Thierry Reding	}
7307232398abc6a7186e315425638c367d50c674718Thierry Reding
7317232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_init(pmc);
7327232398abc6a7186e315425638c367d50c674718Thierry Reding
7337232398abc6a7186e315425638c367d50c674718Thierry Reding	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
7347232398abc6a7186e315425638c367d50c674718Thierry Reding		err = tegra_powergate_debugfs_init();
7357232398abc6a7186e315425638c367d50c674718Thierry Reding		if (err < 0)
7367232398abc6a7186e315425638c367d50c674718Thierry Reding			return err;
7377232398abc6a7186e315425638c367d50c674718Thierry Reding	}
7387232398abc6a7186e315425638c367d50c674718Thierry Reding
7397232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
7407232398abc6a7186e315425638c367d50c674718Thierry Reding}
7417232398abc6a7186e315425638c367d50c674718Thierry Reding
7427232398abc6a7186e315425638c367d50c674718Thierry Reding#ifdef CONFIG_PM_SLEEP
7437232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_pmc_suspend(struct device *dev)
7447232398abc6a7186e315425638c367d50c674718Thierry Reding{
7457232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
7467232398abc6a7186e315425638c367d50c674718Thierry Reding
7477232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
7487232398abc6a7186e315425638c367d50c674718Thierry Reding}
7497232398abc6a7186e315425638c367d50c674718Thierry Reding
7507232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int tegra_pmc_resume(struct device *dev)
7517232398abc6a7186e315425638c367d50c674718Thierry Reding{
7527232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(0x0, PMC_SCRATCH41);
7537232398abc6a7186e315425638c367d50c674718Thierry Reding
7547232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
7557232398abc6a7186e315425638c367d50c674718Thierry Reding}
7567232398abc6a7186e315425638c367d50c674718Thierry Reding#endif
7577232398abc6a7186e315425638c367d50c674718Thierry Reding
7587232398abc6a7186e315425638c367d50c674718Thierry Redingstatic SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume);
7597232398abc6a7186e315425638c367d50c674718Thierry Reding
7607232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const char * const tegra20_powergates[] = {
7617232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU] = "cpu",
7627232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_3D] = "3d",
7637232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VENC] = "venc",
7647232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VDEC] = "vdec",
7657232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_PCIE] = "pcie",
7667232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_L2] = "l2",
7677232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_MPE] = "mpe",
7687232398abc6a7186e315425638c367d50c674718Thierry Reding};
7697232398abc6a7186e315425638c367d50c674718Thierry Reding
7707232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const struct tegra_pmc_soc tegra20_pmc_soc = {
7717232398abc6a7186e315425638c367d50c674718Thierry Reding	.num_powergates = ARRAY_SIZE(tegra20_powergates),
7727232398abc6a7186e315425638c367d50c674718Thierry Reding	.powergates = tegra20_powergates,
7737232398abc6a7186e315425638c367d50c674718Thierry Reding	.num_cpu_powergates = 0,
7747232398abc6a7186e315425638c367d50c674718Thierry Reding	.cpu_powergates = NULL,
7757232398abc6a7186e315425638c367d50c674718Thierry Reding};
7767232398abc6a7186e315425638c367d50c674718Thierry Reding
7777232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const char * const tegra30_powergates[] = {
7787232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU] = "cpu0",
7797232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_3D] = "3d0",
7807232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VENC] = "venc",
7817232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VDEC] = "vdec",
7827232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_PCIE] = "pcie",
7837232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_L2] = "l2",
7847232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_MPE] = "mpe",
7857232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_HEG] = "heg",
7867232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_SATA] = "sata",
7877232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU1] = "cpu1",
7887232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU2] = "cpu2",
7897232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU3] = "cpu3",
7907232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CELP] = "celp",
7917232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_3D1] = "3d1",
7927232398abc6a7186e315425638c367d50c674718Thierry Reding};
7937232398abc6a7186e315425638c367d50c674718Thierry Reding
7947232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const u8 tegra30_cpu_powergates[] = {
7957232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU,
7967232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU1,
7977232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU2,
7987232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU3,
7997232398abc6a7186e315425638c367d50c674718Thierry Reding};
8007232398abc6a7186e315425638c367d50c674718Thierry Reding
8017232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const struct tegra_pmc_soc tegra30_pmc_soc = {
8027232398abc6a7186e315425638c367d50c674718Thierry Reding	.num_powergates = ARRAY_SIZE(tegra30_powergates),
8037232398abc6a7186e315425638c367d50c674718Thierry Reding	.powergates = tegra30_powergates,
8047232398abc6a7186e315425638c367d50c674718Thierry Reding	.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
8057232398abc6a7186e315425638c367d50c674718Thierry Reding	.cpu_powergates = tegra30_cpu_powergates,
8067232398abc6a7186e315425638c367d50c674718Thierry Reding};
8077232398abc6a7186e315425638c367d50c674718Thierry Reding
8087232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const char * const tegra114_powergates[] = {
8097232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU] = "crail",
8107232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_3D] = "3d",
8117232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VENC] = "venc",
8127232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VDEC] = "vdec",
8137232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_MPE] = "mpe",
8147232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_HEG] = "heg",
8157232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU1] = "cpu1",
8167232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU2] = "cpu2",
8177232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU3] = "cpu3",
8187232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CELP] = "celp",
8197232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU0] = "cpu0",
8207232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_C0NC] = "c0nc",
8217232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_C1NC] = "c1nc",
8227232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_DIS] = "dis",
8237232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_DISB] = "disb",
8247232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_XUSBA] = "xusba",
8257232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_XUSBB] = "xusbb",
8267232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_XUSBC] = "xusbc",
8277232398abc6a7186e315425638c367d50c674718Thierry Reding};
8287232398abc6a7186e315425638c367d50c674718Thierry Reding
8297232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const u8 tegra114_cpu_powergates[] = {
8307232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU0,
8317232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU1,
8327232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU2,
8337232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU3,
8347232398abc6a7186e315425638c367d50c674718Thierry Reding};
8357232398abc6a7186e315425638c367d50c674718Thierry Reding
8367232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const struct tegra_pmc_soc tegra114_pmc_soc = {
8377232398abc6a7186e315425638c367d50c674718Thierry Reding	.num_powergates = ARRAY_SIZE(tegra114_powergates),
8387232398abc6a7186e315425638c367d50c674718Thierry Reding	.powergates = tegra114_powergates,
8397232398abc6a7186e315425638c367d50c674718Thierry Reding	.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
8407232398abc6a7186e315425638c367d50c674718Thierry Reding	.cpu_powergates = tegra114_cpu_powergates,
8417232398abc6a7186e315425638c367d50c674718Thierry Reding};
8427232398abc6a7186e315425638c367d50c674718Thierry Reding
8437232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const char * const tegra124_powergates[] = {
8447232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU] = "crail",
8457232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_3D] = "3d",
8467232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VENC] = "venc",
8477232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_PCIE] = "pcie",
8487232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VDEC] = "vdec",
8497232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_L2] = "l2",
8507232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_MPE] = "mpe",
8517232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_HEG] = "heg",
8527232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_SATA] = "sata",
8537232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU1] = "cpu1",
8547232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU2] = "cpu2",
8557232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU3] = "cpu3",
8567232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CELP] = "celp",
8577232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_CPU0] = "cpu0",
8587232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_C0NC] = "c0nc",
8597232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_C1NC] = "c1nc",
8607232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_SOR] = "sor",
8617232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_DIS] = "dis",
8627232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_DISB] = "disb",
8637232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_XUSBA] = "xusba",
8647232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_XUSBB] = "xusbb",
8657232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_XUSBC] = "xusbc",
8667232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_VIC] = "vic",
8677232398abc6a7186e315425638c367d50c674718Thierry Reding	[TEGRA_POWERGATE_IRAM] = "iram",
8687232398abc6a7186e315425638c367d50c674718Thierry Reding};
8697232398abc6a7186e315425638c367d50c674718Thierry Reding
8707232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const u8 tegra124_cpu_powergates[] = {
8717232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU0,
8727232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU1,
8737232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU2,
8747232398abc6a7186e315425638c367d50c674718Thierry Reding	TEGRA_POWERGATE_CPU3,
8757232398abc6a7186e315425638c367d50c674718Thierry Reding};
8767232398abc6a7186e315425638c367d50c674718Thierry Reding
8777232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const struct tegra_pmc_soc tegra124_pmc_soc = {
8787232398abc6a7186e315425638c367d50c674718Thierry Reding	.num_powergates = ARRAY_SIZE(tegra124_powergates),
8797232398abc6a7186e315425638c367d50c674718Thierry Reding	.powergates = tegra124_powergates,
8807232398abc6a7186e315425638c367d50c674718Thierry Reding	.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
8817232398abc6a7186e315425638c367d50c674718Thierry Reding	.cpu_powergates = tegra124_cpu_powergates,
8827232398abc6a7186e315425638c367d50c674718Thierry Reding};
8837232398abc6a7186e315425638c367d50c674718Thierry Reding
8847232398abc6a7186e315425638c367d50c674718Thierry Redingstatic const struct of_device_id tegra_pmc_match[] = {
8857232398abc6a7186e315425638c367d50c674718Thierry Reding	{ .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc },
8867232398abc6a7186e315425638c367d50c674718Thierry Reding	{ .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc },
8877232398abc6a7186e315425638c367d50c674718Thierry Reding	{ .compatible = "nvidia,tegra30-pmc", .data = &tegra30_pmc_soc },
8887232398abc6a7186e315425638c367d50c674718Thierry Reding	{ .compatible = "nvidia,tegra20-pmc", .data = &tegra20_pmc_soc },
8897232398abc6a7186e315425638c367d50c674718Thierry Reding	{ }
8907232398abc6a7186e315425638c367d50c674718Thierry Reding};
8917232398abc6a7186e315425638c367d50c674718Thierry Reding
8927232398abc6a7186e315425638c367d50c674718Thierry Redingstatic struct platform_driver tegra_pmc_driver = {
8937232398abc6a7186e315425638c367d50c674718Thierry Reding	.driver = {
8947232398abc6a7186e315425638c367d50c674718Thierry Reding		.name = "tegra-pmc",
8957232398abc6a7186e315425638c367d50c674718Thierry Reding		.suppress_bind_attrs = true,
8967232398abc6a7186e315425638c367d50c674718Thierry Reding		.of_match_table = tegra_pmc_match,
8977232398abc6a7186e315425638c367d50c674718Thierry Reding		.pm = &tegra_pmc_pm_ops,
8987232398abc6a7186e315425638c367d50c674718Thierry Reding	},
8997232398abc6a7186e315425638c367d50c674718Thierry Reding	.probe = tegra_pmc_probe,
9007232398abc6a7186e315425638c367d50c674718Thierry Reding};
9017232398abc6a7186e315425638c367d50c674718Thierry Redingmodule_platform_driver(tegra_pmc_driver);
9027232398abc6a7186e315425638c367d50c674718Thierry Reding
9037232398abc6a7186e315425638c367d50c674718Thierry Reding/*
9047232398abc6a7186e315425638c367d50c674718Thierry Reding * Early initialization to allow access to registers in the very early boot
9057232398abc6a7186e315425638c367d50c674718Thierry Reding * process.
9067232398abc6a7186e315425638c367d50c674718Thierry Reding */
9077232398abc6a7186e315425638c367d50c674718Thierry Redingstatic int __init tegra_pmc_early_init(void)
9087232398abc6a7186e315425638c367d50c674718Thierry Reding{
9097232398abc6a7186e315425638c367d50c674718Thierry Reding	const struct of_device_id *match;
9107232398abc6a7186e315425638c367d50c674718Thierry Reding	struct device_node *np;
9117232398abc6a7186e315425638c367d50c674718Thierry Reding	struct resource regs;
9127232398abc6a7186e315425638c367d50c674718Thierry Reding	bool invert;
9137232398abc6a7186e315425638c367d50c674718Thierry Reding	u32 value;
9147232398abc6a7186e315425638c367d50c674718Thierry Reding
9157232398abc6a7186e315425638c367d50c674718Thierry Reding	if (!soc_is_tegra())
9167232398abc6a7186e315425638c367d50c674718Thierry Reding		return 0;
9177232398abc6a7186e315425638c367d50c674718Thierry Reding
9187232398abc6a7186e315425638c367d50c674718Thierry Reding	np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
9197232398abc6a7186e315425638c367d50c674718Thierry Reding	if (!np) {
9207232398abc6a7186e315425638c367d50c674718Thierry Reding		pr_warn("PMC device node not found, disabling powergating\n");
9217232398abc6a7186e315425638c367d50c674718Thierry Reding
9227232398abc6a7186e315425638c367d50c674718Thierry Reding		regs.start = 0x7000e400;
9237232398abc6a7186e315425638c367d50c674718Thierry Reding		regs.end = 0x7000e7ff;
9247232398abc6a7186e315425638c367d50c674718Thierry Reding		regs.flags = IORESOURCE_MEM;
9257232398abc6a7186e315425638c367d50c674718Thierry Reding
9267232398abc6a7186e315425638c367d50c674718Thierry Reding		pr_warn("Using memory region %pR\n", &regs);
9277232398abc6a7186e315425638c367d50c674718Thierry Reding	} else {
9287232398abc6a7186e315425638c367d50c674718Thierry Reding		pmc->soc = match->data;
9297232398abc6a7186e315425638c367d50c674718Thierry Reding	}
9307232398abc6a7186e315425638c367d50c674718Thierry Reding
9317232398abc6a7186e315425638c367d50c674718Thierry Reding	if (of_address_to_resource(np, 0, &regs) < 0) {
9327232398abc6a7186e315425638c367d50c674718Thierry Reding		pr_err("failed to get PMC registers\n");
9337232398abc6a7186e315425638c367d50c674718Thierry Reding		return -ENXIO;
9347232398abc6a7186e315425638c367d50c674718Thierry Reding	}
9357232398abc6a7186e315425638c367d50c674718Thierry Reding
9367232398abc6a7186e315425638c367d50c674718Thierry Reding	pmc->base = ioremap_nocache(regs.start, resource_size(&regs));
9377232398abc6a7186e315425638c367d50c674718Thierry Reding	if (!pmc->base) {
9387232398abc6a7186e315425638c367d50c674718Thierry Reding		pr_err("failed to map PMC registers\n");
9397232398abc6a7186e315425638c367d50c674718Thierry Reding		return -ENXIO;
9407232398abc6a7186e315425638c367d50c674718Thierry Reding	}
9417232398abc6a7186e315425638c367d50c674718Thierry Reding
9427232398abc6a7186e315425638c367d50c674718Thierry Reding	mutex_init(&pmc->powergates_lock);
9437232398abc6a7186e315425638c367d50c674718Thierry Reding
9447232398abc6a7186e315425638c367d50c674718Thierry Reding	invert = of_property_read_bool(np, "nvidia,invert-interrupt");
9457232398abc6a7186e315425638c367d50c674718Thierry Reding
9467232398abc6a7186e315425638c367d50c674718Thierry Reding	value = tegra_pmc_readl(PMC_CNTRL);
9477232398abc6a7186e315425638c367d50c674718Thierry Reding
9487232398abc6a7186e315425638c367d50c674718Thierry Reding	if (invert)
9497232398abc6a7186e315425638c367d50c674718Thierry Reding		value |= PMC_CNTRL_INTR_POLARITY;
9507232398abc6a7186e315425638c367d50c674718Thierry Reding	else
9517232398abc6a7186e315425638c367d50c674718Thierry Reding		value &= ~PMC_CNTRL_INTR_POLARITY;
9527232398abc6a7186e315425638c367d50c674718Thierry Reding
9537232398abc6a7186e315425638c367d50c674718Thierry Reding	tegra_pmc_writel(value, PMC_CNTRL);
9547232398abc6a7186e315425638c367d50c674718Thierry Reding
9557232398abc6a7186e315425638c367d50c674718Thierry Reding	return 0;
9567232398abc6a7186e315425638c367d50c674718Thierry Reding}
9577232398abc6a7186e315425638c367d50c674718Thierry Redingearly_initcall(tegra_pmc_early_init);
958