From patchwork Tue Jan 6 10:52:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikko Perttunen X-Patchwork-Id: 5572991 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 2D8B4BF6C3 for ; Tue, 6 Jan 2015 10:57:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 283932020E for ; Tue, 6 Jan 2015 10:57:05 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2430C201EF for ; Tue, 6 Jan 2015 10:57:04 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Y8Rn6-0004Ht-SX; Tue, 06 Jan 2015 10:55:12 +0000 Received: from mx1.kapsi.fi ([2001:1bc8:1004::1:25] helo=mail.kapsi.fi) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Y8RmY-0002pZ-4L for linux-arm-kernel@lists.infradead.org; Tue, 06 Jan 2015 10:54:40 +0000 Received: from [2001:708:30:12d0:beee:7bff:fe5b:f272] (helo=katsura.kyla.fi) by mail.kapsi.fi with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.72) (envelope-from ) id 1Y8Rm2-0005gF-VK; Tue, 06 Jan 2015 12:54:06 +0200 From: Mikko Perttunen To: swarren@wwwdotorg.org, thierry.reding@gmail.com, gnurou@gmail.com Subject: [PATCH v5 3/3] ARM: tegra: Add thermal reset (thermtrip) support to PMC Date: Tue, 6 Jan 2015 12:52:58 +0200 Message-Id: <1420541578-27968-4-git-send-email-mikko.perttunen@kapsi.fi> X-Mailer: git-send-email 2.2.1 In-Reply-To: <1420541578-27968-1-git-send-email-mikko.perttunen@kapsi.fi> References: <1420541578-27968-1-git-send-email-mikko.perttunen@kapsi.fi> X-SA-Exim-Connect-IP: 2001:708:30:12d0:beee:7bff:fe5b:f272 X-SA-Exim-Mail-From: mikko.perttunen@kapsi.fi X-SA-Exim-Scanned: No (on mail.kapsi.fi); SAEximRunCond expanded to false X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150106_025438_364984_18E252A3 X-CRM114-Status: GOOD ( 17.11 ) X-Spam-Score: -0.0 (/) Cc: linux-tegra@vger.kernel.org, wni@nvidia.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Mikko Perttunen X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Mikko Perttunen 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 --- drivers/soc/tegra/pmc.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index a2c0ceb..9ed8be5 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; }; /** @@ -703,6 +720,90 @@ static void tegra_pmc_init(struct tegra_pmc *pmc) tegra_pmc_writel(value, PMC_CNTRL); } +static const struct of_device_id tegra_pmc_match[]; + +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 *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; + } + + if (of_property_read_u32(tt_np, "nvidia,i2c-controller-id", &i2c_ctrl_id)) { + dev_err(dev, "I2C bus controller id missing, disabling emergency thermal reset\n"); + goto put_tt; + } + + 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_tt: + of_node_put(tt_np); +} + static int tegra_pmc_probe(struct platform_device *pdev) { void __iomem *base = pmc->base; @@ -730,6 +831,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) @@ -772,6 +875,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .powergates = tegra20_powergates, .num_cpu_powergates = 0, .cpu_powergates = NULL, + .has_tsense_reset = false, }; static const char * const tegra30_powergates[] = { @@ -803,6 +907,7 @@ 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, }; static const char * const tegra114_powergates[] = { @@ -838,6 +943,7 @@ 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, }; static const char * const tegra124_powergates[] = { @@ -879,6 +985,7 @@ 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, }; static const struct of_device_id tegra_pmc_match[] = {