Update Linux to v5.10.109
Sourced from [1]
[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz
Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index 5394d9d..e5c631f 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -1,9 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* linux/arch/arm/plat-omap/dmtimer.c
*
* OMAP Dual-Mode Timers
*
- * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/
* Tarun Kanti DebBarma <tarun.kanti@ti.com>
* Thara Gopinath <thara@ti.com>
*
@@ -15,28 +16,11 @@
*
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/cpu_pm.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/device.h>
@@ -94,6 +78,9 @@
static void omap_timer_restore_context(struct omap_dm_timer *timer)
{
+ __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+ timer->context.ocp_cfg, 0);
+
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
timer->context.twer);
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
@@ -109,6 +96,50 @@
timer->context.tclr);
}
+static void omap_timer_save_context(struct omap_dm_timer *timer)
+{
+ timer->context.ocp_cfg =
+ __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
+
+ timer->context.tclr =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ timer->context.twer =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG);
+ timer->context.tldr =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_LOAD_REG);
+ timer->context.tmar =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG);
+ timer->context.tier = readl_relaxed(timer->irq_ena);
+ timer->context.tsicr =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_IF_CTRL_REG);
+}
+
+static int omap_timer_context_notifier(struct notifier_block *nb,
+ unsigned long cmd, void *v)
+{
+ struct omap_dm_timer *timer;
+
+ timer = container_of(nb, struct omap_dm_timer, nb);
+
+ switch (cmd) {
+ case CPU_CLUSTER_PM_ENTER:
+ if ((timer->capability & OMAP_TIMER_ALWON) ||
+ !atomic_read(&timer->enabled))
+ break;
+ omap_timer_save_context(timer);
+ break;
+ case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_EXIT:
+ if ((timer->capability & OMAP_TIMER_ALWON) ||
+ !atomic_read(&timer->enabled))
+ break;
+ omap_timer_restore_context(timer);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
static int omap_dm_timer_reset(struct omap_dm_timer *timer)
{
u32 l, timeout = 100000;
@@ -138,35 +169,6 @@
return 0;
}
-static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer)
-{
- int ret;
- struct clk *parent;
-
- /*
- * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
- * do not call clk_get() for these devices.
- */
- if (!timer->fclk)
- return -ENODEV;
-
- parent = clk_get(&timer->pdev->dev, NULL);
- if (IS_ERR(parent))
- return -ENODEV;
-
- /* Bail out if both clocks point to fck */
- if (clk_is_match(parent, timer->fclk))
- return 0;
-
- ret = clk_set_parent(timer->fclk, parent);
- if (ret < 0)
- pr_err("%s: failed to set parent\n", __func__);
-
- clk_put(parent);
-
- return ret;
-}
-
static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{
int ret;
@@ -225,21 +227,7 @@
static void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
- int c;
-
pm_runtime_get_sync(&timer->pdev->dev);
-
- if (!(timer->capability & OMAP_TIMER_ALWON)) {
- if (timer->get_context_loss_count) {
- c = timer->get_context_loss_count(&timer->pdev->dev);
- if (c != timer->ctx_loss_count) {
- omap_timer_restore_context(timer);
- timer->ctx_loss_count = c;
- }
- } else {
- omap_timer_restore_context(timer);
- }
- }
}
static void omap_dm_timer_disable(struct omap_dm_timer *timer)
@@ -276,11 +264,7 @@
__omap_dm_timer_enable_posted(timer);
omap_dm_timer_disable(timer);
- rc = omap_dm_timer_of_set_source(timer);
- if (rc == -ENODEV)
- return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
-
- return rc;
+ return 0;
}
static inline u32 omap_dm_timer_reserved_systimer(int id)
@@ -508,7 +492,7 @@
int omap_dm_timer_trigger(struct omap_dm_timer *timer)
{
- if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+ if (unlikely(!timer || !atomic_read(&timer->enabled))) {
pr_err("%s: timer not available or enabled.\n", __func__);
return -EINVAL;
}
@@ -532,8 +516,6 @@
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
- /* Save the context */
- timer->context.tclr = l;
return 0;
}
@@ -549,38 +531,19 @@
__omap_dm_timer_stop(timer, timer->posted, rate);
- /*
- * Since the register values are computed and written within
- * __omap_dm_timer_stop, we need to use read to retrieve the
- * context.
- */
- timer->context.tclr =
- omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
omap_dm_timer_disable(timer);
return 0;
}
-static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
+static int omap_dm_timer_set_load(struct omap_dm_timer *timer,
unsigned int load)
{
- u32 l;
-
if (unlikely(!timer))
return -EINVAL;
omap_dm_timer_enable(timer);
- l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
- if (autoreload)
- l |= OMAP_TIMER_CTRL_AR;
- else
- l &= ~OMAP_TIMER_CTRL_AR;
- omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
- omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
- /* Save the context */
- timer->context.tclr = l;
- timer->context.tldr = load;
omap_dm_timer_disable(timer);
return 0;
}
@@ -602,15 +565,12 @@
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
- /* Save the context */
- timer->context.tclr = l;
- timer->context.tmar = match;
omap_dm_timer_disable(timer);
return 0;
}
static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
- int toggle, int trigger)
+ int toggle, int trigger, int autoreload)
{
u32 l;
@@ -620,20 +580,34 @@
omap_dm_timer_enable(timer);
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
- OMAP_TIMER_CTRL_PT | (0x03 << 10));
+ OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR);
if (def_on)
l |= OMAP_TIMER_CTRL_SCPWM;
if (toggle)
l |= OMAP_TIMER_CTRL_PT;
l |= trigger << 10;
+ if (autoreload)
+ l |= OMAP_TIMER_CTRL_AR;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
- /* Save the context */
- timer->context.tclr = l;
omap_dm_timer_disable(timer);
return 0;
}
+static int omap_dm_timer_get_pwm_status(struct omap_dm_timer *timer)
+{
+ u32 l;
+
+ if (unlikely(!timer))
+ return -EINVAL;
+
+ omap_dm_timer_enable(timer);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ omap_dm_timer_disable(timer);
+
+ return l;
+}
+
static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
int prescaler)
{
@@ -651,8 +625,6 @@
}
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
- /* Save the context */
- timer->context.tclr = l;
omap_dm_timer_disable(timer);
return 0;
}
@@ -666,9 +638,6 @@
omap_dm_timer_enable(timer);
__omap_dm_timer_int_enable(timer, value);
- /* Save the context */
- timer->context.tier = value;
- timer->context.twer = value;
omap_dm_timer_disable(timer);
return 0;
}
@@ -696,9 +665,6 @@
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
- /* Save the context */
- timer->context.tier &= ~mask;
- timer->context.twer &= ~mask;
omap_dm_timer_disable(timer);
return 0;
}
@@ -707,7 +673,7 @@
{
unsigned int l;
- if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+ if (unlikely(!timer || !atomic_read(&timer->enabled))) {
pr_err("%s: timer not available or enabled.\n", __func__);
return 0;
}
@@ -719,7 +685,7 @@
static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
{
- if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
+ if (unlikely(!timer || !atomic_read(&timer->enabled)))
return -EINVAL;
__omap_dm_timer_write_status(timer, value);
@@ -729,7 +695,7 @@
static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
{
- if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+ if (unlikely(!timer || !atomic_read(&timer->enabled))) {
pr_err("%s: timer not iavailable or enabled.\n", __func__);
return 0;
}
@@ -739,7 +705,7 @@
static int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
{
- if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+ if (unlikely(!timer || !atomic_read(&timer->enabled))) {
pr_err("%s: timer not available or enabled.\n", __func__);
return -EINVAL;
}
@@ -767,6 +733,37 @@
return 0;
}
+static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev)
+{
+ struct omap_dm_timer *timer = dev_get_drvdata(dev);
+
+ atomic_set(&timer->enabled, 0);
+
+ if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base)
+ return 0;
+
+ omap_timer_save_context(timer);
+
+ return 0;
+}
+
+static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev)
+{
+ struct omap_dm_timer *timer = dev_get_drvdata(dev);
+
+ if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base)
+ omap_timer_restore_context(timer);
+
+ atomic_set(&timer->enabled, 1);
+
+ return 0;
+}
+
+static const struct dev_pm_ops omap_dm_timer_pm_ops = {
+ SET_RUNTIME_PM_OPS(omap_dm_timer_runtime_suspend,
+ omap_dm_timer_runtime_resume, NULL)
+};
+
static const struct of_device_id omap_timer_match[];
/**
@@ -780,7 +777,6 @@
{
unsigned long flags;
struct omap_dm_timer *timer;
- struct resource *mem, *irq;
struct device *dev = &pdev->dev;
const struct dmtimer_platform_data *pdata;
int ret;
@@ -796,27 +792,21 @@
return -ENODEV;
}
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (unlikely(!irq)) {
- dev_err(dev, "%s: no IRQ resource.\n", __func__);
- return -ENODEV;
- }
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!mem)) {
- dev_err(dev, "%s: no memory resource.\n", __func__);
- return -ENODEV;
- }
-
timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
if (!timer)
return -ENOMEM;
+ timer->irq = platform_get_irq(pdev, 0);
+ if (timer->irq < 0)
+ return timer->irq;
+
timer->fclk = ERR_PTR(-ENODEV);
- timer->io_base = devm_ioremap_resource(dev, mem);
+ timer->io_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(timer->io_base))
return PTR_ERR(timer->io_base);
+ platform_set_drvdata(pdev, timer);
+
if (dev->of_node) {
if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
timer->capability |= OMAP_TIMER_ALWON;
@@ -830,13 +820,16 @@
timer->id = pdev->id;
timer->capability = pdata->timer_capability;
timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
- timer->get_context_loss_count = pdata->get_context_loss_count;
+ }
+
+ if (!(timer->capability & OMAP_TIMER_ALWON)) {
+ timer->nb.notifier_call = omap_timer_context_notifier;
+ cpu_pm_register_notifier(&timer->nb);
}
if (pdata)
timer->errata = pdata->timer_errata;
- timer->irq = irq->start;
timer->pdev = pdev;
pm_runtime_enable(dev);
@@ -885,6 +878,8 @@
list_for_each_entry(timer, &omap_timer_list, node)
if (!strcmp(dev_name(&timer->pdev->dev),
dev_name(&pdev->dev))) {
+ if (!(timer->capability & OMAP_TIMER_ALWON))
+ cpu_pm_unregister_notifier(&timer->nb);
list_del(&timer->node);
ret = 0;
break;
@@ -913,6 +908,7 @@
.set_load = omap_dm_timer_set_load,
.set_match = omap_dm_timer_set_match,
.set_pwm = omap_dm_timer_set_pwm,
+ .get_pwm_status = omap_dm_timer_get_pwm_status,
.set_prescaler = omap_dm_timer_set_prescaler,
.read_counter = omap_dm_timer_read_counter,
.write_counter = omap_dm_timer_write_counter,
@@ -963,6 +959,7 @@
.driver = {
.name = "omap_timer",
.of_match_table = of_match_ptr(omap_timer_match),
+ .pm = &omap_dm_timer_pm_ops,
},
};