From 6c0bd217c361fa820d953e33fc7b6b95571c28ac Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Jun 2016 18:36:12 +0530 Subject: [PATCH 01/10] soc/tegra: pmc: Use BIT macro for register field definition Use BIT macro for register field definition and make constant as U when using in shift operator like (3 << 30) to (3U << 30) Signed-off-by: Laxman Dewangan Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 52 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 7792ed88d80b..3013c6d28521 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -45,29 +45,29 @@ #include #define PMC_CNTRL 0x0 -#define PMC_CNTRL_SYSCLK_POLARITY (1 << 10) /* sys clk polarity */ -#define PMC_CNTRL_SYSCLK_OE (1 << 11) /* system clock enable */ -#define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */ -#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ -#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ -#define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */ -#define PMC_CNTRL_MAIN_RST (1 << 4) +#define PMC_CNTRL_MAIN_RST BIT(4) +#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ +#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ +#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */ +#define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */ +#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ +#define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ #define DPD_SAMPLE 0x020 -#define DPD_SAMPLE_ENABLE (1 << 0) +#define DPD_SAMPLE_ENABLE BIT(0) #define DPD_SAMPLE_DISABLE (0 << 0) #define PWRGATE_TOGGLE 0x30 -#define PWRGATE_TOGGLE_START (1 << 8) +#define PWRGATE_TOGGLE_START BIT(8) #define REMOVE_CLAMPING 0x34 #define PWRGATE_STATUS 0x38 #define PMC_SCRATCH0 0x50 -#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) -#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) -#define PMC_SCRATCH0_MODE_RCM (1 << 1) +#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 | \ PMC_SCRATCH0_MODE_BOOTLOADER | \ PMC_SCRATCH0_MODE_RCM) @@ -78,8 +78,8 @@ #define PMC_SCRATCH41 0x140 #define PMC_SENSOR_CTRL 0x1b0 -#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) -#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) +#define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) +#define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) #define PMC_RST_STATUS 0x1b4 #define PMC_RST_STATUS_POR 0 @@ -90,10 +90,10 @@ #define PMC_RST_STATUS_AOTAG 5 #define IO_DPD_REQ 0x1b8 -#define IO_DPD_REQ_CODE_IDLE (0 << 30) -#define IO_DPD_REQ_CODE_OFF (1 << 30) -#define IO_DPD_REQ_CODE_ON (2 << 30) -#define IO_DPD_REQ_CODE_MASK (3 << 30) +#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) #define IO_DPD_STATUS 0x1bc #define IO_DPD2_REQ 0x1c0 @@ -101,16 +101,16 @@ #define SEL_DPD_TIM 0x1c8 #define PMC_SCRATCH54 0x258 -#define PMC_SCRATCH54_DATA_SHIFT 8 -#define PMC_SCRATCH54_ADDR_SHIFT 0 +#define PMC_SCRATCH54_DATA_SHIFT 8 +#define PMC_SCRATCH54_ADDR_SHIFT 0 #define PMC_SCRATCH55 0x25c -#define PMC_SCRATCH55_RESET_TEGRA (1 << 31) -#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 -#define PMC_SCRATCH55_PINMUX_SHIFT 24 -#define PMC_SCRATCH55_16BITOP (1 << 15) -#define PMC_SCRATCH55_CHECKSUM_SHIFT 16 -#define PMC_SCRATCH55_I2CSLV1_SHIFT 0 +#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 #define GPU_RG_CNTRL 0x2d4 From 84cf85ea6ea29fc0c933a85fb3e900315759a581 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Jun 2016 18:36:13 +0530 Subject: [PATCH 02/10] soc/tegra: pmc: Correct type of variable for tegra_pmc_readl() The function tegra_pmc_readl() returns the u32 type data and hence change the data type of variable where this data is stored to u32 type. Signed-off-by: Laxman Dewangan Reviewed-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 3013c6d28521..01da62484e20 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -942,10 +942,10 @@ static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, return 0; } -static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, - unsigned long val, unsigned long timeout) +static int tegra_io_rail_poll(unsigned long offset, u32 mask, + u32 val, unsigned long timeout) { - unsigned long value; + u32 value; timeout = jiffies + msecs_to_jiffies(timeout); From 95b780b3d7e3f1900e09dfe90e959f220a8df343 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 10 Oct 2016 13:13:36 +0200 Subject: [PATCH 03/10] soc/tegra: pmc: Use consistent ordering of bit definitions Bit definitions are sorted in decreasing order by offset. Apply the same ordering to all definitions. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 01da62484e20..d57f3e0f5f27 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -45,13 +45,13 @@ #include #define PMC_CNTRL 0x0 -#define PMC_CNTRL_MAIN_RST BIT(4) -#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ -#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ -#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */ -#define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */ -#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ +#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 */ +#define PMC_CNTRL_MAIN_RST BIT(4) #define DPD_SAMPLE 0x020 #define DPD_SAMPLE_ENABLE BIT(0) From 21b4991051780b49b217c363f79366ed94c3b4b7 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 10 Oct 2016 15:14:34 +0200 Subject: [PATCH 04/10] soc/tegra: pmc: Add I/O pad voltage support I/O pins on Tegra SoCs are grouped into so-called I/O pads. Each such pad can be used to control the common voltage signal level and power state of the pins in the given pad. I/O pads can be powered down even if the system is active, which can save power from that I/O interface. For SoC generations prior to Tegra124 the I/O pad voltage is automatically detected and hence the system software doesn't need to configure it. However, starting with Tegra210 the detection logic has been removed, so explicit control of the I/O pad voltage by system software is required. Signed-off-by: Laxman Dewangan Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 273 ++++++++++++++++++++++++++++++++++------ include/soc/tegra/pmc.h | 126 ++++++++++++++----- 2 files changed, 332 insertions(+), 67 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d57f3e0f5f27..81968ef19618 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -64,6 +64,8 @@ #define PWRGATE_STATUS 0x38 +#define PMC_PWR_DET 0x48 + #define PMC_SCRATCH0 0x50 #define PMC_SCRATCH0_MODE_RECOVERY BIT(31) #define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) @@ -75,6 +77,8 @@ #define PMC_CPUPWRGOOD_TIMER 0xc8 #define PMC_CPUPWROFF_TIMER 0xcc +#define PMC_PWR_DET_VALUE 0xe4 + #define PMC_SCRATCH41 0x140 #define PMC_SENSOR_CTRL 0x1b0 @@ -124,6 +128,12 @@ struct tegra_powergate { unsigned int num_resets; }; +struct tegra_io_pad_soc { + enum tegra_io_pad id; + unsigned int dpd; + unsigned int voltage; +}; + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; @@ -132,6 +142,9 @@ struct tegra_pmc_soc { bool has_tsense_reset; bool has_gpu_clamps; + + const struct tegra_io_pad_soc *io_pads; + unsigned int num_io_pads; }; /** @@ -908,21 +921,34 @@ static void tegra_powergate_init(struct tegra_pmc *pmc, of_node_put(np); } -static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, - unsigned long *status, unsigned int *bit) +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; +} + +static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, + unsigned long *status, unsigned int *bit) +{ + const struct tegra_io_pad_soc *pad; unsigned long rate, value; - *bit = id % 32; + pad = tegra_io_pad_find(pmc, id); + if (!pad) + return -ENOENT; - /* - * There are two sets of 30 bits to select IO rails, but bits 30 and - * 31 are control bits rather than IO rail selection bits. - */ - if (id > 63 || *bit == 30 || *bit == 31) - return -EINVAL; + if (pad->dpd == UINT_MAX) + return -ENOTSUPP; - if (id < 32) { + *bit = pad->dpd % 32; + + if (pad->dpd < 32) { *status = IO_DPD_STATUS; *request = IO_DPD_REQ; } else { @@ -942,8 +968,8 @@ static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, return 0; } -static int tegra_io_rail_poll(unsigned long offset, u32 mask, - u32 val, unsigned long timeout) +static int tegra_io_pad_poll(unsigned long offset, u32 mask, + u32 val, unsigned long timeout) { u32 value; @@ -960,12 +986,18 @@ static int tegra_io_rail_poll(unsigned long offset, u32 mask, return -ETIMEDOUT; } -static void tegra_io_rail_unprepare(void) +static void tegra_io_pad_unprepare(void) { tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); } -int tegra_io_rail_power_on(unsigned int id) +/** + * 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) { unsigned long request, status; unsigned int bit; @@ -973,28 +1005,35 @@ int tegra_io_rail_power_on(unsigned int id) mutex_lock(&pmc->powergates_lock); - err = tegra_io_rail_prepare(id, &request, &status, &bit); - if (err) - goto error; + err = tegra_io_pad_prepare(id, &request, &status, &bit); + if (err < 0) { + dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); + goto unlock; + } tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | BIT(bit), request); - err = tegra_io_rail_poll(status, BIT(bit), 0, 250); - if (err) { - pr_info("tegra_io_rail_poll() failed: %d\n", err); - goto error; + err = tegra_io_pad_poll(status, BIT(bit), 0, 250); + if (err < 0) { + dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); + goto unlock; } - tegra_io_rail_unprepare(); + tegra_io_pad_unprepare(); -error: +unlock: mutex_unlock(&pmc->powergates_lock); - return err; } -EXPORT_SYMBOL(tegra_io_rail_power_on); +EXPORT_SYMBOL(tegra_io_pad_power_enable); -int tegra_io_rail_power_off(unsigned int id) +/** + * 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) { unsigned long request, status; unsigned int bit; @@ -1002,24 +1041,108 @@ int tegra_io_rail_power_off(unsigned int id) mutex_lock(&pmc->powergates_lock); - err = tegra_io_rail_prepare(id, &request, &status, &bit); - if (err) { - pr_info("tegra_io_rail_prepare() failed: %d\n", err); - goto error; + err = tegra_io_pad_prepare(id, &request, &status, &bit); + if (err < 0) { + dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); + goto unlock; } tegra_pmc_writel(IO_DPD_REQ_CODE_ON | BIT(bit), request); - err = tegra_io_rail_poll(status, BIT(bit), BIT(bit), 250); - if (err) - goto error; + err = tegra_io_pad_poll(status, BIT(bit), BIT(bit), 250); + if (err < 0) { + dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); + goto unlock; + } - tegra_io_rail_unprepare(); + tegra_io_pad_unprepare(); + +unlock: + mutex_unlock(&pmc->powergates_lock); + return err; +} +EXPORT_SYMBOL(tegra_io_pad_power_disable); + +int tegra_io_pad_set_voltage(enum tegra_io_pad id, + enum tegra_io_pad_voltage voltage) +{ + 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); + + /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */ + value = tegra_pmc_readl(PMC_PWR_DET); + value |= BIT(pad->voltage); + tegra_pmc_writel(value, PMC_PWR_DET); + + /* update I/O voltage */ + value = tegra_pmc_readl(PMC_PWR_DET_VALUE); + + if (voltage == TEGRA_IO_PAD_1800000UV) + value &= ~BIT(pad->voltage); + else + value |= BIT(pad->voltage); + + tegra_pmc_writel(value, PMC_PWR_DET_VALUE); -error: mutex_unlock(&pmc->powergates_lock); - return err; + usleep_range(100, 250); + + return 0; +} +EXPORT_SYMBOL(tegra_io_pad_set_voltage); + +int tegra_io_pad_get_voltage(enum tegra_io_pad id) +{ + 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; + + value = tegra_pmc_readl(PMC_PWR_DET_VALUE); + + if ((value & BIT(pad->voltage)) == 0) + return TEGRA_IO_PAD_1800000UV; + + return TEGRA_IO_PAD_3300000UV; +} +EXPORT_SYMBOL(tegra_io_pad_get_voltage); + +/** + * 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); } EXPORT_SYMBOL(tegra_io_rail_power_off); @@ -1454,6 +1577,39 @@ static const u8 tegra124_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; +static const struct tegra_io_pad_soc tegra124_io_pads[] = { + { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_BB, .dpd = 15, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_COMP, .dpd = 22, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HV, .dpd = 38, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_NAND, .dpd = 13, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 35, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SYS_DDC, .dpd = 58, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX }, +}; + static const struct tegra_pmc_soc tegra124_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra124_powergates), .powergates = tegra124_powergates, @@ -1461,6 +1617,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .cpu_powergates = tegra124_cpu_powergates, .has_tsense_reset = true, .has_gpu_clamps = true, + .num_io_pads = ARRAY_SIZE(tegra124_io_pads), + .io_pads = tegra124_io_pads, }; static const char * const tegra210_powergates[] = { @@ -1497,6 +1655,47 @@ static const u8 tegra210_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; +static const struct tegra_io_pad_soc tegra210_io_pads[] = { + { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = 5 }, + { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = 18 }, + { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = 10 }, + { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIC, .dpd = 42, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSID, .dpd = 43, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIF, .dpd = 45, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = 19 }, + { .id = TEGRA_IO_PAD_DEBUG_NONAO, .dpd = 26, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DMIC, .dpd = 50, .voltage = 20 }, + { .id = TEGRA_IO_PAD_DP, .dpd = 51, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EMMC, .dpd = 35, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EMMC2, .dpd = 37, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_GPIO, .dpd = 27, .voltage = 21 }, + { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = UINT_MAX, .voltage = 11 }, + { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = 12 }, + { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = 13 }, + { .id = TEGRA_IO_PAD_SPI, .dpd = 46, .voltage = 22 }, + { .id = TEGRA_IO_PAD_SPI_HV, .dpd = 47, .voltage = 23 }, + { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = 2 }, + { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB3, .dpd = 18, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX }, +}; + static const struct tegra_pmc_soc tegra210_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra210_powergates), .powergates = tegra210_powergates, @@ -1504,6 +1703,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .cpu_powergates = tegra210_cpu_powergates, .has_tsense_reset = true, .has_gpu_clamps = true, + .num_io_pads = ARRAY_SIZE(tegra210_io_pads), + .io_pads = tegra210_io_pads, }; static const struct of_device_id tegra_pmc_match[] = { diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index e9e53473a63e..2f271d1b9cea 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h @@ -76,37 +76,73 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid); #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D -#define TEGRA_IO_RAIL_CSIA 0 -#define TEGRA_IO_RAIL_CSIB 1 -#define TEGRA_IO_RAIL_DSI 2 -#define TEGRA_IO_RAIL_MIPI_BIAS 3 -#define TEGRA_IO_RAIL_PEX_BIAS 4 -#define TEGRA_IO_RAIL_PEX_CLK1 5 -#define TEGRA_IO_RAIL_PEX_CLK2 6 -#define TEGRA_IO_RAIL_USB0 9 -#define TEGRA_IO_RAIL_USB1 10 -#define TEGRA_IO_RAIL_USB2 11 -#define TEGRA_IO_RAIL_USB_BIAS 12 -#define TEGRA_IO_RAIL_NAND 13 -#define TEGRA_IO_RAIL_UART 14 -#define TEGRA_IO_RAIL_BB 15 -#define TEGRA_IO_RAIL_AUDIO 17 -#define TEGRA_IO_RAIL_HSIC 19 -#define TEGRA_IO_RAIL_COMP 22 -#define TEGRA_IO_RAIL_HDMI 28 -#define TEGRA_IO_RAIL_PEX_CNTRL 32 -#define TEGRA_IO_RAIL_SDMMC1 33 -#define TEGRA_IO_RAIL_SDMMC3 34 -#define TEGRA_IO_RAIL_SDMMC4 35 -#define TEGRA_IO_RAIL_CAM 36 -#define TEGRA_IO_RAIL_RES 37 -#define TEGRA_IO_RAIL_HV 38 -#define TEGRA_IO_RAIL_DSIB 39 -#define TEGRA_IO_RAIL_DSIC 40 -#define TEGRA_IO_RAIL_DSID 41 -#define TEGRA_IO_RAIL_CSIE 44 -#define TEGRA_IO_RAIL_LVDS 57 -#define TEGRA_IO_RAIL_SYS_DDC 58 +/** + * enum tegra_io_pad - I/O pad group identifier + * + * I/O pins on Tegra SoCs are grouped into so-called I/O pads. Each such pad + * can be used to control the common voltage signal level and power state of + * the pins of the given pad. + */ +enum tegra_io_pad { + TEGRA_IO_PAD_AUDIO, + TEGRA_IO_PAD_AUDIO_HV, + TEGRA_IO_PAD_BB, + TEGRA_IO_PAD_CAM, + TEGRA_IO_PAD_COMP, + TEGRA_IO_PAD_CSIA, + TEGRA_IO_PAD_CSIB, + TEGRA_IO_PAD_CSIC, + TEGRA_IO_PAD_CSID, + TEGRA_IO_PAD_CSIE, + TEGRA_IO_PAD_CSIF, + TEGRA_IO_PAD_DBG, + TEGRA_IO_PAD_DEBUG_NONAO, + TEGRA_IO_PAD_DMIC, + TEGRA_IO_PAD_DP, + TEGRA_IO_PAD_DSI, + TEGRA_IO_PAD_DSIB, + TEGRA_IO_PAD_DSIC, + TEGRA_IO_PAD_DSID, + TEGRA_IO_PAD_EMMC, + TEGRA_IO_PAD_EMMC2, + TEGRA_IO_PAD_GPIO, + TEGRA_IO_PAD_HDMI, + TEGRA_IO_PAD_HSIC, + TEGRA_IO_PAD_HV, + TEGRA_IO_PAD_LVDS, + TEGRA_IO_PAD_MIPI_BIAS, + TEGRA_IO_PAD_NAND, + TEGRA_IO_PAD_PEX_BIAS, + TEGRA_IO_PAD_PEX_CLK1, + TEGRA_IO_PAD_PEX_CLK2, + TEGRA_IO_PAD_PEX_CNTRL, + TEGRA_IO_PAD_SDMMC1, + TEGRA_IO_PAD_SDMMC3, + TEGRA_IO_PAD_SDMMC4, + TEGRA_IO_PAD_SPI, + TEGRA_IO_PAD_SPI_HV, + TEGRA_IO_PAD_SYS_DDC, + TEGRA_IO_PAD_UART, + TEGRA_IO_PAD_USB0, + TEGRA_IO_PAD_USB1, + TEGRA_IO_PAD_USB2, + TEGRA_IO_PAD_USB3, + TEGRA_IO_PAD_USB_BIAS, +}; + +/* deprecated, use TEGRA_IO_PAD_{HDMI,LVDS} instead */ +#define TEGRA_IO_RAIL_HDMI TEGRA_IO_PAD_HDMI +#define TEGRA_IO_RAIL_LVDS TEGRA_IO_PAD_LVDS + +/** + * enum tegra_io_pad_voltage - voltage level of the I/O pad's source rail + * @TEGRA_IO_PAD_1800000UV: 1.8 V + * @TEGRA_IO_PAD_3300000UV: 3.3 V + */ +enum tegra_io_pad_voltage { + TEGRA_IO_PAD_1800000UV, + TEGRA_IO_PAD_3300000UV, +}; #ifdef CONFIG_ARCH_TEGRA int tegra_powergate_is_powered(unsigned int id); @@ -118,6 +154,13 @@ int tegra_powergate_remove_clamping(unsigned int id); int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, struct reset_control *rst); +int tegra_io_pad_power_enable(enum tegra_io_pad id); +int tegra_io_pad_power_disable(enum tegra_io_pad id); +int tegra_io_pad_set_voltage(enum tegra_io_pad id, + enum tegra_io_pad_voltage voltage); +int tegra_io_pad_get_voltage(enum tegra_io_pad id); + +/* deprecated, use tegra_io_pad_power_{enable,disable}() instead */ int tegra_io_rail_power_on(unsigned int id); int tegra_io_rail_power_off(unsigned int id); #else @@ -148,6 +191,27 @@ static inline int tegra_powergate_sequence_power_up(unsigned int id, return -ENOSYS; } +static inline int tegra_io_pad_power_enable(enum tegra_io_pad id) +{ + return -ENOSYS; +} + +static inline int tegra_io_pad_power_disable(enum tegra_io_pad id) +{ + return -ENOSYS; +} + +static inline int tegra_io_pad_set_voltage(enum tegra_io_pad id, + enum tegra_io_pad_voltage voltage) +{ + return -ENOSYS; +} + +static inline int tegra_io_pad_get_voltage(enum tegra_io_pad id) +{ + return -ENOSYS; +} + static inline int tegra_io_rail_power_on(unsigned int id) { return -ENOSYS; From f4392d6da5f52727a53298321f4dfeac6df1a093 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sat, 22 Oct 2016 20:23:52 +0100 Subject: [PATCH 05/10] soc/tegra: pmc: Guard against uninitialised PMC clock It is possible for the public functions, tegra_io_rail_power_on/off() to be called before the PMC device has been probed. If this happens then the pmc->clk member will not be initialised and the call to clk_get_rate() in tegra_io_rail_prepare() will return zero and lead to a divide-by-zero exception. The function clk_get_rate() will return zero if a NULl clk pointer is passed. Therefore, rather that checking if pmc->clk is initialised, fix this by checking the return value for clk_get_rate() to make sure it is not zero. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 81968ef19618..c8b54b9dc093 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -957,6 +957,8 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, } rate = clk_get_rate(pmc->clk); + if (!rate) + return -ENODEV; tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); From 27b12b4e58525f7e8a612af5a3999126d0ea76fb Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sat, 22 Oct 2016 20:23:53 +0100 Subject: [PATCH 06/10] soc/tegra: pmc: Simplify IO rail bit handling The function tegra_io_rail_prepare() converts the IO rail ID into a bit position that is used to check the status and control the IO rail in the PMC registers. However, rather than converting to a bit position it is more useful to convert to a bit-mask because this is what is actually used. By doing so the BIT() marco only needs to be used once and we can use the IO_DPD_REQ_CODE_MASK when checking for erroneous rail IDs. Signed-off-by: Jon Hunter [treding@nvidia.com: rebase and rename bit -> mask] Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index c8b54b9dc093..c21d48db058e 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -934,7 +934,7 @@ tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id) } static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, - unsigned long *status, unsigned int *bit) + unsigned long *status, u32 *mask) { const struct tegra_io_pad_soc *pad; unsigned long rate, value; @@ -946,7 +946,7 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, if (pad->dpd == UINT_MAX) return -ENOTSUPP; - *bit = pad->dpd % 32; + *mask = BIT(pad->dpd % 32); if (pad->dpd < 32) { *status = IO_DPD_STATUS; @@ -1002,20 +1002,20 @@ static void tegra_io_pad_unprepare(void) int tegra_io_pad_power_enable(enum tegra_io_pad id) { unsigned long request, status; - unsigned int bit; + u32 mask; int err; mutex_lock(&pmc->powergates_lock); - err = tegra_io_pad_prepare(id, &request, &status, &bit); + err = tegra_io_pad_prepare(id, &request, &status, &mask); if (err < 0) { dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); goto unlock; } - tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | BIT(bit), request); + tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | mask, request); - err = tegra_io_pad_poll(status, BIT(bit), 0, 250); + err = tegra_io_pad_poll(status, mask, 0, 250); if (err < 0) { dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); goto unlock; @@ -1038,20 +1038,20 @@ EXPORT_SYMBOL(tegra_io_pad_power_enable); int tegra_io_pad_power_disable(enum tegra_io_pad id) { unsigned long request, status; - unsigned int bit; + u32 mask; int err; mutex_lock(&pmc->powergates_lock); - err = tegra_io_pad_prepare(id, &request, &status, &bit); + err = tegra_io_pad_prepare(id, &request, &status, &mask); if (err < 0) { dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); goto unlock; } - tegra_pmc_writel(IO_DPD_REQ_CODE_ON | BIT(bit), request); + tegra_pmc_writel(IO_DPD_REQ_CODE_ON | mask, request); - err = tegra_io_pad_poll(status, BIT(bit), BIT(bit), 250); + err = tegra_io_pad_poll(status, mask, mask, 250); if (err < 0) { dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); goto unlock; From 54e247211f6ba24f8fc0cbbd801d4d58e9b161ea Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 8 Nov 2016 10:58:32 +0100 Subject: [PATCH 07/10] soc/tegra: pmc: Clean-up I/O rail error messages Use pr_err() instead of dev_err() when the pmc->dev field has not been initialized yet and add a few missing error messages as well as remove duplicate ones. Based on work by Jon Hunter . Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 43 +++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index c21d48db058e..78fffa22966f 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -251,8 +251,6 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) return i; } - dev_err(pmc->dev, "powergate %s not found\n", name); - return -ENODEV; } @@ -469,13 +467,12 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg) static int tegra_genpd_power_on(struct generic_pm_domain *domain) { struct tegra_powergate *pg = to_powergate(domain); - struct tegra_pmc *pmc = pg->pmc; int err; err = tegra_powergate_power_up(pg, true); if (err) - dev_err(pmc->dev, "failed to turn on PM domain %s: %d\n", - pg->genpd.name, err); + pr_err("failed to turn on PM domain %s: %d\n", pg->genpd.name, + err); return err; } @@ -483,13 +480,12 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain) static int tegra_genpd_power_off(struct generic_pm_domain *domain) { struct tegra_powergate *pg = to_powergate(domain); - struct tegra_pmc *pmc = pg->pmc; int err; err = tegra_powergate_power_down(pg); if (err) - dev_err(pmc->dev, "failed to turn off PM domain %s: %d\n", - pg->genpd.name, err); + pr_err("failed to turn off PM domain %s: %d\n", + pg->genpd.name, err); return err; } @@ -814,8 +810,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) id = tegra_powergate_lookup(pmc, np->name); if (id < 0) { - dev_err(pmc->dev, "powergate lookup failed for %s: %d\n", - np->name, id); + pr_err("powergate lookup failed for %s: %d\n", np->name, id); goto free_mem; } @@ -835,15 +830,13 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = tegra_powergate_of_get_clks(pg, np); if (err < 0) { - dev_err(pmc->dev, "failed to get clocks for %s: %d\n", - np->name, err); + pr_err("failed to get clocks for %s: %d\n", np->name, err); goto set_available; } err = tegra_powergate_of_get_resets(pg, np, off); if (err < 0) { - dev_err(pmc->dev, "failed to get resets for %s: %d\n", - np->name, err); + pr_err("failed to get resets for %s: %d\n", np->name, err); goto remove_clks; } @@ -866,12 +859,12 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = of_genpd_add_provider_simple(np, &pg->genpd); if (err < 0) { - dev_err(pmc->dev, "failed to add genpd provider for %s: %d\n", - np->name, err); + pr_err("failed to add genpd provider for %s: %d\n", np->name, + err); goto remove_resets; } - dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name); + pr_debug("added power domain %s\n", pg->genpd.name); return; @@ -940,8 +933,10 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, unsigned long rate, value; pad = tegra_io_pad_find(pmc, id); - if (!pad) + if (!pad) { + pr_err("invalid I/O pad ID %u\n", id); return -ENOENT; + } if (pad->dpd == UINT_MAX) return -ENOTSUPP; @@ -957,8 +952,10 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, } rate = clk_get_rate(pmc->clk); - if (!rate) + if (!rate) { + pr_err("failed to get clock rate\n"); return -ENODEV; + } tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); @@ -1009,7 +1006,7 @@ int tegra_io_pad_power_enable(enum tegra_io_pad id) err = tegra_io_pad_prepare(id, &request, &status, &mask); if (err < 0) { - dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); + pr_err("failed to prepare I/O pad: %d\n", err); goto unlock; } @@ -1017,7 +1014,7 @@ int tegra_io_pad_power_enable(enum tegra_io_pad id) err = tegra_io_pad_poll(status, mask, 0, 250); if (err < 0) { - dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); + pr_err("failed to enable I/O pad: %d\n", err); goto unlock; } @@ -1045,7 +1042,7 @@ int tegra_io_pad_power_disable(enum tegra_io_pad id) err = tegra_io_pad_prepare(id, &request, &status, &mask); if (err < 0) { - dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); + pr_err("failed to prepare I/O pad: %d\n", err); goto unlock; } @@ -1053,7 +1050,7 @@ int tegra_io_pad_power_disable(enum tegra_io_pad id) err = tegra_io_pad_poll(status, mask, mask, 250); if (err < 0) { - dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); + pr_err("failed to disable I/O pad: %d\n", err); goto unlock; } From cd5ceda27d4b45b797ede85c844fc08da5aa70e3 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sat, 22 Oct 2016 20:23:55 +0100 Subject: [PATCH 08/10] soc/tegra: pmc: Check return code for pm_genpd_init() Commit 7eb231c337e0 ("PM / Domains: Convert pm_genpd_init() to return an error code") updated pm_genpd_init() to return an error code. Update the Tegra PMC driver to check the return value from pm_genpd_init() and handle any errors returned. Signed-off-by: Jon Hunter [treding@nvidia.com: use pr_err() instead of dev_err()] Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 78fffa22966f..bc4267c7fe15 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -855,7 +855,12 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) goto power_on_cleanup; - pm_genpd_init(&pg->genpd, NULL, off); + err = pm_genpd_init(&pg->genpd, NULL, off); + if (err < 0) { + pr_err("failed to initialise power domain %s: %d\n", np->name, + err); + goto remove_resets; + } err = of_genpd_add_provider_simple(np, &pg->genpd); if (err < 0) { From 0b137340d04b9dfa911cc882bc26ed611671f5f5 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sat, 22 Oct 2016 20:23:56 +0100 Subject: [PATCH 09/10] soc/tegra: pmc: Remove genpd when adding provider fails Commit 3fe577107ccf ("PM / Domains: Add support for removing PM domains") add support for removing PM domains. Update the Tegra PMC driver to remove PM domains if we fail to add a provider for the PM domain. Please note that the code under 'power_on_cleanup' label does not really belong in the clean-up error path for tegra_powergate_add(). To keep the error path simple, remove this label and move the associated code to where it needs to be invoked. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index bc4267c7fe15..3400ec355adb 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -840,8 +840,12 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) goto remove_clks; } - if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) - goto power_on_cleanup; + if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { + if (off) + WARN_ON(tegra_powergate_power_up(pg, true)); + + goto remove_resets; + } /* * FIXME: If XHCI is enabled for Tegra, then power-up the XUSB @@ -852,8 +856,12 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) * to be unused. */ if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) && - (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) - goto power_on_cleanup; + (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) { + if (off) + WARN_ON(tegra_powergate_power_up(pg, true)); + + goto remove_resets; + } err = pm_genpd_init(&pg->genpd, NULL, off); if (err < 0) { @@ -866,16 +874,15 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) if (err < 0) { pr_err("failed to add genpd provider for %s: %d\n", np->name, err); - goto remove_resets; + goto remove_genpd; } pr_debug("added power domain %s\n", pg->genpd.name); return; -power_on_cleanup: - if (off) - WARN_ON(tegra_powergate_power_up(pg, true)); +remove_genpd: + pm_genpd_remove(&pg->genpd); remove_resets: while (pg->num_resets--) From 4522112069a976908e32e5dd3231c9272d19794a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 8 Nov 2016 11:05:03 +0100 Subject: [PATCH 10/10] soc/tegra: pmc: Use consistent naming for PM domains The various error messages refer to the PM domains as "power domain", "genpd" and "PM domain". That's confusing, so convert all error messages to use the most prominent: "PM domain". Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 3400ec355adb..e233dd5dcab3 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -865,19 +865,19 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = pm_genpd_init(&pg->genpd, NULL, off); if (err < 0) { - pr_err("failed to initialise power domain %s: %d\n", np->name, + pr_err("failed to initialise PM domain %s: %d\n", np->name, err); goto remove_resets; } err = of_genpd_add_provider_simple(np, &pg->genpd); if (err < 0) { - pr_err("failed to add genpd provider for %s: %d\n", np->name, - err); + pr_err("failed to add PM domain provider for %s: %d\n", + np->name, err); goto remove_genpd; } - pr_debug("added power domain %s\n", pg->genpd.name); + pr_debug("added PM domain %s\n", pg->genpd.name); return;