aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/soc/tegra/pmc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-17 09:27:54 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-17 09:27:54 -0800
commit878ba61aa98cbb97a513757800e77613f856a029 (patch)
treec03b8373cdb7163f81141a867c9cda1a9f71e73e /drivers/soc/tegra/pmc.c
parentMerge tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc (diff)
parentMerge tag 'at91-soc4' of git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91 into next/soc (diff)
downloadlinux-dev-878ba61aa98cbb97a513757800e77613f856a029.tar.xz
linux-dev-878ba61aa98cbb97a513757800e77613f856a029.zip
Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform changes from Olof Johansson: "New and updated SoC support. Also included are some cleanups where the platform maintainers hadn't separated cleanups from new developent in separate branches. Some of the larger things worth pointing out: - A large set of changes from Alexandre Belloni and Nicolas Ferre preparing at91 platforms for multiplatform and cleaning up quite a bit in the process. - Removal of CSR's "Marco" SoC platform that never made it out to the market. We love seeing these since it means the vendor published support before product was out, which is exactly what we want! New platforms this release are: - Conexant Digicolor (CX92755 SoC) - Hisilicon HiP01 SoC - CSR/sirf Atlas7 SoC - ST STiH418 SoC - Common code changes for Nvidia Tegra132 (64-bit SoC) We're seeing more and more platforms having a harder time labelling changes as cleanups vs new development -- which is a good sign that we've come quite far on the cleanup effort. So over time we might start combining the cleanup and new-development branches more" * tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (124 commits) ARM: at91/trivial: unify functions and machine names ARM: at91: remove at91_dt_initialize and machine init_early() ARM: at91: change board files into SoC files ARM: at91: remove at91_boot_soc ARM: at91: move alternative initial mapping to board-dt-sama5.c ARM: at91: merge all SOC_AT91SAM9xxx ARM: at91: at91rm9200: set idle and restart from rm9200_dt_device_init() ARM: digicolor: select syscon and timer ARM: zynq: Simplify SLCR initialization ARM: zynq: PM: Fixed simple typo. ARM: zynq: Setup default gpio number for Xilinx Zynq ARM: digicolor: add low level debug support ARM: initial support for Conexant Digicolor CX92755 SoC ARM: OMAP2+: Add dm816x hwmod support ARM: OMAP2+: Add clock domain support for dm816x ARM: OMAP2+: Add board-generic.c entry for ti81xx ARM: at91: pm: remove warning to remove SOC_AT91SAM9263 usage ARM: at91: remove unused mach/system_rev.h ARM: at91: stop using HAVE_AT91_DBGUx ARM: at91: fix ordering of SRAM and PM initialization ...
Diffstat (limited to 'drivers/soc/tegra/pmc.c')
-rw-r--r--drivers/soc/tegra/pmc.c124
1 files changed, 118 insertions, 6 deletions
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index a2c0ceb95f8f..c956395cf46f 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -70,6 +70,10 @@
#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 IO_DPD_REQ 0x1b8
#define IO_DPD_REQ_CODE_IDLE (0 << 30)
#define IO_DPD_REQ_CODE_OFF (1 << 30)
@@ -81,6 +85,18 @@
#define IO_DPD2_STATUS 0x1c4
#define SEL_DPD_TIM 0x1c8
+#define PMC_SCRATCH54 0x258
+#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 GPU_RG_CNTRL 0x2d4
struct tegra_pmc_soc {
@@ -88,6 +104,9 @@ struct tegra_pmc_soc {
const char *const *powergates;
unsigned int num_cpu_powergates;
const u8 *cpu_powergates;
+
+ bool has_tsense_reset;
+ bool has_gpu_clamps;
};
/**
@@ -110,6 +129,7 @@ struct tegra_pmc_soc {
* @powergates_lock: mutex for power gate register access
*/
struct tegra_pmc {
+ struct device *dev;
void __iomem *base;
struct clk *clk;
@@ -225,11 +245,11 @@ int tegra_powergate_remove_clamping(int id)
return -EINVAL;
/*
- * The Tegra124 GPU has a separate register (with different semantics)
- * to remove clamps.
+ * On Tegra124 and later, the clamps for the GPU are controlled by a
+ * separate register (with different semantics).
*/
- if (tegra_get_chip_id() == TEGRA124) {
- if (id == TEGRA_POWERGATE_3D) {
+ if (id == TEGRA_POWERGATE_3D) {
+ if (pmc->soc->has_gpu_clamps) {
tegra_pmc_writel(0, GPU_RG_CNTRL);
return 0;
}
@@ -703,6 +723,83 @@ static void tegra_pmc_init(struct tegra_pmc *pmc)
tegra_pmc_writel(value, PMC_CNTRL);
}
+void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
+{
+ 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)
+ goto out;
+
+ np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip");
+ if (!np) {
+ dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
+ goto out;
+ }
+
+ 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;
+
+ value = tegra_pmc_readl(PMC_SENSOR_CTRL);
+ value |= PMC_SENSOR_CTRL_SCRATCH_WRITE;
+ tegra_pmc_writel(value, PMC_SENSOR_CTRL);
+
+ value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) |
+ (reg_addr << PMC_SCRATCH54_ADDR_SHIFT);
+ tegra_pmc_writel(value, PMC_SCRATCH54);
+
+ 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;
+
+ tegra_pmc_writel(value, PMC_SCRATCH55);
+
+ value = tegra_pmc_readl(PMC_SENSOR_CTRL);
+ value |= PMC_SENSOR_CTRL_ENABLE_RST;
+ tegra_pmc_writel(value, PMC_SENSOR_CTRL);
+
+ dev_info(pmc->dev, "emergency thermal reset enabled\n");
+
+out:
+ of_node_put(np);
+ return;
+}
+
static int tegra_pmc_probe(struct platform_device *pdev)
{
void __iomem *base = pmc->base;
@@ -728,8 +825,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return err;
}
+ pmc->dev = &pdev->dev;
+
tegra_pmc_init(pmc);
+ tegra_pmc_init_tsense_reset(pmc);
+
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
err = tegra_powergate_debugfs_init();
if (err < 0)
@@ -739,7 +840,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
static int tegra_pmc_suspend(struct device *dev)
{
tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
@@ -753,10 +854,11 @@ static int tegra_pmc_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume);
+#endif
+
static const char * const tegra20_powergates[] = {
[TEGRA_POWERGATE_CPU] = "cpu",
[TEGRA_POWERGATE_3D] = "3d",
@@ -772,6 +874,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.powergates = tegra20_powergates,
.num_cpu_powergates = 0,
.cpu_powergates = NULL,
+ .has_tsense_reset = false,
+ .has_gpu_clamps = false,
};
static const char * const tegra30_powergates[] = {
@@ -803,6 +907,8 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.powergates = tegra30_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
.cpu_powergates = tegra30_cpu_powergates,
+ .has_tsense_reset = true,
+ .has_gpu_clamps = false,
};
static const char * const tegra114_powergates[] = {
@@ -838,6 +944,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.powergates = tegra114_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
.cpu_powergates = tegra114_cpu_powergates,
+ .has_tsense_reset = true,
+ .has_gpu_clamps = false,
};
static const char * const tegra124_powergates[] = {
@@ -879,6 +987,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.powergates = tegra124_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
.cpu_powergates = tegra124_cpu_powergates,
+ .has_tsense_reset = true,
+ .has_gpu_clamps = true,
};
static const struct of_device_id tegra_pmc_match[] = {
@@ -894,7 +1004,9 @@ static struct platform_driver tegra_pmc_driver = {
.name = "tegra-pmc",
.suppress_bind_attrs = true,
.of_match_table = tegra_pmc_match,
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
.pm = &tegra_pmc_pm_ops,
+#endif
},
.probe = tegra_pmc_probe,
};