From patchwork Wed Jun 2 10:46:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 453190 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28969C47083 for ; Wed, 2 Jun 2021 10:46:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 09021613B4 for ; Wed, 2 Jun 2021 10:46:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231441AbhFBKsj (ORCPT ); Wed, 2 Jun 2021 06:48:39 -0400 Received: from muru.com ([72.249.23.125]:35402 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229541AbhFBKsV (ORCPT ); Wed, 2 Jun 2021 06:48:21 -0400 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id 74C6D8027; Wed, 2 Jun 2021 10:46:42 +0000 (UTC) From: Tony Lindgren To: stable@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, afzal mohammed , Daniel Lezcano , Keerthy , Tero Kristo Subject: [Backport for linux-5.4.y PATCH 1/4] ARM: OMAP: replace setup_irq() by request_irq() Date: Wed, 2 Jun 2021 13:46:22 +0300 Message-Id: <20210602104625.6079-1-tony@atomide.com> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: afzal mohammed Upstream commit b75ca5217743e4d7076cf65e044e88389e44318d backported for stable linux-5.4.y to make it easier to apply dra7 timer errata patches. 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 Cc: Keerthy Cc: Tero Kristo Signed-off-by: afzal mohammed Signed-off-by: Tony Lindgren --- 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(-) diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -596,11 +596,6 @@ static irqreturn_t omap_wakeup_interrupt(int irq, void *dev) 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 = { @@ -613,6 +608,7 @@ static const struct platform_suspend_ops omap_pm_ops = { static int __init omap_pm_init(void) { int error = 0; + int irq; if (!cpu_class_is_omap1()) return -ENODEV; @@ -656,9 +652,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) diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -155,15 +155,11 @@ static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id) 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); diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c --- a/arch/arm/mach-omap1/timer32k.c +++ b/arch/arm/mach-omap1/timer32k.c @@ -148,15 +148,11 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id) 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, diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -91,12 +91,6 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) 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) { @@ -382,8 +376,9 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, &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); From patchwork Wed Jun 2 10:46:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 453987 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CE841C47092 for ; Wed, 2 Jun 2021 10:47:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B8008613D0 for ; Wed, 2 Jun 2021 10:47:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231530AbhFBKsm (ORCPT ); Wed, 2 Jun 2021 06:48:42 -0400 Received: from muru.com ([72.249.23.125]:35412 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230124AbhFBKsY (ORCPT ); Wed, 2 Jun 2021 06:48:24 -0400 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id 1F0168119; Wed, 2 Jun 2021 10:46:47 +0000 (UTC) From: Tony Lindgren To: stable@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, Daniel Lezcano , Keerthy , Tero Kristo Subject: [Backport for linux-5.4.y PATCH 2/4] ARM: OMAP2+: Prepare timer code to backport dra7 timer wrap errata i940 Date: Wed, 2 Jun 2021 13:46:23 +0300 Message-Id: <20210602104625.6079-2-tony@atomide.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210602104625.6079-1-tony@atomide.com> References: <20210602104625.6079-1-tony@atomide.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org Prepare linux-5.4.y to backport upstream timer wrap errata commit 3efe7a878a11c13b5297057bfc1e5639ce1241ce and commit 25de4ce5ed02994aea8bc111d133308f6fd62566. Earlier kernels still use mach-omap2/timer instead of drivers/clocksource as these kernels still depend on legacy platform code for timers. Note that earlier stable kernels need also additional patches and will be posted separately. We need to prepare the timer code to allow using multiple timer instances to handle the dra7 timer wrap errata. We do this by adding struct dmtimer_clockevent that we initialize dynamically, and update the timer functions to use it. Cc: Daniel Lezcano Cc: Keerthy Cc: Tero Kristo Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/timer.c | 105 +++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -63,15 +63,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; @@ -83,10 +96,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; } @@ -94,7 +108,9 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) 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; @@ -102,22 +118,26 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles, 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; @@ -131,26 +151,17 @@ static void omap_clkevt_idle(struct clock_event_device *unused) 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", }, @@ -360,44 +371,54 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, 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); + 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(&clkev, OMAP_TIMER_INT_OVERFLOW); + __omap_dm_timer_int_enable(timer, 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, + 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 */ From patchwork Wed Jun 2 10:46:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 453189 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0E7E8C47083 for ; Wed, 2 Jun 2021 10:47:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EB696613D6 for ; Wed, 2 Jun 2021 10:47:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231589AbhFBKsu (ORCPT ); Wed, 2 Jun 2021 06:48:50 -0400 Received: from muru.com ([72.249.23.125]:35424 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230284AbhFBKs3 (ORCPT ); Wed, 2 Jun 2021 06:48:29 -0400 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id 7F6038131; Wed, 2 Jun 2021 10:46:52 +0000 (UTC) From: Tony Lindgren To: stable@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, Daniel Lezcano , Keerthy , Tero Kristo Subject: [Backport for linux-5.4.y PATCH 3/4] ARM: OMAP2+: Prepare to handle dra7 timer wrap issue Date: Wed, 2 Jun 2021 13:46:24 +0300 Message-Id: <20210602104625.6079-3-tony@atomide.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210602104625.6079-1-tony@atomide.com> References: <20210602104625.6079-1-tony@atomide.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org Upstream commit 3efe7a878a11c13b5297057bfc1e5639ce1241ce backported to stable linux-5.4.y mach-omap2/timer instead of drivers/clocksource as linux-5.4.y still depends on legacy platform code for timers. Note that earlier stable kernels need also additional patches and will be posted separately. 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 Cc: Keerthy Cc: Tero Kristo Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/timer.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -367,18 +367,21 @@ void tick_broadcast(const struct cpumask *mask) } #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; @@ -396,19 +399,15 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, &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; @@ -558,7 +557,12 @@ static void __init __omap_sync32k_timer_init(int clkev_nr, const char *clkev_src { 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) From patchwork Wed Jun 2 10:46:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 453986 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E3061C4708F for ; Wed, 2 Jun 2021 10:47:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C20F2613AE for ; Wed, 2 Jun 2021 10:47:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231696AbhFBKsx (ORCPT ); Wed, 2 Jun 2021 06:48:53 -0400 Received: from muru.com ([72.249.23.125]:35432 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229695AbhFBKsd (ORCPT ); Wed, 2 Jun 2021 06:48:33 -0400 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id 5A6F68150; Wed, 2 Jun 2021 10:46:56 +0000 (UTC) From: Tony Lindgren To: stable@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, Daniel Lezcano , Keerthy , Tero Kristo Subject: [Backport for linux-5.4.y PATCH 4/4] ARM: OMAP2+: Handle dra7 timer wrap errata i940 Date: Wed, 2 Jun 2021 13:46:25 +0300 Message-Id: <20210602104625.6079-4-tony@atomide.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210602104625.6079-1-tony@atomide.com> References: <20210602104625.6079-1-tony@atomide.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org Upstream commit 25de4ce5ed02994aea8bc111d133308f6fd62566 backported to stable linux-5.4.y mach-omap2/timer instead of drivers/clocksource as earlier kernels still depend on legacy platform code for timers. Note that earlier stable kernels need also additional patches and will be posted separately. 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 Cc: Keerthy Cc: Tero Kristo Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/dra7-l4.dtsi | 4 +-- arch/arm/boot/dts/dra7.dtsi | 20 +++++++++++ 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 + 6 files changed, 78 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi --- a/arch/arm/boot/dts/dra7-l4.dtsi +++ b/arch/arm/boot/dts/dra7-l4.dtsi @@ -1176,7 +1176,7 @@ }; }; - target-module@34000 { /* 0x48034000, ap 7 46.0 */ + timer3_target: target-module@34000 { /* 0x48034000, ap 7 46.0 */ compatible = "ti,sysc-omap4-timer", "ti,sysc"; ti,hwmods = "timer3"; reg = <0x34000 0x4>, @@ -1204,7 +1204,7 @@ }; }; - target-module@36000 { /* 0x48036000, ap 9 4e.0 */ + timer4_target: target-module@36000 { /* 0x48036000, ap 9 4e.0 */ compatible = "ti,sysc-omap4-timer", "ti,sysc"; ti,hwmods = "timer4"; reg = <0x36000 0x4>, diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -46,6 +46,7 @@ timer { compatible = "arm,armv7-timer"; + status = "disabled"; /* See ARM architected timer wrap erratum i940 */ interrupts = , , , @@ -766,3 +767,22 @@ #include "dra7-l4.dtsi" #include "dra7xx-clocks.dtsi" + +/* Local timers, see ARM architected timer wrap erratum i940 */ +&timer3_target { + ti,no-reset-on-init; + ti,no-idle; + timer@0 { + assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>; + assigned-clock-parents = <&timer_sys_clk_div>; + }; +}; + +&timer4_target { + ti,no-reset-on-init; + ti,no-idle; + timer@0 { + assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>; + assigned-clock-parents = <&timer_sys_clk_div>; + }; +}; diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -327,7 +327,7 @@ DT_MACHINE_START(DRA74X_DT, "Generic DRA74X (Flattened Device Tree)") .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 @@ -350,7 +350,7 @@ DT_MACHINE_START(DRA72X_DT, "Generic DRA72X (Flattened Device Tree)") .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 diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -420,6 +421,53 @@ static void __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt, 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; @@ -564,6 +612,9 @@ static void __init __omap_sync32k_timer_init(int clkev_nr, const char *clkev_src 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, @@ -591,7 +642,7 @@ void __init omap3_secure_sync32k_timer_init(void) #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, diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -793,6 +793,7 @@ 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, "sys_clkin", "sys_clkin1"), + DT_CLK(NULL, "timer_sys_ck", "timer_sys_clk_div"), DT_CLK(NULL, "atl_dpll_clk_mux", "atl-clkctrl:0000:24"), DT_CLK(NULL, "atl_gfclk_mux", "atl-clkctrl:0000:26"), DT_CLK(NULL, "dcan1_sys_clk_mux", "wkupaon-clkctrl:0068:24"), diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -119,6 +119,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,