2019-05-29 17:17:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-07-11 15:19:06 +04:00
/*
* drivers / soc / tegra / pmc . c
*
* Copyright ( c ) 2010 Google , Inc
2023-03-23 16:13:24 +03:00
* Copyright ( c ) 2018 - 2023 , NVIDIA CORPORATION . All rights reserved .
2014-07-11 15:19:06 +04:00
*
* Author :
* Colin Cross < ccross @ google . com >
*/
2015-04-29 13:42:28 +03:00
# define pr_fmt(fmt) "tegra-pmc: " fmt
2019-01-25 13:22:55 +03:00
# include <linux/arm-smccc.h>
2014-07-11 15:19:06 +04:00
# include <linux/clk.h>
2020-01-14 10:24:13 +03:00
# include <linux/clk-provider.h>
# include <linux/clkdev.h>
# include <linux/clk/clk-conf.h>
2014-07-11 15:19:06 +04:00
# include <linux/clk/tegra.h>
# include <linux/debugfs.h>
# include <linux/delay.h>
2020-01-14 10:24:13 +03:00
# include <linux/device.h>
2014-07-11 15:19:06 +04:00
# include <linux/err.h>
# include <linux/export.h>
# include <linux/init.h>
2022-10-02 17:44:09 +03:00
# include <linux/interrupt.h>
2014-07-11 15:19:06 +04:00
# include <linux/io.h>
2016-02-26 18:48:40 +03:00
# include <linux/iopoll.h>
2018-09-17 16:08:17 +03:00
# include <linux/irqdomain.h>
2019-01-25 13:22:49 +03:00
# include <linux/irq.h>
# include <linux/kernel.h>
2014-07-11 15:19:06 +04:00
# include <linux/of_address.h>
2018-04-18 17:50:04 +03:00
# include <linux/of_clk.h>
2019-01-25 13:22:49 +03:00
# include <linux/of.h>
2018-09-17 16:08:17 +03:00
# include <linux/of_irq.h>
2016-03-30 12:15:15 +03:00
# include <linux/of_platform.h>
2018-08-10 21:08:12 +03:00
# include <linux/pinctrl/pinconf-generic.h>
2019-01-25 13:22:49 +03:00
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinctrl.h>
2014-07-11 15:19:06 +04:00
# include <linux/platform_device.h>
2016-03-30 12:15:15 +03:00
# include <linux/pm_domain.h>
2021-06-01 05:31:17 +03:00
# include <linux/pm_opp.h>
2022-05-10 02:32:33 +03:00
# include <linux/power_supply.h>
2014-07-11 15:19:06 +04:00
# include <linux/reboot.h>
2021-01-20 10:34:07 +03:00
# include <linux/regmap.h>
2014-07-11 15:19:06 +04:00
# include <linux/reset.h>
# include <linux/seq_file.h>
2016-03-30 12:15:15 +03:00
# include <linux/slab.h>
2014-07-11 15:19:06 +04:00
# include <linux/spinlock.h>
2022-09-30 19:14:52 +03:00
# include <linux/syscore_ops.h>
2014-07-11 15:19:06 +04:00
# include <soc/tegra/common.h>
# include <soc/tegra/fuse.h>
# include <soc/tegra/pmc.h>
2018-09-17 16:08:17 +03:00
# include <dt-bindings/interrupt-controller/arm-gic.h>
2018-08-10 21:08:11 +03:00
# include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
2018-09-19 19:41:59 +03:00
# include <dt-bindings/gpio/tegra186-gpio.h>
2018-09-19 19:42:37 +03:00
# include <dt-bindings/gpio/tegra194-gpio.h>
2022-01-25 08:57:42 +03:00
# include <dt-bindings/gpio/tegra234-gpio.h>
2020-01-14 10:24:13 +03:00
# include <dt-bindings/soc/tegra-pmc.h>
2018-08-10 21:08:11 +03:00
2014-07-11 15:19:06 +04:00
# define PMC_CNTRL 0x0
2016-06-17 16:06:12 +03:00
# define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */
2016-10-10 14:13:36 +03:00
# define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */
# define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */
# define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */
# define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */
# define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */
2019-08-16 22:42:04 +03:00
# define PMC_CNTRL_PWRREQ_POLARITY BIT(8)
2020-01-14 10:24:15 +03:00
# define PMC_CNTRL_BLINK_EN 7
2016-10-10 14:13:36 +03:00
# define PMC_CNTRL_MAIN_RST BIT(4)
2014-07-11 15:19:06 +04:00
2019-08-16 22:42:02 +03:00
# define PMC_WAKE_MASK 0x0c
# define PMC_WAKE_LEVEL 0x10
# define PMC_WAKE_STATUS 0x14
# define PMC_SW_WAKE_STATUS 0x18
2020-01-14 10:24:15 +03:00
# define PMC_DPD_PADS_ORIDE 0x1c
# define PMC_DPD_PADS_ORIDE_BLINK 20
2019-08-16 22:42:02 +03:00
2014-07-11 15:19:06 +04:00
# define DPD_SAMPLE 0x020
2016-06-17 16:06:12 +03:00
# define DPD_SAMPLE_ENABLE BIT(0)
2014-07-11 15:19:06 +04:00
# define DPD_SAMPLE_DISABLE (0 << 0)
# define PWRGATE_TOGGLE 0x30
2016-06-17 16:06:12 +03:00
# define PWRGATE_TOGGLE_START BIT(8)
2014-07-11 15:19:06 +04:00
# define REMOVE_CLAMPING 0x34
# define PWRGATE_STATUS 0x38
2020-01-14 10:24:15 +03:00
# define PMC_BLINK_TIMER 0x40
2018-08-10 21:08:07 +03:00
# define PMC_IMPL_E_33V_PWR 0x40
2016-10-10 16:14:34 +03:00
# define PMC_PWR_DET 0x48
2017-08-30 13:32:58 +03:00
# define PMC_SCRATCH0_MODE_RECOVERY BIT(31)
# define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30)
# define PMC_SCRATCH0_MODE_RCM BIT(1)
# define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \
2014-07-11 15:19:06 +04:00
PMC_SCRATCH0_MODE_BOOTLOADER | \
PMC_SCRATCH0_MODE_RCM )
# define PMC_CPUPWRGOOD_TIMER 0xc8
# define PMC_CPUPWROFF_TIMER 0xcc
2019-08-16 22:42:05 +03:00
# define PMC_COREPWRGOOD_TIMER 0x3c
# define PMC_COREPWROFF_TIMER 0xe0
2014-07-11 15:19:06 +04:00
2016-10-10 16:14:34 +03:00
# define PMC_PWR_DET_VALUE 0xe4
2021-01-20 10:34:07 +03:00
# define PMC_USB_DEBOUNCE_DEL 0xec
# define PMC_USB_AO 0xf0
2022-05-10 02:32:33 +03:00
# define PMC_SCRATCH37 0x130
2014-07-11 15:19:06 +04:00
# define PMC_SCRATCH41 0x140
2019-08-16 22:42:02 +03:00
# define PMC_WAKE2_MASK 0x160
# define PMC_WAKE2_LEVEL 0x164
# define PMC_WAKE2_STATUS 0x168
# define PMC_SW_WAKE2_STATUS 0x16c
2020-01-14 10:24:13 +03:00
# define PMC_CLK_OUT_CNTRL 0x1a8
# define PMC_CLK_OUT_MUX_MASK GENMASK(1, 0)
2015-01-06 13:52:58 +03:00
# define PMC_SENSOR_CTRL 0x1b0
2016-06-17 16:06:12 +03:00
# define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
# define PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
2015-01-06 13:52:58 +03:00
2015-12-30 19:13:29 +03:00
# define PMC_RST_STATUS_POR 0
# define PMC_RST_STATUS_WATCHDOG 1
# define PMC_RST_STATUS_SENSOR 2
# define PMC_RST_STATUS_SW_MAIN 3
# define PMC_RST_STATUS_LP0 4
# define PMC_RST_STATUS_AOTAG 5
2014-07-11 15:19:06 +04:00
# define IO_DPD_REQ 0x1b8
2016-06-17 16:06:12 +03:00
# define IO_DPD_REQ_CODE_IDLE (0U << 30)
# define IO_DPD_REQ_CODE_OFF (1U << 30)
# define IO_DPD_REQ_CODE_ON (2U << 30)
# define IO_DPD_REQ_CODE_MASK (3U << 30)
2014-07-11 15:19:06 +04:00
# define IO_DPD_STATUS 0x1bc
# define IO_DPD2_REQ 0x1c0
# define IO_DPD2_STATUS 0x1c4
# define SEL_DPD_TIM 0x1c8
2021-01-20 10:34:07 +03:00
# define PMC_UTMIP_UHSIC_TRIGGERS 0x1ec
# define PMC_UTMIP_UHSIC_SAVED_STATE 0x1f0
# define PMC_UTMIP_TERM_PAD_CFG 0x1f8
# define PMC_UTMIP_UHSIC_SLEEP_CFG 0x1fc
# define PMC_UTMIP_UHSIC_FAKE 0x218
2015-01-06 13:52:58 +03:00
# define PMC_SCRATCH54 0x258
2016-06-17 16:06:12 +03:00
# define PMC_SCRATCH54_DATA_SHIFT 8
# define PMC_SCRATCH54_ADDR_SHIFT 0
2015-01-06 13:52:58 +03:00
# define PMC_SCRATCH55 0x25c
2016-06-17 16:06:12 +03:00
# define PMC_SCRATCH55_RESET_TEGRA BIT(31)
# define PMC_SCRATCH55_CNTRL_ID_SHIFT 27
# define PMC_SCRATCH55_PINMUX_SHIFT 24
# define PMC_SCRATCH55_16BITOP BIT(15)
# define PMC_SCRATCH55_CHECKSUM_SHIFT 16
# define PMC_SCRATCH55_I2CSLV1_SHIFT 0
2015-01-06 13:52:58 +03:00
2021-01-20 10:34:07 +03:00
# define PMC_UTMIP_UHSIC_LINE_WAKEUP 0x26c
# define PMC_UTMIP_BIAS_MASTER_CNTRL 0x270
# define PMC_UTMIP_MASTER_CONFIG 0x274
# define PMC_UTMIP_UHSIC2_TRIGGERS 0x27c
# define PMC_UTMIP_MASTER2_CONFIG 0x29c
2014-07-11 15:19:06 +04:00
# define GPU_RG_CNTRL 0x2d4
2021-01-20 10:34:07 +03:00
# define PMC_UTMIP_PAD_CFG0 0x4c0
# define PMC_UTMIP_UHSIC_SLEEP_CFG1 0x4d0
# define PMC_UTMIP_SLEEPWALK_P3 0x4e0
2017-08-30 13:42:34 +03:00
/* Tegra186 and later */
2018-09-17 16:08:17 +03:00
# define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2))
# define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3)
2023-03-30 20:06:21 +03:00
# define WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN (1 << 1)
2018-09-17 16:08:17 +03:00
# define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2))
# define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2))
# define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2))
# define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2))
# define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2))
# define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2))
# define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2))
2022-09-30 19:14:52 +03:00
# define WAKE_AOWAKE_SW_STATUS_W_0 0x49c
# define WAKE_AOWAKE_SW_STATUS(x) (0x4a0 + ((x) << 2))
# define WAKE_LATCH_SW 0x498
2018-09-17 16:08:17 +03:00
2017-08-30 13:42:34 +03:00
# define WAKE_AOWAKE_CTRL 0x4f4
# define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
2023-03-30 20:06:21 +03:00
# define SW_WAKE_ID 83 /* wake83 */
2019-01-25 13:22:55 +03:00
/* for secure PMC */
# define TEGRA_SMC_PMC 0xc2fffe00
# define TEGRA_SMC_PMC_READ 0xaa
# define TEGRA_SMC_PMC_WRITE 0xbb
2020-01-14 10:24:13 +03:00
struct pmc_clk {
struct clk_hw hw ;
unsigned long offs ;
u32 mux_shift ;
u32 force_en_shift ;
} ;
# define to_pmc_clk(_hw) container_of(_hw, struct pmc_clk, hw)
2020-01-14 10:24:15 +03:00
struct pmc_clk_gate {
struct clk_hw hw ;
unsigned long offs ;
u32 shift ;
} ;
# define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
2020-01-14 10:24:13 +03:00
struct pmc_clk_init_data {
char * name ;
const char * const * parents ;
int num_parents ;
int clk_id ;
u8 mux_shift ;
u8 force_en_shift ;
} ;
static const char * const clk_out1_parents [ ] = { " osc " , " osc_div2 " ,
" osc_div4 " , " extern1 " ,
} ;
static const char * const clk_out2_parents [ ] = { " osc " , " osc_div2 " ,
" osc_div4 " , " extern2 " ,
} ;
static const char * const clk_out3_parents [ ] = { " osc " , " osc_div2 " ,
" osc_div4 " , " extern3 " ,
} ;
static const struct pmc_clk_init_data tegra_pmc_clks_data [ ] = {
{
. name = " pmc_clk_out_1 " ,
. parents = clk_out1_parents ,
. num_parents = ARRAY_SIZE ( clk_out1_parents ) ,
. clk_id = TEGRA_PMC_CLK_OUT_1 ,
. mux_shift = 6 ,
. force_en_shift = 2 ,
} ,
{
. name = " pmc_clk_out_2 " ,
. parents = clk_out2_parents ,
. num_parents = ARRAY_SIZE ( clk_out2_parents ) ,
. clk_id = TEGRA_PMC_CLK_OUT_2 ,
. mux_shift = 14 ,
. force_en_shift = 10 ,
} ,
{
. name = " pmc_clk_out_3 " ,
. parents = clk_out3_parents ,
. num_parents = ARRAY_SIZE ( clk_out3_parents ) ,
. clk_id = TEGRA_PMC_CLK_OUT_3 ,
. mux_shift = 22 ,
. force_en_shift = 18 ,
} ,
} ;
2016-03-30 12:15:15 +03:00
struct tegra_powergate {
struct generic_pm_domain genpd ;
struct tegra_pmc * pmc ;
unsigned int id ;
struct clk * * clks ;
unsigned int num_clks ;
2021-03-02 15:25:00 +03:00
unsigned long * clk_rates ;
2017-07-19 18:59:08 +03:00
struct reset_control * reset ;
2016-03-30 12:15:15 +03:00
} ;
2016-10-10 16:14:34 +03:00
struct tegra_io_pad_soc {
enum tegra_io_pad id ;
unsigned int dpd ;
2022-09-30 19:02:13 +03:00
unsigned int request ;
unsigned int status ;
2016-10-10 16:14:34 +03:00
unsigned int voltage ;
2018-08-10 21:08:10 +03:00
const char * name ;
2016-10-10 16:14:34 +03:00
} ;
2017-08-30 13:32:58 +03:00
struct tegra_pmc_regs {
unsigned int scratch0 ;
2018-10-24 10:08:00 +03:00
unsigned int rst_status ;
unsigned int rst_source_shift ;
unsigned int rst_source_mask ;
unsigned int rst_level_shift ;
unsigned int rst_level_mask ;
2017-08-30 13:32:58 +03:00
} ;
2018-09-17 16:08:17 +03:00
struct tegra_wake_event {
const char * name ;
unsigned int id ;
unsigned int irq ;
struct {
unsigned int instance ;
unsigned int pin ;
} gpio ;
2017-08-30 13:32:58 +03:00
} ;
2022-07-11 18:40:30 +03:00
# define TEGRA_WAKE_SIMPLE(_name, _id) \
{ \
. name = _name , \
. id = _id , \
. irq = 0 , \
. gpio = { \
. instance = UINT_MAX , \
. pin = UINT_MAX , \
} , \
}
2018-09-17 16:08:17 +03:00
# define TEGRA_WAKE_IRQ(_name, _id, _irq) \
{ \
. name = _name , \
. id = _id , \
. irq = _irq , \
. gpio = { \
. instance = UINT_MAX , \
. pin = UINT_MAX , \
} , \
}
# define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin) \
{ \
. name = _name , \
. id = _id , \
. irq = 0 , \
. gpio = { \
. instance = _instance , \
. pin = _pin , \
} , \
}
2014-07-11 15:19:06 +04:00
struct tegra_pmc_soc {
unsigned int num_powergates ;
const char * const * powergates ;
unsigned int num_cpu_powergates ;
const u8 * cpu_powergates ;
2015-01-09 13:15:33 +03:00
2015-01-06 13:52:58 +03:00
bool has_tsense_reset ;
2015-01-09 13:15:33 +03:00
bool has_gpu_clamps ;
2018-01-25 17:00:13 +03:00
bool needs_mbist_war ;
2018-08-10 21:08:07 +03:00
bool has_impl_33v_pwr ;
2019-01-25 13:22:55 +03:00
bool maybe_tz_only ;
2016-10-10 16:14:34 +03:00
const struct tegra_io_pad_soc * io_pads ;
unsigned int num_io_pads ;
2017-08-30 13:32:58 +03:00
2018-08-10 21:08:12 +03:00
const struct pinctrl_pin_desc * pin_descs ;
unsigned int num_pin_descs ;
2017-08-30 13:32:58 +03:00
const struct tegra_pmc_regs * regs ;
void ( * init ) ( struct tegra_pmc * pmc ) ;
void ( * setup_irq_polarity ) ( struct tegra_pmc * pmc ,
struct device_node * np ,
bool invert ) ;
2023-03-30 20:06:21 +03:00
void ( * set_wake_filters ) ( struct tegra_pmc * pmc ) ;
2019-08-16 22:42:01 +03:00
int ( * irq_set_wake ) ( struct irq_data * data , unsigned int on ) ;
int ( * irq_set_type ) ( struct irq_data * data , unsigned int type ) ;
2021-03-02 15:24:59 +03:00
int ( * powergate_set ) ( struct tegra_pmc * pmc , unsigned int id ,
bool new_state ) ;
2018-10-24 10:08:00 +03:00
const char * const * reset_sources ;
unsigned int num_reset_sources ;
const char * const * reset_levels ;
unsigned int num_reset_levels ;
2018-09-17 16:08:17 +03:00
2019-06-04 18:41:15 +03:00
/*
* These describe events that can wake the system from sleep ( i . e .
* LP0 or SC7 ) . Wakeup from other sleep states ( such as LP1 or LP2 )
* are dealt with in the LIC .
*/
2018-09-17 16:08:17 +03:00
const struct tegra_wake_event * wake_events ;
unsigned int num_wake_events ;
2022-09-30 19:14:52 +03:00
unsigned int max_wake_events ;
unsigned int max_wake_vectors ;
2020-01-14 10:24:13 +03:00
const struct pmc_clk_init_data * pmc_clks_data ;
unsigned int num_pmc_clks ;
2020-01-14 10:24:15 +03:00
bool has_blink_output ;
2021-01-20 10:34:07 +03:00
bool has_usb_sleepwalk ;
2021-09-27 01:40:26 +03:00
bool supports_core_domain ;
2018-10-24 10:08:00 +03:00
} ;
2014-07-11 15:19:06 +04:00
/**
* struct tegra_pmc - NVIDIA Tegra PMC
2015-12-04 17:57:03 +03:00
* @ dev : pointer to PMC device structure
2014-07-11 15:19:06 +04:00
* @ base : pointer to I / O remapped register region
2019-01-25 13:22:50 +03:00
* @ wake : pointer to I / O remapped region for WAKE registers
* @ aotag : pointer to I / O remapped region for AOTAG registers
* @ scratch : pointer to I / O remapped region for scratch registers
2014-07-11 15:19:06 +04:00
* @ clk : pointer to pclk clock
2015-12-04 17:57:03 +03:00
* @ soc : pointer to SoC data structure
2019-01-25 13:22:55 +03:00
* @ tz_only : flag specifying if the PMC can only be accessed via TrustZone
2015-12-04 17:57:05 +03:00
* @ debugfs : pointer to debugfs entry
2014-07-11 15:19:06 +04:00
* @ rate : currently configured rate of pclk
* @ suspend_mode : lowest suspend mode available
* @ cpu_good_time : CPU power good time ( in microseconds )
* @ cpu_off_time : CPU power off time ( in microsecends )
* @ core_osc_time : core power good OSC time ( in microseconds )
* @ core_pmu_time : core power good PMU time ( in microseconds )
* @ core_off_time : core power off time ( in microseconds )
* @ corereq_high : core power request is active - high
* @ sysclkreq_high : system clock request is active - high
* @ combined_req : combined power request for CPU & core
* @ cpu_pwr_good_en : CPU power good signal is enabled
* @ lp0_vec_phys : physical base address of the LP0 warm boot code
* @ lp0_vec_size : size of the LP0 warm boot code
2016-03-30 12:15:15 +03:00
* @ powergates_available : Bitmap of available power gates
2014-07-11 15:19:06 +04:00
* @ powergates_lock : mutex for power gate register access
2019-01-25 13:22:50 +03:00
* @ pctl_dev : pin controller exposed by the PMC
* @ domain : IRQ domain provided by the PMC
* @ irq : chip implementation for the IRQ domain
2019-09-26 22:17:54 +03:00
* @ clk_nb : pclk clock changes handler
2022-05-06 11:53:15 +03:00
* @ core_domain_state_synced : flag marking the core domain ' s state as synced
* @ core_domain_registered : flag marking the core domain as registered
2022-09-30 19:14:52 +03:00
* @ wake_type_level_map : Bitmap indicating level type for non - dual edge wakes
* @ wake_type_dual_edge_map : Bitmap indicating if a wake is dual - edge or not
* @ wake_sw_status_map : Bitmap to hold raw status of wakes without mask
* @ wake_cntrl_level_map : Bitmap to hold wake levels to be programmed in
* cntrl register associated with each wake during system suspend .
2014-07-11 15:19:06 +04:00
*/
struct tegra_pmc {
2015-01-06 13:52:58 +03:00
struct device * dev ;
2014-07-11 15:19:06 +04:00
void __iomem * base ;
2017-08-30 13:42:34 +03:00
void __iomem * wake ;
void __iomem * aotag ;
2017-08-30 13:32:58 +03:00
void __iomem * scratch ;
2014-07-11 15:19:06 +04:00
struct clk * clk ;
2015-12-04 17:57:05 +03:00
struct dentry * debugfs ;
2014-07-11 15:19:06 +04:00
const struct tegra_pmc_soc * soc ;
2019-01-25 13:22:55 +03:00
bool tz_only ;
2014-07-11 15:19:06 +04:00
unsigned long rate ;
enum tegra_suspend_mode suspend_mode ;
u32 cpu_good_time ;
u32 cpu_off_time ;
u32 core_osc_time ;
u32 core_pmu_time ;
u32 core_off_time ;
bool corereq_high ;
bool sysclkreq_high ;
bool combined_req ;
bool cpu_pwr_good_en ;
u32 lp0_vec_phys ;
u32 lp0_vec_size ;
2016-03-30 12:15:15 +03:00
DECLARE_BITMAP ( powergates_available , TEGRA_POWERGATE_MAX ) ;
2014-07-11 15:19:06 +04:00
struct mutex powergates_lock ;
2018-08-10 21:08:12 +03:00
struct pinctrl_dev * pctl_dev ;
2018-09-17 16:08:17 +03:00
struct irq_domain * domain ;
struct irq_chip irq ;
2019-09-26 22:17:54 +03:00
struct notifier_block clk_nb ;
2021-06-01 05:31:18 +03:00
bool core_domain_state_synced ;
bool core_domain_registered ;
2022-09-30 19:14:52 +03:00
unsigned long * wake_type_level_map ;
unsigned long * wake_type_dual_edge_map ;
unsigned long * wake_sw_status_map ;
unsigned long * wake_cntrl_level_map ;
struct syscore_ops syscore ;
2014-07-11 15:19:06 +04:00
} ;
static struct tegra_pmc * pmc = & ( struct tegra_pmc ) {
. base = NULL ,
2021-07-19 00:27:05 +03:00
. suspend_mode = TEGRA_SUSPEND_NOT_READY ,
2014-07-11 15:19:06 +04:00
} ;
2016-03-30 12:15:15 +03:00
static inline struct tegra_powergate *
to_powergate ( struct generic_pm_domain * domain )
{
return container_of ( domain , struct tegra_powergate , genpd ) ;
}
2019-01-25 13:22:52 +03:00
static u32 tegra_pmc_readl ( struct tegra_pmc * pmc , unsigned long offset )
2014-07-11 15:19:06 +04:00
{
2019-01-25 13:22:55 +03:00
struct arm_smccc_res res ;
if ( pmc - > tz_only ) {
arm_smccc_smc ( TEGRA_SMC_PMC , TEGRA_SMC_PMC_READ , offset , 0 , 0 ,
0 , 0 , 0 , & res ) ;
if ( res . a0 ) {
if ( pmc - > dev )
dev_warn ( pmc - > dev , " %s(): SMC failed: %lu \n " ,
__func__ , res . a0 ) ;
else
pr_warn ( " %s(): SMC failed: %lu \n " , __func__ ,
res . a0 ) ;
}
return res . a1 ;
}
2014-07-11 15:19:06 +04:00
return readl ( pmc - > base + offset ) ;
}
2019-01-25 13:22:52 +03:00
static void tegra_pmc_writel ( struct tegra_pmc * pmc , u32 value ,
unsigned long offset )
2014-07-11 15:19:06 +04:00
{
2019-01-25 13:22:55 +03:00
struct arm_smccc_res res ;
if ( pmc - > tz_only ) {
arm_smccc_smc ( TEGRA_SMC_PMC , TEGRA_SMC_PMC_WRITE , offset ,
value , 0 , 0 , 0 , 0 , & res ) ;
if ( res . a0 ) {
if ( pmc - > dev )
dev_warn ( pmc - > dev , " %s(): SMC failed: %lu \n " ,
__func__ , res . a0 ) ;
else
pr_warn ( " %s(): SMC failed: %lu \n " , __func__ ,
res . a0 ) ;
}
} else {
writel ( value , pmc - > base + offset ) ;
}
}
static u32 tegra_pmc_scratch_readl ( struct tegra_pmc * pmc , unsigned long offset )
{
if ( pmc - > tz_only )
return tegra_pmc_readl ( pmc , offset ) ;
return readl ( pmc - > scratch + offset ) ;
}
static void tegra_pmc_scratch_writel ( struct tegra_pmc * pmc , u32 value ,
unsigned long offset )
{
if ( pmc - > tz_only )
tegra_pmc_writel ( pmc , value , offset ) ;
else
writel ( value , pmc - > scratch + offset ) ;
2014-07-11 15:19:06 +04:00
}
2019-01-25 13:22:52 +03:00
/*
* TODO Figure out a way to call this with the struct tegra_pmc * passed in .
* This currently doesn ' t work because readx_poll_timeout ( ) can only operate
* on functions that take a single argument .
*/
2016-02-11 21:03:23 +03:00
static inline bool tegra_powergate_state ( int id )
{
2016-02-15 15:38:11 +03:00
if ( id = = TEGRA_POWERGATE_3D & & pmc - > soc - > has_gpu_clamps )
2019-01-25 13:22:52 +03:00
return ( tegra_pmc_readl ( pmc , GPU_RG_CNTRL ) & 0x1 ) = = 0 ;
2016-02-15 15:38:11 +03:00
else
2019-01-25 13:22:52 +03:00
return ( tegra_pmc_readl ( pmc , PWRGATE_STATUS ) & BIT ( id ) ) ! = 0 ;
2016-02-11 21:03:23 +03:00
}
2019-01-25 13:22:52 +03:00
static inline bool tegra_powergate_is_valid ( struct tegra_pmc * pmc , int id )
2016-02-11 21:03:24 +03:00
{
return ( pmc - > soc & & pmc - > soc - > powergates [ id ] ) ;
}
2019-01-25 13:22:52 +03:00
static inline bool tegra_powergate_is_available ( struct tegra_pmc * pmc , int id )
2016-03-30 12:15:15 +03:00
{
return test_bit ( id , pmc - > powergates_available ) ;
}
static int tegra_powergate_lookup ( struct tegra_pmc * pmc , const char * name )
{
unsigned int i ;
if ( ! pmc | | ! pmc - > soc | | ! name )
return - EINVAL ;
for ( i = 0 ; i < pmc - > soc - > num_powergates ; i + + ) {
2019-01-25 13:22:52 +03:00
if ( ! tegra_powergate_is_valid ( pmc , i ) )
2016-03-30 12:15:15 +03:00
continue ;
if ( ! strcmp ( name , pmc - > soc - > powergates [ i ] ) )
return i ;
}
return - ENODEV ;
}
2021-03-02 15:24:59 +03:00
static int tegra20_powergate_set ( struct tegra_pmc * pmc , unsigned int id ,
bool new_state )
{
unsigned int retries = 100 ;
bool status ;
int ret ;
/*
* As per TRM documentation , the toggle command will be dropped by PMC
* if there is contention with a HW - initiated toggling ( i . e . CPU core
* power - gated ) , the command should be retried in that case .
*/
do {
tegra_pmc_writel ( pmc , PWRGATE_TOGGLE_START | id , PWRGATE_TOGGLE ) ;
/* wait for PMC to execute the command */
ret = readx_poll_timeout ( tegra_powergate_state , id , status ,
status = = new_state , 1 , 10 ) ;
} while ( ret = = - ETIMEDOUT & & retries - - ) ;
return ret ;
}
static inline bool tegra_powergate_toggle_ready ( struct tegra_pmc * pmc )
{
return ! ( tegra_pmc_readl ( pmc , PWRGATE_TOGGLE ) & PWRGATE_TOGGLE_START ) ;
}
static int tegra114_powergate_set ( struct tegra_pmc * pmc , unsigned int id ,
bool new_state )
{
bool status ;
int err ;
/* wait while PMC power gating is contended */
err = readx_poll_timeout ( tegra_powergate_toggle_ready , pmc , status ,
status = = true , 1 , 100 ) ;
if ( err )
return err ;
tegra_pmc_writel ( pmc , PWRGATE_TOGGLE_START | id , PWRGATE_TOGGLE ) ;
/* wait for PMC to accept the command */
err = readx_poll_timeout ( tegra_powergate_toggle_ready , pmc , status ,
status = = true , 1 , 100 ) ;
if ( err )
return err ;
/* wait for PMC to execute the command */
err = readx_poll_timeout ( tegra_powergate_state , id , status ,
status = = new_state , 10 , 100000 ) ;
if ( err )
return err ;
return 0 ;
}
2014-07-11 15:19:06 +04:00
/**
* tegra_powergate_set ( ) - set the state of a partition
2019-01-25 13:22:52 +03:00
* @ pmc : power management controller
2014-07-11 15:19:06 +04:00
* @ id : partition ID
* @ new_state : new state of the partition
*/
2019-01-25 13:22:52 +03:00
static int tegra_powergate_set ( struct tegra_pmc * pmc , unsigned int id ,
bool new_state )
2014-07-11 15:19:06 +04:00
{
2016-02-26 18:48:40 +03:00
int err ;
2016-02-15 15:38:11 +03:00
if ( id = = TEGRA_POWERGATE_3D & & pmc - > soc - > has_gpu_clamps )
return - EINVAL ;
2014-07-11 15:19:06 +04:00
mutex_lock ( & pmc - > powergates_lock ) ;
2016-02-11 21:03:23 +03:00
if ( tegra_powergate_state ( id ) = = new_state ) {
2014-07-11 15:19:06 +04:00
mutex_unlock ( & pmc - > powergates_lock ) ;
return 0 ;
}
2021-03-02 15:24:59 +03:00
err = pmc - > soc - > powergate_set ( pmc , id , new_state ) ;
2016-02-26 18:48:40 +03:00
2014-07-11 15:19:06 +04:00
mutex_unlock ( & pmc - > powergates_lock ) ;
2016-02-26 18:48:40 +03:00
return err ;
2014-07-11 15:19:06 +04:00
}
2019-01-25 13:22:52 +03:00
static int __tegra_powergate_remove_clamping ( struct tegra_pmc * pmc ,
unsigned int id )
2016-03-30 12:15:15 +03:00
{
u32 mask ;
mutex_lock ( & pmc - > powergates_lock ) ;
/*
* On Tegra124 and later , the clamps for the GPU are controlled by a
* separate register ( with different semantics ) .
*/
if ( id = = TEGRA_POWERGATE_3D ) {
if ( pmc - > soc - > has_gpu_clamps ) {
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , 0 , GPU_RG_CNTRL ) ;
2016-03-30 12:15:15 +03:00
goto out ;
}
}
/*
* Tegra 2 has a bug where PCIE and VDE clamping masks are
* swapped relatively to the partition ids
*/
if ( id = = TEGRA_POWERGATE_VDEC )
mask = ( 1 < < TEGRA_POWERGATE_PCIE ) ;
else if ( id = = TEGRA_POWERGATE_PCIE )
mask = ( 1 < < TEGRA_POWERGATE_VDEC ) ;
else
mask = ( 1 < < id ) ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , mask , REMOVE_CLAMPING ) ;
2016-03-30 12:15:15 +03:00
out :
mutex_unlock ( & pmc - > powergates_lock ) ;
return 0 ;
}
2021-03-02 15:25:00 +03:00
static int tegra_powergate_prepare_clocks ( struct tegra_powergate * pg )
{
unsigned long safe_rate = 100 * 1000 * 1000 ;
unsigned int i ;
int err ;
for ( i = 0 ; i < pg - > num_clks ; i + + ) {
pg - > clk_rates [ i ] = clk_get_rate ( pg - > clks [ i ] ) ;
if ( ! pg - > clk_rates [ i ] ) {
err = - EINVAL ;
goto out ;
}
if ( pg - > clk_rates [ i ] < = safe_rate )
continue ;
/*
* We don ' t know whether voltage state is okay for the
* current clock rate , hence it ' s better to temporally
* switch clock to a safe rate which is suitable for
* all voltages , before enabling the clock .
*/
err = clk_set_rate ( pg - > clks [ i ] , safe_rate ) ;
if ( err )
goto out ;
}
return 0 ;
out :
while ( i - - )
clk_set_rate ( pg - > clks [ i ] , pg - > clk_rates [ i ] ) ;
return err ;
}
static int tegra_powergate_unprepare_clocks ( struct tegra_powergate * pg )
{
unsigned int i ;
int err ;
for ( i = 0 ; i < pg - > num_clks ; i + + ) {
err = clk_set_rate ( pg - > clks [ i ] , pg - > clk_rates [ i ] ) ;
if ( err )
return err ;
}
return 0 ;
}
2016-03-30 12:15:15 +03:00
static void tegra_powergate_disable_clocks ( struct tegra_powergate * pg )
{
unsigned int i ;
for ( i = 0 ; i < pg - > num_clks ; i + + )
clk_disable_unprepare ( pg - > clks [ i ] ) ;
}
static int tegra_powergate_enable_clocks ( struct tegra_powergate * pg )
{
unsigned int i ;
int err ;
for ( i = 0 ; i < pg - > num_clks ; i + + ) {
err = clk_prepare_enable ( pg - > clks [ i ] ) ;
if ( err )
goto out ;
}
return 0 ;
out :
while ( i - - )
clk_disable_unprepare ( pg - > clks [ i ] ) ;
return err ;
}
static int tegra_powergate_power_up ( struct tegra_powergate * pg ,
bool disable_clocks )
{
int err ;
2017-07-19 18:59:08 +03:00
err = reset_control_assert ( pg - > reset ) ;
2016-03-30 12:15:15 +03:00
if ( err )
return err ;
usleep_range ( 10 , 20 ) ;
2019-01-25 13:22:52 +03:00
err = tegra_powergate_set ( pg - > pmc , pg - > id , true ) ;
2016-03-30 12:15:15 +03:00
if ( err < 0 )
return err ;
usleep_range ( 10 , 20 ) ;
2021-03-02 15:25:00 +03:00
err = tegra_powergate_prepare_clocks ( pg ) ;
2016-03-30 12:15:15 +03:00
if ( err )
2021-03-02 15:24:58 +03:00
goto powergate_off ;
2016-03-30 12:15:15 +03:00
2021-03-02 15:25:00 +03:00
err = tegra_powergate_enable_clocks ( pg ) ;
if ( err )
goto unprepare_clks ;
2016-03-30 12:15:15 +03:00
usleep_range ( 10 , 20 ) ;
2019-01-25 13:22:52 +03:00
err = __tegra_powergate_remove_clamping ( pg - > pmc , pg - > id ) ;
2016-03-30 12:15:15 +03:00
if ( err )
goto disable_clks ;
usleep_range ( 10 , 20 ) ;
2017-07-19 18:59:08 +03:00
err = reset_control_deassert ( pg - > reset ) ;
2016-03-30 12:15:15 +03:00
if ( err )
2021-06-27 18:54:31 +03:00
goto disable_clks ;
2016-03-30 12:15:15 +03:00
usleep_range ( 10 , 20 ) ;
2018-01-25 17:00:13 +03:00
if ( pg - > pmc - > soc - > needs_mbist_war )
err = tegra210_clk_handle_mbist_war ( pg - > id ) ;
if ( err )
goto disable_clks ;
2016-03-30 12:15:15 +03:00
if ( disable_clocks )
tegra_powergate_disable_clocks ( pg ) ;
2021-03-02 15:25:00 +03:00
err = tegra_powergate_unprepare_clocks ( pg ) ;
if ( err )
return err ;
2016-03-30 12:15:15 +03:00
return 0 ;
disable_clks :
tegra_powergate_disable_clocks ( pg ) ;
usleep_range ( 10 , 20 ) ;
2016-06-30 13:12:55 +03:00
2021-03-02 15:25:00 +03:00
unprepare_clks :
tegra_powergate_unprepare_clocks ( pg ) ;
2016-03-30 12:15:15 +03:00
powergate_off :
2019-01-25 13:22:52 +03:00
tegra_powergate_set ( pg - > pmc , pg - > id , false ) ;
2016-03-30 12:15:15 +03:00
return err ;
}
static int tegra_powergate_power_down ( struct tegra_powergate * pg )
{
int err ;
2021-03-02 15:25:00 +03:00
err = tegra_powergate_prepare_clocks ( pg ) ;
2016-03-30 12:15:15 +03:00
if ( err )
return err ;
2021-03-02 15:25:00 +03:00
err = tegra_powergate_enable_clocks ( pg ) ;
if ( err )
goto unprepare_clks ;
2016-03-30 12:15:15 +03:00
usleep_range ( 10 , 20 ) ;
2017-07-19 18:59:08 +03:00
err = reset_control_assert ( pg - > reset ) ;
2016-03-30 12:15:15 +03:00
if ( err )
goto disable_clks ;
usleep_range ( 10 , 20 ) ;
tegra_powergate_disable_clocks ( pg ) ;
usleep_range ( 10 , 20 ) ;
2019-01-25 13:22:52 +03:00
err = tegra_powergate_set ( pg - > pmc , pg - > id , false ) ;
2016-03-30 12:15:15 +03:00
if ( err )
goto assert_resets ;
2021-03-02 15:25:00 +03:00
err = tegra_powergate_unprepare_clocks ( pg ) ;
if ( err )
return err ;
2016-03-30 12:15:15 +03:00
return 0 ;
assert_resets :
tegra_powergate_enable_clocks ( pg ) ;
usleep_range ( 10 , 20 ) ;
2017-07-19 18:59:08 +03:00
reset_control_deassert ( pg - > reset ) ;
2016-03-30 12:15:15 +03:00
usleep_range ( 10 , 20 ) ;
2016-06-30 13:12:55 +03:00
2016-03-30 12:15:15 +03:00
disable_clks :
tegra_powergate_disable_clocks ( pg ) ;
2021-03-02 15:25:00 +03:00
unprepare_clks :
tegra_powergate_unprepare_clocks ( pg ) ;
2016-03-30 12:15:15 +03:00
return err ;
}
static int tegra_genpd_power_on ( struct generic_pm_domain * domain )
{
struct tegra_powergate * pg = to_powergate ( domain ) ;
2019-01-25 13:22:52 +03:00
struct device * dev = pg - > pmc - > dev ;
2016-03-30 12:15:15 +03:00
int err ;
err = tegra_powergate_power_up ( pg , true ) ;
2019-02-18 19:36:43 +03:00
if ( err ) {
2019-01-25 13:22:52 +03:00
dev_err ( dev , " failed to turn on PM domain %s: %d \n " ,
pg - > genpd . name , err ) ;
2019-02-18 19:36:43 +03:00
goto out ;
}
reset_control_release ( pg - > reset ) ;
2016-03-30 12:15:15 +03:00
2019-02-18 19:36:43 +03:00
out :
2016-03-30 12:15:15 +03:00
return err ;
}
static int tegra_genpd_power_off ( struct generic_pm_domain * domain )
{
struct tegra_powergate * pg = to_powergate ( domain ) ;
2019-01-25 13:22:52 +03:00
struct device * dev = pg - > pmc - > dev ;
2016-03-30 12:15:15 +03:00
int err ;
2019-02-18 19:36:43 +03:00
err = reset_control_acquire ( pg - > reset ) ;
if ( err < 0 ) {
2021-03-02 15:25:01 +03:00
dev_err ( dev , " failed to acquire resets for PM domain %s: %d \n " ,
pg - > genpd . name , err ) ;
2019-02-18 19:36:43 +03:00
return err ;
}
2016-03-30 12:15:15 +03:00
err = tegra_powergate_power_down ( pg ) ;
2019-02-18 19:36:43 +03:00
if ( err ) {
2019-01-25 13:22:52 +03:00
dev_err ( dev , " failed to turn off PM domain %s: %d \n " ,
pg - > genpd . name , err ) ;
2019-02-18 19:36:43 +03:00
reset_control_release ( pg - > reset ) ;
}
2016-03-30 12:15:15 +03:00
return err ;
}
2014-07-11 15:19:06 +04:00
/**
* tegra_powergate_power_on ( ) - power on partition
* @ id : partition ID
*/
2016-02-11 21:03:22 +03:00
int tegra_powergate_power_on ( unsigned int id )
2014-07-11 15:19:06 +04:00
{
2019-01-25 13:22:52 +03:00
if ( ! tegra_powergate_is_available ( pmc , id ) )
2014-07-11 15:19:06 +04:00
return - EINVAL ;
2019-01-25 13:22:52 +03:00
return tegra_powergate_set ( pmc , id , true ) ;
2014-07-11 15:19:06 +04:00
}
2019-06-18 21:01:40 +03:00
EXPORT_SYMBOL ( tegra_powergate_power_on ) ;
2014-07-11 15:19:06 +04:00
/**
* tegra_powergate_power_off ( ) - power off partition
* @ id : partition ID
*/
2016-02-11 21:03:22 +03:00
int tegra_powergate_power_off ( unsigned int id )
2014-07-11 15:19:06 +04:00
{
2019-01-25 13:22:52 +03:00
if ( ! tegra_powergate_is_available ( pmc , id ) )
2014-07-11 15:19:06 +04:00
return - EINVAL ;
2019-01-25 13:22:52 +03:00
return tegra_powergate_set ( pmc , id , false ) ;
2014-07-11 15:19:06 +04:00
}
EXPORT_SYMBOL ( tegra_powergate_power_off ) ;
/**
* tegra_powergate_is_powered ( ) - check if partition is powered
2019-01-25 13:22:52 +03:00
* @ pmc : power management controller
2014-07-11 15:19:06 +04:00
* @ id : partition ID
*/
2019-01-25 13:22:52 +03:00
static int tegra_powergate_is_powered ( struct tegra_pmc * pmc , unsigned int id )
2014-07-11 15:19:06 +04:00
{
2019-01-25 13:22:52 +03:00
if ( ! tegra_powergate_is_valid ( pmc , id ) )
2014-07-11 15:19:06 +04:00
return - EINVAL ;
2018-10-21 21:36:14 +03:00
return tegra_powergate_state ( id ) ;
2014-07-11 15:19:06 +04:00
}
/**
* tegra_powergate_remove_clamping ( ) - remove power clamps for partition
* @ id : partition ID
*/
2016-02-11 21:03:22 +03:00
int tegra_powergate_remove_clamping ( unsigned int id )
2014-07-11 15:19:06 +04:00
{
2019-01-25 13:22:52 +03:00
if ( ! tegra_powergate_is_available ( pmc , id ) )
2014-07-11 15:19:06 +04:00
return - EINVAL ;
2019-01-25 13:22:52 +03:00
return __tegra_powergate_remove_clamping ( pmc , id ) ;
2014-07-11 15:19:06 +04:00
}
EXPORT_SYMBOL ( tegra_powergate_remove_clamping ) ;
/**
* tegra_powergate_sequence_power_up ( ) - power up partition
* @ id : partition ID
* @ clk : clock for partition
* @ rst : reset for partition
*
* Must be called with clk disabled , and returns with clk enabled .
*/
2016-02-11 21:03:22 +03:00
int tegra_powergate_sequence_power_up ( unsigned int id , struct clk * clk ,
2014-07-11 15:19:06 +04:00
struct reset_control * rst )
{
2018-05-03 11:26:17 +03:00
struct tegra_powergate * pg ;
2016-03-30 12:15:15 +03:00
int err ;
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
if ( ! tegra_powergate_is_available ( pmc , id ) )
2016-06-28 13:38:23 +03:00
return - EINVAL ;
2018-05-03 11:26:17 +03:00
pg = kzalloc ( sizeof ( * pg ) , GFP_KERNEL ) ;
if ( ! pg )
return - ENOMEM ;
2014-07-11 15:19:06 +04:00
2021-03-02 15:25:00 +03:00
pg - > clk_rates = kzalloc ( sizeof ( * pg - > clk_rates ) , GFP_KERNEL ) ;
if ( ! pg - > clk_rates ) {
kfree ( pg - > clks ) ;
return - ENOMEM ;
}
2018-05-03 11:26:17 +03:00
pg - > id = id ;
pg - > clks = & clk ;
pg - > num_clks = 1 ;
pg - > reset = rst ;
pg - > pmc = pmc ;
err = tegra_powergate_power_up ( pg , false ) ;
2016-03-30 12:15:15 +03:00
if ( err )
2019-01-25 13:22:52 +03:00
dev_err ( pmc - > dev , " failed to turn on partition %d: %d \n " , id ,
err ) ;
2014-07-11 15:19:06 +04:00
2021-03-02 15:25:00 +03:00
kfree ( pg - > clk_rates ) ;
2018-05-03 11:26:17 +03:00
kfree ( pg ) ;
2016-03-30 12:15:15 +03:00
return err ;
2014-07-11 15:19:06 +04:00
}
EXPORT_SYMBOL ( tegra_powergate_sequence_power_up ) ;
/**
* tegra_get_cpu_powergate_id ( ) - convert from CPU ID to partition ID
2019-01-25 13:22:52 +03:00
* @ pmc : power management controller
2014-07-11 15:19:06 +04:00
* @ cpuid : CPU partition ID
*
* Returns the partition ID corresponding to the CPU partition ID or a
* negative error code on failure .
*/
2019-01-25 13:22:52 +03:00
static int tegra_get_cpu_powergate_id ( struct tegra_pmc * pmc ,
unsigned int cpuid )
2014-07-11 15:19:06 +04:00
{
2016-02-11 21:03:22 +03:00
if ( pmc - > soc & & cpuid < pmc - > soc - > num_cpu_powergates )
2014-07-11 15:19:06 +04:00
return pmc - > soc - > cpu_powergates [ cpuid ] ;
return - EINVAL ;
}
/**
* tegra_pmc_cpu_is_powered ( ) - check if CPU partition is powered
* @ cpuid : CPU partition ID
*/
2016-02-11 21:03:22 +03:00
bool tegra_pmc_cpu_is_powered ( unsigned int cpuid )
2014-07-11 15:19:06 +04:00
{
int id ;
2019-01-25 13:22:52 +03:00
id = tegra_get_cpu_powergate_id ( pmc , cpuid ) ;
2014-07-11 15:19:06 +04:00
if ( id < 0 )
return false ;
2019-01-25 13:22:52 +03:00
return tegra_powergate_is_powered ( pmc , id ) ;
2014-07-11 15:19:06 +04:00
}
/**
* tegra_pmc_cpu_power_on ( ) - power on CPU partition
* @ cpuid : CPU partition ID
*/
2016-02-11 21:03:22 +03:00
int tegra_pmc_cpu_power_on ( unsigned int cpuid )
2014-07-11 15:19:06 +04:00
{
int id ;
2019-01-25 13:22:52 +03:00
id = tegra_get_cpu_powergate_id ( pmc , cpuid ) ;
2014-07-11 15:19:06 +04:00
if ( id < 0 )
return id ;
2019-01-25 13:22:52 +03:00
return tegra_powergate_set ( pmc , id , true ) ;
2014-07-11 15:19:06 +04:00
}
/**
* tegra_pmc_cpu_remove_clamping ( ) - remove power clamps for CPU partition
* @ cpuid : CPU partition ID
*/
2016-02-11 21:03:22 +03:00
int tegra_pmc_cpu_remove_clamping ( unsigned int cpuid )
2014-07-11 15:19:06 +04:00
{
int id ;
2019-01-25 13:22:52 +03:00
id = tegra_get_cpu_powergate_id ( pmc , cpuid ) ;
2014-07-11 15:19:06 +04:00
if ( id < 0 )
return id ;
return tegra_powergate_remove_clamping ( id ) ;
}
2021-11-30 14:44:06 +03:00
static void tegra_pmc_program_reboot_reason ( const char * cmd )
2014-07-11 15:19:06 +04:00
{
u32 value ;
2019-01-25 13:22:55 +03:00
value = tegra_pmc_scratch_readl ( pmc , pmc - > soc - > regs - > scratch0 ) ;
2014-07-11 15:19:06 +04:00
value & = ~ PMC_SCRATCH0_MODE_MASK ;
if ( cmd ) {
if ( strcmp ( cmd , " recovery " ) = = 0 )
value | = PMC_SCRATCH0_MODE_RECOVERY ;
if ( strcmp ( cmd , " bootloader " ) = = 0 )
value | = PMC_SCRATCH0_MODE_BOOTLOADER ;
if ( strcmp ( cmd , " forced-recovery " ) = = 0 )
value | = PMC_SCRATCH0_MODE_RCM ;
}
2019-01-25 13:22:55 +03:00
tegra_pmc_scratch_writel ( pmc , value , pmc - > soc - > regs - > scratch0 ) ;
2021-11-30 14:44:06 +03:00
}
static int tegra_pmc_reboot_notify ( struct notifier_block * this ,
unsigned long action , void * data )
{
if ( action = = SYS_RESTART )
tegra_pmc_program_reboot_reason ( data ) ;
return NOTIFY_DONE ;
}
static struct notifier_block tegra_pmc_reboot_notifier = {
. notifier_call = tegra_pmc_reboot_notify ,
} ;
2022-05-10 02:32:33 +03:00
static void tegra_pmc_restart ( void )
2021-11-30 14:44:06 +03:00
{
u32 value ;
2014-07-11 15:19:06 +04:00
2015-12-30 19:13:29 +03:00
/* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_CNTRL ) ;
2015-12-30 19:13:29 +03:00
value | = PMC_CNTRL_MAIN_RST ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_CNTRL ) ;
2022-05-10 02:32:33 +03:00
}
static int tegra_pmc_restart_handler ( struct sys_off_data * data )
{
tegra_pmc_restart ( ) ;
2015-03-18 12:52:25 +03:00
return NOTIFY_DONE ;
2014-07-11 15:19:06 +04:00
}
2022-05-10 02:32:33 +03:00
static int tegra_pmc_power_off_handler ( struct sys_off_data * data )
{
/*
* Reboot Nexus 7 into special bootloader mode if USB cable is
* connected in order to display battery status and power off .
*/
if ( of_machine_is_compatible ( " asus,grouper " ) & &
power_supply_is_system_supplied ( ) ) {
const u32 go_to_charger_mode = 0xa5a55a5a ;
tegra_pmc_writel ( pmc , go_to_charger_mode , PMC_SCRATCH37 ) ;
tegra_pmc_restart ( ) ;
}
return NOTIFY_DONE ;
}
2015-03-18 12:52:25 +03:00
2014-07-11 15:19:06 +04:00
static int powergate_show ( struct seq_file * s , void * data )
{
unsigned int i ;
2016-02-11 21:03:25 +03:00
int status ;
2014-07-11 15:19:06 +04:00
seq_printf ( s , " powergate powered \n " ) ;
seq_printf ( s , " ------------------ \n " ) ;
for ( i = 0 ; i < pmc - > soc - > num_powergates ; i + + ) {
2019-01-25 13:22:52 +03:00
status = tegra_powergate_is_powered ( pmc , i ) ;
2016-02-11 21:03:25 +03:00
if ( status < 0 )
2014-07-11 15:19:06 +04:00
continue ;
seq_printf ( s , " %9s %7s \n " , pmc - > soc - > powergates [ i ] ,
2016-02-11 21:03:25 +03:00
status ? " yes " : " no " ) ;
2014-07-11 15:19:06 +04:00
}
return 0 ;
}
2018-11-22 16:12:07 +03:00
DEFINE_SHOW_ATTRIBUTE ( powergate ) ;
2014-07-11 15:19:06 +04:00
static int tegra_powergate_debugfs_init ( void )
{
2015-12-04 17:57:05 +03:00
pmc - > debugfs = debugfs_create_file ( " powergate " , S_IRUGO , NULL , NULL ,
& powergate_fops ) ;
if ( ! pmc - > debugfs )
2014-07-11 15:19:06 +04:00
return - ENOMEM ;
return 0 ;
}
2016-03-30 12:15:15 +03:00
static int tegra_powergate_of_get_clks ( struct tegra_powergate * pg ,
struct device_node * np )
{
struct clk * clk ;
unsigned int i , count ;
int err ;
2018-04-18 17:50:04 +03:00
count = of_clk_get_parent_count ( np ) ;
2016-03-30 12:15:15 +03:00
if ( count = = 0 )
return - ENODEV ;
pg - > clks = kcalloc ( count , sizeof ( clk ) , GFP_KERNEL ) ;
if ( ! pg - > clks )
return - ENOMEM ;
2021-03-02 15:25:00 +03:00
pg - > clk_rates = kcalloc ( count , sizeof ( * pg - > clk_rates ) , GFP_KERNEL ) ;
if ( ! pg - > clk_rates ) {
kfree ( pg - > clks ) ;
return - ENOMEM ;
}
2016-03-30 12:15:15 +03:00
for ( i = 0 ; i < count ; i + + ) {
pg - > clks [ i ] = of_clk_get ( np , i ) ;
if ( IS_ERR ( pg - > clks [ i ] ) ) {
err = PTR_ERR ( pg - > clks [ i ] ) ;
goto err ;
}
}
pg - > num_clks = count ;
return 0 ;
err :
while ( i - - )
clk_put ( pg - > clks [ i ] ) ;
2016-06-30 13:12:55 +03:00
2021-03-02 15:25:00 +03:00
kfree ( pg - > clk_rates ) ;
2016-03-30 12:15:15 +03:00
kfree ( pg - > clks ) ;
return err ;
}
static int tegra_powergate_of_get_resets ( struct tegra_powergate * pg ,
2016-06-29 12:17:47 +03:00
struct device_node * np , bool off )
2016-03-30 12:15:15 +03:00
{
2019-01-25 13:22:52 +03:00
struct device * dev = pg - > pmc - > dev ;
2016-03-30 12:15:15 +03:00
int err ;
2019-02-18 19:36:43 +03:00
pg - > reset = of_reset_control_array_get_exclusive_released ( np ) ;
2017-07-19 18:59:08 +03:00
if ( IS_ERR ( pg - > reset ) ) {
err = PTR_ERR ( pg - > reset ) ;
2019-01-25 13:22:52 +03:00
dev_err ( dev , " failed to get device resets: %d \n " , err ) ;
2017-07-19 18:59:08 +03:00
return err ;
2016-03-30 12:15:15 +03:00
}
2019-02-18 19:36:43 +03:00
err = reset_control_acquire ( pg - > reset ) ;
if ( err < 0 ) {
pr_err ( " failed to acquire resets: %d \n " , err ) ;
goto out ;
}
if ( off ) {
2017-07-19 18:59:08 +03:00
err = reset_control_assert ( pg - > reset ) ;
2019-02-18 19:36:43 +03:00
} else {
2017-07-19 18:59:08 +03:00
err = reset_control_deassert ( pg - > reset ) ;
2019-02-18 19:36:43 +03:00
if ( err < 0 )
goto out ;
2016-06-30 13:12:55 +03:00
2019-02-18 19:36:43 +03:00
reset_control_release ( pg - > reset ) ;
}
out :
if ( err ) {
reset_control_release ( pg - > reset ) ;
2017-07-19 18:59:08 +03:00
reset_control_put ( pg - > reset ) ;
2019-02-18 19:36:43 +03:00
}
2016-03-30 12:15:15 +03:00
return err ;
}
2019-04-16 19:48:08 +03:00
static int tegra_powergate_add ( struct tegra_pmc * pmc , struct device_node * np )
2016-03-30 12:15:15 +03:00
{
2019-01-25 13:22:52 +03:00
struct device * dev = pmc - > dev ;
2016-03-30 12:15:15 +03:00
struct tegra_powergate * pg ;
2019-04-16 19:48:08 +03:00
int id , err = 0 ;
2016-03-30 12:15:15 +03:00
bool off ;
pg = kzalloc ( sizeof ( * pg ) , GFP_KERNEL ) ;
if ( ! pg )
2019-04-16 19:48:08 +03:00
return - ENOMEM ;
2016-03-30 12:15:15 +03:00
id = tegra_powergate_lookup ( pmc , np - > name ) ;
2016-06-30 13:56:24 +03:00
if ( id < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( dev , " powergate lookup failed for %pOFn: %d \n " , np , id ) ;
2019-04-16 19:48:08 +03:00
err = - ENODEV ;
2016-03-30 12:15:15 +03:00
goto free_mem ;
2016-06-30 13:56:24 +03:00
}
2016-03-30 12:15:15 +03:00
/*
* Clear the bit for this powergate so it cannot be managed
* directly via the legacy APIs for controlling powergates .
*/
clear_bit ( id , pmc - > powergates_available ) ;
pg - > id = id ;
pg - > genpd . name = np - > name ;
pg - > genpd . power_off = tegra_genpd_power_off ;
pg - > genpd . power_on = tegra_genpd_power_on ;
pg - > pmc = pmc ;
2019-01-25 13:22:52 +03:00
off = ! tegra_powergate_is_powered ( pmc , pg - > id ) ;
2016-06-29 12:17:47 +03:00
2016-06-30 13:56:24 +03:00
err = tegra_powergate_of_get_clks ( pg , np ) ;
if ( err < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( dev , " failed to get clocks for %pOFn: %d \n " , np , err ) ;
2016-03-30 12:15:15 +03:00
goto set_available ;
2016-06-30 13:56:24 +03:00
}
2016-03-30 12:15:15 +03:00
2016-06-30 13:56:24 +03:00
err = tegra_powergate_of_get_resets ( pg , np , off ) ;
if ( err < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( dev , " failed to get resets for %pOFn: %d \n " , np , err ) ;
2016-03-30 12:15:15 +03:00
goto remove_clks ;
2016-06-30 13:56:24 +03:00
}
2016-03-30 12:15:15 +03:00
2016-10-22 22:23:56 +03:00
if ( ! IS_ENABLED ( CONFIG_PM_GENERIC_DOMAINS ) ) {
if ( off )
WARN_ON ( tegra_powergate_power_up ( pg , true ) ) ;
goto remove_resets ;
}
2016-06-30 13:56:25 +03:00
2016-10-22 22:23:55 +03:00
err = pm_genpd_init ( & pg - > genpd , NULL , off ) ;
if ( err < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( dev , " failed to initialise PM domain %pOFn: %d \n " , np ,
2016-10-22 22:23:55 +03:00
err ) ;
goto remove_resets ;
}
2016-03-30 12:15:15 +03:00
2016-06-30 13:56:24 +03:00
err = of_genpd_add_provider_simple ( np , & pg - > genpd ) ;
if ( err < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( dev , " failed to add PM domain provider for %pOFn: %d \n " ,
np , err ) ;
2016-10-22 22:23:56 +03:00
goto remove_genpd ;
2016-06-30 13:56:24 +03:00
}
2016-03-30 12:15:15 +03:00
2019-01-25 13:22:52 +03:00
dev_dbg ( dev , " added PM domain %s \n " , pg - > genpd . name ) ;
2016-03-30 12:15:15 +03:00
2019-04-16 19:48:08 +03:00
return 0 ;
2016-03-30 12:15:15 +03:00
2016-10-22 22:23:56 +03:00
remove_genpd :
pm_genpd_remove ( & pg - > genpd ) ;
2016-06-30 13:56:25 +03:00
2016-03-30 12:15:15 +03:00
remove_resets :
2017-07-19 18:59:08 +03:00
reset_control_put ( pg - > reset ) ;
2016-03-30 12:15:15 +03:00
remove_clks :
while ( pg - > num_clks - - )
clk_put ( pg - > clks [ pg - > num_clks ] ) ;
2016-06-30 13:12:55 +03:00
2016-03-30 12:15:15 +03:00
kfree ( pg - > clks ) ;
set_available :
set_bit ( id , pmc - > powergates_available ) ;
free_mem :
kfree ( pg ) ;
2019-04-16 19:48:08 +03:00
return err ;
2016-03-30 12:15:15 +03:00
}
2021-06-01 05:31:18 +03:00
bool tegra_pmc_core_domain_state_synced ( void )
{
return pmc - > core_domain_state_synced ;
}
2021-06-01 05:31:17 +03:00
static int
tegra_pmc_core_pd_set_performance_state ( struct generic_pm_domain * genpd ,
unsigned int level )
{
struct dev_pm_opp * opp ;
int err ;
opp = dev_pm_opp_find_level_ceil ( & genpd - > dev , & level ) ;
if ( IS_ERR ( opp ) ) {
dev_err ( & genpd - > dev , " failed to find OPP for level %u: %pe \n " ,
level , opp ) ;
return PTR_ERR ( opp ) ;
}
mutex_lock ( & pmc - > powergates_lock ) ;
err = dev_pm_opp_set_opp ( pmc - > dev , opp ) ;
mutex_unlock ( & pmc - > powergates_lock ) ;
dev_pm_opp_put ( opp ) ;
if ( err ) {
dev_err ( & genpd - > dev , " failed to set voltage to %duV: %d \n " ,
level , err ) ;
return err ;
}
return 0 ;
}
static unsigned int
tegra_pmc_core_pd_opp_to_performance_state ( struct generic_pm_domain * genpd ,
struct dev_pm_opp * opp )
{
return dev_pm_opp_get_level ( opp ) ;
}
static int tegra_pmc_core_pd_add ( struct tegra_pmc * pmc , struct device_node * np )
{
struct generic_pm_domain * genpd ;
2022-07-04 13:40:39 +03:00
const char * rname [ ] = { " core " , NULL } ;
2021-06-01 05:31:17 +03:00
int err ;
genpd = devm_kzalloc ( pmc - > dev , sizeof ( * genpd ) , GFP_KERNEL ) ;
if ( ! genpd )
return - ENOMEM ;
2021-12-01 02:23:39 +03:00
genpd - > name = " core " ;
2021-06-01 05:31:17 +03:00
genpd - > set_performance_state = tegra_pmc_core_pd_set_performance_state ;
genpd - > opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state ;
2022-07-04 13:40:39 +03:00
err = devm_pm_opp_set_regulators ( pmc - > dev , rname ) ;
2021-06-01 05:31:17 +03:00
if ( err )
return dev_err_probe ( pmc - > dev , err ,
" failed to set core OPP regulator \n " ) ;
err = pm_genpd_init ( genpd , NULL , false ) ;
if ( err ) {
dev_err ( pmc - > dev , " failed to init core genpd: %d \n " , err ) ;
return err ;
}
err = of_genpd_add_provider_simple ( np , genpd ) ;
if ( err ) {
dev_err ( pmc - > dev , " failed to add core genpd: %d \n " , err ) ;
goto remove_genpd ;
}
2021-06-01 05:31:18 +03:00
pmc - > core_domain_registered = true ;
2021-06-01 05:31:17 +03:00
return 0 ;
remove_genpd :
pm_genpd_remove ( genpd ) ;
return err ;
}
2019-04-16 19:48:08 +03:00
static int tegra_powergate_init ( struct tegra_pmc * pmc ,
struct device_node * parent )
2016-03-30 12:15:15 +03:00
{
2021-06-01 05:31:17 +03:00
struct of_phandle_args child_args , parent_args ;
2016-03-30 12:15:15 +03:00
struct device_node * np , * child ;
2019-04-16 19:48:08 +03:00
int err = 0 ;
2021-06-01 05:31:17 +03:00
/*
* Core power domain is the parent of powergate domains , hence it
* should be registered first .
*/
np = of_get_child_by_name ( parent , " core-domain " ) ;
if ( np ) {
err = tegra_pmc_core_pd_add ( pmc , np ) ;
of_node_put ( np ) ;
if ( err )
return err ;
}
2019-04-16 19:48:08 +03:00
np = of_get_child_by_name ( parent , " powergates " ) ;
if ( ! np )
return 0 ;
2016-03-30 12:15:15 +03:00
2019-04-16 19:48:08 +03:00
for_each_child_of_node ( np , child ) {
err = tegra_powergate_add ( pmc , child ) ;
if ( err < 0 ) {
of_node_put ( child ) ;
break ;
}
2021-06-01 05:31:17 +03:00
if ( of_parse_phandle_with_args ( child , " power-domains " ,
" #power-domain-cells " ,
0 , & parent_args ) )
continue ;
child_args . np = child ;
child_args . args_count = 0 ;
err = of_genpd_add_subdomain ( & parent_args , & child_args ) ;
of_node_put ( parent_args . np ) ;
if ( err ) {
of_node_put ( child ) ;
break ;
}
2019-04-16 19:48:08 +03:00
}
of_node_put ( np ) ;
return err ;
}
static void tegra_powergate_remove ( struct generic_pm_domain * genpd )
{
struct tegra_powergate * pg = to_powergate ( genpd ) ;
reset_control_put ( pg - > reset ) ;
while ( pg - > num_clks - - )
clk_put ( pg - > clks [ pg - > num_clks ] ) ;
kfree ( pg - > clks ) ;
set_bit ( pg - > id , pmc - > powergates_available ) ;
kfree ( pg ) ;
}
static void tegra_powergate_remove_all ( struct device_node * parent )
{
struct generic_pm_domain * genpd ;
struct device_node * np , * child ;
2016-06-30 13:56:25 +03:00
np = of_get_child_by_name ( parent , " powergates " ) ;
2016-03-30 12:15:15 +03:00
if ( ! np )
return ;
2019-04-16 19:48:08 +03:00
for_each_child_of_node ( np , child ) {
of_genpd_del_provider ( child ) ;
genpd = of_genpd_remove_last ( child ) ;
if ( IS_ERR ( genpd ) )
continue ;
tegra_powergate_remove ( genpd ) ;
}
2016-03-30 12:15:15 +03:00
of_node_put ( np ) ;
2021-06-01 05:31:17 +03:00
np = of_get_child_by_name ( parent , " core-domain " ) ;
if ( np ) {
of_genpd_del_provider ( np ) ;
of_genpd_remove_last ( np ) ;
}
2016-03-30 12:15:15 +03:00
}
2016-10-10 16:14:34 +03:00
static const struct tegra_io_pad_soc *
tegra_io_pad_find ( struct tegra_pmc * pmc , enum tegra_io_pad id )
{
unsigned int i ;
for ( i = 0 ; i < pmc - > soc - > num_io_pads ; i + + )
if ( pmc - > soc - > io_pads [ i ] . id = = id )
return & pmc - > soc - > io_pads [ i ] ;
return NULL ;
}
2022-09-30 19:02:13 +03:00
static int tegra_io_pad_prepare ( struct tegra_pmc * pmc ,
const struct tegra_io_pad_soc * pad ,
unsigned long * request ,
unsigned long * status ,
2019-01-25 13:22:52 +03:00
u32 * mask )
2018-08-10 21:08:08 +03:00
{
unsigned long rate , value ;
2022-09-30 19:02:13 +03:00
if ( pad - > dpd = = UINT_MAX )
return - EINVAL ;
* request = pad - > request ;
* status = pad - > status ;
* mask = BIT ( pad - > dpd ) ;
2018-08-10 21:08:08 +03:00
2017-08-30 13:32:58 +03:00
if ( pmc - > clk ) {
2019-09-26 22:17:54 +03:00
rate = pmc - > rate ;
2017-08-30 13:32:58 +03:00
if ( ! rate ) {
2019-01-25 13:22:52 +03:00
dev_err ( pmc - > dev , " failed to get clock rate \n " ) ;
2017-08-30 13:32:58 +03:00
return - ENODEV ;
}
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , DPD_SAMPLE_ENABLE , DPD_SAMPLE ) ;
2014-07-11 15:19:06 +04:00
2017-08-30 13:32:58 +03:00
/* must be at least 200 ns, in APB (PCLK) clock cycles */
value = DIV_ROUND_UP ( 1000000000 , rate ) ;
value = DIV_ROUND_UP ( 200 , value ) ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , SEL_DPD_TIM ) ;
2017-08-30 13:32:58 +03:00
}
2014-07-11 15:19:06 +04:00
return 0 ;
}
2019-01-25 13:22:52 +03:00
static int tegra_io_pad_poll ( struct tegra_pmc * pmc , unsigned long offset ,
u32 mask , u32 val , unsigned long timeout )
2014-07-11 15:19:06 +04:00
{
2016-06-17 16:06:13 +03:00
u32 value ;
2014-07-11 15:19:06 +04:00
timeout = jiffies + msecs_to_jiffies ( timeout ) ;
while ( time_after ( timeout , jiffies ) ) {
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , offset ) ;
2014-07-11 15:19:06 +04:00
if ( ( value & mask ) = = val )
return 0 ;
usleep_range ( 250 , 1000 ) ;
}
return - ETIMEDOUT ;
}
2019-01-25 13:22:52 +03:00
static void tegra_io_pad_unprepare ( struct tegra_pmc * pmc )
2014-07-11 15:19:06 +04:00
{
2017-08-30 13:32:58 +03:00
if ( pmc - > clk )
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , DPD_SAMPLE_DISABLE , DPD_SAMPLE ) ;
2014-07-11 15:19:06 +04:00
}
2016-10-10 16:14:34 +03:00
/**
* tegra_io_pad_power_enable ( ) - enable power to I / O pad
* @ id : Tegra I / O pad ID for which to enable power
*
* Returns : 0 on success or a negative error code on failure .
*/
int tegra_io_pad_power_enable ( enum tegra_io_pad id )
2014-07-11 15:19:06 +04:00
{
2022-09-30 19:02:13 +03:00
const struct tegra_io_pad_soc * pad ;
2016-08-11 04:13:36 +03:00
unsigned long request , status ;
2016-10-22 22:23:53 +03:00
u32 mask ;
2014-07-11 15:19:06 +04:00
int err ;
2022-09-30 19:02:13 +03:00
pad = tegra_io_pad_find ( pmc , id ) ;
if ( ! pad ) {
dev_err ( pmc - > dev , " invalid I/O pad ID %u \n " , id ) ;
return - ENOENT ;
}
2016-02-11 21:03:21 +03:00
mutex_lock ( & pmc - > powergates_lock ) ;
2022-09-30 19:02:13 +03:00
err = tegra_io_pad_prepare ( pmc , pad , & request , & status , & mask ) ;
2016-10-10 16:14:34 +03:00
if ( err < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( pmc - > dev , " failed to prepare I/O pad: %d \n " , err ) ;
2016-10-10 16:14:34 +03:00
goto unlock ;
}
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , IO_DPD_REQ_CODE_OFF | mask , request ) ;
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
err = tegra_io_pad_poll ( pmc , status , mask , 0 , 250 ) ;
2016-10-10 16:14:34 +03:00
if ( err < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( pmc - > dev , " failed to enable I/O pad: %d \n " , err ) ;
2016-10-10 16:14:34 +03:00
goto unlock ;
2015-08-04 16:25:03 +03:00
}
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
tegra_io_pad_unprepare ( pmc ) ;
2014-07-11 15:19:06 +04:00
2016-10-10 16:14:34 +03:00
unlock :
2016-02-11 21:03:21 +03:00
mutex_unlock ( & pmc - > powergates_lock ) ;
return err ;
2014-07-11 15:19:06 +04:00
}
2016-10-10 16:14:34 +03:00
EXPORT_SYMBOL ( tegra_io_pad_power_enable ) ;
2014-07-11 15:19:06 +04:00
2016-10-10 16:14:34 +03:00
/**
* tegra_io_pad_power_disable ( ) - disable power to I / O pad
* @ id : Tegra I / O pad ID for which to disable power
*
* Returns : 0 on success or a negative error code on failure .
*/
int tegra_io_pad_power_disable ( enum tegra_io_pad id )
2014-07-11 15:19:06 +04:00
{
2022-09-30 19:02:13 +03:00
const struct tegra_io_pad_soc * pad ;
2016-08-11 04:13:36 +03:00
unsigned long request , status ;
2016-10-22 22:23:53 +03:00
u32 mask ;
2014-07-11 15:19:06 +04:00
int err ;
2022-09-30 19:02:13 +03:00
pad = tegra_io_pad_find ( pmc , id ) ;
if ( ! pad ) {
dev_err ( pmc - > dev , " invalid I/O pad ID %u \n " , id ) ;
return - ENOENT ;
}
2016-02-11 21:03:21 +03:00
mutex_lock ( & pmc - > powergates_lock ) ;
2022-09-30 19:02:13 +03:00
err = tegra_io_pad_prepare ( pmc , pad , & request , & status , & mask ) ;
2016-10-10 16:14:34 +03:00
if ( err < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( pmc - > dev , " failed to prepare I/O pad: %d \n " , err ) ;
2016-10-10 16:14:34 +03:00
goto unlock ;
2015-08-04 16:25:03 +03:00
}
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , IO_DPD_REQ_CODE_ON | mask , request ) ;
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
err = tegra_io_pad_poll ( pmc , status , mask , mask , 250 ) ;
2016-10-10 16:14:34 +03:00
if ( err < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( pmc - > dev , " failed to disable I/O pad: %d \n " , err ) ;
2016-10-10 16:14:34 +03:00
goto unlock ;
}
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
tegra_io_pad_unprepare ( pmc ) ;
2014-07-11 15:19:06 +04:00
2016-10-10 16:14:34 +03:00
unlock :
2016-02-11 21:03:21 +03:00
mutex_unlock ( & pmc - > powergates_lock ) ;
return err ;
2014-07-11 15:19:06 +04:00
}
2016-10-10 16:14:34 +03:00
EXPORT_SYMBOL ( tegra_io_pad_power_disable ) ;
2019-01-25 13:22:52 +03:00
static int tegra_io_pad_is_powered ( struct tegra_pmc * pmc , enum tegra_io_pad id )
2018-08-10 21:08:09 +03:00
{
2022-09-30 19:02:13 +03:00
const struct tegra_io_pad_soc * pad ;
unsigned long status ;
2018-08-10 21:08:09 +03:00
u32 mask , value ;
2022-09-30 19:02:13 +03:00
pad = tegra_io_pad_find ( pmc , id ) ;
if ( ! pad ) {
dev_err ( pmc - > dev , " invalid I/O pad ID %u \n " , id ) ;
return - ENOENT ;
}
if ( pad - > dpd = = UINT_MAX )
return - EINVAL ;
status = pad - > status ;
mask = BIT ( pad - > dpd ) ;
2018-08-10 21:08:09 +03:00
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , status ) ;
2018-08-10 21:08:09 +03:00
return ! ( value & mask ) ;
}
2019-01-25 13:22:52 +03:00
static int tegra_io_pad_set_voltage ( struct tegra_pmc * pmc , enum tegra_io_pad id ,
int voltage )
2016-10-10 16:14:34 +03:00
{
const struct tegra_io_pad_soc * pad ;
u32 value ;
pad = tegra_io_pad_find ( pmc , id ) ;
if ( ! pad )
return - ENOENT ;
if ( pad - > voltage = = UINT_MAX )
return - ENOTSUPP ;
mutex_lock ( & pmc - > powergates_lock ) ;
2018-08-10 21:08:07 +03:00
if ( pmc - > soc - > has_impl_33v_pwr ) {
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_IMPL_E_33V_PWR ) ;
2016-10-10 16:14:34 +03:00
2018-08-10 21:08:11 +03:00
if ( voltage = = TEGRA_IO_PAD_VOLTAGE_1V8 )
2018-08-10 21:08:07 +03:00
value & = ~ BIT ( pad - > voltage ) ;
else
value | = BIT ( pad - > voltage ) ;
2016-10-10 16:14:34 +03:00
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_IMPL_E_33V_PWR ) ;
2018-08-10 21:08:07 +03:00
} else {
/* write-enable PMC_PWR_DET_VALUE[pad->voltage] */
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_PWR_DET ) ;
2016-10-10 16:14:34 +03:00
value | = BIT ( pad - > voltage ) ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_PWR_DET ) ;
2016-10-10 16:14:34 +03:00
2018-08-10 21:08:07 +03:00
/* update I/O voltage */
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_PWR_DET_VALUE ) ;
2016-10-10 16:14:34 +03:00
2018-08-10 21:08:11 +03:00
if ( voltage = = TEGRA_IO_PAD_VOLTAGE_1V8 )
2018-08-10 21:08:07 +03:00
value & = ~ BIT ( pad - > voltage ) ;
else
value | = BIT ( pad - > voltage ) ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_PWR_DET_VALUE ) ;
2018-08-10 21:08:07 +03:00
}
2016-10-10 16:14:34 +03:00
mutex_unlock ( & pmc - > powergates_lock ) ;
usleep_range ( 100 , 250 ) ;
return 0 ;
}
2019-01-25 13:22:52 +03:00
static int tegra_io_pad_get_voltage ( struct tegra_pmc * pmc , enum tegra_io_pad id )
2016-10-10 16:14:34 +03:00
{
const struct tegra_io_pad_soc * pad ;
u32 value ;
pad = tegra_io_pad_find ( pmc , id ) ;
if ( ! pad )
return - ENOENT ;
if ( pad - > voltage = = UINT_MAX )
return - ENOTSUPP ;
2018-08-10 21:08:07 +03:00
if ( pmc - > soc - > has_impl_33v_pwr )
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_IMPL_E_33V_PWR ) ;
2018-08-10 21:08:07 +03:00
else
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_PWR_DET_VALUE ) ;
2016-10-10 16:14:34 +03:00
if ( ( value & BIT ( pad - > voltage ) ) = = 0 )
2018-08-10 21:08:11 +03:00
return TEGRA_IO_PAD_VOLTAGE_1V8 ;
2016-10-10 16:14:34 +03:00
2018-08-10 21:08:11 +03:00
return TEGRA_IO_PAD_VOLTAGE_3V3 ;
2016-10-10 16:14:34 +03:00
}
/**
* tegra_io_rail_power_on ( ) - enable power to I / O rail
* @ id : Tegra I / O pad ID for which to enable power
*
* See also : tegra_io_pad_power_enable ( )
*/
int tegra_io_rail_power_on ( unsigned int id )
{
return tegra_io_pad_power_enable ( id ) ;
}
EXPORT_SYMBOL ( tegra_io_rail_power_on ) ;
/**
* tegra_io_rail_power_off ( ) - disable power to I / O rail
* @ id : Tegra I / O pad ID for which to disable power
*
* See also : tegra_io_pad_power_disable ( )
*/
int tegra_io_rail_power_off ( unsigned int id )
{
return tegra_io_pad_power_disable ( id ) ;
}
2014-07-11 15:19:06 +04:00
EXPORT_SYMBOL ( tegra_io_rail_power_off ) ;
# ifdef CONFIG_PM_SLEEP
enum tegra_suspend_mode tegra_pmc_get_suspend_mode ( void )
{
return pmc - > suspend_mode ;
}
void tegra_pmc_set_suspend_mode ( enum tegra_suspend_mode mode )
{
if ( mode < TEGRA_SUSPEND_NONE | | mode > = TEGRA_MAX_SUSPEND_MODE )
return ;
pmc - > suspend_mode = mode ;
}
void tegra_pmc_enter_suspend_mode ( enum tegra_suspend_mode mode )
{
unsigned long long rate = 0 ;
2019-09-26 22:17:54 +03:00
u64 ticks ;
2014-07-11 15:19:06 +04:00
u32 value ;
switch ( mode ) {
case TEGRA_SUSPEND_LP1 :
rate = 32768 ;
break ;
case TEGRA_SUSPEND_LP2 :
2019-09-26 22:17:54 +03:00
rate = pmc - > rate ;
2014-07-11 15:19:06 +04:00
break ;
default :
break ;
}
if ( WARN_ON_ONCE ( rate = = 0 ) )
rate = 100000000 ;
2019-09-26 22:17:54 +03:00
ticks = pmc - > cpu_good_time * rate + USEC_PER_SEC - 1 ;
do_div ( ticks , USEC_PER_SEC ) ;
tegra_pmc_writel ( pmc , ticks , PMC_CPUPWRGOOD_TIMER ) ;
2014-07-11 15:19:06 +04:00
2019-09-26 22:17:54 +03:00
ticks = pmc - > cpu_off_time * rate + USEC_PER_SEC - 1 ;
do_div ( ticks , USEC_PER_SEC ) ;
tegra_pmc_writel ( pmc , ticks , PMC_CPUPWROFF_TIMER ) ;
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_CNTRL ) ;
2014-07-11 15:19:06 +04:00
value & = ~ PMC_CNTRL_SIDE_EFFECT_LP0 ;
value | = PMC_CNTRL_CPU_PWRREQ_OE ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_CNTRL ) ;
2014-07-11 15:19:06 +04:00
}
# endif
static int tegra_pmc_parse_dt ( struct tegra_pmc * pmc , struct device_node * np )
{
u32 value , values [ 2 ] ;
if ( of_property_read_u32 ( np , " nvidia,suspend-mode " , & value ) ) {
2021-07-19 00:27:05 +03:00
pmc - > suspend_mode = TEGRA_SUSPEND_NONE ;
2014-07-11 15:19:06 +04:00
} else {
switch ( value ) {
case 0 :
pmc - > suspend_mode = TEGRA_SUSPEND_LP0 ;
break ;
case 1 :
pmc - > suspend_mode = TEGRA_SUSPEND_LP1 ;
break ;
case 2 :
pmc - > suspend_mode = TEGRA_SUSPEND_LP2 ;
break ;
default :
pmc - > suspend_mode = TEGRA_SUSPEND_NONE ;
break ;
}
}
pmc - > suspend_mode = tegra_pm_validate_suspend_mode ( pmc - > suspend_mode ) ;
if ( of_property_read_u32 ( np , " nvidia,cpu-pwr-good-time " , & value ) )
pmc - > suspend_mode = TEGRA_SUSPEND_NONE ;
pmc - > cpu_good_time = value ;
if ( of_property_read_u32 ( np , " nvidia,cpu-pwr-off-time " , & value ) )
pmc - > suspend_mode = TEGRA_SUSPEND_NONE ;
pmc - > cpu_off_time = value ;
if ( of_property_read_u32_array ( np , " nvidia,core-pwr-good-time " ,
values , ARRAY_SIZE ( values ) ) )
pmc - > suspend_mode = TEGRA_SUSPEND_NONE ;
pmc - > core_osc_time = values [ 0 ] ;
pmc - > core_pmu_time = values [ 1 ] ;
if ( of_property_read_u32 ( np , " nvidia,core-pwr-off-time " , & value ) )
pmc - > suspend_mode = TEGRA_SUSPEND_NONE ;
pmc - > core_off_time = value ;
pmc - > corereq_high = of_property_read_bool ( np ,
" nvidia,core-power-req-active-high " ) ;
pmc - > sysclkreq_high = of_property_read_bool ( np ,
" nvidia,sys-clock-req-active-high " ) ;
pmc - > combined_req = of_property_read_bool ( np ,
" nvidia,combined-power-req " ) ;
pmc - > cpu_pwr_good_en = of_property_read_bool ( np ,
" nvidia,cpu-pwr-good-en " ) ;
if ( of_property_read_u32_array ( np , " nvidia,lp0-vec " , values ,
ARRAY_SIZE ( values ) ) )
if ( pmc - > suspend_mode = = TEGRA_SUSPEND_LP0 )
pmc - > suspend_mode = TEGRA_SUSPEND_LP1 ;
pmc - > lp0_vec_phys = values [ 0 ] ;
pmc - > lp0_vec_size = values [ 1 ] ;
return 0 ;
}
2022-09-30 19:14:52 +03:00
static int tegra_pmc_init ( struct tegra_pmc * pmc )
2014-07-11 15:19:06 +04:00
{
2022-09-30 19:14:52 +03:00
if ( pmc - > soc - > max_wake_events > 0 ) {
pmc - > wake_type_level_map = bitmap_zalloc ( pmc - > soc - > max_wake_events , GFP_KERNEL ) ;
if ( ! pmc - > wake_type_level_map )
return - ENOMEM ;
pmc - > wake_type_dual_edge_map = bitmap_zalloc ( pmc - > soc - > max_wake_events , GFP_KERNEL ) ;
if ( ! pmc - > wake_type_dual_edge_map )
return - ENOMEM ;
pmc - > wake_sw_status_map = bitmap_zalloc ( pmc - > soc - > max_wake_events , GFP_KERNEL ) ;
if ( ! pmc - > wake_sw_status_map )
return - ENOMEM ;
pmc - > wake_cntrl_level_map = bitmap_zalloc ( pmc - > soc - > max_wake_events , GFP_KERNEL ) ;
if ( ! pmc - > wake_cntrl_level_map )
return - ENOMEM ;
}
2017-08-30 13:32:58 +03:00
if ( pmc - > soc - > init )
pmc - > soc - > init ( pmc ) ;
2022-09-30 19:14:52 +03:00
return 0 ;
2014-07-11 15:19:06 +04:00
}
2015-12-04 17:57:04 +03:00
static void tegra_pmc_init_tsense_reset ( struct tegra_pmc * pmc )
2015-01-06 13:52:58 +03:00
{
static const char disabled [ ] = " emergency thermal reset disabled " ;
u32 pmu_addr , ctrl_id , reg_addr , reg_data , pinmux ;
struct device * dev = pmc - > dev ;
struct device_node * np ;
u32 value , checksum ;
if ( ! pmc - > soc - > has_tsense_reset )
2015-07-09 10:59:55 +03:00
return ;
2015-01-06 13:52:58 +03:00
2017-11-15 12:44:58 +03:00
np = of_get_child_by_name ( pmc - > dev - > of_node , " i2c-thermtrip " ) ;
2015-01-06 13:52:58 +03:00
if ( ! np ) {
dev_warn ( dev , " i2c-thermtrip node not found, %s. \n " , disabled ) ;
2015-07-09 10:59:55 +03:00
return ;
2015-01-06 13:52:58 +03:00
}
if ( of_property_read_u32 ( np , " nvidia,i2c-controller-id " , & ctrl_id ) ) {
dev_err ( dev , " I2C controller ID missing, %s. \n " , disabled ) ;
goto out ;
}
if ( of_property_read_u32 ( np , " nvidia,bus-addr " , & pmu_addr ) ) {
dev_err ( dev , " nvidia,bus-addr missing, %s. \n " , disabled ) ;
goto out ;
}
if ( of_property_read_u32 ( np , " nvidia,reg-addr " , & reg_addr ) ) {
dev_err ( dev , " nvidia,reg-addr missing, %s. \n " , disabled ) ;
goto out ;
}
if ( of_property_read_u32 ( np , " nvidia,reg-data " , & reg_data ) ) {
dev_err ( dev , " nvidia,reg-data missing, %s. \n " , disabled ) ;
goto out ;
}
if ( of_property_read_u32 ( np , " nvidia,pinmux-id " , & pinmux ) )
pinmux = 0 ;
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_SENSOR_CTRL ) ;
2015-01-06 13:52:58 +03:00
value | = PMC_SENSOR_CTRL_SCRATCH_WRITE ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_SENSOR_CTRL ) ;
2015-01-06 13:52:58 +03:00
value = ( reg_data < < PMC_SCRATCH54_DATA_SHIFT ) |
( reg_addr < < PMC_SCRATCH54_ADDR_SHIFT ) ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_SCRATCH54 ) ;
2015-01-06 13:52:58 +03:00
value = PMC_SCRATCH55_RESET_TEGRA ;
value | = ctrl_id < < PMC_SCRATCH55_CNTRL_ID_SHIFT ;
value | = pinmux < < PMC_SCRATCH55_PINMUX_SHIFT ;
value | = pmu_addr < < PMC_SCRATCH55_I2CSLV1_SHIFT ;
/*
* Calculate checksum of SCRATCH54 , SCRATCH55 fields . Bits 23 : 16 will
* contain the checksum and are currently zero , so they are not added .
*/
checksum = reg_addr + reg_data + ( value & 0xff ) + ( ( value > > 8 ) & 0xff )
+ ( ( value > > 24 ) & 0xff ) ;
checksum & = 0xff ;
checksum = 0x100 - checksum ;
value | = checksum < < PMC_SCRATCH55_CHECKSUM_SHIFT ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_SCRATCH55 ) ;
2015-01-06 13:52:58 +03:00
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_SENSOR_CTRL ) ;
2015-01-06 13:52:58 +03:00
value | = PMC_SENSOR_CTRL_ENABLE_RST ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_SENSOR_CTRL ) ;
2015-01-06 13:52:58 +03:00
dev_info ( pmc - > dev , " emergency thermal reset enabled \n " ) ;
out :
of_node_put ( np ) ;
}
2018-08-10 21:08:12 +03:00
static int tegra_io_pad_pinctrl_get_groups_count ( struct pinctrl_dev * pctl_dev )
{
2019-01-25 13:22:52 +03:00
struct tegra_pmc * pmc = pinctrl_dev_get_drvdata ( pctl_dev ) ;
2018-08-10 21:08:12 +03:00
return pmc - > soc - > num_io_pads ;
}
2019-01-25 13:22:53 +03:00
static const char * tegra_io_pad_pinctrl_get_group_name ( struct pinctrl_dev * pctl ,
unsigned int group )
2018-08-10 21:08:12 +03:00
{
2019-01-25 13:22:52 +03:00
struct tegra_pmc * pmc = pinctrl_dev_get_drvdata ( pctl ) ;
2018-08-10 21:08:12 +03:00
return pmc - > soc - > io_pads [ group ] . name ;
}
static int tegra_io_pad_pinctrl_get_group_pins ( struct pinctrl_dev * pctl_dev ,
unsigned int group ,
const unsigned int * * pins ,
unsigned int * num_pins )
{
2019-01-25 13:22:52 +03:00
struct tegra_pmc * pmc = pinctrl_dev_get_drvdata ( pctl_dev ) ;
2018-08-10 21:08:12 +03:00
* pins = & pmc - > soc - > io_pads [ group ] . id ;
* num_pins = 1 ;
2019-01-25 13:22:53 +03:00
2018-08-10 21:08:12 +03:00
return 0 ;
}
static const struct pinctrl_ops tegra_io_pad_pinctrl_ops = {
. get_groups_count = tegra_io_pad_pinctrl_get_groups_count ,
. get_group_name = tegra_io_pad_pinctrl_get_group_name ,
. get_group_pins = tegra_io_pad_pinctrl_get_group_pins ,
. dt_node_to_map = pinconf_generic_dt_node_to_map_pin ,
. dt_free_map = pinconf_generic_dt_free_map ,
} ;
static int tegra_io_pad_pinconf_get ( struct pinctrl_dev * pctl_dev ,
unsigned int pin , unsigned long * config )
{
enum pin_config_param param = pinconf_to_config_param ( * config ) ;
2019-01-25 13:22:52 +03:00
struct tegra_pmc * pmc = pinctrl_dev_get_drvdata ( pctl_dev ) ;
const struct tegra_io_pad_soc * pad ;
2018-08-10 21:08:12 +03:00
int ret ;
u32 arg ;
2019-01-25 13:22:52 +03:00
pad = tegra_io_pad_find ( pmc , pin ) ;
2018-08-10 21:08:12 +03:00
if ( ! pad )
return - EINVAL ;
switch ( param ) {
case PIN_CONFIG_POWER_SOURCE :
2019-01-25 13:22:52 +03:00
ret = tegra_io_pad_get_voltage ( pmc , pad - > id ) ;
2018-08-10 21:08:12 +03:00
if ( ret < 0 )
return ret ;
2019-01-25 13:22:53 +03:00
2018-08-10 21:08:12 +03:00
arg = ret ;
break ;
2019-01-25 13:22:53 +03:00
2021-04-12 17:07:40 +03:00
case PIN_CONFIG_MODE_LOW_POWER :
2019-01-25 13:22:52 +03:00
ret = tegra_io_pad_is_powered ( pmc , pad - > id ) ;
2018-08-10 21:08:12 +03:00
if ( ret < 0 )
return ret ;
2019-01-25 13:22:53 +03:00
2018-08-10 21:08:12 +03:00
arg = ! ret ;
break ;
2019-01-25 13:22:53 +03:00
2018-08-10 21:08:12 +03:00
default :
return - EINVAL ;
}
* config = pinconf_to_config_packed ( param , arg ) ;
return 0 ;
}
static int tegra_io_pad_pinconf_set ( struct pinctrl_dev * pctl_dev ,
unsigned int pin , unsigned long * configs ,
unsigned int num_configs )
{
2019-01-25 13:22:52 +03:00
struct tegra_pmc * pmc = pinctrl_dev_get_drvdata ( pctl_dev ) ;
const struct tegra_io_pad_soc * pad ;
2018-08-10 21:08:12 +03:00
enum pin_config_param param ;
unsigned int i ;
int err ;
u32 arg ;
2019-01-25 13:22:52 +03:00
pad = tegra_io_pad_find ( pmc , pin ) ;
2018-08-10 21:08:12 +03:00
if ( ! pad )
return - EINVAL ;
for ( i = 0 ; i < num_configs ; + + i ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
arg = pinconf_to_config_argument ( configs [ i ] ) ;
switch ( param ) {
2021-04-12 17:07:40 +03:00
case PIN_CONFIG_MODE_LOW_POWER :
2018-08-10 21:08:12 +03:00
if ( arg )
err = tegra_io_pad_power_disable ( pad - > id ) ;
else
err = tegra_io_pad_power_enable ( pad - > id ) ;
if ( err )
return err ;
break ;
case PIN_CONFIG_POWER_SOURCE :
if ( arg ! = TEGRA_IO_PAD_VOLTAGE_1V8 & &
arg ! = TEGRA_IO_PAD_VOLTAGE_3V3 )
return - EINVAL ;
2019-01-25 13:22:52 +03:00
err = tegra_io_pad_set_voltage ( pmc , pad - > id , arg ) ;
2018-08-10 21:08:12 +03:00
if ( err )
return err ;
break ;
default :
return - EINVAL ;
}
}
return 0 ;
}
static const struct pinconf_ops tegra_io_pad_pinconf_ops = {
. pin_config_get = tegra_io_pad_pinconf_get ,
. pin_config_set = tegra_io_pad_pinconf_set ,
. is_generic = true ,
} ;
static struct pinctrl_desc tegra_pmc_pctl_desc = {
. pctlops = & tegra_io_pad_pinctrl_ops ,
. confops = & tegra_io_pad_pinconf_ops ,
} ;
static int tegra_pmc_pinctrl_init ( struct tegra_pmc * pmc )
{
2019-01-25 13:22:53 +03:00
int err ;
2018-08-10 21:08:12 +03:00
if ( ! pmc - > soc - > num_pin_descs )
return 0 ;
tegra_pmc_pctl_desc . name = dev_name ( pmc - > dev ) ;
tegra_pmc_pctl_desc . pins = pmc - > soc - > pin_descs ;
tegra_pmc_pctl_desc . npins = pmc - > soc - > num_pin_descs ;
pmc - > pctl_dev = devm_pinctrl_register ( pmc - > dev , & tegra_pmc_pctl_desc ,
pmc ) ;
if ( IS_ERR ( pmc - > pctl_dev ) ) {
err = PTR_ERR ( pmc - > pctl_dev ) ;
2019-01-25 13:22:53 +03:00
dev_err ( pmc - > dev , " failed to register pin controller: %d \n " ,
err ) ;
return err ;
2018-08-10 21:08:12 +03:00
}
2019-01-25 13:22:53 +03:00
return 0 ;
2018-08-10 21:08:12 +03:00
}
2018-10-24 10:08:00 +03:00
static ssize_t reset_reason_show ( struct device * dev ,
2019-01-25 13:22:53 +03:00
struct device_attribute * attr , char * buf )
2018-10-24 10:08:00 +03:00
{
2019-04-16 19:48:06 +03:00
u32 value ;
2018-10-24 10:08:00 +03:00
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , pmc - > soc - > regs - > rst_status ) ;
2019-04-16 19:48:06 +03:00
value & = pmc - > soc - > regs - > rst_source_mask ;
value > > = pmc - > soc - > regs - > rst_source_shift ;
if ( WARN_ON ( value > = pmc - > soc - > num_reset_sources ) )
return sprintf ( buf , " %s \n " , " UNKNOWN " ) ;
2018-10-24 10:08:00 +03:00
2019-04-16 19:48:06 +03:00
return sprintf ( buf , " %s \n " , pmc - > soc - > reset_sources [ value ] ) ;
2018-10-24 10:08:00 +03:00
}
static DEVICE_ATTR_RO ( reset_reason ) ;
static ssize_t reset_level_show ( struct device * dev ,
2019-01-25 13:22:53 +03:00
struct device_attribute * attr , char * buf )
2018-10-24 10:08:00 +03:00
{
2019-04-16 19:48:06 +03:00
u32 value ;
2018-10-24 10:08:00 +03:00
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , pmc - > soc - > regs - > rst_status ) ;
2019-04-16 19:48:06 +03:00
value & = pmc - > soc - > regs - > rst_level_mask ;
value > > = pmc - > soc - > regs - > rst_level_shift ;
2018-10-24 10:08:00 +03:00
2019-04-16 19:48:06 +03:00
if ( WARN_ON ( value > = pmc - > soc - > num_reset_levels ) )
return sprintf ( buf , " %s \n " , " UNKNOWN " ) ;
return sprintf ( buf , " %s \n " , pmc - > soc - > reset_levels [ value ] ) ;
2018-10-24 10:08:00 +03:00
}
static DEVICE_ATTR_RO ( reset_level ) ;
static void tegra_pmc_reset_sysfs_init ( struct tegra_pmc * pmc )
{
struct device * dev = pmc - > dev ;
int err = 0 ;
if ( pmc - > soc - > reset_sources ) {
err = device_create_file ( dev , & dev_attr_reset_reason ) ;
if ( err < 0 )
dev_warn ( dev ,
2019-01-25 13:22:53 +03:00
" failed to create attr \" reset_reason \" : %d \n " ,
err ) ;
2018-10-24 10:08:00 +03:00
}
if ( pmc - > soc - > reset_levels ) {
err = device_create_file ( dev , & dev_attr_reset_level ) ;
if ( err < 0 )
dev_warn ( dev ,
2019-01-25 13:22:53 +03:00
" failed to create attr \" reset_level \" : %d \n " ,
err ) ;
2018-10-24 10:08:00 +03:00
}
}
2018-09-17 16:08:17 +03:00
static int tegra_pmc_irq_translate ( struct irq_domain * domain ,
struct irq_fwspec * fwspec ,
unsigned long * hwirq ,
unsigned int * type )
{
if ( WARN_ON ( fwspec - > param_count < 2 ) )
return - EINVAL ;
* hwirq = fwspec - > param [ 0 ] ;
* type = fwspec - > param [ 1 ] ;
return 0 ;
}
static int tegra_pmc_irq_alloc ( struct irq_domain * domain , unsigned int virq ,
unsigned int num_irqs , void * data )
{
struct tegra_pmc * pmc = domain - > host_data ;
const struct tegra_pmc_soc * soc = pmc - > soc ;
struct irq_fwspec * fwspec = data ;
unsigned int i ;
int err = 0 ;
2019-05-27 13:15:12 +03:00
if ( WARN_ON ( num_irqs > 1 ) )
return - EINVAL ;
2018-09-17 16:08:17 +03:00
for ( i = 0 ; i < soc - > num_wake_events ; i + + ) {
const struct tegra_wake_event * event = & soc - > wake_events [ i ] ;
2022-07-11 18:40:30 +03:00
/* IRQ and simple wake events */
2018-09-17 16:08:17 +03:00
if ( fwspec - > param_count = = 2 ) {
struct irq_fwspec spec ;
if ( event - > id ! = fwspec - > param [ 0 ] )
continue ;
err = irq_domain_set_hwirq_and_chip ( domain , virq ,
event - > id ,
& pmc - > irq , pmc ) ;
if ( err < 0 )
break ;
2022-07-11 18:40:30 +03:00
/* simple hierarchies stop at the PMC level */
if ( event - > irq = = 0 ) {
err = irq_domain_disconnect_hierarchy ( domain - > parent , virq ) ;
break ;
}
2018-09-17 16:08:17 +03:00
spec . fwnode = & pmc - > dev - > of_node - > fwnode ;
spec . param_count = 3 ;
spec . param [ 0 ] = GIC_SPI ;
spec . param [ 1 ] = event - > irq ;
spec . param [ 2 ] = fwspec - > param [ 1 ] ;
err = irq_domain_alloc_irqs_parent ( domain , virq ,
num_irqs , & spec ) ;
break ;
}
2022-07-11 18:40:30 +03:00
/* GPIO wake events */
2018-09-17 16:08:17 +03:00
if ( fwspec - > param_count = = 3 ) {
if ( event - > gpio . instance ! = fwspec - > param [ 0 ] | |
event - > gpio . pin ! = fwspec - > param [ 1 ] )
continue ;
err = irq_domain_set_hwirq_and_chip ( domain , virq ,
event - > id ,
& pmc - > irq , pmc ) ;
2020-10-04 20:27:04 +03:00
/* GPIO hierarchies stop at the PMC level */
if ( ! err & & domain - > parent )
2022-07-11 18:40:29 +03:00
err = irq_domain_disconnect_hierarchy ( domain - > parent ,
2020-10-04 20:27:04 +03:00
virq ) ;
2018-09-17 16:08:17 +03:00
break ;
}
}
2020-10-04 20:27:04 +03:00
/* If there is no wake-up event, there is no PMC mapping */
if ( i = = soc - > num_wake_events )
err = irq_domain_disconnect_hierarchy ( domain , virq ) ;
2019-10-01 14:48:29 +03:00
2018-09-17 16:08:17 +03:00
return err ;
}
static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
. translate = tegra_pmc_irq_translate ,
. alloc = tegra_pmc_irq_alloc ,
} ;
2019-08-16 22:42:02 +03:00
static int tegra210_pmc_irq_set_wake ( struct irq_data * data , unsigned int on )
{
struct tegra_pmc * pmc = irq_data_get_irq_chip_data ( data ) ;
unsigned int offset , bit ;
u32 value ;
offset = data - > hwirq / 32 ;
bit = data - > hwirq % 32 ;
/* clear wake status */
tegra_pmc_writel ( pmc , 0 , PMC_SW_WAKE_STATUS ) ;
tegra_pmc_writel ( pmc , 0 , PMC_SW_WAKE2_STATUS ) ;
tegra_pmc_writel ( pmc , 0 , PMC_WAKE_STATUS ) ;
tegra_pmc_writel ( pmc , 0 , PMC_WAKE2_STATUS ) ;
/* enable PMC wake */
if ( data - > hwirq > = 32 )
offset = PMC_WAKE2_MASK ;
else
offset = PMC_WAKE_MASK ;
value = tegra_pmc_readl ( pmc , offset ) ;
if ( on )
value | = BIT ( bit ) ;
else
value & = ~ BIT ( bit ) ;
tegra_pmc_writel ( pmc , value , offset ) ;
return 0 ;
}
static int tegra210_pmc_irq_set_type ( struct irq_data * data , unsigned int type )
{
struct tegra_pmc * pmc = irq_data_get_irq_chip_data ( data ) ;
unsigned int offset , bit ;
u32 value ;
offset = data - > hwirq / 32 ;
bit = data - > hwirq % 32 ;
if ( data - > hwirq > = 32 )
offset = PMC_WAKE2_LEVEL ;
else
offset = PMC_WAKE_LEVEL ;
value = tegra_pmc_readl ( pmc , offset ) ;
switch ( type ) {
case IRQ_TYPE_EDGE_RISING :
case IRQ_TYPE_LEVEL_HIGH :
value | = BIT ( bit ) ;
break ;
case IRQ_TYPE_EDGE_FALLING :
case IRQ_TYPE_LEVEL_LOW :
value & = ~ BIT ( bit ) ;
break ;
case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING :
value ^ = BIT ( bit ) ;
break ;
default :
return - EINVAL ;
}
tegra_pmc_writel ( pmc , value , offset ) ;
return 0 ;
}
2023-03-30 20:06:21 +03:00
static void tegra186_pmc_set_wake_filters ( struct tegra_pmc * pmc )
{
u32 value ;
/* SW Wake (wake83) needs SR_CAPTURE filter to be enabled */
value = readl ( pmc - > wake + WAKE_AOWAKE_CNTRL ( SW_WAKE_ID ) ) ;
value | = WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN ;
writel ( value , pmc - > wake + WAKE_AOWAKE_CNTRL ( SW_WAKE_ID ) ) ;
dev_dbg ( pmc - > dev , " WAKE_AOWAKE_CNTRL_83 = 0x%x \n " , value ) ;
}
2019-08-16 22:42:01 +03:00
static int tegra186_pmc_irq_set_wake ( struct irq_data * data , unsigned int on )
2018-09-17 16:08:17 +03:00
{
struct tegra_pmc * pmc = irq_data_get_irq_chip_data ( data ) ;
unsigned int offset , bit ;
u32 value ;
offset = data - > hwirq / 32 ;
bit = data - > hwirq % 32 ;
/* clear wake status */
writel ( 0x1 , pmc - > wake + WAKE_AOWAKE_STATUS_W ( data - > hwirq ) ) ;
/* route wake to tier 2 */
value = readl ( pmc - > wake + WAKE_AOWAKE_TIER2_ROUTING ( offset ) ) ;
if ( ! on )
value & = ~ ( 1 < < bit ) ;
else
value | = 1 < < bit ;
writel ( value , pmc - > wake + WAKE_AOWAKE_TIER2_ROUTING ( offset ) ) ;
/* enable wakeup event */
writel ( ! ! on , pmc - > wake + WAKE_AOWAKE_MASK_W ( data - > hwirq ) ) ;
return 0 ;
}
2019-08-16 22:42:01 +03:00
static int tegra186_pmc_irq_set_type ( struct irq_data * data , unsigned int type )
2018-09-17 16:08:17 +03:00
{
struct tegra_pmc * pmc = irq_data_get_irq_chip_data ( data ) ;
u32 value ;
value = readl ( pmc - > wake + WAKE_AOWAKE_CNTRL ( data - > hwirq ) ) ;
switch ( type ) {
case IRQ_TYPE_EDGE_RISING :
case IRQ_TYPE_LEVEL_HIGH :
value | = WAKE_AOWAKE_CNTRL_LEVEL ;
2022-09-30 19:14:52 +03:00
set_bit ( data - > hwirq , pmc - > wake_type_level_map ) ;
clear_bit ( data - > hwirq , pmc - > wake_type_dual_edge_map ) ;
2018-09-17 16:08:17 +03:00
break ;
case IRQ_TYPE_EDGE_FALLING :
case IRQ_TYPE_LEVEL_LOW :
value & = ~ WAKE_AOWAKE_CNTRL_LEVEL ;
2022-09-30 19:14:52 +03:00
clear_bit ( data - > hwirq , pmc - > wake_type_level_map ) ;
clear_bit ( data - > hwirq , pmc - > wake_type_dual_edge_map ) ;
2018-09-17 16:08:17 +03:00
break ;
case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING :
value ^ = WAKE_AOWAKE_CNTRL_LEVEL ;
2022-09-30 19:14:52 +03:00
clear_bit ( data - > hwirq , pmc - > wake_type_level_map ) ;
set_bit ( data - > hwirq , pmc - > wake_type_dual_edge_map ) ;
2018-09-17 16:08:17 +03:00
break ;
default :
return - EINVAL ;
}
writel ( value , pmc - > wake + WAKE_AOWAKE_CNTRL ( data - > hwirq ) ) ;
return 0 ;
}
2020-10-04 23:16:24 +03:00
static void tegra_irq_mask_parent ( struct irq_data * data )
{
if ( data - > parent_data )
irq_chip_mask_parent ( data ) ;
}
static void tegra_irq_unmask_parent ( struct irq_data * data )
{
if ( data - > parent_data )
irq_chip_unmask_parent ( data ) ;
}
static void tegra_irq_eoi_parent ( struct irq_data * data )
{
if ( data - > parent_data )
irq_chip_eoi_parent ( data ) ;
}
static int tegra_irq_set_affinity_parent ( struct irq_data * data ,
const struct cpumask * dest ,
bool force )
{
if ( data - > parent_data )
return irq_chip_set_affinity_parent ( data , dest , force ) ;
return - EINVAL ;
}
2018-09-17 16:08:17 +03:00
static int tegra_pmc_irq_init ( struct tegra_pmc * pmc )
{
struct irq_domain * parent = NULL ;
struct device_node * np ;
np = of_irq_find_parent ( pmc - > dev - > of_node ) ;
if ( np ) {
parent = irq_find_host ( np ) ;
of_node_put ( np ) ;
}
if ( ! parent )
return 0 ;
pmc - > irq . name = dev_name ( pmc - > dev ) ;
2020-10-04 23:16:24 +03:00
pmc - > irq . irq_mask = tegra_irq_mask_parent ;
pmc - > irq . irq_unmask = tegra_irq_unmask_parent ;
pmc - > irq . irq_eoi = tegra_irq_eoi_parent ;
pmc - > irq . irq_set_affinity = tegra_irq_set_affinity_parent ;
2019-08-16 22:42:01 +03:00
pmc - > irq . irq_set_type = pmc - > soc - > irq_set_type ;
pmc - > irq . irq_set_wake = pmc - > soc - > irq_set_wake ;
2018-09-17 16:08:17 +03:00
pmc - > domain = irq_domain_add_hierarchy ( parent , 0 , 96 , pmc - > dev - > of_node ,
& tegra_pmc_irq_domain_ops , pmc ) ;
if ( ! pmc - > domain ) {
dev_err ( pmc - > dev , " failed to allocate domain \n " ) ;
return - ENOMEM ;
}
return 0 ;
}
2019-09-26 22:17:54 +03:00
static int tegra_pmc_clk_notify_cb ( struct notifier_block * nb ,
unsigned long action , void * ptr )
{
struct tegra_pmc * pmc = container_of ( nb , struct tegra_pmc , clk_nb ) ;
struct clk_notifier_data * data = ptr ;
switch ( action ) {
case PRE_RATE_CHANGE :
mutex_lock ( & pmc - > powergates_lock ) ;
break ;
case POST_RATE_CHANGE :
pmc - > rate = data - > new_rate ;
2020-08-24 01:36:59 +03:00
fallthrough ;
2019-09-26 22:17:54 +03:00
case ABORT_RATE_CHANGE :
mutex_unlock ( & pmc - > powergates_lock ) ;
break ;
default :
WARN_ON_ONCE ( 1 ) ;
return notifier_from_errno ( - EINVAL ) ;
}
return NOTIFY_OK ;
}
2020-01-14 10:24:13 +03:00
static void pmc_clk_fence_udelay ( u32 offset )
{
tegra_pmc_readl ( pmc , offset ) ;
/* pmc clk propagation delay 2 us */
udelay ( 2 ) ;
}
static u8 pmc_clk_mux_get_parent ( struct clk_hw * hw )
{
struct pmc_clk * clk = to_pmc_clk ( hw ) ;
u32 val ;
val = tegra_pmc_readl ( pmc , clk - > offs ) > > clk - > mux_shift ;
val & = PMC_CLK_OUT_MUX_MASK ;
return val ;
}
static int pmc_clk_mux_set_parent ( struct clk_hw * hw , u8 index )
{
struct pmc_clk * clk = to_pmc_clk ( hw ) ;
u32 val ;
val = tegra_pmc_readl ( pmc , clk - > offs ) ;
val & = ~ ( PMC_CLK_OUT_MUX_MASK < < clk - > mux_shift ) ;
val | = index < < clk - > mux_shift ;
tegra_pmc_writel ( pmc , val , clk - > offs ) ;
pmc_clk_fence_udelay ( clk - > offs ) ;
return 0 ;
}
static int pmc_clk_is_enabled ( struct clk_hw * hw )
{
struct pmc_clk * clk = to_pmc_clk ( hw ) ;
u32 val ;
val = tegra_pmc_readl ( pmc , clk - > offs ) & BIT ( clk - > force_en_shift ) ;
return val ? 1 : 0 ;
}
static void pmc_clk_set_state ( unsigned long offs , u32 shift , int state )
{
u32 val ;
val = tegra_pmc_readl ( pmc , offs ) ;
val = state ? ( val | BIT ( shift ) ) : ( val & ~ BIT ( shift ) ) ;
tegra_pmc_writel ( pmc , val , offs ) ;
pmc_clk_fence_udelay ( offs ) ;
}
static int pmc_clk_enable ( struct clk_hw * hw )
{
struct pmc_clk * clk = to_pmc_clk ( hw ) ;
pmc_clk_set_state ( clk - > offs , clk - > force_en_shift , 1 ) ;
return 0 ;
}
static void pmc_clk_disable ( struct clk_hw * hw )
{
struct pmc_clk * clk = to_pmc_clk ( hw ) ;
pmc_clk_set_state ( clk - > offs , clk - > force_en_shift , 0 ) ;
}
static const struct clk_ops pmc_clk_ops = {
. get_parent = pmc_clk_mux_get_parent ,
. set_parent = pmc_clk_mux_set_parent ,
. determine_rate = __clk_mux_determine_rate ,
. is_enabled = pmc_clk_is_enabled ,
. enable = pmc_clk_enable ,
. disable = pmc_clk_disable ,
} ;
static struct clk *
tegra_pmc_clk_out_register ( struct tegra_pmc * pmc ,
const struct pmc_clk_init_data * data ,
unsigned long offset )
{
struct clk_init_data init ;
struct pmc_clk * pmc_clk ;
pmc_clk = devm_kzalloc ( pmc - > dev , sizeof ( * pmc_clk ) , GFP_KERNEL ) ;
if ( ! pmc_clk )
return ERR_PTR ( - ENOMEM ) ;
init . name = data - > name ;
init . ops = & pmc_clk_ops ;
init . parent_names = data - > parents ;
init . num_parents = data - > num_parents ;
init . flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT |
CLK_SET_PARENT_GATE ;
pmc_clk - > hw . init = & init ;
pmc_clk - > offs = offset ;
pmc_clk - > mux_shift = data - > mux_shift ;
pmc_clk - > force_en_shift = data - > force_en_shift ;
return clk_register ( NULL , & pmc_clk - > hw ) ;
}
2020-01-14 10:24:15 +03:00
static int pmc_clk_gate_is_enabled ( struct clk_hw * hw )
{
struct pmc_clk_gate * gate = to_pmc_clk_gate ( hw ) ;
return tegra_pmc_readl ( pmc , gate - > offs ) & BIT ( gate - > shift ) ? 1 : 0 ;
}
static int pmc_clk_gate_enable ( struct clk_hw * hw )
{
struct pmc_clk_gate * gate = to_pmc_clk_gate ( hw ) ;
pmc_clk_set_state ( gate - > offs , gate - > shift , 1 ) ;
return 0 ;
}
static void pmc_clk_gate_disable ( struct clk_hw * hw )
{
struct pmc_clk_gate * gate = to_pmc_clk_gate ( hw ) ;
pmc_clk_set_state ( gate - > offs , gate - > shift , 0 ) ;
}
static const struct clk_ops pmc_clk_gate_ops = {
. is_enabled = pmc_clk_gate_is_enabled ,
. enable = pmc_clk_gate_enable ,
. disable = pmc_clk_gate_disable ,
} ;
static struct clk *
tegra_pmc_clk_gate_register ( struct tegra_pmc * pmc , const char * name ,
const char * parent_name , unsigned long offset ,
u32 shift )
{
struct clk_init_data init ;
struct pmc_clk_gate * gate ;
gate = devm_kzalloc ( pmc - > dev , sizeof ( * gate ) , GFP_KERNEL ) ;
if ( ! gate )
return ERR_PTR ( - ENOMEM ) ;
init . name = name ;
init . ops = & pmc_clk_gate_ops ;
init . parent_names = & parent_name ;
init . num_parents = 1 ;
init . flags = 0 ;
gate - > hw . init = & init ;
gate - > offs = offset ;
gate - > shift = shift ;
return clk_register ( NULL , & gate - > hw ) ;
}
2020-01-14 10:24:13 +03:00
static void tegra_pmc_clock_register ( struct tegra_pmc * pmc ,
struct device_node * np )
{
struct clk * clk ;
struct clk_onecell_data * clk_data ;
unsigned int num_clks ;
int i , err ;
num_clks = pmc - > soc - > num_pmc_clks ;
2020-01-14 10:24:15 +03:00
if ( pmc - > soc - > has_blink_output )
num_clks + = 1 ;
2020-01-14 10:24:13 +03:00
if ( ! num_clks )
return ;
clk_data = devm_kmalloc ( pmc - > dev , sizeof ( * clk_data ) , GFP_KERNEL ) ;
if ( ! clk_data )
return ;
clk_data - > clks = devm_kcalloc ( pmc - > dev , TEGRA_PMC_CLK_MAX ,
sizeof ( * clk_data - > clks ) , GFP_KERNEL ) ;
if ( ! clk_data - > clks )
return ;
clk_data - > clk_num = TEGRA_PMC_CLK_MAX ;
for ( i = 0 ; i < TEGRA_PMC_CLK_MAX ; i + + )
clk_data - > clks [ i ] = ERR_PTR ( - ENOENT ) ;
for ( i = 0 ; i < pmc - > soc - > num_pmc_clks ; i + + ) {
const struct pmc_clk_init_data * data ;
data = pmc - > soc - > pmc_clks_data + i ;
clk = tegra_pmc_clk_out_register ( pmc , data , PMC_CLK_OUT_CNTRL ) ;
if ( IS_ERR ( clk ) ) {
dev_warn ( pmc - > dev , " unable to register clock %s: %d \n " ,
data - > name , PTR_ERR_OR_ZERO ( clk ) ) ;
return ;
}
err = clk_register_clkdev ( clk , data - > name , NULL ) ;
if ( err ) {
dev_warn ( pmc - > dev ,
" unable to register %s clock lookup: %d \n " ,
data - > name , err ) ;
return ;
}
clk_data - > clks [ data - > clk_id ] = clk ;
}
2020-01-14 10:24:15 +03:00
if ( pmc - > soc - > has_blink_output ) {
tegra_pmc_writel ( pmc , 0x0 , PMC_BLINK_TIMER ) ;
clk = tegra_pmc_clk_gate_register ( pmc ,
" pmc_blink_override " ,
" clk_32k " ,
PMC_DPD_PADS_ORIDE ,
PMC_DPD_PADS_ORIDE_BLINK ) ;
if ( IS_ERR ( clk ) ) {
dev_warn ( pmc - > dev ,
" unable to register pmc_blink_override: %d \n " ,
PTR_ERR_OR_ZERO ( clk ) ) ;
return ;
}
clk = tegra_pmc_clk_gate_register ( pmc , " pmc_blink " ,
" pmc_blink_override " ,
PMC_CNTRL ,
PMC_CNTRL_BLINK_EN ) ;
if ( IS_ERR ( clk ) ) {
dev_warn ( pmc - > dev ,
" unable to register pmc_blink: %d \n " ,
PTR_ERR_OR_ZERO ( clk ) ) ;
return ;
}
err = clk_register_clkdev ( clk , " pmc_blink " , NULL ) ;
if ( err ) {
dev_warn ( pmc - > dev ,
" unable to register pmc_blink lookup: %d \n " ,
err ) ;
return ;
}
clk_data - > clks [ TEGRA_PMC_CLK_BLINK ] = clk ;
}
2020-01-14 10:24:13 +03:00
err = of_clk_add_provider ( np , of_clk_src_onecell_get , clk_data ) ;
if ( err )
dev_warn ( pmc - > dev , " failed to add pmc clock provider: %d \n " ,
err ) ;
}
2021-01-20 10:34:07 +03:00
static const struct regmap_range pmc_usb_sleepwalk_ranges [ ] = {
regmap_reg_range ( PMC_USB_DEBOUNCE_DEL , PMC_USB_AO ) ,
regmap_reg_range ( PMC_UTMIP_UHSIC_TRIGGERS , PMC_UTMIP_UHSIC_SAVED_STATE ) ,
regmap_reg_range ( PMC_UTMIP_TERM_PAD_CFG , PMC_UTMIP_UHSIC_FAKE ) ,
regmap_reg_range ( PMC_UTMIP_UHSIC_LINE_WAKEUP , PMC_UTMIP_UHSIC_LINE_WAKEUP ) ,
regmap_reg_range ( PMC_UTMIP_BIAS_MASTER_CNTRL , PMC_UTMIP_MASTER_CONFIG ) ,
regmap_reg_range ( PMC_UTMIP_UHSIC2_TRIGGERS , PMC_UTMIP_MASTER2_CONFIG ) ,
regmap_reg_range ( PMC_UTMIP_PAD_CFG0 , PMC_UTMIP_UHSIC_SLEEP_CFG1 ) ,
regmap_reg_range ( PMC_UTMIP_SLEEPWALK_P3 , PMC_UTMIP_SLEEPWALK_P3 ) ,
} ;
static const struct regmap_access_table pmc_usb_sleepwalk_table = {
. yes_ranges = pmc_usb_sleepwalk_ranges ,
. n_yes_ranges = ARRAY_SIZE ( pmc_usb_sleepwalk_ranges ) ,
} ;
static int tegra_pmc_regmap_readl ( void * context , unsigned int offset , unsigned int * value )
{
struct tegra_pmc * pmc = context ;
* value = tegra_pmc_readl ( pmc , offset ) ;
return 0 ;
}
static int tegra_pmc_regmap_writel ( void * context , unsigned int offset , unsigned int value )
{
struct tegra_pmc * pmc = context ;
tegra_pmc_writel ( pmc , value , offset ) ;
return 0 ;
}
static const struct regmap_config usb_sleepwalk_regmap_config = {
. name = " usb_sleepwalk " ,
. reg_bits = 32 ,
. val_bits = 32 ,
. reg_stride = 4 ,
. fast_io = true ,
. rd_table = & pmc_usb_sleepwalk_table ,
. wr_table = & pmc_usb_sleepwalk_table ,
. reg_read = tegra_pmc_regmap_readl ,
. reg_write = tegra_pmc_regmap_writel ,
} ;
static int tegra_pmc_regmap_init ( struct tegra_pmc * pmc )
{
struct regmap * regmap ;
int err ;
if ( pmc - > soc - > has_usb_sleepwalk ) {
regmap = devm_regmap_init ( pmc - > dev , NULL , pmc , & usb_sleepwalk_regmap_config ) ;
if ( IS_ERR ( regmap ) ) {
err = PTR_ERR ( regmap ) ;
dev_err ( pmc - > dev , " failed to allocate register map (%d) \n " , err ) ;
return err ;
}
}
return 0 ;
}
2021-07-19 00:27:05 +03:00
static void tegra_pmc_reset_suspend_mode ( void * data )
{
pmc - > suspend_mode = TEGRA_SUSPEND_NOT_READY ;
}
2014-07-11 15:19:06 +04:00
static int tegra_pmc_probe ( struct platform_device * pdev )
{
2016-02-11 21:03:21 +03:00
void __iomem * base ;
2014-07-11 15:19:06 +04:00
struct resource * res ;
int err ;
2016-06-28 13:38:28 +03:00
/*
* Early initialisation should have configured an initial
* register mapping and setup the soc data pointer . If these
* are not valid then something went badly wrong !
*/
if ( WARN_ON ( ! pmc - > base | | ! pmc - > soc ) )
return - ENODEV ;
2014-07-11 15:19:06 +04:00
err = tegra_pmc_parse_dt ( pmc , pdev - > dev . of_node ) ;
if ( err < 0 )
return err ;
2021-07-19 00:27:05 +03:00
err = devm_add_action_or_reset ( & pdev - > dev , tegra_pmc_reset_suspend_mode ,
NULL ) ;
if ( err )
return err ;
2014-07-11 15:19:06 +04:00
/* take over the memory region from the early initialization */
2021-09-08 10:17:24 +03:00
base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2016-02-11 21:03:20 +03:00
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2014-07-11 15:19:06 +04:00
2017-08-30 13:42:34 +03:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " wake " ) ;
if ( res ) {
pmc - > wake = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( pmc - > wake ) )
return PTR_ERR ( pmc - > wake ) ;
} else {
pmc - > wake = base ;
}
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " aotag " ) ;
if ( res ) {
pmc - > aotag = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( pmc - > aotag ) )
return PTR_ERR ( pmc - > aotag ) ;
} else {
pmc - > aotag = base ;
}
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " scratch " ) ;
if ( res ) {
pmc - > scratch = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( pmc - > scratch ) )
return PTR_ERR ( pmc - > scratch ) ;
} else {
pmc - > scratch = base ;
}
2017-08-30 13:32:58 +03:00
2022-08-07 23:55:59 +03:00
pmc - > clk = devm_clk_get_optional ( & pdev - > dev , " pclk " ) ;
if ( IS_ERR ( pmc - > clk ) )
return dev_err_probe ( & pdev - > dev , PTR_ERR ( pmc - > clk ) ,
" failed to get pclk \n " ) ;
2014-07-11 15:19:06 +04:00
2022-05-10 02:32:33 +03:00
/*
* PMC should be last resort for restarting since it soft - resets
* CPU without resetting everything else .
*/
err = devm_register_reboot_notifier ( & pdev - > dev ,
& tegra_pmc_reboot_notifier ) ;
if ( err ) {
dev_err ( & pdev - > dev , " unable to register reboot notifier, %d \n " ,
err ) ;
return err ;
}
err = devm_register_sys_off_handler ( & pdev - > dev ,
SYS_OFF_MODE_RESTART ,
SYS_OFF_PRIO_LOW ,
tegra_pmc_restart_handler , NULL ) ;
if ( err ) {
dev_err ( & pdev - > dev , " failed to register sys-off handler: %d \n " ,
err ) ;
return err ;
}
/*
* PMC should be primary power - off method if it soft - resets CPU ,
* asking bootloader to shutdown hardware .
*/
err = devm_register_sys_off_handler ( & pdev - > dev ,
SYS_OFF_MODE_POWER_OFF ,
SYS_OFF_PRIO_FIRMWARE ,
tegra_pmc_power_off_handler , NULL ) ;
if ( err ) {
dev_err ( & pdev - > dev , " failed to register sys-off handler: %d \n " ,
err ) ;
return err ;
}
2019-09-26 22:17:54 +03:00
/*
* PCLK clock rate can ' t be retrieved using CLK API because it
* causes lockup if CPU enters LP2 idle state from some other
* CLK notifier , hence we ' re caching the rate ' s value locally .
*/
if ( pmc - > clk ) {
pmc - > clk_nb . notifier_call = tegra_pmc_clk_notify_cb ;
err = clk_notifier_register ( pmc - > clk , & pmc - > clk_nb ) ;
if ( err ) {
dev_err ( & pdev - > dev ,
" failed to register clk notifier \n " ) ;
return err ;
}
pmc - > rate = clk_get_rate ( pmc - > clk ) ;
}
2015-01-06 13:52:58 +03:00
pmc - > dev = & pdev - > dev ;
2022-09-30 19:14:52 +03:00
err = tegra_pmc_init ( pmc ) ;
if ( err < 0 ) {
dev_err ( & pdev - > dev , " failed to initialize PMC: %d \n " , err ) ;
return err ;
}
2014-07-11 15:19:06 +04:00
2015-01-06 13:52:58 +03:00
tegra_pmc_init_tsense_reset ( pmc ) ;
2018-10-24 10:08:00 +03:00
tegra_pmc_reset_sysfs_init ( pmc ) ;
2014-07-11 15:19:06 +04:00
if ( IS_ENABLED ( CONFIG_DEBUG_FS ) ) {
err = tegra_powergate_debugfs_init ( ) ;
if ( err < 0 )
2019-04-16 19:48:07 +03:00
goto cleanup_sysfs ;
2015-03-18 12:52:25 +03:00
}
2018-08-10 21:08:12 +03:00
err = tegra_pmc_pinctrl_init ( pmc ) ;
if ( err )
2022-05-10 02:32:33 +03:00
goto cleanup_debugfs ;
2018-08-10 21:08:12 +03:00
2021-01-20 10:34:07 +03:00
err = tegra_pmc_regmap_init ( pmc ) ;
if ( err < 0 )
2022-05-10 02:32:33 +03:00
goto cleanup_debugfs ;
2021-01-20 10:34:07 +03:00
2019-04-16 19:48:08 +03:00
err = tegra_powergate_init ( pmc , pdev - > dev . of_node ) ;
if ( err < 0 )
goto cleanup_powergates ;
2018-09-17 16:08:17 +03:00
err = tegra_pmc_irq_init ( pmc ) ;
if ( err < 0 )
2019-04-16 19:48:08 +03:00
goto cleanup_powergates ;
2018-09-17 16:08:17 +03:00
2016-02-11 21:03:21 +03:00
mutex_lock ( & pmc - > powergates_lock ) ;
iounmap ( pmc - > base ) ;
2016-02-11 21:03:20 +03:00
pmc - > base = base ;
2016-02-11 21:03:21 +03:00
mutex_unlock ( & pmc - > powergates_lock ) ;
2016-02-11 21:03:20 +03:00
2020-01-14 10:24:13 +03:00
tegra_pmc_clock_register ( pmc , pdev - > dev . of_node ) ;
2019-01-25 13:22:52 +03:00
platform_set_drvdata ( pdev , pmc ) ;
2021-07-19 00:27:05 +03:00
tegra_pm_init_suspend ( ) ;
2019-01-25 13:22:52 +03:00
2023-03-30 20:06:21 +03:00
/* Some wakes require specific filter configuration */
if ( pmc - > soc - > set_wake_filters )
pmc - > soc - > set_wake_filters ( pmc ) ;
2014-07-11 15:19:06 +04:00
return 0 ;
2018-08-10 21:08:12 +03:00
2019-04-16 19:48:08 +03:00
cleanup_powergates :
tegra_powergate_remove_all ( pdev - > dev . of_node ) ;
2018-08-10 21:08:12 +03:00
cleanup_debugfs :
debugfs_remove ( pmc - > debugfs ) ;
2019-04-16 19:48:07 +03:00
cleanup_sysfs :
device_remove_file ( & pdev - > dev , & dev_attr_reset_reason ) ;
device_remove_file ( & pdev - > dev , & dev_attr_reset_level ) ;
2019-09-26 22:17:54 +03:00
clk_notifier_unregister ( pmc - > clk , & pmc - > clk_nb ) ;
2018-08-10 21:08:12 +03:00
return err ;
2014-07-11 15:19:06 +04:00
}
2022-09-30 19:14:52 +03:00
/*
* Ensures that sufficient time is passed for a register write to
* serialize into the 32 KHz domain .
*/
static void wke_32kwritel ( struct tegra_pmc * pmc , u32 value , unsigned int offset )
{
writel ( value , pmc - > wake + offset ) ;
udelay ( 130 ) ;
}
static void wke_write_wake_level ( struct tegra_pmc * pmc , int wake , int level )
{
unsigned int offset = WAKE_AOWAKE_CNTRL ( wake ) ;
u32 value ;
value = readl ( pmc - > wake + offset ) ;
if ( level )
value | = WAKE_AOWAKE_CNTRL_LEVEL ;
else
value & = ~ WAKE_AOWAKE_CNTRL_LEVEL ;
writel ( value , pmc - > wake + offset ) ;
}
static void wke_write_wake_levels ( struct tegra_pmc * pmc )
{
unsigned int i ;
for ( i = 0 ; i < pmc - > soc - > max_wake_events ; i + + )
wke_write_wake_level ( pmc , i , test_bit ( i , pmc - > wake_cntrl_level_map ) ) ;
}
static void wke_clear_sw_wake_status ( struct tegra_pmc * pmc )
{
wke_32kwritel ( pmc , 1 , WAKE_AOWAKE_SW_STATUS_W_0 ) ;
}
static void wke_read_sw_wake_status ( struct tegra_pmc * pmc )
{
unsigned long status ;
unsigned int wake , i ;
for ( i = 0 ; i < pmc - > soc - > max_wake_events ; i + + )
wke_write_wake_level ( pmc , i , 0 ) ;
wke_clear_sw_wake_status ( pmc ) ;
wke_32kwritel ( pmc , 1 , WAKE_LATCH_SW ) ;
/*
* WAKE_AOWAKE_SW_STATUS is edge triggered , so in order to
* obtain the current status of the input wake signals , change
* the polarity of the wake level from 0 - > 1 while latching to force
* a positive edge if the sampled signal is ' 1 ' .
*/
for ( i = 0 ; i < pmc - > soc - > max_wake_events ; i + + )
wke_write_wake_level ( pmc , i , 1 ) ;
/*
* Wait for the update to be synced into the 32 kHz domain ,
* and let enough time lapse , so that the wake signals have time to
* be sampled .
*/
udelay ( 300 ) ;
wke_32kwritel ( pmc , 0 , WAKE_LATCH_SW ) ;
bitmap_zero ( pmc - > wake_sw_status_map , pmc - > soc - > max_wake_events ) ;
for ( i = 0 ; i < pmc - > soc - > max_wake_vectors ; i + + ) {
status = readl ( pmc - > wake + WAKE_AOWAKE_SW_STATUS ( i ) ) ;
for_each_set_bit ( wake , & status , 32 )
set_bit ( wake + ( i * 32 ) , pmc - > wake_sw_status_map ) ;
}
}
static void wke_clear_wake_status ( struct tegra_pmc * pmc )
{
unsigned long status ;
unsigned int i , wake ;
u32 mask ;
for ( i = 0 ; i < pmc - > soc - > max_wake_vectors ; i + + ) {
mask = readl ( pmc - > wake + WAKE_AOWAKE_TIER2_ROUTING ( i ) ) ;
status = readl ( pmc - > wake + WAKE_AOWAKE_STATUS_R ( i ) ) & mask ;
for_each_set_bit ( wake , & status , 32 )
wke_32kwritel ( pmc , 0x1 , WAKE_AOWAKE_STATUS_W ( ( i * 32 ) + wake ) ) ;
}
}
2022-10-02 17:44:09 +03:00
/* translate sc7 wake sources back into IRQs to catch edge triggered wakeups */
static void tegra186_pmc_process_wake_events ( struct tegra_pmc * pmc , unsigned int index ,
unsigned long status )
{
unsigned int wake ;
dev_dbg ( pmc - > dev , " Wake[%d:%d] status=%#lx \n " , ( index * 32 ) + 31 , index * 32 , status ) ;
for_each_set_bit ( wake , & status , 32 ) {
irq_hw_number_t hwirq = wake + 32 * index ;
struct irq_desc * desc ;
unsigned int irq ;
irq = irq_find_mapping ( pmc - > domain , hwirq ) ;
desc = irq_to_desc ( irq ) ;
if ( ! desc | | ! desc - > action | | ! desc - > action - > name ) {
dev_dbg ( pmc - > dev , " Resume caused by WAKE%ld, IRQ %d \n " , hwirq , irq ) ;
continue ;
}
dev_dbg ( pmc - > dev , " Resume caused by WAKE%ld, %s \n " , hwirq , desc - > action - > name ) ;
generic_handle_irq ( irq ) ;
}
}
static void tegra186_pmc_wake_syscore_resume ( void )
{
u32 status , mask ;
unsigned int i ;
for ( i = 0 ; i < pmc - > soc - > max_wake_vectors ; i + + ) {
mask = readl ( pmc - > wake + WAKE_AOWAKE_TIER2_ROUTING ( i ) ) ;
status = readl ( pmc - > wake + WAKE_AOWAKE_STATUS_R ( i ) ) & mask ;
tegra186_pmc_process_wake_events ( pmc , i , status ) ;
}
}
2022-09-30 19:14:52 +03:00
static int tegra186_pmc_wake_syscore_suspend ( void )
{
wke_read_sw_wake_status ( pmc ) ;
/* flip the wakeup trigger for dual-edge triggered pads
* which are currently asserting as wakeups
*/
bitmap_andnot ( pmc - > wake_cntrl_level_map , pmc - > wake_type_dual_edge_map ,
pmc - > wake_sw_status_map , pmc - > soc - > max_wake_events ) ;
bitmap_or ( pmc - > wake_cntrl_level_map , pmc - > wake_cntrl_level_map ,
pmc - > wake_type_level_map , pmc - > soc - > max_wake_events ) ;
/* Clear PMC Wake Status registers while going to suspend */
wke_clear_wake_status ( pmc ) ;
wke_write_wake_levels ( pmc ) ;
return 0 ;
}
2014-12-10 01:36:50 +03:00
# if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
2014-07-11 15:19:06 +04:00
static int tegra_pmc_suspend ( struct device * dev )
{
2019-01-25 13:22:52 +03:00
struct tegra_pmc * pmc = dev_get_drvdata ( dev ) ;
tegra_pmc_writel ( pmc , virt_to_phys ( tegra_resume ) , PMC_SCRATCH41 ) ;
2014-07-11 15:19:06 +04:00
return 0 ;
}
static int tegra_pmc_resume ( struct device * dev )
{
2019-01-25 13:22:52 +03:00
struct tegra_pmc * pmc = dev_get_drvdata ( dev ) ;
tegra_pmc_writel ( pmc , 0x0 , PMC_SCRATCH41 ) ;
2014-07-11 15:19:06 +04:00
return 0 ;
}
static SIMPLE_DEV_PM_OPS ( tegra_pmc_pm_ops , tegra_pmc_suspend , tegra_pmc_resume ) ;
2014-12-10 01:36:50 +03:00
# endif
2014-07-11 15:19:06 +04:00
static const char * const tegra20_powergates [ ] = {
[ TEGRA_POWERGATE_CPU ] = " cpu " ,
2021-12-01 02:23:38 +03:00
[ TEGRA_POWERGATE_3D ] = " td " ,
2014-07-11 15:19:06 +04:00
[ TEGRA_POWERGATE_VENC ] = " venc " ,
[ TEGRA_POWERGATE_VDEC ] = " vdec " ,
[ TEGRA_POWERGATE_PCIE ] = " pcie " ,
[ TEGRA_POWERGATE_L2 ] = " l2 " ,
[ TEGRA_POWERGATE_MPE ] = " mpe " ,
} ;
2017-08-30 13:32:58 +03:00
static const struct tegra_pmc_regs tegra20_pmc_regs = {
. scratch0 = 0x50 ,
2018-10-24 10:08:00 +03:00
. rst_status = 0x1b4 ,
. rst_source_shift = 0x0 ,
. rst_source_mask = 0x7 ,
. rst_level_shift = 0x0 ,
. rst_level_mask = 0x0 ,
2017-08-30 13:32:58 +03:00
} ;
static void tegra20_pmc_init ( struct tegra_pmc * pmc )
{
2019-08-16 22:42:05 +03:00
u32 value , osc , pmu , off ;
2017-08-30 13:32:58 +03:00
/* Always enable CPU power request */
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_CNTRL ) ;
2017-08-30 13:32:58 +03:00
value | = PMC_CNTRL_CPU_PWRREQ_OE ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_CNTRL ) ;
2017-08-30 13:32:58 +03:00
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_CNTRL ) ;
2017-08-30 13:32:58 +03:00
if ( pmc - > sysclkreq_high )
value & = ~ PMC_CNTRL_SYSCLK_POLARITY ;
else
value | = PMC_CNTRL_SYSCLK_POLARITY ;
2019-08-16 22:42:04 +03:00
if ( pmc - > corereq_high )
value & = ~ PMC_CNTRL_PWRREQ_POLARITY ;
else
value | = PMC_CNTRL_PWRREQ_POLARITY ;
2017-08-30 13:32:58 +03:00
/* configure the output polarity while the request is tristated */
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_CNTRL ) ;
2017-08-30 13:32:58 +03:00
/* now enable the request */
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_CNTRL ) ;
2017-08-30 13:32:58 +03:00
value | = PMC_CNTRL_SYSCLK_OE ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_CNTRL ) ;
2019-08-16 22:42:05 +03:00
/* program core timings which are applicable only for suspend state */
if ( pmc - > suspend_mode ! = TEGRA_SUSPEND_NONE ) {
osc = DIV_ROUND_UP ( pmc - > core_osc_time * 8192 , 1000000 ) ;
pmu = DIV_ROUND_UP ( pmc - > core_pmu_time * 32768 , 1000000 ) ;
off = DIV_ROUND_UP ( pmc - > core_off_time * 32768 , 1000000 ) ;
tegra_pmc_writel ( pmc , ( ( osc < < 8 ) & 0xff00 ) | ( pmu & 0xff ) ,
PMC_COREPWRGOOD_TIMER ) ;
tegra_pmc_writel ( pmc , off , PMC_COREPWROFF_TIMER ) ;
}
2017-08-30 13:32:58 +03:00
}
static void tegra20_pmc_setup_irq_polarity ( struct tegra_pmc * pmc ,
struct device_node * np ,
bool invert )
{
u32 value ;
2019-01-25 13:22:52 +03:00
value = tegra_pmc_readl ( pmc , PMC_CNTRL ) ;
2017-08-30 13:32:58 +03:00
if ( invert )
value | = PMC_CNTRL_INTR_POLARITY ;
else
value & = ~ PMC_CNTRL_INTR_POLARITY ;
2019-01-25 13:22:52 +03:00
tegra_pmc_writel ( pmc , value , PMC_CNTRL ) ;
2017-08-30 13:32:58 +03:00
}
2014-07-11 15:19:06 +04:00
static const struct tegra_pmc_soc tegra20_pmc_soc = {
2021-12-01 02:23:40 +03:00
. supports_core_domain = true ,
2014-07-11 15:19:06 +04:00
. num_powergates = ARRAY_SIZE ( tegra20_powergates ) ,
. powergates = tegra20_powergates ,
. num_cpu_powergates = 0 ,
. cpu_powergates = NULL ,
2015-01-06 13:52:58 +03:00
. has_tsense_reset = false ,
2015-01-09 13:15:33 +03:00
. has_gpu_clamps = false ,
2019-01-25 13:22:54 +03:00
. needs_mbist_war = false ,
. has_impl_33v_pwr = false ,
2019-01-25 13:22:55 +03:00
. maybe_tz_only = false ,
2017-08-30 13:32:58 +03:00
. num_io_pads = 0 ,
. io_pads = NULL ,
2018-08-10 21:08:12 +03:00
. num_pin_descs = 0 ,
. pin_descs = NULL ,
2017-08-30 13:32:58 +03:00
. regs = & tegra20_pmc_regs ,
. init = tegra20_pmc_init ,
. setup_irq_polarity = tegra20_pmc_setup_irq_polarity ,
2021-03-02 15:24:59 +03:00
. powergate_set = tegra20_powergate_set ,
2018-10-24 10:08:00 +03:00
. reset_sources = NULL ,
. num_reset_sources = 0 ,
. reset_levels = NULL ,
. num_reset_levels = 0 ,
2020-01-14 10:24:13 +03:00
. pmc_clks_data = NULL ,
. num_pmc_clks = 0 ,
2020-01-14 10:24:15 +03:00
. has_blink_output = true ,
2021-09-12 21:17:14 +03:00
. has_usb_sleepwalk = true ,
2014-07-11 15:19:06 +04:00
} ;
static const char * const tegra30_powergates [ ] = {
[ TEGRA_POWERGATE_CPU ] = " cpu0 " ,
2021-12-01 02:23:38 +03:00
[ TEGRA_POWERGATE_3D ] = " td " ,
2014-07-11 15:19:06 +04:00
[ TEGRA_POWERGATE_VENC ] = " venc " ,
[ TEGRA_POWERGATE_VDEC ] = " vdec " ,
[ TEGRA_POWERGATE_PCIE ] = " pcie " ,
[ TEGRA_POWERGATE_L2 ] = " l2 " ,
[ TEGRA_POWERGATE_MPE ] = " mpe " ,
[ TEGRA_POWERGATE_HEG ] = " heg " ,
[ TEGRA_POWERGATE_SATA ] = " sata " ,
[ TEGRA_POWERGATE_CPU1 ] = " cpu1 " ,
[ TEGRA_POWERGATE_CPU2 ] = " cpu2 " ,
[ TEGRA_POWERGATE_CPU3 ] = " cpu3 " ,
[ TEGRA_POWERGATE_CELP ] = " celp " ,
2021-12-01 02:23:38 +03:00
[ TEGRA_POWERGATE_3D1 ] = " td2 " ,
2014-07-11 15:19:06 +04:00
} ;
static const u8 tegra30_cpu_powergates [ ] = {
TEGRA_POWERGATE_CPU ,
TEGRA_POWERGATE_CPU1 ,
TEGRA_POWERGATE_CPU2 ,
TEGRA_POWERGATE_CPU3 ,
} ;
2020-09-17 13:07:49 +03:00
static const char * const tegra30_reset_sources [ ] = {
" POWER_ON_RESET " ,
" WATCHDOG " ,
" SENSOR " ,
" SW_MAIN " ,
" LP0 "
} ;
2014-07-11 15:19:06 +04:00
static const struct tegra_pmc_soc tegra30_pmc_soc = {
2021-12-01 02:23:40 +03:00
. supports_core_domain = true ,
2014-07-11 15:19:06 +04:00
. num_powergates = ARRAY_SIZE ( tegra30_powergates ) ,
. powergates = tegra30_powergates ,
. num_cpu_powergates = ARRAY_SIZE ( tegra30_cpu_powergates ) ,
. cpu_powergates = tegra30_cpu_powergates ,
2015-01-06 13:52:58 +03:00
. has_tsense_reset = true ,
2015-01-09 13:15:33 +03:00
. has_gpu_clamps = false ,
2019-01-25 13:22:54 +03:00
. needs_mbist_war = false ,
2018-08-10 21:08:07 +03:00
. has_impl_33v_pwr = false ,
2019-01-25 13:22:55 +03:00
. maybe_tz_only = false ,
2017-08-30 13:32:58 +03:00
. num_io_pads = 0 ,
. io_pads = NULL ,
2018-08-10 21:08:12 +03:00
. num_pin_descs = 0 ,
. pin_descs = NULL ,
2017-08-30 13:32:58 +03:00
. regs = & tegra20_pmc_regs ,
. init = tegra20_pmc_init ,
. setup_irq_polarity = tegra20_pmc_setup_irq_polarity ,
2021-03-02 15:24:59 +03:00
. powergate_set = tegra20_powergate_set ,
2018-10-24 10:08:00 +03:00
. reset_sources = tegra30_reset_sources ,
2019-04-16 19:48:06 +03:00
. num_reset_sources = ARRAY_SIZE ( tegra30_reset_sources ) ,
2018-10-24 10:08:00 +03:00
. reset_levels = NULL ,
. num_reset_levels = 0 ,
2020-01-14 10:24:13 +03:00
. pmc_clks_data = tegra_pmc_clks_data ,
. num_pmc_clks = ARRAY_SIZE ( tegra_pmc_clks_data ) ,
2020-01-14 10:24:15 +03:00
. has_blink_output = true ,
2021-09-12 21:17:14 +03:00
. has_usb_sleepwalk = true ,
2014-07-11 15:19:06 +04:00
} ;
static const char * const tegra114_powergates [ ] = {
[ TEGRA_POWERGATE_CPU ] = " crail " ,
2021-12-01 02:23:38 +03:00
[ TEGRA_POWERGATE_3D ] = " td " ,
2014-07-11 15:19:06 +04:00
[ TEGRA_POWERGATE_VENC ] = " venc " ,
[ TEGRA_POWERGATE_VDEC ] = " vdec " ,
[ TEGRA_POWERGATE_MPE ] = " mpe " ,
[ TEGRA_POWERGATE_HEG ] = " heg " ,
[ TEGRA_POWERGATE_CPU1 ] = " cpu1 " ,
[ TEGRA_POWERGATE_CPU2 ] = " cpu2 " ,
[ TEGRA_POWERGATE_CPU3 ] = " cpu3 " ,
[ TEGRA_POWERGATE_CELP ] = " celp " ,
[ TEGRA_POWERGATE_CPU0 ] = " cpu0 " ,
[ TEGRA_POWERGATE_C0NC ] = " c0nc " ,
[ TEGRA_POWERGATE_C1NC ] = " c1nc " ,
[ TEGRA_POWERGATE_DIS ] = " dis " ,
[ TEGRA_POWERGATE_DISB ] = " disb " ,
[ TEGRA_POWERGATE_XUSBA ] = " xusba " ,
[ TEGRA_POWERGATE_XUSBB ] = " xusbb " ,
[ TEGRA_POWERGATE_XUSBC ] = " xusbc " ,
} ;
static const u8 tegra114_cpu_powergates [ ] = {
TEGRA_POWERGATE_CPU0 ,
TEGRA_POWERGATE_CPU1 ,
TEGRA_POWERGATE_CPU2 ,
TEGRA_POWERGATE_CPU3 ,
} ;
static const struct tegra_pmc_soc tegra114_pmc_soc = {
2021-09-27 01:40:26 +03:00
. supports_core_domain = false ,
2014-07-11 15:19:06 +04:00
. num_powergates = ARRAY_SIZE ( tegra114_powergates ) ,
. powergates = tegra114_powergates ,
. num_cpu_powergates = ARRAY_SIZE ( tegra114_cpu_powergates ) ,
. cpu_powergates = tegra114_cpu_powergates ,
2015-01-06 13:52:58 +03:00
. has_tsense_reset = true ,
2015-01-09 13:15:33 +03:00
. has_gpu_clamps = false ,
2019-01-25 13:22:54 +03:00
. needs_mbist_war = false ,
2018-08-10 21:08:07 +03:00
. has_impl_33v_pwr = false ,
2019-01-25 13:22:55 +03:00
. maybe_tz_only = false ,
2017-08-30 13:32:58 +03:00
. num_io_pads = 0 ,
. io_pads = NULL ,
2018-08-10 21:08:12 +03:00
. num_pin_descs = 0 ,
. pin_descs = NULL ,
2017-08-30 13:32:58 +03:00
. regs = & tegra20_pmc_regs ,
. init = tegra20_pmc_init ,
. setup_irq_polarity = tegra20_pmc_setup_irq_polarity ,
2021-03-02 15:24:59 +03:00
. powergate_set = tegra114_powergate_set ,
2018-10-24 10:08:00 +03:00
. reset_sources = tegra30_reset_sources ,
2019-04-16 19:48:06 +03:00
. num_reset_sources = ARRAY_SIZE ( tegra30_reset_sources ) ,
2018-10-24 10:08:00 +03:00
. reset_levels = NULL ,
. num_reset_levels = 0 ,
2020-01-14 10:24:13 +03:00
. pmc_clks_data = tegra_pmc_clks_data ,
. num_pmc_clks = ARRAY_SIZE ( tegra_pmc_clks_data ) ,
2020-01-14 10:24:15 +03:00
. has_blink_output = true ,
2021-09-12 21:17:14 +03:00
. has_usb_sleepwalk = true ,
2014-07-11 15:19:06 +04:00
} ;
static const char * const tegra124_powergates [ ] = {
[ TEGRA_POWERGATE_CPU ] = " crail " ,
[ TEGRA_POWERGATE_3D ] = " 3d " ,
[ TEGRA_POWERGATE_VENC ] = " venc " ,
[ TEGRA_POWERGATE_PCIE ] = " pcie " ,
[ TEGRA_POWERGATE_VDEC ] = " vdec " ,
[ TEGRA_POWERGATE_MPE ] = " mpe " ,
[ TEGRA_POWERGATE_HEG ] = " heg " ,
[ TEGRA_POWERGATE_SATA ] = " sata " ,
[ TEGRA_POWERGATE_CPU1 ] = " cpu1 " ,
[ TEGRA_POWERGATE_CPU2 ] = " cpu2 " ,
[ TEGRA_POWERGATE_CPU3 ] = " cpu3 " ,
[ TEGRA_POWERGATE_CELP ] = " celp " ,
[ TEGRA_POWERGATE_CPU0 ] = " cpu0 " ,
[ TEGRA_POWERGATE_C0NC ] = " c0nc " ,
[ TEGRA_POWERGATE_C1NC ] = " c1nc " ,
[ TEGRA_POWERGATE_SOR ] = " sor " ,
[ TEGRA_POWERGATE_DIS ] = " dis " ,
[ TEGRA_POWERGATE_DISB ] = " disb " ,
[ TEGRA_POWERGATE_XUSBA ] = " xusba " ,
[ TEGRA_POWERGATE_XUSBB ] = " xusbb " ,
[ TEGRA_POWERGATE_XUSBC ] = " xusbc " ,
[ TEGRA_POWERGATE_VIC ] = " vic " ,
[ TEGRA_POWERGATE_IRAM ] = " iram " ,
} ;
static const u8 tegra124_cpu_powergates [ ] = {
TEGRA_POWERGATE_CPU0 ,
TEGRA_POWERGATE_CPU1 ,
TEGRA_POWERGATE_CPU2 ,
TEGRA_POWERGATE_CPU3 ,
} ;
2022-09-30 19:02:13 +03:00
# define TEGRA_IO_PAD(_id, _dpd, _request, _status, _voltage, _name) \
( ( struct tegra_io_pad_soc ) { \
. id = ( _id ) , \
. dpd = ( _dpd ) , \
. request = ( _request ) , \
. status = ( _status ) , \
. voltage = ( _voltage ) , \
. name = ( _name ) , \
2018-08-10 21:08:10 +03:00
} )
2022-09-30 19:02:13 +03:00
# define TEGRA_IO_PIN_DESC(_id, _name) \
( ( struct pinctrl_pin_desc ) { \
. number = ( _id ) , \
. name = ( _name ) , \
2018-08-10 21:08:12 +03:00
} )
2016-10-10 16:14:34 +03:00
static const struct tegra_io_pad_soc tegra124_io_pads [ ] = {
2022-09-30 19:02:13 +03:00
TEGRA_IO_PAD ( TEGRA_IO_PAD_AUDIO , 17 , 0x1b8 , 0x1bc , UINT_MAX , " audio " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_BB , 15 , 0x1b8 , 0x1bc , UINT_MAX , " bb " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CAM , 4 , 0x1c0 , 0x1c4 , UINT_MAX , " cam " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_COMP , 22 , 0x1b8 , 0x1bc , UINT_MAX , " comp " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIA , 0 , 0x1b8 , 0x1bc , UINT_MAX , " csia " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIB , 1 , 0x1b8 , 0x1bc , UINT_MAX , " csib " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIE , 12 , 0x1c0 , 0x1c4 , UINT_MAX , " csie " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSI , 2 , 0x1b8 , 0x1bc , UINT_MAX , " dsi " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSIB , 7 , 0x1c0 , 0x1c4 , UINT_MAX , " dsib " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSIC , 8 , 0x1c0 , 0x1c4 , UINT_MAX , " dsic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSID , 9 , 0x1c0 , 0x1c4 , UINT_MAX , " dsid " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI , 28 , 0x1b8 , 0x1bc , UINT_MAX , " hdmi " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HSIC , 19 , 0x1b8 , 0x1bc , UINT_MAX , " hsic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HV , 6 , 0x1c0 , 0x1c4 , UINT_MAX , " hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_LVDS , 25 , 0x1c0 , 0x1c4 , UINT_MAX , " lvds " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_MIPI_BIAS , 3 , 0x1b8 , 0x1bc , UINT_MAX , " mipi-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_NAND , 13 , 0x1b8 , 0x1bc , UINT_MAX , " nand " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_BIAS , 4 , 0x1b8 , 0x1bc , UINT_MAX , " pex-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK1 , 5 , 0x1b8 , 0x1bc , UINT_MAX , " pex-clk1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK2 , 6 , 0x1b8 , 0x1bc , UINT_MAX , " pex-clk2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CNTRL , 0 , 0x1c0 , 0x1c4 , UINT_MAX , " pex-cntrl " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC1 , 1 , 0x1c0 , 0x1c4 , UINT_MAX , " sdmmc1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC3 , 2 , 0x1c0 , 0x1c4 , UINT_MAX , " sdmmc3 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC4 , 3 , 0x1c0 , 0x1c4 , UINT_MAX , " sdmmc4 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SYS_DDC , 26 , 0x1c0 , 0x1c4 , UINT_MAX , " sys_ddc " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UART , 14 , 0x1b8 , 0x1bc , UINT_MAX , " uart " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB0 , 9 , 0x1b8 , 0x1bc , UINT_MAX , " usb0 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB1 , 10 , 0x1b8 , 0x1bc , UINT_MAX , " usb1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB2 , 11 , 0x1b8 , 0x1bc , UINT_MAX , " usb2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB_BIAS , 12 , 0x1b8 , 0x1bc , UINT_MAX , " usb_bias " ) ,
2016-10-10 16:14:34 +03:00
} ;
2018-08-10 21:08:12 +03:00
static const struct pinctrl_pin_desc tegra124_pin_descs [ ] = {
2022-09-30 19:02:13 +03:00
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AUDIO , " audio " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_BB , " bb " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CAM , " cam " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_COMP , " comp " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIA , " csia " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIB , " csib " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIE , " csie " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSI , " dsi " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSIB , " dsib " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSIC , " dsic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSID , " dsid " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI , " hdmi " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HSIC , " hsic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HV , " hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_LVDS , " lvds " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_MIPI_BIAS , " mipi-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_NAND , " nand " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_BIAS , " pex-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK1 , " pex-clk1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK2 , " pex-clk2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CNTRL , " pex-cntrl " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC1 , " sdmmc1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC3 , " sdmmc3 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC4 , " sdmmc4 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SYS_DDC , " sys_ddc " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UART , " uart " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB0 , " usb0 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB1 , " usb1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB2 , " usb2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB_BIAS , " usb_bias " ) ,
2016-10-10 16:14:34 +03:00
} ;
2014-07-11 15:19:06 +04:00
static const struct tegra_pmc_soc tegra124_pmc_soc = {
2021-09-27 01:40:26 +03:00
. supports_core_domain = false ,
2014-07-11 15:19:06 +04:00
. num_powergates = ARRAY_SIZE ( tegra124_powergates ) ,
. powergates = tegra124_powergates ,
. num_cpu_powergates = ARRAY_SIZE ( tegra124_cpu_powergates ) ,
. cpu_powergates = tegra124_cpu_powergates ,
2015-01-06 13:52:58 +03:00
. has_tsense_reset = true ,
2015-01-09 13:15:33 +03:00
. has_gpu_clamps = true ,
2019-01-25 13:22:54 +03:00
. needs_mbist_war = false ,
2018-08-10 21:08:07 +03:00
. has_impl_33v_pwr = false ,
2019-01-25 13:22:55 +03:00
. maybe_tz_only = false ,
2016-10-10 16:14:34 +03:00
. num_io_pads = ARRAY_SIZE ( tegra124_io_pads ) ,
. io_pads = tegra124_io_pads ,
2018-08-10 21:08:12 +03:00
. num_pin_descs = ARRAY_SIZE ( tegra124_pin_descs ) ,
. pin_descs = tegra124_pin_descs ,
2017-08-30 13:32:58 +03:00
. regs = & tegra20_pmc_regs ,
. init = tegra20_pmc_init ,
. setup_irq_polarity = tegra20_pmc_setup_irq_polarity ,
2021-03-02 15:24:59 +03:00
. powergate_set = tegra114_powergate_set ,
2018-10-24 10:08:00 +03:00
. reset_sources = tegra30_reset_sources ,
2019-04-16 19:48:06 +03:00
. num_reset_sources = ARRAY_SIZE ( tegra30_reset_sources ) ,
2018-10-24 10:08:00 +03:00
. reset_levels = NULL ,
. num_reset_levels = 0 ,
2020-01-14 10:24:13 +03:00
. pmc_clks_data = tegra_pmc_clks_data ,
. num_pmc_clks = ARRAY_SIZE ( tegra_pmc_clks_data ) ,
2020-01-14 10:24:15 +03:00
. has_blink_output = true ,
2021-01-20 10:34:07 +03:00
. has_usb_sleepwalk = true ,
2014-07-11 15:19:06 +04:00
} ;
2015-03-23 13:31:29 +03:00
static const char * const tegra210_powergates [ ] = {
[ TEGRA_POWERGATE_CPU ] = " crail " ,
[ TEGRA_POWERGATE_3D ] = " 3d " ,
[ TEGRA_POWERGATE_VENC ] = " venc " ,
[ TEGRA_POWERGATE_PCIE ] = " pcie " ,
[ TEGRA_POWERGATE_MPE ] = " mpe " ,
[ TEGRA_POWERGATE_SATA ] = " sata " ,
[ TEGRA_POWERGATE_CPU1 ] = " cpu1 " ,
[ TEGRA_POWERGATE_CPU2 ] = " cpu2 " ,
[ TEGRA_POWERGATE_CPU3 ] = " cpu3 " ,
[ TEGRA_POWERGATE_CPU0 ] = " cpu0 " ,
[ TEGRA_POWERGATE_C0NC ] = " c0nc " ,
[ TEGRA_POWERGATE_SOR ] = " sor " ,
[ TEGRA_POWERGATE_DIS ] = " dis " ,
[ TEGRA_POWERGATE_DISB ] = " disb " ,
[ TEGRA_POWERGATE_XUSBA ] = " xusba " ,
[ TEGRA_POWERGATE_XUSBB ] = " xusbb " ,
[ TEGRA_POWERGATE_XUSBC ] = " xusbc " ,
[ TEGRA_POWERGATE_VIC ] = " vic " ,
[ TEGRA_POWERGATE_IRAM ] = " iram " ,
[ TEGRA_POWERGATE_NVDEC ] = " nvdec " ,
[ TEGRA_POWERGATE_NVJPG ] = " nvjpg " ,
[ TEGRA_POWERGATE_AUD ] = " aud " ,
[ TEGRA_POWERGATE_DFD ] = " dfd " ,
[ TEGRA_POWERGATE_VE2 ] = " ve2 " ,
} ;
static const u8 tegra210_cpu_powergates [ ] = {
TEGRA_POWERGATE_CPU0 ,
TEGRA_POWERGATE_CPU1 ,
TEGRA_POWERGATE_CPU2 ,
TEGRA_POWERGATE_CPU3 ,
} ;
2016-10-10 16:14:34 +03:00
static const struct tegra_io_pad_soc tegra210_io_pads [ ] = {
2022-09-30 19:02:13 +03:00
TEGRA_IO_PAD ( TEGRA_IO_PAD_AUDIO , 17 , 0x1b8 , 0x1bc , 5 , " audio " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AUDIO_HV , 29 , 0x1c0 , 0x1c4 , 18 , " audio-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CAM , 4 , 0x1c0 , 0x1c4 , 10 , " cam " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIA , 0 , 0x1b8 , 0x1bc , UINT_MAX , " csia " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIB , 1 , 0x1b8 , 0x1bc , UINT_MAX , " csib " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIC , 10 , 0x1c0 , 0x1c4 , UINT_MAX , " csic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSID , 11 , 0x1c0 , 0x1c4 , UINT_MAX , " csid " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIE , 12 , 0x1c0 , 0x1c4 , UINT_MAX , " csie " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIF , 13 , 0x1c0 , 0x1c4 , UINT_MAX , " csif " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DBG , 25 , 0x1b8 , 0x1bc , 19 , " dbg " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DEBUG_NONAO , 26 , 0x1b8 , 0x1bc , UINT_MAX , " debug-nonao " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DMIC , 18 , 0x1c0 , 0x1c4 , 20 , " dmic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DP , 19 , 0x1c0 , 0x1c4 , UINT_MAX , " dp " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSI , 2 , 0x1b8 , 0x1bc , UINT_MAX , " dsi " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSIB , 7 , 0x1c0 , 0x1c4 , UINT_MAX , " dsib " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSIC , 8 , 0x1c0 , 0x1c4 , UINT_MAX , " dsic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSID , 9 , 0x1c0 , 0x1c4 , UINT_MAX , " dsid " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_EMMC , 3 , 0x1c0 , 0x1c4 , UINT_MAX , " emmc " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_EMMC2 , 5 , 0x1c0 , 0x1c4 , UINT_MAX , " emmc2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_GPIO , 27 , 0x1b8 , 0x1bc , 21 , " gpio " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI , 28 , 0x1b8 , 0x1bc , UINT_MAX , " hdmi " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HSIC , 19 , 0x1b8 , 0x1bc , UINT_MAX , " hsic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_LVDS , 25 , 0x1c0 , 0x1c4 , UINT_MAX , " lvds " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_MIPI_BIAS , 3 , 0x1b8 , 0x1bc , UINT_MAX , " mipi-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_BIAS , 4 , 0x1b8 , 0x1bc , UINT_MAX , " pex-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK1 , 5 , 0x1b8 , 0x1bc , UINT_MAX , " pex-clk1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK2 , 6 , 0x1b8 , 0x1bc , UINT_MAX , " pex-clk2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CNTRL , UINT_MAX , UINT_MAX , UINT_MAX , 11 , " pex-cntrl " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC1 , 1 , 0x1c0 , 0x1c4 , 12 , " sdmmc1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC3 , 2 , 0x1c0 , 0x1c4 , 13 , " sdmmc3 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SPI , 14 , 0x1c0 , 0x1c4 , 22 , " spi " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SPI_HV , 15 , 0x1c0 , 0x1c4 , 23 , " spi-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UART , 14 , 0x1b8 , 0x1bc , 2 , " uart " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB0 , 9 , 0x1b8 , 0x1bc , UINT_MAX , " usb0 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB1 , 10 , 0x1b8 , 0x1bc , UINT_MAX , " usb1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB2 , 11 , 0x1b8 , 0x1bc , UINT_MAX , " usb2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB3 , 18 , 0x1b8 , 0x1bc , UINT_MAX , " usb3 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB_BIAS , 12 , 0x1b8 , 0x1bc , UINT_MAX , " usb-bias " ) ,
2016-10-10 16:14:34 +03:00
} ;
2018-08-10 21:08:12 +03:00
static const struct pinctrl_pin_desc tegra210_pin_descs [ ] = {
2022-09-30 19:02:13 +03:00
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AUDIO , " audio " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AUDIO_HV , " audio-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CAM , " cam " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIA , " csia " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIB , " csib " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIC , " csic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSID , " csid " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIE , " csie " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIF , " csif " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DBG , " dbg " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DEBUG_NONAO , " debug-nonao " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DMIC , " dmic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DP , " dp " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSI , " dsi " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSIB , " dsib " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSIC , " dsic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSID , " dsid " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_EMMC , " emmc " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_EMMC2 , " emmc2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_GPIO , " gpio " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI , " hdmi " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HSIC , " hsic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_LVDS , " lvds " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_MIPI_BIAS , " mipi-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_BIAS , " pex-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK1 , " pex-clk1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK2 , " pex-clk2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CNTRL , " pex-cntrl " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC1 , " sdmmc1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC3 , " sdmmc3 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SPI , " spi " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SPI_HV , " spi-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UART , " uart " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB0 , " usb0 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB1 , " usb1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB2 , " usb2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB3 , " usb3 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB_BIAS , " usb-bias " ) ,
2016-10-10 16:14:34 +03:00
} ;
2020-09-17 13:07:49 +03:00
static const char * const tegra210_reset_sources [ ] = {
" POWER_ON_RESET " ,
" WATCHDOG " ,
" SENSOR " ,
" SW_MAIN " ,
" LP0 " ,
" AOTAG "
} ;
2019-08-16 22:42:02 +03:00
static const struct tegra_wake_event tegra210_wake_events [ ] = {
TEGRA_WAKE_IRQ ( " rtc " , 16 , 2 ) ,
2020-05-20 18:13:17 +03:00
TEGRA_WAKE_IRQ ( " pmu " , 51 , 86 ) ,
2019-08-16 22:42:02 +03:00
} ;
2015-03-23 13:31:29 +03:00
static const struct tegra_pmc_soc tegra210_pmc_soc = {
2021-09-27 01:40:26 +03:00
. supports_core_domain = false ,
2015-03-23 13:31:29 +03:00
. num_powergates = ARRAY_SIZE ( tegra210_powergates ) ,
. powergates = tegra210_powergates ,
. num_cpu_powergates = ARRAY_SIZE ( tegra210_cpu_powergates ) ,
. cpu_powergates = tegra210_cpu_powergates ,
. has_tsense_reset = true ,
. has_gpu_clamps = true ,
2018-01-25 17:00:13 +03:00
. needs_mbist_war = true ,
2019-01-25 13:22:54 +03:00
. has_impl_33v_pwr = false ,
2019-01-25 13:22:55 +03:00
. maybe_tz_only = true ,
2016-10-10 16:14:34 +03:00
. num_io_pads = ARRAY_SIZE ( tegra210_io_pads ) ,
. io_pads = tegra210_io_pads ,
2018-08-10 21:08:12 +03:00
. num_pin_descs = ARRAY_SIZE ( tegra210_pin_descs ) ,
. pin_descs = tegra210_pin_descs ,
2017-08-30 13:32:58 +03:00
. regs = & tegra20_pmc_regs ,
. init = tegra20_pmc_init ,
. setup_irq_polarity = tegra20_pmc_setup_irq_polarity ,
2021-03-02 15:24:59 +03:00
. powergate_set = tegra114_powergate_set ,
2019-08-16 22:42:02 +03:00
. irq_set_wake = tegra210_pmc_irq_set_wake ,
. irq_set_type = tegra210_pmc_irq_set_type ,
2019-04-16 19:48:06 +03:00
. reset_sources = tegra210_reset_sources ,
. num_reset_sources = ARRAY_SIZE ( tegra210_reset_sources ) ,
2018-10-24 10:08:00 +03:00
. reset_levels = NULL ,
. num_reset_levels = 0 ,
2019-08-16 22:42:02 +03:00
. num_wake_events = ARRAY_SIZE ( tegra210_wake_events ) ,
. wake_events = tegra210_wake_events ,
2020-01-14 10:24:13 +03:00
. pmc_clks_data = tegra_pmc_clks_data ,
. num_pmc_clks = ARRAY_SIZE ( tegra_pmc_clks_data ) ,
2020-01-14 10:24:15 +03:00
. has_blink_output = true ,
2021-01-20 10:34:07 +03:00
. has_usb_sleepwalk = true ,
2015-03-23 13:31:29 +03:00
} ;
2017-08-30 13:42:34 +03:00
static const struct tegra_io_pad_soc tegra186_io_pads [ ] = {
2022-09-30 19:02:13 +03:00
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIA , 0 , 0x74 , 0x78 , UINT_MAX , " csia " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIB , 1 , 0x74 , 0x78 , UINT_MAX , " csib " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSI , 2 , 0x74 , 0x78 , UINT_MAX , " dsi " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_MIPI_BIAS , 3 , 0x74 , 0x78 , UINT_MAX , " mipi-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK_BIAS , 4 , 0x74 , 0x78 , UINT_MAX , " pex-clk-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK3 , 5 , 0x74 , 0x78 , UINT_MAX , " pex-clk3 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK2 , 6 , 0x74 , 0x78 , UINT_MAX , " pex-clk2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK1 , 7 , 0x74 , 0x78 , UINT_MAX , " pex-clk1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB0 , 9 , 0x74 , 0x78 , UINT_MAX , " usb0 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB1 , 10 , 0x74 , 0x78 , UINT_MAX , " usb1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB2 , 11 , 0x74 , 0x78 , UINT_MAX , " usb2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_USB_BIAS , 12 , 0x74 , 0x78 , UINT_MAX , " usb-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UART , 14 , 0x74 , 0x78 , UINT_MAX , " uart " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AUDIO , 17 , 0x74 , 0x78 , UINT_MAX , " audio " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HSIC , 19 , 0x74 , 0x78 , UINT_MAX , " hsic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DBG , 25 , 0x74 , 0x78 , UINT_MAX , " dbg " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI_DP0 , 28 , 0x74 , 0x78 , UINT_MAX , " hdmi-dp0 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI_DP1 , 29 , 0x74 , 0x78 , UINT_MAX , " hdmi-dp1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CNTRL , 0 , 0x7c , 0x80 , UINT_MAX , " pex-cntrl " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC2_HV , 2 , 0x7c , 0x80 , 5 , " sdmmc2-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC4 , 4 , 0x7c , 0x80 , UINT_MAX , " sdmmc4 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CAM , 6 , 0x7c , 0x80 , UINT_MAX , " cam " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSIB , 8 , 0x7c , 0x80 , UINT_MAX , " dsib " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSIC , 9 , 0x7c , 0x80 , UINT_MAX , " dsic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DSID , 10 , 0x7c , 0x80 , UINT_MAX , " dsid " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIC , 11 , 0x7c , 0x80 , UINT_MAX , " csic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSID , 12 , 0x7c , 0x80 , UINT_MAX , " csid " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIE , 13 , 0x7c , 0x80 , UINT_MAX , " csie " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIF , 14 , 0x7c , 0x80 , UINT_MAX , " csif " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SPI , 15 , 0x7c , 0x80 , UINT_MAX , " spi " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UFS , 17 , 0x7c , 0x80 , UINT_MAX , " ufs " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DMIC_HV , 20 , 0x7c , 0x80 , 2 , " dmic-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_EDP , 21 , 0x7c , 0x80 , UINT_MAX , " edp " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC1_HV , 23 , 0x7c , 0x80 , 4 , " sdmmc1-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC3_HV , 24 , 0x7c , 0x80 , 6 , " sdmmc3-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CONN , 28 , 0x7c , 0x80 , UINT_MAX , " conn " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AUDIO_HV , 29 , 0x7c , 0x80 , 1 , " audio-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AO_HV , UINT_MAX , UINT_MAX , UINT_MAX , 0 , " ao-hv " ) ,
2017-08-30 13:42:34 +03:00
} ;
2018-08-10 21:08:12 +03:00
static const struct pinctrl_pin_desc tegra186_pin_descs [ ] = {
2022-09-30 19:02:13 +03:00
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIA , " csia " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIB , " csib " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSI , " dsi " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_MIPI_BIAS , " mipi-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK_BIAS , " pex-clk-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK3 , " pex-clk3 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK2 , " pex-clk2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK1 , " pex-clk1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB0 , " usb0 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB1 , " usb1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB2 , " usb2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_USB_BIAS , " usb-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UART , " uart " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AUDIO , " audio " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HSIC , " hsic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DBG , " dbg " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI_DP0 , " hdmi-dp0 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI_DP1 , " hdmi-dp1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CNTRL , " pex-cntrl " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC2_HV , " sdmmc2-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC4 , " sdmmc4 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CAM , " cam " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSIB , " dsib " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSIC , " dsic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DSID , " dsid " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIC , " csic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSID , " csid " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIE , " csie " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIF , " csif " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SPI , " spi " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UFS , " ufs " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DMIC_HV , " dmic-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_EDP , " edp " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC1_HV , " sdmmc1-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC3_HV , " sdmmc3-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CONN , " conn " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AUDIO_HV , " audio-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AO_HV , " ao-hv " ) ,
2017-08-30 13:42:34 +03:00
} ;
static const struct tegra_pmc_regs tegra186_pmc_regs = {
. scratch0 = 0x2000 ,
2018-10-24 10:08:00 +03:00
. rst_status = 0x70 ,
. rst_source_shift = 0x2 ,
2019-11-18 09:33:46 +03:00
. rst_source_mask = 0x3c ,
2018-10-24 10:08:00 +03:00
. rst_level_shift = 0x0 ,
. rst_level_mask = 0x3 ,
2017-08-30 13:42:34 +03:00
} ;
2022-09-30 19:14:52 +03:00
static void tegra186_pmc_init ( struct tegra_pmc * pmc )
{
pmc - > syscore . suspend = tegra186_pmc_wake_syscore_suspend ;
2022-10-02 17:44:09 +03:00
pmc - > syscore . resume = tegra186_pmc_wake_syscore_resume ;
2022-09-30 19:14:52 +03:00
register_syscore_ops ( & pmc - > syscore ) ;
}
2017-08-30 13:42:34 +03:00
static void tegra186_pmc_setup_irq_polarity ( struct tegra_pmc * pmc ,
struct device_node * np ,
bool invert )
{
struct resource regs ;
void __iomem * wake ;
u32 value ;
int index ;
index = of_property_match_string ( np , " reg-names " , " wake " ) ;
if ( index < 0 ) {
2019-01-25 13:22:52 +03:00
dev_err ( pmc - > dev , " failed to find PMC wake registers \n " ) ;
2017-08-30 13:42:34 +03:00
return ;
}
of_address_to_resource ( np , index , & regs ) ;
2020-01-06 11:43:50 +03:00
wake = ioremap ( regs . start , resource_size ( & regs ) ) ;
2017-08-30 13:42:34 +03:00
if ( ! wake ) {
2019-01-25 13:22:52 +03:00
dev_err ( pmc - > dev , " failed to map PMC wake registers \n " ) ;
2017-08-30 13:42:34 +03:00
return ;
}
value = readl ( wake + WAKE_AOWAKE_CTRL ) ;
if ( invert )
value | = WAKE_AOWAKE_CTRL_INTR_POLARITY ;
else
value & = ~ WAKE_AOWAKE_CTRL_INTR_POLARITY ;
writel ( value , wake + WAKE_AOWAKE_CTRL ) ;
iounmap ( wake ) ;
}
2020-09-17 13:07:49 +03:00
static const char * const tegra186_reset_sources [ ] = {
" SYS_RESET " ,
" AOWDT " ,
" MCCPLEXWDT " ,
" BPMPWDT " ,
" SCEWDT " ,
" SPEWDT " ,
" APEWDT " ,
" BCCPLEXWDT " ,
" SENSOR " ,
" AOTAG " ,
" VFSENSOR " ,
" SWREST " ,
" SC7 " ,
" HSM " ,
" CORESIGHT "
} ;
static const char * const tegra186_reset_levels [ ] = {
" L0 " , " L1 " , " L2 " , " WARM "
} ;
2018-09-19 19:41:59 +03:00
static const struct tegra_wake_event tegra186_wake_events [ ] = {
2020-04-17 20:11:16 +03:00
TEGRA_WAKE_IRQ ( " pmu " , 24 , 209 ) ,
2019-01-23 14:38:43 +03:00
TEGRA_WAKE_GPIO ( " power " , 29 , 1 , TEGRA186_AON_GPIO ( FF , 0 ) ) ,
2018-09-19 19:41:59 +03:00
TEGRA_WAKE_IRQ ( " rtc " , 73 , 10 ) ,
} ;
2017-08-30 13:42:34 +03:00
static const struct tegra_pmc_soc tegra186_pmc_soc = {
2021-09-27 01:40:26 +03:00
. supports_core_domain = false ,
2017-08-30 13:42:34 +03:00
. num_powergates = 0 ,
. powergates = NULL ,
. num_cpu_powergates = 0 ,
. cpu_powergates = NULL ,
. has_tsense_reset = false ,
. has_gpu_clamps = false ,
2019-01-25 13:22:54 +03:00
. needs_mbist_war = false ,
2018-08-10 21:08:07 +03:00
. has_impl_33v_pwr = true ,
2019-01-25 13:22:55 +03:00
. maybe_tz_only = false ,
2017-08-30 13:42:34 +03:00
. num_io_pads = ARRAY_SIZE ( tegra186_io_pads ) ,
. io_pads = tegra186_io_pads ,
2018-08-10 21:08:12 +03:00
. num_pin_descs = ARRAY_SIZE ( tegra186_pin_descs ) ,
. pin_descs = tegra186_pin_descs ,
2017-08-30 13:42:34 +03:00
. regs = & tegra186_pmc_regs ,
2022-09-30 19:14:52 +03:00
. init = tegra186_pmc_init ,
2017-08-30 13:42:34 +03:00
. setup_irq_polarity = tegra186_pmc_setup_irq_polarity ,
2023-03-30 20:06:21 +03:00
. set_wake_filters = tegra186_pmc_set_wake_filters ,
2019-08-16 22:42:01 +03:00
. irq_set_wake = tegra186_pmc_irq_set_wake ,
. irq_set_type = tegra186_pmc_irq_set_type ,
2018-10-24 10:08:00 +03:00
. reset_sources = tegra186_reset_sources ,
2019-04-16 19:48:06 +03:00
. num_reset_sources = ARRAY_SIZE ( tegra186_reset_sources ) ,
2018-10-24 10:08:00 +03:00
. reset_levels = tegra186_reset_levels ,
2019-04-16 19:48:06 +03:00
. num_reset_levels = ARRAY_SIZE ( tegra186_reset_levels ) ,
2018-09-19 19:41:59 +03:00
. num_wake_events = ARRAY_SIZE ( tegra186_wake_events ) ,
. wake_events = tegra186_wake_events ,
2022-09-30 19:14:52 +03:00
. max_wake_events = 96 ,
. max_wake_vectors = 3 ,
2020-01-14 10:24:13 +03:00
. pmc_clks_data = NULL ,
. num_pmc_clks = 0 ,
2020-01-14 10:24:15 +03:00
. has_blink_output = false ,
2021-01-20 10:34:07 +03:00
. has_usb_sleepwalk = false ,
2017-08-30 13:42:34 +03:00
} ;
2018-01-25 15:43:45 +03:00
static const struct tegra_io_pad_soc tegra194_io_pads [ ] = {
2022-09-30 19:02:13 +03:00
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIA , 0 , 0x74 , 0x78 , UINT_MAX , " csia " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIB , 1 , 0x74 , 0x78 , UINT_MAX , " csib " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_MIPI_BIAS , 3 , 0x74 , 0x78 , UINT_MAX , " mipi-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK_BIAS , 4 , 0x74 , 0x78 , UINT_MAX , " pex-clk-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK3 , 5 , 0x74 , 0x78 , UINT_MAX , " pex-clk3 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK2 , 6 , 0x74 , 0x78 , UINT_MAX , " pex-clk2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK1 , 7 , 0x74 , 0x78 , UINT_MAX , " pex-clk1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_EQOS , 8 , 0x74 , 0x78 , UINT_MAX , " eqos " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK_2_BIAS , 9 , 0x74 , 0x78 , UINT_MAX , " pex-clk-2-bias " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CLK_2 , 10 , 0x74 , 0x78 , UINT_MAX , " pex-clk-2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DAP3 , 11 , 0x74 , 0x78 , UINT_MAX , " dap3 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DAP5 , 12 , 0x74 , 0x78 , UINT_MAX , " dap5 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UART , 14 , 0x74 , 0x78 , UINT_MAX , " uart " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PWR_CTL , 15 , 0x74 , 0x78 , UINT_MAX , " pwr-ctl " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SOC_GPIO53 , 16 , 0x74 , 0x78 , UINT_MAX , " soc-gpio53 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AUDIO , 17 , 0x74 , 0x78 , UINT_MAX , " audio " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_GP_PWM2 , 18 , 0x74 , 0x78 , UINT_MAX , " gp-pwm2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_GP_PWM3 , 19 , 0x74 , 0x78 , UINT_MAX , " gp-pwm3 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SOC_GPIO12 , 20 , 0x74 , 0x78 , UINT_MAX , " soc-gpio12 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SOC_GPIO13 , 21 , 0x74 , 0x78 , UINT_MAX , " soc-gpio13 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SOC_GPIO10 , 22 , 0x74 , 0x78 , UINT_MAX , " soc-gpio10 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UART4 , 23 , 0x74 , 0x78 , UINT_MAX , " uart4 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UART5 , 24 , 0x74 , 0x78 , UINT_MAX , " uart5 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_DBG , 25 , 0x74 , 0x78 , UINT_MAX , " dbg " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI_DP3 , 26 , 0x74 , 0x78 , UINT_MAX , " hdmi-dp3 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI_DP2 , 27 , 0x74 , 0x78 , UINT_MAX , " hdmi-dp2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI_DP0 , 28 , 0x74 , 0x78 , UINT_MAX , " hdmi-dp0 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI_DP1 , 29 , 0x74 , 0x78 , UINT_MAX , " hdmi-dp1 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CNTRL , 0 , 0x7c , 0x80 , UINT_MAX , " pex-cntrl " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_CTL2 , 1 , 0x7c , 0x80 , UINT_MAX , " pex-ctl2 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_L0_RST , 2 , 0x7c , 0x80 , UINT_MAX , " pex-l0-rst " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_L1_RST , 3 , 0x7c , 0x80 , UINT_MAX , " pex-l1-rst " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC4 , 4 , 0x7c , 0x80 , UINT_MAX , " sdmmc4 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_PEX_L5_RST , 5 , 0x7c , 0x80 , UINT_MAX , " pex-l5-rst " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CAM , 6 , 0x7c , 0x80 , UINT_MAX , " cam " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIC , 11 , 0x7c , 0x80 , UINT_MAX , " csic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSID , 12 , 0x7c , 0x80 , UINT_MAX , " csid " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIE , 13 , 0x7c , 0x80 , UINT_MAX , " csie " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIF , 14 , 0x7c , 0x80 , UINT_MAX , " csif " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SPI , 15 , 0x7c , 0x80 , UINT_MAX , " spi " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UFS , 17 , 0x7c , 0x80 , UINT_MAX , " ufs " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIG , 18 , 0x7c , 0x80 , UINT_MAX , " csig " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIH , 19 , 0x7c , 0x80 , UINT_MAX , " csih " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_EDP , 21 , 0x7c , 0x80 , UINT_MAX , " edp " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC1_HV , 23 , 0x7c , 0x80 , 4 , " sdmmc1-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC3_HV , 24 , 0x7c , 0x80 , 6 , " sdmmc3-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CONN , 28 , 0x7c , 0x80 , UINT_MAX , " conn " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AUDIO_HV , 29 , 0x7c , 0x80 , 1 , " audio-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AO_HV , UINT_MAX , UINT_MAX , UINT_MAX , 0 , " ao-hv " ) ,
2020-03-10 13:43:56 +03:00
} ;
static const struct pinctrl_pin_desc tegra194_pin_descs [ ] = {
2022-09-30 19:02:13 +03:00
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIA , " csia " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIB , " csib " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_MIPI_BIAS , " mipi-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK_BIAS , " pex-clk-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK3 , " pex-clk3 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK2 , " pex-clk2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK1 , " pex-clk1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_EQOS , " eqos " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK_2_BIAS , " pex-clk-2-bias " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CLK_2 , " pex-clk-2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DAP3 , " dap3 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DAP5 , " dap5 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UART , " uart " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PWR_CTL , " pwr-ctl " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SOC_GPIO53 , " soc-gpio53 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AUDIO , " audio " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_GP_PWM2 , " gp-pwm2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_GP_PWM3 , " gp-pwm3 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SOC_GPIO12 , " soc-gpio12 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SOC_GPIO13 , " soc-gpio13 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SOC_GPIO10 , " soc-gpio10 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UART4 , " uart4 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UART5 , " uart5 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_DBG , " dbg " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI_DP3 , " hdmi-dp3 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI_DP2 , " hdmi-dp2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI_DP0 , " hdmi-dp0 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI_DP1 , " hdmi-dp1 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CNTRL , " pex-cntrl " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_CTL2 , " pex-ctl2 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_L0_RST , " pex-l0-rst " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_L1_RST , " pex-l1-rst " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC4 , " sdmmc4 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_PEX_L5_RST , " pex-l5-rst " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CAM , " cam " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIC , " csic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSID , " csid " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIE , " csie " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIF , " csif " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SPI , " spi " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UFS , " ufs " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIG , " csig " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIH , " csih " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_EDP , " edp " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC1_HV , " sdmmc1-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC3_HV , " sdmmc3-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CONN , " conn " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AUDIO_HV , " audio-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AO_HV , " ao-hv " ) ,
2018-01-25 15:43:45 +03:00
} ;
2019-11-18 09:33:48 +03:00
static const struct tegra_pmc_regs tegra194_pmc_regs = {
. scratch0 = 0x2000 ,
. rst_status = 0x70 ,
. rst_source_shift = 0x2 ,
. rst_source_mask = 0x7c ,
. rst_level_shift = 0x0 ,
. rst_level_mask = 0x3 ,
} ;
static const char * const tegra194_reset_sources [ ] = {
" SYS_RESET_N " ,
" AOWDT " ,
" BCCPLEXWDT " ,
" BPMPWDT " ,
" SCEWDT " ,
" SPEWDT " ,
" APEWDT " ,
" LCCPLEXWDT " ,
" SENSOR " ,
" AOTAG " ,
" VFSENSOR " ,
" MAINSWRST " ,
" SC7 " ,
" HSM " ,
" CSITE " ,
" RCEWDT " ,
" PVA0WDT " ,
" PVA1WDT " ,
" L1A_ASYNC " ,
" BPMPBOOT " ,
" FUSECRC " ,
} ;
2018-09-19 19:42:37 +03:00
static const struct tegra_wake_event tegra194_wake_events [ ] = {
2020-05-07 13:13:48 +03:00
TEGRA_WAKE_IRQ ( " pmu " , 24 , 209 ) ,
2018-09-19 19:42:37 +03:00
TEGRA_WAKE_GPIO ( " power " , 29 , 1 , TEGRA194_AON_GPIO ( EE , 4 ) ) ,
TEGRA_WAKE_IRQ ( " rtc " , 73 , 10 ) ,
2022-07-11 18:40:31 +03:00
TEGRA_WAKE_SIMPLE ( " usb3-port-0 " , 76 ) ,
TEGRA_WAKE_SIMPLE ( " usb3-port-1 " , 77 ) ,
TEGRA_WAKE_SIMPLE ( " usb3-port-2-3 " , 78 ) ,
TEGRA_WAKE_SIMPLE ( " usb2-port-0 " , 79 ) ,
TEGRA_WAKE_SIMPLE ( " usb2-port-1 " , 80 ) ,
TEGRA_WAKE_SIMPLE ( " usb2-port-2 " , 81 ) ,
TEGRA_WAKE_SIMPLE ( " usb2-port-3 " , 82 ) ,
2018-09-19 19:42:37 +03:00
} ;
2018-01-25 15:43:45 +03:00
static const struct tegra_pmc_soc tegra194_pmc_soc = {
2021-09-27 01:40:26 +03:00
. supports_core_domain = false ,
2018-01-25 15:43:45 +03:00
. num_powergates = 0 ,
. powergates = NULL ,
. num_cpu_powergates = 0 ,
. cpu_powergates = NULL ,
. has_tsense_reset = false ,
. has_gpu_clamps = false ,
2019-01-25 13:22:54 +03:00
. needs_mbist_war = false ,
2020-03-10 13:43:56 +03:00
. has_impl_33v_pwr = true ,
2019-01-25 13:22:55 +03:00
. maybe_tz_only = false ,
2018-01-25 15:43:45 +03:00
. num_io_pads = ARRAY_SIZE ( tegra194_io_pads ) ,
. io_pads = tegra194_io_pads ,
2020-03-10 13:43:56 +03:00
. num_pin_descs = ARRAY_SIZE ( tegra194_pin_descs ) ,
. pin_descs = tegra194_pin_descs ,
2019-11-18 09:33:48 +03:00
. regs = & tegra194_pmc_regs ,
2022-09-30 19:14:52 +03:00
. init = tegra186_pmc_init ,
2018-01-25 15:43:45 +03:00
. setup_irq_polarity = tegra186_pmc_setup_irq_polarity ,
2023-03-30 20:06:21 +03:00
. set_wake_filters = tegra186_pmc_set_wake_filters ,
2019-11-18 09:33:47 +03:00
. irq_set_wake = tegra186_pmc_irq_set_wake ,
. irq_set_type = tegra186_pmc_irq_set_type ,
2019-11-18 09:33:48 +03:00
. reset_sources = tegra194_reset_sources ,
. num_reset_sources = ARRAY_SIZE ( tegra194_reset_sources ) ,
. reset_levels = tegra186_reset_levels ,
. num_reset_levels = ARRAY_SIZE ( tegra186_reset_levels ) ,
2018-09-19 19:42:37 +03:00
. num_wake_events = ARRAY_SIZE ( tegra194_wake_events ) ,
. wake_events = tegra194_wake_events ,
2022-09-30 19:14:52 +03:00
. max_wake_events = 96 ,
. max_wake_vectors = 3 ,
2020-01-14 10:24:13 +03:00
. pmc_clks_data = NULL ,
. num_pmc_clks = 0 ,
2020-01-14 10:24:15 +03:00
. has_blink_output = false ,
2021-01-20 10:34:07 +03:00
. has_usb_sleepwalk = false ,
2017-08-30 13:42:34 +03:00
} ;
2022-09-30 19:02:13 +03:00
static const struct tegra_io_pad_soc tegra234_io_pads [ ] = {
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIA , 0 , 0xe0c0 , 0xe0c4 , UINT_MAX , " csia " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIB , 1 , 0xe0c0 , 0xe0c4 , UINT_MAX , " csib " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_HDMI_DP0 , 0 , 0xe0d0 , 0xe0d4 , UINT_MAX , " hdmi-dp0 " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIC , 2 , 0xe0c0 , 0xe0c4 , UINT_MAX , " csic " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSID , 3 , 0xe0c0 , 0xe0c4 , UINT_MAX , " csid " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIE , 4 , 0xe0c0 , 0xe0c4 , UINT_MAX , " csie " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIF , 5 , 0xe0c0 , 0xe0c4 , UINT_MAX , " csif " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_UFS , 0 , 0xe064 , 0xe068 , UINT_MAX , " ufs " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_EDP , 1 , 0xe05c , 0xe060 , UINT_MAX , " edp " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC1_HV , 0 , 0xe054 , 0xe058 , 4 , " sdmmc1-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_SDMMC3_HV , UINT_MAX , UINT_MAX , UINT_MAX , 6 , " sdmmc3-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AUDIO_HV , UINT_MAX , UINT_MAX , UINT_MAX , 1 , " audio-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_AO_HV , UINT_MAX , UINT_MAX , UINT_MAX , 0 , " ao-hv " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIG , 6 , 0xe0c0 , 0xe0c4 , UINT_MAX , " csig " ) ,
TEGRA_IO_PAD ( TEGRA_IO_PAD_CSIH , 7 , 0xe0c0 , 0xe0c4 , UINT_MAX , " csih " ) ,
} ;
static const struct pinctrl_pin_desc tegra234_pin_descs [ ] = {
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIA , " csia " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIB , " csib " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_HDMI_DP0 , " hdmi-dp0 " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIC , " csic " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSID , " csid " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIE , " csie " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIF , " csif " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_UFS , " ufs " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_EDP , " edp " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC1_HV , " sdmmc1-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_SDMMC3_HV , " sdmmc3-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AUDIO_HV , " audio-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_AO_HV , " ao-hv " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIG , " csig " ) ,
TEGRA_IO_PIN_DESC ( TEGRA_IO_PAD_CSIH , " csih " ) ,
} ;
2020-09-17 13:07:50 +03:00
static const struct tegra_pmc_regs tegra234_pmc_regs = {
. scratch0 = 0x2000 ,
. rst_status = 0x70 ,
. rst_source_shift = 0x2 ,
. rst_source_mask = 0xfc ,
. rst_level_shift = 0x0 ,
. rst_level_mask = 0x3 ,
} ;
static const char * const tegra234_reset_sources [ ] = {
2022-04-01 17:33:43 +03:00
" SYS_RESET_N " , /* 0x0 */
2020-09-17 13:07:50 +03:00
" AOWDT " ,
" BCCPLEXWDT " ,
" BPMPWDT " ,
" SCEWDT " ,
" SPEWDT " ,
" APEWDT " ,
" LCCPLEXWDT " ,
2022-04-01 17:33:43 +03:00
" SENSOR " , /* 0x8 */
NULL ,
NULL ,
2020-09-17 13:07:50 +03:00
" MAINSWRST " ,
" SC7 " ,
" HSM " ,
2022-04-01 17:33:43 +03:00
NULL ,
2020-09-17 13:07:50 +03:00
" RCEWDT " ,
2022-04-01 17:33:43 +03:00
NULL , /* 0x10 */
NULL ,
NULL ,
2020-09-17 13:07:50 +03:00
" BPMPBOOT " ,
" FUSECRC " ,
2022-04-01 17:33:43 +03:00
" DCEWDT " ,
" PSCWDT " ,
" PSC " ,
" CSITE_SW " , /* 0x18 */
" POD " ,
" SCPM " ,
" VREFRO_POWERBAD " ,
" VMON " ,
" FMON " ,
" FSI_R5WDT " ,
" FSI_THERM " ,
" FSI_R52C0WDT " , /* 0x20 */
" FSI_R52C1WDT " ,
" FSI_R52C2WDT " ,
" FSI_R52C3WDT " ,
" FSI_FMON " ,
" FSI_VMON " , /* 0x25 */
2020-09-17 13:07:50 +03:00
} ;
2022-01-25 08:57:42 +03:00
static const struct tegra_wake_event tegra234_wake_events [ ] = {
2023-03-06 18:09:00 +03:00
TEGRA_WAKE_IRQ ( " pmu " , 24 , 209 ) ,
2022-01-25 08:57:42 +03:00
TEGRA_WAKE_GPIO ( " power " , 29 , 1 , TEGRA234_AON_GPIO ( EE , 4 ) ) ,
2023-03-23 16:13:24 +03:00
TEGRA_WAKE_GPIO ( " mgbe " , 56 , 0 , TEGRA234_MAIN_GPIO ( Y , 3 ) ) ,
2022-01-25 08:57:42 +03:00
TEGRA_WAKE_IRQ ( " rtc " , 73 , 10 ) ,
} ;
2020-09-17 13:07:50 +03:00
static const struct tegra_pmc_soc tegra234_pmc_soc = {
2021-09-27 01:40:26 +03:00
. supports_core_domain = false ,
2020-09-17 13:07:50 +03:00
. num_powergates = 0 ,
. powergates = NULL ,
. num_cpu_powergates = 0 ,
. cpu_powergates = NULL ,
. has_tsense_reset = false ,
. has_gpu_clamps = false ,
. needs_mbist_war = false ,
. has_impl_33v_pwr = true ,
. maybe_tz_only = false ,
2022-09-30 19:02:13 +03:00
. num_io_pads = ARRAY_SIZE ( tegra234_io_pads ) ,
. io_pads = tegra234_io_pads ,
. num_pin_descs = ARRAY_SIZE ( tegra234_pin_descs ) ,
. pin_descs = tegra234_pin_descs ,
2020-09-17 13:07:50 +03:00
. regs = & tegra234_pmc_regs ,
2022-09-30 19:14:52 +03:00
. init = tegra186_pmc_init ,
2020-09-17 13:07:50 +03:00
. setup_irq_polarity = tegra186_pmc_setup_irq_polarity ,
2023-03-30 20:06:21 +03:00
. set_wake_filters = tegra186_pmc_set_wake_filters ,
2020-09-17 13:07:50 +03:00
. irq_set_wake = tegra186_pmc_irq_set_wake ,
. irq_set_type = tegra186_pmc_irq_set_type ,
. reset_sources = tegra234_reset_sources ,
. num_reset_sources = ARRAY_SIZE ( tegra234_reset_sources ) ,
. reset_levels = tegra186_reset_levels ,
. num_reset_levels = ARRAY_SIZE ( tegra186_reset_levels ) ,
2022-01-25 08:57:42 +03:00
. num_wake_events = ARRAY_SIZE ( tegra234_wake_events ) ,
. wake_events = tegra234_wake_events ,
2022-09-30 19:14:52 +03:00
. max_wake_events = 96 ,
. max_wake_vectors = 3 ,
2020-09-17 13:07:50 +03:00
. pmc_clks_data = NULL ,
. num_pmc_clks = 0 ,
. has_blink_output = false ,
} ;
2014-07-11 15:19:06 +04:00
static const struct of_device_id tegra_pmc_match [ ] = {
2020-09-17 13:07:50 +03:00
{ . compatible = " nvidia,tegra234-pmc " , . data = & tegra234_pmc_soc } ,
2018-01-25 15:43:45 +03:00
{ . compatible = " nvidia,tegra194-pmc " , . data = & tegra194_pmc_soc } ,
2017-08-30 13:42:34 +03:00
{ . compatible = " nvidia,tegra186-pmc " , . data = & tegra186_pmc_soc } ,
2015-03-23 13:31:29 +03:00
{ . compatible = " nvidia,tegra210-pmc " , . data = & tegra210_pmc_soc } ,
2015-04-29 13:42:28 +03:00
{ . compatible = " nvidia,tegra132-pmc " , . data = & tegra124_pmc_soc } ,
2014-07-11 15:19:06 +04:00
{ . compatible = " nvidia,tegra124-pmc " , . data = & tegra124_pmc_soc } ,
{ . compatible = " nvidia,tegra114-pmc " , . data = & tegra114_pmc_soc } ,
{ . compatible = " nvidia,tegra30-pmc " , . data = & tegra30_pmc_soc } ,
{ . compatible = " nvidia,tegra20-pmc " , . data = & tegra20_pmc_soc } ,
{ }
} ;
2021-06-01 05:31:18 +03:00
static void tegra_pmc_sync_state ( struct device * dev )
{
int err ;
2021-09-27 01:40:26 +03:00
/*
* Newer device - trees have power domains , but we need to prepare all
* device drivers with runtime PM and OPP support first , otherwise
* state syncing is unsafe .
*/
if ( ! pmc - > soc - > supports_core_domain )
return ;
2021-06-01 05:31:18 +03:00
/*
* Older device - trees don ' t have core PD , and thus , there are
* no dependencies that will block the state syncing . We shouldn ' t
* mark the domain as synced in this case .
*/
if ( ! pmc - > core_domain_registered )
return ;
pmc - > core_domain_state_synced = true ;
/* this is a no-op if core regulator isn't used */
mutex_lock ( & pmc - > powergates_lock ) ;
err = dev_pm_opp_sync_regulators ( dev ) ;
mutex_unlock ( & pmc - > powergates_lock ) ;
if ( err )
dev_err ( dev , " failed to sync regulators: %d \n " , err ) ;
}
2014-07-11 15:19:06 +04:00
static struct platform_driver tegra_pmc_driver = {
. driver = {
. name = " tegra-pmc " ,
. suppress_bind_attrs = true ,
. of_match_table = tegra_pmc_match ,
2014-12-10 01:36:50 +03:00
# if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
2014-07-11 15:19:06 +04:00
. pm = & tegra_pmc_pm_ops ,
2014-12-10 01:36:50 +03:00
# endif
2021-06-01 05:31:18 +03:00
. sync_state = tegra_pmc_sync_state ,
2014-07-11 15:19:06 +04:00
} ,
. probe = tegra_pmc_probe ,
} ;
2015-05-02 03:10:57 +03:00
builtin_platform_driver ( tegra_pmc_driver ) ;
2014-07-11 15:19:06 +04:00
2019-01-25 13:22:55 +03:00
static bool __init tegra_pmc_detect_tz_only ( struct tegra_pmc * pmc )
{
u32 value , saved ;
saved = readl ( pmc - > base + pmc - > soc - > regs - > scratch0 ) ;
value = saved ^ 0xffffffff ;
if ( value = = 0xffffffff )
value = 0xdeadbeef ;
/* write pattern and read it back */
writel ( value , pmc - > base + pmc - > soc - > regs - > scratch0 ) ;
value = readl ( pmc - > base + pmc - > soc - > regs - > scratch0 ) ;
/* if we read all-zeroes, access is restricted to TZ only */
if ( value = = 0 ) {
pr_info ( " access to PMC is restricted to TZ \n " ) ;
return true ;
}
/* restore original value */
writel ( saved , pmc - > base + pmc - > soc - > regs - > scratch0 ) ;
return false ;
}
2014-07-11 15:19:06 +04:00
/*
* Early initialization to allow access to registers in the very early boot
* process .
*/
static int __init tegra_pmc_early_init ( void )
{
const struct of_device_id * match ;
struct device_node * np ;
struct resource regs ;
2019-04-16 19:48:08 +03:00
unsigned int i ;
2014-07-11 15:19:06 +04:00
bool invert ;
2016-06-28 13:38:26 +03:00
mutex_init ( & pmc - > powergates_lock ) ;
2014-07-11 15:19:06 +04:00
np = of_find_matching_node_and_match ( NULL , tegra_pmc_match , & match ) ;
if ( ! np ) {
2015-04-29 13:42:28 +03:00
/*
* Fall back to legacy initialization for 32 - bit ARM only . All
* 64 - bit ARM device tree files for Tegra are required to have
* a PMC node .
*
* This is for backwards - compatibility with old device trees
* that didn ' t contain a PMC node . Note that in this case the
* SoC data can ' t be matched and therefore powergating is
* disabled .
*/
if ( IS_ENABLED ( CONFIG_ARM ) & & soc_is_tegra ( ) ) {
pr_warn ( " DT node not found, powergating disabled \n " ) ;
regs . start = 0x7000e400 ;
regs . end = 0x7000e7ff ;
regs . flags = IORESOURCE_MEM ;
pr_warn ( " Using memory region %pR \n " , & regs ) ;
} else {
/*
* At this point we ' re not running on Tegra , so play
* nice with multi - platform kernels .
*/
return 0 ;
}
2014-07-11 15:19:06 +04:00
} else {
2015-04-29 13:42:28 +03:00
/*
* Extract information from the device tree if we ' ve found a
* matching node .
*/
if ( of_address_to_resource ( np , 0 , & regs ) < 0 ) {
pr_err ( " failed to get PMC registers \n " ) ;
2016-06-28 13:38:27 +03:00
of_node_put ( np ) ;
2015-04-29 13:42:28 +03:00
return - ENXIO ;
}
2014-07-11 15:19:06 +04:00
}
2020-01-06 11:43:50 +03:00
pmc - > base = ioremap ( regs . start , resource_size ( & regs ) ) ;
2014-07-11 15:19:06 +04:00
if ( ! pmc - > base ) {
pr_err ( " failed to map PMC registers \n " ) ;
2016-06-28 13:38:27 +03:00
of_node_put ( np ) ;
2014-07-11 15:19:06 +04:00
return - ENXIO ;
}
2022-09-06 16:51:17 +03:00
if ( of_device_is_available ( np ) ) {
2016-06-28 13:38:25 +03:00
pmc - > soc = match - > data ;
2019-01-25 13:22:55 +03:00
if ( pmc - > soc - > maybe_tz_only )
pmc - > tz_only = tegra_pmc_detect_tz_only ( pmc ) ;
2019-04-16 19:48:08 +03:00
/* Create a bitmap of the available and valid partitions */
for ( i = 0 ; i < pmc - > soc - > num_powergates ; i + + )
if ( pmc - > soc - > powergates [ i ] )
set_bit ( i , pmc - > powergates_available ) ;
2014-07-11 15:19:06 +04:00
2016-06-28 13:38:24 +03:00
/*
* Invert the interrupt polarity if a PMC device tree node
* exists and contains the nvidia , invert - interrupt property .
*/
invert = of_property_read_bool ( np , " nvidia,invert-interrupt " ) ;
2014-07-11 15:19:06 +04:00
2017-08-30 13:32:58 +03:00
pmc - > soc - > setup_irq_polarity ( pmc , np , invert ) ;
2016-06-28 13:38:27 +03:00
of_node_put ( np ) ;
2016-06-28 13:38:24 +03:00
}
2014-07-11 15:19:06 +04:00
return 0 ;
}
early_initcall ( tegra_pmc_early_init ) ;