xref: /kernel/linux/linux-6.6/drivers/soc/tegra/pmc.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/soc/tegra/pmc.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2010 Google, Inc
662306a36Sopenharmony_ci * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author:
962306a36Sopenharmony_ci *	Colin Cross <ccross@google.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define pr_fmt(fmt) "tegra-pmc: " fmt
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/arm-smccc.h>
1562306a36Sopenharmony_ci#include <linux/clk.h>
1662306a36Sopenharmony_ci#include <linux/clk-provider.h>
1762306a36Sopenharmony_ci#include <linux/clkdev.h>
1862306a36Sopenharmony_ci#include <linux/clk/clk-conf.h>
1962306a36Sopenharmony_ci#include <linux/clk/tegra.h>
2062306a36Sopenharmony_ci#include <linux/debugfs.h>
2162306a36Sopenharmony_ci#include <linux/delay.h>
2262306a36Sopenharmony_ci#include <linux/device.h>
2362306a36Sopenharmony_ci#include <linux/err.h>
2462306a36Sopenharmony_ci#include <linux/export.h>
2562306a36Sopenharmony_ci#include <linux/init.h>
2662306a36Sopenharmony_ci#include <linux/interrupt.h>
2762306a36Sopenharmony_ci#include <linux/io.h>
2862306a36Sopenharmony_ci#include <linux/iopoll.h>
2962306a36Sopenharmony_ci#include <linux/irqdomain.h>
3062306a36Sopenharmony_ci#include <linux/irq.h>
3162306a36Sopenharmony_ci#include <linux/kernel.h>
3262306a36Sopenharmony_ci#include <linux/of_address.h>
3362306a36Sopenharmony_ci#include <linux/of_clk.h>
3462306a36Sopenharmony_ci#include <linux/of.h>
3562306a36Sopenharmony_ci#include <linux/of_irq.h>
3662306a36Sopenharmony_ci#include <linux/of_platform.h>
3762306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
3862306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
3962306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
4062306a36Sopenharmony_ci#include <linux/platform_device.h>
4162306a36Sopenharmony_ci#include <linux/pm_domain.h>
4262306a36Sopenharmony_ci#include <linux/pm_opp.h>
4362306a36Sopenharmony_ci#include <linux/power_supply.h>
4462306a36Sopenharmony_ci#include <linux/reboot.h>
4562306a36Sopenharmony_ci#include <linux/regmap.h>
4662306a36Sopenharmony_ci#include <linux/reset.h>
4762306a36Sopenharmony_ci#include <linux/seq_file.h>
4862306a36Sopenharmony_ci#include <linux/slab.h>
4962306a36Sopenharmony_ci#include <linux/spinlock.h>
5062306a36Sopenharmony_ci#include <linux/syscore_ops.h>
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#include <soc/tegra/common.h>
5362306a36Sopenharmony_ci#include <soc/tegra/fuse.h>
5462306a36Sopenharmony_ci#include <soc/tegra/pmc.h>
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#include <dt-bindings/interrupt-controller/arm-gic.h>
5762306a36Sopenharmony_ci#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
5862306a36Sopenharmony_ci#include <dt-bindings/gpio/tegra186-gpio.h>
5962306a36Sopenharmony_ci#include <dt-bindings/gpio/tegra194-gpio.h>
6062306a36Sopenharmony_ci#include <dt-bindings/gpio/tegra234-gpio.h>
6162306a36Sopenharmony_ci#include <dt-bindings/soc/tegra-pmc.h>
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define PMC_CNTRL			0x0
6462306a36Sopenharmony_ci#define  PMC_CNTRL_INTR_POLARITY	BIT(17) /* inverts INTR polarity */
6562306a36Sopenharmony_ci#define  PMC_CNTRL_CPU_PWRREQ_OE	BIT(16) /* CPU pwr req enable */
6662306a36Sopenharmony_ci#define  PMC_CNTRL_CPU_PWRREQ_POLARITY	BIT(15) /* CPU pwr req polarity */
6762306a36Sopenharmony_ci#define  PMC_CNTRL_SIDE_EFFECT_LP0	BIT(14) /* LP0 when CPU pwr gated */
6862306a36Sopenharmony_ci#define  PMC_CNTRL_SYSCLK_OE		BIT(11) /* system clock enable */
6962306a36Sopenharmony_ci#define  PMC_CNTRL_SYSCLK_POLARITY	BIT(10) /* sys clk polarity */
7062306a36Sopenharmony_ci#define  PMC_CNTRL_PWRREQ_POLARITY	BIT(8)
7162306a36Sopenharmony_ci#define  PMC_CNTRL_BLINK_EN		7
7262306a36Sopenharmony_ci#define  PMC_CNTRL_MAIN_RST		BIT(4)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define PMC_WAKE_MASK			0x0c
7562306a36Sopenharmony_ci#define PMC_WAKE_LEVEL			0x10
7662306a36Sopenharmony_ci#define PMC_WAKE_STATUS			0x14
7762306a36Sopenharmony_ci#define PMC_SW_WAKE_STATUS		0x18
7862306a36Sopenharmony_ci#define PMC_DPD_PADS_ORIDE		0x1c
7962306a36Sopenharmony_ci#define  PMC_DPD_PADS_ORIDE_BLINK	20
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define DPD_SAMPLE			0x020
8262306a36Sopenharmony_ci#define  DPD_SAMPLE_ENABLE		BIT(0)
8362306a36Sopenharmony_ci#define  DPD_SAMPLE_DISABLE		(0 << 0)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define PWRGATE_TOGGLE			0x30
8662306a36Sopenharmony_ci#define  PWRGATE_TOGGLE_START		BIT(8)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define REMOVE_CLAMPING			0x34
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define PWRGATE_STATUS			0x38
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define PMC_BLINK_TIMER			0x40
9362306a36Sopenharmony_ci#define PMC_IMPL_E_33V_PWR		0x40
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define PMC_PWR_DET			0x48
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define PMC_SCRATCH0_MODE_RECOVERY	BIT(31)
9862306a36Sopenharmony_ci#define PMC_SCRATCH0_MODE_BOOTLOADER	BIT(30)
9962306a36Sopenharmony_ci#define PMC_SCRATCH0_MODE_RCM		BIT(1)
10062306a36Sopenharmony_ci#define PMC_SCRATCH0_MODE_MASK		(PMC_SCRATCH0_MODE_RECOVERY | \
10162306a36Sopenharmony_ci					 PMC_SCRATCH0_MODE_BOOTLOADER | \
10262306a36Sopenharmony_ci					 PMC_SCRATCH0_MODE_RCM)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define PMC_CPUPWRGOOD_TIMER		0xc8
10562306a36Sopenharmony_ci#define PMC_CPUPWROFF_TIMER		0xcc
10662306a36Sopenharmony_ci#define PMC_COREPWRGOOD_TIMER		0x3c
10762306a36Sopenharmony_ci#define PMC_COREPWROFF_TIMER		0xe0
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define PMC_PWR_DET_VALUE		0xe4
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define PMC_USB_DEBOUNCE_DEL		0xec
11262306a36Sopenharmony_ci#define PMC_USB_AO			0xf0
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define PMC_SCRATCH37			0x130
11562306a36Sopenharmony_ci#define PMC_SCRATCH41			0x140
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define PMC_WAKE2_MASK			0x160
11862306a36Sopenharmony_ci#define PMC_WAKE2_LEVEL			0x164
11962306a36Sopenharmony_ci#define PMC_WAKE2_STATUS		0x168
12062306a36Sopenharmony_ci#define PMC_SW_WAKE2_STATUS		0x16c
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#define PMC_CLK_OUT_CNTRL		0x1a8
12362306a36Sopenharmony_ci#define  PMC_CLK_OUT_MUX_MASK		GENMASK(1, 0)
12462306a36Sopenharmony_ci#define PMC_SENSOR_CTRL			0x1b0
12562306a36Sopenharmony_ci#define  PMC_SENSOR_CTRL_SCRATCH_WRITE	BIT(2)
12662306a36Sopenharmony_ci#define  PMC_SENSOR_CTRL_ENABLE_RST	BIT(1)
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define  PMC_RST_STATUS_POR		0
12962306a36Sopenharmony_ci#define  PMC_RST_STATUS_WATCHDOG	1
13062306a36Sopenharmony_ci#define  PMC_RST_STATUS_SENSOR		2
13162306a36Sopenharmony_ci#define  PMC_RST_STATUS_SW_MAIN		3
13262306a36Sopenharmony_ci#define  PMC_RST_STATUS_LP0		4
13362306a36Sopenharmony_ci#define  PMC_RST_STATUS_AOTAG		5
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define IO_DPD_REQ			0x1b8
13662306a36Sopenharmony_ci#define  IO_DPD_REQ_CODE_IDLE		(0U << 30)
13762306a36Sopenharmony_ci#define  IO_DPD_REQ_CODE_OFF		(1U << 30)
13862306a36Sopenharmony_ci#define  IO_DPD_REQ_CODE_ON		(2U << 30)
13962306a36Sopenharmony_ci#define  IO_DPD_REQ_CODE_MASK		(3U << 30)
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#define IO_DPD_STATUS			0x1bc
14262306a36Sopenharmony_ci#define IO_DPD2_REQ			0x1c0
14362306a36Sopenharmony_ci#define IO_DPD2_STATUS			0x1c4
14462306a36Sopenharmony_ci#define SEL_DPD_TIM			0x1c8
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define PMC_UTMIP_UHSIC_TRIGGERS	0x1ec
14762306a36Sopenharmony_ci#define PMC_UTMIP_UHSIC_SAVED_STATE	0x1f0
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define PMC_UTMIP_TERM_PAD_CFG		0x1f8
15062306a36Sopenharmony_ci#define PMC_UTMIP_UHSIC_SLEEP_CFG	0x1fc
15162306a36Sopenharmony_ci#define PMC_UTMIP_UHSIC_FAKE		0x218
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define PMC_SCRATCH54			0x258
15462306a36Sopenharmony_ci#define  PMC_SCRATCH54_DATA_SHIFT	8
15562306a36Sopenharmony_ci#define  PMC_SCRATCH54_ADDR_SHIFT	0
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define PMC_SCRATCH55			0x25c
15862306a36Sopenharmony_ci#define  PMC_SCRATCH55_RESET_TEGRA	BIT(31)
15962306a36Sopenharmony_ci#define  PMC_SCRATCH55_CNTRL_ID_SHIFT	27
16062306a36Sopenharmony_ci#define  PMC_SCRATCH55_PINMUX_SHIFT	24
16162306a36Sopenharmony_ci#define  PMC_SCRATCH55_16BITOP		BIT(15)
16262306a36Sopenharmony_ci#define  PMC_SCRATCH55_CHECKSUM_SHIFT	16
16362306a36Sopenharmony_ci#define  PMC_SCRATCH55_I2CSLV1_SHIFT	0
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci#define  PMC_UTMIP_UHSIC_LINE_WAKEUP	0x26c
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#define PMC_UTMIP_BIAS_MASTER_CNTRL	0x270
16862306a36Sopenharmony_ci#define PMC_UTMIP_MASTER_CONFIG		0x274
16962306a36Sopenharmony_ci#define PMC_UTMIP_UHSIC2_TRIGGERS	0x27c
17062306a36Sopenharmony_ci#define PMC_UTMIP_MASTER2_CONFIG	0x29c
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci#define GPU_RG_CNTRL			0x2d4
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci#define PMC_UTMIP_PAD_CFG0		0x4c0
17562306a36Sopenharmony_ci#define PMC_UTMIP_UHSIC_SLEEP_CFG1	0x4d0
17662306a36Sopenharmony_ci#define PMC_UTMIP_SLEEPWALK_P3		0x4e0
17762306a36Sopenharmony_ci/* Tegra186 and later */
17862306a36Sopenharmony_ci#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2))
17962306a36Sopenharmony_ci#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3)
18062306a36Sopenharmony_ci#define WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN (1 << 1)
18162306a36Sopenharmony_ci#define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2))
18262306a36Sopenharmony_ci#define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2))
18362306a36Sopenharmony_ci#define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2))
18462306a36Sopenharmony_ci#define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2))
18562306a36Sopenharmony_ci#define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2))
18662306a36Sopenharmony_ci#define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2))
18762306a36Sopenharmony_ci#define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2))
18862306a36Sopenharmony_ci#define WAKE_AOWAKE_SW_STATUS_W_0	0x49c
18962306a36Sopenharmony_ci#define WAKE_AOWAKE_SW_STATUS(x)	(0x4a0 + ((x) << 2))
19062306a36Sopenharmony_ci#define WAKE_LATCH_SW			0x498
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci#define WAKE_AOWAKE_CTRL 0x4f4
19362306a36Sopenharmony_ci#define  WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#define SW_WAKE_ID		83 /* wake83 */
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/* for secure PMC */
19862306a36Sopenharmony_ci#define TEGRA_SMC_PMC		0xc2fffe00
19962306a36Sopenharmony_ci#define  TEGRA_SMC_PMC_READ	0xaa
20062306a36Sopenharmony_ci#define  TEGRA_SMC_PMC_WRITE	0xbb
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistruct pmc_clk {
20362306a36Sopenharmony_ci	struct clk_hw	hw;
20462306a36Sopenharmony_ci	unsigned long	offs;
20562306a36Sopenharmony_ci	u32		mux_shift;
20662306a36Sopenharmony_ci	u32		force_en_shift;
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define to_pmc_clk(_hw) container_of(_hw, struct pmc_clk, hw)
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistruct pmc_clk_gate {
21262306a36Sopenharmony_ci	struct clk_hw	hw;
21362306a36Sopenharmony_ci	unsigned long	offs;
21462306a36Sopenharmony_ci	u32		shift;
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistruct pmc_clk_init_data {
22062306a36Sopenharmony_ci	char *name;
22162306a36Sopenharmony_ci	const char *const *parents;
22262306a36Sopenharmony_ci	int num_parents;
22362306a36Sopenharmony_ci	int clk_id;
22462306a36Sopenharmony_ci	u8 mux_shift;
22562306a36Sopenharmony_ci	u8 force_en_shift;
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const char * const clk_out1_parents[] = { "osc", "osc_div2",
22962306a36Sopenharmony_ci	"osc_div4", "extern1",
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic const char * const clk_out2_parents[] = { "osc", "osc_div2",
23362306a36Sopenharmony_ci	"osc_div4", "extern2",
23462306a36Sopenharmony_ci};
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic const char * const clk_out3_parents[] = { "osc", "osc_div2",
23762306a36Sopenharmony_ci	"osc_div4", "extern3",
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic const struct pmc_clk_init_data tegra_pmc_clks_data[] = {
24162306a36Sopenharmony_ci	{
24262306a36Sopenharmony_ci		.name = "pmc_clk_out_1",
24362306a36Sopenharmony_ci		.parents = clk_out1_parents,
24462306a36Sopenharmony_ci		.num_parents = ARRAY_SIZE(clk_out1_parents),
24562306a36Sopenharmony_ci		.clk_id = TEGRA_PMC_CLK_OUT_1,
24662306a36Sopenharmony_ci		.mux_shift = 6,
24762306a36Sopenharmony_ci		.force_en_shift = 2,
24862306a36Sopenharmony_ci	},
24962306a36Sopenharmony_ci	{
25062306a36Sopenharmony_ci		.name = "pmc_clk_out_2",
25162306a36Sopenharmony_ci		.parents = clk_out2_parents,
25262306a36Sopenharmony_ci		.num_parents = ARRAY_SIZE(clk_out2_parents),
25362306a36Sopenharmony_ci		.clk_id = TEGRA_PMC_CLK_OUT_2,
25462306a36Sopenharmony_ci		.mux_shift = 14,
25562306a36Sopenharmony_ci		.force_en_shift = 10,
25662306a36Sopenharmony_ci	},
25762306a36Sopenharmony_ci	{
25862306a36Sopenharmony_ci		.name = "pmc_clk_out_3",
25962306a36Sopenharmony_ci		.parents = clk_out3_parents,
26062306a36Sopenharmony_ci		.num_parents = ARRAY_SIZE(clk_out3_parents),
26162306a36Sopenharmony_ci		.clk_id = TEGRA_PMC_CLK_OUT_3,
26262306a36Sopenharmony_ci		.mux_shift = 22,
26362306a36Sopenharmony_ci		.force_en_shift = 18,
26462306a36Sopenharmony_ci	},
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistruct tegra_powergate {
26862306a36Sopenharmony_ci	struct generic_pm_domain genpd;
26962306a36Sopenharmony_ci	struct tegra_pmc *pmc;
27062306a36Sopenharmony_ci	unsigned int id;
27162306a36Sopenharmony_ci	struct clk **clks;
27262306a36Sopenharmony_ci	unsigned int num_clks;
27362306a36Sopenharmony_ci	unsigned long *clk_rates;
27462306a36Sopenharmony_ci	struct reset_control *reset;
27562306a36Sopenharmony_ci};
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistruct tegra_io_pad_soc {
27862306a36Sopenharmony_ci	enum tegra_io_pad id;
27962306a36Sopenharmony_ci	unsigned int dpd;
28062306a36Sopenharmony_ci	unsigned int request;
28162306a36Sopenharmony_ci	unsigned int status;
28262306a36Sopenharmony_ci	unsigned int voltage;
28362306a36Sopenharmony_ci	const char *name;
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistruct tegra_pmc_regs {
28762306a36Sopenharmony_ci	unsigned int scratch0;
28862306a36Sopenharmony_ci	unsigned int rst_status;
28962306a36Sopenharmony_ci	unsigned int rst_source_shift;
29062306a36Sopenharmony_ci	unsigned int rst_source_mask;
29162306a36Sopenharmony_ci	unsigned int rst_level_shift;
29262306a36Sopenharmony_ci	unsigned int rst_level_mask;
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistruct tegra_wake_event {
29662306a36Sopenharmony_ci	const char *name;
29762306a36Sopenharmony_ci	unsigned int id;
29862306a36Sopenharmony_ci	unsigned int irq;
29962306a36Sopenharmony_ci	struct {
30062306a36Sopenharmony_ci		unsigned int instance;
30162306a36Sopenharmony_ci		unsigned int pin;
30262306a36Sopenharmony_ci	} gpio;
30362306a36Sopenharmony_ci};
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci#define TEGRA_WAKE_SIMPLE(_name, _id)			\
30662306a36Sopenharmony_ci	{						\
30762306a36Sopenharmony_ci		.name = _name,				\
30862306a36Sopenharmony_ci		.id = _id,				\
30962306a36Sopenharmony_ci		.irq = 0,				\
31062306a36Sopenharmony_ci		.gpio = {				\
31162306a36Sopenharmony_ci			.instance = UINT_MAX,		\
31262306a36Sopenharmony_ci			.pin = UINT_MAX,		\
31362306a36Sopenharmony_ci		},					\
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci#define TEGRA_WAKE_IRQ(_name, _id, _irq)		\
31762306a36Sopenharmony_ci	{						\
31862306a36Sopenharmony_ci		.name = _name,				\
31962306a36Sopenharmony_ci		.id = _id,				\
32062306a36Sopenharmony_ci		.irq = _irq,				\
32162306a36Sopenharmony_ci		.gpio = {				\
32262306a36Sopenharmony_ci			.instance = UINT_MAX,		\
32362306a36Sopenharmony_ci			.pin = UINT_MAX,		\
32462306a36Sopenharmony_ci		},					\
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci#define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin)	\
32862306a36Sopenharmony_ci	{						\
32962306a36Sopenharmony_ci		.name = _name,				\
33062306a36Sopenharmony_ci		.id = _id,				\
33162306a36Sopenharmony_ci		.irq = 0,				\
33262306a36Sopenharmony_ci		.gpio = {				\
33362306a36Sopenharmony_ci			.instance = _instance,		\
33462306a36Sopenharmony_ci			.pin = _pin,			\
33562306a36Sopenharmony_ci		},					\
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistruct tegra_pmc_soc {
33962306a36Sopenharmony_ci	unsigned int num_powergates;
34062306a36Sopenharmony_ci	const char *const *powergates;
34162306a36Sopenharmony_ci	unsigned int num_cpu_powergates;
34262306a36Sopenharmony_ci	const u8 *cpu_powergates;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	bool has_tsense_reset;
34562306a36Sopenharmony_ci	bool has_gpu_clamps;
34662306a36Sopenharmony_ci	bool needs_mbist_war;
34762306a36Sopenharmony_ci	bool has_impl_33v_pwr;
34862306a36Sopenharmony_ci	bool maybe_tz_only;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	const struct tegra_io_pad_soc *io_pads;
35162306a36Sopenharmony_ci	unsigned int num_io_pads;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	const struct pinctrl_pin_desc *pin_descs;
35462306a36Sopenharmony_ci	unsigned int num_pin_descs;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	const struct tegra_pmc_regs *regs;
35762306a36Sopenharmony_ci	void (*init)(struct tegra_pmc *pmc);
35862306a36Sopenharmony_ci	void (*setup_irq_polarity)(struct tegra_pmc *pmc,
35962306a36Sopenharmony_ci				   struct device_node *np,
36062306a36Sopenharmony_ci				   bool invert);
36162306a36Sopenharmony_ci	void (*set_wake_filters)(struct tegra_pmc *pmc);
36262306a36Sopenharmony_ci	int (*irq_set_wake)(struct irq_data *data, unsigned int on);
36362306a36Sopenharmony_ci	int (*irq_set_type)(struct irq_data *data, unsigned int type);
36462306a36Sopenharmony_ci	int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id,
36562306a36Sopenharmony_ci			     bool new_state);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	const char * const *reset_sources;
36862306a36Sopenharmony_ci	unsigned int num_reset_sources;
36962306a36Sopenharmony_ci	const char * const *reset_levels;
37062306a36Sopenharmony_ci	unsigned int num_reset_levels;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/*
37362306a36Sopenharmony_ci	 * These describe events that can wake the system from sleep (i.e.
37462306a36Sopenharmony_ci	 * LP0 or SC7). Wakeup from other sleep states (such as LP1 or LP2)
37562306a36Sopenharmony_ci	 * are dealt with in the LIC.
37662306a36Sopenharmony_ci	 */
37762306a36Sopenharmony_ci	const struct tegra_wake_event *wake_events;
37862306a36Sopenharmony_ci	unsigned int num_wake_events;
37962306a36Sopenharmony_ci	unsigned int max_wake_events;
38062306a36Sopenharmony_ci	unsigned int max_wake_vectors;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	const struct pmc_clk_init_data *pmc_clks_data;
38362306a36Sopenharmony_ci	unsigned int num_pmc_clks;
38462306a36Sopenharmony_ci	bool has_blink_output;
38562306a36Sopenharmony_ci	bool has_usb_sleepwalk;
38662306a36Sopenharmony_ci	bool supports_core_domain;
38762306a36Sopenharmony_ci};
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/**
39062306a36Sopenharmony_ci * struct tegra_pmc - NVIDIA Tegra PMC
39162306a36Sopenharmony_ci * @dev: pointer to PMC device structure
39262306a36Sopenharmony_ci * @base: pointer to I/O remapped register region
39362306a36Sopenharmony_ci * @wake: pointer to I/O remapped region for WAKE registers
39462306a36Sopenharmony_ci * @aotag: pointer to I/O remapped region for AOTAG registers
39562306a36Sopenharmony_ci * @scratch: pointer to I/O remapped region for scratch registers
39662306a36Sopenharmony_ci * @clk: pointer to pclk clock
39762306a36Sopenharmony_ci * @soc: pointer to SoC data structure
39862306a36Sopenharmony_ci * @tz_only: flag specifying if the PMC can only be accessed via TrustZone
39962306a36Sopenharmony_ci * @rate: currently configured rate of pclk
40062306a36Sopenharmony_ci * @suspend_mode: lowest suspend mode available
40162306a36Sopenharmony_ci * @cpu_good_time: CPU power good time (in microseconds)
40262306a36Sopenharmony_ci * @cpu_off_time: CPU power off time (in microsecends)
40362306a36Sopenharmony_ci * @core_osc_time: core power good OSC time (in microseconds)
40462306a36Sopenharmony_ci * @core_pmu_time: core power good PMU time (in microseconds)
40562306a36Sopenharmony_ci * @core_off_time: core power off time (in microseconds)
40662306a36Sopenharmony_ci * @corereq_high: core power request is active-high
40762306a36Sopenharmony_ci * @sysclkreq_high: system clock request is active-high
40862306a36Sopenharmony_ci * @combined_req: combined power request for CPU & core
40962306a36Sopenharmony_ci * @cpu_pwr_good_en: CPU power good signal is enabled
41062306a36Sopenharmony_ci * @lp0_vec_phys: physical base address of the LP0 warm boot code
41162306a36Sopenharmony_ci * @lp0_vec_size: size of the LP0 warm boot code
41262306a36Sopenharmony_ci * @powergates_available: Bitmap of available power gates
41362306a36Sopenharmony_ci * @powergates_lock: mutex for power gate register access
41462306a36Sopenharmony_ci * @pctl_dev: pin controller exposed by the PMC
41562306a36Sopenharmony_ci * @domain: IRQ domain provided by the PMC
41662306a36Sopenharmony_ci * @irq: chip implementation for the IRQ domain
41762306a36Sopenharmony_ci * @clk_nb: pclk clock changes handler
41862306a36Sopenharmony_ci * @core_domain_state_synced: flag marking the core domain's state as synced
41962306a36Sopenharmony_ci * @core_domain_registered: flag marking the core domain as registered
42062306a36Sopenharmony_ci * @wake_type_level_map: Bitmap indicating level type for non-dual edge wakes
42162306a36Sopenharmony_ci * @wake_type_dual_edge_map: Bitmap indicating if a wake is dual-edge or not
42262306a36Sopenharmony_ci * @wake_sw_status_map: Bitmap to hold raw status of wakes without mask
42362306a36Sopenharmony_ci * @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in
42462306a36Sopenharmony_ci *     cntrl register associated with each wake during system suspend.
42562306a36Sopenharmony_ci */
42662306a36Sopenharmony_cistruct tegra_pmc {
42762306a36Sopenharmony_ci	struct device *dev;
42862306a36Sopenharmony_ci	void __iomem *base;
42962306a36Sopenharmony_ci	void __iomem *wake;
43062306a36Sopenharmony_ci	void __iomem *aotag;
43162306a36Sopenharmony_ci	void __iomem *scratch;
43262306a36Sopenharmony_ci	struct clk *clk;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	const struct tegra_pmc_soc *soc;
43562306a36Sopenharmony_ci	bool tz_only;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	unsigned long rate;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	enum tegra_suspend_mode suspend_mode;
44062306a36Sopenharmony_ci	u32 cpu_good_time;
44162306a36Sopenharmony_ci	u32 cpu_off_time;
44262306a36Sopenharmony_ci	u32 core_osc_time;
44362306a36Sopenharmony_ci	u32 core_pmu_time;
44462306a36Sopenharmony_ci	u32 core_off_time;
44562306a36Sopenharmony_ci	bool corereq_high;
44662306a36Sopenharmony_ci	bool sysclkreq_high;
44762306a36Sopenharmony_ci	bool combined_req;
44862306a36Sopenharmony_ci	bool cpu_pwr_good_en;
44962306a36Sopenharmony_ci	u32 lp0_vec_phys;
45062306a36Sopenharmony_ci	u32 lp0_vec_size;
45162306a36Sopenharmony_ci	DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	struct mutex powergates_lock;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	struct pinctrl_dev *pctl_dev;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	struct irq_domain *domain;
45862306a36Sopenharmony_ci	struct irq_chip irq;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	struct notifier_block clk_nb;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	bool core_domain_state_synced;
46362306a36Sopenharmony_ci	bool core_domain_registered;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	unsigned long *wake_type_level_map;
46662306a36Sopenharmony_ci	unsigned long *wake_type_dual_edge_map;
46762306a36Sopenharmony_ci	unsigned long *wake_sw_status_map;
46862306a36Sopenharmony_ci	unsigned long *wake_cntrl_level_map;
46962306a36Sopenharmony_ci	struct syscore_ops syscore;
47062306a36Sopenharmony_ci};
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic struct tegra_pmc *pmc = &(struct tegra_pmc) {
47362306a36Sopenharmony_ci	.base = NULL,
47462306a36Sopenharmony_ci	.suspend_mode = TEGRA_SUSPEND_NOT_READY,
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic inline struct tegra_powergate *
47862306a36Sopenharmony_cito_powergate(struct generic_pm_domain *domain)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	return container_of(domain, struct tegra_powergate, genpd);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic u32 tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct arm_smccc_res res;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (pmc->tz_only) {
48862306a36Sopenharmony_ci		arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_READ, offset, 0, 0,
48962306a36Sopenharmony_ci			      0, 0, 0, &res);
49062306a36Sopenharmony_ci		if (res.a0) {
49162306a36Sopenharmony_ci			if (pmc->dev)
49262306a36Sopenharmony_ci				dev_warn(pmc->dev, "%s(): SMC failed: %lu\n",
49362306a36Sopenharmony_ci					 __func__, res.a0);
49462306a36Sopenharmony_ci			else
49562306a36Sopenharmony_ci				pr_warn("%s(): SMC failed: %lu\n", __func__,
49662306a36Sopenharmony_ci					res.a0);
49762306a36Sopenharmony_ci		}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		return res.a1;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	return readl(pmc->base + offset);
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic void tegra_pmc_writel(struct tegra_pmc *pmc, u32 value,
50662306a36Sopenharmony_ci			     unsigned long offset)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct arm_smccc_res res;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (pmc->tz_only) {
51162306a36Sopenharmony_ci		arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_WRITE, offset,
51262306a36Sopenharmony_ci			      value, 0, 0, 0, 0, &res);
51362306a36Sopenharmony_ci		if (res.a0) {
51462306a36Sopenharmony_ci			if (pmc->dev)
51562306a36Sopenharmony_ci				dev_warn(pmc->dev, "%s(): SMC failed: %lu\n",
51662306a36Sopenharmony_ci					 __func__, res.a0);
51762306a36Sopenharmony_ci			else
51862306a36Sopenharmony_ci				pr_warn("%s(): SMC failed: %lu\n", __func__,
51962306a36Sopenharmony_ci					res.a0);
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci	} else {
52262306a36Sopenharmony_ci		writel(value, pmc->base + offset);
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic u32 tegra_pmc_scratch_readl(struct tegra_pmc *pmc, unsigned long offset)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	if (pmc->tz_only)
52962306a36Sopenharmony_ci		return tegra_pmc_readl(pmc, offset);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	return readl(pmc->scratch + offset);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic void tegra_pmc_scratch_writel(struct tegra_pmc *pmc, u32 value,
53562306a36Sopenharmony_ci				     unsigned long offset)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	if (pmc->tz_only)
53862306a36Sopenharmony_ci		tegra_pmc_writel(pmc, value, offset);
53962306a36Sopenharmony_ci	else
54062306a36Sopenharmony_ci		writel(value, pmc->scratch + offset);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci/*
54462306a36Sopenharmony_ci * TODO Figure out a way to call this with the struct tegra_pmc * passed in.
54562306a36Sopenharmony_ci * This currently doesn't work because readx_poll_timeout() can only operate
54662306a36Sopenharmony_ci * on functions that take a single argument.
54762306a36Sopenharmony_ci */
54862306a36Sopenharmony_cistatic inline bool tegra_powergate_state(int id)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps)
55162306a36Sopenharmony_ci		return (tegra_pmc_readl(pmc, GPU_RG_CNTRL) & 0x1) == 0;
55262306a36Sopenharmony_ci	else
55362306a36Sopenharmony_ci		return (tegra_pmc_readl(pmc, PWRGATE_STATUS) & BIT(id)) != 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic inline bool tegra_powergate_is_valid(struct tegra_pmc *pmc, int id)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	return (pmc->soc && pmc->soc->powergates[id]);
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic inline bool tegra_powergate_is_available(struct tegra_pmc *pmc, int id)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	return test_bit(id, pmc->powergates_available);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	unsigned int i;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (!pmc || !pmc->soc || !name)
57162306a36Sopenharmony_ci		return -EINVAL;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->num_powergates; i++) {
57462306a36Sopenharmony_ci		if (!tegra_powergate_is_valid(pmc, i))
57562306a36Sopenharmony_ci			continue;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		if (!strcmp(name, pmc->soc->powergates[i]))
57862306a36Sopenharmony_ci			return i;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	return -ENODEV;
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic int tegra20_powergate_set(struct tegra_pmc *pmc, unsigned int id,
58562306a36Sopenharmony_ci				 bool new_state)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	unsigned int retries = 100;
58862306a36Sopenharmony_ci	bool status;
58962306a36Sopenharmony_ci	int ret;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/*
59262306a36Sopenharmony_ci	 * As per TRM documentation, the toggle command will be dropped by PMC
59362306a36Sopenharmony_ci	 * if there is contention with a HW-initiated toggling (i.e. CPU core
59462306a36Sopenharmony_ci	 * power-gated), the command should be retried in that case.
59562306a36Sopenharmony_ci	 */
59662306a36Sopenharmony_ci	do {
59762306a36Sopenharmony_ci		tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		/* wait for PMC to execute the command */
60062306a36Sopenharmony_ci		ret = readx_poll_timeout(tegra_powergate_state, id, status,
60162306a36Sopenharmony_ci					 status == new_state, 1, 10);
60262306a36Sopenharmony_ci	} while (ret == -ETIMEDOUT && retries--);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	return ret;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic inline bool tegra_powergate_toggle_ready(struct tegra_pmc *pmc)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	return !(tegra_pmc_readl(pmc, PWRGATE_TOGGLE) & PWRGATE_TOGGLE_START);
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic int tegra114_powergate_set(struct tegra_pmc *pmc, unsigned int id,
61362306a36Sopenharmony_ci				  bool new_state)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	bool status;
61662306a36Sopenharmony_ci	int err;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* wait while PMC power gating is contended */
61962306a36Sopenharmony_ci	err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status,
62062306a36Sopenharmony_ci				 status == true, 1, 100);
62162306a36Sopenharmony_ci	if (err)
62262306a36Sopenharmony_ci		return err;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* wait for PMC to accept the command */
62762306a36Sopenharmony_ci	err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status,
62862306a36Sopenharmony_ci				 status == true, 1, 100);
62962306a36Sopenharmony_ci	if (err)
63062306a36Sopenharmony_ci		return err;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/* wait for PMC to execute the command */
63362306a36Sopenharmony_ci	err = readx_poll_timeout(tegra_powergate_state, id, status,
63462306a36Sopenharmony_ci				 status == new_state, 10, 100000);
63562306a36Sopenharmony_ci	if (err)
63662306a36Sopenharmony_ci		return err;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	return 0;
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci/**
64262306a36Sopenharmony_ci * tegra_powergate_set() - set the state of a partition
64362306a36Sopenharmony_ci * @pmc: power management controller
64462306a36Sopenharmony_ci * @id: partition ID
64562306a36Sopenharmony_ci * @new_state: new state of the partition
64662306a36Sopenharmony_ci */
64762306a36Sopenharmony_cistatic int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id,
64862306a36Sopenharmony_ci			       bool new_state)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	int err;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps)
65362306a36Sopenharmony_ci		return -EINVAL;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	mutex_lock(&pmc->powergates_lock);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (tegra_powergate_state(id) == new_state) {
65862306a36Sopenharmony_ci		mutex_unlock(&pmc->powergates_lock);
65962306a36Sopenharmony_ci		return 0;
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	err = pmc->soc->powergate_set(pmc, id, new_state);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	mutex_unlock(&pmc->powergates_lock);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	return err;
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic int __tegra_powergate_remove_clamping(struct tegra_pmc *pmc,
67062306a36Sopenharmony_ci					     unsigned int id)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	u32 mask;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	mutex_lock(&pmc->powergates_lock);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	/*
67762306a36Sopenharmony_ci	 * On Tegra124 and later, the clamps for the GPU are controlled by a
67862306a36Sopenharmony_ci	 * separate register (with different semantics).
67962306a36Sopenharmony_ci	 */
68062306a36Sopenharmony_ci	if (id == TEGRA_POWERGATE_3D) {
68162306a36Sopenharmony_ci		if (pmc->soc->has_gpu_clamps) {
68262306a36Sopenharmony_ci			tegra_pmc_writel(pmc, 0, GPU_RG_CNTRL);
68362306a36Sopenharmony_ci			goto out;
68462306a36Sopenharmony_ci		}
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/*
68862306a36Sopenharmony_ci	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
68962306a36Sopenharmony_ci	 * swapped relatively to the partition ids
69062306a36Sopenharmony_ci	 */
69162306a36Sopenharmony_ci	if (id == TEGRA_POWERGATE_VDEC)
69262306a36Sopenharmony_ci		mask = (1 << TEGRA_POWERGATE_PCIE);
69362306a36Sopenharmony_ci	else if (id == TEGRA_POWERGATE_PCIE)
69462306a36Sopenharmony_ci		mask = (1 << TEGRA_POWERGATE_VDEC);
69562306a36Sopenharmony_ci	else
69662306a36Sopenharmony_ci		mask = (1 << id);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	tegra_pmc_writel(pmc, mask, REMOVE_CLAMPING);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ciout:
70162306a36Sopenharmony_ci	mutex_unlock(&pmc->powergates_lock);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	return 0;
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic int tegra_powergate_prepare_clocks(struct tegra_powergate *pg)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	unsigned long safe_rate = 100 * 1000 * 1000;
70962306a36Sopenharmony_ci	unsigned int i;
71062306a36Sopenharmony_ci	int err;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	for (i = 0; i < pg->num_clks; i++) {
71362306a36Sopenharmony_ci		pg->clk_rates[i] = clk_get_rate(pg->clks[i]);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		if (!pg->clk_rates[i]) {
71662306a36Sopenharmony_ci			err = -EINVAL;
71762306a36Sopenharmony_ci			goto out;
71862306a36Sopenharmony_ci		}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		if (pg->clk_rates[i] <= safe_rate)
72162306a36Sopenharmony_ci			continue;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		/*
72462306a36Sopenharmony_ci		 * We don't know whether voltage state is okay for the
72562306a36Sopenharmony_ci		 * current clock rate, hence it's better to temporally
72662306a36Sopenharmony_ci		 * switch clock to a safe rate which is suitable for
72762306a36Sopenharmony_ci		 * all voltages, before enabling the clock.
72862306a36Sopenharmony_ci		 */
72962306a36Sopenharmony_ci		err = clk_set_rate(pg->clks[i], safe_rate);
73062306a36Sopenharmony_ci		if (err)
73162306a36Sopenharmony_ci			goto out;
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	return 0;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ciout:
73762306a36Sopenharmony_ci	while (i--)
73862306a36Sopenharmony_ci		clk_set_rate(pg->clks[i], pg->clk_rates[i]);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	return err;
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic int tegra_powergate_unprepare_clocks(struct tegra_powergate *pg)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	unsigned int i;
74662306a36Sopenharmony_ci	int err;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	for (i = 0; i < pg->num_clks; i++) {
74962306a36Sopenharmony_ci		err = clk_set_rate(pg->clks[i], pg->clk_rates[i]);
75062306a36Sopenharmony_ci		if (err)
75162306a36Sopenharmony_ci			return err;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	return 0;
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic void tegra_powergate_disable_clocks(struct tegra_powergate *pg)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	unsigned int i;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	for (i = 0; i < pg->num_clks; i++)
76262306a36Sopenharmony_ci		clk_disable_unprepare(pg->clks[i]);
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cistatic int tegra_powergate_enable_clocks(struct tegra_powergate *pg)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	unsigned int i;
76862306a36Sopenharmony_ci	int err;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	for (i = 0; i < pg->num_clks; i++) {
77162306a36Sopenharmony_ci		err = clk_prepare_enable(pg->clks[i]);
77262306a36Sopenharmony_ci		if (err)
77362306a36Sopenharmony_ci			goto out;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	return 0;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ciout:
77962306a36Sopenharmony_ci	while (i--)
78062306a36Sopenharmony_ci		clk_disable_unprepare(pg->clks[i]);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	return err;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic int tegra_powergate_power_up(struct tegra_powergate *pg,
78662306a36Sopenharmony_ci				    bool disable_clocks)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	int err;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	err = reset_control_assert(pg->reset);
79162306a36Sopenharmony_ci	if (err)
79262306a36Sopenharmony_ci		return err;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	usleep_range(10, 20);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	err = tegra_powergate_set(pg->pmc, pg->id, true);
79762306a36Sopenharmony_ci	if (err < 0)
79862306a36Sopenharmony_ci		return err;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	usleep_range(10, 20);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	err = tegra_powergate_prepare_clocks(pg);
80362306a36Sopenharmony_ci	if (err)
80462306a36Sopenharmony_ci		goto powergate_off;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	err = tegra_powergate_enable_clocks(pg);
80762306a36Sopenharmony_ci	if (err)
80862306a36Sopenharmony_ci		goto unprepare_clks;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	usleep_range(10, 20);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	err = __tegra_powergate_remove_clamping(pg->pmc, pg->id);
81362306a36Sopenharmony_ci	if (err)
81462306a36Sopenharmony_ci		goto disable_clks;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	usleep_range(10, 20);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	err = reset_control_deassert(pg->reset);
81962306a36Sopenharmony_ci	if (err)
82062306a36Sopenharmony_ci		goto disable_clks;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	usleep_range(10, 20);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if (pg->pmc->soc->needs_mbist_war)
82562306a36Sopenharmony_ci		err = tegra210_clk_handle_mbist_war(pg->id);
82662306a36Sopenharmony_ci	if (err)
82762306a36Sopenharmony_ci		goto disable_clks;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	if (disable_clocks)
83062306a36Sopenharmony_ci		tegra_powergate_disable_clocks(pg);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	err = tegra_powergate_unprepare_clocks(pg);
83362306a36Sopenharmony_ci	if (err)
83462306a36Sopenharmony_ci		return err;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return 0;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cidisable_clks:
83962306a36Sopenharmony_ci	tegra_powergate_disable_clocks(pg);
84062306a36Sopenharmony_ci	usleep_range(10, 20);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ciunprepare_clks:
84362306a36Sopenharmony_ci	tegra_powergate_unprepare_clocks(pg);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cipowergate_off:
84662306a36Sopenharmony_ci	tegra_powergate_set(pg->pmc, pg->id, false);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return err;
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic int tegra_powergate_power_down(struct tegra_powergate *pg)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	int err;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	err = tegra_powergate_prepare_clocks(pg);
85662306a36Sopenharmony_ci	if (err)
85762306a36Sopenharmony_ci		return err;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	err = tegra_powergate_enable_clocks(pg);
86062306a36Sopenharmony_ci	if (err)
86162306a36Sopenharmony_ci		goto unprepare_clks;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	usleep_range(10, 20);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	err = reset_control_assert(pg->reset);
86662306a36Sopenharmony_ci	if (err)
86762306a36Sopenharmony_ci		goto disable_clks;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	usleep_range(10, 20);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	tegra_powergate_disable_clocks(pg);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	usleep_range(10, 20);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	err = tegra_powergate_set(pg->pmc, pg->id, false);
87662306a36Sopenharmony_ci	if (err)
87762306a36Sopenharmony_ci		goto assert_resets;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	err = tegra_powergate_unprepare_clocks(pg);
88062306a36Sopenharmony_ci	if (err)
88162306a36Sopenharmony_ci		return err;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	return 0;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ciassert_resets:
88662306a36Sopenharmony_ci	tegra_powergate_enable_clocks(pg);
88762306a36Sopenharmony_ci	usleep_range(10, 20);
88862306a36Sopenharmony_ci	reset_control_deassert(pg->reset);
88962306a36Sopenharmony_ci	usleep_range(10, 20);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cidisable_clks:
89262306a36Sopenharmony_ci	tegra_powergate_disable_clocks(pg);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ciunprepare_clks:
89562306a36Sopenharmony_ci	tegra_powergate_unprepare_clocks(pg);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	return err;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int tegra_genpd_power_on(struct generic_pm_domain *domain)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	struct tegra_powergate *pg = to_powergate(domain);
90362306a36Sopenharmony_ci	struct device *dev = pg->pmc->dev;
90462306a36Sopenharmony_ci	int err;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	err = tegra_powergate_power_up(pg, true);
90762306a36Sopenharmony_ci	if (err) {
90862306a36Sopenharmony_ci		dev_err(dev, "failed to turn on PM domain %s: %d\n",
90962306a36Sopenharmony_ci			pg->genpd.name, err);
91062306a36Sopenharmony_ci		goto out;
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	reset_control_release(pg->reset);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ciout:
91662306a36Sopenharmony_ci	return err;
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic int tegra_genpd_power_off(struct generic_pm_domain *domain)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	struct tegra_powergate *pg = to_powergate(domain);
92262306a36Sopenharmony_ci	struct device *dev = pg->pmc->dev;
92362306a36Sopenharmony_ci	int err;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	err = reset_control_acquire(pg->reset);
92662306a36Sopenharmony_ci	if (err < 0) {
92762306a36Sopenharmony_ci		dev_err(dev, "failed to acquire resets for PM domain %s: %d\n",
92862306a36Sopenharmony_ci			pg->genpd.name, err);
92962306a36Sopenharmony_ci		return err;
93062306a36Sopenharmony_ci	}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	err = tegra_powergate_power_down(pg);
93362306a36Sopenharmony_ci	if (err) {
93462306a36Sopenharmony_ci		dev_err(dev, "failed to turn off PM domain %s: %d\n",
93562306a36Sopenharmony_ci			pg->genpd.name, err);
93662306a36Sopenharmony_ci		reset_control_release(pg->reset);
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	return err;
94062306a36Sopenharmony_ci}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci/**
94362306a36Sopenharmony_ci * tegra_powergate_power_on() - power on partition
94462306a36Sopenharmony_ci * @id: partition ID
94562306a36Sopenharmony_ci */
94662306a36Sopenharmony_ciint tegra_powergate_power_on(unsigned int id)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	if (!tegra_powergate_is_available(pmc, id))
94962306a36Sopenharmony_ci		return -EINVAL;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	return tegra_powergate_set(pmc, id, true);
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ciEXPORT_SYMBOL(tegra_powergate_power_on);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci/**
95662306a36Sopenharmony_ci * tegra_powergate_power_off() - power off partition
95762306a36Sopenharmony_ci * @id: partition ID
95862306a36Sopenharmony_ci */
95962306a36Sopenharmony_ciint tegra_powergate_power_off(unsigned int id)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	if (!tegra_powergate_is_available(pmc, id))
96262306a36Sopenharmony_ci		return -EINVAL;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	return tegra_powergate_set(pmc, id, false);
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ciEXPORT_SYMBOL(tegra_powergate_power_off);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci/**
96962306a36Sopenharmony_ci * tegra_powergate_is_powered() - check if partition is powered
97062306a36Sopenharmony_ci * @pmc: power management controller
97162306a36Sopenharmony_ci * @id: partition ID
97262306a36Sopenharmony_ci */
97362306a36Sopenharmony_cistatic int tegra_powergate_is_powered(struct tegra_pmc *pmc, unsigned int id)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	if (!tegra_powergate_is_valid(pmc, id))
97662306a36Sopenharmony_ci		return -EINVAL;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	return tegra_powergate_state(id);
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci/**
98262306a36Sopenharmony_ci * tegra_powergate_remove_clamping() - remove power clamps for partition
98362306a36Sopenharmony_ci * @id: partition ID
98462306a36Sopenharmony_ci */
98562306a36Sopenharmony_ciint tegra_powergate_remove_clamping(unsigned int id)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	if (!tegra_powergate_is_available(pmc, id))
98862306a36Sopenharmony_ci		return -EINVAL;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	return __tegra_powergate_remove_clamping(pmc, id);
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ciEXPORT_SYMBOL(tegra_powergate_remove_clamping);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci/**
99562306a36Sopenharmony_ci * tegra_powergate_sequence_power_up() - power up partition
99662306a36Sopenharmony_ci * @id: partition ID
99762306a36Sopenharmony_ci * @clk: clock for partition
99862306a36Sopenharmony_ci * @rst: reset for partition
99962306a36Sopenharmony_ci *
100062306a36Sopenharmony_ci * Must be called with clk disabled, and returns with clk enabled.
100162306a36Sopenharmony_ci */
100262306a36Sopenharmony_ciint tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
100362306a36Sopenharmony_ci				      struct reset_control *rst)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	struct tegra_powergate *pg;
100662306a36Sopenharmony_ci	int err;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (!tegra_powergate_is_available(pmc, id))
100962306a36Sopenharmony_ci		return -EINVAL;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	pg = kzalloc(sizeof(*pg), GFP_KERNEL);
101262306a36Sopenharmony_ci	if (!pg)
101362306a36Sopenharmony_ci		return -ENOMEM;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	pg->clk_rates = kzalloc(sizeof(*pg->clk_rates), GFP_KERNEL);
101662306a36Sopenharmony_ci	if (!pg->clk_rates) {
101762306a36Sopenharmony_ci		kfree(pg->clks);
101862306a36Sopenharmony_ci		return -ENOMEM;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	pg->id = id;
102262306a36Sopenharmony_ci	pg->clks = &clk;
102362306a36Sopenharmony_ci	pg->num_clks = 1;
102462306a36Sopenharmony_ci	pg->reset = rst;
102562306a36Sopenharmony_ci	pg->pmc = pmc;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	err = tegra_powergate_power_up(pg, false);
102862306a36Sopenharmony_ci	if (err)
102962306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to turn on partition %d: %d\n", id,
103062306a36Sopenharmony_ci			err);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	kfree(pg->clk_rates);
103362306a36Sopenharmony_ci	kfree(pg);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	return err;
103662306a36Sopenharmony_ci}
103762306a36Sopenharmony_ciEXPORT_SYMBOL(tegra_powergate_sequence_power_up);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci/**
104062306a36Sopenharmony_ci * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
104162306a36Sopenharmony_ci * @pmc: power management controller
104262306a36Sopenharmony_ci * @cpuid: CPU partition ID
104362306a36Sopenharmony_ci *
104462306a36Sopenharmony_ci * Returns the partition ID corresponding to the CPU partition ID or a
104562306a36Sopenharmony_ci * negative error code on failure.
104662306a36Sopenharmony_ci */
104762306a36Sopenharmony_cistatic int tegra_get_cpu_powergate_id(struct tegra_pmc *pmc,
104862306a36Sopenharmony_ci				      unsigned int cpuid)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates)
105162306a36Sopenharmony_ci		return pmc->soc->cpu_powergates[cpuid];
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	return -EINVAL;
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci/**
105762306a36Sopenharmony_ci * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
105862306a36Sopenharmony_ci * @cpuid: CPU partition ID
105962306a36Sopenharmony_ci */
106062306a36Sopenharmony_cibool tegra_pmc_cpu_is_powered(unsigned int cpuid)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	int id;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	id = tegra_get_cpu_powergate_id(pmc, cpuid);
106562306a36Sopenharmony_ci	if (id < 0)
106662306a36Sopenharmony_ci		return false;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	return tegra_powergate_is_powered(pmc, id);
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci/**
107262306a36Sopenharmony_ci * tegra_pmc_cpu_power_on() - power on CPU partition
107362306a36Sopenharmony_ci * @cpuid: CPU partition ID
107462306a36Sopenharmony_ci */
107562306a36Sopenharmony_ciint tegra_pmc_cpu_power_on(unsigned int cpuid)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	int id;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	id = tegra_get_cpu_powergate_id(pmc, cpuid);
108062306a36Sopenharmony_ci	if (id < 0)
108162306a36Sopenharmony_ci		return id;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	return tegra_powergate_set(pmc, id, true);
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci/**
108762306a36Sopenharmony_ci * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
108862306a36Sopenharmony_ci * @cpuid: CPU partition ID
108962306a36Sopenharmony_ci */
109062306a36Sopenharmony_ciint tegra_pmc_cpu_remove_clamping(unsigned int cpuid)
109162306a36Sopenharmony_ci{
109262306a36Sopenharmony_ci	int id;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	id = tegra_get_cpu_powergate_id(pmc, cpuid);
109562306a36Sopenharmony_ci	if (id < 0)
109662306a36Sopenharmony_ci		return id;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	return tegra_powergate_remove_clamping(id);
109962306a36Sopenharmony_ci}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic void tegra_pmc_program_reboot_reason(const char *cmd)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	u32 value;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	value = tegra_pmc_scratch_readl(pmc, pmc->soc->regs->scratch0);
110662306a36Sopenharmony_ci	value &= ~PMC_SCRATCH0_MODE_MASK;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	if (cmd) {
110962306a36Sopenharmony_ci		if (strcmp(cmd, "recovery") == 0)
111062306a36Sopenharmony_ci			value |= PMC_SCRATCH0_MODE_RECOVERY;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci		if (strcmp(cmd, "bootloader") == 0)
111362306a36Sopenharmony_ci			value |= PMC_SCRATCH0_MODE_BOOTLOADER;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci		if (strcmp(cmd, "forced-recovery") == 0)
111662306a36Sopenharmony_ci			value |= PMC_SCRATCH0_MODE_RCM;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	tegra_pmc_scratch_writel(pmc, value, pmc->soc->regs->scratch0);
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cistatic int tegra_pmc_reboot_notify(struct notifier_block *this,
112362306a36Sopenharmony_ci				   unsigned long action, void *data)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	if (action == SYS_RESTART)
112662306a36Sopenharmony_ci		tegra_pmc_program_reboot_reason(data);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	return NOTIFY_DONE;
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_cistatic struct notifier_block tegra_pmc_reboot_notifier = {
113262306a36Sopenharmony_ci	.notifier_call = tegra_pmc_reboot_notify,
113362306a36Sopenharmony_ci};
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_cistatic void tegra_pmc_restart(void)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	u32 value;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	/* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */
114062306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, PMC_CNTRL);
114162306a36Sopenharmony_ci	value |= PMC_CNTRL_MAIN_RST;
114262306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_CNTRL);
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_cistatic int tegra_pmc_restart_handler(struct sys_off_data *data)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	tegra_pmc_restart();
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	return NOTIFY_DONE;
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic int tegra_pmc_power_off_handler(struct sys_off_data *data)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	/*
115562306a36Sopenharmony_ci	 * Reboot Nexus 7 into special bootloader mode if USB cable is
115662306a36Sopenharmony_ci	 * connected in order to display battery status and power off.
115762306a36Sopenharmony_ci	 */
115862306a36Sopenharmony_ci	if (of_machine_is_compatible("asus,grouper") &&
115962306a36Sopenharmony_ci	    power_supply_is_system_supplied()) {
116062306a36Sopenharmony_ci		const u32 go_to_charger_mode = 0xa5a55a5a;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci		tegra_pmc_writel(pmc, go_to_charger_mode, PMC_SCRATCH37);
116362306a36Sopenharmony_ci		tegra_pmc_restart();
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	return NOTIFY_DONE;
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic int powergate_show(struct seq_file *s, void *data)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	unsigned int i;
117262306a36Sopenharmony_ci	int status;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	seq_printf(s, " powergate powered\n");
117562306a36Sopenharmony_ci	seq_printf(s, "------------------\n");
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->num_powergates; i++) {
117862306a36Sopenharmony_ci		status = tegra_powergate_is_powered(pmc, i);
117962306a36Sopenharmony_ci		if (status < 0)
118062306a36Sopenharmony_ci			continue;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i],
118362306a36Sopenharmony_ci			   status ? "yes" : "no");
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	return 0;
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(powergate);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistatic int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
119262306a36Sopenharmony_ci				       struct device_node *np)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	struct clk *clk;
119562306a36Sopenharmony_ci	unsigned int i, count;
119662306a36Sopenharmony_ci	int err;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	count = of_clk_get_parent_count(np);
119962306a36Sopenharmony_ci	if (count == 0)
120062306a36Sopenharmony_ci		return -ENODEV;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	pg->clks = kcalloc(count, sizeof(clk), GFP_KERNEL);
120362306a36Sopenharmony_ci	if (!pg->clks)
120462306a36Sopenharmony_ci		return -ENOMEM;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	pg->clk_rates = kcalloc(count, sizeof(*pg->clk_rates), GFP_KERNEL);
120762306a36Sopenharmony_ci	if (!pg->clk_rates) {
120862306a36Sopenharmony_ci		kfree(pg->clks);
120962306a36Sopenharmony_ci		return -ENOMEM;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
121362306a36Sopenharmony_ci		pg->clks[i] = of_clk_get(np, i);
121462306a36Sopenharmony_ci		if (IS_ERR(pg->clks[i])) {
121562306a36Sopenharmony_ci			err = PTR_ERR(pg->clks[i]);
121662306a36Sopenharmony_ci			goto err;
121762306a36Sopenharmony_ci		}
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	pg->num_clks = count;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	return 0;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_cierr:
122562306a36Sopenharmony_ci	while (i--)
122662306a36Sopenharmony_ci		clk_put(pg->clks[i]);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	kfree(pg->clk_rates);
122962306a36Sopenharmony_ci	kfree(pg->clks);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	return err;
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
123562306a36Sopenharmony_ci					 struct device_node *np, bool off)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct device *dev = pg->pmc->dev;
123862306a36Sopenharmony_ci	int err;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	pg->reset = of_reset_control_array_get_exclusive_released(np);
124162306a36Sopenharmony_ci	if (IS_ERR(pg->reset)) {
124262306a36Sopenharmony_ci		err = PTR_ERR(pg->reset);
124362306a36Sopenharmony_ci		dev_err(dev, "failed to get device resets: %d\n", err);
124462306a36Sopenharmony_ci		return err;
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	err = reset_control_acquire(pg->reset);
124862306a36Sopenharmony_ci	if (err < 0) {
124962306a36Sopenharmony_ci		pr_err("failed to acquire resets: %d\n", err);
125062306a36Sopenharmony_ci		goto out;
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (off) {
125462306a36Sopenharmony_ci		err = reset_control_assert(pg->reset);
125562306a36Sopenharmony_ci	} else {
125662306a36Sopenharmony_ci		err = reset_control_deassert(pg->reset);
125762306a36Sopenharmony_ci		if (err < 0)
125862306a36Sopenharmony_ci			goto out;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci		reset_control_release(pg->reset);
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ciout:
126462306a36Sopenharmony_ci	if (err) {
126562306a36Sopenharmony_ci		reset_control_release(pg->reset);
126662306a36Sopenharmony_ci		reset_control_put(pg->reset);
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	return err;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	struct device *dev = pmc->dev;
127562306a36Sopenharmony_ci	struct tegra_powergate *pg;
127662306a36Sopenharmony_ci	int id, err = 0;
127762306a36Sopenharmony_ci	bool off;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	pg = kzalloc(sizeof(*pg), GFP_KERNEL);
128062306a36Sopenharmony_ci	if (!pg)
128162306a36Sopenharmony_ci		return -ENOMEM;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	id = tegra_powergate_lookup(pmc, np->name);
128462306a36Sopenharmony_ci	if (id < 0) {
128562306a36Sopenharmony_ci		dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id);
128662306a36Sopenharmony_ci		err = -ENODEV;
128762306a36Sopenharmony_ci		goto free_mem;
128862306a36Sopenharmony_ci	}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/*
129162306a36Sopenharmony_ci	 * Clear the bit for this powergate so it cannot be managed
129262306a36Sopenharmony_ci	 * directly via the legacy APIs for controlling powergates.
129362306a36Sopenharmony_ci	 */
129462306a36Sopenharmony_ci	clear_bit(id, pmc->powergates_available);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	pg->id = id;
129762306a36Sopenharmony_ci	pg->genpd.name = np->name;
129862306a36Sopenharmony_ci	pg->genpd.power_off = tegra_genpd_power_off;
129962306a36Sopenharmony_ci	pg->genpd.power_on = tegra_genpd_power_on;
130062306a36Sopenharmony_ci	pg->pmc = pmc;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	off = !tegra_powergate_is_powered(pmc, pg->id);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	err = tegra_powergate_of_get_clks(pg, np);
130562306a36Sopenharmony_ci	if (err < 0) {
130662306a36Sopenharmony_ci		dev_err(dev, "failed to get clocks for %pOFn: %d\n", np, err);
130762306a36Sopenharmony_ci		goto set_available;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	err = tegra_powergate_of_get_resets(pg, np, off);
131162306a36Sopenharmony_ci	if (err < 0) {
131262306a36Sopenharmony_ci		dev_err(dev, "failed to get resets for %pOFn: %d\n", np, err);
131362306a36Sopenharmony_ci		goto remove_clks;
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
131762306a36Sopenharmony_ci		if (off)
131862306a36Sopenharmony_ci			WARN_ON(tegra_powergate_power_up(pg, true));
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci		goto remove_resets;
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	err = pm_genpd_init(&pg->genpd, NULL, off);
132462306a36Sopenharmony_ci	if (err < 0) {
132562306a36Sopenharmony_ci		dev_err(dev, "failed to initialise PM domain %pOFn: %d\n", np,
132662306a36Sopenharmony_ci		       err);
132762306a36Sopenharmony_ci		goto remove_resets;
132862306a36Sopenharmony_ci	}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	err = of_genpd_add_provider_simple(np, &pg->genpd);
133162306a36Sopenharmony_ci	if (err < 0) {
133262306a36Sopenharmony_ci		dev_err(dev, "failed to add PM domain provider for %pOFn: %d\n",
133362306a36Sopenharmony_ci			np, err);
133462306a36Sopenharmony_ci		goto remove_genpd;
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	dev_dbg(dev, "added PM domain %s\n", pg->genpd.name);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	return 0;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ciremove_genpd:
134262306a36Sopenharmony_ci	pm_genpd_remove(&pg->genpd);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ciremove_resets:
134562306a36Sopenharmony_ci	reset_control_put(pg->reset);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ciremove_clks:
134862306a36Sopenharmony_ci	while (pg->num_clks--)
134962306a36Sopenharmony_ci		clk_put(pg->clks[pg->num_clks]);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	kfree(pg->clks);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ciset_available:
135462306a36Sopenharmony_ci	set_bit(id, pmc->powergates_available);
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_cifree_mem:
135762306a36Sopenharmony_ci	kfree(pg);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	return err;
136062306a36Sopenharmony_ci}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_cibool tegra_pmc_core_domain_state_synced(void)
136362306a36Sopenharmony_ci{
136462306a36Sopenharmony_ci	return pmc->core_domain_state_synced;
136562306a36Sopenharmony_ci}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_cistatic int
136862306a36Sopenharmony_citegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
136962306a36Sopenharmony_ci					unsigned int level)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	struct dev_pm_opp *opp;
137262306a36Sopenharmony_ci	int err;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level);
137562306a36Sopenharmony_ci	if (IS_ERR(opp)) {
137662306a36Sopenharmony_ci		dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n",
137762306a36Sopenharmony_ci			level, opp);
137862306a36Sopenharmony_ci		return PTR_ERR(opp);
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	mutex_lock(&pmc->powergates_lock);
138262306a36Sopenharmony_ci	err = dev_pm_opp_set_opp(pmc->dev, opp);
138362306a36Sopenharmony_ci	mutex_unlock(&pmc->powergates_lock);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	dev_pm_opp_put(opp);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if (err) {
138862306a36Sopenharmony_ci		dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n",
138962306a36Sopenharmony_ci			level, err);
139062306a36Sopenharmony_ci		return err;
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	return 0;
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic unsigned int
139762306a36Sopenharmony_citegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
139862306a36Sopenharmony_ci					   struct dev_pm_opp *opp)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	return dev_pm_opp_get_level(opp);
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_cistatic int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
140462306a36Sopenharmony_ci{
140562306a36Sopenharmony_ci	struct generic_pm_domain *genpd;
140662306a36Sopenharmony_ci	const char *rname[] = { "core", NULL};
140762306a36Sopenharmony_ci	int err;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
141062306a36Sopenharmony_ci	if (!genpd)
141162306a36Sopenharmony_ci		return -ENOMEM;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	genpd->name = "core";
141462306a36Sopenharmony_ci	genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
141562306a36Sopenharmony_ci	genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	err = devm_pm_opp_set_regulators(pmc->dev, rname);
141862306a36Sopenharmony_ci	if (err)
141962306a36Sopenharmony_ci		return dev_err_probe(pmc->dev, err,
142062306a36Sopenharmony_ci				     "failed to set core OPP regulator\n");
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	err = pm_genpd_init(genpd, NULL, false);
142362306a36Sopenharmony_ci	if (err) {
142462306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to init core genpd: %d\n", err);
142562306a36Sopenharmony_ci		return err;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	err = of_genpd_add_provider_simple(np, genpd);
142962306a36Sopenharmony_ci	if (err) {
143062306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to add core genpd: %d\n", err);
143162306a36Sopenharmony_ci		goto remove_genpd;
143262306a36Sopenharmony_ci	}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	pmc->core_domain_registered = true;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	return 0;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ciremove_genpd:
143962306a36Sopenharmony_ci	pm_genpd_remove(genpd);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	return err;
144262306a36Sopenharmony_ci}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic int tegra_powergate_init(struct tegra_pmc *pmc,
144562306a36Sopenharmony_ci				struct device_node *parent)
144662306a36Sopenharmony_ci{
144762306a36Sopenharmony_ci	struct of_phandle_args child_args, parent_args;
144862306a36Sopenharmony_ci	struct device_node *np, *child;
144962306a36Sopenharmony_ci	int err = 0;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	/*
145262306a36Sopenharmony_ci	 * Core power domain is the parent of powergate domains, hence it
145362306a36Sopenharmony_ci	 * should be registered first.
145462306a36Sopenharmony_ci	 */
145562306a36Sopenharmony_ci	np = of_get_child_by_name(parent, "core-domain");
145662306a36Sopenharmony_ci	if (np) {
145762306a36Sopenharmony_ci		err = tegra_pmc_core_pd_add(pmc, np);
145862306a36Sopenharmony_ci		of_node_put(np);
145962306a36Sopenharmony_ci		if (err)
146062306a36Sopenharmony_ci			return err;
146162306a36Sopenharmony_ci	}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	np = of_get_child_by_name(parent, "powergates");
146462306a36Sopenharmony_ci	if (!np)
146562306a36Sopenharmony_ci		return 0;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	for_each_child_of_node(np, child) {
146862306a36Sopenharmony_ci		err = tegra_powergate_add(pmc, child);
146962306a36Sopenharmony_ci		if (err < 0) {
147062306a36Sopenharmony_ci			of_node_put(child);
147162306a36Sopenharmony_ci			break;
147262306a36Sopenharmony_ci		}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		if (of_parse_phandle_with_args(child, "power-domains",
147562306a36Sopenharmony_ci					       "#power-domain-cells",
147662306a36Sopenharmony_ci					       0, &parent_args))
147762306a36Sopenharmony_ci			continue;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		child_args.np = child;
148062306a36Sopenharmony_ci		child_args.args_count = 0;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci		err = of_genpd_add_subdomain(&parent_args, &child_args);
148362306a36Sopenharmony_ci		of_node_put(parent_args.np);
148462306a36Sopenharmony_ci		if (err) {
148562306a36Sopenharmony_ci			of_node_put(child);
148662306a36Sopenharmony_ci			break;
148762306a36Sopenharmony_ci		}
148862306a36Sopenharmony_ci	}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	of_node_put(np);
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	return err;
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic void tegra_powergate_remove(struct generic_pm_domain *genpd)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	struct tegra_powergate *pg = to_powergate(genpd);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	reset_control_put(pg->reset);
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	while (pg->num_clks--)
150262306a36Sopenharmony_ci		clk_put(pg->clks[pg->num_clks]);
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	kfree(pg->clks);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	set_bit(pg->id, pmc->powergates_available);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	kfree(pg);
150962306a36Sopenharmony_ci}
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_cistatic void tegra_powergate_remove_all(struct device_node *parent)
151262306a36Sopenharmony_ci{
151362306a36Sopenharmony_ci	struct generic_pm_domain *genpd;
151462306a36Sopenharmony_ci	struct device_node *np, *child;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	np = of_get_child_by_name(parent, "powergates");
151762306a36Sopenharmony_ci	if (!np)
151862306a36Sopenharmony_ci		return;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	for_each_child_of_node(np, child) {
152162306a36Sopenharmony_ci		of_genpd_del_provider(child);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci		genpd = of_genpd_remove_last(child);
152462306a36Sopenharmony_ci		if (IS_ERR(genpd))
152562306a36Sopenharmony_ci			continue;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci		tegra_powergate_remove(genpd);
152862306a36Sopenharmony_ci	}
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	of_node_put(np);
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	np = of_get_child_by_name(parent, "core-domain");
153362306a36Sopenharmony_ci	if (np) {
153462306a36Sopenharmony_ci		of_genpd_del_provider(np);
153562306a36Sopenharmony_ci		of_genpd_remove_last(np);
153662306a36Sopenharmony_ci	}
153762306a36Sopenharmony_ci}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cistatic const struct tegra_io_pad_soc *
154062306a36Sopenharmony_citegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	unsigned int i;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->num_io_pads; i++)
154562306a36Sopenharmony_ci		if (pmc->soc->io_pads[i].id == id)
154662306a36Sopenharmony_ci			return &pmc->soc->io_pads[i];
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	return NULL;
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_cistatic int tegra_io_pad_prepare(struct tegra_pmc *pmc,
155262306a36Sopenharmony_ci				const struct tegra_io_pad_soc *pad,
155362306a36Sopenharmony_ci				unsigned long *request,
155462306a36Sopenharmony_ci				unsigned long *status,
155562306a36Sopenharmony_ci				u32 *mask)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	unsigned long rate, value;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	if (pad->dpd == UINT_MAX)
156062306a36Sopenharmony_ci		return -EINVAL;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	*request = pad->request;
156362306a36Sopenharmony_ci	*status = pad->status;
156462306a36Sopenharmony_ci	*mask = BIT(pad->dpd);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (pmc->clk) {
156762306a36Sopenharmony_ci		rate = pmc->rate;
156862306a36Sopenharmony_ci		if (!rate) {
156962306a36Sopenharmony_ci			dev_err(pmc->dev, "failed to get clock rate\n");
157062306a36Sopenharmony_ci			return -ENODEV;
157162306a36Sopenharmony_ci		}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci		tegra_pmc_writel(pmc, DPD_SAMPLE_ENABLE, DPD_SAMPLE);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci		/* must be at least 200 ns, in APB (PCLK) clock cycles */
157662306a36Sopenharmony_ci		value = DIV_ROUND_UP(1000000000, rate);
157762306a36Sopenharmony_ci		value = DIV_ROUND_UP(200, value);
157862306a36Sopenharmony_ci		tegra_pmc_writel(pmc, value, SEL_DPD_TIM);
157962306a36Sopenharmony_ci	}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	return 0;
158262306a36Sopenharmony_ci}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_cistatic int tegra_io_pad_poll(struct tegra_pmc *pmc, unsigned long offset,
158562306a36Sopenharmony_ci			     u32 mask, u32 val, unsigned long timeout)
158662306a36Sopenharmony_ci{
158762306a36Sopenharmony_ci	u32 value;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(timeout);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	while (time_after(timeout, jiffies)) {
159262306a36Sopenharmony_ci		value = tegra_pmc_readl(pmc, offset);
159362306a36Sopenharmony_ci		if ((value & mask) == val)
159462306a36Sopenharmony_ci			return 0;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci		usleep_range(250, 1000);
159762306a36Sopenharmony_ci	}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	return -ETIMEDOUT;
160062306a36Sopenharmony_ci}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_cistatic void tegra_io_pad_unprepare(struct tegra_pmc *pmc)
160362306a36Sopenharmony_ci{
160462306a36Sopenharmony_ci	if (pmc->clk)
160562306a36Sopenharmony_ci		tegra_pmc_writel(pmc, DPD_SAMPLE_DISABLE, DPD_SAMPLE);
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci/**
160962306a36Sopenharmony_ci * tegra_io_pad_power_enable() - enable power to I/O pad
161062306a36Sopenharmony_ci * @id: Tegra I/O pad ID for which to enable power
161162306a36Sopenharmony_ci *
161262306a36Sopenharmony_ci * Returns: 0 on success or a negative error code on failure.
161362306a36Sopenharmony_ci */
161462306a36Sopenharmony_ciint tegra_io_pad_power_enable(enum tegra_io_pad id)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	const struct tegra_io_pad_soc *pad;
161762306a36Sopenharmony_ci	unsigned long request, status;
161862306a36Sopenharmony_ci	u32 mask;
161962306a36Sopenharmony_ci	int err;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	pad = tegra_io_pad_find(pmc, id);
162262306a36Sopenharmony_ci	if (!pad) {
162362306a36Sopenharmony_ci		dev_err(pmc->dev, "invalid I/O pad ID %u\n", id);
162462306a36Sopenharmony_ci		return -ENOENT;
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	mutex_lock(&pmc->powergates_lock);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	err = tegra_io_pad_prepare(pmc, pad, &request, &status, &mask);
163062306a36Sopenharmony_ci	if (err < 0) {
163162306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to prepare I/O pad: %d\n", err);
163262306a36Sopenharmony_ci		goto unlock;
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	tegra_pmc_writel(pmc, IO_DPD_REQ_CODE_OFF | mask, request);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	err = tegra_io_pad_poll(pmc, status, mask, 0, 250);
163862306a36Sopenharmony_ci	if (err < 0) {
163962306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to enable I/O pad: %d\n", err);
164062306a36Sopenharmony_ci		goto unlock;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	tegra_io_pad_unprepare(pmc);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ciunlock:
164662306a36Sopenharmony_ci	mutex_unlock(&pmc->powergates_lock);
164762306a36Sopenharmony_ci	return err;
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ciEXPORT_SYMBOL(tegra_io_pad_power_enable);
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci/**
165262306a36Sopenharmony_ci * tegra_io_pad_power_disable() - disable power to I/O pad
165362306a36Sopenharmony_ci * @id: Tegra I/O pad ID for which to disable power
165462306a36Sopenharmony_ci *
165562306a36Sopenharmony_ci * Returns: 0 on success or a negative error code on failure.
165662306a36Sopenharmony_ci */
165762306a36Sopenharmony_ciint tegra_io_pad_power_disable(enum tegra_io_pad id)
165862306a36Sopenharmony_ci{
165962306a36Sopenharmony_ci	const struct tegra_io_pad_soc *pad;
166062306a36Sopenharmony_ci	unsigned long request, status;
166162306a36Sopenharmony_ci	u32 mask;
166262306a36Sopenharmony_ci	int err;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	pad = tegra_io_pad_find(pmc, id);
166562306a36Sopenharmony_ci	if (!pad) {
166662306a36Sopenharmony_ci		dev_err(pmc->dev, "invalid I/O pad ID %u\n", id);
166762306a36Sopenharmony_ci		return -ENOENT;
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	mutex_lock(&pmc->powergates_lock);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	err = tegra_io_pad_prepare(pmc, pad, &request, &status, &mask);
167362306a36Sopenharmony_ci	if (err < 0) {
167462306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to prepare I/O pad: %d\n", err);
167562306a36Sopenharmony_ci		goto unlock;
167662306a36Sopenharmony_ci	}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	tegra_pmc_writel(pmc, IO_DPD_REQ_CODE_ON | mask, request);
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	err = tegra_io_pad_poll(pmc, status, mask, mask, 250);
168162306a36Sopenharmony_ci	if (err < 0) {
168262306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to disable I/O pad: %d\n", err);
168362306a36Sopenharmony_ci		goto unlock;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	tegra_io_pad_unprepare(pmc);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ciunlock:
168962306a36Sopenharmony_ci	mutex_unlock(&pmc->powergates_lock);
169062306a36Sopenharmony_ci	return err;
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ciEXPORT_SYMBOL(tegra_io_pad_power_disable);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_cistatic int tegra_io_pad_is_powered(struct tegra_pmc *pmc, enum tegra_io_pad id)
169562306a36Sopenharmony_ci{
169662306a36Sopenharmony_ci	const struct tegra_io_pad_soc *pad;
169762306a36Sopenharmony_ci	unsigned long status;
169862306a36Sopenharmony_ci	u32 mask, value;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	pad = tegra_io_pad_find(pmc, id);
170162306a36Sopenharmony_ci	if (!pad) {
170262306a36Sopenharmony_ci		dev_err(pmc->dev, "invalid I/O pad ID %u\n", id);
170362306a36Sopenharmony_ci		return -ENOENT;
170462306a36Sopenharmony_ci	}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	if (pad->dpd == UINT_MAX)
170762306a36Sopenharmony_ci		return -EINVAL;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	status = pad->status;
171062306a36Sopenharmony_ci	mask = BIT(pad->dpd);
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, status);
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	return !(value & mask);
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_cistatic int tegra_io_pad_set_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id,
171862306a36Sopenharmony_ci				    int voltage)
171962306a36Sopenharmony_ci{
172062306a36Sopenharmony_ci	const struct tegra_io_pad_soc *pad;
172162306a36Sopenharmony_ci	u32 value;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	pad = tegra_io_pad_find(pmc, id);
172462306a36Sopenharmony_ci	if (!pad)
172562306a36Sopenharmony_ci		return -ENOENT;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	if (pad->voltage == UINT_MAX)
172862306a36Sopenharmony_ci		return -ENOTSUPP;
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	mutex_lock(&pmc->powergates_lock);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (pmc->soc->has_impl_33v_pwr) {
173362306a36Sopenharmony_ci		value = tegra_pmc_readl(pmc, PMC_IMPL_E_33V_PWR);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci		if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8)
173662306a36Sopenharmony_ci			value &= ~BIT(pad->voltage);
173762306a36Sopenharmony_ci		else
173862306a36Sopenharmony_ci			value |= BIT(pad->voltage);
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		tegra_pmc_writel(pmc, value, PMC_IMPL_E_33V_PWR);
174162306a36Sopenharmony_ci	} else {
174262306a36Sopenharmony_ci		/* write-enable PMC_PWR_DET_VALUE[pad->voltage] */
174362306a36Sopenharmony_ci		value = tegra_pmc_readl(pmc, PMC_PWR_DET);
174462306a36Sopenharmony_ci		value |= BIT(pad->voltage);
174562306a36Sopenharmony_ci		tegra_pmc_writel(pmc, value, PMC_PWR_DET);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci		/* update I/O voltage */
174862306a36Sopenharmony_ci		value = tegra_pmc_readl(pmc, PMC_PWR_DET_VALUE);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci		if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8)
175162306a36Sopenharmony_ci			value &= ~BIT(pad->voltage);
175262306a36Sopenharmony_ci		else
175362306a36Sopenharmony_ci			value |= BIT(pad->voltage);
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci		tegra_pmc_writel(pmc, value, PMC_PWR_DET_VALUE);
175662306a36Sopenharmony_ci	}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	mutex_unlock(&pmc->powergates_lock);
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	usleep_range(100, 250);
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	return 0;
176362306a36Sopenharmony_ci}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_cistatic int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci	const struct tegra_io_pad_soc *pad;
176862306a36Sopenharmony_ci	u32 value;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	pad = tegra_io_pad_find(pmc, id);
177162306a36Sopenharmony_ci	if (!pad)
177262306a36Sopenharmony_ci		return -ENOENT;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (pad->voltage == UINT_MAX)
177562306a36Sopenharmony_ci		return -ENOTSUPP;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if (pmc->soc->has_impl_33v_pwr)
177862306a36Sopenharmony_ci		value = tegra_pmc_readl(pmc, PMC_IMPL_E_33V_PWR);
177962306a36Sopenharmony_ci	else
178062306a36Sopenharmony_ci		value = tegra_pmc_readl(pmc, PMC_PWR_DET_VALUE);
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	if ((value & BIT(pad->voltage)) == 0)
178362306a36Sopenharmony_ci		return TEGRA_IO_PAD_VOLTAGE_1V8;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	return TEGRA_IO_PAD_VOLTAGE_3V3;
178662306a36Sopenharmony_ci}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci/**
178962306a36Sopenharmony_ci * tegra_io_rail_power_on() - enable power to I/O rail
179062306a36Sopenharmony_ci * @id: Tegra I/O pad ID for which to enable power
179162306a36Sopenharmony_ci *
179262306a36Sopenharmony_ci * See also: tegra_io_pad_power_enable()
179362306a36Sopenharmony_ci */
179462306a36Sopenharmony_ciint tegra_io_rail_power_on(unsigned int id)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	return tegra_io_pad_power_enable(id);
179762306a36Sopenharmony_ci}
179862306a36Sopenharmony_ciEXPORT_SYMBOL(tegra_io_rail_power_on);
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci/**
180162306a36Sopenharmony_ci * tegra_io_rail_power_off() - disable power to I/O rail
180262306a36Sopenharmony_ci * @id: Tegra I/O pad ID for which to disable power
180362306a36Sopenharmony_ci *
180462306a36Sopenharmony_ci * See also: tegra_io_pad_power_disable()
180562306a36Sopenharmony_ci */
180662306a36Sopenharmony_ciint tegra_io_rail_power_off(unsigned int id)
180762306a36Sopenharmony_ci{
180862306a36Sopenharmony_ci	return tegra_io_pad_power_disable(id);
180962306a36Sopenharmony_ci}
181062306a36Sopenharmony_ciEXPORT_SYMBOL(tegra_io_rail_power_off);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
181362306a36Sopenharmony_cienum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
181462306a36Sopenharmony_ci{
181562306a36Sopenharmony_ci	return pmc->suspend_mode;
181662306a36Sopenharmony_ci}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_civoid tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
181962306a36Sopenharmony_ci{
182062306a36Sopenharmony_ci	if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
182162306a36Sopenharmony_ci		return;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	pmc->suspend_mode = mode;
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_civoid tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
182762306a36Sopenharmony_ci{
182862306a36Sopenharmony_ci	unsigned long long rate = 0;
182962306a36Sopenharmony_ci	u64 ticks;
183062306a36Sopenharmony_ci	u32 value;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	switch (mode) {
183362306a36Sopenharmony_ci	case TEGRA_SUSPEND_LP1:
183462306a36Sopenharmony_ci		rate = 32768;
183562306a36Sopenharmony_ci		break;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	case TEGRA_SUSPEND_LP2:
183862306a36Sopenharmony_ci		rate = pmc->rate;
183962306a36Sopenharmony_ci		break;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	default:
184262306a36Sopenharmony_ci		break;
184362306a36Sopenharmony_ci	}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if (WARN_ON_ONCE(rate == 0))
184662306a36Sopenharmony_ci		rate = 100000000;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
184962306a36Sopenharmony_ci	do_div(ticks, USEC_PER_SEC);
185062306a36Sopenharmony_ci	tegra_pmc_writel(pmc, ticks, PMC_CPUPWRGOOD_TIMER);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
185362306a36Sopenharmony_ci	do_div(ticks, USEC_PER_SEC);
185462306a36Sopenharmony_ci	tegra_pmc_writel(pmc, ticks, PMC_CPUPWROFF_TIMER);
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, PMC_CNTRL);
185762306a36Sopenharmony_ci	value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
185862306a36Sopenharmony_ci	value |= PMC_CNTRL_CPU_PWRREQ_OE;
185962306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_CNTRL);
186062306a36Sopenharmony_ci}
186162306a36Sopenharmony_ci#endif
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	u32 value, values[2];
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) {
186862306a36Sopenharmony_ci		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
186962306a36Sopenharmony_ci	} else {
187062306a36Sopenharmony_ci		switch (value) {
187162306a36Sopenharmony_ci		case 0:
187262306a36Sopenharmony_ci			pmc->suspend_mode = TEGRA_SUSPEND_LP0;
187362306a36Sopenharmony_ci			break;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci		case 1:
187662306a36Sopenharmony_ci			pmc->suspend_mode = TEGRA_SUSPEND_LP1;
187762306a36Sopenharmony_ci			break;
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci		case 2:
188062306a36Sopenharmony_ci			pmc->suspend_mode = TEGRA_SUSPEND_LP2;
188162306a36Sopenharmony_ci			break;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci		default:
188462306a36Sopenharmony_ci			pmc->suspend_mode = TEGRA_SUSPEND_NONE;
188562306a36Sopenharmony_ci			break;
188662306a36Sopenharmony_ci		}
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	pmc->suspend_mode = tegra_pm_validate_suspend_mode(pmc->suspend_mode);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &value))
189262306a36Sopenharmony_ci		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	pmc->cpu_good_time = value;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &value))
189762306a36Sopenharmony_ci		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	pmc->cpu_off_time = value;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time",
190262306a36Sopenharmony_ci				       values, ARRAY_SIZE(values)))
190362306a36Sopenharmony_ci		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	pmc->core_osc_time = values[0];
190662306a36Sopenharmony_ci	pmc->core_pmu_time = values[1];
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,core-pwr-off-time", &value))
190962306a36Sopenharmony_ci		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	pmc->core_off_time = value;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	pmc->corereq_high = of_property_read_bool(np,
191462306a36Sopenharmony_ci				"nvidia,core-power-req-active-high");
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	pmc->sysclkreq_high = of_property_read_bool(np,
191762306a36Sopenharmony_ci				"nvidia,sys-clock-req-active-high");
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	pmc->combined_req = of_property_read_bool(np,
192062306a36Sopenharmony_ci				"nvidia,combined-power-req");
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	pmc->cpu_pwr_good_en = of_property_read_bool(np,
192362306a36Sopenharmony_ci				"nvidia,cpu-pwr-good-en");
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	if (of_property_read_u32_array(np, "nvidia,lp0-vec", values,
192662306a36Sopenharmony_ci				       ARRAY_SIZE(values)))
192762306a36Sopenharmony_ci		if (pmc->suspend_mode == TEGRA_SUSPEND_LP0)
192862306a36Sopenharmony_ci			pmc->suspend_mode = TEGRA_SUSPEND_LP1;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	pmc->lp0_vec_phys = values[0];
193162306a36Sopenharmony_ci	pmc->lp0_vec_size = values[1];
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	return 0;
193462306a36Sopenharmony_ci}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_cistatic int tegra_pmc_init(struct tegra_pmc *pmc)
193762306a36Sopenharmony_ci{
193862306a36Sopenharmony_ci	if (pmc->soc->max_wake_events > 0) {
193962306a36Sopenharmony_ci		pmc->wake_type_level_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
194062306a36Sopenharmony_ci		if (!pmc->wake_type_level_map)
194162306a36Sopenharmony_ci			return -ENOMEM;
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci		pmc->wake_type_dual_edge_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
194462306a36Sopenharmony_ci		if (!pmc->wake_type_dual_edge_map)
194562306a36Sopenharmony_ci			return -ENOMEM;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci		pmc->wake_sw_status_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
194862306a36Sopenharmony_ci		if (!pmc->wake_sw_status_map)
194962306a36Sopenharmony_ci			return -ENOMEM;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci		pmc->wake_cntrl_level_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
195262306a36Sopenharmony_ci		if (!pmc->wake_cntrl_level_map)
195362306a36Sopenharmony_ci			return -ENOMEM;
195462306a36Sopenharmony_ci	}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	if (pmc->soc->init)
195762306a36Sopenharmony_ci		pmc->soc->init(pmc);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	return 0;
196062306a36Sopenharmony_ci}
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_cistatic void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	static const char disabled[] = "emergency thermal reset disabled";
196562306a36Sopenharmony_ci	u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux;
196662306a36Sopenharmony_ci	struct device *dev = pmc->dev;
196762306a36Sopenharmony_ci	struct device_node *np;
196862306a36Sopenharmony_ci	u32 value, checksum;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	if (!pmc->soc->has_tsense_reset)
197162306a36Sopenharmony_ci		return;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	np = of_get_child_by_name(pmc->dev->of_node, "i2c-thermtrip");
197462306a36Sopenharmony_ci	if (!np) {
197562306a36Sopenharmony_ci		dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
197662306a36Sopenharmony_ci		return;
197762306a36Sopenharmony_ci	}
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) {
198062306a36Sopenharmony_ci		dev_err(dev, "I2C controller ID missing, %s.\n", disabled);
198162306a36Sopenharmony_ci		goto out;
198262306a36Sopenharmony_ci	}
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,bus-addr", &pmu_addr)) {
198562306a36Sopenharmony_ci		dev_err(dev, "nvidia,bus-addr missing, %s.\n", disabled);
198662306a36Sopenharmony_ci		goto out;
198762306a36Sopenharmony_ci	}
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,reg-addr", &reg_addr)) {
199062306a36Sopenharmony_ci		dev_err(dev, "nvidia,reg-addr missing, %s.\n", disabled);
199162306a36Sopenharmony_ci		goto out;
199262306a36Sopenharmony_ci	}
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,reg-data", &reg_data)) {
199562306a36Sopenharmony_ci		dev_err(dev, "nvidia,reg-data missing, %s.\n", disabled);
199662306a36Sopenharmony_ci		goto out;
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	if (of_property_read_u32(np, "nvidia,pinmux-id", &pinmux))
200062306a36Sopenharmony_ci		pinmux = 0;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, PMC_SENSOR_CTRL);
200362306a36Sopenharmony_ci	value |= PMC_SENSOR_CTRL_SCRATCH_WRITE;
200462306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_SENSOR_CTRL);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) |
200762306a36Sopenharmony_ci		(reg_addr << PMC_SCRATCH54_ADDR_SHIFT);
200862306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_SCRATCH54);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	value = PMC_SCRATCH55_RESET_TEGRA;
201162306a36Sopenharmony_ci	value |= ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT;
201262306a36Sopenharmony_ci	value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT;
201362306a36Sopenharmony_ci	value |= pmu_addr << PMC_SCRATCH55_I2CSLV1_SHIFT;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	/*
201662306a36Sopenharmony_ci	 * Calculate checksum of SCRATCH54, SCRATCH55 fields. Bits 23:16 will
201762306a36Sopenharmony_ci	 * contain the checksum and are currently zero, so they are not added.
201862306a36Sopenharmony_ci	 */
201962306a36Sopenharmony_ci	checksum = reg_addr + reg_data + (value & 0xff) + ((value >> 8) & 0xff)
202062306a36Sopenharmony_ci		+ ((value >> 24) & 0xff);
202162306a36Sopenharmony_ci	checksum &= 0xff;
202262306a36Sopenharmony_ci	checksum = 0x100 - checksum;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	value |= checksum << PMC_SCRATCH55_CHECKSUM_SHIFT;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_SCRATCH55);
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, PMC_SENSOR_CTRL);
202962306a36Sopenharmony_ci	value |= PMC_SENSOR_CTRL_ENABLE_RST;
203062306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_SENSOR_CTRL);
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	dev_info(pmc->dev, "emergency thermal reset enabled\n");
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ciout:
203562306a36Sopenharmony_ci	of_node_put(np);
203662306a36Sopenharmony_ci}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_cistatic int tegra_io_pad_pinctrl_get_groups_count(struct pinctrl_dev *pctl_dev)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl_dev);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	return pmc->soc->num_io_pads;
204362306a36Sopenharmony_ci}
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_cistatic const char *tegra_io_pad_pinctrl_get_group_name(struct pinctrl_dev *pctl,
204662306a36Sopenharmony_ci						       unsigned int group)
204762306a36Sopenharmony_ci{
204862306a36Sopenharmony_ci	struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl);
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	return pmc->soc->io_pads[group].name;
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_cistatic int tegra_io_pad_pinctrl_get_group_pins(struct pinctrl_dev *pctl_dev,
205462306a36Sopenharmony_ci					       unsigned int group,
205562306a36Sopenharmony_ci					       const unsigned int **pins,
205662306a36Sopenharmony_ci					       unsigned int *num_pins)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl_dev);
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	*pins = &pmc->soc->io_pads[group].id;
206162306a36Sopenharmony_ci	*num_pins = 1;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	return 0;
206462306a36Sopenharmony_ci}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_cistatic const struct pinctrl_ops tegra_io_pad_pinctrl_ops = {
206762306a36Sopenharmony_ci	.get_groups_count = tegra_io_pad_pinctrl_get_groups_count,
206862306a36Sopenharmony_ci	.get_group_name = tegra_io_pad_pinctrl_get_group_name,
206962306a36Sopenharmony_ci	.get_group_pins = tegra_io_pad_pinctrl_get_group_pins,
207062306a36Sopenharmony_ci	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
207162306a36Sopenharmony_ci	.dt_free_map = pinconf_generic_dt_free_map,
207262306a36Sopenharmony_ci};
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_cistatic int tegra_io_pad_pinconf_get(struct pinctrl_dev *pctl_dev,
207562306a36Sopenharmony_ci				    unsigned int pin, unsigned long *config)
207662306a36Sopenharmony_ci{
207762306a36Sopenharmony_ci	enum pin_config_param param = pinconf_to_config_param(*config);
207862306a36Sopenharmony_ci	struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl_dev);
207962306a36Sopenharmony_ci	const struct tegra_io_pad_soc *pad;
208062306a36Sopenharmony_ci	int ret;
208162306a36Sopenharmony_ci	u32 arg;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	pad = tegra_io_pad_find(pmc, pin);
208462306a36Sopenharmony_ci	if (!pad)
208562306a36Sopenharmony_ci		return -EINVAL;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	switch (param) {
208862306a36Sopenharmony_ci	case PIN_CONFIG_POWER_SOURCE:
208962306a36Sopenharmony_ci		ret = tegra_io_pad_get_voltage(pmc, pad->id);
209062306a36Sopenharmony_ci		if (ret < 0)
209162306a36Sopenharmony_ci			return ret;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci		arg = ret;
209462306a36Sopenharmony_ci		break;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	case PIN_CONFIG_MODE_LOW_POWER:
209762306a36Sopenharmony_ci		ret = tegra_io_pad_is_powered(pmc, pad->id);
209862306a36Sopenharmony_ci		if (ret < 0)
209962306a36Sopenharmony_ci			return ret;
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci		arg = !ret;
210262306a36Sopenharmony_ci		break;
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	default:
210562306a36Sopenharmony_ci		return -EINVAL;
210662306a36Sopenharmony_ci	}
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	*config = pinconf_to_config_packed(param, arg);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	return 0;
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_cistatic int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctl_dev,
211462306a36Sopenharmony_ci				    unsigned int pin, unsigned long *configs,
211562306a36Sopenharmony_ci				    unsigned int num_configs)
211662306a36Sopenharmony_ci{
211762306a36Sopenharmony_ci	struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl_dev);
211862306a36Sopenharmony_ci	const struct tegra_io_pad_soc *pad;
211962306a36Sopenharmony_ci	enum pin_config_param param;
212062306a36Sopenharmony_ci	unsigned int i;
212162306a36Sopenharmony_ci	int err;
212262306a36Sopenharmony_ci	u32 arg;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	pad = tegra_io_pad_find(pmc, pin);
212562306a36Sopenharmony_ci	if (!pad)
212662306a36Sopenharmony_ci		return -EINVAL;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	for (i = 0; i < num_configs; ++i) {
212962306a36Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
213062306a36Sopenharmony_ci		arg = pinconf_to_config_argument(configs[i]);
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci		switch (param) {
213362306a36Sopenharmony_ci		case PIN_CONFIG_MODE_LOW_POWER:
213462306a36Sopenharmony_ci			if (arg)
213562306a36Sopenharmony_ci				err = tegra_io_pad_power_disable(pad->id);
213662306a36Sopenharmony_ci			else
213762306a36Sopenharmony_ci				err = tegra_io_pad_power_enable(pad->id);
213862306a36Sopenharmony_ci			if (err)
213962306a36Sopenharmony_ci				return err;
214062306a36Sopenharmony_ci			break;
214162306a36Sopenharmony_ci		case PIN_CONFIG_POWER_SOURCE:
214262306a36Sopenharmony_ci			if (arg != TEGRA_IO_PAD_VOLTAGE_1V8 &&
214362306a36Sopenharmony_ci			    arg != TEGRA_IO_PAD_VOLTAGE_3V3)
214462306a36Sopenharmony_ci				return -EINVAL;
214562306a36Sopenharmony_ci			err = tegra_io_pad_set_voltage(pmc, pad->id, arg);
214662306a36Sopenharmony_ci			if (err)
214762306a36Sopenharmony_ci				return err;
214862306a36Sopenharmony_ci			break;
214962306a36Sopenharmony_ci		default:
215062306a36Sopenharmony_ci			return -EINVAL;
215162306a36Sopenharmony_ci		}
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	return 0;
215562306a36Sopenharmony_ci}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_cistatic const struct pinconf_ops tegra_io_pad_pinconf_ops = {
215862306a36Sopenharmony_ci	.pin_config_get = tegra_io_pad_pinconf_get,
215962306a36Sopenharmony_ci	.pin_config_set = tegra_io_pad_pinconf_set,
216062306a36Sopenharmony_ci	.is_generic = true,
216162306a36Sopenharmony_ci};
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cistatic struct pinctrl_desc tegra_pmc_pctl_desc = {
216462306a36Sopenharmony_ci	.pctlops = &tegra_io_pad_pinctrl_ops,
216562306a36Sopenharmony_ci	.confops = &tegra_io_pad_pinconf_ops,
216662306a36Sopenharmony_ci};
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_cistatic int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	int err;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	if (!pmc->soc->num_pin_descs)
217362306a36Sopenharmony_ci		return 0;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	tegra_pmc_pctl_desc.name = dev_name(pmc->dev);
217662306a36Sopenharmony_ci	tegra_pmc_pctl_desc.pins = pmc->soc->pin_descs;
217762306a36Sopenharmony_ci	tegra_pmc_pctl_desc.npins = pmc->soc->num_pin_descs;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	pmc->pctl_dev = devm_pinctrl_register(pmc->dev, &tegra_pmc_pctl_desc,
218062306a36Sopenharmony_ci					      pmc);
218162306a36Sopenharmony_ci	if (IS_ERR(pmc->pctl_dev)) {
218262306a36Sopenharmony_ci		err = PTR_ERR(pmc->pctl_dev);
218362306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to register pin controller: %d\n",
218462306a36Sopenharmony_ci			err);
218562306a36Sopenharmony_ci		return err;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	return 0;
218962306a36Sopenharmony_ci}
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_cistatic ssize_t reset_reason_show(struct device *dev,
219262306a36Sopenharmony_ci				 struct device_attribute *attr, char *buf)
219362306a36Sopenharmony_ci{
219462306a36Sopenharmony_ci	u32 value;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status);
219762306a36Sopenharmony_ci	value &= pmc->soc->regs->rst_source_mask;
219862306a36Sopenharmony_ci	value >>= pmc->soc->regs->rst_source_shift;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	if (WARN_ON(value >= pmc->soc->num_reset_sources))
220162306a36Sopenharmony_ci		return sprintf(buf, "%s\n", "UNKNOWN");
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	return sprintf(buf, "%s\n", pmc->soc->reset_sources[value]);
220462306a36Sopenharmony_ci}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(reset_reason);
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_cistatic ssize_t reset_level_show(struct device *dev,
220962306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
221062306a36Sopenharmony_ci{
221162306a36Sopenharmony_ci	u32 value;
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status);
221462306a36Sopenharmony_ci	value &= pmc->soc->regs->rst_level_mask;
221562306a36Sopenharmony_ci	value >>= pmc->soc->regs->rst_level_shift;
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	if (WARN_ON(value >= pmc->soc->num_reset_levels))
221862306a36Sopenharmony_ci		return sprintf(buf, "%s\n", "UNKNOWN");
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	return sprintf(buf, "%s\n", pmc->soc->reset_levels[value]);
222162306a36Sopenharmony_ci}
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(reset_level);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_cistatic void tegra_pmc_reset_sysfs_init(struct tegra_pmc *pmc)
222662306a36Sopenharmony_ci{
222762306a36Sopenharmony_ci	struct device *dev = pmc->dev;
222862306a36Sopenharmony_ci	int err = 0;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	if (pmc->soc->reset_sources) {
223162306a36Sopenharmony_ci		err = device_create_file(dev, &dev_attr_reset_reason);
223262306a36Sopenharmony_ci		if (err < 0)
223362306a36Sopenharmony_ci			dev_warn(dev,
223462306a36Sopenharmony_ci				 "failed to create attr \"reset_reason\": %d\n",
223562306a36Sopenharmony_ci				 err);
223662306a36Sopenharmony_ci	}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	if (pmc->soc->reset_levels) {
223962306a36Sopenharmony_ci		err = device_create_file(dev, &dev_attr_reset_level);
224062306a36Sopenharmony_ci		if (err < 0)
224162306a36Sopenharmony_ci			dev_warn(dev,
224262306a36Sopenharmony_ci				 "failed to create attr \"reset_level\": %d\n",
224362306a36Sopenharmony_ci				 err);
224462306a36Sopenharmony_ci	}
224562306a36Sopenharmony_ci}
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_cistatic int tegra_pmc_irq_translate(struct irq_domain *domain,
224862306a36Sopenharmony_ci				   struct irq_fwspec *fwspec,
224962306a36Sopenharmony_ci				   unsigned long *hwirq,
225062306a36Sopenharmony_ci				   unsigned int *type)
225162306a36Sopenharmony_ci{
225262306a36Sopenharmony_ci	if (WARN_ON(fwspec->param_count < 2))
225362306a36Sopenharmony_ci		return -EINVAL;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	*hwirq = fwspec->param[0];
225662306a36Sopenharmony_ci	*type = fwspec->param[1];
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	return 0;
225962306a36Sopenharmony_ci}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_cistatic int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
226262306a36Sopenharmony_ci			       unsigned int num_irqs, void *data)
226362306a36Sopenharmony_ci{
226462306a36Sopenharmony_ci	struct tegra_pmc *pmc = domain->host_data;
226562306a36Sopenharmony_ci	const struct tegra_pmc_soc *soc = pmc->soc;
226662306a36Sopenharmony_ci	struct irq_fwspec *fwspec = data;
226762306a36Sopenharmony_ci	unsigned int i;
226862306a36Sopenharmony_ci	int err = 0;
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	if (WARN_ON(num_irqs > 1))
227162306a36Sopenharmony_ci		return -EINVAL;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	for (i = 0; i < soc->num_wake_events; i++) {
227462306a36Sopenharmony_ci		const struct tegra_wake_event *event = &soc->wake_events[i];
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci		/* IRQ and simple wake events */
227762306a36Sopenharmony_ci		if (fwspec->param_count == 2) {
227862306a36Sopenharmony_ci			struct irq_fwspec spec;
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci			if (event->id != fwspec->param[0])
228162306a36Sopenharmony_ci				continue;
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci			err = irq_domain_set_hwirq_and_chip(domain, virq,
228462306a36Sopenharmony_ci							    event->id,
228562306a36Sopenharmony_ci							    &pmc->irq, pmc);
228662306a36Sopenharmony_ci			if (err < 0)
228762306a36Sopenharmony_ci				break;
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci			/* simple hierarchies stop at the PMC level */
229062306a36Sopenharmony_ci			if (event->irq == 0) {
229162306a36Sopenharmony_ci				err = irq_domain_disconnect_hierarchy(domain->parent, virq);
229262306a36Sopenharmony_ci				break;
229362306a36Sopenharmony_ci			}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci			spec.fwnode = &pmc->dev->of_node->fwnode;
229662306a36Sopenharmony_ci			spec.param_count = 3;
229762306a36Sopenharmony_ci			spec.param[0] = GIC_SPI;
229862306a36Sopenharmony_ci			spec.param[1] = event->irq;
229962306a36Sopenharmony_ci			spec.param[2] = fwspec->param[1];
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci			err = irq_domain_alloc_irqs_parent(domain, virq,
230262306a36Sopenharmony_ci							   num_irqs, &spec);
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci			break;
230562306a36Sopenharmony_ci		}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci		/* GPIO wake events */
230862306a36Sopenharmony_ci		if (fwspec->param_count == 3) {
230962306a36Sopenharmony_ci			if (event->gpio.instance != fwspec->param[0] ||
231062306a36Sopenharmony_ci			    event->gpio.pin != fwspec->param[1])
231162306a36Sopenharmony_ci				continue;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci			err = irq_domain_set_hwirq_and_chip(domain, virq,
231462306a36Sopenharmony_ci							    event->id,
231562306a36Sopenharmony_ci							    &pmc->irq, pmc);
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci			/* GPIO hierarchies stop at the PMC level */
231862306a36Sopenharmony_ci			if (!err && domain->parent)
231962306a36Sopenharmony_ci				err = irq_domain_disconnect_hierarchy(domain->parent,
232062306a36Sopenharmony_ci								      virq);
232162306a36Sopenharmony_ci			break;
232262306a36Sopenharmony_ci		}
232362306a36Sopenharmony_ci	}
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	/* If there is no wake-up event, there is no PMC mapping */
232662306a36Sopenharmony_ci	if (i == soc->num_wake_events)
232762306a36Sopenharmony_ci		err = irq_domain_disconnect_hierarchy(domain, virq);
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	return err;
233062306a36Sopenharmony_ci}
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_cistatic const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
233362306a36Sopenharmony_ci	.translate = tegra_pmc_irq_translate,
233462306a36Sopenharmony_ci	.alloc = tegra_pmc_irq_alloc,
233562306a36Sopenharmony_ci};
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_cistatic int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
233862306a36Sopenharmony_ci{
233962306a36Sopenharmony_ci	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
234062306a36Sopenharmony_ci	unsigned int offset, bit;
234162306a36Sopenharmony_ci	u32 value;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	offset = data->hwirq / 32;
234462306a36Sopenharmony_ci	bit = data->hwirq % 32;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	/* clear wake status */
234762306a36Sopenharmony_ci	tegra_pmc_writel(pmc, 0, PMC_SW_WAKE_STATUS);
234862306a36Sopenharmony_ci	tegra_pmc_writel(pmc, 0, PMC_SW_WAKE2_STATUS);
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	tegra_pmc_writel(pmc, 0, PMC_WAKE_STATUS);
235162306a36Sopenharmony_ci	tegra_pmc_writel(pmc, 0, PMC_WAKE2_STATUS);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	/* enable PMC wake */
235462306a36Sopenharmony_ci	if (data->hwirq >= 32)
235562306a36Sopenharmony_ci		offset = PMC_WAKE2_MASK;
235662306a36Sopenharmony_ci	else
235762306a36Sopenharmony_ci		offset = PMC_WAKE_MASK;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, offset);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	if (on)
236262306a36Sopenharmony_ci		value |= BIT(bit);
236362306a36Sopenharmony_ci	else
236462306a36Sopenharmony_ci		value &= ~BIT(bit);
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, offset);
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	return 0;
236962306a36Sopenharmony_ci}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_cistatic int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type)
237262306a36Sopenharmony_ci{
237362306a36Sopenharmony_ci	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
237462306a36Sopenharmony_ci	unsigned int offset, bit;
237562306a36Sopenharmony_ci	u32 value;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	offset = data->hwirq / 32;
237862306a36Sopenharmony_ci	bit = data->hwirq % 32;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	if (data->hwirq >= 32)
238162306a36Sopenharmony_ci		offset = PMC_WAKE2_LEVEL;
238262306a36Sopenharmony_ci	else
238362306a36Sopenharmony_ci		offset = PMC_WAKE_LEVEL;
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, offset);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	switch (type) {
238862306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
238962306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_HIGH:
239062306a36Sopenharmony_ci		value |= BIT(bit);
239162306a36Sopenharmony_ci		break;
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
239462306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
239562306a36Sopenharmony_ci		value &= ~BIT(bit);
239662306a36Sopenharmony_ci		break;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING:
239962306a36Sopenharmony_ci		value ^= BIT(bit);
240062306a36Sopenharmony_ci		break;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	default:
240362306a36Sopenharmony_ci		return -EINVAL;
240462306a36Sopenharmony_ci	}
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, offset);
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	return 0;
240962306a36Sopenharmony_ci}
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_cistatic void tegra186_pmc_set_wake_filters(struct tegra_pmc *pmc)
241262306a36Sopenharmony_ci{
241362306a36Sopenharmony_ci	u32 value;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	/* SW Wake (wake83) needs SR_CAPTURE filter to be enabled */
241662306a36Sopenharmony_ci	value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID));
241762306a36Sopenharmony_ci	value |= WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN;
241862306a36Sopenharmony_ci	writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID));
241962306a36Sopenharmony_ci	dev_dbg(pmc->dev, "WAKE_AOWAKE_CNTRL_83 = 0x%x\n", value);
242062306a36Sopenharmony_ci}
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_cistatic int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
242362306a36Sopenharmony_ci{
242462306a36Sopenharmony_ci	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
242562306a36Sopenharmony_ci	unsigned int offset, bit;
242662306a36Sopenharmony_ci	u32 value;
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	offset = data->hwirq / 32;
242962306a36Sopenharmony_ci	bit = data->hwirq % 32;
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	/* clear wake status */
243262306a36Sopenharmony_ci	writel(0x1, pmc->wake + WAKE_AOWAKE_STATUS_W(data->hwirq));
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	/* route wake to tier 2 */
243562306a36Sopenharmony_ci	value = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset));
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci	if (!on)
243862306a36Sopenharmony_ci		value &= ~(1 << bit);
243962306a36Sopenharmony_ci	else
244062306a36Sopenharmony_ci		value |= 1 << bit;
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	writel(value, pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset));
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	/* enable wakeup event */
244562306a36Sopenharmony_ci	writel(!!on, pmc->wake + WAKE_AOWAKE_MASK_W(data->hwirq));
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	return 0;
244862306a36Sopenharmony_ci}
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_cistatic int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
245162306a36Sopenharmony_ci{
245262306a36Sopenharmony_ci	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
245362306a36Sopenharmony_ci	u32 value;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq));
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	switch (type) {
245862306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
245962306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_HIGH:
246062306a36Sopenharmony_ci		value |= WAKE_AOWAKE_CNTRL_LEVEL;
246162306a36Sopenharmony_ci		set_bit(data->hwirq, pmc->wake_type_level_map);
246262306a36Sopenharmony_ci		clear_bit(data->hwirq, pmc->wake_type_dual_edge_map);
246362306a36Sopenharmony_ci		break;
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
246662306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
246762306a36Sopenharmony_ci		value &= ~WAKE_AOWAKE_CNTRL_LEVEL;
246862306a36Sopenharmony_ci		clear_bit(data->hwirq, pmc->wake_type_level_map);
246962306a36Sopenharmony_ci		clear_bit(data->hwirq, pmc->wake_type_dual_edge_map);
247062306a36Sopenharmony_ci		break;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING:
247362306a36Sopenharmony_ci		value ^= WAKE_AOWAKE_CNTRL_LEVEL;
247462306a36Sopenharmony_ci		clear_bit(data->hwirq, pmc->wake_type_level_map);
247562306a36Sopenharmony_ci		set_bit(data->hwirq, pmc->wake_type_dual_edge_map);
247662306a36Sopenharmony_ci		break;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	default:
247962306a36Sopenharmony_ci		return -EINVAL;
248062306a36Sopenharmony_ci	}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq));
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	return 0;
248562306a36Sopenharmony_ci}
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_cistatic void tegra_irq_mask_parent(struct irq_data *data)
248862306a36Sopenharmony_ci{
248962306a36Sopenharmony_ci	if (data->parent_data)
249062306a36Sopenharmony_ci		irq_chip_mask_parent(data);
249162306a36Sopenharmony_ci}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_cistatic void tegra_irq_unmask_parent(struct irq_data *data)
249462306a36Sopenharmony_ci{
249562306a36Sopenharmony_ci	if (data->parent_data)
249662306a36Sopenharmony_ci		irq_chip_unmask_parent(data);
249762306a36Sopenharmony_ci}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_cistatic void tegra_irq_eoi_parent(struct irq_data *data)
250062306a36Sopenharmony_ci{
250162306a36Sopenharmony_ci	if (data->parent_data)
250262306a36Sopenharmony_ci		irq_chip_eoi_parent(data);
250362306a36Sopenharmony_ci}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_cistatic int tegra_irq_set_affinity_parent(struct irq_data *data,
250662306a36Sopenharmony_ci					 const struct cpumask *dest,
250762306a36Sopenharmony_ci					 bool force)
250862306a36Sopenharmony_ci{
250962306a36Sopenharmony_ci	if (data->parent_data)
251062306a36Sopenharmony_ci		return irq_chip_set_affinity_parent(data, dest, force);
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	return -EINVAL;
251362306a36Sopenharmony_ci}
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_cistatic int tegra_pmc_irq_init(struct tegra_pmc *pmc)
251662306a36Sopenharmony_ci{
251762306a36Sopenharmony_ci	struct irq_domain *parent = NULL;
251862306a36Sopenharmony_ci	struct device_node *np;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	np = of_irq_find_parent(pmc->dev->of_node);
252162306a36Sopenharmony_ci	if (np) {
252262306a36Sopenharmony_ci		parent = irq_find_host(np);
252362306a36Sopenharmony_ci		of_node_put(np);
252462306a36Sopenharmony_ci	}
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	if (!parent)
252762306a36Sopenharmony_ci		return 0;
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	pmc->irq.name = dev_name(pmc->dev);
253062306a36Sopenharmony_ci	pmc->irq.irq_mask = tegra_irq_mask_parent;
253162306a36Sopenharmony_ci	pmc->irq.irq_unmask = tegra_irq_unmask_parent;
253262306a36Sopenharmony_ci	pmc->irq.irq_eoi = tegra_irq_eoi_parent;
253362306a36Sopenharmony_ci	pmc->irq.irq_set_affinity = tegra_irq_set_affinity_parent;
253462306a36Sopenharmony_ci	pmc->irq.irq_set_type = pmc->soc->irq_set_type;
253562306a36Sopenharmony_ci	pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node,
253862306a36Sopenharmony_ci					       &tegra_pmc_irq_domain_ops, pmc);
253962306a36Sopenharmony_ci	if (!pmc->domain) {
254062306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to allocate domain\n");
254162306a36Sopenharmony_ci		return -ENOMEM;
254262306a36Sopenharmony_ci	}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	return 0;
254562306a36Sopenharmony_ci}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_cistatic int tegra_pmc_clk_notify_cb(struct notifier_block *nb,
254862306a36Sopenharmony_ci				   unsigned long action, void *ptr)
254962306a36Sopenharmony_ci{
255062306a36Sopenharmony_ci	struct tegra_pmc *pmc = container_of(nb, struct tegra_pmc, clk_nb);
255162306a36Sopenharmony_ci	struct clk_notifier_data *data = ptr;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	switch (action) {
255462306a36Sopenharmony_ci	case PRE_RATE_CHANGE:
255562306a36Sopenharmony_ci		mutex_lock(&pmc->powergates_lock);
255662306a36Sopenharmony_ci		break;
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	case POST_RATE_CHANGE:
255962306a36Sopenharmony_ci		pmc->rate = data->new_rate;
256062306a36Sopenharmony_ci		fallthrough;
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	case ABORT_RATE_CHANGE:
256362306a36Sopenharmony_ci		mutex_unlock(&pmc->powergates_lock);
256462306a36Sopenharmony_ci		break;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	default:
256762306a36Sopenharmony_ci		WARN_ON_ONCE(1);
256862306a36Sopenharmony_ci		return notifier_from_errno(-EINVAL);
256962306a36Sopenharmony_ci	}
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	return NOTIFY_OK;
257262306a36Sopenharmony_ci}
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_cistatic void pmc_clk_fence_udelay(u32 offset)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	tegra_pmc_readl(pmc, offset);
257762306a36Sopenharmony_ci	/* pmc clk propagation delay 2 us */
257862306a36Sopenharmony_ci	udelay(2);
257962306a36Sopenharmony_ci}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_cistatic u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
258262306a36Sopenharmony_ci{
258362306a36Sopenharmony_ci	struct pmc_clk *clk = to_pmc_clk(hw);
258462306a36Sopenharmony_ci	u32 val;
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	val = tegra_pmc_readl(pmc, clk->offs) >> clk->mux_shift;
258762306a36Sopenharmony_ci	val &= PMC_CLK_OUT_MUX_MASK;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	return val;
259062306a36Sopenharmony_ci}
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_cistatic int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
259362306a36Sopenharmony_ci{
259462306a36Sopenharmony_ci	struct pmc_clk *clk = to_pmc_clk(hw);
259562306a36Sopenharmony_ci	u32 val;
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	val = tegra_pmc_readl(pmc, clk->offs);
259862306a36Sopenharmony_ci	val &= ~(PMC_CLK_OUT_MUX_MASK << clk->mux_shift);
259962306a36Sopenharmony_ci	val |= index << clk->mux_shift;
260062306a36Sopenharmony_ci	tegra_pmc_writel(pmc, val, clk->offs);
260162306a36Sopenharmony_ci	pmc_clk_fence_udelay(clk->offs);
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	return 0;
260462306a36Sopenharmony_ci}
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_cistatic int pmc_clk_is_enabled(struct clk_hw *hw)
260762306a36Sopenharmony_ci{
260862306a36Sopenharmony_ci	struct pmc_clk *clk = to_pmc_clk(hw);
260962306a36Sopenharmony_ci	u32 val;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	val = tegra_pmc_readl(pmc, clk->offs) & BIT(clk->force_en_shift);
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	return val ? 1 : 0;
261462306a36Sopenharmony_ci}
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_cistatic void pmc_clk_set_state(unsigned long offs, u32 shift, int state)
261762306a36Sopenharmony_ci{
261862306a36Sopenharmony_ci	u32 val;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	val = tegra_pmc_readl(pmc, offs);
262162306a36Sopenharmony_ci	val = state ? (val | BIT(shift)) : (val & ~BIT(shift));
262262306a36Sopenharmony_ci	tegra_pmc_writel(pmc, val, offs);
262362306a36Sopenharmony_ci	pmc_clk_fence_udelay(offs);
262462306a36Sopenharmony_ci}
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_cistatic int pmc_clk_enable(struct clk_hw *hw)
262762306a36Sopenharmony_ci{
262862306a36Sopenharmony_ci	struct pmc_clk *clk = to_pmc_clk(hw);
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	pmc_clk_set_state(clk->offs, clk->force_en_shift, 1);
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	return 0;
263362306a36Sopenharmony_ci}
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_cistatic void pmc_clk_disable(struct clk_hw *hw)
263662306a36Sopenharmony_ci{
263762306a36Sopenharmony_ci	struct pmc_clk *clk = to_pmc_clk(hw);
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	pmc_clk_set_state(clk->offs, clk->force_en_shift, 0);
264062306a36Sopenharmony_ci}
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_cistatic const struct clk_ops pmc_clk_ops = {
264362306a36Sopenharmony_ci	.get_parent = pmc_clk_mux_get_parent,
264462306a36Sopenharmony_ci	.set_parent = pmc_clk_mux_set_parent,
264562306a36Sopenharmony_ci	.determine_rate = __clk_mux_determine_rate,
264662306a36Sopenharmony_ci	.is_enabled = pmc_clk_is_enabled,
264762306a36Sopenharmony_ci	.enable = pmc_clk_enable,
264862306a36Sopenharmony_ci	.disable = pmc_clk_disable,
264962306a36Sopenharmony_ci};
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_cistatic struct clk *
265262306a36Sopenharmony_citegra_pmc_clk_out_register(struct tegra_pmc *pmc,
265362306a36Sopenharmony_ci			   const struct pmc_clk_init_data *data,
265462306a36Sopenharmony_ci			   unsigned long offset)
265562306a36Sopenharmony_ci{
265662306a36Sopenharmony_ci	struct clk_init_data init;
265762306a36Sopenharmony_ci	struct pmc_clk *pmc_clk;
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	pmc_clk = devm_kzalloc(pmc->dev, sizeof(*pmc_clk), GFP_KERNEL);
266062306a36Sopenharmony_ci	if (!pmc_clk)
266162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	init.name = data->name;
266462306a36Sopenharmony_ci	init.ops = &pmc_clk_ops;
266562306a36Sopenharmony_ci	init.parent_names = data->parents;
266662306a36Sopenharmony_ci	init.num_parents = data->num_parents;
266762306a36Sopenharmony_ci	init.flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT |
266862306a36Sopenharmony_ci		     CLK_SET_PARENT_GATE;
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	pmc_clk->hw.init = &init;
267162306a36Sopenharmony_ci	pmc_clk->offs = offset;
267262306a36Sopenharmony_ci	pmc_clk->mux_shift = data->mux_shift;
267362306a36Sopenharmony_ci	pmc_clk->force_en_shift = data->force_en_shift;
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	return clk_register(NULL, &pmc_clk->hw);
267662306a36Sopenharmony_ci}
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_cistatic int pmc_clk_gate_is_enabled(struct clk_hw *hw)
267962306a36Sopenharmony_ci{
268062306a36Sopenharmony_ci	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0;
268362306a36Sopenharmony_ci}
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_cistatic int pmc_clk_gate_enable(struct clk_hw *hw)
268662306a36Sopenharmony_ci{
268762306a36Sopenharmony_ci	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	pmc_clk_set_state(gate->offs, gate->shift, 1);
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	return 0;
269262306a36Sopenharmony_ci}
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_cistatic void pmc_clk_gate_disable(struct clk_hw *hw)
269562306a36Sopenharmony_ci{
269662306a36Sopenharmony_ci	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	pmc_clk_set_state(gate->offs, gate->shift, 0);
269962306a36Sopenharmony_ci}
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_cistatic const struct clk_ops pmc_clk_gate_ops = {
270262306a36Sopenharmony_ci	.is_enabled = pmc_clk_gate_is_enabled,
270362306a36Sopenharmony_ci	.enable = pmc_clk_gate_enable,
270462306a36Sopenharmony_ci	.disable = pmc_clk_gate_disable,
270562306a36Sopenharmony_ci};
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_cistatic struct clk *
270862306a36Sopenharmony_citegra_pmc_clk_gate_register(struct tegra_pmc *pmc, const char *name,
270962306a36Sopenharmony_ci			    const char *parent_name, unsigned long offset,
271062306a36Sopenharmony_ci			    u32 shift)
271162306a36Sopenharmony_ci{
271262306a36Sopenharmony_ci	struct clk_init_data init;
271362306a36Sopenharmony_ci	struct pmc_clk_gate *gate;
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	gate = devm_kzalloc(pmc->dev, sizeof(*gate), GFP_KERNEL);
271662306a36Sopenharmony_ci	if (!gate)
271762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	init.name = name;
272062306a36Sopenharmony_ci	init.ops = &pmc_clk_gate_ops;
272162306a36Sopenharmony_ci	init.parent_names = &parent_name;
272262306a36Sopenharmony_ci	init.num_parents = 1;
272362306a36Sopenharmony_ci	init.flags = 0;
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	gate->hw.init = &init;
272662306a36Sopenharmony_ci	gate->offs = offset;
272762306a36Sopenharmony_ci	gate->shift = shift;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	return clk_register(NULL, &gate->hw);
273062306a36Sopenharmony_ci}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_cistatic void tegra_pmc_clock_register(struct tegra_pmc *pmc,
273362306a36Sopenharmony_ci				     struct device_node *np)
273462306a36Sopenharmony_ci{
273562306a36Sopenharmony_ci	struct clk *clk;
273662306a36Sopenharmony_ci	struct clk_onecell_data *clk_data;
273762306a36Sopenharmony_ci	unsigned int num_clks;
273862306a36Sopenharmony_ci	int i, err;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	num_clks = pmc->soc->num_pmc_clks;
274162306a36Sopenharmony_ci	if (pmc->soc->has_blink_output)
274262306a36Sopenharmony_ci		num_clks += 1;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	if (!num_clks)
274562306a36Sopenharmony_ci		return;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	clk_data = devm_kmalloc(pmc->dev, sizeof(*clk_data), GFP_KERNEL);
274862306a36Sopenharmony_ci	if (!clk_data)
274962306a36Sopenharmony_ci		return;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	clk_data->clks = devm_kcalloc(pmc->dev, TEGRA_PMC_CLK_MAX,
275262306a36Sopenharmony_ci				      sizeof(*clk_data->clks), GFP_KERNEL);
275362306a36Sopenharmony_ci	if (!clk_data->clks)
275462306a36Sopenharmony_ci		return;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	clk_data->clk_num = TEGRA_PMC_CLK_MAX;
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	for (i = 0; i < TEGRA_PMC_CLK_MAX; i++)
275962306a36Sopenharmony_ci		clk_data->clks[i] = ERR_PTR(-ENOENT);
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
276262306a36Sopenharmony_ci		const struct pmc_clk_init_data *data;
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci		data = pmc->soc->pmc_clks_data + i;
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci		clk = tegra_pmc_clk_out_register(pmc, data, PMC_CLK_OUT_CNTRL);
276762306a36Sopenharmony_ci		if (IS_ERR(clk)) {
276862306a36Sopenharmony_ci			dev_warn(pmc->dev, "unable to register clock %s: %d\n",
276962306a36Sopenharmony_ci				 data->name, PTR_ERR_OR_ZERO(clk));
277062306a36Sopenharmony_ci			return;
277162306a36Sopenharmony_ci		}
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci		err = clk_register_clkdev(clk, data->name, NULL);
277462306a36Sopenharmony_ci		if (err) {
277562306a36Sopenharmony_ci			dev_warn(pmc->dev,
277662306a36Sopenharmony_ci				 "unable to register %s clock lookup: %d\n",
277762306a36Sopenharmony_ci				 data->name, err);
277862306a36Sopenharmony_ci			return;
277962306a36Sopenharmony_ci		}
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci		clk_data->clks[data->clk_id] = clk;
278262306a36Sopenharmony_ci	}
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	if (pmc->soc->has_blink_output) {
278562306a36Sopenharmony_ci		tegra_pmc_writel(pmc, 0x0, PMC_BLINK_TIMER);
278662306a36Sopenharmony_ci		clk = tegra_pmc_clk_gate_register(pmc,
278762306a36Sopenharmony_ci						  "pmc_blink_override",
278862306a36Sopenharmony_ci						  "clk_32k",
278962306a36Sopenharmony_ci						  PMC_DPD_PADS_ORIDE,
279062306a36Sopenharmony_ci						  PMC_DPD_PADS_ORIDE_BLINK);
279162306a36Sopenharmony_ci		if (IS_ERR(clk)) {
279262306a36Sopenharmony_ci			dev_warn(pmc->dev,
279362306a36Sopenharmony_ci				 "unable to register pmc_blink_override: %d\n",
279462306a36Sopenharmony_ci				 PTR_ERR_OR_ZERO(clk));
279562306a36Sopenharmony_ci			return;
279662306a36Sopenharmony_ci		}
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci		clk = tegra_pmc_clk_gate_register(pmc, "pmc_blink",
279962306a36Sopenharmony_ci						  "pmc_blink_override",
280062306a36Sopenharmony_ci						  PMC_CNTRL,
280162306a36Sopenharmony_ci						  PMC_CNTRL_BLINK_EN);
280262306a36Sopenharmony_ci		if (IS_ERR(clk)) {
280362306a36Sopenharmony_ci			dev_warn(pmc->dev,
280462306a36Sopenharmony_ci				 "unable to register pmc_blink: %d\n",
280562306a36Sopenharmony_ci				 PTR_ERR_OR_ZERO(clk));
280662306a36Sopenharmony_ci			return;
280762306a36Sopenharmony_ci		}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci		err = clk_register_clkdev(clk, "pmc_blink", NULL);
281062306a36Sopenharmony_ci		if (err) {
281162306a36Sopenharmony_ci			dev_warn(pmc->dev,
281262306a36Sopenharmony_ci				 "unable to register pmc_blink lookup: %d\n",
281362306a36Sopenharmony_ci				 err);
281462306a36Sopenharmony_ci			return;
281562306a36Sopenharmony_ci		}
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci		clk_data->clks[TEGRA_PMC_CLK_BLINK] = clk;
281862306a36Sopenharmony_ci	}
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	err = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
282162306a36Sopenharmony_ci	if (err)
282262306a36Sopenharmony_ci		dev_warn(pmc->dev, "failed to add pmc clock provider: %d\n",
282362306a36Sopenharmony_ci			 err);
282462306a36Sopenharmony_ci}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_cistatic const struct regmap_range pmc_usb_sleepwalk_ranges[] = {
282762306a36Sopenharmony_ci	regmap_reg_range(PMC_USB_DEBOUNCE_DEL, PMC_USB_AO),
282862306a36Sopenharmony_ci	regmap_reg_range(PMC_UTMIP_UHSIC_TRIGGERS, PMC_UTMIP_UHSIC_SAVED_STATE),
282962306a36Sopenharmony_ci	regmap_reg_range(PMC_UTMIP_TERM_PAD_CFG, PMC_UTMIP_UHSIC_FAKE),
283062306a36Sopenharmony_ci	regmap_reg_range(PMC_UTMIP_UHSIC_LINE_WAKEUP, PMC_UTMIP_UHSIC_LINE_WAKEUP),
283162306a36Sopenharmony_ci	regmap_reg_range(PMC_UTMIP_BIAS_MASTER_CNTRL, PMC_UTMIP_MASTER_CONFIG),
283262306a36Sopenharmony_ci	regmap_reg_range(PMC_UTMIP_UHSIC2_TRIGGERS, PMC_UTMIP_MASTER2_CONFIG),
283362306a36Sopenharmony_ci	regmap_reg_range(PMC_UTMIP_PAD_CFG0, PMC_UTMIP_UHSIC_SLEEP_CFG1),
283462306a36Sopenharmony_ci	regmap_reg_range(PMC_UTMIP_SLEEPWALK_P3, PMC_UTMIP_SLEEPWALK_P3),
283562306a36Sopenharmony_ci};
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_cistatic const struct regmap_access_table pmc_usb_sleepwalk_table = {
283862306a36Sopenharmony_ci	.yes_ranges = pmc_usb_sleepwalk_ranges,
283962306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(pmc_usb_sleepwalk_ranges),
284062306a36Sopenharmony_ci};
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_cistatic int tegra_pmc_regmap_readl(void *context, unsigned int offset, unsigned int *value)
284362306a36Sopenharmony_ci{
284462306a36Sopenharmony_ci	struct tegra_pmc *pmc = context;
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	*value = tegra_pmc_readl(pmc, offset);
284762306a36Sopenharmony_ci	return 0;
284862306a36Sopenharmony_ci}
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_cistatic int tegra_pmc_regmap_writel(void *context, unsigned int offset, unsigned int value)
285162306a36Sopenharmony_ci{
285262306a36Sopenharmony_ci	struct tegra_pmc *pmc = context;
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, offset);
285562306a36Sopenharmony_ci	return 0;
285662306a36Sopenharmony_ci}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_cistatic const struct regmap_config usb_sleepwalk_regmap_config = {
285962306a36Sopenharmony_ci	.name = "usb_sleepwalk",
286062306a36Sopenharmony_ci	.reg_bits = 32,
286162306a36Sopenharmony_ci	.val_bits = 32,
286262306a36Sopenharmony_ci	.reg_stride = 4,
286362306a36Sopenharmony_ci	.fast_io = true,
286462306a36Sopenharmony_ci	.rd_table = &pmc_usb_sleepwalk_table,
286562306a36Sopenharmony_ci	.wr_table = &pmc_usb_sleepwalk_table,
286662306a36Sopenharmony_ci	.reg_read = tegra_pmc_regmap_readl,
286762306a36Sopenharmony_ci	.reg_write = tegra_pmc_regmap_writel,
286862306a36Sopenharmony_ci};
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_cistatic int tegra_pmc_regmap_init(struct tegra_pmc *pmc)
287162306a36Sopenharmony_ci{
287262306a36Sopenharmony_ci	struct regmap *regmap;
287362306a36Sopenharmony_ci	int err;
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	if (pmc->soc->has_usb_sleepwalk) {
287662306a36Sopenharmony_ci		regmap = devm_regmap_init(pmc->dev, NULL, pmc, &usb_sleepwalk_regmap_config);
287762306a36Sopenharmony_ci		if (IS_ERR(regmap)) {
287862306a36Sopenharmony_ci			err = PTR_ERR(regmap);
287962306a36Sopenharmony_ci			dev_err(pmc->dev, "failed to allocate register map (%d)\n", err);
288062306a36Sopenharmony_ci			return err;
288162306a36Sopenharmony_ci		}
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	return 0;
288562306a36Sopenharmony_ci}
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_cistatic void tegra_pmc_reset_suspend_mode(void *data)
288862306a36Sopenharmony_ci{
288962306a36Sopenharmony_ci	pmc->suspend_mode = TEGRA_SUSPEND_NOT_READY;
289062306a36Sopenharmony_ci}
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_cistatic int tegra_pmc_probe(struct platform_device *pdev)
289362306a36Sopenharmony_ci{
289462306a36Sopenharmony_ci	void __iomem *base;
289562306a36Sopenharmony_ci	struct resource *res;
289662306a36Sopenharmony_ci	int err;
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	/*
289962306a36Sopenharmony_ci	 * Early initialisation should have configured an initial
290062306a36Sopenharmony_ci	 * register mapping and setup the soc data pointer. If these
290162306a36Sopenharmony_ci	 * are not valid then something went badly wrong!
290262306a36Sopenharmony_ci	 */
290362306a36Sopenharmony_ci	if (WARN_ON(!pmc->base || !pmc->soc))
290462306a36Sopenharmony_ci		return -ENODEV;
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node);
290762306a36Sopenharmony_ci	if (err < 0)
290862306a36Sopenharmony_ci		return err;
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	err = devm_add_action_or_reset(&pdev->dev, tegra_pmc_reset_suspend_mode,
291162306a36Sopenharmony_ci				       NULL);
291262306a36Sopenharmony_ci	if (err)
291362306a36Sopenharmony_ci		return err;
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	/* take over the memory region from the early initialization */
291662306a36Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
291762306a36Sopenharmony_ci	if (IS_ERR(base))
291862306a36Sopenharmony_ci		return PTR_ERR(base);
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake");
292162306a36Sopenharmony_ci	if (res) {
292262306a36Sopenharmony_ci		pmc->wake = devm_ioremap_resource(&pdev->dev, res);
292362306a36Sopenharmony_ci		if (IS_ERR(pmc->wake))
292462306a36Sopenharmony_ci			return PTR_ERR(pmc->wake);
292562306a36Sopenharmony_ci	} else {
292662306a36Sopenharmony_ci		pmc->wake = base;
292762306a36Sopenharmony_ci	}
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag");
293062306a36Sopenharmony_ci	if (res) {
293162306a36Sopenharmony_ci		pmc->aotag = devm_ioremap_resource(&pdev->dev, res);
293262306a36Sopenharmony_ci		if (IS_ERR(pmc->aotag))
293362306a36Sopenharmony_ci			return PTR_ERR(pmc->aotag);
293462306a36Sopenharmony_ci	} else {
293562306a36Sopenharmony_ci		pmc->aotag = base;
293662306a36Sopenharmony_ci	}
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch");
293962306a36Sopenharmony_ci	if (res) {
294062306a36Sopenharmony_ci		pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
294162306a36Sopenharmony_ci		if (IS_ERR(pmc->scratch))
294262306a36Sopenharmony_ci			return PTR_ERR(pmc->scratch);
294362306a36Sopenharmony_ci	} else {
294462306a36Sopenharmony_ci		pmc->scratch = base;
294562306a36Sopenharmony_ci	}
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	pmc->clk = devm_clk_get_optional(&pdev->dev, "pclk");
294862306a36Sopenharmony_ci	if (IS_ERR(pmc->clk))
294962306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(pmc->clk),
295062306a36Sopenharmony_ci				     "failed to get pclk\n");
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci	/*
295362306a36Sopenharmony_ci	 * PMC should be last resort for restarting since it soft-resets
295462306a36Sopenharmony_ci	 * CPU without resetting everything else.
295562306a36Sopenharmony_ci	 */
295662306a36Sopenharmony_ci	err = devm_register_reboot_notifier(&pdev->dev,
295762306a36Sopenharmony_ci					    &tegra_pmc_reboot_notifier);
295862306a36Sopenharmony_ci	if (err) {
295962306a36Sopenharmony_ci		dev_err(&pdev->dev, "unable to register reboot notifier, %d\n",
296062306a36Sopenharmony_ci			err);
296162306a36Sopenharmony_ci		return err;
296262306a36Sopenharmony_ci	}
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	err = devm_register_sys_off_handler(&pdev->dev,
296562306a36Sopenharmony_ci					    SYS_OFF_MODE_RESTART,
296662306a36Sopenharmony_ci					    SYS_OFF_PRIO_LOW,
296762306a36Sopenharmony_ci					    tegra_pmc_restart_handler, NULL);
296862306a36Sopenharmony_ci	if (err) {
296962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to register sys-off handler: %d\n",
297062306a36Sopenharmony_ci			err);
297162306a36Sopenharmony_ci		return err;
297262306a36Sopenharmony_ci	}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	/*
297562306a36Sopenharmony_ci	 * PMC should be primary power-off method if it soft-resets CPU,
297662306a36Sopenharmony_ci	 * asking bootloader to shutdown hardware.
297762306a36Sopenharmony_ci	 */
297862306a36Sopenharmony_ci	err = devm_register_sys_off_handler(&pdev->dev,
297962306a36Sopenharmony_ci					    SYS_OFF_MODE_POWER_OFF,
298062306a36Sopenharmony_ci					    SYS_OFF_PRIO_FIRMWARE,
298162306a36Sopenharmony_ci					    tegra_pmc_power_off_handler, NULL);
298262306a36Sopenharmony_ci	if (err) {
298362306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to register sys-off handler: %d\n",
298462306a36Sopenharmony_ci			err);
298562306a36Sopenharmony_ci		return err;
298662306a36Sopenharmony_ci	}
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci	/*
298962306a36Sopenharmony_ci	 * PCLK clock rate can't be retrieved using CLK API because it
299062306a36Sopenharmony_ci	 * causes lockup if CPU enters LP2 idle state from some other
299162306a36Sopenharmony_ci	 * CLK notifier, hence we're caching the rate's value locally.
299262306a36Sopenharmony_ci	 */
299362306a36Sopenharmony_ci	if (pmc->clk) {
299462306a36Sopenharmony_ci		pmc->clk_nb.notifier_call = tegra_pmc_clk_notify_cb;
299562306a36Sopenharmony_ci		err = devm_clk_notifier_register(&pdev->dev, pmc->clk,
299662306a36Sopenharmony_ci						 &pmc->clk_nb);
299762306a36Sopenharmony_ci		if (err) {
299862306a36Sopenharmony_ci			dev_err(&pdev->dev,
299962306a36Sopenharmony_ci				"failed to register clk notifier\n");
300062306a36Sopenharmony_ci			return err;
300162306a36Sopenharmony_ci		}
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci		pmc->rate = clk_get_rate(pmc->clk);
300462306a36Sopenharmony_ci	}
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ci	pmc->dev = &pdev->dev;
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	err = tegra_pmc_init(pmc);
300962306a36Sopenharmony_ci	if (err < 0) {
301062306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to initialize PMC: %d\n", err);
301162306a36Sopenharmony_ci		return err;
301262306a36Sopenharmony_ci	}
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci	tegra_pmc_init_tsense_reset(pmc);
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	tegra_pmc_reset_sysfs_init(pmc);
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci	err = tegra_pmc_pinctrl_init(pmc);
301962306a36Sopenharmony_ci	if (err)
302062306a36Sopenharmony_ci		goto cleanup_sysfs;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	err = tegra_pmc_regmap_init(pmc);
302362306a36Sopenharmony_ci	if (err < 0)
302462306a36Sopenharmony_ci		goto cleanup_sysfs;
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	err = tegra_powergate_init(pmc, pdev->dev.of_node);
302762306a36Sopenharmony_ci	if (err < 0)
302862306a36Sopenharmony_ci		goto cleanup_powergates;
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_ci	err = tegra_pmc_irq_init(pmc);
303162306a36Sopenharmony_ci	if (err < 0)
303262306a36Sopenharmony_ci		goto cleanup_powergates;
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	mutex_lock(&pmc->powergates_lock);
303562306a36Sopenharmony_ci	iounmap(pmc->base);
303662306a36Sopenharmony_ci	pmc->base = base;
303762306a36Sopenharmony_ci	mutex_unlock(&pmc->powergates_lock);
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	tegra_pmc_clock_register(pmc, pdev->dev.of_node);
304062306a36Sopenharmony_ci	platform_set_drvdata(pdev, pmc);
304162306a36Sopenharmony_ci	tegra_pm_init_suspend();
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	/* Some wakes require specific filter configuration */
304462306a36Sopenharmony_ci	if (pmc->soc->set_wake_filters)
304562306a36Sopenharmony_ci		pmc->soc->set_wake_filters(pmc);
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	debugfs_create_file("powergate", 0444, NULL, NULL, &powergate_fops);
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	return 0;
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_cicleanup_powergates:
305262306a36Sopenharmony_ci	tegra_powergate_remove_all(pdev->dev.of_node);
305362306a36Sopenharmony_cicleanup_sysfs:
305462306a36Sopenharmony_ci	device_remove_file(&pdev->dev, &dev_attr_reset_reason);
305562306a36Sopenharmony_ci	device_remove_file(&pdev->dev, &dev_attr_reset_level);
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci	return err;
305862306a36Sopenharmony_ci}
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci/*
306162306a36Sopenharmony_ci * Ensures that sufficient time is passed for a register write to
306262306a36Sopenharmony_ci * serialize into the 32KHz domain.
306362306a36Sopenharmony_ci */
306462306a36Sopenharmony_cistatic void wke_32kwritel(struct tegra_pmc *pmc, u32 value, unsigned int offset)
306562306a36Sopenharmony_ci{
306662306a36Sopenharmony_ci	writel(value, pmc->wake + offset);
306762306a36Sopenharmony_ci	udelay(130);
306862306a36Sopenharmony_ci}
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_cistatic void wke_write_wake_level(struct tegra_pmc *pmc, int wake, int level)
307162306a36Sopenharmony_ci{
307262306a36Sopenharmony_ci	unsigned int offset = WAKE_AOWAKE_CNTRL(wake);
307362306a36Sopenharmony_ci	u32 value;
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci	value = readl(pmc->wake + offset);
307662306a36Sopenharmony_ci	if (level)
307762306a36Sopenharmony_ci		value |= WAKE_AOWAKE_CNTRL_LEVEL;
307862306a36Sopenharmony_ci	else
307962306a36Sopenharmony_ci		value &= ~WAKE_AOWAKE_CNTRL_LEVEL;
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	writel(value, pmc->wake + offset);
308262306a36Sopenharmony_ci}
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_cistatic void wke_write_wake_levels(struct tegra_pmc *pmc)
308562306a36Sopenharmony_ci{
308662306a36Sopenharmony_ci	unsigned int i;
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->max_wake_events; i++)
308962306a36Sopenharmony_ci		wke_write_wake_level(pmc, i, test_bit(i, pmc->wake_cntrl_level_map));
309062306a36Sopenharmony_ci}
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_cistatic void wke_clear_sw_wake_status(struct tegra_pmc *pmc)
309362306a36Sopenharmony_ci{
309462306a36Sopenharmony_ci	wke_32kwritel(pmc, 1, WAKE_AOWAKE_SW_STATUS_W_0);
309562306a36Sopenharmony_ci}
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_cistatic void wke_read_sw_wake_status(struct tegra_pmc *pmc)
309862306a36Sopenharmony_ci{
309962306a36Sopenharmony_ci	unsigned long status;
310062306a36Sopenharmony_ci	unsigned int wake, i;
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->max_wake_events; i++)
310362306a36Sopenharmony_ci		wke_write_wake_level(pmc, i, 0);
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	wke_clear_sw_wake_status(pmc);
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	wke_32kwritel(pmc, 1, WAKE_LATCH_SW);
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	/*
311062306a36Sopenharmony_ci	 * WAKE_AOWAKE_SW_STATUS is edge triggered, so in order to
311162306a36Sopenharmony_ci	 * obtain the current status of the input wake signals, change
311262306a36Sopenharmony_ci	 * the polarity of the wake level from 0->1 while latching to force
311362306a36Sopenharmony_ci	 * a positive edge if the sampled signal is '1'.
311462306a36Sopenharmony_ci	 */
311562306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->max_wake_events; i++)
311662306a36Sopenharmony_ci		wke_write_wake_level(pmc, i, 1);
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci	/*
311962306a36Sopenharmony_ci	 * Wait for the update to be synced into the 32kHz domain,
312062306a36Sopenharmony_ci	 * and let enough time lapse, so that the wake signals have time to
312162306a36Sopenharmony_ci	 * be sampled.
312262306a36Sopenharmony_ci	 */
312362306a36Sopenharmony_ci	udelay(300);
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	wke_32kwritel(pmc, 0, WAKE_LATCH_SW);
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci	bitmap_zero(pmc->wake_sw_status_map, pmc->soc->max_wake_events);
312862306a36Sopenharmony_ci
312962306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
313062306a36Sopenharmony_ci		status = readl(pmc->wake + WAKE_AOWAKE_SW_STATUS(i));
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci		for_each_set_bit(wake, &status, 32)
313362306a36Sopenharmony_ci			set_bit(wake + (i * 32), pmc->wake_sw_status_map);
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci}
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_cistatic void wke_clear_wake_status(struct tegra_pmc *pmc)
313862306a36Sopenharmony_ci{
313962306a36Sopenharmony_ci	unsigned long status;
314062306a36Sopenharmony_ci	unsigned int i, wake;
314162306a36Sopenharmony_ci	u32 mask;
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
314462306a36Sopenharmony_ci		mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i));
314562306a36Sopenharmony_ci		status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask;
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci		for_each_set_bit(wake, &status, 32)
314862306a36Sopenharmony_ci			wke_32kwritel(pmc, 0x1, WAKE_AOWAKE_STATUS_W((i * 32) + wake));
314962306a36Sopenharmony_ci	}
315062306a36Sopenharmony_ci}
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci/* translate sc7 wake sources back into IRQs to catch edge triggered wakeups */
315362306a36Sopenharmony_cistatic void tegra186_pmc_process_wake_events(struct tegra_pmc *pmc, unsigned int index,
315462306a36Sopenharmony_ci					     unsigned long status)
315562306a36Sopenharmony_ci{
315662306a36Sopenharmony_ci	unsigned int wake;
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	dev_dbg(pmc->dev, "Wake[%d:%d]  status=%#lx\n", (index * 32) + 31, index * 32, status);
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	for_each_set_bit(wake, &status, 32) {
316162306a36Sopenharmony_ci		irq_hw_number_t hwirq = wake + 32 * index;
316262306a36Sopenharmony_ci		struct irq_desc *desc;
316362306a36Sopenharmony_ci		unsigned int irq;
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci		irq = irq_find_mapping(pmc->domain, hwirq);
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci		desc = irq_to_desc(irq);
316862306a36Sopenharmony_ci		if (!desc || !desc->action || !desc->action->name) {
316962306a36Sopenharmony_ci			dev_dbg(pmc->dev, "Resume caused by WAKE%ld, IRQ %d\n", hwirq, irq);
317062306a36Sopenharmony_ci			continue;
317162306a36Sopenharmony_ci		}
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci		dev_dbg(pmc->dev, "Resume caused by WAKE%ld, %s\n", hwirq, desc->action->name);
317462306a36Sopenharmony_ci		generic_handle_irq(irq);
317562306a36Sopenharmony_ci	}
317662306a36Sopenharmony_ci}
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_cistatic void tegra186_pmc_wake_syscore_resume(void)
317962306a36Sopenharmony_ci{
318062306a36Sopenharmony_ci	u32 status, mask;
318162306a36Sopenharmony_ci	unsigned int i;
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
318462306a36Sopenharmony_ci		mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i));
318562306a36Sopenharmony_ci		status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask;
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci		tegra186_pmc_process_wake_events(pmc, i, status);
318862306a36Sopenharmony_ci	}
318962306a36Sopenharmony_ci}
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_cistatic int tegra186_pmc_wake_syscore_suspend(void)
319262306a36Sopenharmony_ci{
319362306a36Sopenharmony_ci	wke_read_sw_wake_status(pmc);
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci	/* flip the wakeup trigger for dual-edge triggered pads
319662306a36Sopenharmony_ci	 * which are currently asserting as wakeups
319762306a36Sopenharmony_ci	 */
319862306a36Sopenharmony_ci	bitmap_andnot(pmc->wake_cntrl_level_map, pmc->wake_type_dual_edge_map,
319962306a36Sopenharmony_ci		      pmc->wake_sw_status_map, pmc->soc->max_wake_events);
320062306a36Sopenharmony_ci	bitmap_or(pmc->wake_cntrl_level_map, pmc->wake_cntrl_level_map,
320162306a36Sopenharmony_ci		  pmc->wake_type_level_map, pmc->soc->max_wake_events);
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	/* Clear PMC Wake Status registers while going to suspend */
320462306a36Sopenharmony_ci	wke_clear_wake_status(pmc);
320562306a36Sopenharmony_ci	wke_write_wake_levels(pmc);
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	return 0;
320862306a36Sopenharmony_ci}
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
321162306a36Sopenharmony_cistatic int tegra_pmc_suspend(struct device *dev)
321262306a36Sopenharmony_ci{
321362306a36Sopenharmony_ci	struct tegra_pmc *pmc = dev_get_drvdata(dev);
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	tegra_pmc_writel(pmc, virt_to_phys(tegra_resume), PMC_SCRATCH41);
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	return 0;
321862306a36Sopenharmony_ci}
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_cistatic int tegra_pmc_resume(struct device *dev)
322162306a36Sopenharmony_ci{
322262306a36Sopenharmony_ci	struct tegra_pmc *pmc = dev_get_drvdata(dev);
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	tegra_pmc_writel(pmc, 0x0, PMC_SCRATCH41);
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	return 0;
322762306a36Sopenharmony_ci}
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume);
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci#endif
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_cistatic const char * const tegra20_powergates[] = {
323462306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU] = "cpu",
323562306a36Sopenharmony_ci	[TEGRA_POWERGATE_3D] = "td",
323662306a36Sopenharmony_ci	[TEGRA_POWERGATE_VENC] = "venc",
323762306a36Sopenharmony_ci	[TEGRA_POWERGATE_VDEC] = "vdec",
323862306a36Sopenharmony_ci	[TEGRA_POWERGATE_PCIE] = "pcie",
323962306a36Sopenharmony_ci	[TEGRA_POWERGATE_L2] = "l2",
324062306a36Sopenharmony_ci	[TEGRA_POWERGATE_MPE] = "mpe",
324162306a36Sopenharmony_ci};
324262306a36Sopenharmony_ci
324362306a36Sopenharmony_cistatic const struct tegra_pmc_regs tegra20_pmc_regs = {
324462306a36Sopenharmony_ci	.scratch0 = 0x50,
324562306a36Sopenharmony_ci	.rst_status = 0x1b4,
324662306a36Sopenharmony_ci	.rst_source_shift = 0x0,
324762306a36Sopenharmony_ci	.rst_source_mask = 0x7,
324862306a36Sopenharmony_ci	.rst_level_shift = 0x0,
324962306a36Sopenharmony_ci	.rst_level_mask = 0x0,
325062306a36Sopenharmony_ci};
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_cistatic void tegra20_pmc_init(struct tegra_pmc *pmc)
325362306a36Sopenharmony_ci{
325462306a36Sopenharmony_ci	u32 value, osc, pmu, off;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	/* Always enable CPU power request */
325762306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, PMC_CNTRL);
325862306a36Sopenharmony_ci	value |= PMC_CNTRL_CPU_PWRREQ_OE;
325962306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_CNTRL);
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, PMC_CNTRL);
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci	if (pmc->sysclkreq_high)
326462306a36Sopenharmony_ci		value &= ~PMC_CNTRL_SYSCLK_POLARITY;
326562306a36Sopenharmony_ci	else
326662306a36Sopenharmony_ci		value |= PMC_CNTRL_SYSCLK_POLARITY;
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	if (pmc->corereq_high)
326962306a36Sopenharmony_ci		value &= ~PMC_CNTRL_PWRREQ_POLARITY;
327062306a36Sopenharmony_ci	else
327162306a36Sopenharmony_ci		value |= PMC_CNTRL_PWRREQ_POLARITY;
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci	/* configure the output polarity while the request is tristated */
327462306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_CNTRL);
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	/* now enable the request */
327762306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, PMC_CNTRL);
327862306a36Sopenharmony_ci	value |= PMC_CNTRL_SYSCLK_OE;
327962306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_CNTRL);
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	/* program core timings which are applicable only for suspend state */
328262306a36Sopenharmony_ci	if (pmc->suspend_mode != TEGRA_SUSPEND_NONE) {
328362306a36Sopenharmony_ci		osc = DIV_ROUND_UP(pmc->core_osc_time * 8192, 1000000);
328462306a36Sopenharmony_ci		pmu = DIV_ROUND_UP(pmc->core_pmu_time * 32768, 1000000);
328562306a36Sopenharmony_ci		off = DIV_ROUND_UP(pmc->core_off_time * 32768, 1000000);
328662306a36Sopenharmony_ci		tegra_pmc_writel(pmc, ((osc << 8) & 0xff00) | (pmu & 0xff),
328762306a36Sopenharmony_ci				 PMC_COREPWRGOOD_TIMER);
328862306a36Sopenharmony_ci		tegra_pmc_writel(pmc, off, PMC_COREPWROFF_TIMER);
328962306a36Sopenharmony_ci	}
329062306a36Sopenharmony_ci}
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_cistatic void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
329362306a36Sopenharmony_ci					   struct device_node *np,
329462306a36Sopenharmony_ci					   bool invert)
329562306a36Sopenharmony_ci{
329662306a36Sopenharmony_ci	u32 value;
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	value = tegra_pmc_readl(pmc, PMC_CNTRL);
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	if (invert)
330162306a36Sopenharmony_ci		value |= PMC_CNTRL_INTR_POLARITY;
330262306a36Sopenharmony_ci	else
330362306a36Sopenharmony_ci		value &= ~PMC_CNTRL_INTR_POLARITY;
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci	tegra_pmc_writel(pmc, value, PMC_CNTRL);
330662306a36Sopenharmony_ci}
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_cistatic const struct tegra_pmc_soc tegra20_pmc_soc = {
330962306a36Sopenharmony_ci	.supports_core_domain = true,
331062306a36Sopenharmony_ci	.num_powergates = ARRAY_SIZE(tegra20_powergates),
331162306a36Sopenharmony_ci	.powergates = tegra20_powergates,
331262306a36Sopenharmony_ci	.num_cpu_powergates = 0,
331362306a36Sopenharmony_ci	.cpu_powergates = NULL,
331462306a36Sopenharmony_ci	.has_tsense_reset = false,
331562306a36Sopenharmony_ci	.has_gpu_clamps = false,
331662306a36Sopenharmony_ci	.needs_mbist_war = false,
331762306a36Sopenharmony_ci	.has_impl_33v_pwr = false,
331862306a36Sopenharmony_ci	.maybe_tz_only = false,
331962306a36Sopenharmony_ci	.num_io_pads = 0,
332062306a36Sopenharmony_ci	.io_pads = NULL,
332162306a36Sopenharmony_ci	.num_pin_descs = 0,
332262306a36Sopenharmony_ci	.pin_descs = NULL,
332362306a36Sopenharmony_ci	.regs = &tegra20_pmc_regs,
332462306a36Sopenharmony_ci	.init = tegra20_pmc_init,
332562306a36Sopenharmony_ci	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
332662306a36Sopenharmony_ci	.powergate_set = tegra20_powergate_set,
332762306a36Sopenharmony_ci	.reset_sources = NULL,
332862306a36Sopenharmony_ci	.num_reset_sources = 0,
332962306a36Sopenharmony_ci	.reset_levels = NULL,
333062306a36Sopenharmony_ci	.num_reset_levels = 0,
333162306a36Sopenharmony_ci	.pmc_clks_data = NULL,
333262306a36Sopenharmony_ci	.num_pmc_clks = 0,
333362306a36Sopenharmony_ci	.has_blink_output = true,
333462306a36Sopenharmony_ci	.has_usb_sleepwalk = true,
333562306a36Sopenharmony_ci};
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_cistatic const char * const tegra30_powergates[] = {
333862306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU] = "cpu0",
333962306a36Sopenharmony_ci	[TEGRA_POWERGATE_3D] = "td",
334062306a36Sopenharmony_ci	[TEGRA_POWERGATE_VENC] = "venc",
334162306a36Sopenharmony_ci	[TEGRA_POWERGATE_VDEC] = "vdec",
334262306a36Sopenharmony_ci	[TEGRA_POWERGATE_PCIE] = "pcie",
334362306a36Sopenharmony_ci	[TEGRA_POWERGATE_L2] = "l2",
334462306a36Sopenharmony_ci	[TEGRA_POWERGATE_MPE] = "mpe",
334562306a36Sopenharmony_ci	[TEGRA_POWERGATE_HEG] = "heg",
334662306a36Sopenharmony_ci	[TEGRA_POWERGATE_SATA] = "sata",
334762306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU1] = "cpu1",
334862306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU2] = "cpu2",
334962306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU3] = "cpu3",
335062306a36Sopenharmony_ci	[TEGRA_POWERGATE_CELP] = "celp",
335162306a36Sopenharmony_ci	[TEGRA_POWERGATE_3D1] = "td2",
335262306a36Sopenharmony_ci};
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_cistatic const u8 tegra30_cpu_powergates[] = {
335562306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU,
335662306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU1,
335762306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU2,
335862306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU3,
335962306a36Sopenharmony_ci};
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_cistatic const char * const tegra30_reset_sources[] = {
336262306a36Sopenharmony_ci	"POWER_ON_RESET",
336362306a36Sopenharmony_ci	"WATCHDOG",
336462306a36Sopenharmony_ci	"SENSOR",
336562306a36Sopenharmony_ci	"SW_MAIN",
336662306a36Sopenharmony_ci	"LP0"
336762306a36Sopenharmony_ci};
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_cistatic const struct tegra_pmc_soc tegra30_pmc_soc = {
337062306a36Sopenharmony_ci	.supports_core_domain = true,
337162306a36Sopenharmony_ci	.num_powergates = ARRAY_SIZE(tegra30_powergates),
337262306a36Sopenharmony_ci	.powergates = tegra30_powergates,
337362306a36Sopenharmony_ci	.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
337462306a36Sopenharmony_ci	.cpu_powergates = tegra30_cpu_powergates,
337562306a36Sopenharmony_ci	.has_tsense_reset = true,
337662306a36Sopenharmony_ci	.has_gpu_clamps = false,
337762306a36Sopenharmony_ci	.needs_mbist_war = false,
337862306a36Sopenharmony_ci	.has_impl_33v_pwr = false,
337962306a36Sopenharmony_ci	.maybe_tz_only = false,
338062306a36Sopenharmony_ci	.num_io_pads = 0,
338162306a36Sopenharmony_ci	.io_pads = NULL,
338262306a36Sopenharmony_ci	.num_pin_descs = 0,
338362306a36Sopenharmony_ci	.pin_descs = NULL,
338462306a36Sopenharmony_ci	.regs = &tegra20_pmc_regs,
338562306a36Sopenharmony_ci	.init = tegra20_pmc_init,
338662306a36Sopenharmony_ci	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
338762306a36Sopenharmony_ci	.powergate_set = tegra20_powergate_set,
338862306a36Sopenharmony_ci	.reset_sources = tegra30_reset_sources,
338962306a36Sopenharmony_ci	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
339062306a36Sopenharmony_ci	.reset_levels = NULL,
339162306a36Sopenharmony_ci	.num_reset_levels = 0,
339262306a36Sopenharmony_ci	.pmc_clks_data = tegra_pmc_clks_data,
339362306a36Sopenharmony_ci	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
339462306a36Sopenharmony_ci	.has_blink_output = true,
339562306a36Sopenharmony_ci	.has_usb_sleepwalk = true,
339662306a36Sopenharmony_ci};
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_cistatic const char * const tegra114_powergates[] = {
339962306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU] = "crail",
340062306a36Sopenharmony_ci	[TEGRA_POWERGATE_3D] = "td",
340162306a36Sopenharmony_ci	[TEGRA_POWERGATE_VENC] = "venc",
340262306a36Sopenharmony_ci	[TEGRA_POWERGATE_VDEC] = "vdec",
340362306a36Sopenharmony_ci	[TEGRA_POWERGATE_MPE] = "mpe",
340462306a36Sopenharmony_ci	[TEGRA_POWERGATE_HEG] = "heg",
340562306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU1] = "cpu1",
340662306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU2] = "cpu2",
340762306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU3] = "cpu3",
340862306a36Sopenharmony_ci	[TEGRA_POWERGATE_CELP] = "celp",
340962306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU0] = "cpu0",
341062306a36Sopenharmony_ci	[TEGRA_POWERGATE_C0NC] = "c0nc",
341162306a36Sopenharmony_ci	[TEGRA_POWERGATE_C1NC] = "c1nc",
341262306a36Sopenharmony_ci	[TEGRA_POWERGATE_DIS] = "dis",
341362306a36Sopenharmony_ci	[TEGRA_POWERGATE_DISB] = "disb",
341462306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBA] = "xusba",
341562306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBB] = "xusbb",
341662306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBC] = "xusbc",
341762306a36Sopenharmony_ci};
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_cistatic const u8 tegra114_cpu_powergates[] = {
342062306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU0,
342162306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU1,
342262306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU2,
342362306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU3,
342462306a36Sopenharmony_ci};
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_cistatic const struct tegra_pmc_soc tegra114_pmc_soc = {
342762306a36Sopenharmony_ci	.supports_core_domain = false,
342862306a36Sopenharmony_ci	.num_powergates = ARRAY_SIZE(tegra114_powergates),
342962306a36Sopenharmony_ci	.powergates = tegra114_powergates,
343062306a36Sopenharmony_ci	.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
343162306a36Sopenharmony_ci	.cpu_powergates = tegra114_cpu_powergates,
343262306a36Sopenharmony_ci	.has_tsense_reset = true,
343362306a36Sopenharmony_ci	.has_gpu_clamps = false,
343462306a36Sopenharmony_ci	.needs_mbist_war = false,
343562306a36Sopenharmony_ci	.has_impl_33v_pwr = false,
343662306a36Sopenharmony_ci	.maybe_tz_only = false,
343762306a36Sopenharmony_ci	.num_io_pads = 0,
343862306a36Sopenharmony_ci	.io_pads = NULL,
343962306a36Sopenharmony_ci	.num_pin_descs = 0,
344062306a36Sopenharmony_ci	.pin_descs = NULL,
344162306a36Sopenharmony_ci	.regs = &tegra20_pmc_regs,
344262306a36Sopenharmony_ci	.init = tegra20_pmc_init,
344362306a36Sopenharmony_ci	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
344462306a36Sopenharmony_ci	.powergate_set = tegra114_powergate_set,
344562306a36Sopenharmony_ci	.reset_sources = tegra30_reset_sources,
344662306a36Sopenharmony_ci	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
344762306a36Sopenharmony_ci	.reset_levels = NULL,
344862306a36Sopenharmony_ci	.num_reset_levels = 0,
344962306a36Sopenharmony_ci	.pmc_clks_data = tegra_pmc_clks_data,
345062306a36Sopenharmony_ci	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
345162306a36Sopenharmony_ci	.has_blink_output = true,
345262306a36Sopenharmony_ci	.has_usb_sleepwalk = true,
345362306a36Sopenharmony_ci};
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_cistatic const char * const tegra124_powergates[] = {
345662306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU] = "crail",
345762306a36Sopenharmony_ci	[TEGRA_POWERGATE_3D] = "3d",
345862306a36Sopenharmony_ci	[TEGRA_POWERGATE_VENC] = "venc",
345962306a36Sopenharmony_ci	[TEGRA_POWERGATE_PCIE] = "pcie",
346062306a36Sopenharmony_ci	[TEGRA_POWERGATE_VDEC] = "vdec",
346162306a36Sopenharmony_ci	[TEGRA_POWERGATE_MPE] = "mpe",
346262306a36Sopenharmony_ci	[TEGRA_POWERGATE_HEG] = "heg",
346362306a36Sopenharmony_ci	[TEGRA_POWERGATE_SATA] = "sata",
346462306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU1] = "cpu1",
346562306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU2] = "cpu2",
346662306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU3] = "cpu3",
346762306a36Sopenharmony_ci	[TEGRA_POWERGATE_CELP] = "celp",
346862306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU0] = "cpu0",
346962306a36Sopenharmony_ci	[TEGRA_POWERGATE_C0NC] = "c0nc",
347062306a36Sopenharmony_ci	[TEGRA_POWERGATE_C1NC] = "c1nc",
347162306a36Sopenharmony_ci	[TEGRA_POWERGATE_SOR] = "sor",
347262306a36Sopenharmony_ci	[TEGRA_POWERGATE_DIS] = "dis",
347362306a36Sopenharmony_ci	[TEGRA_POWERGATE_DISB] = "disb",
347462306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBA] = "xusba",
347562306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBB] = "xusbb",
347662306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBC] = "xusbc",
347762306a36Sopenharmony_ci	[TEGRA_POWERGATE_VIC] = "vic",
347862306a36Sopenharmony_ci	[TEGRA_POWERGATE_IRAM] = "iram",
347962306a36Sopenharmony_ci};
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_cistatic const u8 tegra124_cpu_powergates[] = {
348262306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU0,
348362306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU1,
348462306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU2,
348562306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU3,
348662306a36Sopenharmony_ci};
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci#define TEGRA_IO_PAD(_id, _dpd, _request, _status, _voltage, _name)	\
348962306a36Sopenharmony_ci	((struct tegra_io_pad_soc) {					\
349062306a36Sopenharmony_ci		.id		= (_id),				\
349162306a36Sopenharmony_ci		.dpd		= (_dpd),				\
349262306a36Sopenharmony_ci		.request	= (_request),				\
349362306a36Sopenharmony_ci		.status		= (_status),				\
349462306a36Sopenharmony_ci		.voltage	= (_voltage),				\
349562306a36Sopenharmony_ci		.name		= (_name),				\
349662306a36Sopenharmony_ci	})
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_ci#define TEGRA_IO_PIN_DESC(_id, _name)	\
349962306a36Sopenharmony_ci	((struct pinctrl_pin_desc) {	\
350062306a36Sopenharmony_ci		.number	= (_id),	\
350162306a36Sopenharmony_ci		.name	= (_name),	\
350262306a36Sopenharmony_ci	})
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_cistatic const struct tegra_io_pad_soc tegra124_io_pads[] = {
350562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, UINT_MAX, "audio"),
350662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_BB, 15, 0x1b8, 0x1bc, UINT_MAX, "bb"),
350762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, UINT_MAX, "cam"),
350862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_COMP, 22, 0x1b8, 0x1bc, UINT_MAX, "comp"),
350962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, UINT_MAX, "csia"),
351062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, UINT_MAX, "csib"),
351162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, UINT_MAX, "csie"),
351262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, UINT_MAX, "dsi"),
351362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, UINT_MAX, "dsib"),
351462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, UINT_MAX, "dsic"),
351562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, UINT_MAX, "dsid"),
351662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, UINT_MAX, "hdmi"),
351762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, UINT_MAX, "hsic"),
351862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HV, 6, 0x1c0, 0x1c4, UINT_MAX, "hv"),
351962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, UINT_MAX, "lvds"),
352062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, UINT_MAX, "mipi-bias"),
352162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_NAND, 13, 0x1b8, 0x1bc, UINT_MAX, "nand"),
352262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, UINT_MAX, "pex-bias"),
352362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, UINT_MAX, "pex-clk1"),
352462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, UINT_MAX, "pex-clk2"),
352562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x1c0, 0x1c4, UINT_MAX, "pex-cntrl"),
352662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, UINT_MAX, "sdmmc1"),
352762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, UINT_MAX, "sdmmc3"),
352862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 3, 0x1c0, 0x1c4, UINT_MAX, "sdmmc4"),
352962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SYS_DDC, 26, 0x1c0, 0x1c4, UINT_MAX, "sys_ddc"),
353062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, UINT_MAX, "uart"),
353162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, UINT_MAX, "usb0"),
353262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, UINT_MAX, "usb1"),
353362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, UINT_MAX, "usb2"),
353462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, UINT_MAX, "usb_bias"),
353562306a36Sopenharmony_ci};
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_cistatic const struct pinctrl_pin_desc tegra124_pin_descs[] = {
353862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
353962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_BB, "bb"),
354062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"),
354162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_COMP, "comp"),
354262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
354362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
354462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
354562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"),
354662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"),
354762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"),
354862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"),
354962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI, "hdmi"),
355062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"),
355162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HV, "hv"),
355262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_LVDS, "lvds"),
355362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"),
355462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_NAND, "nand"),
355562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_BIAS, "pex-bias"),
355662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"),
355762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"),
355862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"),
355962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1, "sdmmc1"),
356062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3, "sdmmc3"),
356162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"),
356262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SYS_DDC, "sys_ddc"),
356362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"),
356462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"),
356562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"),
356662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"),
356762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb_bias"),
356862306a36Sopenharmony_ci};
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_cistatic const struct tegra_pmc_soc tegra124_pmc_soc = {
357162306a36Sopenharmony_ci	.supports_core_domain = false,
357262306a36Sopenharmony_ci	.num_powergates = ARRAY_SIZE(tegra124_powergates),
357362306a36Sopenharmony_ci	.powergates = tegra124_powergates,
357462306a36Sopenharmony_ci	.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
357562306a36Sopenharmony_ci	.cpu_powergates = tegra124_cpu_powergates,
357662306a36Sopenharmony_ci	.has_tsense_reset = true,
357762306a36Sopenharmony_ci	.has_gpu_clamps = true,
357862306a36Sopenharmony_ci	.needs_mbist_war = false,
357962306a36Sopenharmony_ci	.has_impl_33v_pwr = false,
358062306a36Sopenharmony_ci	.maybe_tz_only = false,
358162306a36Sopenharmony_ci	.num_io_pads = ARRAY_SIZE(tegra124_io_pads),
358262306a36Sopenharmony_ci	.io_pads = tegra124_io_pads,
358362306a36Sopenharmony_ci	.num_pin_descs = ARRAY_SIZE(tegra124_pin_descs),
358462306a36Sopenharmony_ci	.pin_descs = tegra124_pin_descs,
358562306a36Sopenharmony_ci	.regs = &tegra20_pmc_regs,
358662306a36Sopenharmony_ci	.init = tegra20_pmc_init,
358762306a36Sopenharmony_ci	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
358862306a36Sopenharmony_ci	.powergate_set = tegra114_powergate_set,
358962306a36Sopenharmony_ci	.reset_sources = tegra30_reset_sources,
359062306a36Sopenharmony_ci	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
359162306a36Sopenharmony_ci	.reset_levels = NULL,
359262306a36Sopenharmony_ci	.num_reset_levels = 0,
359362306a36Sopenharmony_ci	.pmc_clks_data = tegra_pmc_clks_data,
359462306a36Sopenharmony_ci	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
359562306a36Sopenharmony_ci	.has_blink_output = true,
359662306a36Sopenharmony_ci	.has_usb_sleepwalk = true,
359762306a36Sopenharmony_ci};
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_cistatic const char * const tegra210_powergates[] = {
360062306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU] = "crail",
360162306a36Sopenharmony_ci	[TEGRA_POWERGATE_3D] = "3d",
360262306a36Sopenharmony_ci	[TEGRA_POWERGATE_VENC] = "venc",
360362306a36Sopenharmony_ci	[TEGRA_POWERGATE_PCIE] = "pcie",
360462306a36Sopenharmony_ci	[TEGRA_POWERGATE_MPE] = "mpe",
360562306a36Sopenharmony_ci	[TEGRA_POWERGATE_SATA] = "sata",
360662306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU1] = "cpu1",
360762306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU2] = "cpu2",
360862306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU3] = "cpu3",
360962306a36Sopenharmony_ci	[TEGRA_POWERGATE_CPU0] = "cpu0",
361062306a36Sopenharmony_ci	[TEGRA_POWERGATE_C0NC] = "c0nc",
361162306a36Sopenharmony_ci	[TEGRA_POWERGATE_SOR] = "sor",
361262306a36Sopenharmony_ci	[TEGRA_POWERGATE_DIS] = "dis",
361362306a36Sopenharmony_ci	[TEGRA_POWERGATE_DISB] = "disb",
361462306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBA] = "xusba",
361562306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBB] = "xusbb",
361662306a36Sopenharmony_ci	[TEGRA_POWERGATE_XUSBC] = "xusbc",
361762306a36Sopenharmony_ci	[TEGRA_POWERGATE_VIC] = "vic",
361862306a36Sopenharmony_ci	[TEGRA_POWERGATE_IRAM] = "iram",
361962306a36Sopenharmony_ci	[TEGRA_POWERGATE_NVDEC] = "nvdec",
362062306a36Sopenharmony_ci	[TEGRA_POWERGATE_NVJPG] = "nvjpg",
362162306a36Sopenharmony_ci	[TEGRA_POWERGATE_AUD] = "aud",
362262306a36Sopenharmony_ci	[TEGRA_POWERGATE_DFD] = "dfd",
362362306a36Sopenharmony_ci	[TEGRA_POWERGATE_VE2] = "ve2",
362462306a36Sopenharmony_ci};
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_cistatic const u8 tegra210_cpu_powergates[] = {
362762306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU0,
362862306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU1,
362962306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU2,
363062306a36Sopenharmony_ci	TEGRA_POWERGATE_CPU3,
363162306a36Sopenharmony_ci};
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_cistatic const struct tegra_io_pad_soc tegra210_io_pads[] = {
363462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, 5, "audio"),
363562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x1c0, 0x1c4, 18, "audio-hv"),
363662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, 10, "cam"),
363762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, UINT_MAX, "csia"),
363862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, UINT_MAX, "csib"),
363962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 10, 0x1c0, 0x1c4, UINT_MAX, "csic"),
364062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 11, 0x1c0, 0x1c4, UINT_MAX, "csid"),
364162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, UINT_MAX, "csie"),
364262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 13, 0x1c0, 0x1c4, UINT_MAX, "csif"),
364362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x1b8, 0x1bc, 19, "dbg"),
364462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DEBUG_NONAO, 26, 0x1b8, 0x1bc, UINT_MAX, "debug-nonao"),
364562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC, 18, 0x1c0, 0x1c4, 20, "dmic"),
364662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DP, 19, 0x1c0, 0x1c4, UINT_MAX, "dp"),
364762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, UINT_MAX, "dsi"),
364862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, UINT_MAX, "dsib"),
364962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, UINT_MAX, "dsic"),
365062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, UINT_MAX, "dsid"),
365162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC, 3, 0x1c0, 0x1c4, UINT_MAX, "emmc"),
365262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC2, 5, 0x1c0, 0x1c4, UINT_MAX, "emmc2"),
365362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_GPIO, 27, 0x1b8, 0x1bc, 21, "gpio"),
365462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, UINT_MAX, "hdmi"),
365562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, UINT_MAX, "hsic"),
365662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, UINT_MAX, "lvds"),
365762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, UINT_MAX, "mipi-bias"),
365862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, UINT_MAX, "pex-bias"),
365962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, UINT_MAX, "pex-clk1"),
366062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, UINT_MAX, "pex-clk2"),
366162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, UINT_MAX, UINT_MAX, 11, "pex-cntrl"),
366262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, 12, "sdmmc1"),
366362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, 13, "sdmmc3"),
366462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 14, 0x1c0, 0x1c4, 22, "spi"),
366562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SPI_HV, 15, 0x1c0, 0x1c4, 23, "spi-hv"),
366662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, 2, "uart"),
366762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, UINT_MAX, "usb0"),
366862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, UINT_MAX, "usb1"),
366962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, UINT_MAX, "usb2"),
367062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB3, 18, 0x1b8, 0x1bc, UINT_MAX, "usb3"),
367162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, UINT_MAX, "usb-bias"),
367262306a36Sopenharmony_ci};
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_cistatic const struct pinctrl_pin_desc tegra210_pin_descs[] = {
367562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
367662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
367762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"),
367862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
367962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
368062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
368162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
368262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
368362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
368462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"),
368562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DEBUG_NONAO, "debug-nonao"),
368662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DMIC, "dmic"),
368762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DP, "dp"),
368862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"),
368962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"),
369062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"),
369162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"),
369262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EMMC, "emmc"),
369362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EMMC2, "emmc2"),
369462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GPIO, "gpio"),
369562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI, "hdmi"),
369662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"),
369762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_LVDS, "lvds"),
369862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"),
369962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_BIAS, "pex-bias"),
370062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"),
370162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"),
370262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"),
370362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1, "sdmmc1"),
370462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3, "sdmmc3"),
370562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"),
370662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI_HV, "spi-hv"),
370762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"),
370862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"),
370962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"),
371062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"),
371162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB3, "usb3"),
371262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb-bias"),
371362306a36Sopenharmony_ci};
371462306a36Sopenharmony_ci
371562306a36Sopenharmony_cistatic const char * const tegra210_reset_sources[] = {
371662306a36Sopenharmony_ci	"POWER_ON_RESET",
371762306a36Sopenharmony_ci	"WATCHDOG",
371862306a36Sopenharmony_ci	"SENSOR",
371962306a36Sopenharmony_ci	"SW_MAIN",
372062306a36Sopenharmony_ci	"LP0",
372162306a36Sopenharmony_ci	"AOTAG"
372262306a36Sopenharmony_ci};
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_cistatic const struct tegra_wake_event tegra210_wake_events[] = {
372562306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("rtc", 16, 2),
372662306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("pmu", 51, 86),
372762306a36Sopenharmony_ci};
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_cistatic const struct tegra_pmc_soc tegra210_pmc_soc = {
373062306a36Sopenharmony_ci	.supports_core_domain = false,
373162306a36Sopenharmony_ci	.num_powergates = ARRAY_SIZE(tegra210_powergates),
373262306a36Sopenharmony_ci	.powergates = tegra210_powergates,
373362306a36Sopenharmony_ci	.num_cpu_powergates = ARRAY_SIZE(tegra210_cpu_powergates),
373462306a36Sopenharmony_ci	.cpu_powergates = tegra210_cpu_powergates,
373562306a36Sopenharmony_ci	.has_tsense_reset = true,
373662306a36Sopenharmony_ci	.has_gpu_clamps = true,
373762306a36Sopenharmony_ci	.needs_mbist_war = true,
373862306a36Sopenharmony_ci	.has_impl_33v_pwr = false,
373962306a36Sopenharmony_ci	.maybe_tz_only = true,
374062306a36Sopenharmony_ci	.num_io_pads = ARRAY_SIZE(tegra210_io_pads),
374162306a36Sopenharmony_ci	.io_pads = tegra210_io_pads,
374262306a36Sopenharmony_ci	.num_pin_descs = ARRAY_SIZE(tegra210_pin_descs),
374362306a36Sopenharmony_ci	.pin_descs = tegra210_pin_descs,
374462306a36Sopenharmony_ci	.regs = &tegra20_pmc_regs,
374562306a36Sopenharmony_ci	.init = tegra20_pmc_init,
374662306a36Sopenharmony_ci	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
374762306a36Sopenharmony_ci	.powergate_set = tegra114_powergate_set,
374862306a36Sopenharmony_ci	.irq_set_wake = tegra210_pmc_irq_set_wake,
374962306a36Sopenharmony_ci	.irq_set_type = tegra210_pmc_irq_set_type,
375062306a36Sopenharmony_ci	.reset_sources = tegra210_reset_sources,
375162306a36Sopenharmony_ci	.num_reset_sources = ARRAY_SIZE(tegra210_reset_sources),
375262306a36Sopenharmony_ci	.reset_levels = NULL,
375362306a36Sopenharmony_ci	.num_reset_levels = 0,
375462306a36Sopenharmony_ci	.num_wake_events = ARRAY_SIZE(tegra210_wake_events),
375562306a36Sopenharmony_ci	.wake_events = tegra210_wake_events,
375662306a36Sopenharmony_ci	.pmc_clks_data = tegra_pmc_clks_data,
375762306a36Sopenharmony_ci	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
375862306a36Sopenharmony_ci	.has_blink_output = true,
375962306a36Sopenharmony_ci	.has_usb_sleepwalk = true,
376062306a36Sopenharmony_ci};
376162306a36Sopenharmony_ci
376262306a36Sopenharmony_cistatic const struct tegra_io_pad_soc tegra186_io_pads[] = {
376362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, UINT_MAX, "csia"),
376462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, UINT_MAX, "csib"),
376562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x74, 0x78, UINT_MAX, "dsi"),
376662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, UINT_MAX, "mipi-bias"),
376762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, UINT_MAX, "pex-clk-bias"),
376862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, UINT_MAX, "pex-clk3"),
376962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, UINT_MAX, "pex-clk2"),
377062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, UINT_MAX, "pex-clk1"),
377162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x74, 0x78, UINT_MAX, "usb0"),
377262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x74, 0x78, UINT_MAX, "usb1"),
377362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x74, 0x78, UINT_MAX, "usb2"),
377462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x74, 0x78, UINT_MAX, "usb-bias"),
377562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, UINT_MAX, "uart"),
377662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, UINT_MAX, "audio"),
377762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x74, 0x78, UINT_MAX, "hsic"),
377862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, UINT_MAX, "dbg"),
377962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, UINT_MAX, "hdmi-dp0"),
378062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, UINT_MAX, "hdmi-dp1"),
378162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, UINT_MAX, "pex-cntrl"),
378262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC2_HV, 2, 0x7c, 0x80, 5, "sdmmc2-hv"),
378362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, UINT_MAX, "sdmmc4"),
378462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, UINT_MAX, "cam"),
378562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 8, 0x7c, 0x80, UINT_MAX, "dsib"),
378662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 9, 0x7c, 0x80, UINT_MAX, "dsic"),
378762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 10, 0x7c, 0x80, UINT_MAX, "dsid"),
378862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, UINT_MAX, "csic"),
378962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, UINT_MAX, "csid"),
379062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, UINT_MAX, "csie"),
379162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, UINT_MAX, "csif"),
379262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, UINT_MAX, "spi"),
379362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, UINT_MAX, "ufs"),
379462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC_HV, 20, 0x7c, 0x80, 2, "dmic-hv"),
379562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, UINT_MAX, "edp"),
379662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, 4, "sdmmc1-hv"),
379762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, 6, "sdmmc3-hv"),
379862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, UINT_MAX, "conn"),
379962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, 1, "audio-hv"),
380062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
380162306a36Sopenharmony_ci};
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_cistatic const struct pinctrl_pin_desc tegra186_pin_descs[] = {
380462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
380562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
380662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"),
380762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"),
380862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_BIAS, "pex-clk-bias"),
380962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK3, "pex-clk3"),
381062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"),
381162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"),
381262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"),
381362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"),
381462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"),
381562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb-bias"),
381662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"),
381762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
381862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"),
381962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"),
382062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"),
382162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP1, "hdmi-dp1"),
382262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"),
382362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC2_HV, "sdmmc2-hv"),
382462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"),
382562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"),
382662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"),
382762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"),
382862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"),
382962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
383062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
383162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
383262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
383362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"),
383462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"),
383562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DMIC_HV, "dmic-hv"),
383662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"),
383762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"),
383862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3_HV, "sdmmc3-hv"),
383962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CONN, "conn"),
384062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
384162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AO_HV, "ao-hv"),
384262306a36Sopenharmony_ci};
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_cistatic const struct tegra_pmc_regs tegra186_pmc_regs = {
384562306a36Sopenharmony_ci	.scratch0 = 0x2000,
384662306a36Sopenharmony_ci	.rst_status = 0x70,
384762306a36Sopenharmony_ci	.rst_source_shift = 0x2,
384862306a36Sopenharmony_ci	.rst_source_mask = 0x3c,
384962306a36Sopenharmony_ci	.rst_level_shift = 0x0,
385062306a36Sopenharmony_ci	.rst_level_mask = 0x3,
385162306a36Sopenharmony_ci};
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_cistatic void tegra186_pmc_init(struct tegra_pmc *pmc)
385462306a36Sopenharmony_ci{
385562306a36Sopenharmony_ci	pmc->syscore.suspend = tegra186_pmc_wake_syscore_suspend;
385662306a36Sopenharmony_ci	pmc->syscore.resume = tegra186_pmc_wake_syscore_resume;
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_ci	register_syscore_ops(&pmc->syscore);
385962306a36Sopenharmony_ci}
386062306a36Sopenharmony_ci
386162306a36Sopenharmony_cistatic void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
386262306a36Sopenharmony_ci					    struct device_node *np,
386362306a36Sopenharmony_ci					    bool invert)
386462306a36Sopenharmony_ci{
386562306a36Sopenharmony_ci	struct resource regs;
386662306a36Sopenharmony_ci	void __iomem *wake;
386762306a36Sopenharmony_ci	u32 value;
386862306a36Sopenharmony_ci	int index;
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci	index = of_property_match_string(np, "reg-names", "wake");
387162306a36Sopenharmony_ci	if (index < 0) {
387262306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to find PMC wake registers\n");
387362306a36Sopenharmony_ci		return;
387462306a36Sopenharmony_ci	}
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci	of_address_to_resource(np, index, &regs);
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci	wake = ioremap(regs.start, resource_size(&regs));
387962306a36Sopenharmony_ci	if (!wake) {
388062306a36Sopenharmony_ci		dev_err(pmc->dev, "failed to map PMC wake registers\n");
388162306a36Sopenharmony_ci		return;
388262306a36Sopenharmony_ci	}
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	value = readl(wake + WAKE_AOWAKE_CTRL);
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci	if (invert)
388762306a36Sopenharmony_ci		value |= WAKE_AOWAKE_CTRL_INTR_POLARITY;
388862306a36Sopenharmony_ci	else
388962306a36Sopenharmony_ci		value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY;
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_ci	writel(value, wake + WAKE_AOWAKE_CTRL);
389262306a36Sopenharmony_ci
389362306a36Sopenharmony_ci	iounmap(wake);
389462306a36Sopenharmony_ci}
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_cistatic const char * const tegra186_reset_sources[] = {
389762306a36Sopenharmony_ci	"SYS_RESET",
389862306a36Sopenharmony_ci	"AOWDT",
389962306a36Sopenharmony_ci	"MCCPLEXWDT",
390062306a36Sopenharmony_ci	"BPMPWDT",
390162306a36Sopenharmony_ci	"SCEWDT",
390262306a36Sopenharmony_ci	"SPEWDT",
390362306a36Sopenharmony_ci	"APEWDT",
390462306a36Sopenharmony_ci	"BCCPLEXWDT",
390562306a36Sopenharmony_ci	"SENSOR",
390662306a36Sopenharmony_ci	"AOTAG",
390762306a36Sopenharmony_ci	"VFSENSOR",
390862306a36Sopenharmony_ci	"SWREST",
390962306a36Sopenharmony_ci	"SC7",
391062306a36Sopenharmony_ci	"HSM",
391162306a36Sopenharmony_ci	"CORESIGHT"
391262306a36Sopenharmony_ci};
391362306a36Sopenharmony_ci
391462306a36Sopenharmony_cistatic const char * const tegra186_reset_levels[] = {
391562306a36Sopenharmony_ci	"L0", "L1", "L2", "WARM"
391662306a36Sopenharmony_ci};
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_cistatic const struct tegra_wake_event tegra186_wake_events[] = {
391962306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("pmu", 24, 209),
392062306a36Sopenharmony_ci	TEGRA_WAKE_GPIO("power", 29, 1, TEGRA186_AON_GPIO(FF, 0)),
392162306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("rtc", 73, 10),
392262306a36Sopenharmony_ci};
392362306a36Sopenharmony_ci
392462306a36Sopenharmony_cistatic const struct tegra_pmc_soc tegra186_pmc_soc = {
392562306a36Sopenharmony_ci	.supports_core_domain = false,
392662306a36Sopenharmony_ci	.num_powergates = 0,
392762306a36Sopenharmony_ci	.powergates = NULL,
392862306a36Sopenharmony_ci	.num_cpu_powergates = 0,
392962306a36Sopenharmony_ci	.cpu_powergates = NULL,
393062306a36Sopenharmony_ci	.has_tsense_reset = false,
393162306a36Sopenharmony_ci	.has_gpu_clamps = false,
393262306a36Sopenharmony_ci	.needs_mbist_war = false,
393362306a36Sopenharmony_ci	.has_impl_33v_pwr = true,
393462306a36Sopenharmony_ci	.maybe_tz_only = false,
393562306a36Sopenharmony_ci	.num_io_pads = ARRAY_SIZE(tegra186_io_pads),
393662306a36Sopenharmony_ci	.io_pads = tegra186_io_pads,
393762306a36Sopenharmony_ci	.num_pin_descs = ARRAY_SIZE(tegra186_pin_descs),
393862306a36Sopenharmony_ci	.pin_descs = tegra186_pin_descs,
393962306a36Sopenharmony_ci	.regs = &tegra186_pmc_regs,
394062306a36Sopenharmony_ci	.init = tegra186_pmc_init,
394162306a36Sopenharmony_ci	.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
394262306a36Sopenharmony_ci	.set_wake_filters = tegra186_pmc_set_wake_filters,
394362306a36Sopenharmony_ci	.irq_set_wake = tegra186_pmc_irq_set_wake,
394462306a36Sopenharmony_ci	.irq_set_type = tegra186_pmc_irq_set_type,
394562306a36Sopenharmony_ci	.reset_sources = tegra186_reset_sources,
394662306a36Sopenharmony_ci	.num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
394762306a36Sopenharmony_ci	.reset_levels = tegra186_reset_levels,
394862306a36Sopenharmony_ci	.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
394962306a36Sopenharmony_ci	.num_wake_events = ARRAY_SIZE(tegra186_wake_events),
395062306a36Sopenharmony_ci	.wake_events = tegra186_wake_events,
395162306a36Sopenharmony_ci	.max_wake_events = 96,
395262306a36Sopenharmony_ci	.max_wake_vectors = 3,
395362306a36Sopenharmony_ci	.pmc_clks_data = NULL,
395462306a36Sopenharmony_ci	.num_pmc_clks = 0,
395562306a36Sopenharmony_ci	.has_blink_output = false,
395662306a36Sopenharmony_ci	.has_usb_sleepwalk = false,
395762306a36Sopenharmony_ci};
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_cistatic const struct tegra_io_pad_soc tegra194_io_pads[] = {
396062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, UINT_MAX, "csia"),
396162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, UINT_MAX, "csib"),
396262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, UINT_MAX, "mipi-bias"),
396362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, UINT_MAX, "pex-clk-bias"),
396462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, UINT_MAX, "pex-clk3"),
396562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, UINT_MAX, "pex-clk2"),
396662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, UINT_MAX, "pex-clk1"),
396762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_EQOS, 8, 0x74, 0x78, UINT_MAX, "eqos"),
396862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, 0x74, 0x78, UINT_MAX, "pex-clk-2-bias"),
396962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2, 10, 0x74, 0x78, UINT_MAX, "pex-clk-2"),
397062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DAP3, 11, 0x74, 0x78, UINT_MAX, "dap3"),
397162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DAP5, 12, 0x74, 0x78, UINT_MAX, "dap5"),
397262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, UINT_MAX, "uart"),
397362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PWR_CTL, 15, 0x74, 0x78, UINT_MAX, "pwr-ctl"),
397462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO53, 16, 0x74, 0x78, UINT_MAX, "soc-gpio53"),
397562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, UINT_MAX, "audio"),
397662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM2, 18, 0x74, 0x78, UINT_MAX, "gp-pwm2"),
397762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM3, 19, 0x74, 0x78, UINT_MAX, "gp-pwm3"),
397862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO12, 20, 0x74, 0x78, UINT_MAX, "soc-gpio12"),
397962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO13, 21, 0x74, 0x78, UINT_MAX, "soc-gpio13"),
398062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO10, 22, 0x74, 0x78, UINT_MAX, "soc-gpio10"),
398162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UART4, 23, 0x74, 0x78, UINT_MAX, "uart4"),
398262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UART5, 24, 0x74, 0x78, UINT_MAX, "uart5"),
398362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, UINT_MAX, "dbg"),
398462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP3, 26, 0x74, 0x78, UINT_MAX, "hdmi-dp3"),
398562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP2, 27, 0x74, 0x78, UINT_MAX, "hdmi-dp2"),
398662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, UINT_MAX, "hdmi-dp0"),
398762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, UINT_MAX, "hdmi-dp1"),
398862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, UINT_MAX, "pex-cntrl"),
398962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CTL2, 1, 0x7c, 0x80, UINT_MAX, "pex-ctl2"),
399062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L0_RST, 2, 0x7c, 0x80, UINT_MAX, "pex-l0-rst"),
399162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L1_RST, 3, 0x7c, 0x80, UINT_MAX, "pex-l1-rst"),
399262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, UINT_MAX, "sdmmc4"),
399362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L5_RST, 5, 0x7c, 0x80, UINT_MAX, "pex-l5-rst"),
399462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, UINT_MAX, "cam"),
399562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, UINT_MAX, "csic"),
399662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, UINT_MAX, "csid"),
399762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, UINT_MAX, "csie"),
399862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, UINT_MAX, "csif"),
399962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, UINT_MAX, "spi"),
400062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, UINT_MAX, "ufs"),
400162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 18, 0x7c, 0x80, UINT_MAX, "csig"),
400262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 19, 0x7c, 0x80, UINT_MAX, "csih"),
400362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, UINT_MAX, "edp"),
400462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, 4, "sdmmc1-hv"),
400562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, 6, "sdmmc3-hv"),
400662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, UINT_MAX, "conn"),
400762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, 1, "audio-hv"),
400862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
400962306a36Sopenharmony_ci};
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_cistatic const struct pinctrl_pin_desc tegra194_pin_descs[] = {
401262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
401362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
401462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"),
401562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_BIAS, "pex-clk-bias"),
401662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK3, "pex-clk3"),
401762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"),
401862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"),
401962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EQOS, "eqos"),
402062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_2_BIAS, "pex-clk-2-bias"),
402162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_2, "pex-clk-2"),
402262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DAP3, "dap3"),
402362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DAP5, "dap5"),
402462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"),
402562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PWR_CTL, "pwr-ctl"),
402662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO53, "soc-gpio53"),
402762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
402862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GP_PWM2, "gp-pwm2"),
402962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GP_PWM3, "gp-pwm3"),
403062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO12, "soc-gpio12"),
403162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO13, "soc-gpio13"),
403262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO10, "soc-gpio10"),
403362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART4, "uart4"),
403462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART5, "uart5"),
403562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"),
403662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP3, "hdmi-dp3"),
403762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP2, "hdmi-dp2"),
403862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"),
403962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP1, "hdmi-dp1"),
404062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"),
404162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CTL2, "pex-ctl2"),
404262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L0_RST, "pex-l0-rst"),
404362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L1_RST, "pex-l1-rst"),
404462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"),
404562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L5_RST, "pex-l5-rst"),
404662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"),
404762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
404862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
404962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
405062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
405162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"),
405262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"),
405362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIG, "csig"),
405462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIH, "csih"),
405562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"),
405662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"),
405762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3_HV, "sdmmc3-hv"),
405862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CONN, "conn"),
405962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
406062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AO_HV, "ao-hv"),
406162306a36Sopenharmony_ci};
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_cistatic const struct tegra_pmc_regs tegra194_pmc_regs = {
406462306a36Sopenharmony_ci	.scratch0 = 0x2000,
406562306a36Sopenharmony_ci	.rst_status = 0x70,
406662306a36Sopenharmony_ci	.rst_source_shift = 0x2,
406762306a36Sopenharmony_ci	.rst_source_mask = 0x7c,
406862306a36Sopenharmony_ci	.rst_level_shift = 0x0,
406962306a36Sopenharmony_ci	.rst_level_mask = 0x3,
407062306a36Sopenharmony_ci};
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_cistatic const char * const tegra194_reset_sources[] = {
407362306a36Sopenharmony_ci	"SYS_RESET_N",
407462306a36Sopenharmony_ci	"AOWDT",
407562306a36Sopenharmony_ci	"BCCPLEXWDT",
407662306a36Sopenharmony_ci	"BPMPWDT",
407762306a36Sopenharmony_ci	"SCEWDT",
407862306a36Sopenharmony_ci	"SPEWDT",
407962306a36Sopenharmony_ci	"APEWDT",
408062306a36Sopenharmony_ci	"LCCPLEXWDT",
408162306a36Sopenharmony_ci	"SENSOR",
408262306a36Sopenharmony_ci	"AOTAG",
408362306a36Sopenharmony_ci	"VFSENSOR",
408462306a36Sopenharmony_ci	"MAINSWRST",
408562306a36Sopenharmony_ci	"SC7",
408662306a36Sopenharmony_ci	"HSM",
408762306a36Sopenharmony_ci	"CSITE",
408862306a36Sopenharmony_ci	"RCEWDT",
408962306a36Sopenharmony_ci	"PVA0WDT",
409062306a36Sopenharmony_ci	"PVA1WDT",
409162306a36Sopenharmony_ci	"L1A_ASYNC",
409262306a36Sopenharmony_ci	"BPMPBOOT",
409362306a36Sopenharmony_ci	"FUSECRC",
409462306a36Sopenharmony_ci};
409562306a36Sopenharmony_ci
409662306a36Sopenharmony_cistatic const struct tegra_wake_event tegra194_wake_events[] = {
409762306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("pmu", 24, 209),
409862306a36Sopenharmony_ci	TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)),
409962306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("rtc", 73, 10),
410062306a36Sopenharmony_ci	TEGRA_WAKE_SIMPLE("usb3-port-0", 76),
410162306a36Sopenharmony_ci	TEGRA_WAKE_SIMPLE("usb3-port-1", 77),
410262306a36Sopenharmony_ci	TEGRA_WAKE_SIMPLE("usb3-port-2-3", 78),
410362306a36Sopenharmony_ci	TEGRA_WAKE_SIMPLE("usb2-port-0", 79),
410462306a36Sopenharmony_ci	TEGRA_WAKE_SIMPLE("usb2-port-1", 80),
410562306a36Sopenharmony_ci	TEGRA_WAKE_SIMPLE("usb2-port-2", 81),
410662306a36Sopenharmony_ci	TEGRA_WAKE_SIMPLE("usb2-port-3", 82),
410762306a36Sopenharmony_ci};
410862306a36Sopenharmony_ci
410962306a36Sopenharmony_cistatic const struct tegra_pmc_soc tegra194_pmc_soc = {
411062306a36Sopenharmony_ci	.supports_core_domain = false,
411162306a36Sopenharmony_ci	.num_powergates = 0,
411262306a36Sopenharmony_ci	.powergates = NULL,
411362306a36Sopenharmony_ci	.num_cpu_powergates = 0,
411462306a36Sopenharmony_ci	.cpu_powergates = NULL,
411562306a36Sopenharmony_ci	.has_tsense_reset = false,
411662306a36Sopenharmony_ci	.has_gpu_clamps = false,
411762306a36Sopenharmony_ci	.needs_mbist_war = false,
411862306a36Sopenharmony_ci	.has_impl_33v_pwr = true,
411962306a36Sopenharmony_ci	.maybe_tz_only = false,
412062306a36Sopenharmony_ci	.num_io_pads = ARRAY_SIZE(tegra194_io_pads),
412162306a36Sopenharmony_ci	.io_pads = tegra194_io_pads,
412262306a36Sopenharmony_ci	.num_pin_descs = ARRAY_SIZE(tegra194_pin_descs),
412362306a36Sopenharmony_ci	.pin_descs = tegra194_pin_descs,
412462306a36Sopenharmony_ci	.regs = &tegra194_pmc_regs,
412562306a36Sopenharmony_ci	.init = tegra186_pmc_init,
412662306a36Sopenharmony_ci	.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
412762306a36Sopenharmony_ci	.set_wake_filters = tegra186_pmc_set_wake_filters,
412862306a36Sopenharmony_ci	.irq_set_wake = tegra186_pmc_irq_set_wake,
412962306a36Sopenharmony_ci	.irq_set_type = tegra186_pmc_irq_set_type,
413062306a36Sopenharmony_ci	.reset_sources = tegra194_reset_sources,
413162306a36Sopenharmony_ci	.num_reset_sources = ARRAY_SIZE(tegra194_reset_sources),
413262306a36Sopenharmony_ci	.reset_levels = tegra186_reset_levels,
413362306a36Sopenharmony_ci	.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
413462306a36Sopenharmony_ci	.num_wake_events = ARRAY_SIZE(tegra194_wake_events),
413562306a36Sopenharmony_ci	.wake_events = tegra194_wake_events,
413662306a36Sopenharmony_ci	.max_wake_events = 96,
413762306a36Sopenharmony_ci	.max_wake_vectors = 3,
413862306a36Sopenharmony_ci	.pmc_clks_data = NULL,
413962306a36Sopenharmony_ci	.num_pmc_clks = 0,
414062306a36Sopenharmony_ci	.has_blink_output = false,
414162306a36Sopenharmony_ci	.has_usb_sleepwalk = false,
414262306a36Sopenharmony_ci};
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_cistatic const struct tegra_io_pad_soc tegra234_io_pads[] = {
414562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0xe0c0, 0xe0c4, UINT_MAX, "csia"),
414662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0xe0c0, 0xe0c4, UINT_MAX, "csib"),
414762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 0, 0xe0d0, 0xe0d4, UINT_MAX, "hdmi-dp0"),
414862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 2, 0xe0c0, 0xe0c4, UINT_MAX, "csic"),
414962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 3, 0xe0c0, 0xe0c4, UINT_MAX, "csid"),
415062306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 4, 0xe0c0, 0xe0c4, UINT_MAX, "csie"),
415162306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 5, 0xe0c0, 0xe0c4, UINT_MAX, "csif"),
415262306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 0, 0xe064, 0xe068, UINT_MAX, "ufs"),
415362306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 1, 0xe05c, 0xe060, UINT_MAX, "edp"),
415462306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 0, 0xe054, 0xe058, 4, "sdmmc1-hv"),
415562306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, UINT_MAX, UINT_MAX, UINT_MAX, 6, "sdmmc3-hv"),
415662306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 1, "audio-hv"),
415762306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
415862306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 6, 0xe0c0, 0xe0c4, UINT_MAX, "csig"),
415962306a36Sopenharmony_ci	TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 7, 0xe0c0, 0xe0c4, UINT_MAX, "csih"),
416062306a36Sopenharmony_ci};
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_cistatic const struct pinctrl_pin_desc tegra234_pin_descs[] = {
416362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
416462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
416562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"),
416662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
416762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
416862306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
416962306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
417062306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"),
417162306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"),
417262306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"),
417362306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3_HV, "sdmmc3-hv"),
417462306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
417562306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AO_HV, "ao-hv"),
417662306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIG, "csig"),
417762306a36Sopenharmony_ci	TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIH, "csih"),
417862306a36Sopenharmony_ci};
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_cistatic const struct tegra_pmc_regs tegra234_pmc_regs = {
418162306a36Sopenharmony_ci	.scratch0 = 0x2000,
418262306a36Sopenharmony_ci	.rst_status = 0x70,
418362306a36Sopenharmony_ci	.rst_source_shift = 0x2,
418462306a36Sopenharmony_ci	.rst_source_mask = 0xfc,
418562306a36Sopenharmony_ci	.rst_level_shift = 0x0,
418662306a36Sopenharmony_ci	.rst_level_mask = 0x3,
418762306a36Sopenharmony_ci};
418862306a36Sopenharmony_ci
418962306a36Sopenharmony_cistatic const char * const tegra234_reset_sources[] = {
419062306a36Sopenharmony_ci	"SYS_RESET_N",	/* 0x0 */
419162306a36Sopenharmony_ci	"AOWDT",
419262306a36Sopenharmony_ci	"BCCPLEXWDT",
419362306a36Sopenharmony_ci	"BPMPWDT",
419462306a36Sopenharmony_ci	"SCEWDT",
419562306a36Sopenharmony_ci	"SPEWDT",
419662306a36Sopenharmony_ci	"APEWDT",
419762306a36Sopenharmony_ci	"LCCPLEXWDT",
419862306a36Sopenharmony_ci	"SENSOR",	/* 0x8 */
419962306a36Sopenharmony_ci	NULL,
420062306a36Sopenharmony_ci	NULL,
420162306a36Sopenharmony_ci	"MAINSWRST",
420262306a36Sopenharmony_ci	"SC7",
420362306a36Sopenharmony_ci	"HSM",
420462306a36Sopenharmony_ci	NULL,
420562306a36Sopenharmony_ci	"RCEWDT",
420662306a36Sopenharmony_ci	NULL,		/* 0x10 */
420762306a36Sopenharmony_ci	NULL,
420862306a36Sopenharmony_ci	NULL,
420962306a36Sopenharmony_ci	"BPMPBOOT",
421062306a36Sopenharmony_ci	"FUSECRC",
421162306a36Sopenharmony_ci	"DCEWDT",
421262306a36Sopenharmony_ci	"PSCWDT",
421362306a36Sopenharmony_ci	"PSC",
421462306a36Sopenharmony_ci	"CSITE_SW",	/* 0x18 */
421562306a36Sopenharmony_ci	"POD",
421662306a36Sopenharmony_ci	"SCPM",
421762306a36Sopenharmony_ci	"VREFRO_POWERBAD",
421862306a36Sopenharmony_ci	"VMON",
421962306a36Sopenharmony_ci	"FMON",
422062306a36Sopenharmony_ci	"FSI_R5WDT",
422162306a36Sopenharmony_ci	"FSI_THERM",
422262306a36Sopenharmony_ci	"FSI_R52C0WDT",	/* 0x20 */
422362306a36Sopenharmony_ci	"FSI_R52C1WDT",
422462306a36Sopenharmony_ci	"FSI_R52C2WDT",
422562306a36Sopenharmony_ci	"FSI_R52C3WDT",
422662306a36Sopenharmony_ci	"FSI_FMON",
422762306a36Sopenharmony_ci	"FSI_VMON",	/* 0x25 */
422862306a36Sopenharmony_ci};
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_cistatic const struct tegra_wake_event tegra234_wake_events[] = {
423162306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("pmu", 24, 209),
423262306a36Sopenharmony_ci	TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)),
423362306a36Sopenharmony_ci	TEGRA_WAKE_GPIO("mgbe", 56, 0, TEGRA234_MAIN_GPIO(Y, 3)),
423462306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("rtc", 73, 10),
423562306a36Sopenharmony_ci	TEGRA_WAKE_IRQ("sw-wake", SW_WAKE_ID, 179),
423662306a36Sopenharmony_ci};
423762306a36Sopenharmony_ci
423862306a36Sopenharmony_cistatic const struct tegra_pmc_soc tegra234_pmc_soc = {
423962306a36Sopenharmony_ci	.supports_core_domain = false,
424062306a36Sopenharmony_ci	.num_powergates = 0,
424162306a36Sopenharmony_ci	.powergates = NULL,
424262306a36Sopenharmony_ci	.num_cpu_powergates = 0,
424362306a36Sopenharmony_ci	.cpu_powergates = NULL,
424462306a36Sopenharmony_ci	.has_tsense_reset = false,
424562306a36Sopenharmony_ci	.has_gpu_clamps = false,
424662306a36Sopenharmony_ci	.needs_mbist_war = false,
424762306a36Sopenharmony_ci	.has_impl_33v_pwr = true,
424862306a36Sopenharmony_ci	.maybe_tz_only = false,
424962306a36Sopenharmony_ci	.num_io_pads = ARRAY_SIZE(tegra234_io_pads),
425062306a36Sopenharmony_ci	.io_pads = tegra234_io_pads,
425162306a36Sopenharmony_ci	.num_pin_descs = ARRAY_SIZE(tegra234_pin_descs),
425262306a36Sopenharmony_ci	.pin_descs = tegra234_pin_descs,
425362306a36Sopenharmony_ci	.regs = &tegra234_pmc_regs,
425462306a36Sopenharmony_ci	.init = tegra186_pmc_init,
425562306a36Sopenharmony_ci	.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
425662306a36Sopenharmony_ci	.set_wake_filters = tegra186_pmc_set_wake_filters,
425762306a36Sopenharmony_ci	.irq_set_wake = tegra186_pmc_irq_set_wake,
425862306a36Sopenharmony_ci	.irq_set_type = tegra186_pmc_irq_set_type,
425962306a36Sopenharmony_ci	.reset_sources = tegra234_reset_sources,
426062306a36Sopenharmony_ci	.num_reset_sources = ARRAY_SIZE(tegra234_reset_sources),
426162306a36Sopenharmony_ci	.reset_levels = tegra186_reset_levels,
426262306a36Sopenharmony_ci	.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
426362306a36Sopenharmony_ci	.num_wake_events = ARRAY_SIZE(tegra234_wake_events),
426462306a36Sopenharmony_ci	.wake_events = tegra234_wake_events,
426562306a36Sopenharmony_ci	.max_wake_events = 96,
426662306a36Sopenharmony_ci	.max_wake_vectors = 3,
426762306a36Sopenharmony_ci	.pmc_clks_data = NULL,
426862306a36Sopenharmony_ci	.num_pmc_clks = 0,
426962306a36Sopenharmony_ci	.has_blink_output = false,
427062306a36Sopenharmony_ci};
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_cistatic const struct of_device_id tegra_pmc_match[] = {
427362306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc },
427462306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc },
427562306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc },
427662306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc },
427762306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc },
427862306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc },
427962306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc },
428062306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra30-pmc", .data = &tegra30_pmc_soc },
428162306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra20-pmc", .data = &tegra20_pmc_soc },
428262306a36Sopenharmony_ci	{ }
428362306a36Sopenharmony_ci};
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_cistatic void tegra_pmc_sync_state(struct device *dev)
428662306a36Sopenharmony_ci{
428762306a36Sopenharmony_ci	int err;
428862306a36Sopenharmony_ci
428962306a36Sopenharmony_ci	/*
429062306a36Sopenharmony_ci	 * Newer device-trees have power domains, but we need to prepare all
429162306a36Sopenharmony_ci	 * device drivers with runtime PM and OPP support first, otherwise
429262306a36Sopenharmony_ci	 * state syncing is unsafe.
429362306a36Sopenharmony_ci	 */
429462306a36Sopenharmony_ci	if (!pmc->soc->supports_core_domain)
429562306a36Sopenharmony_ci		return;
429662306a36Sopenharmony_ci
429762306a36Sopenharmony_ci	/*
429862306a36Sopenharmony_ci	 * Older device-trees don't have core PD, and thus, there are
429962306a36Sopenharmony_ci	 * no dependencies that will block the state syncing. We shouldn't
430062306a36Sopenharmony_ci	 * mark the domain as synced in this case.
430162306a36Sopenharmony_ci	 */
430262306a36Sopenharmony_ci	if (!pmc->core_domain_registered)
430362306a36Sopenharmony_ci		return;
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	pmc->core_domain_state_synced = true;
430662306a36Sopenharmony_ci
430762306a36Sopenharmony_ci	/* this is a no-op if core regulator isn't used */
430862306a36Sopenharmony_ci	mutex_lock(&pmc->powergates_lock);
430962306a36Sopenharmony_ci	err = dev_pm_opp_sync_regulators(dev);
431062306a36Sopenharmony_ci	mutex_unlock(&pmc->powergates_lock);
431162306a36Sopenharmony_ci
431262306a36Sopenharmony_ci	if (err)
431362306a36Sopenharmony_ci		dev_err(dev, "failed to sync regulators: %d\n", err);
431462306a36Sopenharmony_ci}
431562306a36Sopenharmony_ci
431662306a36Sopenharmony_cistatic struct platform_driver tegra_pmc_driver = {
431762306a36Sopenharmony_ci	.driver = {
431862306a36Sopenharmony_ci		.name = "tegra-pmc",
431962306a36Sopenharmony_ci		.suppress_bind_attrs = true,
432062306a36Sopenharmony_ci		.of_match_table = tegra_pmc_match,
432162306a36Sopenharmony_ci#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
432262306a36Sopenharmony_ci		.pm = &tegra_pmc_pm_ops,
432362306a36Sopenharmony_ci#endif
432462306a36Sopenharmony_ci		.sync_state = tegra_pmc_sync_state,
432562306a36Sopenharmony_ci	},
432662306a36Sopenharmony_ci	.probe = tegra_pmc_probe,
432762306a36Sopenharmony_ci};
432862306a36Sopenharmony_cibuiltin_platform_driver(tegra_pmc_driver);
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_cistatic bool __init tegra_pmc_detect_tz_only(struct tegra_pmc *pmc)
433162306a36Sopenharmony_ci{
433262306a36Sopenharmony_ci	u32 value, saved;
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	saved = readl(pmc->base + pmc->soc->regs->scratch0);
433562306a36Sopenharmony_ci	value = saved ^ 0xffffffff;
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_ci	if (value == 0xffffffff)
433862306a36Sopenharmony_ci		value = 0xdeadbeef;
433962306a36Sopenharmony_ci
434062306a36Sopenharmony_ci	/* write pattern and read it back */
434162306a36Sopenharmony_ci	writel(value, pmc->base + pmc->soc->regs->scratch0);
434262306a36Sopenharmony_ci	value = readl(pmc->base + pmc->soc->regs->scratch0);
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_ci	/* if we read all-zeroes, access is restricted to TZ only */
434562306a36Sopenharmony_ci	if (value == 0) {
434662306a36Sopenharmony_ci		pr_info("access to PMC is restricted to TZ\n");
434762306a36Sopenharmony_ci		return true;
434862306a36Sopenharmony_ci	}
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci	/* restore original value */
435162306a36Sopenharmony_ci	writel(saved, pmc->base + pmc->soc->regs->scratch0);
435262306a36Sopenharmony_ci
435362306a36Sopenharmony_ci	return false;
435462306a36Sopenharmony_ci}
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci/*
435762306a36Sopenharmony_ci * Early initialization to allow access to registers in the very early boot
435862306a36Sopenharmony_ci * process.
435962306a36Sopenharmony_ci */
436062306a36Sopenharmony_cistatic int __init tegra_pmc_early_init(void)
436162306a36Sopenharmony_ci{
436262306a36Sopenharmony_ci	const struct of_device_id *match;
436362306a36Sopenharmony_ci	struct device_node *np;
436462306a36Sopenharmony_ci	struct resource regs;
436562306a36Sopenharmony_ci	unsigned int i;
436662306a36Sopenharmony_ci	bool invert;
436762306a36Sopenharmony_ci
436862306a36Sopenharmony_ci	mutex_init(&pmc->powergates_lock);
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_ci	np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
437162306a36Sopenharmony_ci	if (!np) {
437262306a36Sopenharmony_ci		/*
437362306a36Sopenharmony_ci		 * Fall back to legacy initialization for 32-bit ARM only. All
437462306a36Sopenharmony_ci		 * 64-bit ARM device tree files for Tegra are required to have
437562306a36Sopenharmony_ci		 * a PMC node.
437662306a36Sopenharmony_ci		 *
437762306a36Sopenharmony_ci		 * This is for backwards-compatibility with old device trees
437862306a36Sopenharmony_ci		 * that didn't contain a PMC node. Note that in this case the
437962306a36Sopenharmony_ci		 * SoC data can't be matched and therefore powergating is
438062306a36Sopenharmony_ci		 * disabled.
438162306a36Sopenharmony_ci		 */
438262306a36Sopenharmony_ci		if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) {
438362306a36Sopenharmony_ci			pr_warn("DT node not found, powergating disabled\n");
438462306a36Sopenharmony_ci
438562306a36Sopenharmony_ci			regs.start = 0x7000e400;
438662306a36Sopenharmony_ci			regs.end = 0x7000e7ff;
438762306a36Sopenharmony_ci			regs.flags = IORESOURCE_MEM;
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci			pr_warn("Using memory region %pR\n", &regs);
439062306a36Sopenharmony_ci		} else {
439162306a36Sopenharmony_ci			/*
439262306a36Sopenharmony_ci			 * At this point we're not running on Tegra, so play
439362306a36Sopenharmony_ci			 * nice with multi-platform kernels.
439462306a36Sopenharmony_ci			 */
439562306a36Sopenharmony_ci			return 0;
439662306a36Sopenharmony_ci		}
439762306a36Sopenharmony_ci	} else {
439862306a36Sopenharmony_ci		/*
439962306a36Sopenharmony_ci		 * Extract information from the device tree if we've found a
440062306a36Sopenharmony_ci		 * matching node.
440162306a36Sopenharmony_ci		 */
440262306a36Sopenharmony_ci		if (of_address_to_resource(np, 0, &regs) < 0) {
440362306a36Sopenharmony_ci			pr_err("failed to get PMC registers\n");
440462306a36Sopenharmony_ci			of_node_put(np);
440562306a36Sopenharmony_ci			return -ENXIO;
440662306a36Sopenharmony_ci		}
440762306a36Sopenharmony_ci	}
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_ci	pmc->base = ioremap(regs.start, resource_size(&regs));
441062306a36Sopenharmony_ci	if (!pmc->base) {
441162306a36Sopenharmony_ci		pr_err("failed to map PMC registers\n");
441262306a36Sopenharmony_ci		of_node_put(np);
441362306a36Sopenharmony_ci		return -ENXIO;
441462306a36Sopenharmony_ci	}
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci	if (of_device_is_available(np)) {
441762306a36Sopenharmony_ci		pmc->soc = match->data;
441862306a36Sopenharmony_ci
441962306a36Sopenharmony_ci		if (pmc->soc->maybe_tz_only)
442062306a36Sopenharmony_ci			pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
442162306a36Sopenharmony_ci
442262306a36Sopenharmony_ci		/* Create a bitmap of the available and valid partitions */
442362306a36Sopenharmony_ci		for (i = 0; i < pmc->soc->num_powergates; i++)
442462306a36Sopenharmony_ci			if (pmc->soc->powergates[i])
442562306a36Sopenharmony_ci				set_bit(i, pmc->powergates_available);
442662306a36Sopenharmony_ci
442762306a36Sopenharmony_ci		/*
442862306a36Sopenharmony_ci		 * Invert the interrupt polarity if a PMC device tree node
442962306a36Sopenharmony_ci		 * exists and contains the nvidia,invert-interrupt property.
443062306a36Sopenharmony_ci		 */
443162306a36Sopenharmony_ci		invert = of_property_read_bool(np, "nvidia,invert-interrupt");
443262306a36Sopenharmony_ci
443362306a36Sopenharmony_ci		pmc->soc->setup_irq_polarity(pmc, np, invert);
443462306a36Sopenharmony_ci
443562306a36Sopenharmony_ci		of_node_put(np);
443662306a36Sopenharmony_ci	}
443762306a36Sopenharmony_ci
443862306a36Sopenharmony_ci	return 0;
443962306a36Sopenharmony_ci}
444062306a36Sopenharmony_ciearly_initcall(tegra_pmc_early_init);
4441