18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * drivers/soc/tegra/pmc.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010 Google, Inc 68c2ecf20Sopenharmony_ci * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: 98c2ecf20Sopenharmony_ci * Colin Cross <ccross@google.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "tegra-pmc: " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/arm-smccc.h> 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 178c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 188c2ecf20Sopenharmony_ci#include <linux/clk/clk-conf.h> 198c2ecf20Sopenharmony_ci#include <linux/clk/tegra.h> 208c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/device.h> 238c2ecf20Sopenharmony_ci#include <linux/err.h> 248c2ecf20Sopenharmony_ci#include <linux/export.h> 258c2ecf20Sopenharmony_ci#include <linux/init.h> 268c2ecf20Sopenharmony_ci#include <linux/io.h> 278c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 288c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 298c2ecf20Sopenharmony_ci#include <linux/irq.h> 308c2ecf20Sopenharmony_ci#include <linux/kernel.h> 318c2ecf20Sopenharmony_ci#include <linux/of_address.h> 328c2ecf20Sopenharmony_ci#include <linux/of_clk.h> 338c2ecf20Sopenharmony_ci#include <linux/of.h> 348c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 358c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 368c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 378c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 388c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 398c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 408c2ecf20Sopenharmony_ci#include <linux/pm_domain.h> 418c2ecf20Sopenharmony_ci#include <linux/reboot.h> 428c2ecf20Sopenharmony_ci#include <linux/reset.h> 438c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 448c2ecf20Sopenharmony_ci#include <linux/slab.h> 458c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include <soc/tegra/common.h> 488c2ecf20Sopenharmony_ci#include <soc/tegra/fuse.h> 498c2ecf20Sopenharmony_ci#include <soc/tegra/pmc.h> 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#include <dt-bindings/interrupt-controller/arm-gic.h> 528c2ecf20Sopenharmony_ci#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h> 538c2ecf20Sopenharmony_ci#include <dt-bindings/gpio/tegra186-gpio.h> 548c2ecf20Sopenharmony_ci#include <dt-bindings/gpio/tegra194-gpio.h> 558c2ecf20Sopenharmony_ci#include <dt-bindings/soc/tegra-pmc.h> 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define PMC_CNTRL 0x0 588c2ecf20Sopenharmony_ci#define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ 598c2ecf20Sopenharmony_ci#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ 608c2ecf20Sopenharmony_ci#define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */ 618c2ecf20Sopenharmony_ci#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */ 628c2ecf20Sopenharmony_ci#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ 638c2ecf20Sopenharmony_ci#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ 648c2ecf20Sopenharmony_ci#define PMC_CNTRL_PWRREQ_POLARITY BIT(8) 658c2ecf20Sopenharmony_ci#define PMC_CNTRL_BLINK_EN 7 668c2ecf20Sopenharmony_ci#define PMC_CNTRL_MAIN_RST BIT(4) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define PMC_WAKE_MASK 0x0c 698c2ecf20Sopenharmony_ci#define PMC_WAKE_LEVEL 0x10 708c2ecf20Sopenharmony_ci#define PMC_WAKE_STATUS 0x14 718c2ecf20Sopenharmony_ci#define PMC_SW_WAKE_STATUS 0x18 728c2ecf20Sopenharmony_ci#define PMC_DPD_PADS_ORIDE 0x1c 738c2ecf20Sopenharmony_ci#define PMC_DPD_PADS_ORIDE_BLINK 20 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define DPD_SAMPLE 0x020 768c2ecf20Sopenharmony_ci#define DPD_SAMPLE_ENABLE BIT(0) 778c2ecf20Sopenharmony_ci#define DPD_SAMPLE_DISABLE (0 << 0) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define PWRGATE_TOGGLE 0x30 808c2ecf20Sopenharmony_ci#define PWRGATE_TOGGLE_START BIT(8) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define REMOVE_CLAMPING 0x34 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define PWRGATE_STATUS 0x38 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define PMC_BLINK_TIMER 0x40 878c2ecf20Sopenharmony_ci#define PMC_IMPL_E_33V_PWR 0x40 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define PMC_PWR_DET 0x48 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define PMC_SCRATCH0_MODE_RECOVERY BIT(31) 928c2ecf20Sopenharmony_ci#define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) 938c2ecf20Sopenharmony_ci#define PMC_SCRATCH0_MODE_RCM BIT(1) 948c2ecf20Sopenharmony_ci#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ 958c2ecf20Sopenharmony_ci PMC_SCRATCH0_MODE_BOOTLOADER | \ 968c2ecf20Sopenharmony_ci PMC_SCRATCH0_MODE_RCM) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define PMC_CPUPWRGOOD_TIMER 0xc8 998c2ecf20Sopenharmony_ci#define PMC_CPUPWROFF_TIMER 0xcc 1008c2ecf20Sopenharmony_ci#define PMC_COREPWRGOOD_TIMER 0x3c 1018c2ecf20Sopenharmony_ci#define PMC_COREPWROFF_TIMER 0xe0 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define PMC_PWR_DET_VALUE 0xe4 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define PMC_SCRATCH41 0x140 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define PMC_WAKE2_MASK 0x160 1088c2ecf20Sopenharmony_ci#define PMC_WAKE2_LEVEL 0x164 1098c2ecf20Sopenharmony_ci#define PMC_WAKE2_STATUS 0x168 1108c2ecf20Sopenharmony_ci#define PMC_SW_WAKE2_STATUS 0x16c 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define PMC_CLK_OUT_CNTRL 0x1a8 1138c2ecf20Sopenharmony_ci#define PMC_CLK_OUT_MUX_MASK GENMASK(1, 0) 1148c2ecf20Sopenharmony_ci#define PMC_SENSOR_CTRL 0x1b0 1158c2ecf20Sopenharmony_ci#define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) 1168c2ecf20Sopenharmony_ci#define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define PMC_RST_STATUS_POR 0 1198c2ecf20Sopenharmony_ci#define PMC_RST_STATUS_WATCHDOG 1 1208c2ecf20Sopenharmony_ci#define PMC_RST_STATUS_SENSOR 2 1218c2ecf20Sopenharmony_ci#define PMC_RST_STATUS_SW_MAIN 3 1228c2ecf20Sopenharmony_ci#define PMC_RST_STATUS_LP0 4 1238c2ecf20Sopenharmony_ci#define PMC_RST_STATUS_AOTAG 5 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define IO_DPD_REQ 0x1b8 1268c2ecf20Sopenharmony_ci#define IO_DPD_REQ_CODE_IDLE (0U << 30) 1278c2ecf20Sopenharmony_ci#define IO_DPD_REQ_CODE_OFF (1U << 30) 1288c2ecf20Sopenharmony_ci#define IO_DPD_REQ_CODE_ON (2U << 30) 1298c2ecf20Sopenharmony_ci#define IO_DPD_REQ_CODE_MASK (3U << 30) 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define IO_DPD_STATUS 0x1bc 1328c2ecf20Sopenharmony_ci#define IO_DPD2_REQ 0x1c0 1338c2ecf20Sopenharmony_ci#define IO_DPD2_STATUS 0x1c4 1348c2ecf20Sopenharmony_ci#define SEL_DPD_TIM 0x1c8 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define PMC_SCRATCH54 0x258 1378c2ecf20Sopenharmony_ci#define PMC_SCRATCH54_DATA_SHIFT 8 1388c2ecf20Sopenharmony_ci#define PMC_SCRATCH54_ADDR_SHIFT 0 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#define PMC_SCRATCH55 0x25c 1418c2ecf20Sopenharmony_ci#define PMC_SCRATCH55_RESET_TEGRA BIT(31) 1428c2ecf20Sopenharmony_ci#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 1438c2ecf20Sopenharmony_ci#define PMC_SCRATCH55_PINMUX_SHIFT 24 1448c2ecf20Sopenharmony_ci#define PMC_SCRATCH55_16BITOP BIT(15) 1458c2ecf20Sopenharmony_ci#define PMC_SCRATCH55_CHECKSUM_SHIFT 16 1468c2ecf20Sopenharmony_ci#define PMC_SCRATCH55_I2CSLV1_SHIFT 0 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define GPU_RG_CNTRL 0x2d4 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* Tegra186 and later */ 1518c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) 1528c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) 1538c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2)) 1548c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2)) 1558c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2)) 1568c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2)) 1578c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2)) 1588c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2)) 1598c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2)) 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_CTRL 0x4f4 1628c2ecf20Sopenharmony_ci#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* for secure PMC */ 1658c2ecf20Sopenharmony_ci#define TEGRA_SMC_PMC 0xc2fffe00 1668c2ecf20Sopenharmony_ci#define TEGRA_SMC_PMC_READ 0xaa 1678c2ecf20Sopenharmony_ci#define TEGRA_SMC_PMC_WRITE 0xbb 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistruct pmc_clk { 1708c2ecf20Sopenharmony_ci struct clk_hw hw; 1718c2ecf20Sopenharmony_ci unsigned long offs; 1728c2ecf20Sopenharmony_ci u32 mux_shift; 1738c2ecf20Sopenharmony_ci u32 force_en_shift; 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define to_pmc_clk(_hw) container_of(_hw, struct pmc_clk, hw) 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistruct pmc_clk_gate { 1798c2ecf20Sopenharmony_ci struct clk_hw hw; 1808c2ecf20Sopenharmony_ci unsigned long offs; 1818c2ecf20Sopenharmony_ci u32 shift; 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw) 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistruct pmc_clk_init_data { 1878c2ecf20Sopenharmony_ci char *name; 1888c2ecf20Sopenharmony_ci const char *const *parents; 1898c2ecf20Sopenharmony_ci int num_parents; 1908c2ecf20Sopenharmony_ci int clk_id; 1918c2ecf20Sopenharmony_ci u8 mux_shift; 1928c2ecf20Sopenharmony_ci u8 force_en_shift; 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic const char * const clk_out1_parents[] = { "osc", "osc_div2", 1968c2ecf20Sopenharmony_ci "osc_div4", "extern1", 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic const char * const clk_out2_parents[] = { "osc", "osc_div2", 2008c2ecf20Sopenharmony_ci "osc_div4", "extern2", 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic const char * const clk_out3_parents[] = { "osc", "osc_div2", 2048c2ecf20Sopenharmony_ci "osc_div4", "extern3", 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic const struct pmc_clk_init_data tegra_pmc_clks_data[] = { 2088c2ecf20Sopenharmony_ci { 2098c2ecf20Sopenharmony_ci .name = "pmc_clk_out_1", 2108c2ecf20Sopenharmony_ci .parents = clk_out1_parents, 2118c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(clk_out1_parents), 2128c2ecf20Sopenharmony_ci .clk_id = TEGRA_PMC_CLK_OUT_1, 2138c2ecf20Sopenharmony_ci .mux_shift = 6, 2148c2ecf20Sopenharmony_ci .force_en_shift = 2, 2158c2ecf20Sopenharmony_ci }, 2168c2ecf20Sopenharmony_ci { 2178c2ecf20Sopenharmony_ci .name = "pmc_clk_out_2", 2188c2ecf20Sopenharmony_ci .parents = clk_out2_parents, 2198c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(clk_out2_parents), 2208c2ecf20Sopenharmony_ci .clk_id = TEGRA_PMC_CLK_OUT_2, 2218c2ecf20Sopenharmony_ci .mux_shift = 14, 2228c2ecf20Sopenharmony_ci .force_en_shift = 10, 2238c2ecf20Sopenharmony_ci }, 2248c2ecf20Sopenharmony_ci { 2258c2ecf20Sopenharmony_ci .name = "pmc_clk_out_3", 2268c2ecf20Sopenharmony_ci .parents = clk_out3_parents, 2278c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(clk_out3_parents), 2288c2ecf20Sopenharmony_ci .clk_id = TEGRA_PMC_CLK_OUT_3, 2298c2ecf20Sopenharmony_ci .mux_shift = 22, 2308c2ecf20Sopenharmony_ci .force_en_shift = 18, 2318c2ecf20Sopenharmony_ci }, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistruct tegra_powergate { 2358c2ecf20Sopenharmony_ci struct generic_pm_domain genpd; 2368c2ecf20Sopenharmony_ci struct tegra_pmc *pmc; 2378c2ecf20Sopenharmony_ci unsigned int id; 2388c2ecf20Sopenharmony_ci struct clk **clks; 2398c2ecf20Sopenharmony_ci unsigned int num_clks; 2408c2ecf20Sopenharmony_ci struct reset_control *reset; 2418c2ecf20Sopenharmony_ci}; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistruct tegra_io_pad_soc { 2448c2ecf20Sopenharmony_ci enum tegra_io_pad id; 2458c2ecf20Sopenharmony_ci unsigned int dpd; 2468c2ecf20Sopenharmony_ci unsigned int voltage; 2478c2ecf20Sopenharmony_ci const char *name; 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistruct tegra_pmc_regs { 2518c2ecf20Sopenharmony_ci unsigned int scratch0; 2528c2ecf20Sopenharmony_ci unsigned int dpd_req; 2538c2ecf20Sopenharmony_ci unsigned int dpd_status; 2548c2ecf20Sopenharmony_ci unsigned int dpd2_req; 2558c2ecf20Sopenharmony_ci unsigned int dpd2_status; 2568c2ecf20Sopenharmony_ci unsigned int rst_status; 2578c2ecf20Sopenharmony_ci unsigned int rst_source_shift; 2588c2ecf20Sopenharmony_ci unsigned int rst_source_mask; 2598c2ecf20Sopenharmony_ci unsigned int rst_level_shift; 2608c2ecf20Sopenharmony_ci unsigned int rst_level_mask; 2618c2ecf20Sopenharmony_ci}; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistruct tegra_wake_event { 2648c2ecf20Sopenharmony_ci const char *name; 2658c2ecf20Sopenharmony_ci unsigned int id; 2668c2ecf20Sopenharmony_ci unsigned int irq; 2678c2ecf20Sopenharmony_ci struct { 2688c2ecf20Sopenharmony_ci unsigned int instance; 2698c2ecf20Sopenharmony_ci unsigned int pin; 2708c2ecf20Sopenharmony_ci } gpio; 2718c2ecf20Sopenharmony_ci}; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci#define TEGRA_WAKE_IRQ(_name, _id, _irq) \ 2748c2ecf20Sopenharmony_ci { \ 2758c2ecf20Sopenharmony_ci .name = _name, \ 2768c2ecf20Sopenharmony_ci .id = _id, \ 2778c2ecf20Sopenharmony_ci .irq = _irq, \ 2788c2ecf20Sopenharmony_ci .gpio = { \ 2798c2ecf20Sopenharmony_ci .instance = UINT_MAX, \ 2808c2ecf20Sopenharmony_ci .pin = UINT_MAX, \ 2818c2ecf20Sopenharmony_ci }, \ 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci#define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin) \ 2858c2ecf20Sopenharmony_ci { \ 2868c2ecf20Sopenharmony_ci .name = _name, \ 2878c2ecf20Sopenharmony_ci .id = _id, \ 2888c2ecf20Sopenharmony_ci .irq = 0, \ 2898c2ecf20Sopenharmony_ci .gpio = { \ 2908c2ecf20Sopenharmony_ci .instance = _instance, \ 2918c2ecf20Sopenharmony_ci .pin = _pin, \ 2928c2ecf20Sopenharmony_ci }, \ 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistruct tegra_pmc_soc { 2968c2ecf20Sopenharmony_ci unsigned int num_powergates; 2978c2ecf20Sopenharmony_ci const char *const *powergates; 2988c2ecf20Sopenharmony_ci unsigned int num_cpu_powergates; 2998c2ecf20Sopenharmony_ci const u8 *cpu_powergates; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci bool has_tsense_reset; 3028c2ecf20Sopenharmony_ci bool has_gpu_clamps; 3038c2ecf20Sopenharmony_ci bool needs_mbist_war; 3048c2ecf20Sopenharmony_ci bool has_impl_33v_pwr; 3058c2ecf20Sopenharmony_ci bool maybe_tz_only; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci const struct tegra_io_pad_soc *io_pads; 3088c2ecf20Sopenharmony_ci unsigned int num_io_pads; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci const struct pinctrl_pin_desc *pin_descs; 3118c2ecf20Sopenharmony_ci unsigned int num_pin_descs; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci const struct tegra_pmc_regs *regs; 3148c2ecf20Sopenharmony_ci void (*init)(struct tegra_pmc *pmc); 3158c2ecf20Sopenharmony_ci void (*setup_irq_polarity)(struct tegra_pmc *pmc, 3168c2ecf20Sopenharmony_ci struct device_node *np, 3178c2ecf20Sopenharmony_ci bool invert); 3188c2ecf20Sopenharmony_ci int (*irq_set_wake)(struct irq_data *data, unsigned int on); 3198c2ecf20Sopenharmony_ci int (*irq_set_type)(struct irq_data *data, unsigned int type); 3208c2ecf20Sopenharmony_ci int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id, 3218c2ecf20Sopenharmony_ci bool new_state); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci const char * const *reset_sources; 3248c2ecf20Sopenharmony_ci unsigned int num_reset_sources; 3258c2ecf20Sopenharmony_ci const char * const *reset_levels; 3268c2ecf20Sopenharmony_ci unsigned int num_reset_levels; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * These describe events that can wake the system from sleep (i.e. 3308c2ecf20Sopenharmony_ci * LP0 or SC7). Wakeup from other sleep states (such as LP1 or LP2) 3318c2ecf20Sopenharmony_ci * are dealt with in the LIC. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci const struct tegra_wake_event *wake_events; 3348c2ecf20Sopenharmony_ci unsigned int num_wake_events; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci const struct pmc_clk_init_data *pmc_clks_data; 3378c2ecf20Sopenharmony_ci unsigned int num_pmc_clks; 3388c2ecf20Sopenharmony_ci bool has_blink_output; 3398c2ecf20Sopenharmony_ci}; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/** 3428c2ecf20Sopenharmony_ci * struct tegra_pmc - NVIDIA Tegra PMC 3438c2ecf20Sopenharmony_ci * @dev: pointer to PMC device structure 3448c2ecf20Sopenharmony_ci * @base: pointer to I/O remapped register region 3458c2ecf20Sopenharmony_ci * @wake: pointer to I/O remapped region for WAKE registers 3468c2ecf20Sopenharmony_ci * @aotag: pointer to I/O remapped region for AOTAG registers 3478c2ecf20Sopenharmony_ci * @scratch: pointer to I/O remapped region for scratch registers 3488c2ecf20Sopenharmony_ci * @clk: pointer to pclk clock 3498c2ecf20Sopenharmony_ci * @soc: pointer to SoC data structure 3508c2ecf20Sopenharmony_ci * @tz_only: flag specifying if the PMC can only be accessed via TrustZone 3518c2ecf20Sopenharmony_ci * @debugfs: pointer to debugfs entry 3528c2ecf20Sopenharmony_ci * @rate: currently configured rate of pclk 3538c2ecf20Sopenharmony_ci * @suspend_mode: lowest suspend mode available 3548c2ecf20Sopenharmony_ci * @cpu_good_time: CPU power good time (in microseconds) 3558c2ecf20Sopenharmony_ci * @cpu_off_time: CPU power off time (in microsecends) 3568c2ecf20Sopenharmony_ci * @core_osc_time: core power good OSC time (in microseconds) 3578c2ecf20Sopenharmony_ci * @core_pmu_time: core power good PMU time (in microseconds) 3588c2ecf20Sopenharmony_ci * @core_off_time: core power off time (in microseconds) 3598c2ecf20Sopenharmony_ci * @corereq_high: core power request is active-high 3608c2ecf20Sopenharmony_ci * @sysclkreq_high: system clock request is active-high 3618c2ecf20Sopenharmony_ci * @combined_req: combined power request for CPU & core 3628c2ecf20Sopenharmony_ci * @cpu_pwr_good_en: CPU power good signal is enabled 3638c2ecf20Sopenharmony_ci * @lp0_vec_phys: physical base address of the LP0 warm boot code 3648c2ecf20Sopenharmony_ci * @lp0_vec_size: size of the LP0 warm boot code 3658c2ecf20Sopenharmony_ci * @powergates_available: Bitmap of available power gates 3668c2ecf20Sopenharmony_ci * @powergates_lock: mutex for power gate register access 3678c2ecf20Sopenharmony_ci * @pctl_dev: pin controller exposed by the PMC 3688c2ecf20Sopenharmony_ci * @domain: IRQ domain provided by the PMC 3698c2ecf20Sopenharmony_ci * @irq: chip implementation for the IRQ domain 3708c2ecf20Sopenharmony_ci * @clk_nb: pclk clock changes handler 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_cistruct tegra_pmc { 3738c2ecf20Sopenharmony_ci struct device *dev; 3748c2ecf20Sopenharmony_ci void __iomem *base; 3758c2ecf20Sopenharmony_ci void __iomem *wake; 3768c2ecf20Sopenharmony_ci void __iomem *aotag; 3778c2ecf20Sopenharmony_ci void __iomem *scratch; 3788c2ecf20Sopenharmony_ci struct clk *clk; 3798c2ecf20Sopenharmony_ci struct dentry *debugfs; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci const struct tegra_pmc_soc *soc; 3828c2ecf20Sopenharmony_ci bool tz_only; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci unsigned long rate; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci enum tegra_suspend_mode suspend_mode; 3878c2ecf20Sopenharmony_ci u32 cpu_good_time; 3888c2ecf20Sopenharmony_ci u32 cpu_off_time; 3898c2ecf20Sopenharmony_ci u32 core_osc_time; 3908c2ecf20Sopenharmony_ci u32 core_pmu_time; 3918c2ecf20Sopenharmony_ci u32 core_off_time; 3928c2ecf20Sopenharmony_ci bool corereq_high; 3938c2ecf20Sopenharmony_ci bool sysclkreq_high; 3948c2ecf20Sopenharmony_ci bool combined_req; 3958c2ecf20Sopenharmony_ci bool cpu_pwr_good_en; 3968c2ecf20Sopenharmony_ci u32 lp0_vec_phys; 3978c2ecf20Sopenharmony_ci u32 lp0_vec_size; 3988c2ecf20Sopenharmony_ci DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci struct mutex powergates_lock; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl_dev; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci struct irq_domain *domain; 4058c2ecf20Sopenharmony_ci struct irq_chip irq; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci struct notifier_block clk_nb; 4088c2ecf20Sopenharmony_ci}; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic struct tegra_pmc *pmc = &(struct tegra_pmc) { 4118c2ecf20Sopenharmony_ci .base = NULL, 4128c2ecf20Sopenharmony_ci .suspend_mode = TEGRA_SUSPEND_NONE, 4138c2ecf20Sopenharmony_ci}; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic inline struct tegra_powergate * 4168c2ecf20Sopenharmony_cito_powergate(struct generic_pm_domain *domain) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci return container_of(domain, struct tegra_powergate, genpd); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic u32 tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct arm_smccc_res res; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (pmc->tz_only) { 4268c2ecf20Sopenharmony_ci arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_READ, offset, 0, 0, 4278c2ecf20Sopenharmony_ci 0, 0, 0, &res); 4288c2ecf20Sopenharmony_ci if (res.a0) { 4298c2ecf20Sopenharmony_ci if (pmc->dev) 4308c2ecf20Sopenharmony_ci dev_warn(pmc->dev, "%s(): SMC failed: %lu\n", 4318c2ecf20Sopenharmony_ci __func__, res.a0); 4328c2ecf20Sopenharmony_ci else 4338c2ecf20Sopenharmony_ci pr_warn("%s(): SMC failed: %lu\n", __func__, 4348c2ecf20Sopenharmony_ci res.a0); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return res.a1; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return readl(pmc->base + offset); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void tegra_pmc_writel(struct tegra_pmc *pmc, u32 value, 4448c2ecf20Sopenharmony_ci unsigned long offset) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct arm_smccc_res res; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (pmc->tz_only) { 4498c2ecf20Sopenharmony_ci arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_WRITE, offset, 4508c2ecf20Sopenharmony_ci value, 0, 0, 0, 0, &res); 4518c2ecf20Sopenharmony_ci if (res.a0) { 4528c2ecf20Sopenharmony_ci if (pmc->dev) 4538c2ecf20Sopenharmony_ci dev_warn(pmc->dev, "%s(): SMC failed: %lu\n", 4548c2ecf20Sopenharmony_ci __func__, res.a0); 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci pr_warn("%s(): SMC failed: %lu\n", __func__, 4578c2ecf20Sopenharmony_ci res.a0); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci } else { 4608c2ecf20Sopenharmony_ci writel(value, pmc->base + offset); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic u32 tegra_pmc_scratch_readl(struct tegra_pmc *pmc, unsigned long offset) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci if (pmc->tz_only) 4678c2ecf20Sopenharmony_ci return tegra_pmc_readl(pmc, offset); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return readl(pmc->scratch + offset); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void tegra_pmc_scratch_writel(struct tegra_pmc *pmc, u32 value, 4738c2ecf20Sopenharmony_ci unsigned long offset) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci if (pmc->tz_only) 4768c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, offset); 4778c2ecf20Sopenharmony_ci else 4788c2ecf20Sopenharmony_ci writel(value, pmc->scratch + offset); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/* 4828c2ecf20Sopenharmony_ci * TODO Figure out a way to call this with the struct tegra_pmc * passed in. 4838c2ecf20Sopenharmony_ci * This currently doesn't work because readx_poll_timeout() can only operate 4848c2ecf20Sopenharmony_ci * on functions that take a single argument. 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_cistatic inline bool tegra_powergate_state(int id) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) 4898c2ecf20Sopenharmony_ci return (tegra_pmc_readl(pmc, GPU_RG_CNTRL) & 0x1) == 0; 4908c2ecf20Sopenharmony_ci else 4918c2ecf20Sopenharmony_ci return (tegra_pmc_readl(pmc, PWRGATE_STATUS) & BIT(id)) != 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic inline bool tegra_powergate_is_valid(struct tegra_pmc *pmc, int id) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci return (pmc->soc && pmc->soc->powergates[id]); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic inline bool tegra_powergate_is_available(struct tegra_pmc *pmc, int id) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci return test_bit(id, pmc->powergates_available); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci unsigned int i; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (!pmc || !pmc->soc || !name) 5098c2ecf20Sopenharmony_ci return -EINVAL; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci for (i = 0; i < pmc->soc->num_powergates; i++) { 5128c2ecf20Sopenharmony_ci if (!tegra_powergate_is_valid(pmc, i)) 5138c2ecf20Sopenharmony_ci continue; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (!strcmp(name, pmc->soc->powergates[i])) 5168c2ecf20Sopenharmony_ci return i; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return -ENODEV; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic int tegra20_powergate_set(struct tegra_pmc *pmc, unsigned int id, 5238c2ecf20Sopenharmony_ci bool new_state) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci unsigned int retries = 100; 5268c2ecf20Sopenharmony_ci bool status; 5278c2ecf20Sopenharmony_ci int ret; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* 5308c2ecf20Sopenharmony_ci * As per TRM documentation, the toggle command will be dropped by PMC 5318c2ecf20Sopenharmony_ci * if there is contention with a HW-initiated toggling (i.e. CPU core 5328c2ecf20Sopenharmony_ci * power-gated), the command should be retried in that case. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci do { 5358c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* wait for PMC to execute the command */ 5388c2ecf20Sopenharmony_ci ret = readx_poll_timeout(tegra_powergate_state, id, status, 5398c2ecf20Sopenharmony_ci status == new_state, 1, 10); 5408c2ecf20Sopenharmony_ci } while (ret == -ETIMEDOUT && retries--); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return ret; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic inline bool tegra_powergate_toggle_ready(struct tegra_pmc *pmc) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci return !(tegra_pmc_readl(pmc, PWRGATE_TOGGLE) & PWRGATE_TOGGLE_START); 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic int tegra114_powergate_set(struct tegra_pmc *pmc, unsigned int id, 5518c2ecf20Sopenharmony_ci bool new_state) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci bool status; 5548c2ecf20Sopenharmony_ci int err; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* wait while PMC power gating is contended */ 5578c2ecf20Sopenharmony_ci err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status, 5588c2ecf20Sopenharmony_ci status == true, 1, 100); 5598c2ecf20Sopenharmony_ci if (err) 5608c2ecf20Sopenharmony_ci return err; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* wait for PMC to accept the command */ 5658c2ecf20Sopenharmony_ci err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status, 5668c2ecf20Sopenharmony_ci status == true, 1, 100); 5678c2ecf20Sopenharmony_ci if (err) 5688c2ecf20Sopenharmony_ci return err; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* wait for PMC to execute the command */ 5718c2ecf20Sopenharmony_ci err = readx_poll_timeout(tegra_powergate_state, id, status, 5728c2ecf20Sopenharmony_ci status == new_state, 10, 100000); 5738c2ecf20Sopenharmony_ci if (err) 5748c2ecf20Sopenharmony_ci return err; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci return 0; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci/** 5808c2ecf20Sopenharmony_ci * tegra_powergate_set() - set the state of a partition 5818c2ecf20Sopenharmony_ci * @pmc: power management controller 5828c2ecf20Sopenharmony_ci * @id: partition ID 5838c2ecf20Sopenharmony_ci * @new_state: new state of the partition 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_cistatic int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id, 5868c2ecf20Sopenharmony_ci bool new_state) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci int err; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) 5918c2ecf20Sopenharmony_ci return -EINVAL; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci mutex_lock(&pmc->powergates_lock); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (tegra_powergate_state(id) == new_state) { 5968c2ecf20Sopenharmony_ci mutex_unlock(&pmc->powergates_lock); 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci err = pmc->soc->powergate_set(pmc, id, new_state); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci mutex_unlock(&pmc->powergates_lock); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return err; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int __tegra_powergate_remove_clamping(struct tegra_pmc *pmc, 6088c2ecf20Sopenharmony_ci unsigned int id) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci u32 mask; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci mutex_lock(&pmc->powergates_lock); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * On Tegra124 and later, the clamps for the GPU are controlled by a 6168c2ecf20Sopenharmony_ci * separate register (with different semantics). 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci if (id == TEGRA_POWERGATE_3D) { 6198c2ecf20Sopenharmony_ci if (pmc->soc->has_gpu_clamps) { 6208c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, 0, GPU_RG_CNTRL); 6218c2ecf20Sopenharmony_ci goto out; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* 6268c2ecf20Sopenharmony_ci * Tegra 2 has a bug where PCIE and VDE clamping masks are 6278c2ecf20Sopenharmony_ci * swapped relatively to the partition ids 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci if (id == TEGRA_POWERGATE_VDEC) 6308c2ecf20Sopenharmony_ci mask = (1 << TEGRA_POWERGATE_PCIE); 6318c2ecf20Sopenharmony_ci else if (id == TEGRA_POWERGATE_PCIE) 6328c2ecf20Sopenharmony_ci mask = (1 << TEGRA_POWERGATE_VDEC); 6338c2ecf20Sopenharmony_ci else 6348c2ecf20Sopenharmony_ci mask = (1 << id); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, mask, REMOVE_CLAMPING); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ciout: 6398c2ecf20Sopenharmony_ci mutex_unlock(&pmc->powergates_lock); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic void tegra_powergate_disable_clocks(struct tegra_powergate *pg) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci unsigned int i; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci for (i = 0; i < pg->num_clks; i++) 6498c2ecf20Sopenharmony_ci clk_disable_unprepare(pg->clks[i]); 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic int tegra_powergate_enable_clocks(struct tegra_powergate *pg) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci unsigned int i; 6558c2ecf20Sopenharmony_ci int err; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci for (i = 0; i < pg->num_clks; i++) { 6588c2ecf20Sopenharmony_ci err = clk_prepare_enable(pg->clks[i]); 6598c2ecf20Sopenharmony_ci if (err) 6608c2ecf20Sopenharmony_ci goto out; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci return 0; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ciout: 6668c2ecf20Sopenharmony_ci while (i--) 6678c2ecf20Sopenharmony_ci clk_disable_unprepare(pg->clks[i]); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return err; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ciint __weak tegra210_clk_handle_mbist_war(unsigned int id) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci return 0; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int tegra_powergate_power_up(struct tegra_powergate *pg, 6788c2ecf20Sopenharmony_ci bool disable_clocks) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci int err; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci err = reset_control_assert(pg->reset); 6838c2ecf20Sopenharmony_ci if (err) 6848c2ecf20Sopenharmony_ci return err; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci usleep_range(10, 20); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci err = tegra_powergate_set(pg->pmc, pg->id, true); 6898c2ecf20Sopenharmony_ci if (err < 0) 6908c2ecf20Sopenharmony_ci return err; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci usleep_range(10, 20); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci err = tegra_powergate_enable_clocks(pg); 6958c2ecf20Sopenharmony_ci if (err) 6968c2ecf20Sopenharmony_ci goto powergate_off; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci usleep_range(10, 20); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci err = __tegra_powergate_remove_clamping(pg->pmc, pg->id); 7018c2ecf20Sopenharmony_ci if (err) 7028c2ecf20Sopenharmony_ci goto disable_clks; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci usleep_range(10, 20); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci err = reset_control_deassert(pg->reset); 7078c2ecf20Sopenharmony_ci if (err) 7088c2ecf20Sopenharmony_ci goto disable_clks; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci usleep_range(10, 20); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (pg->pmc->soc->needs_mbist_war) 7138c2ecf20Sopenharmony_ci err = tegra210_clk_handle_mbist_war(pg->id); 7148c2ecf20Sopenharmony_ci if (err) 7158c2ecf20Sopenharmony_ci goto disable_clks; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (disable_clocks) 7188c2ecf20Sopenharmony_ci tegra_powergate_disable_clocks(pg); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cidisable_clks: 7238c2ecf20Sopenharmony_ci tegra_powergate_disable_clocks(pg); 7248c2ecf20Sopenharmony_ci usleep_range(10, 20); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cipowergate_off: 7278c2ecf20Sopenharmony_ci tegra_powergate_set(pg->pmc, pg->id, false); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return err; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic int tegra_powergate_power_down(struct tegra_powergate *pg) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci int err; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci err = tegra_powergate_enable_clocks(pg); 7378c2ecf20Sopenharmony_ci if (err) 7388c2ecf20Sopenharmony_ci return err; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci usleep_range(10, 20); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci err = reset_control_assert(pg->reset); 7438c2ecf20Sopenharmony_ci if (err) 7448c2ecf20Sopenharmony_ci goto disable_clks; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci usleep_range(10, 20); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci tegra_powergate_disable_clocks(pg); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci usleep_range(10, 20); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci err = tegra_powergate_set(pg->pmc, pg->id, false); 7538c2ecf20Sopenharmony_ci if (err) 7548c2ecf20Sopenharmony_ci goto assert_resets; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ciassert_resets: 7598c2ecf20Sopenharmony_ci tegra_powergate_enable_clocks(pg); 7608c2ecf20Sopenharmony_ci usleep_range(10, 20); 7618c2ecf20Sopenharmony_ci reset_control_deassert(pg->reset); 7628c2ecf20Sopenharmony_ci usleep_range(10, 20); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cidisable_clks: 7658c2ecf20Sopenharmony_ci tegra_powergate_disable_clocks(pg); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci return err; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic int tegra_genpd_power_on(struct generic_pm_domain *domain) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct tegra_powergate *pg = to_powergate(domain); 7738c2ecf20Sopenharmony_ci struct device *dev = pg->pmc->dev; 7748c2ecf20Sopenharmony_ci int err; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci err = tegra_powergate_power_up(pg, true); 7778c2ecf20Sopenharmony_ci if (err) { 7788c2ecf20Sopenharmony_ci dev_err(dev, "failed to turn on PM domain %s: %d\n", 7798c2ecf20Sopenharmony_ci pg->genpd.name, err); 7808c2ecf20Sopenharmony_ci goto out; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci reset_control_release(pg->reset); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ciout: 7868c2ecf20Sopenharmony_ci return err; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int tegra_genpd_power_off(struct generic_pm_domain *domain) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct tegra_powergate *pg = to_powergate(domain); 7928c2ecf20Sopenharmony_ci struct device *dev = pg->pmc->dev; 7938c2ecf20Sopenharmony_ci int err; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci err = reset_control_acquire(pg->reset); 7968c2ecf20Sopenharmony_ci if (err < 0) { 7978c2ecf20Sopenharmony_ci pr_err("failed to acquire resets: %d\n", err); 7988c2ecf20Sopenharmony_ci return err; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci err = tegra_powergate_power_down(pg); 8028c2ecf20Sopenharmony_ci if (err) { 8038c2ecf20Sopenharmony_ci dev_err(dev, "failed to turn off PM domain %s: %d\n", 8048c2ecf20Sopenharmony_ci pg->genpd.name, err); 8058c2ecf20Sopenharmony_ci reset_control_release(pg->reset); 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci return err; 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci/** 8128c2ecf20Sopenharmony_ci * tegra_powergate_power_on() - power on partition 8138c2ecf20Sopenharmony_ci * @id: partition ID 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_ciint tegra_powergate_power_on(unsigned int id) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci if (!tegra_powergate_is_available(pmc, id)) 8188c2ecf20Sopenharmony_ci return -EINVAL; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return tegra_powergate_set(pmc, id, true); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tegra_powergate_power_on); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci/** 8258c2ecf20Sopenharmony_ci * tegra_powergate_power_off() - power off partition 8268c2ecf20Sopenharmony_ci * @id: partition ID 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ciint tegra_powergate_power_off(unsigned int id) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci if (!tegra_powergate_is_available(pmc, id)) 8318c2ecf20Sopenharmony_ci return -EINVAL; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return tegra_powergate_set(pmc, id, false); 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tegra_powergate_power_off); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci/** 8388c2ecf20Sopenharmony_ci * tegra_powergate_is_powered() - check if partition is powered 8398c2ecf20Sopenharmony_ci * @pmc: power management controller 8408c2ecf20Sopenharmony_ci * @id: partition ID 8418c2ecf20Sopenharmony_ci */ 8428c2ecf20Sopenharmony_cistatic int tegra_powergate_is_powered(struct tegra_pmc *pmc, unsigned int id) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci if (!tegra_powergate_is_valid(pmc, id)) 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci return tegra_powergate_state(id); 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci/** 8518c2ecf20Sopenharmony_ci * tegra_powergate_remove_clamping() - remove power clamps for partition 8528c2ecf20Sopenharmony_ci * @id: partition ID 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_ciint tegra_powergate_remove_clamping(unsigned int id) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci if (!tegra_powergate_is_available(pmc, id)) 8578c2ecf20Sopenharmony_ci return -EINVAL; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci return __tegra_powergate_remove_clamping(pmc, id); 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tegra_powergate_remove_clamping); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci/** 8648c2ecf20Sopenharmony_ci * tegra_powergate_sequence_power_up() - power up partition 8658c2ecf20Sopenharmony_ci * @id: partition ID 8668c2ecf20Sopenharmony_ci * @clk: clock for partition 8678c2ecf20Sopenharmony_ci * @rst: reset for partition 8688c2ecf20Sopenharmony_ci * 8698c2ecf20Sopenharmony_ci * Must be called with clk disabled, and returns with clk enabled. 8708c2ecf20Sopenharmony_ci */ 8718c2ecf20Sopenharmony_ciint tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, 8728c2ecf20Sopenharmony_ci struct reset_control *rst) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci struct tegra_powergate *pg; 8758c2ecf20Sopenharmony_ci int err; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (!tegra_powergate_is_available(pmc, id)) 8788c2ecf20Sopenharmony_ci return -EINVAL; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci pg = kzalloc(sizeof(*pg), GFP_KERNEL); 8818c2ecf20Sopenharmony_ci if (!pg) 8828c2ecf20Sopenharmony_ci return -ENOMEM; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci pg->id = id; 8858c2ecf20Sopenharmony_ci pg->clks = &clk; 8868c2ecf20Sopenharmony_ci pg->num_clks = 1; 8878c2ecf20Sopenharmony_ci pg->reset = rst; 8888c2ecf20Sopenharmony_ci pg->pmc = pmc; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci err = tegra_powergate_power_up(pg, false); 8918c2ecf20Sopenharmony_ci if (err) 8928c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to turn on partition %d: %d\n", id, 8938c2ecf20Sopenharmony_ci err); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci kfree(pg); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return err; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tegra_powergate_sequence_power_up); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci/** 9028c2ecf20Sopenharmony_ci * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID 9038c2ecf20Sopenharmony_ci * @pmc: power management controller 9048c2ecf20Sopenharmony_ci * @cpuid: CPU partition ID 9058c2ecf20Sopenharmony_ci * 9068c2ecf20Sopenharmony_ci * Returns the partition ID corresponding to the CPU partition ID or a 9078c2ecf20Sopenharmony_ci * negative error code on failure. 9088c2ecf20Sopenharmony_ci */ 9098c2ecf20Sopenharmony_cistatic int tegra_get_cpu_powergate_id(struct tegra_pmc *pmc, 9108c2ecf20Sopenharmony_ci unsigned int cpuid) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates) 9138c2ecf20Sopenharmony_ci return pmc->soc->cpu_powergates[cpuid]; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return -EINVAL; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci/** 9198c2ecf20Sopenharmony_ci * tegra_pmc_cpu_is_powered() - check if CPU partition is powered 9208c2ecf20Sopenharmony_ci * @cpuid: CPU partition ID 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_cibool tegra_pmc_cpu_is_powered(unsigned int cpuid) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci int id; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci id = tegra_get_cpu_powergate_id(pmc, cpuid); 9278c2ecf20Sopenharmony_ci if (id < 0) 9288c2ecf20Sopenharmony_ci return false; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci return tegra_powergate_is_powered(pmc, id); 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci/** 9348c2ecf20Sopenharmony_ci * tegra_pmc_cpu_power_on() - power on CPU partition 9358c2ecf20Sopenharmony_ci * @cpuid: CPU partition ID 9368c2ecf20Sopenharmony_ci */ 9378c2ecf20Sopenharmony_ciint tegra_pmc_cpu_power_on(unsigned int cpuid) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci int id; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci id = tegra_get_cpu_powergate_id(pmc, cpuid); 9428c2ecf20Sopenharmony_ci if (id < 0) 9438c2ecf20Sopenharmony_ci return id; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci return tegra_powergate_set(pmc, id, true); 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci/** 9498c2ecf20Sopenharmony_ci * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition 9508c2ecf20Sopenharmony_ci * @cpuid: CPU partition ID 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_ciint tegra_pmc_cpu_remove_clamping(unsigned int cpuid) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci int id; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci id = tegra_get_cpu_powergate_id(pmc, cpuid); 9578c2ecf20Sopenharmony_ci if (id < 0) 9588c2ecf20Sopenharmony_ci return id; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci return tegra_powergate_remove_clamping(id); 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic int tegra_pmc_restart_notify(struct notifier_block *this, 9648c2ecf20Sopenharmony_ci unsigned long action, void *data) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci const char *cmd = data; 9678c2ecf20Sopenharmony_ci u32 value; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci value = tegra_pmc_scratch_readl(pmc, pmc->soc->regs->scratch0); 9708c2ecf20Sopenharmony_ci value &= ~PMC_SCRATCH0_MODE_MASK; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (cmd) { 9738c2ecf20Sopenharmony_ci if (strcmp(cmd, "recovery") == 0) 9748c2ecf20Sopenharmony_ci value |= PMC_SCRATCH0_MODE_RECOVERY; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (strcmp(cmd, "bootloader") == 0) 9778c2ecf20Sopenharmony_ci value |= PMC_SCRATCH0_MODE_BOOTLOADER; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (strcmp(cmd, "forced-recovery") == 0) 9808c2ecf20Sopenharmony_ci value |= PMC_SCRATCH0_MODE_RCM; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci tegra_pmc_scratch_writel(pmc, value, pmc->soc->regs->scratch0); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */ 9868c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_CNTRL); 9878c2ecf20Sopenharmony_ci value |= PMC_CNTRL_MAIN_RST; 9888c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_CNTRL); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return NOTIFY_DONE; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic struct notifier_block tegra_pmc_restart_handler = { 9948c2ecf20Sopenharmony_ci .notifier_call = tegra_pmc_restart_notify, 9958c2ecf20Sopenharmony_ci .priority = 128, 9968c2ecf20Sopenharmony_ci}; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic int powergate_show(struct seq_file *s, void *data) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci unsigned int i; 10018c2ecf20Sopenharmony_ci int status; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci seq_printf(s, " powergate powered\n"); 10048c2ecf20Sopenharmony_ci seq_printf(s, "------------------\n"); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci for (i = 0; i < pmc->soc->num_powergates; i++) { 10078c2ecf20Sopenharmony_ci status = tegra_powergate_is_powered(pmc, i); 10088c2ecf20Sopenharmony_ci if (status < 0) 10098c2ecf20Sopenharmony_ci continue; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i], 10128c2ecf20Sopenharmony_ci status ? "yes" : "no"); 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(powergate); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_cistatic int tegra_powergate_debugfs_init(void) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, 10238c2ecf20Sopenharmony_ci &powergate_fops); 10248c2ecf20Sopenharmony_ci if (!pmc->debugfs) 10258c2ecf20Sopenharmony_ci return -ENOMEM; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci return 0; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic int tegra_powergate_of_get_clks(struct tegra_powergate *pg, 10318c2ecf20Sopenharmony_ci struct device_node *np) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct clk *clk; 10348c2ecf20Sopenharmony_ci unsigned int i, count; 10358c2ecf20Sopenharmony_ci int err; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci count = of_clk_get_parent_count(np); 10388c2ecf20Sopenharmony_ci if (count == 0) 10398c2ecf20Sopenharmony_ci return -ENODEV; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci pg->clks = kcalloc(count, sizeof(clk), GFP_KERNEL); 10428c2ecf20Sopenharmony_ci if (!pg->clks) 10438c2ecf20Sopenharmony_ci return -ENOMEM; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 10468c2ecf20Sopenharmony_ci pg->clks[i] = of_clk_get(np, i); 10478c2ecf20Sopenharmony_ci if (IS_ERR(pg->clks[i])) { 10488c2ecf20Sopenharmony_ci err = PTR_ERR(pg->clks[i]); 10498c2ecf20Sopenharmony_ci goto err; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci pg->num_clks = count; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci return 0; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cierr: 10588c2ecf20Sopenharmony_ci while (i--) 10598c2ecf20Sopenharmony_ci clk_put(pg->clks[i]); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci kfree(pg->clks); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci return err; 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic int tegra_powergate_of_get_resets(struct tegra_powergate *pg, 10678c2ecf20Sopenharmony_ci struct device_node *np, bool off) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct device *dev = pg->pmc->dev; 10708c2ecf20Sopenharmony_ci int err; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci pg->reset = of_reset_control_array_get_exclusive_released(np); 10738c2ecf20Sopenharmony_ci if (IS_ERR(pg->reset)) { 10748c2ecf20Sopenharmony_ci err = PTR_ERR(pg->reset); 10758c2ecf20Sopenharmony_ci dev_err(dev, "failed to get device resets: %d\n", err); 10768c2ecf20Sopenharmony_ci return err; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci err = reset_control_acquire(pg->reset); 10808c2ecf20Sopenharmony_ci if (err < 0) { 10818c2ecf20Sopenharmony_ci pr_err("failed to acquire resets: %d\n", err); 10828c2ecf20Sopenharmony_ci goto out; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (off) { 10868c2ecf20Sopenharmony_ci err = reset_control_assert(pg->reset); 10878c2ecf20Sopenharmony_ci } else { 10888c2ecf20Sopenharmony_ci err = reset_control_deassert(pg->reset); 10898c2ecf20Sopenharmony_ci if (err < 0) 10908c2ecf20Sopenharmony_ci goto out; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci reset_control_release(pg->reset); 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ciout: 10968c2ecf20Sopenharmony_ci if (err) { 10978c2ecf20Sopenharmony_ci reset_control_release(pg->reset); 10988c2ecf20Sopenharmony_ci reset_control_put(pg->reset); 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci return err; 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci struct device *dev = pmc->dev; 11078c2ecf20Sopenharmony_ci struct tegra_powergate *pg; 11088c2ecf20Sopenharmony_ci int id, err = 0; 11098c2ecf20Sopenharmony_ci bool off; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci pg = kzalloc(sizeof(*pg), GFP_KERNEL); 11128c2ecf20Sopenharmony_ci if (!pg) 11138c2ecf20Sopenharmony_ci return -ENOMEM; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci id = tegra_powergate_lookup(pmc, np->name); 11168c2ecf20Sopenharmony_ci if (id < 0) { 11178c2ecf20Sopenharmony_ci dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id); 11188c2ecf20Sopenharmony_ci err = -ENODEV; 11198c2ecf20Sopenharmony_ci goto free_mem; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* 11238c2ecf20Sopenharmony_ci * Clear the bit for this powergate so it cannot be managed 11248c2ecf20Sopenharmony_ci * directly via the legacy APIs for controlling powergates. 11258c2ecf20Sopenharmony_ci */ 11268c2ecf20Sopenharmony_ci clear_bit(id, pmc->powergates_available); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci pg->id = id; 11298c2ecf20Sopenharmony_ci pg->genpd.name = np->name; 11308c2ecf20Sopenharmony_ci pg->genpd.power_off = tegra_genpd_power_off; 11318c2ecf20Sopenharmony_ci pg->genpd.power_on = tegra_genpd_power_on; 11328c2ecf20Sopenharmony_ci pg->pmc = pmc; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci off = !tegra_powergate_is_powered(pmc, pg->id); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci err = tegra_powergate_of_get_clks(pg, np); 11378c2ecf20Sopenharmony_ci if (err < 0) { 11388c2ecf20Sopenharmony_ci dev_err(dev, "failed to get clocks for %pOFn: %d\n", np, err); 11398c2ecf20Sopenharmony_ci goto set_available; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci err = tegra_powergate_of_get_resets(pg, np, off); 11438c2ecf20Sopenharmony_ci if (err < 0) { 11448c2ecf20Sopenharmony_ci dev_err(dev, "failed to get resets for %pOFn: %d\n", np, err); 11458c2ecf20Sopenharmony_ci goto remove_clks; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { 11498c2ecf20Sopenharmony_ci if (off) 11508c2ecf20Sopenharmony_ci WARN_ON(tegra_powergate_power_up(pg, true)); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci goto remove_resets; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci err = pm_genpd_init(&pg->genpd, NULL, off); 11568c2ecf20Sopenharmony_ci if (err < 0) { 11578c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialise PM domain %pOFn: %d\n", np, 11588c2ecf20Sopenharmony_ci err); 11598c2ecf20Sopenharmony_ci goto remove_resets; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci err = of_genpd_add_provider_simple(np, &pg->genpd); 11638c2ecf20Sopenharmony_ci if (err < 0) { 11648c2ecf20Sopenharmony_ci dev_err(dev, "failed to add PM domain provider for %pOFn: %d\n", 11658c2ecf20Sopenharmony_ci np, err); 11668c2ecf20Sopenharmony_ci goto remove_genpd; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci dev_dbg(dev, "added PM domain %s\n", pg->genpd.name); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci return 0; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ciremove_genpd: 11748c2ecf20Sopenharmony_ci pm_genpd_remove(&pg->genpd); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ciremove_resets: 11778c2ecf20Sopenharmony_ci reset_control_put(pg->reset); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ciremove_clks: 11808c2ecf20Sopenharmony_ci while (pg->num_clks--) 11818c2ecf20Sopenharmony_ci clk_put(pg->clks[pg->num_clks]); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci kfree(pg->clks); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ciset_available: 11868c2ecf20Sopenharmony_ci set_bit(id, pmc->powergates_available); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cifree_mem: 11898c2ecf20Sopenharmony_ci kfree(pg); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci return err; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic int tegra_powergate_init(struct tegra_pmc *pmc, 11958c2ecf20Sopenharmony_ci struct device_node *parent) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci struct device_node *np, *child; 11988c2ecf20Sopenharmony_ci int err = 0; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci np = of_get_child_by_name(parent, "powergates"); 12018c2ecf20Sopenharmony_ci if (!np) 12028c2ecf20Sopenharmony_ci return 0; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 12058c2ecf20Sopenharmony_ci err = tegra_powergate_add(pmc, child); 12068c2ecf20Sopenharmony_ci if (err < 0) { 12078c2ecf20Sopenharmony_ci of_node_put(child); 12088c2ecf20Sopenharmony_ci break; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci of_node_put(np); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci return err; 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cistatic void tegra_powergate_remove(struct generic_pm_domain *genpd) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci struct tegra_powergate *pg = to_powergate(genpd); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci reset_control_put(pg->reset); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci while (pg->num_clks--) 12248c2ecf20Sopenharmony_ci clk_put(pg->clks[pg->num_clks]); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci kfree(pg->clks); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci set_bit(pg->id, pmc->powergates_available); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci kfree(pg); 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic void tegra_powergate_remove_all(struct device_node *parent) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct generic_pm_domain *genpd; 12368c2ecf20Sopenharmony_ci struct device_node *np, *child; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci np = of_get_child_by_name(parent, "powergates"); 12398c2ecf20Sopenharmony_ci if (!np) 12408c2ecf20Sopenharmony_ci return; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 12438c2ecf20Sopenharmony_ci of_genpd_del_provider(child); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci genpd = of_genpd_remove_last(child); 12468c2ecf20Sopenharmony_ci if (IS_ERR(genpd)) 12478c2ecf20Sopenharmony_ci continue; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci tegra_powergate_remove(genpd); 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci of_node_put(np); 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic const struct tegra_io_pad_soc * 12568c2ecf20Sopenharmony_citegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci unsigned int i; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci for (i = 0; i < pmc->soc->num_io_pads; i++) 12618c2ecf20Sopenharmony_ci if (pmc->soc->io_pads[i].id == id) 12628c2ecf20Sopenharmony_ci return &pmc->soc->io_pads[i]; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci return NULL; 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_cistatic int tegra_io_pad_get_dpd_register_bit(struct tegra_pmc *pmc, 12688c2ecf20Sopenharmony_ci enum tegra_io_pad id, 12698c2ecf20Sopenharmony_ci unsigned long *request, 12708c2ecf20Sopenharmony_ci unsigned long *status, 12718c2ecf20Sopenharmony_ci u32 *mask) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci const struct tegra_io_pad_soc *pad; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci pad = tegra_io_pad_find(pmc, id); 12768c2ecf20Sopenharmony_ci if (!pad) { 12778c2ecf20Sopenharmony_ci dev_err(pmc->dev, "invalid I/O pad ID %u\n", id); 12788c2ecf20Sopenharmony_ci return -ENOENT; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (pad->dpd == UINT_MAX) 12828c2ecf20Sopenharmony_ci return -ENOTSUPP; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci *mask = BIT(pad->dpd % 32); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if (pad->dpd < 32) { 12878c2ecf20Sopenharmony_ci *status = pmc->soc->regs->dpd_status; 12888c2ecf20Sopenharmony_ci *request = pmc->soc->regs->dpd_req; 12898c2ecf20Sopenharmony_ci } else { 12908c2ecf20Sopenharmony_ci *status = pmc->soc->regs->dpd2_status; 12918c2ecf20Sopenharmony_ci *request = pmc->soc->regs->dpd2_req; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci return 0; 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic int tegra_io_pad_prepare(struct tegra_pmc *pmc, enum tegra_io_pad id, 12988c2ecf20Sopenharmony_ci unsigned long *request, unsigned long *status, 12998c2ecf20Sopenharmony_ci u32 *mask) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci unsigned long rate, value; 13028c2ecf20Sopenharmony_ci int err; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci err = tegra_io_pad_get_dpd_register_bit(pmc, id, request, status, mask); 13058c2ecf20Sopenharmony_ci if (err) 13068c2ecf20Sopenharmony_ci return err; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (pmc->clk) { 13098c2ecf20Sopenharmony_ci rate = pmc->rate; 13108c2ecf20Sopenharmony_ci if (!rate) { 13118c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to get clock rate\n"); 13128c2ecf20Sopenharmony_ci return -ENODEV; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, DPD_SAMPLE_ENABLE, DPD_SAMPLE); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* must be at least 200 ns, in APB (PCLK) clock cycles */ 13188c2ecf20Sopenharmony_ci value = DIV_ROUND_UP(1000000000, rate); 13198c2ecf20Sopenharmony_ci value = DIV_ROUND_UP(200, value); 13208c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, SEL_DPD_TIM); 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci return 0; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic int tegra_io_pad_poll(struct tegra_pmc *pmc, unsigned long offset, 13278c2ecf20Sopenharmony_ci u32 mask, u32 val, unsigned long timeout) 13288c2ecf20Sopenharmony_ci{ 13298c2ecf20Sopenharmony_ci u32 value; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(timeout); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci while (time_after(timeout, jiffies)) { 13348c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, offset); 13358c2ecf20Sopenharmony_ci if ((value & mask) == val) 13368c2ecf20Sopenharmony_ci return 0; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci usleep_range(250, 1000); 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci return -ETIMEDOUT; 13428c2ecf20Sopenharmony_ci} 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_cistatic void tegra_io_pad_unprepare(struct tegra_pmc *pmc) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci if (pmc->clk) 13478c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, DPD_SAMPLE_DISABLE, DPD_SAMPLE); 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci/** 13518c2ecf20Sopenharmony_ci * tegra_io_pad_power_enable() - enable power to I/O pad 13528c2ecf20Sopenharmony_ci * @id: Tegra I/O pad ID for which to enable power 13538c2ecf20Sopenharmony_ci * 13548c2ecf20Sopenharmony_ci * Returns: 0 on success or a negative error code on failure. 13558c2ecf20Sopenharmony_ci */ 13568c2ecf20Sopenharmony_ciint tegra_io_pad_power_enable(enum tegra_io_pad id) 13578c2ecf20Sopenharmony_ci{ 13588c2ecf20Sopenharmony_ci unsigned long request, status; 13598c2ecf20Sopenharmony_ci u32 mask; 13608c2ecf20Sopenharmony_ci int err; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci mutex_lock(&pmc->powergates_lock); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci err = tegra_io_pad_prepare(pmc, id, &request, &status, &mask); 13658c2ecf20Sopenharmony_ci if (err < 0) { 13668c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to prepare I/O pad: %d\n", err); 13678c2ecf20Sopenharmony_ci goto unlock; 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, IO_DPD_REQ_CODE_OFF | mask, request); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci err = tegra_io_pad_poll(pmc, status, mask, 0, 250); 13738c2ecf20Sopenharmony_ci if (err < 0) { 13748c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to enable I/O pad: %d\n", err); 13758c2ecf20Sopenharmony_ci goto unlock; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci tegra_io_pad_unprepare(pmc); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ciunlock: 13818c2ecf20Sopenharmony_ci mutex_unlock(&pmc->powergates_lock); 13828c2ecf20Sopenharmony_ci return err; 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tegra_io_pad_power_enable); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci/** 13878c2ecf20Sopenharmony_ci * tegra_io_pad_power_disable() - disable power to I/O pad 13888c2ecf20Sopenharmony_ci * @id: Tegra I/O pad ID for which to disable power 13898c2ecf20Sopenharmony_ci * 13908c2ecf20Sopenharmony_ci * Returns: 0 on success or a negative error code on failure. 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_ciint tegra_io_pad_power_disable(enum tegra_io_pad id) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci unsigned long request, status; 13958c2ecf20Sopenharmony_ci u32 mask; 13968c2ecf20Sopenharmony_ci int err; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci mutex_lock(&pmc->powergates_lock); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci err = tegra_io_pad_prepare(pmc, id, &request, &status, &mask); 14018c2ecf20Sopenharmony_ci if (err < 0) { 14028c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to prepare I/O pad: %d\n", err); 14038c2ecf20Sopenharmony_ci goto unlock; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, IO_DPD_REQ_CODE_ON | mask, request); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci err = tegra_io_pad_poll(pmc, status, mask, mask, 250); 14098c2ecf20Sopenharmony_ci if (err < 0) { 14108c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to disable I/O pad: %d\n", err); 14118c2ecf20Sopenharmony_ci goto unlock; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci tegra_io_pad_unprepare(pmc); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ciunlock: 14178c2ecf20Sopenharmony_ci mutex_unlock(&pmc->powergates_lock); 14188c2ecf20Sopenharmony_ci return err; 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tegra_io_pad_power_disable); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_cistatic int tegra_io_pad_is_powered(struct tegra_pmc *pmc, enum tegra_io_pad id) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci unsigned long request, status; 14258c2ecf20Sopenharmony_ci u32 mask, value; 14268c2ecf20Sopenharmony_ci int err; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci err = tegra_io_pad_get_dpd_register_bit(pmc, id, &request, &status, 14298c2ecf20Sopenharmony_ci &mask); 14308c2ecf20Sopenharmony_ci if (err) 14318c2ecf20Sopenharmony_ci return err; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, status); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return !(value & mask); 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic int tegra_io_pad_set_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id, 14398c2ecf20Sopenharmony_ci int voltage) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci const struct tegra_io_pad_soc *pad; 14428c2ecf20Sopenharmony_ci u32 value; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci pad = tegra_io_pad_find(pmc, id); 14458c2ecf20Sopenharmony_ci if (!pad) 14468c2ecf20Sopenharmony_ci return -ENOENT; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (pad->voltage == UINT_MAX) 14498c2ecf20Sopenharmony_ci return -ENOTSUPP; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci mutex_lock(&pmc->powergates_lock); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci if (pmc->soc->has_impl_33v_pwr) { 14548c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_IMPL_E_33V_PWR); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8) 14578c2ecf20Sopenharmony_ci value &= ~BIT(pad->voltage); 14588c2ecf20Sopenharmony_ci else 14598c2ecf20Sopenharmony_ci value |= BIT(pad->voltage); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_IMPL_E_33V_PWR); 14628c2ecf20Sopenharmony_ci } else { 14638c2ecf20Sopenharmony_ci /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */ 14648c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_PWR_DET); 14658c2ecf20Sopenharmony_ci value |= BIT(pad->voltage); 14668c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_PWR_DET); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* update I/O voltage */ 14698c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_PWR_DET_VALUE); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8) 14728c2ecf20Sopenharmony_ci value &= ~BIT(pad->voltage); 14738c2ecf20Sopenharmony_ci else 14748c2ecf20Sopenharmony_ci value |= BIT(pad->voltage); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_PWR_DET_VALUE); 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci mutex_unlock(&pmc->powergates_lock); 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci usleep_range(100, 250); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci return 0; 14848c2ecf20Sopenharmony_ci} 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cistatic int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id) 14878c2ecf20Sopenharmony_ci{ 14888c2ecf20Sopenharmony_ci const struct tegra_io_pad_soc *pad; 14898c2ecf20Sopenharmony_ci u32 value; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci pad = tegra_io_pad_find(pmc, id); 14928c2ecf20Sopenharmony_ci if (!pad) 14938c2ecf20Sopenharmony_ci return -ENOENT; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci if (pad->voltage == UINT_MAX) 14968c2ecf20Sopenharmony_ci return -ENOTSUPP; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (pmc->soc->has_impl_33v_pwr) 14998c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_IMPL_E_33V_PWR); 15008c2ecf20Sopenharmony_ci else 15018c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_PWR_DET_VALUE); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci if ((value & BIT(pad->voltage)) == 0) 15048c2ecf20Sopenharmony_ci return TEGRA_IO_PAD_VOLTAGE_1V8; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci return TEGRA_IO_PAD_VOLTAGE_3V3; 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci/** 15108c2ecf20Sopenharmony_ci * tegra_io_rail_power_on() - enable power to I/O rail 15118c2ecf20Sopenharmony_ci * @id: Tegra I/O pad ID for which to enable power 15128c2ecf20Sopenharmony_ci * 15138c2ecf20Sopenharmony_ci * See also: tegra_io_pad_power_enable() 15148c2ecf20Sopenharmony_ci */ 15158c2ecf20Sopenharmony_ciint tegra_io_rail_power_on(unsigned int id) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci return tegra_io_pad_power_enable(id); 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tegra_io_rail_power_on); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci/** 15228c2ecf20Sopenharmony_ci * tegra_io_rail_power_off() - disable power to I/O rail 15238c2ecf20Sopenharmony_ci * @id: Tegra I/O pad ID for which to disable power 15248c2ecf20Sopenharmony_ci * 15258c2ecf20Sopenharmony_ci * See also: tegra_io_pad_power_disable() 15268c2ecf20Sopenharmony_ci */ 15278c2ecf20Sopenharmony_ciint tegra_io_rail_power_off(unsigned int id) 15288c2ecf20Sopenharmony_ci{ 15298c2ecf20Sopenharmony_ci return tegra_io_pad_power_disable(id); 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tegra_io_rail_power_off); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 15348c2ecf20Sopenharmony_cienum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) 15358c2ecf20Sopenharmony_ci{ 15368c2ecf20Sopenharmony_ci return pmc->suspend_mode; 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_civoid tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE) 15428c2ecf20Sopenharmony_ci return; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci pmc->suspend_mode = mode; 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_civoid tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci unsigned long long rate = 0; 15508c2ecf20Sopenharmony_ci u64 ticks; 15518c2ecf20Sopenharmony_ci u32 value; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci switch (mode) { 15548c2ecf20Sopenharmony_ci case TEGRA_SUSPEND_LP1: 15558c2ecf20Sopenharmony_ci rate = 32768; 15568c2ecf20Sopenharmony_ci break; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci case TEGRA_SUSPEND_LP2: 15598c2ecf20Sopenharmony_ci rate = pmc->rate; 15608c2ecf20Sopenharmony_ci break; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci default: 15638c2ecf20Sopenharmony_ci break; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(rate == 0)) 15678c2ecf20Sopenharmony_ci rate = 100000000; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1; 15708c2ecf20Sopenharmony_ci do_div(ticks, USEC_PER_SEC); 15718c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, ticks, PMC_CPUPWRGOOD_TIMER); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1; 15748c2ecf20Sopenharmony_ci do_div(ticks, USEC_PER_SEC); 15758c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, ticks, PMC_CPUPWROFF_TIMER); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_CNTRL); 15788c2ecf20Sopenharmony_ci value &= ~PMC_CNTRL_SIDE_EFFECT_LP0; 15798c2ecf20Sopenharmony_ci value |= PMC_CNTRL_CPU_PWRREQ_OE; 15808c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_CNTRL); 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci#endif 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_cistatic int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci u32 value, values[2]; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) { 15898c2ecf20Sopenharmony_ci } else { 15908c2ecf20Sopenharmony_ci switch (value) { 15918c2ecf20Sopenharmony_ci case 0: 15928c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_LP0; 15938c2ecf20Sopenharmony_ci break; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci case 1: 15968c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_LP1; 15978c2ecf20Sopenharmony_ci break; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci case 2: 16008c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_LP2; 16018c2ecf20Sopenharmony_ci break; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci default: 16048c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_NONE; 16058c2ecf20Sopenharmony_ci break; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci pmc->suspend_mode = tegra_pm_validate_suspend_mode(pmc->suspend_mode); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &value)) 16128c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_NONE; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci pmc->cpu_good_time = value; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &value)) 16178c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_NONE; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci pmc->cpu_off_time = value; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time", 16228c2ecf20Sopenharmony_ci values, ARRAY_SIZE(values))) 16238c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_NONE; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci pmc->core_osc_time = values[0]; 16268c2ecf20Sopenharmony_ci pmc->core_pmu_time = values[1]; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,core-pwr-off-time", &value)) 16298c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_NONE; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci pmc->core_off_time = value; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci pmc->corereq_high = of_property_read_bool(np, 16348c2ecf20Sopenharmony_ci "nvidia,core-power-req-active-high"); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci pmc->sysclkreq_high = of_property_read_bool(np, 16378c2ecf20Sopenharmony_ci "nvidia,sys-clock-req-active-high"); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci pmc->combined_req = of_property_read_bool(np, 16408c2ecf20Sopenharmony_ci "nvidia,combined-power-req"); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci pmc->cpu_pwr_good_en = of_property_read_bool(np, 16438c2ecf20Sopenharmony_ci "nvidia,cpu-pwr-good-en"); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci if (of_property_read_u32_array(np, "nvidia,lp0-vec", values, 16468c2ecf20Sopenharmony_ci ARRAY_SIZE(values))) 16478c2ecf20Sopenharmony_ci if (pmc->suspend_mode == TEGRA_SUSPEND_LP0) 16488c2ecf20Sopenharmony_ci pmc->suspend_mode = TEGRA_SUSPEND_LP1; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci pmc->lp0_vec_phys = values[0]; 16518c2ecf20Sopenharmony_ci pmc->lp0_vec_size = values[1]; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci return 0; 16548c2ecf20Sopenharmony_ci} 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cistatic void tegra_pmc_init(struct tegra_pmc *pmc) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci if (pmc->soc->init) 16598c2ecf20Sopenharmony_ci pmc->soc->init(pmc); 16608c2ecf20Sopenharmony_ci} 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_cistatic void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) 16638c2ecf20Sopenharmony_ci{ 16648c2ecf20Sopenharmony_ci static const char disabled[] = "emergency thermal reset disabled"; 16658c2ecf20Sopenharmony_ci u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux; 16668c2ecf20Sopenharmony_ci struct device *dev = pmc->dev; 16678c2ecf20Sopenharmony_ci struct device_node *np; 16688c2ecf20Sopenharmony_ci u32 value, checksum; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci if (!pmc->soc->has_tsense_reset) 16718c2ecf20Sopenharmony_ci return; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci np = of_get_child_by_name(pmc->dev->of_node, "i2c-thermtrip"); 16748c2ecf20Sopenharmony_ci if (!np) { 16758c2ecf20Sopenharmony_ci dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled); 16768c2ecf20Sopenharmony_ci return; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) { 16808c2ecf20Sopenharmony_ci dev_err(dev, "I2C controller ID missing, %s.\n", disabled); 16818c2ecf20Sopenharmony_ci goto out; 16828c2ecf20Sopenharmony_ci } 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,bus-addr", &pmu_addr)) { 16858c2ecf20Sopenharmony_ci dev_err(dev, "nvidia,bus-addr missing, %s.\n", disabled); 16868c2ecf20Sopenharmony_ci goto out; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,reg-addr", ®_addr)) { 16908c2ecf20Sopenharmony_ci dev_err(dev, "nvidia,reg-addr missing, %s.\n", disabled); 16918c2ecf20Sopenharmony_ci goto out; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,reg-data", ®_data)) { 16958c2ecf20Sopenharmony_ci dev_err(dev, "nvidia,reg-data missing, %s.\n", disabled); 16968c2ecf20Sopenharmony_ci goto out; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "nvidia,pinmux-id", &pinmux)) 17008c2ecf20Sopenharmony_ci pinmux = 0; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_SENSOR_CTRL); 17038c2ecf20Sopenharmony_ci value |= PMC_SENSOR_CTRL_SCRATCH_WRITE; 17048c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_SENSOR_CTRL); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) | 17078c2ecf20Sopenharmony_ci (reg_addr << PMC_SCRATCH54_ADDR_SHIFT); 17088c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_SCRATCH54); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci value = PMC_SCRATCH55_RESET_TEGRA; 17118c2ecf20Sopenharmony_ci value |= ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT; 17128c2ecf20Sopenharmony_ci value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT; 17138c2ecf20Sopenharmony_ci value |= pmu_addr << PMC_SCRATCH55_I2CSLV1_SHIFT; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci /* 17168c2ecf20Sopenharmony_ci * Calculate checksum of SCRATCH54, SCRATCH55 fields. Bits 23:16 will 17178c2ecf20Sopenharmony_ci * contain the checksum and are currently zero, so they are not added. 17188c2ecf20Sopenharmony_ci */ 17198c2ecf20Sopenharmony_ci checksum = reg_addr + reg_data + (value & 0xff) + ((value >> 8) & 0xff) 17208c2ecf20Sopenharmony_ci + ((value >> 24) & 0xff); 17218c2ecf20Sopenharmony_ci checksum &= 0xff; 17228c2ecf20Sopenharmony_ci checksum = 0x100 - checksum; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci value |= checksum << PMC_SCRATCH55_CHECKSUM_SHIFT; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_SCRATCH55); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_SENSOR_CTRL); 17298c2ecf20Sopenharmony_ci value |= PMC_SENSOR_CTRL_ENABLE_RST; 17308c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_SENSOR_CTRL); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci dev_info(pmc->dev, "emergency thermal reset enabled\n"); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ciout: 17358c2ecf20Sopenharmony_ci of_node_put(np); 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistatic int tegra_io_pad_pinctrl_get_groups_count(struct pinctrl_dev *pctl_dev) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl_dev); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci return pmc->soc->num_io_pads; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_cistatic const char *tegra_io_pad_pinctrl_get_group_name(struct pinctrl_dev *pctl, 17468c2ecf20Sopenharmony_ci unsigned int group) 17478c2ecf20Sopenharmony_ci{ 17488c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci return pmc->soc->io_pads[group].name; 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_cistatic int tegra_io_pad_pinctrl_get_group_pins(struct pinctrl_dev *pctl_dev, 17548c2ecf20Sopenharmony_ci unsigned int group, 17558c2ecf20Sopenharmony_ci const unsigned int **pins, 17568c2ecf20Sopenharmony_ci unsigned int *num_pins) 17578c2ecf20Sopenharmony_ci{ 17588c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl_dev); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci *pins = &pmc->soc->io_pads[group].id; 17618c2ecf20Sopenharmony_ci *num_pins = 1; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci return 0; 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cistatic const struct pinctrl_ops tegra_io_pad_pinctrl_ops = { 17678c2ecf20Sopenharmony_ci .get_groups_count = tegra_io_pad_pinctrl_get_groups_count, 17688c2ecf20Sopenharmony_ci .get_group_name = tegra_io_pad_pinctrl_get_group_name, 17698c2ecf20Sopenharmony_ci .get_group_pins = tegra_io_pad_pinctrl_get_group_pins, 17708c2ecf20Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, 17718c2ecf20Sopenharmony_ci .dt_free_map = pinconf_generic_dt_free_map, 17728c2ecf20Sopenharmony_ci}; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_cistatic int tegra_io_pad_pinconf_get(struct pinctrl_dev *pctl_dev, 17758c2ecf20Sopenharmony_ci unsigned int pin, unsigned long *config) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*config); 17788c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl_dev); 17798c2ecf20Sopenharmony_ci const struct tegra_io_pad_soc *pad; 17808c2ecf20Sopenharmony_ci int ret; 17818c2ecf20Sopenharmony_ci u32 arg; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci pad = tegra_io_pad_find(pmc, pin); 17848c2ecf20Sopenharmony_ci if (!pad) 17858c2ecf20Sopenharmony_ci return -EINVAL; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci switch (param) { 17888c2ecf20Sopenharmony_ci case PIN_CONFIG_POWER_SOURCE: 17898c2ecf20Sopenharmony_ci ret = tegra_io_pad_get_voltage(pmc, pad->id); 17908c2ecf20Sopenharmony_ci if (ret < 0) 17918c2ecf20Sopenharmony_ci return ret; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci arg = ret; 17948c2ecf20Sopenharmony_ci break; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci case PIN_CONFIG_LOW_POWER_MODE: 17978c2ecf20Sopenharmony_ci ret = tegra_io_pad_is_powered(pmc, pad->id); 17988c2ecf20Sopenharmony_ci if (ret < 0) 17998c2ecf20Sopenharmony_ci return ret; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci arg = !ret; 18028c2ecf20Sopenharmony_ci break; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci default: 18058c2ecf20Sopenharmony_ci return -EINVAL; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci return 0; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_cistatic int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctl_dev, 18148c2ecf20Sopenharmony_ci unsigned int pin, unsigned long *configs, 18158c2ecf20Sopenharmony_ci unsigned int num_configs) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = pinctrl_dev_get_drvdata(pctl_dev); 18188c2ecf20Sopenharmony_ci const struct tegra_io_pad_soc *pad; 18198c2ecf20Sopenharmony_ci enum pin_config_param param; 18208c2ecf20Sopenharmony_ci unsigned int i; 18218c2ecf20Sopenharmony_ci int err; 18228c2ecf20Sopenharmony_ci u32 arg; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci pad = tegra_io_pad_find(pmc, pin); 18258c2ecf20Sopenharmony_ci if (!pad) 18268c2ecf20Sopenharmony_ci return -EINVAL; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; ++i) { 18298c2ecf20Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 18308c2ecf20Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci switch (param) { 18338c2ecf20Sopenharmony_ci case PIN_CONFIG_LOW_POWER_MODE: 18348c2ecf20Sopenharmony_ci if (arg) 18358c2ecf20Sopenharmony_ci err = tegra_io_pad_power_disable(pad->id); 18368c2ecf20Sopenharmony_ci else 18378c2ecf20Sopenharmony_ci err = tegra_io_pad_power_enable(pad->id); 18388c2ecf20Sopenharmony_ci if (err) 18398c2ecf20Sopenharmony_ci return err; 18408c2ecf20Sopenharmony_ci break; 18418c2ecf20Sopenharmony_ci case PIN_CONFIG_POWER_SOURCE: 18428c2ecf20Sopenharmony_ci if (arg != TEGRA_IO_PAD_VOLTAGE_1V8 && 18438c2ecf20Sopenharmony_ci arg != TEGRA_IO_PAD_VOLTAGE_3V3) 18448c2ecf20Sopenharmony_ci return -EINVAL; 18458c2ecf20Sopenharmony_ci err = tegra_io_pad_set_voltage(pmc, pad->id, arg); 18468c2ecf20Sopenharmony_ci if (err) 18478c2ecf20Sopenharmony_ci return err; 18488c2ecf20Sopenharmony_ci break; 18498c2ecf20Sopenharmony_ci default: 18508c2ecf20Sopenharmony_ci return -EINVAL; 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci return 0; 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_cistatic const struct pinconf_ops tegra_io_pad_pinconf_ops = { 18588c2ecf20Sopenharmony_ci .pin_config_get = tegra_io_pad_pinconf_get, 18598c2ecf20Sopenharmony_ci .pin_config_set = tegra_io_pad_pinconf_set, 18608c2ecf20Sopenharmony_ci .is_generic = true, 18618c2ecf20Sopenharmony_ci}; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_cistatic struct pinctrl_desc tegra_pmc_pctl_desc = { 18648c2ecf20Sopenharmony_ci .pctlops = &tegra_io_pad_pinctrl_ops, 18658c2ecf20Sopenharmony_ci .confops = &tegra_io_pad_pinconf_ops, 18668c2ecf20Sopenharmony_ci}; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_cistatic int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci int err; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci if (!pmc->soc->num_pin_descs) 18738c2ecf20Sopenharmony_ci return 0; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci tegra_pmc_pctl_desc.name = dev_name(pmc->dev); 18768c2ecf20Sopenharmony_ci tegra_pmc_pctl_desc.pins = pmc->soc->pin_descs; 18778c2ecf20Sopenharmony_ci tegra_pmc_pctl_desc.npins = pmc->soc->num_pin_descs; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci pmc->pctl_dev = devm_pinctrl_register(pmc->dev, &tegra_pmc_pctl_desc, 18808c2ecf20Sopenharmony_ci pmc); 18818c2ecf20Sopenharmony_ci if (IS_ERR(pmc->pctl_dev)) { 18828c2ecf20Sopenharmony_ci err = PTR_ERR(pmc->pctl_dev); 18838c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to register pin controller: %d\n", 18848c2ecf20Sopenharmony_ci err); 18858c2ecf20Sopenharmony_ci return err; 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci return 0; 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_cistatic ssize_t reset_reason_show(struct device *dev, 18928c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 18938c2ecf20Sopenharmony_ci{ 18948c2ecf20Sopenharmony_ci u32 value; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status); 18978c2ecf20Sopenharmony_ci value &= pmc->soc->regs->rst_source_mask; 18988c2ecf20Sopenharmony_ci value >>= pmc->soc->regs->rst_source_shift; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci if (WARN_ON(value >= pmc->soc->num_reset_sources)) 19018c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", "UNKNOWN"); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", pmc->soc->reset_sources[value]); 19048c2ecf20Sopenharmony_ci} 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(reset_reason); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic ssize_t reset_level_show(struct device *dev, 19098c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci u32 value; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status); 19148c2ecf20Sopenharmony_ci value &= pmc->soc->regs->rst_level_mask; 19158c2ecf20Sopenharmony_ci value >>= pmc->soc->regs->rst_level_shift; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci if (WARN_ON(value >= pmc->soc->num_reset_levels)) 19188c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", "UNKNOWN"); 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", pmc->soc->reset_levels[value]); 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(reset_level); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_cistatic void tegra_pmc_reset_sysfs_init(struct tegra_pmc *pmc) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci struct device *dev = pmc->dev; 19288c2ecf20Sopenharmony_ci int err = 0; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci if (pmc->soc->reset_sources) { 19318c2ecf20Sopenharmony_ci err = device_create_file(dev, &dev_attr_reset_reason); 19328c2ecf20Sopenharmony_ci if (err < 0) 19338c2ecf20Sopenharmony_ci dev_warn(dev, 19348c2ecf20Sopenharmony_ci "failed to create attr \"reset_reason\": %d\n", 19358c2ecf20Sopenharmony_ci err); 19368c2ecf20Sopenharmony_ci } 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci if (pmc->soc->reset_levels) { 19398c2ecf20Sopenharmony_ci err = device_create_file(dev, &dev_attr_reset_level); 19408c2ecf20Sopenharmony_ci if (err < 0) 19418c2ecf20Sopenharmony_ci dev_warn(dev, 19428c2ecf20Sopenharmony_ci "failed to create attr \"reset_level\": %d\n", 19438c2ecf20Sopenharmony_ci err); 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci} 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_cistatic int tegra_pmc_irq_translate(struct irq_domain *domain, 19488c2ecf20Sopenharmony_ci struct irq_fwspec *fwspec, 19498c2ecf20Sopenharmony_ci unsigned long *hwirq, 19508c2ecf20Sopenharmony_ci unsigned int *type) 19518c2ecf20Sopenharmony_ci{ 19528c2ecf20Sopenharmony_ci if (WARN_ON(fwspec->param_count < 2)) 19538c2ecf20Sopenharmony_ci return -EINVAL; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci *hwirq = fwspec->param[0]; 19568c2ecf20Sopenharmony_ci *type = fwspec->param[1]; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci return 0; 19598c2ecf20Sopenharmony_ci} 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_cistatic int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, 19628c2ecf20Sopenharmony_ci unsigned int num_irqs, void *data) 19638c2ecf20Sopenharmony_ci{ 19648c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = domain->host_data; 19658c2ecf20Sopenharmony_ci const struct tegra_pmc_soc *soc = pmc->soc; 19668c2ecf20Sopenharmony_ci struct irq_fwspec *fwspec = data; 19678c2ecf20Sopenharmony_ci unsigned int i; 19688c2ecf20Sopenharmony_ci int err = 0; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci if (WARN_ON(num_irqs > 1)) 19718c2ecf20Sopenharmony_ci return -EINVAL; 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci for (i = 0; i < soc->num_wake_events; i++) { 19748c2ecf20Sopenharmony_ci const struct tegra_wake_event *event = &soc->wake_events[i]; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci if (fwspec->param_count == 2) { 19778c2ecf20Sopenharmony_ci struct irq_fwspec spec; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci if (event->id != fwspec->param[0]) 19808c2ecf20Sopenharmony_ci continue; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci err = irq_domain_set_hwirq_and_chip(domain, virq, 19838c2ecf20Sopenharmony_ci event->id, 19848c2ecf20Sopenharmony_ci &pmc->irq, pmc); 19858c2ecf20Sopenharmony_ci if (err < 0) 19868c2ecf20Sopenharmony_ci break; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci spec.fwnode = &pmc->dev->of_node->fwnode; 19898c2ecf20Sopenharmony_ci spec.param_count = 3; 19908c2ecf20Sopenharmony_ci spec.param[0] = GIC_SPI; 19918c2ecf20Sopenharmony_ci spec.param[1] = event->irq; 19928c2ecf20Sopenharmony_ci spec.param[2] = fwspec->param[1]; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci err = irq_domain_alloc_irqs_parent(domain, virq, 19958c2ecf20Sopenharmony_ci num_irqs, &spec); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci break; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci if (fwspec->param_count == 3) { 20018c2ecf20Sopenharmony_ci if (event->gpio.instance != fwspec->param[0] || 20028c2ecf20Sopenharmony_ci event->gpio.pin != fwspec->param[1]) 20038c2ecf20Sopenharmony_ci continue; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci err = irq_domain_set_hwirq_and_chip(domain, virq, 20068c2ecf20Sopenharmony_ci event->id, 20078c2ecf20Sopenharmony_ci &pmc->irq, pmc); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci /* GPIO hierarchies stop at the PMC level */ 20108c2ecf20Sopenharmony_ci if (!err && domain->parent) 20118c2ecf20Sopenharmony_ci err = irq_domain_disconnect_hierarchy(domain->parent, 20128c2ecf20Sopenharmony_ci virq); 20138c2ecf20Sopenharmony_ci break; 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci /* If there is no wake-up event, there is no PMC mapping */ 20188c2ecf20Sopenharmony_ci if (i == soc->num_wake_events) 20198c2ecf20Sopenharmony_ci err = irq_domain_disconnect_hierarchy(domain, virq); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci return err; 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic const struct irq_domain_ops tegra_pmc_irq_domain_ops = { 20258c2ecf20Sopenharmony_ci .translate = tegra_pmc_irq_translate, 20268c2ecf20Sopenharmony_ci .alloc = tegra_pmc_irq_alloc, 20278c2ecf20Sopenharmony_ci}; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_cistatic int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on) 20308c2ecf20Sopenharmony_ci{ 20318c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); 20328c2ecf20Sopenharmony_ci unsigned int offset, bit; 20338c2ecf20Sopenharmony_ci u32 value; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci offset = data->hwirq / 32; 20368c2ecf20Sopenharmony_ci bit = data->hwirq % 32; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci /* clear wake status */ 20398c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, 0, PMC_SW_WAKE_STATUS); 20408c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, 0, PMC_SW_WAKE2_STATUS); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, 0, PMC_WAKE_STATUS); 20438c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, 0, PMC_WAKE2_STATUS); 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci /* enable PMC wake */ 20468c2ecf20Sopenharmony_ci if (data->hwirq >= 32) 20478c2ecf20Sopenharmony_ci offset = PMC_WAKE2_MASK; 20488c2ecf20Sopenharmony_ci else 20498c2ecf20Sopenharmony_ci offset = PMC_WAKE_MASK; 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, offset); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci if (on) 20548c2ecf20Sopenharmony_ci value |= BIT(bit); 20558c2ecf20Sopenharmony_ci else 20568c2ecf20Sopenharmony_ci value &= ~BIT(bit); 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, offset); 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci return 0; 20618c2ecf20Sopenharmony_ci} 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_cistatic int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type) 20648c2ecf20Sopenharmony_ci{ 20658c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); 20668c2ecf20Sopenharmony_ci unsigned int offset, bit; 20678c2ecf20Sopenharmony_ci u32 value; 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci offset = data->hwirq / 32; 20708c2ecf20Sopenharmony_ci bit = data->hwirq % 32; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci if (data->hwirq >= 32) 20738c2ecf20Sopenharmony_ci offset = PMC_WAKE2_LEVEL; 20748c2ecf20Sopenharmony_ci else 20758c2ecf20Sopenharmony_ci offset = PMC_WAKE_LEVEL; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, offset); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci switch (type) { 20808c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 20818c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 20828c2ecf20Sopenharmony_ci value |= BIT(bit); 20838c2ecf20Sopenharmony_ci break; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 20868c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 20878c2ecf20Sopenharmony_ci value &= ~BIT(bit); 20888c2ecf20Sopenharmony_ci break; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING: 20918c2ecf20Sopenharmony_ci value ^= BIT(bit); 20928c2ecf20Sopenharmony_ci break; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci default: 20958c2ecf20Sopenharmony_ci return -EINVAL; 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, offset); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci return 0; 21018c2ecf20Sopenharmony_ci} 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_cistatic int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on) 21048c2ecf20Sopenharmony_ci{ 21058c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); 21068c2ecf20Sopenharmony_ci unsigned int offset, bit; 21078c2ecf20Sopenharmony_ci u32 value; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci offset = data->hwirq / 32; 21108c2ecf20Sopenharmony_ci bit = data->hwirq % 32; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci /* clear wake status */ 21138c2ecf20Sopenharmony_ci writel(0x1, pmc->wake + WAKE_AOWAKE_STATUS_W(data->hwirq)); 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci /* route wake to tier 2 */ 21168c2ecf20Sopenharmony_ci value = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset)); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci if (!on) 21198c2ecf20Sopenharmony_ci value &= ~(1 << bit); 21208c2ecf20Sopenharmony_ci else 21218c2ecf20Sopenharmony_ci value |= 1 << bit; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci writel(value, pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset)); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci /* enable wakeup event */ 21268c2ecf20Sopenharmony_ci writel(!!on, pmc->wake + WAKE_AOWAKE_MASK_W(data->hwirq)); 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci return 0; 21298c2ecf20Sopenharmony_ci} 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_cistatic int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type) 21328c2ecf20Sopenharmony_ci{ 21338c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); 21348c2ecf20Sopenharmony_ci u32 value; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci switch (type) { 21398c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 21408c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 21418c2ecf20Sopenharmony_ci value |= WAKE_AOWAKE_CNTRL_LEVEL; 21428c2ecf20Sopenharmony_ci break; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 21458c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 21468c2ecf20Sopenharmony_ci value &= ~WAKE_AOWAKE_CNTRL_LEVEL; 21478c2ecf20Sopenharmony_ci break; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING: 21508c2ecf20Sopenharmony_ci value ^= WAKE_AOWAKE_CNTRL_LEVEL; 21518c2ecf20Sopenharmony_ci break; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci default: 21548c2ecf20Sopenharmony_ci return -EINVAL; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci return 0; 21608c2ecf20Sopenharmony_ci} 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_cistatic void tegra_irq_mask_parent(struct irq_data *data) 21638c2ecf20Sopenharmony_ci{ 21648c2ecf20Sopenharmony_ci if (data->parent_data) 21658c2ecf20Sopenharmony_ci irq_chip_mask_parent(data); 21668c2ecf20Sopenharmony_ci} 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_cistatic void tegra_irq_unmask_parent(struct irq_data *data) 21698c2ecf20Sopenharmony_ci{ 21708c2ecf20Sopenharmony_ci if (data->parent_data) 21718c2ecf20Sopenharmony_ci irq_chip_unmask_parent(data); 21728c2ecf20Sopenharmony_ci} 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_cistatic void tegra_irq_eoi_parent(struct irq_data *data) 21758c2ecf20Sopenharmony_ci{ 21768c2ecf20Sopenharmony_ci if (data->parent_data) 21778c2ecf20Sopenharmony_ci irq_chip_eoi_parent(data); 21788c2ecf20Sopenharmony_ci} 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_cistatic int tegra_irq_set_affinity_parent(struct irq_data *data, 21818c2ecf20Sopenharmony_ci const struct cpumask *dest, 21828c2ecf20Sopenharmony_ci bool force) 21838c2ecf20Sopenharmony_ci{ 21848c2ecf20Sopenharmony_ci if (data->parent_data) 21858c2ecf20Sopenharmony_ci return irq_chip_set_affinity_parent(data, dest, force); 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci return -EINVAL; 21888c2ecf20Sopenharmony_ci} 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_cistatic int tegra_pmc_irq_init(struct tegra_pmc *pmc) 21918c2ecf20Sopenharmony_ci{ 21928c2ecf20Sopenharmony_ci struct irq_domain *parent = NULL; 21938c2ecf20Sopenharmony_ci struct device_node *np; 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci np = of_irq_find_parent(pmc->dev->of_node); 21968c2ecf20Sopenharmony_ci if (np) { 21978c2ecf20Sopenharmony_ci parent = irq_find_host(np); 21988c2ecf20Sopenharmony_ci of_node_put(np); 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci if (!parent) 22028c2ecf20Sopenharmony_ci return 0; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci pmc->irq.name = dev_name(pmc->dev); 22058c2ecf20Sopenharmony_ci pmc->irq.irq_mask = tegra_irq_mask_parent; 22068c2ecf20Sopenharmony_ci pmc->irq.irq_unmask = tegra_irq_unmask_parent; 22078c2ecf20Sopenharmony_ci pmc->irq.irq_eoi = tegra_irq_eoi_parent; 22088c2ecf20Sopenharmony_ci pmc->irq.irq_set_affinity = tegra_irq_set_affinity_parent; 22098c2ecf20Sopenharmony_ci pmc->irq.irq_set_type = pmc->soc->irq_set_type; 22108c2ecf20Sopenharmony_ci pmc->irq.irq_set_wake = pmc->soc->irq_set_wake; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node, 22138c2ecf20Sopenharmony_ci &tegra_pmc_irq_domain_ops, pmc); 22148c2ecf20Sopenharmony_ci if (!pmc->domain) { 22158c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to allocate domain\n"); 22168c2ecf20Sopenharmony_ci return -ENOMEM; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci return 0; 22208c2ecf20Sopenharmony_ci} 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_cistatic int tegra_pmc_clk_notify_cb(struct notifier_block *nb, 22238c2ecf20Sopenharmony_ci unsigned long action, void *ptr) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = container_of(nb, struct tegra_pmc, clk_nb); 22268c2ecf20Sopenharmony_ci struct clk_notifier_data *data = ptr; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci switch (action) { 22298c2ecf20Sopenharmony_ci case PRE_RATE_CHANGE: 22308c2ecf20Sopenharmony_ci mutex_lock(&pmc->powergates_lock); 22318c2ecf20Sopenharmony_ci break; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci case POST_RATE_CHANGE: 22348c2ecf20Sopenharmony_ci pmc->rate = data->new_rate; 22358c2ecf20Sopenharmony_ci fallthrough; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci case ABORT_RATE_CHANGE: 22388c2ecf20Sopenharmony_ci mutex_unlock(&pmc->powergates_lock); 22398c2ecf20Sopenharmony_ci break; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci default: 22428c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 22438c2ecf20Sopenharmony_ci return notifier_from_errno(-EINVAL); 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci return NOTIFY_OK; 22478c2ecf20Sopenharmony_ci} 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_cistatic void pmc_clk_fence_udelay(u32 offset) 22508c2ecf20Sopenharmony_ci{ 22518c2ecf20Sopenharmony_ci tegra_pmc_readl(pmc, offset); 22528c2ecf20Sopenharmony_ci /* pmc clk propagation delay 2 us */ 22538c2ecf20Sopenharmony_ci udelay(2); 22548c2ecf20Sopenharmony_ci} 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_cistatic u8 pmc_clk_mux_get_parent(struct clk_hw *hw) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci struct pmc_clk *clk = to_pmc_clk(hw); 22598c2ecf20Sopenharmony_ci u32 val; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci val = tegra_pmc_readl(pmc, clk->offs) >> clk->mux_shift; 22628c2ecf20Sopenharmony_ci val &= PMC_CLK_OUT_MUX_MASK; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci return val; 22658c2ecf20Sopenharmony_ci} 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_cistatic int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index) 22688c2ecf20Sopenharmony_ci{ 22698c2ecf20Sopenharmony_ci struct pmc_clk *clk = to_pmc_clk(hw); 22708c2ecf20Sopenharmony_ci u32 val; 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci val = tegra_pmc_readl(pmc, clk->offs); 22738c2ecf20Sopenharmony_ci val &= ~(PMC_CLK_OUT_MUX_MASK << clk->mux_shift); 22748c2ecf20Sopenharmony_ci val |= index << clk->mux_shift; 22758c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, val, clk->offs); 22768c2ecf20Sopenharmony_ci pmc_clk_fence_udelay(clk->offs); 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci return 0; 22798c2ecf20Sopenharmony_ci} 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_cistatic int pmc_clk_is_enabled(struct clk_hw *hw) 22828c2ecf20Sopenharmony_ci{ 22838c2ecf20Sopenharmony_ci struct pmc_clk *clk = to_pmc_clk(hw); 22848c2ecf20Sopenharmony_ci u32 val; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci val = tegra_pmc_readl(pmc, clk->offs) & BIT(clk->force_en_shift); 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci return val ? 1 : 0; 22898c2ecf20Sopenharmony_ci} 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_cistatic void pmc_clk_set_state(unsigned long offs, u32 shift, int state) 22928c2ecf20Sopenharmony_ci{ 22938c2ecf20Sopenharmony_ci u32 val; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci val = tegra_pmc_readl(pmc, offs); 22968c2ecf20Sopenharmony_ci val = state ? (val | BIT(shift)) : (val & ~BIT(shift)); 22978c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, val, offs); 22988c2ecf20Sopenharmony_ci pmc_clk_fence_udelay(offs); 22998c2ecf20Sopenharmony_ci} 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_cistatic int pmc_clk_enable(struct clk_hw *hw) 23028c2ecf20Sopenharmony_ci{ 23038c2ecf20Sopenharmony_ci struct pmc_clk *clk = to_pmc_clk(hw); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci pmc_clk_set_state(clk->offs, clk->force_en_shift, 1); 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci return 0; 23088c2ecf20Sopenharmony_ci} 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_cistatic void pmc_clk_disable(struct clk_hw *hw) 23118c2ecf20Sopenharmony_ci{ 23128c2ecf20Sopenharmony_ci struct pmc_clk *clk = to_pmc_clk(hw); 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci pmc_clk_set_state(clk->offs, clk->force_en_shift, 0); 23158c2ecf20Sopenharmony_ci} 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_cistatic const struct clk_ops pmc_clk_ops = { 23188c2ecf20Sopenharmony_ci .get_parent = pmc_clk_mux_get_parent, 23198c2ecf20Sopenharmony_ci .set_parent = pmc_clk_mux_set_parent, 23208c2ecf20Sopenharmony_ci .determine_rate = __clk_mux_determine_rate, 23218c2ecf20Sopenharmony_ci .is_enabled = pmc_clk_is_enabled, 23228c2ecf20Sopenharmony_ci .enable = pmc_clk_enable, 23238c2ecf20Sopenharmony_ci .disable = pmc_clk_disable, 23248c2ecf20Sopenharmony_ci}; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic struct clk * 23278c2ecf20Sopenharmony_citegra_pmc_clk_out_register(struct tegra_pmc *pmc, 23288c2ecf20Sopenharmony_ci const struct pmc_clk_init_data *data, 23298c2ecf20Sopenharmony_ci unsigned long offset) 23308c2ecf20Sopenharmony_ci{ 23318c2ecf20Sopenharmony_ci struct clk_init_data init; 23328c2ecf20Sopenharmony_ci struct pmc_clk *pmc_clk; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci pmc_clk = devm_kzalloc(pmc->dev, sizeof(*pmc_clk), GFP_KERNEL); 23358c2ecf20Sopenharmony_ci if (!pmc_clk) 23368c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci init.name = data->name; 23398c2ecf20Sopenharmony_ci init.ops = &pmc_clk_ops; 23408c2ecf20Sopenharmony_ci init.parent_names = data->parents; 23418c2ecf20Sopenharmony_ci init.num_parents = data->num_parents; 23428c2ecf20Sopenharmony_ci init.flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT | 23438c2ecf20Sopenharmony_ci CLK_SET_PARENT_GATE; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci pmc_clk->hw.init = &init; 23468c2ecf20Sopenharmony_ci pmc_clk->offs = offset; 23478c2ecf20Sopenharmony_ci pmc_clk->mux_shift = data->mux_shift; 23488c2ecf20Sopenharmony_ci pmc_clk->force_en_shift = data->force_en_shift; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci return clk_register(NULL, &pmc_clk->hw); 23518c2ecf20Sopenharmony_ci} 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_cistatic int pmc_clk_gate_is_enabled(struct clk_hw *hw) 23548c2ecf20Sopenharmony_ci{ 23558c2ecf20Sopenharmony_ci struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0; 23588c2ecf20Sopenharmony_ci} 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_cistatic int pmc_clk_gate_enable(struct clk_hw *hw) 23618c2ecf20Sopenharmony_ci{ 23628c2ecf20Sopenharmony_ci struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci pmc_clk_set_state(gate->offs, gate->shift, 1); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci return 0; 23678c2ecf20Sopenharmony_ci} 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_cistatic void pmc_clk_gate_disable(struct clk_hw *hw) 23708c2ecf20Sopenharmony_ci{ 23718c2ecf20Sopenharmony_ci struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci pmc_clk_set_state(gate->offs, gate->shift, 0); 23748c2ecf20Sopenharmony_ci} 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_cistatic const struct clk_ops pmc_clk_gate_ops = { 23778c2ecf20Sopenharmony_ci .is_enabled = pmc_clk_gate_is_enabled, 23788c2ecf20Sopenharmony_ci .enable = pmc_clk_gate_enable, 23798c2ecf20Sopenharmony_ci .disable = pmc_clk_gate_disable, 23808c2ecf20Sopenharmony_ci}; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_cistatic struct clk * 23838c2ecf20Sopenharmony_citegra_pmc_clk_gate_register(struct tegra_pmc *pmc, const char *name, 23848c2ecf20Sopenharmony_ci const char *parent_name, unsigned long offset, 23858c2ecf20Sopenharmony_ci u32 shift) 23868c2ecf20Sopenharmony_ci{ 23878c2ecf20Sopenharmony_ci struct clk_init_data init; 23888c2ecf20Sopenharmony_ci struct pmc_clk_gate *gate; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci gate = devm_kzalloc(pmc->dev, sizeof(*gate), GFP_KERNEL); 23918c2ecf20Sopenharmony_ci if (!gate) 23928c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci init.name = name; 23958c2ecf20Sopenharmony_ci init.ops = &pmc_clk_gate_ops; 23968c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 23978c2ecf20Sopenharmony_ci init.num_parents = 1; 23988c2ecf20Sopenharmony_ci init.flags = 0; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci gate->hw.init = &init; 24018c2ecf20Sopenharmony_ci gate->offs = offset; 24028c2ecf20Sopenharmony_ci gate->shift = shift; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci return clk_register(NULL, &gate->hw); 24058c2ecf20Sopenharmony_ci} 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_cistatic void tegra_pmc_clock_register(struct tegra_pmc *pmc, 24088c2ecf20Sopenharmony_ci struct device_node *np) 24098c2ecf20Sopenharmony_ci{ 24108c2ecf20Sopenharmony_ci struct clk *clk; 24118c2ecf20Sopenharmony_ci struct clk_onecell_data *clk_data; 24128c2ecf20Sopenharmony_ci unsigned int num_clks; 24138c2ecf20Sopenharmony_ci int i, err; 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci num_clks = pmc->soc->num_pmc_clks; 24168c2ecf20Sopenharmony_ci if (pmc->soc->has_blink_output) 24178c2ecf20Sopenharmony_ci num_clks += 1; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci if (!num_clks) 24208c2ecf20Sopenharmony_ci return; 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci clk_data = devm_kmalloc(pmc->dev, sizeof(*clk_data), GFP_KERNEL); 24238c2ecf20Sopenharmony_ci if (!clk_data) 24248c2ecf20Sopenharmony_ci return; 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci clk_data->clks = devm_kcalloc(pmc->dev, TEGRA_PMC_CLK_MAX, 24278c2ecf20Sopenharmony_ci sizeof(*clk_data->clks), GFP_KERNEL); 24288c2ecf20Sopenharmony_ci if (!clk_data->clks) 24298c2ecf20Sopenharmony_ci return; 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci clk_data->clk_num = TEGRA_PMC_CLK_MAX; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci for (i = 0; i < TEGRA_PMC_CLK_MAX; i++) 24348c2ecf20Sopenharmony_ci clk_data->clks[i] = ERR_PTR(-ENOENT); 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci for (i = 0; i < pmc->soc->num_pmc_clks; i++) { 24378c2ecf20Sopenharmony_ci const struct pmc_clk_init_data *data; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci data = pmc->soc->pmc_clks_data + i; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci clk = tegra_pmc_clk_out_register(pmc, data, PMC_CLK_OUT_CNTRL); 24428c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 24438c2ecf20Sopenharmony_ci dev_warn(pmc->dev, "unable to register clock %s: %d\n", 24448c2ecf20Sopenharmony_ci data->name, PTR_ERR_OR_ZERO(clk)); 24458c2ecf20Sopenharmony_ci return; 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci err = clk_register_clkdev(clk, data->name, NULL); 24498c2ecf20Sopenharmony_ci if (err) { 24508c2ecf20Sopenharmony_ci dev_warn(pmc->dev, 24518c2ecf20Sopenharmony_ci "unable to register %s clock lookup: %d\n", 24528c2ecf20Sopenharmony_ci data->name, err); 24538c2ecf20Sopenharmony_ci return; 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci clk_data->clks[data->clk_id] = clk; 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci if (pmc->soc->has_blink_output) { 24608c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, 0x0, PMC_BLINK_TIMER); 24618c2ecf20Sopenharmony_ci clk = tegra_pmc_clk_gate_register(pmc, 24628c2ecf20Sopenharmony_ci "pmc_blink_override", 24638c2ecf20Sopenharmony_ci "clk_32k", 24648c2ecf20Sopenharmony_ci PMC_DPD_PADS_ORIDE, 24658c2ecf20Sopenharmony_ci PMC_DPD_PADS_ORIDE_BLINK); 24668c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 24678c2ecf20Sopenharmony_ci dev_warn(pmc->dev, 24688c2ecf20Sopenharmony_ci "unable to register pmc_blink_override: %d\n", 24698c2ecf20Sopenharmony_ci PTR_ERR_OR_ZERO(clk)); 24708c2ecf20Sopenharmony_ci return; 24718c2ecf20Sopenharmony_ci } 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci clk = tegra_pmc_clk_gate_register(pmc, "pmc_blink", 24748c2ecf20Sopenharmony_ci "pmc_blink_override", 24758c2ecf20Sopenharmony_ci PMC_CNTRL, 24768c2ecf20Sopenharmony_ci PMC_CNTRL_BLINK_EN); 24778c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 24788c2ecf20Sopenharmony_ci dev_warn(pmc->dev, 24798c2ecf20Sopenharmony_ci "unable to register pmc_blink: %d\n", 24808c2ecf20Sopenharmony_ci PTR_ERR_OR_ZERO(clk)); 24818c2ecf20Sopenharmony_ci return; 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci err = clk_register_clkdev(clk, "pmc_blink", NULL); 24858c2ecf20Sopenharmony_ci if (err) { 24868c2ecf20Sopenharmony_ci dev_warn(pmc->dev, 24878c2ecf20Sopenharmony_ci "unable to register pmc_blink lookup: %d\n", 24888c2ecf20Sopenharmony_ci err); 24898c2ecf20Sopenharmony_ci return; 24908c2ecf20Sopenharmony_ci } 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci clk_data->clks[TEGRA_PMC_CLK_BLINK] = clk; 24938c2ecf20Sopenharmony_ci } 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci err = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); 24968c2ecf20Sopenharmony_ci if (err) 24978c2ecf20Sopenharmony_ci dev_warn(pmc->dev, "failed to add pmc clock provider: %d\n", 24988c2ecf20Sopenharmony_ci err); 24998c2ecf20Sopenharmony_ci} 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_cistatic int tegra_pmc_probe(struct platform_device *pdev) 25028c2ecf20Sopenharmony_ci{ 25038c2ecf20Sopenharmony_ci void __iomem *base; 25048c2ecf20Sopenharmony_ci struct resource *res; 25058c2ecf20Sopenharmony_ci int err; 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci /* 25088c2ecf20Sopenharmony_ci * Early initialisation should have configured an initial 25098c2ecf20Sopenharmony_ci * register mapping and setup the soc data pointer. If these 25108c2ecf20Sopenharmony_ci * are not valid then something went badly wrong! 25118c2ecf20Sopenharmony_ci */ 25128c2ecf20Sopenharmony_ci if (WARN_ON(!pmc->base || !pmc->soc)) 25138c2ecf20Sopenharmony_ci return -ENODEV; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node); 25168c2ecf20Sopenharmony_ci if (err < 0) 25178c2ecf20Sopenharmony_ci return err; 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci /* take over the memory region from the early initialization */ 25208c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 25218c2ecf20Sopenharmony_ci base = devm_ioremap_resource(&pdev->dev, res); 25228c2ecf20Sopenharmony_ci if (IS_ERR(base)) 25238c2ecf20Sopenharmony_ci return PTR_ERR(base); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake"); 25268c2ecf20Sopenharmony_ci if (res) { 25278c2ecf20Sopenharmony_ci pmc->wake = devm_ioremap_resource(&pdev->dev, res); 25288c2ecf20Sopenharmony_ci if (IS_ERR(pmc->wake)) 25298c2ecf20Sopenharmony_ci return PTR_ERR(pmc->wake); 25308c2ecf20Sopenharmony_ci } else { 25318c2ecf20Sopenharmony_ci pmc->wake = base; 25328c2ecf20Sopenharmony_ci } 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag"); 25358c2ecf20Sopenharmony_ci if (res) { 25368c2ecf20Sopenharmony_ci pmc->aotag = devm_ioremap_resource(&pdev->dev, res); 25378c2ecf20Sopenharmony_ci if (IS_ERR(pmc->aotag)) 25388c2ecf20Sopenharmony_ci return PTR_ERR(pmc->aotag); 25398c2ecf20Sopenharmony_ci } else { 25408c2ecf20Sopenharmony_ci pmc->aotag = base; 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch"); 25448c2ecf20Sopenharmony_ci if (res) { 25458c2ecf20Sopenharmony_ci pmc->scratch = devm_ioremap_resource(&pdev->dev, res); 25468c2ecf20Sopenharmony_ci if (IS_ERR(pmc->scratch)) 25478c2ecf20Sopenharmony_ci return PTR_ERR(pmc->scratch); 25488c2ecf20Sopenharmony_ci } else { 25498c2ecf20Sopenharmony_ci pmc->scratch = base; 25508c2ecf20Sopenharmony_ci } 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci pmc->clk = devm_clk_get(&pdev->dev, "pclk"); 25538c2ecf20Sopenharmony_ci if (IS_ERR(pmc->clk)) { 25548c2ecf20Sopenharmony_ci err = PTR_ERR(pmc->clk); 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci if (err != -ENOENT) { 25578c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get pclk: %d\n", err); 25588c2ecf20Sopenharmony_ci return err; 25598c2ecf20Sopenharmony_ci } 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci pmc->clk = NULL; 25628c2ecf20Sopenharmony_ci } 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci /* 25658c2ecf20Sopenharmony_ci * PCLK clock rate can't be retrieved using CLK API because it 25668c2ecf20Sopenharmony_ci * causes lockup if CPU enters LP2 idle state from some other 25678c2ecf20Sopenharmony_ci * CLK notifier, hence we're caching the rate's value locally. 25688c2ecf20Sopenharmony_ci */ 25698c2ecf20Sopenharmony_ci if (pmc->clk) { 25708c2ecf20Sopenharmony_ci pmc->clk_nb.notifier_call = tegra_pmc_clk_notify_cb; 25718c2ecf20Sopenharmony_ci err = clk_notifier_register(pmc->clk, &pmc->clk_nb); 25728c2ecf20Sopenharmony_ci if (err) { 25738c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 25748c2ecf20Sopenharmony_ci "failed to register clk notifier\n"); 25758c2ecf20Sopenharmony_ci return err; 25768c2ecf20Sopenharmony_ci } 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci pmc->rate = clk_get_rate(pmc->clk); 25798c2ecf20Sopenharmony_ci } 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci pmc->dev = &pdev->dev; 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci tegra_pmc_init(pmc); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci tegra_pmc_init_tsense_reset(pmc); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci tegra_pmc_reset_sysfs_init(pmc); 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) { 25908c2ecf20Sopenharmony_ci err = tegra_powergate_debugfs_init(); 25918c2ecf20Sopenharmony_ci if (err < 0) 25928c2ecf20Sopenharmony_ci goto cleanup_sysfs; 25938c2ecf20Sopenharmony_ci } 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci err = register_restart_handler(&tegra_pmc_restart_handler); 25968c2ecf20Sopenharmony_ci if (err) { 25978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unable to register restart handler, %d\n", 25988c2ecf20Sopenharmony_ci err); 25998c2ecf20Sopenharmony_ci goto cleanup_debugfs; 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci err = tegra_pmc_pinctrl_init(pmc); 26038c2ecf20Sopenharmony_ci if (err) 26048c2ecf20Sopenharmony_ci goto cleanup_restart_handler; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci err = tegra_powergate_init(pmc, pdev->dev.of_node); 26078c2ecf20Sopenharmony_ci if (err < 0) 26088c2ecf20Sopenharmony_ci goto cleanup_powergates; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci err = tegra_pmc_irq_init(pmc); 26118c2ecf20Sopenharmony_ci if (err < 0) 26128c2ecf20Sopenharmony_ci goto cleanup_powergates; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci mutex_lock(&pmc->powergates_lock); 26158c2ecf20Sopenharmony_ci iounmap(pmc->base); 26168c2ecf20Sopenharmony_ci pmc->base = base; 26178c2ecf20Sopenharmony_ci mutex_unlock(&pmc->powergates_lock); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci tegra_pmc_clock_register(pmc, pdev->dev.of_node); 26208c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pmc); 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci return 0; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_cicleanup_powergates: 26258c2ecf20Sopenharmony_ci tegra_powergate_remove_all(pdev->dev.of_node); 26268c2ecf20Sopenharmony_cicleanup_restart_handler: 26278c2ecf20Sopenharmony_ci unregister_restart_handler(&tegra_pmc_restart_handler); 26288c2ecf20Sopenharmony_cicleanup_debugfs: 26298c2ecf20Sopenharmony_ci debugfs_remove(pmc->debugfs); 26308c2ecf20Sopenharmony_cicleanup_sysfs: 26318c2ecf20Sopenharmony_ci device_remove_file(&pdev->dev, &dev_attr_reset_reason); 26328c2ecf20Sopenharmony_ci device_remove_file(&pdev->dev, &dev_attr_reset_level); 26338c2ecf20Sopenharmony_ci clk_notifier_unregister(pmc->clk, &pmc->clk_nb); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci return err; 26368c2ecf20Sopenharmony_ci} 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) 26398c2ecf20Sopenharmony_cistatic int tegra_pmc_suspend(struct device *dev) 26408c2ecf20Sopenharmony_ci{ 26418c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = dev_get_drvdata(dev); 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, virt_to_phys(tegra_resume), PMC_SCRATCH41); 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci return 0; 26468c2ecf20Sopenharmony_ci} 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_cistatic int tegra_pmc_resume(struct device *dev) 26498c2ecf20Sopenharmony_ci{ 26508c2ecf20Sopenharmony_ci struct tegra_pmc *pmc = dev_get_drvdata(dev); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, 0x0, PMC_SCRATCH41); 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci return 0; 26558c2ecf20Sopenharmony_ci} 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci#endif 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_cistatic const char * const tegra20_powergates[] = { 26628c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU] = "cpu", 26638c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_3D] = "3d", 26648c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VENC] = "venc", 26658c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VDEC] = "vdec", 26668c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_PCIE] = "pcie", 26678c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_L2] = "l2", 26688c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_MPE] = "mpe", 26698c2ecf20Sopenharmony_ci}; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_cistatic const struct tegra_pmc_regs tegra20_pmc_regs = { 26728c2ecf20Sopenharmony_ci .scratch0 = 0x50, 26738c2ecf20Sopenharmony_ci .dpd_req = 0x1b8, 26748c2ecf20Sopenharmony_ci .dpd_status = 0x1bc, 26758c2ecf20Sopenharmony_ci .dpd2_req = 0x1c0, 26768c2ecf20Sopenharmony_ci .dpd2_status = 0x1c4, 26778c2ecf20Sopenharmony_ci .rst_status = 0x1b4, 26788c2ecf20Sopenharmony_ci .rst_source_shift = 0x0, 26798c2ecf20Sopenharmony_ci .rst_source_mask = 0x7, 26808c2ecf20Sopenharmony_ci .rst_level_shift = 0x0, 26818c2ecf20Sopenharmony_ci .rst_level_mask = 0x0, 26828c2ecf20Sopenharmony_ci}; 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_cistatic void tegra20_pmc_init(struct tegra_pmc *pmc) 26858c2ecf20Sopenharmony_ci{ 26868c2ecf20Sopenharmony_ci u32 value, osc, pmu, off; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci /* Always enable CPU power request */ 26898c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_CNTRL); 26908c2ecf20Sopenharmony_ci value |= PMC_CNTRL_CPU_PWRREQ_OE; 26918c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_CNTRL); 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_CNTRL); 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci if (pmc->sysclkreq_high) 26968c2ecf20Sopenharmony_ci value &= ~PMC_CNTRL_SYSCLK_POLARITY; 26978c2ecf20Sopenharmony_ci else 26988c2ecf20Sopenharmony_ci value |= PMC_CNTRL_SYSCLK_POLARITY; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci if (pmc->corereq_high) 27018c2ecf20Sopenharmony_ci value &= ~PMC_CNTRL_PWRREQ_POLARITY; 27028c2ecf20Sopenharmony_ci else 27038c2ecf20Sopenharmony_ci value |= PMC_CNTRL_PWRREQ_POLARITY; 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci /* configure the output polarity while the request is tristated */ 27068c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_CNTRL); 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci /* now enable the request */ 27098c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_CNTRL); 27108c2ecf20Sopenharmony_ci value |= PMC_CNTRL_SYSCLK_OE; 27118c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_CNTRL); 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci /* program core timings which are applicable only for suspend state */ 27148c2ecf20Sopenharmony_ci if (pmc->suspend_mode != TEGRA_SUSPEND_NONE) { 27158c2ecf20Sopenharmony_ci osc = DIV_ROUND_UP(pmc->core_osc_time * 8192, 1000000); 27168c2ecf20Sopenharmony_ci pmu = DIV_ROUND_UP(pmc->core_pmu_time * 32768, 1000000); 27178c2ecf20Sopenharmony_ci off = DIV_ROUND_UP(pmc->core_off_time * 32768, 1000000); 27188c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, ((osc << 8) & 0xff00) | (pmu & 0xff), 27198c2ecf20Sopenharmony_ci PMC_COREPWRGOOD_TIMER); 27208c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, off, PMC_COREPWROFF_TIMER); 27218c2ecf20Sopenharmony_ci } 27228c2ecf20Sopenharmony_ci} 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_cistatic void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc, 27258c2ecf20Sopenharmony_ci struct device_node *np, 27268c2ecf20Sopenharmony_ci bool invert) 27278c2ecf20Sopenharmony_ci{ 27288c2ecf20Sopenharmony_ci u32 value; 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci value = tegra_pmc_readl(pmc, PMC_CNTRL); 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci if (invert) 27338c2ecf20Sopenharmony_ci value |= PMC_CNTRL_INTR_POLARITY; 27348c2ecf20Sopenharmony_ci else 27358c2ecf20Sopenharmony_ci value &= ~PMC_CNTRL_INTR_POLARITY; 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci tegra_pmc_writel(pmc, value, PMC_CNTRL); 27388c2ecf20Sopenharmony_ci} 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_cistatic const struct tegra_pmc_soc tegra20_pmc_soc = { 27418c2ecf20Sopenharmony_ci .num_powergates = ARRAY_SIZE(tegra20_powergates), 27428c2ecf20Sopenharmony_ci .powergates = tegra20_powergates, 27438c2ecf20Sopenharmony_ci .num_cpu_powergates = 0, 27448c2ecf20Sopenharmony_ci .cpu_powergates = NULL, 27458c2ecf20Sopenharmony_ci .has_tsense_reset = false, 27468c2ecf20Sopenharmony_ci .has_gpu_clamps = false, 27478c2ecf20Sopenharmony_ci .needs_mbist_war = false, 27488c2ecf20Sopenharmony_ci .has_impl_33v_pwr = false, 27498c2ecf20Sopenharmony_ci .maybe_tz_only = false, 27508c2ecf20Sopenharmony_ci .num_io_pads = 0, 27518c2ecf20Sopenharmony_ci .io_pads = NULL, 27528c2ecf20Sopenharmony_ci .num_pin_descs = 0, 27538c2ecf20Sopenharmony_ci .pin_descs = NULL, 27548c2ecf20Sopenharmony_ci .regs = &tegra20_pmc_regs, 27558c2ecf20Sopenharmony_ci .init = tegra20_pmc_init, 27568c2ecf20Sopenharmony_ci .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 27578c2ecf20Sopenharmony_ci .powergate_set = tegra20_powergate_set, 27588c2ecf20Sopenharmony_ci .reset_sources = NULL, 27598c2ecf20Sopenharmony_ci .num_reset_sources = 0, 27608c2ecf20Sopenharmony_ci .reset_levels = NULL, 27618c2ecf20Sopenharmony_ci .num_reset_levels = 0, 27628c2ecf20Sopenharmony_ci .pmc_clks_data = NULL, 27638c2ecf20Sopenharmony_ci .num_pmc_clks = 0, 27648c2ecf20Sopenharmony_ci .has_blink_output = true, 27658c2ecf20Sopenharmony_ci}; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_cistatic const char * const tegra30_powergates[] = { 27688c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU] = "cpu0", 27698c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_3D] = "3d0", 27708c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VENC] = "venc", 27718c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VDEC] = "vdec", 27728c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_PCIE] = "pcie", 27738c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_L2] = "l2", 27748c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_MPE] = "mpe", 27758c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_HEG] = "heg", 27768c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_SATA] = "sata", 27778c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU1] = "cpu1", 27788c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU2] = "cpu2", 27798c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU3] = "cpu3", 27808c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CELP] = "celp", 27818c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_3D1] = "3d1", 27828c2ecf20Sopenharmony_ci}; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_cistatic const u8 tegra30_cpu_powergates[] = { 27858c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU, 27868c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU1, 27878c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU2, 27888c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU3, 27898c2ecf20Sopenharmony_ci}; 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_cistatic const char * const tegra30_reset_sources[] = { 27928c2ecf20Sopenharmony_ci "POWER_ON_RESET", 27938c2ecf20Sopenharmony_ci "WATCHDOG", 27948c2ecf20Sopenharmony_ci "SENSOR", 27958c2ecf20Sopenharmony_ci "SW_MAIN", 27968c2ecf20Sopenharmony_ci "LP0" 27978c2ecf20Sopenharmony_ci}; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_cistatic const struct tegra_pmc_soc tegra30_pmc_soc = { 28008c2ecf20Sopenharmony_ci .num_powergates = ARRAY_SIZE(tegra30_powergates), 28018c2ecf20Sopenharmony_ci .powergates = tegra30_powergates, 28028c2ecf20Sopenharmony_ci .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), 28038c2ecf20Sopenharmony_ci .cpu_powergates = tegra30_cpu_powergates, 28048c2ecf20Sopenharmony_ci .has_tsense_reset = true, 28058c2ecf20Sopenharmony_ci .has_gpu_clamps = false, 28068c2ecf20Sopenharmony_ci .needs_mbist_war = false, 28078c2ecf20Sopenharmony_ci .has_impl_33v_pwr = false, 28088c2ecf20Sopenharmony_ci .maybe_tz_only = false, 28098c2ecf20Sopenharmony_ci .num_io_pads = 0, 28108c2ecf20Sopenharmony_ci .io_pads = NULL, 28118c2ecf20Sopenharmony_ci .num_pin_descs = 0, 28128c2ecf20Sopenharmony_ci .pin_descs = NULL, 28138c2ecf20Sopenharmony_ci .regs = &tegra20_pmc_regs, 28148c2ecf20Sopenharmony_ci .init = tegra20_pmc_init, 28158c2ecf20Sopenharmony_ci .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 28168c2ecf20Sopenharmony_ci .powergate_set = tegra20_powergate_set, 28178c2ecf20Sopenharmony_ci .reset_sources = tegra30_reset_sources, 28188c2ecf20Sopenharmony_ci .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), 28198c2ecf20Sopenharmony_ci .reset_levels = NULL, 28208c2ecf20Sopenharmony_ci .num_reset_levels = 0, 28218c2ecf20Sopenharmony_ci .pmc_clks_data = tegra_pmc_clks_data, 28228c2ecf20Sopenharmony_ci .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), 28238c2ecf20Sopenharmony_ci .has_blink_output = true, 28248c2ecf20Sopenharmony_ci}; 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_cistatic const char * const tegra114_powergates[] = { 28278c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU] = "crail", 28288c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_3D] = "3d", 28298c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VENC] = "venc", 28308c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VDEC] = "vdec", 28318c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_MPE] = "mpe", 28328c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_HEG] = "heg", 28338c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU1] = "cpu1", 28348c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU2] = "cpu2", 28358c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU3] = "cpu3", 28368c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CELP] = "celp", 28378c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU0] = "cpu0", 28388c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_C0NC] = "c0nc", 28398c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_C1NC] = "c1nc", 28408c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_DIS] = "dis", 28418c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_DISB] = "disb", 28428c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBA] = "xusba", 28438c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBB] = "xusbb", 28448c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBC] = "xusbc", 28458c2ecf20Sopenharmony_ci}; 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_cistatic const u8 tegra114_cpu_powergates[] = { 28488c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU0, 28498c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU1, 28508c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU2, 28518c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU3, 28528c2ecf20Sopenharmony_ci}; 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_cistatic const struct tegra_pmc_soc tegra114_pmc_soc = { 28558c2ecf20Sopenharmony_ci .num_powergates = ARRAY_SIZE(tegra114_powergates), 28568c2ecf20Sopenharmony_ci .powergates = tegra114_powergates, 28578c2ecf20Sopenharmony_ci .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), 28588c2ecf20Sopenharmony_ci .cpu_powergates = tegra114_cpu_powergates, 28598c2ecf20Sopenharmony_ci .has_tsense_reset = true, 28608c2ecf20Sopenharmony_ci .has_gpu_clamps = false, 28618c2ecf20Sopenharmony_ci .needs_mbist_war = false, 28628c2ecf20Sopenharmony_ci .has_impl_33v_pwr = false, 28638c2ecf20Sopenharmony_ci .maybe_tz_only = false, 28648c2ecf20Sopenharmony_ci .num_io_pads = 0, 28658c2ecf20Sopenharmony_ci .io_pads = NULL, 28668c2ecf20Sopenharmony_ci .num_pin_descs = 0, 28678c2ecf20Sopenharmony_ci .pin_descs = NULL, 28688c2ecf20Sopenharmony_ci .regs = &tegra20_pmc_regs, 28698c2ecf20Sopenharmony_ci .init = tegra20_pmc_init, 28708c2ecf20Sopenharmony_ci .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 28718c2ecf20Sopenharmony_ci .powergate_set = tegra114_powergate_set, 28728c2ecf20Sopenharmony_ci .reset_sources = tegra30_reset_sources, 28738c2ecf20Sopenharmony_ci .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), 28748c2ecf20Sopenharmony_ci .reset_levels = NULL, 28758c2ecf20Sopenharmony_ci .num_reset_levels = 0, 28768c2ecf20Sopenharmony_ci .pmc_clks_data = tegra_pmc_clks_data, 28778c2ecf20Sopenharmony_ci .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), 28788c2ecf20Sopenharmony_ci .has_blink_output = true, 28798c2ecf20Sopenharmony_ci}; 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_cistatic const char * const tegra124_powergates[] = { 28828c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU] = "crail", 28838c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_3D] = "3d", 28848c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VENC] = "venc", 28858c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_PCIE] = "pcie", 28868c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VDEC] = "vdec", 28878c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_MPE] = "mpe", 28888c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_HEG] = "heg", 28898c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_SATA] = "sata", 28908c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU1] = "cpu1", 28918c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU2] = "cpu2", 28928c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU3] = "cpu3", 28938c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CELP] = "celp", 28948c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU0] = "cpu0", 28958c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_C0NC] = "c0nc", 28968c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_C1NC] = "c1nc", 28978c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_SOR] = "sor", 28988c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_DIS] = "dis", 28998c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_DISB] = "disb", 29008c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBA] = "xusba", 29018c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBB] = "xusbb", 29028c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBC] = "xusbc", 29038c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VIC] = "vic", 29048c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_IRAM] = "iram", 29058c2ecf20Sopenharmony_ci}; 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_cistatic const u8 tegra124_cpu_powergates[] = { 29088c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU0, 29098c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU1, 29108c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU2, 29118c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU3, 29128c2ecf20Sopenharmony_ci}; 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci#define TEGRA_IO_PAD(_id, _dpd, _voltage, _name) \ 29158c2ecf20Sopenharmony_ci ((struct tegra_io_pad_soc) { \ 29168c2ecf20Sopenharmony_ci .id = (_id), \ 29178c2ecf20Sopenharmony_ci .dpd = (_dpd), \ 29188c2ecf20Sopenharmony_ci .voltage = (_voltage), \ 29198c2ecf20Sopenharmony_ci .name = (_name), \ 29208c2ecf20Sopenharmony_ci }) 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci#define TEGRA_IO_PIN_DESC(_id, _dpd, _voltage, _name) \ 29238c2ecf20Sopenharmony_ci ((struct pinctrl_pin_desc) { \ 29248c2ecf20Sopenharmony_ci .number = (_id), \ 29258c2ecf20Sopenharmony_ci .name = (_name) \ 29268c2ecf20Sopenharmony_ci }) 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci#define TEGRA124_IO_PAD_TABLE(_pad) \ 29298c2ecf20Sopenharmony_ci /* .id .dpd .voltage .name */ \ 29308c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ 29318c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_BB, 15, UINT_MAX, "bb"), \ 29328c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CAM, 36, UINT_MAX, "cam"), \ 29338c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_COMP, 22, UINT_MAX, "comp"), \ 29348c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ 29358c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csb"), \ 29368c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "cse"), \ 29378c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ 29388c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ 29398c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ 29408c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ 29418c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ 29428c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ 29438c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HV, 38, UINT_MAX, "hv"), \ 29448c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ 29458c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ 29468c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_NAND, 13, UINT_MAX, "nand"), \ 29478c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ 29488c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ 29498c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ 29508c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ 29518c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC1, 33, UINT_MAX, "sdmmc1"), \ 29528c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC3, 34, UINT_MAX, "sdmmc3"), \ 29538c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC4, 35, UINT_MAX, "sdmmc4"), \ 29548c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SYS_DDC, 58, UINT_MAX, "sys_ddc"), \ 29558c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ 29568c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ 29578c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ 29588c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ 29598c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb_bias") 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_cistatic const struct tegra_io_pad_soc tegra124_io_pads[] = { 29628c2ecf20Sopenharmony_ci TEGRA124_IO_PAD_TABLE(TEGRA_IO_PAD) 29638c2ecf20Sopenharmony_ci}; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_cistatic const struct pinctrl_pin_desc tegra124_pin_descs[] = { 29668c2ecf20Sopenharmony_ci TEGRA124_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) 29678c2ecf20Sopenharmony_ci}; 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_cistatic const struct tegra_pmc_soc tegra124_pmc_soc = { 29708c2ecf20Sopenharmony_ci .num_powergates = ARRAY_SIZE(tegra124_powergates), 29718c2ecf20Sopenharmony_ci .powergates = tegra124_powergates, 29728c2ecf20Sopenharmony_ci .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), 29738c2ecf20Sopenharmony_ci .cpu_powergates = tegra124_cpu_powergates, 29748c2ecf20Sopenharmony_ci .has_tsense_reset = true, 29758c2ecf20Sopenharmony_ci .has_gpu_clamps = true, 29768c2ecf20Sopenharmony_ci .needs_mbist_war = false, 29778c2ecf20Sopenharmony_ci .has_impl_33v_pwr = false, 29788c2ecf20Sopenharmony_ci .maybe_tz_only = false, 29798c2ecf20Sopenharmony_ci .num_io_pads = ARRAY_SIZE(tegra124_io_pads), 29808c2ecf20Sopenharmony_ci .io_pads = tegra124_io_pads, 29818c2ecf20Sopenharmony_ci .num_pin_descs = ARRAY_SIZE(tegra124_pin_descs), 29828c2ecf20Sopenharmony_ci .pin_descs = tegra124_pin_descs, 29838c2ecf20Sopenharmony_ci .regs = &tegra20_pmc_regs, 29848c2ecf20Sopenharmony_ci .init = tegra20_pmc_init, 29858c2ecf20Sopenharmony_ci .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 29868c2ecf20Sopenharmony_ci .powergate_set = tegra114_powergate_set, 29878c2ecf20Sopenharmony_ci .reset_sources = tegra30_reset_sources, 29888c2ecf20Sopenharmony_ci .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), 29898c2ecf20Sopenharmony_ci .reset_levels = NULL, 29908c2ecf20Sopenharmony_ci .num_reset_levels = 0, 29918c2ecf20Sopenharmony_ci .pmc_clks_data = tegra_pmc_clks_data, 29928c2ecf20Sopenharmony_ci .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), 29938c2ecf20Sopenharmony_ci .has_blink_output = true, 29948c2ecf20Sopenharmony_ci}; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_cistatic const char * const tegra210_powergates[] = { 29978c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU] = "crail", 29988c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_3D] = "3d", 29998c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VENC] = "venc", 30008c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_PCIE] = "pcie", 30018c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_MPE] = "mpe", 30028c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_SATA] = "sata", 30038c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU1] = "cpu1", 30048c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU2] = "cpu2", 30058c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU3] = "cpu3", 30068c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_CPU0] = "cpu0", 30078c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_C0NC] = "c0nc", 30088c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_SOR] = "sor", 30098c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_DIS] = "dis", 30108c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_DISB] = "disb", 30118c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBA] = "xusba", 30128c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBB] = "xusbb", 30138c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_XUSBC] = "xusbc", 30148c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VIC] = "vic", 30158c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_IRAM] = "iram", 30168c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_NVDEC] = "nvdec", 30178c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_NVJPG] = "nvjpg", 30188c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_AUD] = "aud", 30198c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_DFD] = "dfd", 30208c2ecf20Sopenharmony_ci [TEGRA_POWERGATE_VE2] = "ve2", 30218c2ecf20Sopenharmony_ci}; 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_cistatic const u8 tegra210_cpu_powergates[] = { 30248c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU0, 30258c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU1, 30268c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU2, 30278c2ecf20Sopenharmony_ci TEGRA_POWERGATE_CPU3, 30288c2ecf20Sopenharmony_ci}; 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci#define TEGRA210_IO_PAD_TABLE(_pad) \ 30318c2ecf20Sopenharmony_ci /* .id .dpd .voltage .name */ \ 30328c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AUDIO, 17, 5, "audio"), \ 30338c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 18, "audio-hv"), \ 30348c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CAM, 36, 10, "cam"), \ 30358c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ 30368c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ 30378c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIC, 42, UINT_MAX, "csic"), \ 30388c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSID, 43, UINT_MAX, "csid"), \ 30398c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "csie"), \ 30408c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIF, 45, UINT_MAX, "csif"), \ 30418c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DBG, 25, 19, "dbg"), \ 30428c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DEBUG_NONAO, 26, UINT_MAX, "debug-nonao"), \ 30438c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DMIC, 50, 20, "dmic"), \ 30448c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DP, 51, UINT_MAX, "dp"), \ 30458c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ 30468c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ 30478c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ 30488c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ 30498c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_EMMC, 35, UINT_MAX, "emmc"), \ 30508c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_EMMC2, 37, UINT_MAX, "emmc2"), \ 30518c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_GPIO, 27, 21, "gpio"), \ 30528c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ 30538c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ 30548c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ 30558c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ 30568c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ 30578c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ 30588c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ 30598c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, 11, "pex-cntrl"), \ 30608c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC1, 33, 12, "sdmmc1"), \ 30618c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC3, 34, 13, "sdmmc3"), \ 30628c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SPI, 46, 22, "spi"), \ 30638c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SPI_HV, 47, 23, "spi-hv"), \ 30648c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_UART, 14, 2, "uart"), \ 30658c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ 30668c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ 30678c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ 30688c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB3, 18, UINT_MAX, "usb3"), \ 30698c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias") 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_cistatic const struct tegra_io_pad_soc tegra210_io_pads[] = { 30728c2ecf20Sopenharmony_ci TEGRA210_IO_PAD_TABLE(TEGRA_IO_PAD) 30738c2ecf20Sopenharmony_ci}; 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_cistatic const struct pinctrl_pin_desc tegra210_pin_descs[] = { 30768c2ecf20Sopenharmony_ci TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) 30778c2ecf20Sopenharmony_ci}; 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_cistatic const char * const tegra210_reset_sources[] = { 30808c2ecf20Sopenharmony_ci "POWER_ON_RESET", 30818c2ecf20Sopenharmony_ci "WATCHDOG", 30828c2ecf20Sopenharmony_ci "SENSOR", 30838c2ecf20Sopenharmony_ci "SW_MAIN", 30848c2ecf20Sopenharmony_ci "LP0", 30858c2ecf20Sopenharmony_ci "AOTAG" 30868c2ecf20Sopenharmony_ci}; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_cistatic const struct tegra_wake_event tegra210_wake_events[] = { 30898c2ecf20Sopenharmony_ci TEGRA_WAKE_IRQ("rtc", 16, 2), 30908c2ecf20Sopenharmony_ci TEGRA_WAKE_IRQ("pmu", 51, 86), 30918c2ecf20Sopenharmony_ci}; 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_cistatic const struct tegra_pmc_soc tegra210_pmc_soc = { 30948c2ecf20Sopenharmony_ci .num_powergates = ARRAY_SIZE(tegra210_powergates), 30958c2ecf20Sopenharmony_ci .powergates = tegra210_powergates, 30968c2ecf20Sopenharmony_ci .num_cpu_powergates = ARRAY_SIZE(tegra210_cpu_powergates), 30978c2ecf20Sopenharmony_ci .cpu_powergates = tegra210_cpu_powergates, 30988c2ecf20Sopenharmony_ci .has_tsense_reset = true, 30998c2ecf20Sopenharmony_ci .has_gpu_clamps = true, 31008c2ecf20Sopenharmony_ci .needs_mbist_war = true, 31018c2ecf20Sopenharmony_ci .has_impl_33v_pwr = false, 31028c2ecf20Sopenharmony_ci .maybe_tz_only = true, 31038c2ecf20Sopenharmony_ci .num_io_pads = ARRAY_SIZE(tegra210_io_pads), 31048c2ecf20Sopenharmony_ci .io_pads = tegra210_io_pads, 31058c2ecf20Sopenharmony_ci .num_pin_descs = ARRAY_SIZE(tegra210_pin_descs), 31068c2ecf20Sopenharmony_ci .pin_descs = tegra210_pin_descs, 31078c2ecf20Sopenharmony_ci .regs = &tegra20_pmc_regs, 31088c2ecf20Sopenharmony_ci .init = tegra20_pmc_init, 31098c2ecf20Sopenharmony_ci .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 31108c2ecf20Sopenharmony_ci .powergate_set = tegra114_powergate_set, 31118c2ecf20Sopenharmony_ci .irq_set_wake = tegra210_pmc_irq_set_wake, 31128c2ecf20Sopenharmony_ci .irq_set_type = tegra210_pmc_irq_set_type, 31138c2ecf20Sopenharmony_ci .reset_sources = tegra210_reset_sources, 31148c2ecf20Sopenharmony_ci .num_reset_sources = ARRAY_SIZE(tegra210_reset_sources), 31158c2ecf20Sopenharmony_ci .reset_levels = NULL, 31168c2ecf20Sopenharmony_ci .num_reset_levels = 0, 31178c2ecf20Sopenharmony_ci .num_wake_events = ARRAY_SIZE(tegra210_wake_events), 31188c2ecf20Sopenharmony_ci .wake_events = tegra210_wake_events, 31198c2ecf20Sopenharmony_ci .pmc_clks_data = tegra_pmc_clks_data, 31208c2ecf20Sopenharmony_ci .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), 31218c2ecf20Sopenharmony_ci .has_blink_output = true, 31228c2ecf20Sopenharmony_ci}; 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci#define TEGRA186_IO_PAD_TABLE(_pad) \ 31258c2ecf20Sopenharmony_ci /* .id .dpd .voltage .name */ \ 31268c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ 31278c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ 31288c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ 31298c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ 31308c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \ 31318c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \ 31328c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ 31338c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \ 31348c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ 31358c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ 31368c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ 31378c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias"), \ 31388c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ 31398c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ 31408c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ 31418c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \ 31428c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \ 31438c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \ 31448c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ 31458c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC2_HV, 34, 5, "sdmmc2-hv"), \ 31468c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \ 31478c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \ 31488c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSIB, 40, UINT_MAX, "dsib"), \ 31498c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSIC, 41, UINT_MAX, "dsic"), \ 31508c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DSID, 42, UINT_MAX, "dsid"), \ 31518c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \ 31528c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \ 31538c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \ 31548c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \ 31558c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \ 31568c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \ 31578c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DMIC_HV, 52, 2, "dmic-hv"), \ 31588c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \ 31598c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \ 31608c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \ 31618c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \ 31628c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \ 31638c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv") 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_cistatic const struct tegra_io_pad_soc tegra186_io_pads[] = { 31668c2ecf20Sopenharmony_ci TEGRA186_IO_PAD_TABLE(TEGRA_IO_PAD) 31678c2ecf20Sopenharmony_ci}; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_cistatic const struct pinctrl_pin_desc tegra186_pin_descs[] = { 31708c2ecf20Sopenharmony_ci TEGRA186_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) 31718c2ecf20Sopenharmony_ci}; 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_cistatic const struct tegra_pmc_regs tegra186_pmc_regs = { 31748c2ecf20Sopenharmony_ci .scratch0 = 0x2000, 31758c2ecf20Sopenharmony_ci .dpd_req = 0x74, 31768c2ecf20Sopenharmony_ci .dpd_status = 0x78, 31778c2ecf20Sopenharmony_ci .dpd2_req = 0x7c, 31788c2ecf20Sopenharmony_ci .dpd2_status = 0x80, 31798c2ecf20Sopenharmony_ci .rst_status = 0x70, 31808c2ecf20Sopenharmony_ci .rst_source_shift = 0x2, 31818c2ecf20Sopenharmony_ci .rst_source_mask = 0x3c, 31828c2ecf20Sopenharmony_ci .rst_level_shift = 0x0, 31838c2ecf20Sopenharmony_ci .rst_level_mask = 0x3, 31848c2ecf20Sopenharmony_ci}; 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_cistatic void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, 31878c2ecf20Sopenharmony_ci struct device_node *np, 31888c2ecf20Sopenharmony_ci bool invert) 31898c2ecf20Sopenharmony_ci{ 31908c2ecf20Sopenharmony_ci struct resource regs; 31918c2ecf20Sopenharmony_ci void __iomem *wake; 31928c2ecf20Sopenharmony_ci u32 value; 31938c2ecf20Sopenharmony_ci int index; 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci index = of_property_match_string(np, "reg-names", "wake"); 31968c2ecf20Sopenharmony_ci if (index < 0) { 31978c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to find PMC wake registers\n"); 31988c2ecf20Sopenharmony_ci return; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci of_address_to_resource(np, index, ®s); 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci wake = ioremap(regs.start, resource_size(®s)); 32048c2ecf20Sopenharmony_ci if (!wake) { 32058c2ecf20Sopenharmony_ci dev_err(pmc->dev, "failed to map PMC wake registers\n"); 32068c2ecf20Sopenharmony_ci return; 32078c2ecf20Sopenharmony_ci } 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci value = readl(wake + WAKE_AOWAKE_CTRL); 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci if (invert) 32128c2ecf20Sopenharmony_ci value |= WAKE_AOWAKE_CTRL_INTR_POLARITY; 32138c2ecf20Sopenharmony_ci else 32148c2ecf20Sopenharmony_ci value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci writel(value, wake + WAKE_AOWAKE_CTRL); 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci iounmap(wake); 32198c2ecf20Sopenharmony_ci} 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_cistatic const char * const tegra186_reset_sources[] = { 32228c2ecf20Sopenharmony_ci "SYS_RESET", 32238c2ecf20Sopenharmony_ci "AOWDT", 32248c2ecf20Sopenharmony_ci "MCCPLEXWDT", 32258c2ecf20Sopenharmony_ci "BPMPWDT", 32268c2ecf20Sopenharmony_ci "SCEWDT", 32278c2ecf20Sopenharmony_ci "SPEWDT", 32288c2ecf20Sopenharmony_ci "APEWDT", 32298c2ecf20Sopenharmony_ci "BCCPLEXWDT", 32308c2ecf20Sopenharmony_ci "SENSOR", 32318c2ecf20Sopenharmony_ci "AOTAG", 32328c2ecf20Sopenharmony_ci "VFSENSOR", 32338c2ecf20Sopenharmony_ci "SWREST", 32348c2ecf20Sopenharmony_ci "SC7", 32358c2ecf20Sopenharmony_ci "HSM", 32368c2ecf20Sopenharmony_ci "CORESIGHT" 32378c2ecf20Sopenharmony_ci}; 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_cistatic const char * const tegra186_reset_levels[] = { 32408c2ecf20Sopenharmony_ci "L0", "L1", "L2", "WARM" 32418c2ecf20Sopenharmony_ci}; 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_cistatic const struct tegra_wake_event tegra186_wake_events[] = { 32448c2ecf20Sopenharmony_ci TEGRA_WAKE_IRQ("pmu", 24, 209), 32458c2ecf20Sopenharmony_ci TEGRA_WAKE_GPIO("power", 29, 1, TEGRA186_AON_GPIO(FF, 0)), 32468c2ecf20Sopenharmony_ci TEGRA_WAKE_IRQ("rtc", 73, 10), 32478c2ecf20Sopenharmony_ci}; 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_cistatic const struct tegra_pmc_soc tegra186_pmc_soc = { 32508c2ecf20Sopenharmony_ci .num_powergates = 0, 32518c2ecf20Sopenharmony_ci .powergates = NULL, 32528c2ecf20Sopenharmony_ci .num_cpu_powergates = 0, 32538c2ecf20Sopenharmony_ci .cpu_powergates = NULL, 32548c2ecf20Sopenharmony_ci .has_tsense_reset = false, 32558c2ecf20Sopenharmony_ci .has_gpu_clamps = false, 32568c2ecf20Sopenharmony_ci .needs_mbist_war = false, 32578c2ecf20Sopenharmony_ci .has_impl_33v_pwr = true, 32588c2ecf20Sopenharmony_ci .maybe_tz_only = false, 32598c2ecf20Sopenharmony_ci .num_io_pads = ARRAY_SIZE(tegra186_io_pads), 32608c2ecf20Sopenharmony_ci .io_pads = tegra186_io_pads, 32618c2ecf20Sopenharmony_ci .num_pin_descs = ARRAY_SIZE(tegra186_pin_descs), 32628c2ecf20Sopenharmony_ci .pin_descs = tegra186_pin_descs, 32638c2ecf20Sopenharmony_ci .regs = &tegra186_pmc_regs, 32648c2ecf20Sopenharmony_ci .init = NULL, 32658c2ecf20Sopenharmony_ci .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, 32668c2ecf20Sopenharmony_ci .irq_set_wake = tegra186_pmc_irq_set_wake, 32678c2ecf20Sopenharmony_ci .irq_set_type = tegra186_pmc_irq_set_type, 32688c2ecf20Sopenharmony_ci .reset_sources = tegra186_reset_sources, 32698c2ecf20Sopenharmony_ci .num_reset_sources = ARRAY_SIZE(tegra186_reset_sources), 32708c2ecf20Sopenharmony_ci .reset_levels = tegra186_reset_levels, 32718c2ecf20Sopenharmony_ci .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), 32728c2ecf20Sopenharmony_ci .num_wake_events = ARRAY_SIZE(tegra186_wake_events), 32738c2ecf20Sopenharmony_ci .wake_events = tegra186_wake_events, 32748c2ecf20Sopenharmony_ci .pmc_clks_data = NULL, 32758c2ecf20Sopenharmony_ci .num_pmc_clks = 0, 32768c2ecf20Sopenharmony_ci .has_blink_output = false, 32778c2ecf20Sopenharmony_ci}; 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci#define TEGRA194_IO_PAD_TABLE(_pad) \ 32808c2ecf20Sopenharmony_ci /* .id .dpd .voltage .name */ \ 32818c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ 32828c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ 32838c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ 32848c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \ 32858c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \ 32868c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ 32878c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \ 32888c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_EQOS, 8, UINT_MAX, "eqos"), \ 32898c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, UINT_MAX, "pex-clk-2-bias"), \ 32908c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CLK_2, 10, UINT_MAX, "pex-clk-2"), \ 32918c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DAP3, 11, UINT_MAX, "dap3"), \ 32928c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DAP5, 12, UINT_MAX, "dap5"), \ 32938c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ 32948c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PWR_CTL, 15, UINT_MAX, "pwr-ctl"), \ 32958c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SOC_GPIO53, 16, UINT_MAX, "soc-gpio53"), \ 32968c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ 32978c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_GP_PWM2, 18, UINT_MAX, "gp-pwm2"), \ 32988c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_GP_PWM3, 19, UINT_MAX, "gp-pwm3"), \ 32998c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SOC_GPIO12, 20, UINT_MAX, "soc-gpio12"), \ 33008c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SOC_GPIO13, 21, UINT_MAX, "soc-gpio13"), \ 33018c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SOC_GPIO10, 22, UINT_MAX, "soc-gpio10"), \ 33028c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_UART4, 23, UINT_MAX, "uart4"), \ 33038c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_UART5, 24, UINT_MAX, "uart5"), \ 33048c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \ 33058c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HDMI_DP3, 26, UINT_MAX, "hdmi-dp3"), \ 33068c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HDMI_DP2, 27, UINT_MAX, "hdmi-dp2"), \ 33078c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \ 33088c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \ 33098c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ 33108c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_CTL2, 33, UINT_MAX, "pex-ctl2"), \ 33118c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_L0_RST_N, 34, UINT_MAX, "pex-l0-rst"), \ 33128c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_L1_RST_N, 35, UINT_MAX, "pex-l1-rst"), \ 33138c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \ 33148c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_PEX_L5_RST_N, 37, UINT_MAX, "pex-l5-rst"), \ 33158c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \ 33168c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \ 33178c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \ 33188c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \ 33198c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \ 33208c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \ 33218c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \ 33228c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIG, 50, UINT_MAX, "csig"), \ 33238c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CSIH, 51, UINT_MAX, "csih"), \ 33248c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \ 33258c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \ 33268c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \ 33278c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \ 33288c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \ 33298c2ecf20Sopenharmony_ci _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv") 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_cistatic const struct tegra_io_pad_soc tegra194_io_pads[] = { 33328c2ecf20Sopenharmony_ci TEGRA194_IO_PAD_TABLE(TEGRA_IO_PAD) 33338c2ecf20Sopenharmony_ci}; 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_cistatic const struct pinctrl_pin_desc tegra194_pin_descs[] = { 33368c2ecf20Sopenharmony_ci TEGRA194_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) 33378c2ecf20Sopenharmony_ci}; 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_cistatic const struct tegra_pmc_regs tegra194_pmc_regs = { 33408c2ecf20Sopenharmony_ci .scratch0 = 0x2000, 33418c2ecf20Sopenharmony_ci .dpd_req = 0x74, 33428c2ecf20Sopenharmony_ci .dpd_status = 0x78, 33438c2ecf20Sopenharmony_ci .dpd2_req = 0x7c, 33448c2ecf20Sopenharmony_ci .dpd2_status = 0x80, 33458c2ecf20Sopenharmony_ci .rst_status = 0x70, 33468c2ecf20Sopenharmony_ci .rst_source_shift = 0x2, 33478c2ecf20Sopenharmony_ci .rst_source_mask = 0x7c, 33488c2ecf20Sopenharmony_ci .rst_level_shift = 0x0, 33498c2ecf20Sopenharmony_ci .rst_level_mask = 0x3, 33508c2ecf20Sopenharmony_ci}; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_cistatic const char * const tegra194_reset_sources[] = { 33538c2ecf20Sopenharmony_ci "SYS_RESET_N", 33548c2ecf20Sopenharmony_ci "AOWDT", 33558c2ecf20Sopenharmony_ci "BCCPLEXWDT", 33568c2ecf20Sopenharmony_ci "BPMPWDT", 33578c2ecf20Sopenharmony_ci "SCEWDT", 33588c2ecf20Sopenharmony_ci "SPEWDT", 33598c2ecf20Sopenharmony_ci "APEWDT", 33608c2ecf20Sopenharmony_ci "LCCPLEXWDT", 33618c2ecf20Sopenharmony_ci "SENSOR", 33628c2ecf20Sopenharmony_ci "AOTAG", 33638c2ecf20Sopenharmony_ci "VFSENSOR", 33648c2ecf20Sopenharmony_ci "MAINSWRST", 33658c2ecf20Sopenharmony_ci "SC7", 33668c2ecf20Sopenharmony_ci "HSM", 33678c2ecf20Sopenharmony_ci "CSITE", 33688c2ecf20Sopenharmony_ci "RCEWDT", 33698c2ecf20Sopenharmony_ci "PVA0WDT", 33708c2ecf20Sopenharmony_ci "PVA1WDT", 33718c2ecf20Sopenharmony_ci "L1A_ASYNC", 33728c2ecf20Sopenharmony_ci "BPMPBOOT", 33738c2ecf20Sopenharmony_ci "FUSECRC", 33748c2ecf20Sopenharmony_ci}; 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_cistatic const struct tegra_wake_event tegra194_wake_events[] = { 33778c2ecf20Sopenharmony_ci TEGRA_WAKE_IRQ("pmu", 24, 209), 33788c2ecf20Sopenharmony_ci TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)), 33798c2ecf20Sopenharmony_ci TEGRA_WAKE_IRQ("rtc", 73, 10), 33808c2ecf20Sopenharmony_ci}; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_cistatic const struct tegra_pmc_soc tegra194_pmc_soc = { 33838c2ecf20Sopenharmony_ci .num_powergates = 0, 33848c2ecf20Sopenharmony_ci .powergates = NULL, 33858c2ecf20Sopenharmony_ci .num_cpu_powergates = 0, 33868c2ecf20Sopenharmony_ci .cpu_powergates = NULL, 33878c2ecf20Sopenharmony_ci .has_tsense_reset = false, 33888c2ecf20Sopenharmony_ci .has_gpu_clamps = false, 33898c2ecf20Sopenharmony_ci .needs_mbist_war = false, 33908c2ecf20Sopenharmony_ci .has_impl_33v_pwr = true, 33918c2ecf20Sopenharmony_ci .maybe_tz_only = false, 33928c2ecf20Sopenharmony_ci .num_io_pads = ARRAY_SIZE(tegra194_io_pads), 33938c2ecf20Sopenharmony_ci .io_pads = tegra194_io_pads, 33948c2ecf20Sopenharmony_ci .num_pin_descs = ARRAY_SIZE(tegra194_pin_descs), 33958c2ecf20Sopenharmony_ci .pin_descs = tegra194_pin_descs, 33968c2ecf20Sopenharmony_ci .regs = &tegra194_pmc_regs, 33978c2ecf20Sopenharmony_ci .init = NULL, 33988c2ecf20Sopenharmony_ci .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, 33998c2ecf20Sopenharmony_ci .irq_set_wake = tegra186_pmc_irq_set_wake, 34008c2ecf20Sopenharmony_ci .irq_set_type = tegra186_pmc_irq_set_type, 34018c2ecf20Sopenharmony_ci .reset_sources = tegra194_reset_sources, 34028c2ecf20Sopenharmony_ci .num_reset_sources = ARRAY_SIZE(tegra194_reset_sources), 34038c2ecf20Sopenharmony_ci .reset_levels = tegra186_reset_levels, 34048c2ecf20Sopenharmony_ci .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), 34058c2ecf20Sopenharmony_ci .num_wake_events = ARRAY_SIZE(tegra194_wake_events), 34068c2ecf20Sopenharmony_ci .wake_events = tegra194_wake_events, 34078c2ecf20Sopenharmony_ci .pmc_clks_data = NULL, 34088c2ecf20Sopenharmony_ci .num_pmc_clks = 0, 34098c2ecf20Sopenharmony_ci .has_blink_output = false, 34108c2ecf20Sopenharmony_ci}; 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_cistatic const struct tegra_pmc_regs tegra234_pmc_regs = { 34138c2ecf20Sopenharmony_ci .scratch0 = 0x2000, 34148c2ecf20Sopenharmony_ci .dpd_req = 0, 34158c2ecf20Sopenharmony_ci .dpd_status = 0, 34168c2ecf20Sopenharmony_ci .dpd2_req = 0, 34178c2ecf20Sopenharmony_ci .dpd2_status = 0, 34188c2ecf20Sopenharmony_ci .rst_status = 0x70, 34198c2ecf20Sopenharmony_ci .rst_source_shift = 0x2, 34208c2ecf20Sopenharmony_ci .rst_source_mask = 0xfc, 34218c2ecf20Sopenharmony_ci .rst_level_shift = 0x0, 34228c2ecf20Sopenharmony_ci .rst_level_mask = 0x3, 34238c2ecf20Sopenharmony_ci}; 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_cistatic const char * const tegra234_reset_sources[] = { 34268c2ecf20Sopenharmony_ci "SYS_RESET_N", 34278c2ecf20Sopenharmony_ci "AOWDT", 34288c2ecf20Sopenharmony_ci "BCCPLEXWDT", 34298c2ecf20Sopenharmony_ci "BPMPWDT", 34308c2ecf20Sopenharmony_ci "SCEWDT", 34318c2ecf20Sopenharmony_ci "SPEWDT", 34328c2ecf20Sopenharmony_ci "APEWDT", 34338c2ecf20Sopenharmony_ci "LCCPLEXWDT", 34348c2ecf20Sopenharmony_ci "SENSOR", 34358c2ecf20Sopenharmony_ci "AOTAG", 34368c2ecf20Sopenharmony_ci "VFSENSOR", 34378c2ecf20Sopenharmony_ci "MAINSWRST", 34388c2ecf20Sopenharmony_ci "SC7", 34398c2ecf20Sopenharmony_ci "HSM", 34408c2ecf20Sopenharmony_ci "CSITE", 34418c2ecf20Sopenharmony_ci "RCEWDT", 34428c2ecf20Sopenharmony_ci "PVA0WDT", 34438c2ecf20Sopenharmony_ci "PVA1WDT", 34448c2ecf20Sopenharmony_ci "L1A_ASYNC", 34458c2ecf20Sopenharmony_ci "BPMPBOOT", 34468c2ecf20Sopenharmony_ci "FUSECRC", 34478c2ecf20Sopenharmony_ci}; 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_cistatic const struct tegra_pmc_soc tegra234_pmc_soc = { 34508c2ecf20Sopenharmony_ci .num_powergates = 0, 34518c2ecf20Sopenharmony_ci .powergates = NULL, 34528c2ecf20Sopenharmony_ci .num_cpu_powergates = 0, 34538c2ecf20Sopenharmony_ci .cpu_powergates = NULL, 34548c2ecf20Sopenharmony_ci .has_tsense_reset = false, 34558c2ecf20Sopenharmony_ci .has_gpu_clamps = false, 34568c2ecf20Sopenharmony_ci .needs_mbist_war = false, 34578c2ecf20Sopenharmony_ci .has_impl_33v_pwr = true, 34588c2ecf20Sopenharmony_ci .maybe_tz_only = false, 34598c2ecf20Sopenharmony_ci .num_io_pads = 0, 34608c2ecf20Sopenharmony_ci .io_pads = NULL, 34618c2ecf20Sopenharmony_ci .num_pin_descs = 0, 34628c2ecf20Sopenharmony_ci .pin_descs = NULL, 34638c2ecf20Sopenharmony_ci .regs = &tegra234_pmc_regs, 34648c2ecf20Sopenharmony_ci .init = NULL, 34658c2ecf20Sopenharmony_ci .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, 34668c2ecf20Sopenharmony_ci .irq_set_wake = tegra186_pmc_irq_set_wake, 34678c2ecf20Sopenharmony_ci .irq_set_type = tegra186_pmc_irq_set_type, 34688c2ecf20Sopenharmony_ci .reset_sources = tegra234_reset_sources, 34698c2ecf20Sopenharmony_ci .num_reset_sources = ARRAY_SIZE(tegra234_reset_sources), 34708c2ecf20Sopenharmony_ci .reset_levels = tegra186_reset_levels, 34718c2ecf20Sopenharmony_ci .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), 34728c2ecf20Sopenharmony_ci .num_wake_events = 0, 34738c2ecf20Sopenharmony_ci .wake_events = NULL, 34748c2ecf20Sopenharmony_ci .pmc_clks_data = NULL, 34758c2ecf20Sopenharmony_ci .num_pmc_clks = 0, 34768c2ecf20Sopenharmony_ci .has_blink_output = false, 34778c2ecf20Sopenharmony_ci}; 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_cistatic const struct of_device_id tegra_pmc_match[] = { 34808c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc }, 34818c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc }, 34828c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc }, 34838c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, 34848c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc }, 34858c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc }, 34868c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc }, 34878c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra30-pmc", .data = &tegra30_pmc_soc }, 34888c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra20-pmc", .data = &tegra20_pmc_soc }, 34898c2ecf20Sopenharmony_ci { } 34908c2ecf20Sopenharmony_ci}; 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_cistatic struct platform_driver tegra_pmc_driver = { 34938c2ecf20Sopenharmony_ci .driver = { 34948c2ecf20Sopenharmony_ci .name = "tegra-pmc", 34958c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 34968c2ecf20Sopenharmony_ci .of_match_table = tegra_pmc_match, 34978c2ecf20Sopenharmony_ci#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) 34988c2ecf20Sopenharmony_ci .pm = &tegra_pmc_pm_ops, 34998c2ecf20Sopenharmony_ci#endif 35008c2ecf20Sopenharmony_ci }, 35018c2ecf20Sopenharmony_ci .probe = tegra_pmc_probe, 35028c2ecf20Sopenharmony_ci}; 35038c2ecf20Sopenharmony_cibuiltin_platform_driver(tegra_pmc_driver); 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_cistatic bool __init tegra_pmc_detect_tz_only(struct tegra_pmc *pmc) 35068c2ecf20Sopenharmony_ci{ 35078c2ecf20Sopenharmony_ci u32 value, saved; 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci saved = readl(pmc->base + pmc->soc->regs->scratch0); 35108c2ecf20Sopenharmony_ci value = saved ^ 0xffffffff; 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_ci if (value == 0xffffffff) 35138c2ecf20Sopenharmony_ci value = 0xdeadbeef; 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci /* write pattern and read it back */ 35168c2ecf20Sopenharmony_ci writel(value, pmc->base + pmc->soc->regs->scratch0); 35178c2ecf20Sopenharmony_ci value = readl(pmc->base + pmc->soc->regs->scratch0); 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci /* if we read all-zeroes, access is restricted to TZ only */ 35208c2ecf20Sopenharmony_ci if (value == 0) { 35218c2ecf20Sopenharmony_ci pr_info("access to PMC is restricted to TZ\n"); 35228c2ecf20Sopenharmony_ci return true; 35238c2ecf20Sopenharmony_ci } 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci /* restore original value */ 35268c2ecf20Sopenharmony_ci writel(saved, pmc->base + pmc->soc->regs->scratch0); 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci return false; 35298c2ecf20Sopenharmony_ci} 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci/* 35328c2ecf20Sopenharmony_ci * Early initialization to allow access to registers in the very early boot 35338c2ecf20Sopenharmony_ci * process. 35348c2ecf20Sopenharmony_ci */ 35358c2ecf20Sopenharmony_cistatic int __init tegra_pmc_early_init(void) 35368c2ecf20Sopenharmony_ci{ 35378c2ecf20Sopenharmony_ci const struct of_device_id *match; 35388c2ecf20Sopenharmony_ci struct device_node *np; 35398c2ecf20Sopenharmony_ci struct resource regs; 35408c2ecf20Sopenharmony_ci unsigned int i; 35418c2ecf20Sopenharmony_ci bool invert; 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci mutex_init(&pmc->powergates_lock); 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ci np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match); 35468c2ecf20Sopenharmony_ci if (!np) { 35478c2ecf20Sopenharmony_ci /* 35488c2ecf20Sopenharmony_ci * Fall back to legacy initialization for 32-bit ARM only. All 35498c2ecf20Sopenharmony_ci * 64-bit ARM device tree files for Tegra are required to have 35508c2ecf20Sopenharmony_ci * a PMC node. 35518c2ecf20Sopenharmony_ci * 35528c2ecf20Sopenharmony_ci * This is for backwards-compatibility with old device trees 35538c2ecf20Sopenharmony_ci * that didn't contain a PMC node. Note that in this case the 35548c2ecf20Sopenharmony_ci * SoC data can't be matched and therefore powergating is 35558c2ecf20Sopenharmony_ci * disabled. 35568c2ecf20Sopenharmony_ci */ 35578c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) { 35588c2ecf20Sopenharmony_ci pr_warn("DT node not found, powergating disabled\n"); 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci regs.start = 0x7000e400; 35618c2ecf20Sopenharmony_ci regs.end = 0x7000e7ff; 35628c2ecf20Sopenharmony_ci regs.flags = IORESOURCE_MEM; 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci pr_warn("Using memory region %pR\n", ®s); 35658c2ecf20Sopenharmony_ci } else { 35668c2ecf20Sopenharmony_ci /* 35678c2ecf20Sopenharmony_ci * At this point we're not running on Tegra, so play 35688c2ecf20Sopenharmony_ci * nice with multi-platform kernels. 35698c2ecf20Sopenharmony_ci */ 35708c2ecf20Sopenharmony_ci return 0; 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci } else { 35738c2ecf20Sopenharmony_ci /* 35748c2ecf20Sopenharmony_ci * Extract information from the device tree if we've found a 35758c2ecf20Sopenharmony_ci * matching node. 35768c2ecf20Sopenharmony_ci */ 35778c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 0, ®s) < 0) { 35788c2ecf20Sopenharmony_ci pr_err("failed to get PMC registers\n"); 35798c2ecf20Sopenharmony_ci of_node_put(np); 35808c2ecf20Sopenharmony_ci return -ENXIO; 35818c2ecf20Sopenharmony_ci } 35828c2ecf20Sopenharmony_ci } 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_ci pmc->base = ioremap(regs.start, resource_size(®s)); 35858c2ecf20Sopenharmony_ci if (!pmc->base) { 35868c2ecf20Sopenharmony_ci pr_err("failed to map PMC registers\n"); 35878c2ecf20Sopenharmony_ci of_node_put(np); 35888c2ecf20Sopenharmony_ci return -ENXIO; 35898c2ecf20Sopenharmony_ci } 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci if (np) { 35928c2ecf20Sopenharmony_ci pmc->soc = match->data; 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci if (pmc->soc->maybe_tz_only) 35958c2ecf20Sopenharmony_ci pmc->tz_only = tegra_pmc_detect_tz_only(pmc); 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci /* Create a bitmap of the available and valid partitions */ 35988c2ecf20Sopenharmony_ci for (i = 0; i < pmc->soc->num_powergates; i++) 35998c2ecf20Sopenharmony_ci if (pmc->soc->powergates[i]) 36008c2ecf20Sopenharmony_ci set_bit(i, pmc->powergates_available); 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci /* 36038c2ecf20Sopenharmony_ci * Invert the interrupt polarity if a PMC device tree node 36048c2ecf20Sopenharmony_ci * exists and contains the nvidia,invert-interrupt property. 36058c2ecf20Sopenharmony_ci */ 36068c2ecf20Sopenharmony_ci invert = of_property_read_bool(np, "nvidia,invert-interrupt"); 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ci pmc->soc->setup_irq_polarity(pmc, np, invert); 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci of_node_put(np); 36118c2ecf20Sopenharmony_ci } 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_ci return 0; 36148c2ecf20Sopenharmony_ci} 36158c2ecf20Sopenharmony_ciearly_initcall(tegra_pmc_early_init); 3616