Hi all,
The TI dmtimer has been using a custom API to expose some hardware timer
features for PWM and remoteproc so far with struct omap_dm_timer_ops. It
seems that for most part we can nowadays replace most of the custom API
with chained interrupts and clock provider features.
There are lots of the dmtimer instances on TI SoCs, some have tens of
them. Some timers have an IO pad available, which means the timers could
be used as clock output for an external device with a 50% duty cycle. The
timers also have input capture capability, but that is not currently
supported. There have been some patches posted earlier for the PWM capture
support though.
These patches are against v6.1-rc2, and need also the following pending
patch:
[PATCH] clocksource/drivers/timer-ti-dm: Clear settings on probe and free
For am6, these patches depend on the pending dts changes posted earlier:
[PATCH v3 0/2] Configure dmtimers for am65
[PATCH 1/2] arm64: dts: ti: k3-am62: Add general purpose timers for am62
I have only lightly tested this so far to make sure I get clock output on
k3-am625-sk on TIMER_IO2 at user expansion connector pin 10. I have not
worried at all so far about disabling the legacy API if used with
interrupts and clock framework.
Regards,
Tony
Tony Lindgren (3):
clocksource/drivers/timer-ti-dm: Add lock for register access
clocksource/drivers/timer-ti-dm: Implement chained irq
clocksource/drivers/timer-ti-dm: Add clock provider support
drivers/clocksource/timer-ti-dm.c | 591 +++++++++++++++++++++++++++++-
drivers/pwm/pwm-omap-dmtimer.c | 1 +
include/clocksource/timer-ti-dm.h | 2 +
3 files changed, 578 insertions(+), 16 deletions(-)
--
2.37.3
We currently have no locking for timer control register and we assume that
the consumer device using struct omap_dm_timer_ops takes care of locking
for the timer.
In order to prepare for adding irchip and clock provider support to start
removing the struct omap_dm_timer_ops custom API, let's add timer->lock
and use it for the timer control register. This is needed to protect the
control register access between the different kernel frameworks.
Not-Yet-Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/clocksource/timer-ti-dm.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -121,6 +121,7 @@ struct dmtimer {
int id;
int irq;
struct clk *fclk;
+ spinlock_t lock; /* For shared register access */
void __iomem *io_base;
int irq_stat; /* TISR/IRQSTATUS interrupt status */
@@ -633,6 +634,7 @@ static struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *n
static int omap_dm_timer_free(struct omap_dm_timer *cookie)
{
struct dmtimer *timer;
+ unsigned long flags;
struct device *dev;
int rc;
@@ -649,7 +651,9 @@ static int omap_dm_timer_free(struct omap_dm_timer *cookie)
return rc;
/* Clear timer configuration */
+ spin_lock_irqsave(&timer->lock, flags);
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
+ spin_unlock_irqrestore(&timer->lock, flags);
pm_runtime_put_sync(dev);
@@ -728,6 +732,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
static int omap_dm_timer_start(struct omap_dm_timer *cookie)
{
struct dmtimer *timer;
+ unsigned long flags;
struct device *dev;
int rc;
u32 l;
@@ -742,11 +747,13 @@ static int omap_dm_timer_start(struct omap_dm_timer *cookie)
if (rc)
return rc;
+ spin_lock_irqsave(&timer->lock, flags);
l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
if (!(l & OMAP_TIMER_CTRL_ST)) {
l |= OMAP_TIMER_CTRL_ST;
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
}
+ spin_unlock_irqrestore(&timer->lock, flags);
return 0;
}
@@ -754,6 +761,7 @@ static int omap_dm_timer_start(struct omap_dm_timer *cookie)
static int omap_dm_timer_stop(struct omap_dm_timer *cookie)
{
struct dmtimer *timer;
+ unsigned long flags;
struct device *dev;
unsigned long rate = 0;
@@ -766,7 +774,9 @@ static int omap_dm_timer_stop(struct omap_dm_timer *cookie)
if (!timer->omap1)
rate = clk_get_rate(timer->fclk);
+ spin_lock_irqsave(&timer->lock, flags);
__omap_dm_timer_stop(timer, rate);
+ spin_unlock_irqrestore(&timer->lock, flags);
pm_runtime_put_sync(dev);
@@ -800,6 +810,7 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *cookie, int enable,
unsigned int match)
{
struct dmtimer *timer;
+ unsigned long flags;
struct device *dev;
int rc;
u32 l;
@@ -813,6 +824,7 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *cookie, int enable,
if (rc)
return rc;
+ spin_lock_irqsave(&timer->lock, flags);
l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
if (enable)
l |= OMAP_TIMER_CTRL_CE;
@@ -820,6 +832,7 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *cookie, int enable,
l &= ~OMAP_TIMER_CTRL_CE;
dmtimer_write(timer, OMAP_TIMER_MATCH_REG, match);
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
+ spin_unlock_irqrestore(&timer->lock, flags);
pm_runtime_put_sync(dev);
@@ -830,6 +843,7 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *cookie, int def_on,
int toggle, int trigger, int autoreload)
{
struct dmtimer *timer;
+ unsigned long flags;
struct device *dev;
int rc;
u32 l;
@@ -843,6 +857,7 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *cookie, int def_on,
if (rc)
return rc;
+ spin_lock_irqsave(&timer->lock, flags);
l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR);
@@ -854,6 +869,7 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *cookie, int def_on,
if (autoreload)
l |= OMAP_TIMER_CTRL_AR;
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
+ spin_unlock_irqrestore(&timer->lock, flags);
pm_runtime_put_sync(dev);
@@ -887,6 +903,7 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *cookie,
int prescaler)
{
struct dmtimer *timer;
+ unsigned long flags;
struct device *dev;
int rc;
u32 l;
@@ -900,6 +917,7 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *cookie,
if (rc)
return rc;
+ spin_lock_irqsave(&timer->lock, flags);
l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
if (prescaler >= 0) {
@@ -907,6 +925,7 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *cookie,
l |= prescaler << 2;
}
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
+ spin_unlock_irqrestore(&timer->lock, flags);
pm_runtime_put_sync(dev);
@@ -1093,6 +1112,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
if (!timer)
return -ENOMEM;
+ spin_lock_init(&timer->lock);
+
timer->irq = platform_get_irq(pdev, 0);
if (timer->irq < 0)
return timer->irq;
--
2.37.3
* Tony Lindgren <[email protected]> [221031 11:46]:
> I have only lightly tested this so far to make sure I get clock output on
> k3-am625-sk on TIMER_IO2 at user expansion connector pin 10.
For reference, I used something like the patch below to configure the timer2
for clock output.
Regards,
Tony
8< ---------------------
diff --git a/arch/arm64/boot/dts/ti/k3-am625-sk.dts b/arch/arm64/boot/dts/ti/k3-am625-sk.dts
--- a/arch/arm64/boot/dts/ti/k3-am625-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am625-sk.dts
@@ -143,6 +143,25 @@ led-0 {
default-state = "off";
};
};
+
+ main_pwm2: dmtimer-main-pwm-2 {
+ pinctrl-0 = <&main_timer2_pins_default>;
+ pinctrl-names = "default";
+ compatible = "ti,omap-dmtimer-pwm";
+ #pwm-cells = <3>;
+ ti,timers = <&main_timer2>;
+ interrupts-extended = <&main_timer2 2 IRQ_TYPE_EDGE_RISING>,
+ <&main_timer2 1 IRQ_TYPE_EDGE_RISING>,
+ <&main_timer2 0 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "compare", "overflow", "match";
+ clocks = <&main_timer2>;
+ };
+};
+
+&main_timer2 {
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #clock-cells = <0>;
};
&main_pmx0 {
@@ -270,6 +289,13 @@ AM62X_IOPAD(0x07c, PIN_OUTPUT, 7) /* (P25) GPMC0_CLK.GPIO0_31 */
>;
};
+ main_timer2_pins_default: main-timer2-pins-default {
+ pinctrl-single,pins = <
+ /* (C15) PADCFG_CTRL_PADCONFIG118 0x000f41d8 TIMER_IO2 */
+ AM65X_IOPAD(0x1d8, PIN_OUTPUT, 2)
+ >;
+ };
+
main_gpio1_ioexp_intr_pins_default: main-gpio1-ioexp-intr-pins-default {
pinctrl-single,pins = <
AM62X_IOPAD(0x01d4, PIN_INPUT, 7) /* (B15) UART0_RTSn.GPIO1_23 */