soc: tegra: Core SoC changes for v4.10-rc1

This contains mostly cleanup and new feature work on the power
 management controller as well as the addition of a Kconfig symbol for
 the new Tegra186 (Parker) SoC generation.
 -----BEGIN PGP SIGNATURE-----
 
 iQIwBAABCAAaBQJYLyZwExx0cmVkaW5nQG52aWRpYS5jb20ACgkQ3SOs138+s6E5
 chAAo2l3z3hPBGEFC75kQC2W3W25wlpCbj0B0K07z5fCdPvqntBxr25Ath2/o7hb
 Frz6B/GpaRguePlVEKRxWWJ5PkhLVBkBtdpYyx0dUFMvW6KjU6BLMmjhrNynUjtx
 SJ/DYawNhPSGBQBUUKSnRO1hNX/l/ZYKURQZrz5SN5ZiudWUoN93/ltqU8/QcH4M
 7/qDCJRCB7JH8D0+CuYu7rQ+evz77YwMMSYZ/zJvcCioaSC3eUdSPzMrVaaLkA9X
 W+Q03VhJoztO9KJ0aQJWnQmdS4M0nagolD/jvHWnXSqdvT/X4VFgrnY/xLQDXCvK
 /yAmf07V0vISYebOKdmcL7/2Cu6EDdvTWUITaapkXvuDs6fjLqH02DeTmTacaNBI
 H7KSYP4kIz0i5lkLdunHIgmbDSXCgeJ2l+c6zUZ6/D8G31UnrUEuesdNRmTttqBw
 3QRSVjFq1bsVAo5rF4tNHhl/4SEOMbttkOfodDMTV8s5Pbk7WYP3TFqNdKavBOeQ
 xx3EUsZIDuIxerxem93z47hUrUp0chwP1NM0S4nJpWClK0f4RZm4VJbSW2/9iwTt
 g2v02vcmSou38uKuKdXtv6gzc8+Lgab0FnfyQouMaNmVLpIPkDJxJQvTlF+BeMPY
 MdPll5afxHCdD90a8OFlUmxNUE5mq0ZlPuqnNfLgt46Zpdw=
 =yvrl
 -----END PGP SIGNATURE-----

Merge tag 'tegra-for-4.10-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers

soc: tegra: Core SoC changes for v4.10-rc1

This contains mostly cleanup and new feature work on the power
management controller as well as the addition of a Kconfig symbol for
the new Tegra186 (Parker) SoC generation.

* tag 'tegra-for-4.10-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  soc/tegra: pmc: Use consistent naming for PM domains
  soc/tegra: pmc: Remove genpd when adding provider fails
  soc/tegra: pmc: Check return code for pm_genpd_init()
  soc/tegra: pmc: Clean-up I/O rail error messages
  soc/tegra: pmc: Simplify IO rail bit handling
  soc/tegra: pmc: Guard against uninitialised PMC clock
  soc/tegra: pmc: Add I/O pad voltage support
  soc/tegra: pmc: Use consistent ordering of bit definitions
  soc/tegra: pmc: Correct type of variable for tegra_pmc_readl()
  soc/tegra: pmc: Use BIT macro for register field definition

Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson 2016-11-18 18:42:33 -08:00
commit b029ffe00c
2 changed files with 414 additions and 138 deletions

View File

