From: Mikko Perttunen <cyndis@kapsi.fi> To: swarren@wwwdotorg.org, thierry.reding@gmail.com Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-tegra@vger.kernel.org, wni@nvidia.com, Mikko Perttunen <mperttunen@nvidia.com> Subject: [PATCH v3 5/5] ARM: tegra: Add thermal reset (thermtrip) support to PMC Date: Sat, 6 Sep 2014 11:54:45 +0300 [thread overview] Message-ID: <1409993685-21911-6-git-send-email-cyndis@kapsi.fi> (raw) In-Reply-To: <1409993685-21911-1-git-send-email-cyndis@kapsi.fi> From: Mikko Perttunen <mperttunen@nvidia.com> This adds a device tree controlled option to enable PMC-based thermal reset in overheating situations. Thermtrip is supported on Tegra30, Tegra114 and Tegra124. The thermal reset only works when the thermal sensors are calibrated, so a soctherm driver is also required. The thermtrip event is triggered by the soctherm block, and all soctherm sensors default to showing a temperature of zero Celsius before they are initialized. Because of this, it is safe to initialize thermtrip and soctherm in any order. Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com> Reviewed-by: Wei Ni <wni@nvidia.com> Tested-by: Wei Ni <wni@nvidia.com> --- v3 - updated to new binding - updated commit message drivers/soc/tegra/pmc.c | 379 +++++++++++++++++++++++++++++++----------------- 1 file changed, 247 insertions(+), 132 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index a2c0ceb..de514fe 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -83,11 +83,28 @@ #define GPU_RG_CNTRL 0x2d4 +#define PMC_SENSOR_CTRL 0x1b0 +#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) +#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) + +#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 + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; unsigned int num_cpu_powergates; const u8 *cpu_powergates; + bool has_tsense_reset; }; /** @@ -606,6 +623,234 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) } #endif +static const char * const tegra20_powergates[] = { + [TEGRA_POWERGATE_CPU] = "cpu", + [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_VENC] = "venc", + [TEGRA_POWERGATE_VDEC] = "vdec", + [TEGRA_POWERGATE_PCIE] = "pcie", + [TEGRA_POWERGATE_L2] = "l2", + [TEGRA_POWERGATE_MPE] = "mpe", +}; + +static const struct tegra_pmc_soc tegra20_pmc_soc = { + .num_powergates = ARRAY_SIZE(tegra20_powergates), + .powergates = tegra20_powergates, + .num_cpu_powergates = 0, + .cpu_powergates = NULL, +}; + +static const char * const tegra30_powergates[] = { + [TEGRA_POWERGATE_CPU] = "cpu0", + [TEGRA_POWERGATE_3D] = "3d0", + [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", + [TEGRA_POWERGATE_3D1] = "3d1", +}; + +static const u8 tegra30_cpu_powergates[] = { + TEGRA_POWERGATE_CPU, + TEGRA_POWERGATE_CPU1, + TEGRA_POWERGATE_CPU2, + TEGRA_POWERGATE_CPU3, +}; + +static const struct tegra_pmc_soc tegra30_pmc_soc = { + .num_powergates = ARRAY_SIZE(tegra30_powergates), + .powergates = tegra30_powergates, + .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), + .cpu_powergates = tegra30_cpu_powergates, + .has_tsense_reset = true, +}; + +static const char * const tegra114_powergates[] = { + [TEGRA_POWERGATE_CPU] = "crail", + [TEGRA_POWERGATE_3D] = "3d", + [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 = { + .num_powergates = ARRAY_SIZE(tegra114_powergates), + .powergates = tegra114_powergates, + .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), + .cpu_powergates = tegra114_cpu_powergates, + .has_tsense_reset = true, +}; + +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_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", + [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, +}; + +static const struct tegra_pmc_soc tegra124_pmc_soc = { + .num_powergates = ARRAY_SIZE(tegra124_powergates), + .powergates = tegra124_powergates, + .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), + .cpu_powergates = tegra124_cpu_powergates, + .has_tsense_reset = true, +}; + +static const struct of_device_id tegra_pmc_match[] = { + { .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 }, + { } +}; + +void tegra_pmc_init_tsense_reset(struct device *dev) +{ + u32 pmu_i2c_addr, i2c_ctrl_id, reg_addr, reg_data, pinmux; + u32 value, checksum; + struct device_node *np = dev->of_node; + struct device_node *i2c_np, *tt_np; + const struct of_device_id *match = of_match_node(tegra_pmc_match, np); + const struct tegra_pmc_soc *data = match->data; + + if (!data->has_tsense_reset) + return; + + tt_np = of_find_node_by_name(np, "i2c-thermtrip"); + if (!tt_np) { + dev_warn(dev, "no i2c-thermtrip node found, disabling emergency thermal reset\n"); + return; + } + + i2c_np = of_parse_phandle(tt_np, "nvidia,i2c-bus", 0); + if (!i2c_np) { + dev_err(dev, "I2C bus reference missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + if (of_property_read_u32(i2c_np, "nvidia,controller-id", &i2c_ctrl_id)) { + dev_err(dev, "I2C bus controller id missing, disabling emergency thermal reset\n"); + goto put_i2c; + } + + of_node_put(i2c_np); + + if (of_property_read_u32(tt_np, "nvidia,bus-addr", &pmu_i2c_addr)) { + dev_err(dev, "nvidia,bus-addr missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + if (of_property_read_u32(tt_np, "nvidia,reg-addr", ®_addr)) { + dev_err(dev, "nvidia,reg-addr missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + if (of_property_read_u32(tt_np, "nvidia,reg-data", ®_data)) { + dev_err(dev, "nvidia,reg-data missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + if (of_property_read_u32(tt_np, "nvidia,pinmux-id", &pinmux)) + pinmux = 0; + + of_node_put(tt_np); + + 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 = 0; + value |= PMC_SCRATCH55_RESET_TEGRA; + value |= i2c_ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT; + value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT; + value |= pmu_i2c_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(dev, "PMC emergency thermal reset enabled\n"); + + return; + +put_i2c: + of_node_put(i2c_np); + +put_tt: + of_node_put(tt_np); +} + static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) { u32 value, values[2]; @@ -730,6 +975,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) tegra_pmc_init(pmc); + tegra_pmc_init_tsense_reset(&pdev->dev); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_powergate_debugfs_init(); if (err < 0) @@ -757,138 +1004,6 @@ static int tegra_pmc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); -static const char * const tegra20_powergates[] = { - [TEGRA_POWERGATE_CPU] = "cpu", - [TEGRA_POWERGATE_3D] = "3d", - [TEGRA_POWERGATE_VENC] = "venc", - [TEGRA_POWERGATE_VDEC] = "vdec", - [TEGRA_POWERGATE_PCIE] = "pcie", - [TEGRA_POWERGATE_L2] = "l2", - [TEGRA_POWERGATE_MPE] = "mpe", -}; - -static const struct tegra_pmc_soc tegra20_pmc_soc = { - .num_powergates = ARRAY_SIZE(tegra20_powergates), - .powergates = tegra20_powergates, - .num_cpu_powergates = 0, - .cpu_powergates = NULL, -}; - -static const char * const tegra30_powergates[] = { - [TEGRA_POWERGATE_CPU] = "cpu0", - [TEGRA_POWERGATE_3D] = "3d0", - [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", - [TEGRA_POWERGATE_3D1] = "3d1", -}; - -static const u8 tegra30_cpu_powergates[] = { - TEGRA_POWERGATE_CPU, - TEGRA_POWERGATE_CPU1, - TEGRA_POWERGATE_CPU2, - TEGRA_POWERGATE_CPU3, -}; - -static const struct tegra_pmc_soc tegra30_pmc_soc = { - .num_powergates = ARRAY_SIZE(tegra30_powergates), - .powergates = tegra30_powergates, - .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), - .cpu_powergates = tegra30_cpu_powergates, -}; - -static const char * const tegra114_powergates[] = { - [TEGRA_POWERGATE_CPU] = "crail", - [TEGRA_POWERGATE_3D] = "3d", - [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 = { - .num_powergates = ARRAY_SIZE(tegra114_powergates), - .powergates = tegra114_powergates, - .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), - .cpu_powergates = tegra114_cpu_powergates, -}; - -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_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", - [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, -}; - -static const struct tegra_pmc_soc tegra124_pmc_soc = { - .num_powergates = ARRAY_SIZE(tegra124_powergates), - .powergates = tegra124_powergates, - .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), - .cpu_powergates = tegra124_cpu_powergates, -}; - -static const struct of_device_id tegra_pmc_match[] = { - { .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 }, - { } -}; - static struct platform_driver tegra_pmc_driver = { .driver = { .name = "tegra-pmc", -- 2.1.0
WARNING: multiple messages have this Message-ID (diff)
From: cyndis@kapsi.fi (Mikko Perttunen) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH v3 5/5] ARM: tegra: Add thermal reset (thermtrip) support to PMC Date: Sat, 6 Sep 2014 11:54:45 +0300 [thread overview] Message-ID: <1409993685-21911-6-git-send-email-cyndis@kapsi.fi> (raw) In-Reply-To: <1409993685-21911-1-git-send-email-cyndis@kapsi.fi> From: Mikko Perttunen <mperttunen@nvidia.com> This adds a device tree controlled option to enable PMC-based thermal reset in overheating situations. Thermtrip is supported on Tegra30, Tegra114 and Tegra124. The thermal reset only works when the thermal sensors are calibrated, so a soctherm driver is also required. The thermtrip event is triggered by the soctherm block, and all soctherm sensors default to showing a temperature of zero Celsius before they are initialized. Because of this, it is safe to initialize thermtrip and soctherm in any order. Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com> Reviewed-by: Wei Ni <wni@nvidia.com> Tested-by: Wei Ni <wni@nvidia.com> --- v3 - updated to new binding - updated commit message drivers/soc/tegra/pmc.c | 379 +++++++++++++++++++++++++++++++----------------- 1 file changed, 247 insertions(+), 132 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index a2c0ceb..de514fe 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -83,11 +83,28 @@ #define GPU_RG_CNTRL 0x2d4 +#define PMC_SENSOR_CTRL 0x1b0 +#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) +#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) + +#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 + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; unsigned int num_cpu_powergates; const u8 *cpu_powergates; + bool has_tsense_reset; }; /** @@ -606,6 +623,234 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) } #endif +static const char * const tegra20_powergates[] = { + [TEGRA_POWERGATE_CPU] = "cpu", + [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_VENC] = "venc", + [TEGRA_POWERGATE_VDEC] = "vdec", + [TEGRA_POWERGATE_PCIE] = "pcie", + [TEGRA_POWERGATE_L2] = "l2", + [TEGRA_POWERGATE_MPE] = "mpe", +}; + +static const struct tegra_pmc_soc tegra20_pmc_soc = { + .num_powergates = ARRAY_SIZE(tegra20_powergates), + .powergates = tegra20_powergates, + .num_cpu_powergates = 0, + .cpu_powergates = NULL, +}; + +static const char * const tegra30_powergates[] = { + [TEGRA_POWERGATE_CPU] = "cpu0", + [TEGRA_POWERGATE_3D] = "3d0", + [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", + [TEGRA_POWERGATE_3D1] = "3d1", +}; + +static const u8 tegra30_cpu_powergates[] = { + TEGRA_POWERGATE_CPU, + TEGRA_POWERGATE_CPU1, + TEGRA_POWERGATE_CPU2, + TEGRA_POWERGATE_CPU3, +}; + +static const struct tegra_pmc_soc tegra30_pmc_soc = { + .num_powergates = ARRAY_SIZE(tegra30_powergates), + .powergates = tegra30_powergates, + .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), + .cpu_powergates = tegra30_cpu_powergates, + .has_tsense_reset = true, +}; + +static const char * const tegra114_powergates[] = { + [TEGRA_POWERGATE_CPU] = "crail", + [TEGRA_POWERGATE_3D] = "3d", + [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 = { + .num_powergates = ARRAY_SIZE(tegra114_powergates), + .powergates = tegra114_powergates, + .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), + .cpu_powergates = tegra114_cpu_powergates, + .has_tsense_reset = true, +}; + +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_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", + [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, +}; + +static const struct tegra_pmc_soc tegra124_pmc_soc = { + .num_powergates = ARRAY_SIZE(tegra124_powergates), + .powergates = tegra124_powergates, + .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), + .cpu_powergates = tegra124_cpu_powergates, + .has_tsense_reset = true, +}; + +static const struct of_device_id tegra_pmc_match[] = { + { .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 }, + { } +}; + +void tegra_pmc_init_tsense_reset(struct device *dev) +{ + u32 pmu_i2c_addr, i2c_ctrl_id, reg_addr, reg_data, pinmux; + u32 value, checksum; + struct device_node *np = dev->of_node; + struct device_node *i2c_np, *tt_np; + const struct of_device_id *match = of_match_node(tegra_pmc_match, np); + const struct tegra_pmc_soc *data = match->data; + + if (!data->has_tsense_reset) + return; + + tt_np = of_find_node_by_name(np, "i2c-thermtrip"); + if (!tt_np) { + dev_warn(dev, "no i2c-thermtrip node found, disabling emergency thermal reset\n"); + return; + } + + i2c_np = of_parse_phandle(tt_np, "nvidia,i2c-bus", 0); + if (!i2c_np) { + dev_err(dev, "I2C bus reference missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + if (of_property_read_u32(i2c_np, "nvidia,controller-id", &i2c_ctrl_id)) { + dev_err(dev, "I2C bus controller id missing, disabling emergency thermal reset\n"); + goto put_i2c; + } + + of_node_put(i2c_np); + + if (of_property_read_u32(tt_np, "nvidia,bus-addr", &pmu_i2c_addr)) { + dev_err(dev, "nvidia,bus-addr missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + if (of_property_read_u32(tt_np, "nvidia,reg-addr", ®_addr)) { + dev_err(dev, "nvidia,reg-addr missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + if (of_property_read_u32(tt_np, "nvidia,reg-data", ®_data)) { + dev_err(dev, "nvidia,reg-data missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + if (of_property_read_u32(tt_np, "nvidia,pinmux-id", &pinmux)) + pinmux = 0; + + of_node_put(tt_np); + + 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 = 0; + value |= PMC_SCRATCH55_RESET_TEGRA; + value |= i2c_ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT; + value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT; + value |= pmu_i2c_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(dev, "PMC emergency thermal reset enabled\n"); + + return; + +put_i2c: + of_node_put(i2c_np); + +put_tt: + of_node_put(tt_np); +} + static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) { u32 value, values[2]; @@ -730,6 +975,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) tegra_pmc_init(pmc); + tegra_pmc_init_tsense_reset(&pdev->dev); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_powergate_debugfs_init(); if (err < 0) @@ -757,138 +1004,6 @@ static int tegra_pmc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); -static const char * const tegra20_powergates[] = { - [TEGRA_POWERGATE_CPU] = "cpu", - [TEGRA_POWERGATE_3D] = "3d", - [TEGRA_POWERGATE_VENC] = "venc", - [TEGRA_POWERGATE_VDEC] = "vdec", - [TEGRA_POWERGATE_PCIE] = "pcie", - [TEGRA_POWERGATE_L2] = "l2", - [TEGRA_POWERGATE_MPE] = "mpe", -}; - -static const struct tegra_pmc_soc tegra20_pmc_soc = { - .num_powergates = ARRAY_SIZE(tegra20_powergates), - .powergates = tegra20_powergates, - .num_cpu_powergates = 0, - .cpu_powergates = NULL, -}; - -static const char * const tegra30_powergates[] = { - [TEGRA_POWERGATE_CPU] = "cpu0", - [TEGRA_POWERGATE_3D] = "3d0", - [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", - [TEGRA_POWERGATE_3D1] = "3d1", -}; - -static const u8 tegra30_cpu_powergates[] = { - TEGRA_POWERGATE_CPU, - TEGRA_POWERGATE_CPU1, - TEGRA_POWERGATE_CPU2, - TEGRA_POWERGATE_CPU3, -}; - -static const struct tegra_pmc_soc tegra30_pmc_soc = { - .num_powergates = ARRAY_SIZE(tegra30_powergates), - .powergates = tegra30_powergates, - .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), - .cpu_powergates = tegra30_cpu_powergates, -}; - -static const char * const tegra114_powergates[] = { - [TEGRA_POWERGATE_CPU] = "crail", - [TEGRA_POWERGATE_3D] = "3d", - [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 = { - .num_powergates = ARRAY_SIZE(tegra114_powergates), - .powergates = tegra114_powergates, - .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), - .cpu_powergates = tegra114_cpu_powergates, -}; - -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_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", - [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, -}; - -static const struct tegra_pmc_soc tegra124_pmc_soc = { - .num_powergates = ARRAY_SIZE(tegra124_powergates), - .powergates = tegra124_powergates, - .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), - .cpu_powergates = tegra124_cpu_powergates, -}; - -static const struct of_device_id tegra_pmc_match[] = { - { .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 }, - { } -}; - static struct platform_driver tegra_pmc_driver = { .driver = { .name = "tegra-pmc", -- 2.1.0
next prev parent reply other threads:[~2014-09-06 8:54 UTC|newest] Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top 2014-09-06 8:54 [PATCH v3 0/5] Thermal reset support in PMC Mikko Perttunen 2014-09-06 8:54 ` Mikko Perttunen [not found] ` <1409993685-21911-1-git-send-email-cyndis-/1wQRMveznE@public.gmane.org> 2014-09-06 8:54 ` [PATCH v3 1/5] of: Add descriptions of thermtrip properties to Tegra PMC bindings Mikko Perttunen 2014-09-06 8:54 ` Mikko Perttunen 2014-09-06 8:54 ` Mikko Perttunen [not found] ` <1409993685-21911-2-git-send-email-cyndis-/1wQRMveznE@public.gmane.org> 2014-09-06 9:03 ` [PATCH v4 " Mikko Perttunen 2014-09-06 9:03 ` Mikko Perttunen 2014-09-06 9:03 ` Mikko Perttunen 2014-09-06 8:54 ` [PATCH v3 2/5] of: Add nvidia,controller-id property to Tegra I2C bindings Mikko Perttunen 2014-09-06 8:54 ` [PATCH v3 2/5] of: Add nvidia, controller-id " Mikko Perttunen 2014-09-06 8:54 ` [PATCH v3 2/5] of: Add nvidia,controller-id " Mikko Perttunen 2014-09-06 8:54 ` [PATCH v3 4/5] ARM: tegra: Add PMC thermtrip programming to Jetson TK1 device tree Mikko Perttunen 2014-09-06 8:54 ` Mikko Perttunen 2014-09-06 8:54 ` Mikko Perttunen 2014-09-06 8:54 ` [PATCH v3 3/5] ARM: tegra124: Add I2C controller ids to " Mikko Perttunen 2014-09-06 8:54 ` Mikko Perttunen 2014-09-06 8:54 ` Mikko Perttunen [this message] 2014-09-06 8:54 ` [PATCH v3 5/5] ARM: tegra: Add thermal reset (thermtrip) support to PMC Mikko Perttunen
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1409993685-21911-6-git-send-email-cyndis@kapsi.fi \ --to=cyndis@kapsi.fi \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-tegra@vger.kernel.org \ --cc=mperttunen@nvidia.com \ --cc=swarren@wwwdotorg.org \ --cc=thierry.reding@gmail.com \ --cc=wni@nvidia.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.