--- /dev/null
+From foo@baz Fri Jul 9 03:07:28 PM CEST 2021
+From: Tony Lindgren <tony@atomide.com>
+Date: Fri, 9 Jul 2021 10:37:42 +0300
+Subject: ARM: OMAP: replace setup_irq() by request_irq()
+To: stable@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, afzal mohammed <afzal.mohd.ma@gmail.com>, Daniel Lezcano <daniel.lezcano@linaro.org>, Keerthy <j-keerthy@ti.com>, Tero Kristo <kristo@kernel.org>
+Message-ID: <20210709073745.13916-1-tony@atomide.com>
+
+From: afzal mohammed <afzal.mohd.ma@gmail.com>
+
+commit b75ca5217743e4d7076cf65e044e88389e44318d upstream.
+
+request_irq() is preferred over setup_irq(). Invocations of setup_irq()
+occur after memory allocators are ready.
+
+Per tglx[1], setup_irq() existed in olden days when allocators were not
+ready by the time early interrupts were initialized.
+
+Hence replace setup_irq() by request_irq().
+
+[1] https://lkml.kernel.org/r/alpine.DEB.2.20.1710191609480.1971@nanos
+
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
+Cc: Keerthy <j-keerthy@ti.com>
+Cc: Tero Kristo <kristo@kernel.org>
+Signed-off-by: afzal mohammed <afzal.mohd.ma@gmail.com>
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/mach-omap1/pm.c | 13 ++++++-------
+ arch/arm/mach-omap1/time.c | 10 +++-------
+ arch/arm/mach-omap1/timer32k.c | 10 +++-------
+ arch/arm/mach-omap2/timer.c | 11 +++--------
+ 4 files changed, 15 insertions(+), 29 deletions(-)
+
+--- a/arch/arm/mach-omap1/pm.c
++++ b/arch/arm/mach-omap1/pm.c
+@@ -610,11 +610,6 @@ static irqreturn_t omap_wakeup_interrupt
+ return IRQ_HANDLED;
+ }
+
+-static struct irqaction omap_wakeup_irq = {
+- .name = "peripheral wakeup",
+- .handler = omap_wakeup_interrupt
+-};
+-
+
+
+ static const struct platform_suspend_ops omap_pm_ops = {
+@@ -627,6 +622,7 @@ static const struct platform_suspend_ops
+ static int __init omap_pm_init(void)
+ {
+ int error = 0;
++ int irq;
+
+ if (!cpu_class_is_omap1())
+ return -ENODEV;
+@@ -670,9 +666,12 @@ static int __init omap_pm_init(void)
+ arm_pm_idle = omap1_pm_idle;
+
+ if (cpu_is_omap7xx())
+- setup_irq(INT_7XX_WAKE_UP_REQ, &omap_wakeup_irq);
++ irq = INT_7XX_WAKE_UP_REQ;
+ else if (cpu_is_omap16xx())
+- setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
++ irq = INT_1610_WAKE_UP_REQ;
++ if (request_irq(irq, omap_wakeup_interrupt, 0, "peripheral wakeup",
++ NULL))
++ pr_err("Failed to request irq %d (peripheral wakeup)\n", irq);
+
+ /* Program new power ramp-up time
+ * (0 for most boards since we don't lower voltage when in deep sleep)
+--- a/arch/arm/mach-omap1/time.c
++++ b/arch/arm/mach-omap1/time.c
+@@ -155,15 +155,11 @@ static irqreturn_t omap_mpu_timer1_inter
+ return IRQ_HANDLED;
+ }
+
+-static struct irqaction omap_mpu_timer1_irq = {
+- .name = "mpu_timer1",
+- .flags = IRQF_TIMER | IRQF_IRQPOLL,
+- .handler = omap_mpu_timer1_interrupt,
+-};
+-
+ static __init void omap_init_mpu_timer(unsigned long rate)
+ {
+- setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
++ if (request_irq(INT_TIMER1, omap_mpu_timer1_interrupt,
++ IRQF_TIMER | IRQF_IRQPOLL, "mpu_timer1", NULL))
++ pr_err("Failed to request irq %d (mpu_timer1)\n", INT_TIMER1);
+ omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+ clockevent_mpu_timer1.cpumask = cpumask_of(0);
+--- a/arch/arm/mach-omap1/timer32k.c
++++ b/arch/arm/mach-omap1/timer32k.c
+@@ -148,15 +148,11 @@ static irqreturn_t omap_32k_timer_interr
+ return IRQ_HANDLED;
+ }
+
+-static struct irqaction omap_32k_timer_irq = {
+- .name = "32KHz timer",
+- .flags = IRQF_TIMER | IRQF_IRQPOLL,
+- .handler = omap_32k_timer_interrupt,
+-};
+-
+ static __init void omap_init_32k_timer(void)
+ {
+- setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
++ if (request_irq(INT_OS_TIMER, omap_32k_timer_interrupt,
++ IRQF_TIMER | IRQF_IRQPOLL, "32KHz timer", NULL))
++ pr_err("Failed to request irq %d(32KHz timer)\n", INT_OS_TIMER);
+
+ clockevent_32k_timer.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&clockevent_32k_timer,
+--- a/arch/arm/mach-omap2/timer.c
++++ b/arch/arm/mach-omap2/timer.c
+@@ -92,12 +92,6 @@ static irqreturn_t omap2_gp_timer_interr
+ return IRQ_HANDLED;
+ }
+
+-static struct irqaction omap2_gp_timer_irq = {
+- .name = "gp_timer",
+- .flags = IRQF_TIMER | IRQF_IRQPOLL,
+- .handler = omap2_gp_timer_interrupt,
+-};
+-
+ static int omap2_gp_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+ {
+@@ -383,8 +377,9 @@ static void __init omap2_gp_clockevent_i
+ &clockevent_gpt.name, OMAP_TIMER_POSTED);
+ BUG_ON(res);
+
+- omap2_gp_timer_irq.dev_id = &clkev;
+- setup_irq(clkev.irq, &omap2_gp_timer_irq);
++ if (request_irq(clkev.irq, omap2_gp_timer_interrupt,
++ IRQF_TIMER | IRQF_IRQPOLL, "gp_timer", &clkev))
++ pr_err("Failed to request irq %d (gp_timer)\n", clkev.irq);
+
+ __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+
--- /dev/null
+From foo@baz Fri Jul 9 03:07:28 PM CEST 2021
+From: Tony Lindgren <tony@atomide.com>
+Date: Fri, 9 Jul 2021 10:37:43 +0300
+Subject: clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support
+To: stable@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, Daniel Lezcano <daniel.lezcano@linaro.org>, Keerthy <j-keerthy@ti.com>, Tero Kristo <kristo@kernel.org>
+Message-ID: <20210709073745.13916-2-tony@atomide.com>
+
+From: Tony Lindgren <tony@atomide.com>
+
+commit 52762fbd1c4778ac9b173624ca0faacd22ef4724 upstream.
+
+We can move the TI dmtimer clockevent and clocksource to live under
+drivers/clocksource if we rely only on the clock framework, and handle
+the module configuration directly in the clocksource driver based on the
+device tree data.
+
+This removes the early dependency with system timers to the interconnect
+related code, and we can probe pretty much everything else later on at
+the module_init level.
+
+Let's first add a new driver for timer-ti-dm-systimer based on existing
+arch/arm/mach-omap2/timer.c. Then let's start moving SoCs to probe with
+device tree data while still keeping the old timer.c. And eventually we
+can just drop the old timer.c.
+
+Let's take the opportunity to switch to use readl/writel as pointed out
+by Daniel Lezcano <daniel.lezcano@linaro.org>. This allows further
+clean-up of the timer-ti-dm code the a lot of the shared helpers can
+just become static to the non-syster related code.
+
+Note the boards can optionally configure different timer source clocks
+if needed with assigned-clocks and assigned-clock-parents.
+
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
+Cc: Keerthy <j-keerthy@ti.com>
+Cc: Tero Kristo <kristo@kernel.org>
+[tony@atomide.com: backported to 4.19.y]
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/mach-omap2/timer.c | 109 ++++++++++++++++++++++++++------------------
+ 1 file changed, 65 insertions(+), 44 deletions(-)
+
+--- a/arch/arm/mach-omap2/timer.c
++++ b/arch/arm/mach-omap2/timer.c
+@@ -64,15 +64,28 @@
+
+ /* Clockevent code */
+
+-static struct omap_dm_timer clkev;
+-static struct clock_event_device clockevent_gpt;
+-
+ /* Clockevent hwmod for am335x and am437x suspend */
+ static struct omap_hwmod *clockevent_gpt_hwmod;
+
+ /* Clockesource hwmod for am437x suspend */
+ static struct omap_hwmod *clocksource_gpt_hwmod;
+
++struct dmtimer_clockevent {
++ struct clock_event_device dev;
++ struct omap_dm_timer timer;
++};
++
++static struct dmtimer_clockevent clockevent;
++
++static struct omap_dm_timer *to_dmtimer(struct clock_event_device *clockevent)
++{
++ struct dmtimer_clockevent *clkevt =
++ container_of(clockevent, struct dmtimer_clockevent, dev);
++ struct omap_dm_timer *timer = &clkevt->timer;
++
++ return timer;
++}
++
+ #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
+ static unsigned long arch_timer_freq;
+
+@@ -84,10 +97,11 @@ void set_cntfreq(void)
+
+ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
+ {
+- struct clock_event_device *evt = &clockevent_gpt;
+-
+- __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
++ struct dmtimer_clockevent *clkevt = dev_id;
++ struct clock_event_device *evt = &clkevt->dev;
++ struct omap_dm_timer *timer = &clkevt->timer;
+
++ __omap_dm_timer_write_status(timer, OMAP_TIMER_INT_OVERFLOW);
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+ }
+@@ -95,7 +109,9 @@ static irqreturn_t omap2_gp_timer_interr
+ static int omap2_gp_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+ {
+- __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
++ struct omap_dm_timer *timer = to_dmtimer(evt);
++
++ __omap_dm_timer_load_start(timer, OMAP_TIMER_CTRL_ST,
+ 0xffffffff - cycles, OMAP_TIMER_POSTED);
+
+ return 0;
+@@ -103,22 +119,26 @@ static int omap2_gp_timer_set_next_event
+
+ static int omap2_gp_timer_shutdown(struct clock_event_device *evt)
+ {
+- __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate);
++ struct omap_dm_timer *timer = to_dmtimer(evt);
++
++ __omap_dm_timer_stop(timer, OMAP_TIMER_POSTED, timer->rate);
++
+ return 0;
+ }
+
+ static int omap2_gp_timer_set_periodic(struct clock_event_device *evt)
+ {
++ struct omap_dm_timer *timer = to_dmtimer(evt);
+ u32 period;
+
+- __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate);
++ __omap_dm_timer_stop(timer, OMAP_TIMER_POSTED, timer->rate);
+
+- period = clkev.rate / HZ;
++ period = timer->rate / HZ;
+ period -= 1;
+ /* Looks like we need to first set the load value separately */
+- __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, 0xffffffff - period,
++ __omap_dm_timer_write(timer, OMAP_TIMER_LOAD_REG, 0xffffffff - period,
+ OMAP_TIMER_POSTED);
+- __omap_dm_timer_load_start(&clkev,
++ __omap_dm_timer_load_start(timer,
+ OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
+ 0xffffffff - period, OMAP_TIMER_POSTED);
+ return 0;
+@@ -132,26 +152,17 @@ static void omap_clkevt_idle(struct cloc
+ omap_hwmod_idle(clockevent_gpt_hwmod);
+ }
+
+-static void omap_clkevt_unidle(struct clock_event_device *unused)
++static void omap_clkevt_unidle(struct clock_event_device *evt)
+ {
++ struct omap_dm_timer *timer = to_dmtimer(evt);
++
+ if (!clockevent_gpt_hwmod)
+ return;
+
+ omap_hwmod_enable(clockevent_gpt_hwmod);
+- __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
++ __omap_dm_timer_int_enable(timer, OMAP_TIMER_INT_OVERFLOW);
+ }
+
+-static struct clock_event_device clockevent_gpt = {
+- .features = CLOCK_EVT_FEAT_PERIODIC |
+- CLOCK_EVT_FEAT_ONESHOT,
+- .rating = 300,
+- .set_next_event = omap2_gp_timer_set_next_event,
+- .set_state_shutdown = omap2_gp_timer_shutdown,
+- .set_state_periodic = omap2_gp_timer_set_periodic,
+- .set_state_oneshot = omap2_gp_timer_shutdown,
+- .tick_resume = omap2_gp_timer_shutdown,
+-};
+-
+ static const struct of_device_id omap_timer_match[] __initconst = {
+ { .compatible = "ti,omap2420-timer", },
+ { .compatible = "ti,omap3430-timer", },
+@@ -361,44 +372,54 @@ static void __init omap2_gp_clockevent_i
+ const char *fck_source,
+ const char *property)
+ {
++ struct dmtimer_clockevent *clkevt = &clockevent;
++ struct omap_dm_timer *timer = &clkevt->timer;
+ int res;
+
+- clkev.id = gptimer_id;
+- clkev.errata = omap_dm_timer_get_errata();
++ timer->id = gptimer_id;
++ timer->errata = omap_dm_timer_get_errata();
++ clkevt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
++ clkevt->dev.rating = 300;
++ clkevt->dev.set_next_event = omap2_gp_timer_set_next_event;
++ clkevt->dev.set_state_shutdown = omap2_gp_timer_shutdown;
++ clkevt->dev.set_state_periodic = omap2_gp_timer_set_periodic;
++ clkevt->dev.set_state_oneshot = omap2_gp_timer_shutdown;
++ clkevt->dev.tick_resume = omap2_gp_timer_shutdown;
+
+ /*
+ * For clock-event timers we never read the timer counter and
+ * so we are not impacted by errata i103 and i767. Therefore,
+ * we can safely ignore this errata for clock-event timers.
+ */
+- __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767);
++ __omap_dm_timer_override_errata(timer, OMAP_TIMER_ERRATA_I103_I767);
+
+- res = omap_dm_timer_init_one(&clkev, fck_source, property,
+- &clockevent_gpt.name, OMAP_TIMER_POSTED);
++ res = omap_dm_timer_init_one(timer, fck_source, property,
++ &clkevt->dev.name, OMAP_TIMER_POSTED);
+ BUG_ON(res);
+
+- if (request_irq(clkev.irq, omap2_gp_timer_interrupt,
+- IRQF_TIMER | IRQF_IRQPOLL, "gp_timer", &clkev))
+- pr_err("Failed to request irq %d (gp_timer)\n", clkev.irq);
+-
+- __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+-
+- clockevent_gpt.cpumask = cpu_possible_mask;
+- clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev);
+- clockevents_config_and_register(&clockevent_gpt, clkev.rate,
++ clkevt->dev.cpumask = cpu_possible_mask;
++ clkevt->dev.irq = omap_dm_timer_get_irq(timer);
++
++ if (request_irq(timer->irq, omap2_gp_timer_interrupt,
++ IRQF_TIMER | IRQF_IRQPOLL, "gp_timer", clkevt))
++ pr_err("Failed to request irq %d (gp_timer)\n", timer->irq);
++
++ __omap_dm_timer_int_enable(timer, OMAP_TIMER_INT_OVERFLOW);
++
++ clockevents_config_and_register(&clkevt->dev, timer->rate,
+ 3, /* Timer internal resynch latency */
+ 0xffffffff);
+
+ if (soc_is_am33xx() || soc_is_am43xx()) {
+- clockevent_gpt.suspend = omap_clkevt_idle;
+- clockevent_gpt.resume = omap_clkevt_unidle;
++ clkevt->dev.suspend = omap_clkevt_idle;
++ clkevt->dev.resume = omap_clkevt_unidle;
+
+ clockevent_gpt_hwmod =
+- omap_hwmod_lookup(clockevent_gpt.name);
++ omap_hwmod_lookup(clkevt->dev.name);
+ }
+
+- pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name,
+- clkev.rate);
++ pr_info("OMAP clockevent source: %s at %lu Hz\n", clkevt->dev.name,
++ timer->rate);
+ }
+
+ /* Clocksource code */
--- /dev/null
+From foo@baz Fri Jul 9 03:07:28 PM CEST 2021
+From: Tony Lindgren <tony@atomide.com>
+Date: Fri, 9 Jul 2021 10:37:45 +0300
+Subject: clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
+To: stable@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, Daniel Lezcano <daniel.lezcano@linaro.org>, Keerthy <j-keerthy@ti.com>, Tero Kristo <kristo@kernel.org>
+Message-ID: <20210709073745.13916-4-tony@atomide.com>
+
+From: Tony Lindgren <tony@atomide.com>
+
+commit 25de4ce5ed02994aea8bc111d133308f6fd62566 upstream.
+
+There is a timer wrap issue on dra7 for the ARM architected timer.
+In a typical clock configuration the timer fails to wrap after 388 days.
+
+To work around the issue, we need to use timer-ti-dm percpu timers instead.
+
+Let's configure dmtimer3 and 4 as percpu timers by default, and warn about
+the issue if the dtb is not configured properly.
+
+For more information, please see the errata for "AM572x Sitara Processors
+Silicon Revisions 1.1, 2.0":
+
+https://www.ti.com/lit/er/sprz429m/sprz429m.pdf
+
+The concept is based on earlier reference patches done by Tero Kristo and
+Keerthy.
+
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
+Cc: Keerthy <j-keerthy@ti.com>
+Cc: Tero Kristo <kristo@kernel.org>
+[tony@atomide.com: backported to 4.19.y]
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/boot/dts/dra7.dtsi | 11 +++++++
+ arch/arm/mach-omap2/board-generic.c | 4 +-
+ arch/arm/mach-omap2/timer.c | 53 +++++++++++++++++++++++++++++++++++-
+ drivers/clk/ti/clk-7xx.c | 1
+ include/linux/cpuhotplug.h | 1
+ 5 files changed, 67 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/dra7.dtsi
++++ b/arch/arm/boot/dts/dra7.dtsi
+@@ -48,6 +48,7 @@
+
+ timer {
+ compatible = "arm,armv7-timer";
++ status = "disabled"; /* See ARM architected timer wrap erratum i940 */
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+@@ -910,6 +911,8 @@
+ reg = <0x48032000 0x80>;
+ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "timer2";
++ clock-names = "fck";
++ clocks = <&l4per_clkctrl DRA7_TIMER2_CLKCTRL 24>;
+ };
+
+ timer3: timer@48034000 {
+@@ -917,6 +920,10 @@
+ reg = <0x48034000 0x80>;
+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "timer3";
++ clock-names = "fck";
++ clocks = <&l4per_clkctrl DRA7_TIMER3_CLKCTRL 24>;
++ assigned-clocks = <&l4per_clkctrl DRA7_TIMER3_CLKCTRL 24>;
++ assigned-clock-parents = <&timer_sys_clk_div>;
+ };
+
+ timer4: timer@48036000 {
+@@ -924,6 +931,10 @@
+ reg = <0x48036000 0x80>;
+ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "timer4";
++ clock-names = "fck";
++ clocks = <&l4per_clkctrl DRA7_TIMER4_CLKCTRL 24>;
++ assigned-clocks = <&l4per_clkctrl DRA7_TIMER4_CLKCTRL 24>;
++ assigned-clock-parents = <&timer_sys_clk_div>;
+ };
+
+ timer5: timer@48820000 {
+--- a/arch/arm/mach-omap2/board-generic.c
++++ b/arch/arm/mach-omap2/board-generic.c
+@@ -330,7 +330,7 @@ DT_MACHINE_START(DRA74X_DT, "Generic DRA
+ .init_late = dra7xx_init_late,
+ .init_irq = omap_gic_of_init,
+ .init_machine = omap_generic_init,
+- .init_time = omap5_realtime_timer_init,
++ .init_time = omap3_gptimer_timer_init,
+ .dt_compat = dra74x_boards_compat,
+ .restart = omap44xx_restart,
+ MACHINE_END
+@@ -353,7 +353,7 @@ DT_MACHINE_START(DRA72X_DT, "Generic DRA
+ .init_late = dra7xx_init_late,
+ .init_irq = omap_gic_of_init,
+ .init_machine = omap_generic_init,
+- .init_time = omap5_realtime_timer_init,
++ .init_time = omap3_gptimer_timer_init,
+ .dt_compat = dra72x_boards_compat,
+ .restart = omap44xx_restart,
+ MACHINE_END
+--- a/arch/arm/mach-omap2/timer.c
++++ b/arch/arm/mach-omap2/timer.c
+@@ -42,6 +42,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/platform_data/dmtimer-omap.h>
+ #include <linux/sched_clock.h>
++#include <linux/cpu.h>
+
+ #include <asm/mach/time.h>
+ #include <asm/smp_twd.h>
+@@ -421,6 +422,53 @@ static void __init dmtimer_clkevt_init_c
+ timer->rate);
+ }
+
++static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
++
++static int omap_gptimer_starting_cpu(unsigned int cpu)
++{
++ struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
++ struct clock_event_device *dev = &clkevt->dev;
++ struct omap_dm_timer *timer = &clkevt->timer;
++
++ clockevents_config_and_register(dev, timer->rate, 3, ULONG_MAX);
++ irq_force_affinity(dev->irq, cpumask_of(cpu));
++
++ return 0;
++}
++
++static int __init dmtimer_percpu_quirk_init(void)
++{
++ struct dmtimer_clockevent *clkevt;
++ struct clock_event_device *dev;
++ struct device_node *arm_timer;
++ struct omap_dm_timer *timer;
++ int cpu = 0;
++
++ arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
++ if (of_device_is_available(arm_timer)) {
++ pr_warn_once("ARM architected timer wrap issue i940 detected\n");
++ return 0;
++ }
++
++ for_each_possible_cpu(cpu) {
++ clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
++ dev = &clkevt->dev;
++ timer = &clkevt->timer;
++
++ dmtimer_clkevt_init_common(clkevt, 0, "timer_sys_ck",
++ CLOCK_EVT_FEAT_ONESHOT,
++ cpumask_of(cpu),
++ "assigned-clock-parents",
++ 500, "percpu timer");
++ }
++
++ cpuhp_setup_state(CPUHP_AP_OMAP_DM_TIMER_STARTING,
++ "clockevents/omap/gptimer:starting",
++ omap_gptimer_starting_cpu, NULL);
++
++ return 0;
++}
++
+ /* Clocksource code */
+ static struct omap_dm_timer clksrc;
+ static bool use_gptimer_clksrc __initdata;
+@@ -565,6 +613,9 @@ static void __init __omap_sync32k_timer_
+ 3, /* Timer internal resynch latency */
+ 0xffffffff);
+
++ if (soc_is_dra7xx())
++ dmtimer_percpu_quirk_init();
++
+ /* Enable the use of clocksource="gp_timer" kernel parameter */
+ if (use_gptimer_clksrc || gptimer)
+ omap2_gptimer_clocksource_init(clksrc_nr, clksrc_src,
+@@ -592,7 +643,7 @@ void __init omap3_secure_sync32k_timer_i
+ #endif /* CONFIG_ARCH_OMAP3 */
+
+ #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) || \
+- defined(CONFIG_SOC_AM43XX)
++ defined(CONFIG_SOC_AM43XX) || defined(CONFIG_SOC_DRA7XX)
+ void __init omap3_gptimer_timer_init(void)
+ {
+ __omap_sync32k_timer_init(2, "timer_sys_ck", NULL,
+--- a/drivers/clk/ti/clk-7xx.c
++++ b/drivers/clk/ti/clk-7xx.c
+@@ -733,6 +733,7 @@ const struct omap_clkctrl_data dra7_clkc
+ static struct ti_dt_clk dra7xx_clks[] = {
+ DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
+ DT_CLK(NULL, "sys_clkin_ck", "timer_sys_clk_div"),
++ DT_CLK(NULL, "timer_sys_ck", "timer_sys_clk_div"),
+ DT_CLK(NULL, "sys_clkin", "sys_clkin1"),
+ DT_CLK(NULL, "atl_dpll_clk_mux", "atl_cm:0000:24"),
+ DT_CLK(NULL, "atl_gfclk_mux", "atl_cm:0000:26"),
+--- a/include/linux/cpuhotplug.h
++++ b/include/linux/cpuhotplug.h
+@@ -118,6 +118,7 @@ enum cpuhp_state {
+ CPUHP_AP_ARM_L2X0_STARTING,
+ CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
+ CPUHP_AP_ARM_ARCH_TIMER_STARTING,
++ CPUHP_AP_OMAP_DM_TIMER_STARTING,
+ CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
+ CPUHP_AP_JCORE_TIMER_STARTING,
+ CPUHP_AP_ARM_TWD_STARTING,
--- /dev/null
+From foo@baz Fri Jul 9 03:07:28 PM CEST 2021
+From: Tony Lindgren <tony@atomide.com>
+Date: Fri, 9 Jul 2021 10:37:44 +0300
+Subject: clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue
+To: stable@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, Daniel Lezcano <daniel.lezcano@linaro.org>, Keerthy <j-keerthy@ti.com>, Tero Kristo <kristo@kernel.org>
+Message-ID: <20210709073745.13916-3-tony@atomide.com>
+
+From: Tony Lindgren <tony@atomide.com>
+
+commit 3efe7a878a11c13b5297057bfc1e5639ce1241ce upstream.
+
+There is a timer wrap issue on dra7 for the ARM architected timer.
+In a typical clock configuration the timer fails to wrap after 388 days.
+
+To work around the issue, we need to use timer-ti-dm timers instead.
+
+Let's prepare for adding support for percpu timers by adding a common
+dmtimer_clkevt_init_common() and call it from __omap_sync32k_timer_init().
+This patch makes no intentional functional changes.
+
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
+Cc: Keerthy <j-keerthy@ti.com>
+Cc: Tero Kristo <kristo@kernel.org>
+[tony@atomide.com: backported to 4.19.y]
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/mach-omap2/timer.c | 34 +++++++++++++++++++---------------
+ 1 file changed, 19 insertions(+), 15 deletions(-)
+
+--- a/arch/arm/mach-omap2/timer.c
++++ b/arch/arm/mach-omap2/timer.c
+@@ -368,18 +368,21 @@ void tick_broadcast(const struct cpumask
+ }
+ #endif
+
+-static void __init omap2_gp_clockevent_init(int gptimer_id,
+- const char *fck_source,
+- const char *property)
++static void __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt,
++ int gptimer_id,
++ const char *fck_source,
++ unsigned int features,
++ const struct cpumask *cpumask,
++ const char *property,
++ int rating, const char *name)
+ {
+- struct dmtimer_clockevent *clkevt = &clockevent;
+ struct omap_dm_timer *timer = &clkevt->timer;
+ int res;
+
+ timer->id = gptimer_id;
+ timer->errata = omap_dm_timer_get_errata();
+- clkevt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+- clkevt->dev.rating = 300;
++ clkevt->dev.features = features;
++ clkevt->dev.rating = rating;
+ clkevt->dev.set_next_event = omap2_gp_timer_set_next_event;
+ clkevt->dev.set_state_shutdown = omap2_gp_timer_shutdown;
+ clkevt->dev.set_state_periodic = omap2_gp_timer_set_periodic;
+@@ -397,19 +400,15 @@ static void __init omap2_gp_clockevent_i
+ &clkevt->dev.name, OMAP_TIMER_POSTED);
+ BUG_ON(res);
+
+- clkevt->dev.cpumask = cpu_possible_mask;
++ clkevt->dev.cpumask = cpumask;
+ clkevt->dev.irq = omap_dm_timer_get_irq(timer);
+
+- if (request_irq(timer->irq, omap2_gp_timer_interrupt,
+- IRQF_TIMER | IRQF_IRQPOLL, "gp_timer", clkevt))
+- pr_err("Failed to request irq %d (gp_timer)\n", timer->irq);
++ if (request_irq(clkevt->dev.irq, omap2_gp_timer_interrupt,
++ IRQF_TIMER | IRQF_IRQPOLL, name, clkevt))
++ pr_err("Failed to request irq %d (gp_timer)\n", clkevt->dev.irq);
+
+ __omap_dm_timer_int_enable(timer, OMAP_TIMER_INT_OVERFLOW);
+
+- clockevents_config_and_register(&clkevt->dev, timer->rate,
+- 3, /* Timer internal resynch latency */
+- 0xffffffff);
+-
+ if (soc_is_am33xx() || soc_is_am43xx()) {
+ clkevt->dev.suspend = omap_clkevt_idle;
+ clkevt->dev.resume = omap_clkevt_unidle;
+@@ -559,7 +558,12 @@ static void __init __omap_sync32k_timer_
+ {
+ omap_clk_init();
+ omap_dmtimer_init();
+- omap2_gp_clockevent_init(clkev_nr, clkev_src, clkev_prop);
++ dmtimer_clkevt_init_common(&clockevent, clkev_nr, clkev_src,
++ CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
++ cpu_possible_mask, clkev_prop, 300, "clockevent");
++ clockevents_config_and_register(&clockevent.dev, clockevent.timer.rate,
++ 3, /* Timer internal resynch latency */
++ 0xffffffff);
+
+ /* Enable the use of clocksource="gp_timer" kernel parameter */
+ if (use_gptimer_clksrc || gptimer)
kthread-prevent-deadlock-when-kthread_mod_delayed_work-races-with-kthread_cancel_delayed_work_sync.patch
xen-events-reset-active-flag-for-lateeoi-events-later.patch
kvm-svm-call-sev-guest-decommission-if-asid-binding-fails.patch
+arm-omap-replace-setup_irq-by-request_irq.patch
+clocksource-drivers-timer-ti-dm-add-clockevent-and-clocksource-support.patch
+clocksource-drivers-timer-ti-dm-prepare-to-handle-dra7-timer-wrap-issue.patch
+clocksource-drivers-timer-ti-dm-handle-dra7-timer-wrap-errata-i940.patch