mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'timers-v5.20-rc1' of https://git.linaro.org/people/daniel.lezcano/linux into timers/core
Pull clockevent/source updates from Daniel Lezcano:
- Add the missing DT bindings for the MTU nomadik timer (Linus
Walleij)
- Fix grammar typo in the ARM global timer Kconfig option (Randy
Dunlap)
- Add the tegra186 timer and use it on the tegra234 board (Thierry
Reding)
- Add the 'CPUXGPT' CPU timer for Mediatek MT6795 and implement a
workaround to overcome an ATF bug where the timer is not correctly
initialized (AngeloGioacchino Del Regno)
- Rework the suspend/resume approach to enable the feature on the
timer even it is not an active clock and fix a compilation warning
(Claudiu Beznea)
- Add the Add R-Car Gen4 timer support along with the DT bindings
(Wolfram Sang)
- Add compatible for ti,am654-timer to support AM6 SoC (Tony Lindgren)
- Fix Kconfig option to put it back to 'bool' instead of 'tristate'
for the tegra186 (Daniel Lezcano)
- Sort 'family,type' DT bindings for the Renesas timers (Geert
Uytterhoeven)
- Add compatible 'allwinner,sun20i-d1-timer' for Allwinner D1 (Samuel
Holland)
- Remove unnecessary (void*) conversions for sun4i (XU pengfei)
- Remove unnecessary (void*) conversions for sun5i (Li zeming)
Link: https://lore.kernel.org/all/7472984e-f502-5f27-82bf-070127dd85a5@linaro.org
This commit is contained in:
@@ -20,6 +20,7 @@ properties:
|
||||
- allwinner,suniv-f1c100s-timer
|
||||
- items:
|
||||
- enum:
|
||||
- allwinner,sun20i-d1-timer
|
||||
- allwinner,sun50i-a64-timer
|
||||
- allwinner,sun50i-h6-timer
|
||||
- allwinner,sun50i-h616-timer
|
||||
|
||||
@@ -113,7 +113,7 @@ properties:
|
||||
patternProperties:
|
||||
"^watchdog@[a-f0-9]+$":
|
||||
type: object
|
||||
$ref: ../watchdog/watchdog.yaml#
|
||||
$ref: /schemas/watchdog/watchdog.yaml#
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
@@ -145,7 +145,7 @@ patternProperties:
|
||||
|
||||
"^pwm@[a-f0-9]+$":
|
||||
type: object
|
||||
$ref: ../pwm/pwm.yaml#
|
||||
$ref: /schemas/pwm/pwm.yaml#
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
MediaTek Timers
|
||||
---------------
|
||||
|
||||
MediaTek SoCs have two different timers on different platforms,
|
||||
MediaTek SoCs have different timers on different platforms,
|
||||
- CPUX (ARM/ARM64 System Timer)
|
||||
- GPT (General Purpose Timer)
|
||||
- SYST (System Timer)
|
||||
|
||||
@@ -29,6 +30,9 @@ Required properties:
|
||||
* "mediatek,mt7629-timer" for MT7629 compatible timers (SYST)
|
||||
* "mediatek,mt6765-timer" for MT6765 and all above compatible timers (SYST)
|
||||
|
||||
For those SoCs that use CPUX
|
||||
* "mediatek,mt6795-systimer" for MT6795 compatible timers (CPUX)
|
||||
|
||||
- reg: Should contain location and length for timer register.
|
||||
- clocks: Should contain system clock.
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ properties:
|
||||
- renesas,r8a77980-cmt0 # 32-bit CMT0 on R-Car V3H
|
||||
- renesas,r8a77990-cmt0 # 32-bit CMT0 on R-Car E3
|
||||
- renesas,r8a77995-cmt0 # 32-bit CMT0 on R-Car D3
|
||||
- renesas,r8a779a0-cmt0 # 32-bit CMT0 on R-Car V3U
|
||||
- const: renesas,rcar-gen3-cmt0 # 32-bit CMT0 on R-Car Gen3 and RZ/G2
|
||||
|
||||
- items:
|
||||
@@ -97,9 +96,20 @@ properties:
|
||||
- renesas,r8a77980-cmt1 # 48-bit CMT on R-Car V3H
|
||||
- renesas,r8a77990-cmt1 # 48-bit CMT on R-Car E3
|
||||
- renesas,r8a77995-cmt1 # 48-bit CMT on R-Car D3
|
||||
- renesas,r8a779a0-cmt1 # 48-bit CMT on R-Car V3U
|
||||
- const: renesas,rcar-gen3-cmt1 # 48-bit CMT on R-Car Gen3 and RZ/G2
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r8a779a0-cmt0 # 32-bit CMT0 on R-Car V3U
|
||||
- renesas,r8a779f0-cmt0 # 32-bit CMT0 on R-Car S4-8
|
||||
- const: renesas,rcar-gen4-cmt0 # 32-bit CMT0 on R-Car Gen4
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r8a779a0-cmt1 # 48-bit CMT on R-Car V3U
|
||||
- renesas,r8a779f0-cmt1 # 48-bit CMT on R-Car S4-8
|
||||
- const: renesas,rcar-gen4-cmt1 # 48-bit CMT on R-Car Gen4
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -135,6 +145,7 @@ allOf:
|
||||
enum:
|
||||
- renesas,rcar-gen2-cmt0
|
||||
- renesas,rcar-gen3-cmt0
|
||||
- renesas,rcar-gen4-cmt0
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
@@ -148,6 +159,7 @@ allOf:
|
||||
enum:
|
||||
- renesas,rcar-gen2-cmt1
|
||||
- renesas,rcar-gen3-cmt1
|
||||
- renesas,rcar-gen4-cmt1
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2022 Linaro Ltd.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/timer/st,nomadik-mtu.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: ST Microelectronics Nomadik Multi-Timer Unit MTU Timer
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
description: This timer is found in the ST Microelectronics Nomadik
|
||||
SoCs STn8800, STn8810 and STn8815 as well as in ST-Ericsson DB8500.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: st,nomadik-mtu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: The first clock named TIMCLK clocks the actual timers and
|
||||
the second clock clocks the digital interface to the interconnect.
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: timclk
|
||||
- const: apb_pclk
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/mfd/dbx500-prcmu.h>
|
||||
timer@a03c6000 {
|
||||
compatible = "st,nomadik-mtu";
|
||||
reg = <0xa03c6000 0x1000>;
|
||||
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
clocks = <&prcmu_clk PRCMU_TIMCLK>, <&prcc_pclk 6 6>;
|
||||
clock-names = "timclk", "apb_pclk";
|
||||
};
|
||||
@@ -105,6 +105,7 @@ config ARCH_OMAP2PLUS
|
||||
select MACH_OMAP_GENERIC
|
||||
select MEMORY
|
||||
select MFD_SYSCON
|
||||
select OMAP_DM_SYSTIMER
|
||||
select OMAP_DM_TIMER
|
||||
select OMAP_GPMC
|
||||
select PINCTRL
|
||||
@@ -209,6 +210,7 @@ config SOC_OMAP2420
|
||||
bool "OMAP2420 support"
|
||||
depends on ARCH_OMAP2
|
||||
default y
|
||||
select OMAP_DM_SYSTIMER
|
||||
select OMAP_DM_TIMER
|
||||
select SOC_HAS_OMAP2_SDRC
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ config CLKEVT_I8253
|
||||
config I8253_LOCK
|
||||
bool
|
||||
|
||||
config OMAP_DM_TIMER
|
||||
config OMAP_DM_SYSTIMER
|
||||
bool
|
||||
select TIMER_OF
|
||||
|
||||
@@ -56,6 +56,13 @@ config DIGICOLOR_TIMER
|
||||
help
|
||||
Enables the support for the digicolor timer driver.
|
||||
|
||||
config OMAP_DM_TIMER
|
||||
bool "OMAP dual-mode timer driver" if ARCH_K3 || COMPILE_TEST
|
||||
default y if ARCH_K3
|
||||
select TIMER_OF
|
||||
help
|
||||
Enables the support for the TI dual-mode timer driver.
|
||||
|
||||
config DW_APB_TIMER
|
||||
bool "DW APB timer driver" if COMPILE_TEST
|
||||
help
|
||||
@@ -150,6 +157,14 @@ config TEGRA_TIMER
|
||||
help
|
||||
Enables support for the Tegra driver.
|
||||
|
||||
config TEGRA186_TIMER
|
||||
bool "NVIDIA Tegra186 timer driver"
|
||||
depends on ARCH_TEGRA || COMPILE_TEST
|
||||
depends on WATCHDOG && WATCHDOG_CORE
|
||||
help
|
||||
Enables support for the timers and watchdogs found on NVIDIA
|
||||
Tegra186 and later SoCs.
|
||||
|
||||
config VT8500_TIMER
|
||||
bool "VT8500 timer driver" if COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
@@ -367,7 +382,7 @@ config ARM_GT_INITIAL_PRESCALER_VAL
|
||||
depends on ARM_GLOBAL_TIMER
|
||||
help
|
||||
When the ARM global timer initializes, its current rate is declared
|
||||
to the kernel and maintained forever. Should it's parent clock
|
||||
to the kernel and maintained forever. Should its parent clock
|
||||
change, the driver tries to fix the timer's internal prescaler.
|
||||
On some machs (i.e. Zynq) the initial prescaler value thus poses
|
||||
bounds about how much the parent clock is allowed to decrease or
|
||||
|
||||
@@ -18,7 +18,7 @@ obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
|
||||
obj-$(CONFIG_DAVINCI_TIMER) += timer-davinci.o
|
||||
obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o
|
||||
obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm.o
|
||||
obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm-systimer.o
|
||||
obj-$(CONFIG_OMAP_DM_SYSTIMER) += timer-ti-dm-systimer.o
|
||||
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
|
||||
obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
|
||||
obj-$(CONFIG_FTTMR010_TIMER) += timer-fttmr010.o
|
||||
@@ -36,6 +36,7 @@ obj-$(CONFIG_SUN4I_TIMER) += timer-sun4i.o
|
||||
obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o
|
||||
obj-$(CONFIG_MESON6_TIMER) += timer-meson6.o
|
||||
obj-$(CONFIG_TEGRA_TIMER) += timer-tegra.o
|
||||
obj-$(CONFIG_TEGRA186_TIMER) += timer-tegra186.o
|
||||
obj-$(CONFIG_VT8500_TIMER) += timer-vt8500.o
|
||||
obj-$(CONFIG_NSPIRE_TIMER) += timer-zevio.o
|
||||
obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o
|
||||
|
||||
@@ -981,6 +981,14 @@ static const struct of_device_id sh_cmt_of_table[] __maybe_unused = {
|
||||
.compatible = "renesas,rcar-gen3-cmt1",
|
||||
.data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rcar-gen4-cmt0",
|
||||
.data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rcar-gen4-cmt1",
|
||||
.data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sh_cmt_of_table);
|
||||
|
||||
@@ -22,6 +22,19 @@
|
||||
|
||||
#define TIMER_SYNC_TICKS (3)
|
||||
|
||||
/* cpux mcusys wrapper */
|
||||
#define CPUX_CON_REG 0x0
|
||||
#define CPUX_IDX_REG 0x4
|
||||
|
||||
/* cpux */
|
||||
#define CPUX_IDX_GLOBAL_CTRL 0x0
|
||||
#define CPUX_ENABLE BIT(0)
|
||||
#define CPUX_CLK_DIV_MASK GENMASK(10, 8)
|
||||
#define CPUX_CLK_DIV1 BIT(8)
|
||||
#define CPUX_CLK_DIV2 BIT(9)
|
||||
#define CPUX_CLK_DIV4 BIT(10)
|
||||
#define CPUX_IDX_GLOBAL_IRQ 0x30
|
||||
|
||||
/* gpt */
|
||||
#define GPT_IRQ_EN_REG 0x00
|
||||
#define GPT_IRQ_ENABLE(val) BIT((val) - 1)
|
||||
@@ -72,6 +85,52 @@
|
||||
|
||||
static void __iomem *gpt_sched_reg __read_mostly;
|
||||
|
||||
static u32 mtk_cpux_readl(u32 reg_idx, struct timer_of *to)
|
||||
{
|
||||
writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG);
|
||||
return readl(timer_of_base(to) + CPUX_CON_REG);
|
||||
}
|
||||
|
||||
static void mtk_cpux_writel(u32 val, u32 reg_idx, struct timer_of *to)
|
||||
{
|
||||
writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG);
|
||||
writel(val, timer_of_base(to) + CPUX_CON_REG);
|
||||
}
|
||||
|
||||
static void mtk_cpux_set_irq(struct timer_of *to, bool enable)
|
||||
{
|
||||
const unsigned long *irq_mask = cpumask_bits(cpu_possible_mask);
|
||||
u32 val;
|
||||
|
||||
val = mtk_cpux_readl(CPUX_IDX_GLOBAL_IRQ, to);
|
||||
|
||||
if (enable)
|
||||
val |= *irq_mask;
|
||||
else
|
||||
val &= ~(*irq_mask);
|
||||
|
||||
mtk_cpux_writel(val, CPUX_IDX_GLOBAL_IRQ, to);
|
||||
}
|
||||
|
||||
static int mtk_cpux_clkevt_shutdown(struct clock_event_device *clkevt)
|
||||
{
|
||||
/* Clear any irq */
|
||||
mtk_cpux_set_irq(to_timer_of(clkevt), false);
|
||||
|
||||
/*
|
||||
* Disabling CPUXGPT timer will crash the platform, especially
|
||||
* if Trusted Firmware is using it (usually, for sleep states),
|
||||
* so we only mask the IRQ and call it a day.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_cpux_clkevt_resume(struct clock_event_device *clkevt)
|
||||
{
|
||||
mtk_cpux_set_irq(to_timer_of(clkevt), true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_syst_ack_irq(struct timer_of *to)
|
||||
{
|
||||
/* Clear and disable interrupt */
|
||||
@@ -281,6 +340,60 @@ static struct timer_of to = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mtk_cpux_init(struct device_node *node)
|
||||
{
|
||||
static struct timer_of to_cpux;
|
||||
u32 freq, val;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* There are per-cpu interrupts for the CPUX General Purpose Timer
|
||||
* but since this timer feeds the AArch64 System Timer we can rely
|
||||
* on the CPU timer PPIs as well, so we don't declare TIMER_OF_IRQ.
|
||||
*/
|
||||
to_cpux.flags = TIMER_OF_BASE | TIMER_OF_CLOCK;
|
||||
to_cpux.clkevt.name = "mtk-cpuxgpt";
|
||||
to_cpux.clkevt.rating = 10;
|
||||
to_cpux.clkevt.cpumask = cpu_possible_mask;
|
||||
to_cpux.clkevt.set_state_shutdown = mtk_cpux_clkevt_shutdown;
|
||||
to_cpux.clkevt.tick_resume = mtk_cpux_clkevt_resume;
|
||||
|
||||
/* If this fails, bad things are about to happen... */
|
||||
ret = timer_of_init(node, &to_cpux);
|
||||
if (ret) {
|
||||
WARN(1, "Cannot start CPUX timers.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we're given a clock with the right frequency for this
|
||||
* timer, otherwise warn but keep going with the setup anyway, as
|
||||
* that makes it possible to still boot the kernel, even though
|
||||
* it may not work correctly (random lockups, etc).
|
||||
* The reason behind this is that having an early UART may not be
|
||||
* possible for everyone and this gives a chance to retrieve kmsg
|
||||
* for eventual debugging even on consumer devices.
|
||||
*/
|
||||
freq = timer_of_rate(&to_cpux);
|
||||
if (freq > 13000000)
|
||||
WARN(1, "Requested unsupported timer frequency %u\n", freq);
|
||||
|
||||
/* Clock input is 26MHz, set DIV2 to achieve 13MHz clock */
|
||||
val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to_cpux);
|
||||
val &= ~CPUX_CLK_DIV_MASK;
|
||||
val |= CPUX_CLK_DIV2;
|
||||
mtk_cpux_writel(val, CPUX_IDX_GLOBAL_CTRL, &to_cpux);
|
||||
|
||||
/* Enable all CPUXGPT timers */
|
||||
val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to_cpux);
|
||||
mtk_cpux_writel(val | CPUX_ENABLE, CPUX_IDX_GLOBAL_CTRL, &to_cpux);
|
||||
|
||||
clockevents_config_and_register(&to_cpux.clkevt, timer_of_rate(&to_cpux),
|
||||
TIMER_SYNC_TICKS, 0xffffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init mtk_syst_init(struct device_node *node)
|
||||
{
|
||||
int ret;
|
||||
@@ -339,3 +452,4 @@ static int __init mtk_gpt_init(struct device_node *node)
|
||||
}
|
||||
TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_gpt_init);
|
||||
TIMER_OF_DECLARE(mtk_mt6765, "mediatek,mt6765-timer", mtk_syst_init);
|
||||
TIMER_OF_DECLARE(mtk_mt6795, "mediatek,mt6795-systimer", mtk_cpux_init);
|
||||
|
||||
@@ -61,7 +61,7 @@ struct mchp_pit64b_timer {
|
||||
};
|
||||
|
||||
/**
|
||||
* mchp_pit64b_clkevt - PIT64B clockevent data structure
|
||||
* struct mchp_pit64b_clkevt - PIT64B clockevent data structure
|
||||
* @timer: PIT64B timer
|
||||
* @clkevt: clockevent
|
||||
*/
|
||||
@@ -75,7 +75,7 @@ struct mchp_pit64b_clkevt {
|
||||
struct mchp_pit64b_clkevt, clkevt))
|
||||
|
||||
/**
|
||||
* mchp_pit64b_clksrc - PIT64B clocksource data structure
|
||||
* struct mchp_pit64b_clksrc - PIT64B clocksource data structure
|
||||
* @timer: PIT64B timer
|
||||
* @clksrc: clocksource
|
||||
*/
|
||||
@@ -173,7 +173,8 @@ static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev)
|
||||
{
|
||||
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
|
||||
|
||||
writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
|
||||
if (!clockevent_state_detached(cedev))
|
||||
mchp_pit64b_suspend(timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -182,12 +183,28 @@ static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev)
|
||||
{
|
||||
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
|
||||
|
||||
if (clockevent_state_shutdown(cedev))
|
||||
mchp_pit64b_resume(timer);
|
||||
|
||||
mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_CONT,
|
||||
MCHP_PIT64B_IER_PERIOD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mchp_pit64b_clkevt_set_oneshot(struct clock_event_device *cedev)
|
||||
{
|
||||
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
|
||||
|
||||
if (clockevent_state_shutdown(cedev))
|
||||
mchp_pit64b_resume(timer);
|
||||
|
||||
mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_ONE_SHOT,
|
||||
MCHP_PIT64B_IER_PERIOD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
|
||||
struct clock_event_device *cedev)
|
||||
{
|
||||
@@ -199,20 +216,6 @@ static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev)
|
||||
{
|
||||
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
|
||||
|
||||
mchp_pit64b_suspend(timer);
|
||||
}
|
||||
|
||||
static void mchp_pit64b_clkevt_resume(struct clock_event_device *cedev)
|
||||
{
|
||||
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
|
||||
|
||||
mchp_pit64b_resume(timer);
|
||||
}
|
||||
|
||||
static irqreturn_t mchp_pit64b_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct mchp_pit64b_clkevt *irq_data = dev_id;
|
||||
@@ -242,8 +245,10 @@ static void __init mchp_pit64b_pres_compute(u32 *pres, u32 clk_rate,
|
||||
}
|
||||
|
||||
/**
|
||||
* mchp_pit64b_init_mode - prepare PIT64B mode register value to be used at
|
||||
* runtime; this includes prescaler and SGCLK bit
|
||||
* mchp_pit64b_init_mode() - prepare PIT64B mode register value to be used at
|
||||
* runtime; this includes prescaler and SGCLK bit
|
||||
* @timer: pointer to pit64b timer to init
|
||||
* @max_rate: maximum rate that timer's clock could use
|
||||
*
|
||||
* PIT64B timer may be fed by gclk or pclk. When gclk is used its rate has to
|
||||
* be at least 3 times lower that pclk's rate. pclk rate is fixed, gclk rate
|
||||
@@ -341,6 +346,7 @@ static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer,
|
||||
if (!cs)
|
||||
return -ENOMEM;
|
||||
|
||||
mchp_pit64b_resume(timer);
|
||||
mchp_pit64b_reset(timer, ULLONG_MAX, MCHP_PIT64B_MR_CONT, 0);
|
||||
|
||||
mchp_pit64b_cs_base = timer->base;
|
||||
@@ -362,8 +368,7 @@ static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer,
|
||||
pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
|
||||
|
||||
/* Stop timer. */
|
||||
writel_relaxed(MCHP_PIT64B_CR_SWRST,
|
||||
timer->base + MCHP_PIT64B_CR);
|
||||
mchp_pit64b_suspend(timer);
|
||||
kfree(cs);
|
||||
|
||||
return ret;
|
||||
@@ -395,9 +400,8 @@ static int __init mchp_pit64b_init_clkevt(struct mchp_pit64b_timer *timer,
|
||||
ce->clkevt.rating = 150;
|
||||
ce->clkevt.set_state_shutdown = mchp_pit64b_clkevt_shutdown;
|
||||
ce->clkevt.set_state_periodic = mchp_pit64b_clkevt_set_periodic;
|
||||
ce->clkevt.set_state_oneshot = mchp_pit64b_clkevt_set_oneshot;
|
||||
ce->clkevt.set_next_event = mchp_pit64b_clkevt_set_next_event;
|
||||
ce->clkevt.suspend = mchp_pit64b_clkevt_suspend;
|
||||
ce->clkevt.resume = mchp_pit64b_clkevt_resume;
|
||||
ce->clkevt.cpumask = cpumask_of(0);
|
||||
ce->clkevt.irq = irq;
|
||||
|
||||
@@ -448,19 +452,10 @@ static int __init mchp_pit64b_dt_init_timer(struct device_node *node,
|
||||
if (ret)
|
||||
goto irq_unmap;
|
||||
|
||||
ret = clk_prepare_enable(timer.pclk);
|
||||
if (ret)
|
||||
goto irq_unmap;
|
||||
|
||||
if (timer.mode & MCHP_PIT64B_MR_SGCLK) {
|
||||
ret = clk_prepare_enable(timer.gclk);
|
||||
if (ret)
|
||||
goto pclk_unprepare;
|
||||
|
||||
if (timer.mode & MCHP_PIT64B_MR_SGCLK)
|
||||
clk_rate = clk_get_rate(timer.gclk);
|
||||
} else {
|
||||
else
|
||||
clk_rate = clk_get_rate(timer.pclk);
|
||||
}
|
||||
clk_rate = clk_rate / (MCHP_PIT64B_MODE_TO_PRES(timer.mode) + 1);
|
||||
|
||||
if (clkevt)
|
||||
@@ -469,15 +464,10 @@ static int __init mchp_pit64b_dt_init_timer(struct device_node *node,
|
||||
ret = mchp_pit64b_init_clksrc(&timer, clk_rate);
|
||||
|
||||
if (ret)
|
||||
goto gclk_unprepare;
|
||||
goto irq_unmap;
|
||||
|
||||
return 0;
|
||||
|
||||
gclk_unprepare:
|
||||
if (timer.mode & MCHP_PIT64B_MR_SGCLK)
|
||||
clk_disable_unprepare(timer.gclk);
|
||||
pclk_unprepare:
|
||||
clk_disable_unprepare(timer.pclk);
|
||||
irq_unmap:
|
||||
irq_dispose_mapping(irq);
|
||||
io_unmap:
|
||||
|
||||
@@ -128,7 +128,7 @@ static void sun4i_timer_clear_interrupt(void __iomem *base)
|
||||
|
||||
static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = (struct clock_event_device *)dev_id;
|
||||
struct clock_event_device *evt = dev_id;
|
||||
struct timer_of *to = to_timer_of(evt);
|
||||
|
||||
sun4i_timer_clear_interrupt(timer_of_base(to));
|
||||
|
||||
@@ -142,7 +142,7 @@ static int sun5i_clkevt_next_event(unsigned long evt,
|
||||
|
||||
static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct sun5i_timer_clkevt *ce = (struct sun5i_timer_clkevt *)dev_id;
|
||||
struct sun5i_timer_clkevt *ce = dev_id;
|
||||
|
||||
writel(0x1, ce->timer.base + TIMER_IRQ_ST_REG);
|
||||
ce->clkevt.event_handler(&ce->clkevt);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,121 @@ enum {
|
||||
REQUEST_BY_NODE,
|
||||
};
|
||||
|
||||
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
|
||||
int posted)
|
||||
{
|
||||
if (posted)
|
||||
while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
|
||||
cpu_relax();
|
||||
|
||||
return readl_relaxed(timer->func_base + (reg & 0xff));
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
|
||||
u32 reg, u32 val, int posted)
|
||||
{
|
||||
if (posted)
|
||||
while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
|
||||
cpu_relax();
|
||||
|
||||
writel_relaxed(val, timer->func_base + (reg & 0xff));
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
|
||||
{
|
||||
u32 tidr;
|
||||
|
||||
/* Assume v1 ip if bits [31:16] are zero */
|
||||
tidr = readl_relaxed(timer->io_base);
|
||||
if (!(tidr >> 16)) {
|
||||
timer->revision = 1;
|
||||
timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
|
||||
timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
|
||||
timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
|
||||
timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
|
||||
timer->func_base = timer->io_base;
|
||||
} else {
|
||||
timer->revision = 2;
|
||||
timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
|
||||
timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
|
||||
timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
|
||||
timer->pend = timer->io_base +
|
||||
_OMAP_TIMER_WRITE_PEND_OFFSET +
|
||||
OMAP_TIMER_V2_FUNC_OFFSET;
|
||||
timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* __omap_dm_timer_enable_posted - enables write posted mode
|
||||
* @timer: pointer to timer instance handle
|
||||
*
|
||||
* Enables the write posted mode for the timer. When posted mode is enabled
|
||||
* writes to certain timer registers are immediately acknowledged by the
|
||||
* internal bus and hence prevents stalling the CPU waiting for the write to
|
||||
* complete. Enabling this feature can improve performance for writing to the
|
||||
* timer registers.
|
||||
*/
|
||||
static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
|
||||
{
|
||||
if (timer->posted)
|
||||
return;
|
||||
|
||||
if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) {
|
||||
timer->posted = OMAP_TIMER_NONPOSTED;
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
|
||||
OMAP_TIMER_CTRL_POSTED, 0);
|
||||
timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
|
||||
timer->posted = OMAP_TIMER_POSTED;
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
|
||||
int posted, unsigned long rate)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
|
||||
if (l & OMAP_TIMER_CTRL_ST) {
|
||||
l &= ~0x1;
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
|
||||
#ifdef CONFIG_ARCH_OMAP2PLUS
|
||||
/* Readback to make sure write has completed */
|
||||
__omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
|
||||
/*
|
||||
* Wait for functional clock period x 3.5 to make sure that
|
||||
* timer is stopped
|
||||
*/
|
||||
udelay(3500000 / rate + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Ack possibly pending interrupt */
|
||||
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
|
||||
unsigned int value)
|
||||
{
|
||||
writel_relaxed(value, timer->irq_ena);
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
|
||||
{
|
||||
return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
|
||||
unsigned int value)
|
||||
{
|
||||
writel_relaxed(value, timer->irq_stat);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
|
||||
* @timer: timer pointer over which read operation to perform
|
||||
@@ -921,6 +1036,10 @@ static const struct dmtimer_platform_data omap3plus_pdata = {
|
||||
.timer_ops = &dmtimer_ops,
|
||||
};
|
||||
|
||||
static const struct dmtimer_platform_data am6_pdata = {
|
||||
.timer_ops = &dmtimer_ops,
|
||||
};
|
||||
|
||||
static const struct of_device_id omap_timer_match[] = {
|
||||
{
|
||||
.compatible = "ti,omap2420-timer",
|
||||
@@ -949,6 +1068,10 @@ static const struct of_device_id omap_timer_match[] = {
|
||||
.compatible = "ti,dm816-timer",
|
||||
.data = &omap3plus_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,am654-timer",
|
||||
.data = &am6_pdata,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, omap_timer_match);
|
||||
|
||||
@@ -399,6 +399,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
|
||||
.compatible = "renesas,r8a779a0-thermal",
|
||||
.data = &rcar_gen3_ths_tj_1,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,r8a779f0-thermal",
|
||||
.data = &rcar_gen3_ths_tj_1,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
|
||||
|
||||
@@ -247,148 +247,4 @@ int omap_dm_timers_active(void);
|
||||
#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \
|
||||
(_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
|
||||
|
||||
/*
|
||||
* The below are inlined to optimize code size for system timers. Other code
|
||||
* should not need these at all.
|
||||
*/
|
||||
#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2PLUS)
|
||||
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
|
||||
int posted)
|
||||
{
|
||||
if (posted)
|
||||
while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
|
||||
cpu_relax();
|
||||
|
||||
return readl_relaxed(timer->func_base + (reg & 0xff));
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
|
||||
u32 reg, u32 val, int posted)
|
||||
{
|
||||
if (posted)
|
||||
while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
|
||||
cpu_relax();
|
||||
|
||||
writel_relaxed(val, timer->func_base + (reg & 0xff));
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
|
||||
{
|
||||
u32 tidr;
|
||||
|
||||
/* Assume v1 ip if bits [31:16] are zero */
|
||||
tidr = readl_relaxed(timer->io_base);
|
||||
if (!(tidr >> 16)) {
|
||||
timer->revision = 1;
|
||||
timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
|
||||
timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
|
||||
timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
|
||||
timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
|
||||
timer->func_base = timer->io_base;
|
||||
} else {
|
||||
timer->revision = 2;
|
||||
timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
|
||||
timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
|
||||
timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
|
||||
timer->pend = timer->io_base +
|
||||
_OMAP_TIMER_WRITE_PEND_OFFSET +
|
||||
OMAP_TIMER_V2_FUNC_OFFSET;
|
||||
timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* __omap_dm_timer_enable_posted - enables write posted mode
|
||||
* @timer: pointer to timer instance handle
|
||||
*
|
||||
* Enables the write posted mode for the timer. When posted mode is enabled
|
||||
* writes to certain timer registers are immediately acknowledged by the
|
||||
* internal bus and hence prevents stalling the CPU waiting for the write to
|
||||
* complete. Enabling this feature can improve performance for writing to the
|
||||
* timer registers.
|
||||
*/
|
||||
static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
|
||||
{
|
||||
if (timer->posted)
|
||||
return;
|
||||
|
||||
if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) {
|
||||
timer->posted = OMAP_TIMER_NONPOSTED;
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
|
||||
OMAP_TIMER_CTRL_POSTED, 0);
|
||||
timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
|
||||
timer->posted = OMAP_TIMER_POSTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* __omap_dm_timer_override_errata - override errata flags for a timer
|
||||
* @timer: pointer to timer handle
|
||||
* @errata: errata flags to be ignored
|
||||
*
|
||||
* For a given timer, override a timer errata by clearing the flags
|
||||
* specified by the errata argument. A specific erratum should only be
|
||||
* overridden for a timer if the timer is used in such a way the erratum
|
||||
* has no impact.
|
||||
*/
|
||||
static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer,
|
||||
u32 errata)
|
||||
{
|
||||
timer->errata &= ~errata;
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
|
||||
int posted, unsigned long rate)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
|
||||
if (l & OMAP_TIMER_CTRL_ST) {
|
||||
l &= ~0x1;
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
|
||||
#ifdef CONFIG_ARCH_OMAP2PLUS
|
||||
/* Readback to make sure write has completed */
|
||||
__omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
|
||||
/*
|
||||
* Wait for functional clock period x 3.5 to make sure that
|
||||
* timer is stopped
|
||||
*/
|
||||
udelay(3500000 / rate + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Ack possibly pending interrupt */
|
||||
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
|
||||
u32 ctrl, unsigned int load,
|
||||
int posted)
|
||||
{
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
|
||||
unsigned int value)
|
||||
{
|
||||
writel_relaxed(value, timer->irq_ena);
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
|
||||
{
|
||||
return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
|
||||
unsigned int value)
|
||||
{
|
||||
writel_relaxed(value, timer->irq_stat);
|
||||
}
|
||||
#endif /* CONFIG_ARCH_OMAP1 || CONFIG_ARCH_OMAP2PLUS */
|
||||
#endif /* __CLOCKSOURCE_DMTIMER_H */
|
||||
|
||||
Reference in New Issue
Block a user