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", ®_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", ®_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, ®s); 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_ci wake = ioremap(regs.start, resource_size(®s)); 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", ®s); 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, ®s) < 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(®s)); 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