summaryrefslogtreecommitdiffstats
path: root/drivers/soc/tegra/pmc.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2017-08-30 12:32:58 +0200
committerThierry Reding <treding@nvidia.com>2017-12-13 13:04:50 +0100
commit5be2255676bf2bc69170f05cfe15f771e5aeef24 (patch)
tree7cfda090c95370560aadeb5ce7b1eba2aabfcf5d /drivers/soc/tegra/pmc.c
parent75c15b90e42373a3c651d53e6e55239b0f03777d (diff)
downloadblackbird-obmc-linux-5be2255676bf2bc69170f05cfe15f771e5aeef24.tar.gz
blackbird-obmc-linux-5be2255676bf2bc69170f05cfe15f771e5aeef24.zip
soc/tegra: pmc: Parameterize driver
Parameterize some aspects of the driver in preparation for Tegra186 PMC support. Initially the Tegra186 driver had been split off into an extra driver, but it turns out the backwards-compatibility break isn't as bad as originally assumed, so with a little parameterization the same code can be used to keep supporting all SoC generations. Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/soc/tegra/pmc.c')
-rw-r--r--drivers/soc/tegra/pmc.c175
1 files changed, 121 insertions, 54 deletions
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 0453ff6839a7..363b4b9c3aaf 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -66,11 +66,10 @@
#define PMC_PWR_DET 0x48
-#define PMC_SCRATCH0 0x50
-#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 | \
+#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)
@@ -134,6 +133,14 @@ struct tegra_io_pad_soc {
unsigned int voltage;
};
+struct tegra_pmc_regs {
+ unsigned int scratch0;
+ unsigned int dpd_req;
+ unsigned int dpd_status;
+ unsigned int dpd2_req;
+ unsigned int dpd2_status;
+};
+
struct tegra_pmc_soc {
unsigned int num_powergates;
const char *const *powergates;
@@ -145,6 +152,12 @@ struct tegra_pmc_soc {
const struct tegra_io_pad_soc *io_pads;
unsigned int num_io_pads;
+
+ 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);
};
/**
@@ -173,6 +186,7 @@ struct tegra_pmc_soc {
struct tegra_pmc {
struct device *dev;
void __iomem *base;
+ void __iomem *scratch;
struct clk *clk;
struct dentry *debugfs;
@@ -645,7 +659,7 @@ static int tegra_pmc_restart_notify(struct notifier_block *this,
const char *cmd = data;
u32 value;
- value = tegra_pmc_readl(PMC_SCRATCH0);
+ value = readl(pmc->scratch + pmc->soc->regs->scratch0);
value &= ~PMC_SCRATCH0_MODE_MASK;
if (cmd) {
@@ -659,7 +673,7 @@ static int tegra_pmc_restart_notify(struct notifier_block *this,
value |= PMC_SCRATCH0_MODE_RCM;
}
- tegra_pmc_writel(value, PMC_SCRATCH0);
+ writel(value, pmc->scratch + pmc->soc->regs->scratch0);
/* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */
value = tegra_pmc_readl(PMC_CNTRL);
@@ -954,25 +968,27 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request,
*mask = BIT(pad->dpd % 32);
if (pad->dpd < 32) {
- *status = IO_DPD_STATUS;
- *request = IO_DPD_REQ;
+ *status = pmc->soc->regs->dpd_status;
+ *request = pmc->soc->regs->dpd_req;
} else {
- *status = IO_DPD2_STATUS;
- *request = IO_DPD2_REQ;
+ *status = pmc->soc->regs->dpd2_status;
+ *request = pmc->soc->regs->dpd2_req;
}
- rate = clk_get_rate(pmc->clk);
- if (!rate) {
- pr_err("failed to get clock rate\n");
- return -ENODEV;
- }
+ if (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);
- /* must be at least 200 ns, in APB (PCLK) clock cycles */
- value = DIV_ROUND_UP(1000000000, rate);
- value = DIV_ROUND_UP(200, value);
- tegra_pmc_writel(value, SEL_DPD_TIM);
+ /* must be at least 200 ns, in APB (PCLK) clock cycles */
+ value = DIV_ROUND_UP(1000000000, rate);
+ value = DIV_ROUND_UP(200, value);
+ tegra_pmc_writel(value, SEL_DPD_TIM);
+ }
return 0;
}
@@ -997,7 +1013,8 @@ static int tegra_io_pad_poll(unsigned long offset, u32 mask,
static void tegra_io_pad_unprepare(void)
{
- tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
+ if (pmc->clk)
+ tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
}
/**
@@ -1287,27 +1304,8 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
static void tegra_pmc_init(struct tegra_pmc *pmc)
{
- u32 value;
-
- /* Always enable CPU power request */
- value = tegra_pmc_readl(PMC_CNTRL);
- value |= PMC_CNTRL_CPU_PWRREQ_OE;
- tegra_pmc_writel(value, PMC_CNTRL);
-
- value = tegra_pmc_readl(PMC_CNTRL);
-
- if (pmc->sysclkreq_high)
- value &= ~PMC_CNTRL_SYSCLK_POLARITY;
- else
- value |= PMC_CNTRL_SYSCLK_POLARITY;
-
- /* configure the output polarity while the request is tristated */
- tegra_pmc_writel(value, PMC_CNTRL);
-
- /* now enable the request */
- value = tegra_pmc_readl(PMC_CNTRL);
- value |= PMC_CNTRL_SYSCLK_OE;
- tegra_pmc_writel(value, PMC_CNTRL);
+ if (pmc->soc->init)
+ pmc->soc->init(pmc);
}
static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
@@ -1410,11 +1408,18 @@ static int tegra_pmc_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
+ pmc->scratch = base;
+
pmc->clk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(pmc->clk)) {
err = PTR_ERR(pmc->clk);
- dev_err(&pdev->dev, "failed to get pclk: %d\n", err);
- return err;
+
+ if (err != -ENOENT) {
+ dev_err(&pdev->dev, "failed to get pclk: %d\n", err);
+ return err;
+ }
+
+ pmc->clk = NULL;
}
pmc->dev = &pdev->dev;
@@ -1474,6 +1479,55 @@ static const char * const tegra20_powergates[] = {
[TEGRA_POWERGATE_MPE] = "mpe",
};
+static const struct tegra_pmc_regs tegra20_pmc_regs = {
+ .scratch0 = 0x50,
+ .dpd_req = 0x1b8,
+ .dpd_status = 0x1bc,
+ .dpd2_req = 0x1c0,
+ .dpd2_status = 0x1c4,
+};
+
+static void tegra20_pmc_init(struct tegra_pmc *pmc)
+{
+ u32 value;
+
+ /* Always enable CPU power request */
+ value = tegra_pmc_readl(PMC_CNTRL);
+ value |= PMC_CNTRL_CPU_PWRREQ_OE;
+ tegra_pmc_writel(value, PMC_CNTRL);
+
+ value = tegra_pmc_readl(PMC_CNTRL);
+
+ if (pmc->sysclkreq_high)
+ value &= ~PMC_CNTRL_SYSCLK_POLARITY;
+ else
+ value |= PMC_CNTRL_SYSCLK_POLARITY;
+
+ /* configure the output polarity while the request is tristated */
+ tegra_pmc_writel(value, PMC_CNTRL);
+
+ /* now enable the request */
+ value = tegra_pmc_readl(PMC_CNTRL);
+ value |= PMC_CNTRL_SYSCLK_OE;
+ tegra_pmc_writel(value, PMC_CNTRL);
+}
+
+static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
+ struct device_node *np,
+ bool invert)
+{
+ u32 value;
+
+ value = tegra_pmc_readl(PMC_CNTRL);
+
+ if (invert)
+ value |= PMC_CNTRL_INTR_POLARITY;
+ else
+ value &= ~PMC_CNTRL_INTR_POLARITY;
+
+ tegra_pmc_writel(value, PMC_CNTRL);
+}
+
static const struct tegra_pmc_soc tegra20_pmc_soc = {
.num_powergates = ARRAY_SIZE(tegra20_powergates),
.powergates = tegra20_powergates,
@@ -1481,6 +1535,11 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.cpu_powergates = NULL,
.has_tsense_reset = false,
.has_gpu_clamps = false,
+ .num_io_pads = 0,
+ .io_pads = NULL,
+ .regs = &tegra20_pmc_regs,
+ .init = tegra20_pmc_init,
+ .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
};
static const char * const tegra30_powergates[] = {
@@ -1514,6 +1573,11 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.cpu_powergates = tegra30_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = false,
+ .num_io_pads = 0,
+ .io_pads = NULL,
+ .regs = &tegra20_pmc_regs,
+ .init = tegra20_pmc_init,
+ .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
};
static const char * const tegra114_powergates[] = {
@@ -1551,6 +1615,11 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.cpu_powergates = tegra114_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = false,
+ .num_io_pads = 0,
+ .io_pads = NULL,
+ .regs = &tegra20_pmc_regs,
+ .init = tegra20_pmc_init,
+ .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
};
static const char * const tegra124_powergates[] = {
@@ -1628,6 +1697,9 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.has_gpu_clamps = true,
.num_io_pads = ARRAY_SIZE(tegra124_io_pads),
.io_pads = tegra124_io_pads,
+ .regs = &tegra20_pmc_regs,
+ .init = tegra20_pmc_init,
+ .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
};
static const char * const tegra210_powergates[] = {
@@ -1714,6 +1786,9 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.has_gpu_clamps = true,
.num_io_pads = ARRAY_SIZE(tegra210_io_pads),
.io_pads = tegra210_io_pads,
+ .regs = &tegra20_pmc_regs,
+ .init = tegra20_pmc_init,
+ .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
};
static const struct of_device_id tegra_pmc_match[] = {
@@ -1749,7 +1824,6 @@ static int __init tegra_pmc_early_init(void)
struct device_node *np;
struct resource regs;
bool invert;
- u32 value;
mutex_init(&pmc->powergates_lock);
@@ -1810,14 +1884,7 @@ static int __init tegra_pmc_early_init(void)
*/
invert = of_property_read_bool(np, "nvidia,invert-interrupt");
- value = tegra_pmc_readl(PMC_CNTRL);
-
- if (invert)
- value |= PMC_CNTRL_INTR_POLARITY;
- else
- value &= ~PMC_CNTRL_INTR_POLARITY;
-
- tegra_pmc_writel(value, PMC_CNTRL);
+ pmc->soc->setup_irq_polarity(pmc, np, invert);
of_node_put(np);
}
OpenPOWER on IntegriCloud