@ -45,29 +45,31 @@
#include <soc/tegra/pmc.h> #include <soc/tegra/pmc.h>
#define PMC_CNTRL 0x0 #define PMC_CNTRL 0x0
#define PMC_CNTRL_SYSCLK_POLARITY (1 << 10) /* sys clk polarity */ #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */
#define PMC_CNTRL_SYSCLK_OE (1 << 11) /* system clock enable */ #define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */
#define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */ #define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */
#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ #define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */
#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ #define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */
#define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */ #define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */
#define PMC_CNTRL_MAIN_RST (1 << 4) #define PMC_CNTRL_MAIN_RST BIT(4)
#define DPD_SAMPLE 0x020 #define DPD_SAMPLE 0x020
#define DPD_SAMPLE_ENABLE (1 << 0) #define DPD_SAMPLE_ENABLE BIT(0)
#define DPD_SAMPLE_DISABLE (0 << 0) #define DPD_SAMPLE_DISABLE (0 << 0)
#define PWRGATE_TOGGLE 0x30 #define PWRGATE_TOGGLE 0x30
#define PWRGATE_TOGGLE_START (1 << 8) #define PWRGATE_TOGGLE_START BIT(8)
#define REMOVE_CLAMPING 0x34 #define REMOVE_CLAMPING 0x34
#define PWRGATE_STATUS 0x38 #define PWRGATE_STATUS 0x38
#define PMC_PWR_DET 0x48
#define PMC_SCRATCH0 0x50 #define PMC_SCRATCH0 0x50
#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) #define PMC_SCRATCH0_MODE_RECOVERY BIT(31)
#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) #define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30)
#define PMC_SCRATCH0_MODE_RCM (1 << 1) #define PMC_SCRATCH0_MODE_RCM BIT(1)
#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ #define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \
PMC_SCRATCH0_MODE_BOOTLOADER | \ PMC_SCRATCH0_MODE_BOOTLOADER | \
PMC_SCRATCH0_MODE_RCM) PMC_SCRATCH0_MODE_RCM)
@ -75,11 +77,13 @@
#define PMC_CPUPWRGOOD_TIMER 0xc8 #define PMC_CPUPWRGOOD_TIMER 0xc8
#define PMC_CPUPWROFF_TIMER 0xcc #define PMC_CPUPWROFF_TIMER 0xcc
#define PMC_PWR_DET_VALUE 0xe4
#define PMC_SCRATCH41 0x140 #define PMC_SCRATCH41 0x140
#define PMC_SENSOR_CTRL 0x1b0 #define PMC_SENSOR_CTRL 0x1b0
#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) #define PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
#define PMC_RST_STATUS 0x1b4 #define PMC_RST_STATUS 0x1b4
#define PMC_RST_STATUS_POR 0 #define PMC_RST_STATUS_POR 0
@ -90,10 +94,10 @@
#define PMC_RST_STATUS_AOTAG 5 #define PMC_RST_STATUS_AOTAG 5
#define IO_DPD_REQ 0x1b8 #define IO_DPD_REQ 0x1b8
#define IO_DPD_REQ_CODE_IDLE (0 << 30) #define IO_DPD_REQ_CODE_IDLE (0U << 30)
#define IO_DPD_REQ_CODE_OFF (1 << 30) #define IO_DPD_REQ_CODE_OFF (1U << 30)
#define IO_DPD_REQ_CODE_ON (2 << 30) #define IO_DPD_REQ_CODE_ON (2U << 30)
#define IO_DPD_REQ_CODE_MASK (3 << 30) #define IO_DPD_REQ_CODE_MASK (3U << 30)
#define IO_DPD_STATUS 0x1bc #define IO_DPD_STATUS 0x1bc
#define IO_DPD2_REQ 0x1c0 #define IO_DPD2_REQ 0x1c0
@ -101,16 +105,16 @@
#define SEL_DPD_TIM 0x1c8 #define SEL_DPD_TIM 0x1c8
#define PMC_SCRATCH54 0x258 #define PMC_SCRATCH54 0x258
#define PMC_SCRATCH54_DATA_SHIFT 8 #define PMC_SCRATCH54_DATA_SHIFT 8
#define PMC_SCRATCH54_ADDR_SHIFT 0 #define PMC_SCRATCH54_ADDR_SHIFT 0
#define PMC_SCRATCH55 0x25c #define PMC_SCRATCH55 0x25c
#define PMC_SCRATCH55_RESET_TEGRA (1 << 31) #define PMC_SCRATCH55_RESET_TEGRA BIT(31)
#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 #define PMC_SCRATCH55_CNTRL_ID_SHIFT 27
#define PMC_SCRATCH55_PINMUX_SHIFT 24 #define PMC_SCRATCH55_PINMUX_SHIFT 24
#define PMC_SCRATCH55_16BITOP (1 << 15) #define PMC_SCRATCH55_16BITOP BIT(15)
#define PMC_SCRATCH55_CHECKSUM_SHIFT 16 #define PMC_SCRATCH55_CHECKSUM_SHIFT 16
#define PMC_SCRATCH55_I2CSLV1_SHIFT 0 #define PMC_SCRATCH55_I2CSLV1_SHIFT 0
#define GPU_RG_CNTRL 0x2d4 #define GPU_RG_CNTRL 0x2d4
@ -124,6 +128,12 @@ struct tegra_powergate {
unsigned int num_resets; unsigned int num_resets;
}; };
struct tegra_io_pad_soc {
enum tegra_io_pad id;
unsigned int dpd;
unsigned int voltage;
};
struct tegra_pmc_soc { struct tegra_pmc_soc {
unsigned int num_powergates; unsigned int num_powergates;
const char *const *powergates; const char *const *powergates;
@ -132,6 +142,9 @@ struct tegra_pmc_soc {
bool has_tsense_reset; bool has_tsense_reset;
bool has_gpu_clamps; bool has_gpu_clamps;
const struct tegra_io_pad_soc *io_pads;
unsigned int num_io_pads;
}; };
/** /**
@ -238,8 +251,6 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name)
return i; return i;
} }
dev_err(pmc->dev, "powergate %s not found\n", name);
return -ENODEV; return -ENODEV;
} }
@ -456,13 +467,12 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg)
static int tegra_genpd_power_on(struct generic_pm_domain *domain) static int tegra_genpd_power_on(struct generic_pm_domain *domain)
{ {
struct tegra_powergate *pg = to_powergate(domain); struct tegra_powergate *pg = to_powergate(domain);
struct tegra_pmc *pmc = pg->pmc;
int err; int err;
err = tegra_powergate_power_up(pg, true); err = tegra_powergate_power_up(pg, true);
if (err) if (err)
dev_err(pmc->dev, "failed to turn on PM domain %s: %d\n", pr_err("failed to turn on PM domain %s: %d\n", pg->genpd.name,
pg->genpd.name, err); err);
return err; return err;
} }
@ -470,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) static int tegra_genpd_power_off(struct generic_pm_domain *domain)
{ {
struct tegra_powergate *pg = to_powergate(domain); struct tegra_powergate *pg = to_powergate(domain);
struct tegra_pmc *pmc = pg->pmc;
int err; int err;
err = tegra_powergate_power_down(pg); err = tegra_powergate_power_down(pg);
if (err) if (err)
dev_err(pmc->dev, "failed to turn off PM domain %s: %d\n", pr_err("failed to turn off PM domain %s: %d\n",
pg->genpd.name, err); pg->genpd.name, err);
return err; return err;
} }
@ -801,8 +810,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
id = tegra_powergate_lookup(pmc, np->name); id = tegra_powergate_lookup(pmc, np->name);
if (id < 0) { if (id < 0) {
dev_err(pmc->dev, "powergate lookup failed for %s: %d\n", pr_err("powergate lookup failed for %s: %d\n", np->name, id);
np->name, id);
goto free_mem; goto free_mem;
} }
@ -822,20 +830,22 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
err = tegra_powergate_of_get_clks(pg, np); err = tegra_powergate_of_get_clks(pg, np);
if (err < 0) { if (err < 0) {
dev_err(pmc->dev, "failed to get clocks for %s: %d\n", pr_err("failed to get clocks for %s: %d\n", np->name, err);
np->name, err);
goto set_available; goto set_available;
} }
err = tegra_powergate_of_get_resets(pg, np, off); err = tegra_powergate_of_get_resets(pg, np, off);
if (err < 0) { if (err < 0) {
dev_err(pmc->dev, "failed to get resets for %s: %d\n", pr_err("failed to get resets for %s: %d\n", np->name, err);
np->name, err);
goto remove_clks; goto remove_clks;
} }
if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
goto power_on_cleanup; 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 * FIXME: If XHCI is enabled for Tegra, then power-up the XUSB
@ -846,25 +856,33 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
* to be unused. * to be unused.
*/ */
if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) && if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) &&
(id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) {
goto power_on_cleanup; if (off)
WARN_ON(tegra_powergate_power_up(pg, true));
pm_genpd_init(&pg->genpd, NULL, off);
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);
goto remove_resets; goto remove_resets;
} }
dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name); err = pm_genpd_init(&pg->genpd, NULL, off);
if (err < 0) {
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 PM domain provider for %s: %d\n",
np->name, err);
goto remove_genpd;
}
pr_debug("added PM domain %s\n", pg->genpd.name);
return; return;
power_on_cleanup: remove_genpd:
if (off) pm_genpd_remove(&pg->genpd);
WARN_ON(tegra_powergate_power_up(pg, true));
remove_resets: remove_resets:
while (pg->num_resets--) while (pg->num_resets--)
@ -908,21 +926,36 @@ static void tegra_powergate_init(struct tegra_pmc *pmc,
of_node_put(np); of_node_put(np);
} }
static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, static const struct tegra_io_pad_soc *
unsigned long *status, unsigned int *bit) 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, u32 *mask)
{
const struct tegra_io_pad_soc *pad;
unsigned long rate, value; unsigned long rate, value;
*bit = id % 32; pad = tegra_io_pad_find(pmc, id);
if (!pad) {
pr_err("invalid I/O pad ID %u\n", id);
return -ENOENT;
}
/* if (pad->dpd == UINT_MAX)
* There are two sets of 30 bits to select IO rails, but bits 30 and return -ENOTSUPP;
* 31 are control bits rather than IO rail selection bits.
*/
if (id > 63 || *bit == 30 || *bit == 31)
return -EINVAL;
if (id < 32) { *mask = BIT(pad->dpd % 32);
if (pad->dpd < 32) {
*status = IO_DPD_STATUS; *status = IO_DPD_STATUS;
*request = IO_DPD_REQ; *request = IO_DPD_REQ;
} else { } else {
@ -931,6 +964,10 @@ static int tegra_io_rail_prepare(unsigned int id, unsigned long *request,
} }
rate = clk_get_rate(pmc->clk); rate = clk_get_rate(pmc->clk);
if (!rate) {
pr_err("failed to get clock rate\n");
return -ENODEV;
}
tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE);
@ -942,10 +979,10 @@ static int tegra_io_rail_prepare(unsigned int id, unsigned long *request,
return 0; return 0;
} }
static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, static int tegra_io_pad_poll(unsigned long offset, u32 mask,
unsigned long val, unsigned long timeout) u32 val, unsigned long timeout)
{ {
unsigned long value; u32 value;
timeout = jiffies + msecs_to_jiffies(timeout); timeout = jiffies + msecs_to_jiffies(timeout);
@ -960,66 +997,163 @@ static int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static void tegra_io_rail_unprepare(void) static void tegra_io_pad_unprepare(void)
{ {
tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); 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 long request, status;
unsigned int bit; u32 mask;
int err; int err;
mutex_lock(&pmc->powergates_lock); mutex_lock(&pmc->powergates_lock);
err = tegra_io_rail_prepare(id, &request, &status, &bit); err = tegra_io_pad_prepare(id, &request, &status, &mask);
if (err) if (err < 0) {
goto error; pr_err("failed to prepare I/O pad: %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;
} }
tegra_io_rail_unprepare(); tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | mask, request);
err = tegra_io_pad_poll(status, mask, 0, 250);
if (err < 0) {
pr_err("failed to enable I/O pad: %d\n", err);
goto unlock;
}
tegra_io_pad_unprepare();
unlock:
mutex_unlock(&pmc->powergates_lock);
return err;
}
EXPORT_SYMBOL(tegra_io_pad_power_enable);
/**
* 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;
u32 mask;
int err;
mutex_lock(&pmc->powergates_lock);
err = tegra_io_pad_prepare(id, &request, &status, &mask);
if (err < 0) {
pr_err("failed to prepare I/O pad: %d\n", err);
goto unlock;
}
tegra_pmc_writel(IO_DPD_REQ_CODE_ON | mask, request);
err = tegra_io_pad_poll(status, mask, mask, 250);
if (err < 0) {
pr_err("failed to disable I/O pad: %d\n", err);
goto unlock;
}
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); 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); 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) int tegra_io_rail_power_off(unsigned int id)
{ {
unsigned long request, status; return tegra_io_pad_power_disable(id);
unsigned int bit;
int err;
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;
}
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;
tegra_io_rail_unprepare();
error:
mutex_unlock(&pmc->powergates_lock);
return err;
} }
EXPORT_SYMBOL(tegra_io_rail_power_off); EXPORT_SYMBOL(tegra_io_rail_power_off);
@ -1454,6 +1588,39 @@ static const u8 tegra124_cpu_powergates[] = {
TEGRA_POWERGATE_CPU3, 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 = { static const struct tegra_pmc_soc tegra124_pmc_soc = {
.num_powergates = ARRAY_SIZE(tegra124_powergates), .num_powergates = ARRAY_SIZE(tegra124_powergates),
.powergates = tegra124_powergates, .powergates = tegra124_powergates,
@ -1461,6 +1628,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.cpu_powergates = tegra124_cpu_powergates, .cpu_powergates = tegra124_cpu_powergates,
.has_tsense_reset = true, .has_tsense_reset = true,
.has_gpu_clamps = true, .has_gpu_clamps = true,
.num_io_pads = ARRAY_SIZE(tegra124_io_pads),
.io_pads = tegra124_io_pads,
}; };
static const char * const tegra210_powergates[] = { static const char * const tegra210_powergates[] = {
@ -1497,6 +1666,47 @@ static const u8 tegra210_cpu_powergates[] = {
TEGRA_POWERGATE_CPU3, 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 = { static const struct tegra_pmc_soc tegra210_pmc_soc = {
.num_powergates = ARRAY_SIZE(tegra210_powergates), .num_powergates = ARRAY_SIZE(tegra210_powergates),
.powergates = tegra210_powergates, .powergates = tegra210_powergates,
@ -1504,6 +1714,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.cpu_powergates = tegra210_cpu_powergates, .cpu_powergates = tegra210_cpu_powergates,
.has_tsense_reset = true, .has_tsense_reset = true,
.has_gpu_clamps = 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[] = { static const struct of_device_id tegra_pmc_match[] = {

View File

@ -76,37 +76,73 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid);
#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D
#define TEGRA_IO_RAIL_CSIA 0 /**
#define TEGRA_IO_RAIL_CSIB 1 * enum tegra_io_pad - I/O pad group identifier
#define TEGRA_IO_RAIL_DSI 2 *
#define TEGRA_IO_RAIL_MIPI_BIAS 3 * I/O pins on Tegra SoCs are grouped into so-called I/O pads. Each such pad
#define TEGRA_IO_RAIL_PEX_BIAS 4 * can be used to control the common voltage signal level and power state of
#define TEGRA_IO_RAIL_PEX_CLK1 5 * the pins of the given pad.
#define TEGRA_IO_RAIL_PEX_CLK2 6 */
#define TEGRA_IO_RAIL_USB0 9 enum tegra_io_pad {
#define TEGRA_IO_RAIL_USB1 10 TEGRA_IO_PAD_AUDIO,
#define TEGRA_IO_RAIL_USB2 11 TEGRA_IO_PAD_AUDIO_HV,
#define TEGRA_IO_RAIL_USB_BIAS 12 TEGRA_IO_PAD_BB,
#define TEGRA_IO_RAIL_NAND 13 TEGRA_IO_PAD_CAM,
#define TEGRA_IO_RAIL_UART 14 TEGRA_IO_PAD_COMP,
#define TEGRA_IO_RAIL_BB 15 TEGRA_IO_PAD_CSIA,
#define TEGRA_IO_RAIL_AUDIO 17 TEGRA_IO_PAD_CSIB,
#define TEGRA_IO_RAIL_HSIC 19 TEGRA_IO_PAD_CSIC,
#define TEGRA_IO_RAIL_COMP 22 TEGRA_IO_PAD_CSID,
#define TEGRA_IO_RAIL_HDMI 28 TEGRA_IO_PAD_CSIE,
#define TEGRA_IO_RAIL_PEX_CNTRL 32 TEGRA_IO_PAD_CSIF,
#define TEGRA_IO_RAIL_SDMMC1 33 TEGRA_IO_PAD_DBG,
#define TEGRA_IO_RAIL_SDMMC3 34 TEGRA_IO_PAD_DEBUG_NONAO,
#define TEGRA_IO_RAIL_SDMMC4 35 TEGRA_IO_PAD_DMIC,
#define TEGRA_IO_RAIL_CAM 36 TEGRA_IO_PAD_DP,
#define TEGRA_IO_RAIL_RES 37 TEGRA_IO_PAD_DSI,
#define TEGRA_IO_RAIL_HV 38 TEGRA_IO_PAD_DSIB,
#define TEGRA_IO_RAIL_DSIB 39 TEGRA_IO_PAD_DSIC,
#define TEGRA_IO_RAIL_DSIC 40 TEGRA_IO_PAD_DSID,
#define TEGRA_IO_RAIL_DSID 41 TEGRA_IO_PAD_EMMC,
#define TEGRA_IO_RAIL_CSIE 44 TEGRA_IO_PAD_EMMC2,
#define TEGRA_IO_RAIL_LVDS 57 TEGRA_IO_PAD_GPIO,
#define TEGRA_IO_RAIL_SYS_DDC 58 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 #ifdef CONFIG_ARCH_TEGRA
int tegra_powergate_is_powered(unsigned int id); 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, int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
struct reset_control *rst); 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_on(unsigned int id);
int tegra_io_rail_power_off(unsigned int id); int tegra_io_rail_power_off(unsigned int id);
#else #else
@ -148,6 +191,27 @@ static inline int tegra_powergate_sequence_power_up(unsigned int id,
return -ENOSYS; 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) static inline int tegra_io_rail_power_on(unsigned int id)
{ {
return -ENOSYS; return -ENOSYS;