Commit 1b7efaa6 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'timers-v5.9' of https://git.linaro.org/people/daniel.lezcano/linux into timers/core

Pull clock event/surce driver changes from Daniel Lezcano:

  - Add sama5d2 support and rework the 32kHz clock handling (Alexandre Belloni)
  - Add the high resolution support for SMP/SMT on the Ingenic timer (Zhou Yanjie)
  - Add support for i.MX TPM driver with ARM64 (Anson Huang)
  - Fix typo by replacing KHz to kHz (Geert Uytterhoeven)
  - Add 32kHz support by setting the minimum ticks to 5 on Nomadik MTU (Linus Walleij)
  - Replace HTTP links with HTTPS ones for security reasons (Alexander A. Klimov)
  - Add support for the Ingenic X1000 OST (Zhou Yanjie)
parents 36cd28a4 5ecafc12
* Device tree bindings for Atmel Timer Counter Blocks
- compatible: Should be "atmel,<chip>-tcb", "simple-mfd", "syscon".
<chip> can be "at91rm9200" or "at91sam9x5"
- reg: Should contain registers location and length
- #address-cells: has to be 1
- #size-cells: has to be 0
- interrupts: Should contain all interrupts for the TC block
Note that you can specify several interrupt cells if the TC
block has one interrupt per channel.
- clock-names: tuple listing input clock names.
Required elements: "t0_clk", "slow_clk"
Optional elements: "t1_clk", "t2_clk"
- clocks: phandles to input clocks.
The TCB can expose multiple subdevices:
* a timer
- compatible: Should be "atmel,tcb-timer"
- reg: Should contain the TCB channels to be used. If the
counter width is 16 bits (at91rm9200-tcb), two consecutive
channels are needed. Else, only one channel will be used.
Examples:
One interrupt per TC block:
tcb0: timer@fff7c000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
clocks = <&tcb0_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
timer@0 {
compatible = "atmel,tcb-timer";
reg = <0>, <1>;
};
timer@2 {
compatible = "atmel,tcb-timer";
reg = <2>;
};
};
One interrupt per TC channel in a TC block:
tcb1: timer@fffdc000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfffdc000 0x100>;
interrupts = <26 4>, <27 4>, <28 4>;
clocks = <&tcb1_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/soc/microchip/atmel,at91rm9200-tcb.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Atmel Timer Counter Block
maintainers:
- Alexandre Belloni <alexandre.belloni@bootlin.com>
description: |
The Atmel (now Microchip) SoCs have timers named Timer Counter Block. Each
timer has three channels with two counters each.
properties:
compatible:
items:
- enum:
- atmel,at91rm9200-tcb
- atmel,at91sam9x5-tcb
- atmel,sama5d2-tcb
- const: simple-mfd
- const: syscon
reg:
maxItems: 1
interrupts:
description:
List of interrupts. One interrupt per TCB channel if available or one
interrupt for the TC block
minItems: 1
maxItems: 3
clock-names:
description:
List of clock names. Always includes t0_clk and slow clk. Also includes
t1_clk and t2_clk if a clock per channel is available.
minItems: 2
maxItems: 4
clocks:
minItems: 2
maxItems: 4
'#address-cells':
const: 1
'#size-cells':
const: 0
patternProperties:
"^timer@[0-2]$":
description: The timer block channels that are used as timers.
type: object
properties:
compatible:
const: atmel,tcb-timer
reg:
description:
List of channels to use for this particular timer.
minItems: 1
maxItems: 3
required:
- compatible
- reg
allOf:
- if:
properties:
compatible:
contains:
const: atmel,sama5d2-tcb
then:
properties:
clocks:
minItems: 3
maxItems: 3
clock-names:
items:
- const: t0_clk
- const: gclk
- const: slow_clk
else:
properties:
clocks:
minItems: 2
maxItems: 4
clock-names:
oneOf:
- items:
- const: t0_clk
- const: slow_clk
- items:
- const: t0_clk
- const: t1_clk
- const: t2_clk
- const: slow_clk
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- '#address-cells'
- '#size-cells'
additionalProperties: false
examples:
- |
/* One interrupt per TC block: */
tcb0: timer@fff7c000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
clocks = <&tcb0_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
timer@0 {
compatible = "atmel,tcb-timer";
reg = <0>, <1>;
};
timer@2 {
compatible = "atmel,tcb-timer";
reg = <2>;
};
};
/* One interrupt per TC channel in a TC block: */
tcb1: timer@fffdc000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfffdc000 0x100>;
interrupts = <26 4>, <27 4>, <28 4>;
clocks = <&tcb1_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
timer@0 {
compatible = "atmel,tcb-timer";
reg = <0>;
};
timer@1 {
compatible = "atmel,tcb-timer";
reg = <1>;
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/timer/ingenic,sysost.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bindings for SYSOST in Ingenic XBurst family SoCs
maintainers:
- 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
description:
The SYSOST in an Ingenic SoC provides one 64bit timer for clocksource
and one or more 32bit timers for clockevent.
properties:
"#clock-cells":
const: 1
compatible:
enum:
- ingenic,x1000-ost
- ingenic,x2000-ost
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
const: ost
interrupts:
maxItems: 1
required:
- "#clock-cells"
- compatible
- reg
- clocks
- clock-names
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/x1000-cgu.h>
ost: timer@12000000 {
compatible = "ingenic,x1000-ost";
reg = <0x12000000 0x3c>;
#clock-cells = <1>;
clocks = <&cgu X1000_CLK_OST>;
clock-names = "ost";
interrupt-parent = <&cpuintc>;
interrupts = <3>;
};
...
......@@ -10,7 +10,7 @@ It is global timer is a free running up-counter and can generate interrupt
when the counter reaches preset counter values.
Documentation:
http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf
https://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf
Required properties:
......
......@@ -375,23 +375,23 @@ macb0: ethernet@f8008000 {
};
tcb0: timer@f800c000 {
compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
compatible = "atmel,sama5d2-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xf800c000 0x100>;
interrupts = <35 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&pmc PMC_TYPE_PERIPHERAL 35>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
clocks = <&pmc PMC_TYPE_PERIPHERAL 35>, <&pmc PMC_TYPE_GCK 35>, <&clk32k>;
clock-names = "t0_clk", "gclk", "slow_clk";
};
tcb1: timer@f8010000 {
compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
compatible = "atmel,sama5d2-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xf8010000 0x100>;
interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&pmc PMC_TYPE_PERIPHERAL 36>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
clocks = <&pmc PMC_TYPE_PERIPHERAL 36>, <&pmc PMC_TYPE_GCK 36>, <&clk32k>;
clock-names = "t0_clk", "gclk", "slow_clk";
};
hsmc: hsmc@f8014000 {
......
......@@ -616,8 +616,9 @@ config CLKSRC_IMX_GPT
config CLKSRC_IMX_TPM
bool "Clocksource using i.MX TPM" if COMPILE_TEST
depends on ARM && CLKDEV_LOOKUP
depends on (ARM || ARM64) && CLKDEV_LOOKUP
select CLKSRC_MMIO
select TIMER_OF
help
Enable this option to use IMX Timer/PWM Module (TPM) timer as
clocksource.
......@@ -696,8 +697,18 @@ config INGENIC_TIMER
help
Support for the timer/counter unit of the Ingenic JZ SoCs.
config INGENIC_SYSOST
bool "Clocksource/timer using the SYSOST in Ingenic X SoCs"
depends on MIPS || COMPILE_TEST
depends on COMMON_CLK
select MFD_SYSCON
select TIMER_OF
select IRQ_DOMAIN
help
Support for the SYSOST of the Ingenic X Series SoCs.
config INGENIC_OST
bool "Clocksource for Ingenic OS Timer"
bool "Clocksource using the OST in Ingenic JZ SoCs"
depends on MIPS || COMPILE_TEST
depends on COMMON_CLK
select MFD_SYSCON
......
......@@ -82,6 +82,7 @@ obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o
obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
obj-$(CONFIG_INGENIC_OST) += ingenic-ost.o
obj-$(CONFIG_INGENIC_SYSOST) += ingenic-sysost.o
obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o
obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
......
This diff is collapsed.
This diff is collapsed.
......@@ -186,6 +186,7 @@ static int __init nmdk_timer_init(void __iomem *base, int irq,
{
unsigned long rate;
int ret;
int min_ticks;
mtu_base = base;
......@@ -194,7 +195,8 @@ static int __init nmdk_timer_init(void __iomem *base, int irq,
/*
* Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz
* for ux500.
* for ux500, and in one specific Ux500 case 32768 Hz.
*
* Use a divide-by-16 counter if the tick rate is more than 32MHz.
* At 32 MHz, the timer (with 32 bit counter) can be programmed
* to wake-up at a max 127s a head in time. Dividing a 2.4 MHz timer
......@@ -230,7 +232,12 @@ static int __init nmdk_timer_init(void __iomem *base, int irq,
pr_err("%s: request_irq() failed\n", "Nomadik Timer Tick");
nmdk_clkevt.cpumask = cpumask_of(0);
nmdk_clkevt.irq = irq;
clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU);
if (rate < 100000)
min_ticks = 5;
else
min_ticks = 2;
clockevents_config_and_register(&nmdk_clkevt, rate, min_ticks,
0xffffffffU);
mtu_delay_timer.read_current_timer = &nmdk_timer_read_current_timer;
mtu_delay_timer.freq = rate;
......
......@@ -349,7 +349,7 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
/*
* According to the sh73a0 user's manual, as CMCNT can be operated
* only by the RCLK (Pseudo 32 KHz), there's one restriction on
* only by the RCLK (Pseudo 32 kHz), there's one restriction on
* modifying CMCNT register; two RCLK cycles are necessary before
* this register is either read or any modification of the value
* it holds is reflected in the LSI's actual operation.
......
......@@ -27,9 +27,10 @@
* - Some chips support 32 bit counter. A single channel is used for
* this 32 bit free-running counter. the second channel is not used.
*
* - The third channel may be used to provide a 16-bit clockevent
* source, used in either periodic or oneshot mode. This runs
* at 32 KiHZ, and can handle delays of up to two seconds.
* - The third channel may be used to provide a clockevent source, used in
* either periodic or oneshot mode. For 16-bit counter its runs at 32 KiHZ,
* and can handle delays of up to two seconds. For 32-bit counters, it runs at
* the same rate as the clocksource
*
* REVISIT behavior during system suspend states... we should disable
* all clocks and save the power. Easily done for clockevent devices,
......@@ -47,6 +48,8 @@ static struct
} tcb_cache[3];
static u32 bmr_cache;
static const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128 };
static u64 tc_get_cycles(struct clocksource *cs)
{
unsigned long flags;
......@@ -143,6 +146,7 @@ static unsigned long notrace tc_delay_timer_read32(void)
struct tc_clkevt_device {
struct clock_event_device clkevt;
struct clk *clk;
u32 rate;
void __iomem *regs;
};
......@@ -151,13 +155,6 @@ static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
return container_of(clkevt, struct tc_clkevt_device, clkevt);
}
/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
* because using one of the divided clocks would usually mean the
* tick rate can never be less than several dozen Hz (vs 0.5 Hz).
*
* A divided clock could be good for high resolution timers, since
* 30.5 usec resolution can seem "low".
*/
static u32 timer_clock;
static int tc_shutdown(struct clock_event_device *d)
......@@ -183,7 +180,7 @@ static int tc_set_oneshot(struct clock_event_device *d)
clk_enable(tcd->clk);
/* slow clock, count up to RC, then irq and stop */
/* count up to RC, then irq and stop */
writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE |
ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR));
writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
......@@ -205,10 +202,10 @@ static int tc_set_periodic(struct clock_event_device *d)
*/
clk_enable(tcd->clk);
/* slow clock, count up to RC, then irq and restart */
/* count up to RC, then irq and restart */
writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
regs + ATMEL_TC_REG(2, CMR));
writel((32768 + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
writel((tcd->rate + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
/* Enable clock and interrupts on RC compare */
writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
......@@ -256,47 +253,55 @@ static irqreturn_t ch2_irq(int irq, void *handle)
return IRQ_NONE;
}
static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)
{
int ret;
struct clk *t2_clk = tc->clk[2];
int irq = tc->irq[2];
ret = clk_prepare_enable(tc->slow_clk);
if (ret)
return ret;
int bits = tc->tcb_config->counter_width;
/* try to enable t2 clk to avoid future errors in mode change */
ret = clk_prepare_enable(t2_clk);
if (ret) {
clk_disable_unprepare(tc->slow_clk);
if (ret)
return ret;
}
clk_disable(t2_clk);
clkevt.regs = tc->regs;
clkevt.clk = t2_clk;
timer_clock = clk32k_divisor_idx;
if (bits == 32) {
timer_clock = divisor_idx;
clkevt.rate = clk_get_rate(t2_clk) / atmel_tcb_divisors[divisor_idx];
} else {
ret = clk_prepare_enable(tc->slow_clk);
if (ret) {
clk_disable_unprepare(t2_clk);
return ret;
}
clkevt.rate = clk_get_rate(tc->slow_clk);
timer_clock = ATMEL_TC_TIMER_CLOCK5;
}
clk_disable(t2_clk);
clkevt.clkevt.cpumask = cpumask_of(0);
ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt);
if (ret) {
clk_unprepare(t2_clk);
clk_disable_unprepare(tc->slow_clk);
if (bits != 32)
clk_disable_unprepare(tc->slow_clk);
return ret;
}
clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff);
clockevents_config_and_register(&clkevt.clkevt, clkevt.rate, 1, BIT(bits) - 1);
return ret;
}
#else /* !CONFIG_GENERIC_CLOCKEVENTS */
static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)
{
/* NOTHING */
return 0;
......@@ -346,11 +351,23 @@ static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_id
writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
}
static const u8 atmel_tcb_divisors[5] = { 2, 8, 32, 128, 0, };
static struct atmel_tcb_config tcb_rm9200_config = {
.counter_width = 16,
};
static struct atmel_tcb_config tcb_sam9x5_config = {
.counter_width = 32,
};
static struct atmel_tcb_config tcb_sama5d2_config = {
.counter_width = 32,
.has_gclk = 1,
};
static const struct of_device_id atmel_tcb_of_match[] = {
{ .compatible = "atmel,at91rm9200-tcb", .data = (void *)16, },
{ .compatible = "atmel,at91sam9x5-tcb", .data = (void *)32, },
{ .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },
{ .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },
{ .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },
{ /* sentinel */ }
};
......@@ -362,7 +379,6 @@ static int __init tcb_clksrc_init(struct device_node *node)
u64 (*tc_sched_clock)(void);
u32 rate, divided_rate = 0;
int best_divisor_idx = -1;
int clk32k_divisor_idx = -1;
int bits;
int i;
int ret;
......@@ -399,7 +415,11 @@ static int __init tcb_clksrc_init(struct device_node *node)
}
match = of_match_node(atmel_tcb_of_match, node->parent);
bits = (uintptr_t)match->data;
if (!match)
return -ENODEV;
tc.tcb_config = match->data;
bits = tc.tcb_config->counter_width;
for (i = 0; i < ARRAY_SIZE(tc.irq); i++)
writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR));
......@@ -412,22 +432,17 @@ static int __init tcb_clksrc_init(struct device_node *node)
/* How fast will we be counting? Pick something over 5 MHz. */
rate = (u32) clk_get_rate(t0_clk);
for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); i++) {
i = 0;
if (tc.tcb_config->has_gclk)
i = 1;
for (; i < ARRAY_SIZE(atmel_tcb_divisors); i++) {
unsigned divisor = atmel_tcb_divisors[i];
unsigned tmp;
/* remember 32 KiHz clock for later */
if (!divisor) {
clk32k_divisor_idx = i;
continue;
}
tmp = rate / divisor;
pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
if (best_divisor_idx > 0) {
if (tmp < 5 * 1000 * 1000)
continue;
}
if ((best_divisor_idx >= 0) && (tmp < 5 * 1000 * 1000))
break;
divided_rate = tmp;
best_divisor_idx = i;
}
......@@ -467,7 +482,7 @@ static int __init tcb_clksrc_init(struct device_node *node)
goto err_disable_t1;
/* channel 2: periodic and oneshot timer support */
ret = setup_clkevents(&tc, clk32k_divisor_idx);
ret = setup_clkevents(&tc, best_divisor_idx);
if (ret)
goto err_unregister_clksrc;
......
......@@ -21,7 +21,7 @@
* Roughly modelled after the OMAP1 MPU timer code.
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
* Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*/
#include <linux/clk.h>
......
......@@ -4,7 +4,7 @@
*
* 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>
*
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This header provides clock numbers for the ingenic,tcu DT binding.
*/
#ifndef __DT_BINDINGS_CLOCK_INGENIC_OST_H__
#define __DT_BINDINGS_CLOCK_INGENIC_OST_H__
#define OST_CLK_PERCPU_TIMER 0
#define OST_CLK_GLOBAL_TIMER 1
#endif /* __DT_BINDINGS_CLOCK_INGENIC_OST_H__ */
......@@ -36,9 +36,14 @@ struct clk;
/**
* struct atmel_tcb_config - SoC data for a Timer/Counter Block
* @counter_width: size in bits of a timer counter register
* @has_gclk: boolean indicating if a timer counter has a generic clock
* @has_qdec: boolean indicating if a timer counter has a quadrature
* decoder.
*/
struct atmel_tcb_config {
size_t counter_width;
bool has_gclk;
bool has_qdec;
};
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment