[arm64] rtc: tegra: Implement clock handling (Closes: #858514)
This commit is contained in:
parent
8a7210aeea
commit
42ea80c71c
|
@ -144,6 +144,7 @@ linux (4.9.18-1) UNRELEASED; urgency=medium
|
|||
* [x86] drm/vmwgfx: fix integer overflow in vmw_surface_define_ioctl()
|
||||
(CVE-2017-7294)
|
||||
* net/packet: Fix integer overflow in various range checks (CVE-2017-7308)
|
||||
* [arm64] rtc: tegra: Implement clock handling (Closes: #858514)
|
||||
|
||||
-- Ben Hutchings <ben@decadent.org.uk> Mon, 27 Mar 2017 21:54:36 +0100
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
From: Thierry Reding <treding@nvidia.com>
|
||||
Date: Thu, 12 Jan 2017 17:07:43 +0100
|
||||
Subject: rtc: tegra: Implement clock handling
|
||||
Origin: https://git.kernel.org/linus/5fa4086987506b2ab8c92f8f99f2295db9918856
|
||||
Bug-Debian: https://bugs.debian.org/858514
|
||||
|
||||
Accessing the registers of the RTC block on Tegra requires the module
|
||||
clock to be enabled. This only works because the RTC module clock will
|
||||
be enabled by default during early boot. However, because the clock is
|
||||
unused, the CCF will disable it at late_init time. This causes the RTC
|
||||
to become unusable afterwards. This can easily be reproduced by trying
|
||||
to use the RTC:
|
||||
|
||||
$ hwclock --rtc /dev/rtc1
|
||||
|
||||
This will hang the system. I ran into this by following up on a report
|
||||
by Martin Michlmayr that reboot wasn't working on Tegra210 systems. It
|
||||
turns out that the rtc-tegra driver's ->shutdown() implementation will
|
||||
hang the CPU, because of the disabled clock, before the system can be
|
||||
rebooted.
|
||||
|
||||
What confused me for a while is that the same driver is used on prior
|
||||
Tegra generations where the hang can not be observed. However, as Peter
|
||||
De Schrijver pointed out, this is because on 32-bit Tegra chips the RTC
|
||||
clock is enabled by the tegra20_timer.c clocksource driver, which uses
|
||||
the RTC to provide a persistent clock. This code is never enabled on
|
||||
64-bit Tegra because the persistent clock infrastructure does not exist
|
||||
on 64-bit ARM.
|
||||
|
||||
The proper fix for this is to add proper clock handling to the RTC
|
||||
driver in order to ensure that the clock is enabled when the driver
|
||||
requires it. All device trees contain the clock already, therefore
|
||||
no additional changes are required.
|
||||
|
||||
Reported-by: Martin Michlmayr <tbm@cyrius.com>
|
||||
Acked-By Peter De Schrijver <pdeschrijver@nvidia.com>
|
||||
Signed-off-by: Thierry Reding <treding@nvidia.com>
|
||||
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
[bwh: Backported to 4.9: adjust context]
|
||||
---
|
||||
drivers/rtc/rtc-tegra.c | 28 ++++++++++++++++++++++++++--
|
||||
1 file changed, 26 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/rtc/rtc-tegra.c
|
||||
+++ b/drivers/rtc/rtc-tegra.c
|
||||
@@ -18,6 +18,7 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
+#include <linux/clk.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -59,6 +60,7 @@ struct tegra_rtc_info {
|
||||
struct platform_device *pdev;
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *rtc_base; /* NULL if not initialized. */
|
||||
+ struct clk *clk;
|
||||
int tegra_rtc_irq; /* alarm and periodic irq */
|
||||
spinlock_t tegra_rtc_lock;
|
||||
};
|
||||
@@ -326,6 +328,14 @@ static int __init tegra_rtc_probe(struct
|
||||
if (info->tegra_rtc_irq <= 0)
|
||||
return -EBUSY;
|
||||
|
||||
+ info->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(info->clk))
|
||||
+ return PTR_ERR(info->clk);
|
||||
+
|
||||
+ ret = clk_prepare_enable(info->clk);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
/* set context info. */
|
||||
info->pdev = pdev;
|
||||
spin_lock_init(&info->tegra_rtc_lock);
|
||||
@@ -346,7 +356,7 @@ static int __init tegra_rtc_probe(struct
|
||||
ret = PTR_ERR(info->rtc_dev);
|
||||
dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
|
||||
ret);
|
||||
- return ret;
|
||||
+ goto disable_clk;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
|
||||
@@ -356,12 +366,25 @@ static int __init tegra_rtc_probe(struct
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to request interrupt for device (err=%d).\n",
|
||||
ret);
|
||||
- return ret;
|
||||
+ goto disable_clk;
|
||||
}
|
||||
|
||||
dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
|
||||
|
||||
return 0;
|
||||
+
|
||||
+disable_clk:
|
||||
+ clk_disable_unprepare(info->clk);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int tegra_rtc_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct tegra_rtc_info *info = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ clk_disable_unprepare(info->clk);
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@@ -413,6 +436,7 @@ static void tegra_rtc_shutdown(struct pl
|
||||
|
||||
MODULE_ALIAS("platform:tegra_rtc");
|
||||
static struct platform_driver tegra_rtc_driver = {
|
||||
+ .remove = tegra_rtc_remove,
|
||||
.shutdown = tegra_rtc_shutdown,
|
||||
.driver = {
|
||||
.name = "tegra_rtc",
|
|
@ -55,6 +55,7 @@ bugfix/x86/asoc-intel-select-dw_dmac_core-since-it-s-mandatory.patch
|
|||
bugfix/x86/platform-x86-acer-wmi-setup-accelerometer-when-machi.patch
|
||||
bugfix/x86/x86-xen-fix-apic-id-mismatch-warning-on-intel.patch
|
||||
bugfix/arm/arm-dts-kirkwood-fix-sata-pinmux-ing-for-ts419.patch
|
||||
bugfix/arm64/rtc-tegra-implement-clock-handling.patch
|
||||
|
||||
# Arch features
|
||||
features/mips/MIPS-increase-MAX-PHYSMEM-BITS-on-Loongson-3-only.patch
|
||||
|
|
Loading…
Reference in New Issue