forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/sc…
…m/linux/kernel/git/tip/tip Pull more timer updates from Thomas Gleixner: "A set of commits for the new C-SKY architecture timers" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: dt-bindings: timer: gx6605s SOC timer clocksource/drivers/c-sky: Add gx6605s SOC system timer dt-bindings: timer: C-SKY Multi-processor timer clocksource/drivers/c-sky: Add C-SKY SMP timer
- Loading branch information
Showing
7 changed files
with
432 additions
and
0 deletions.
There are no files selected for viewing
42 changes: 42 additions & 0 deletions
42
Documentation/devicetree/bindings/timer/csky,gx6605s-timer.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
================= | ||
gx6605s SOC Timer | ||
================= | ||
|
||
The timer is used in gx6605s soc as system timer and the driver | ||
contain clk event and clk source. | ||
|
||
============================== | ||
timer node bindings definition | ||
============================== | ||
|
||
Description: Describes gx6605s SOC timer | ||
|
||
PROPERTIES | ||
|
||
- compatible | ||
Usage: required | ||
Value type: <string> | ||
Definition: must be "csky,gx6605s-timer" | ||
- reg | ||
Usage: required | ||
Value type: <u32 u32> | ||
Definition: <phyaddr size> in soc from cpu view | ||
- clocks | ||
Usage: required | ||
Value type: phandle + clock specifier cells | ||
Definition: must be input clk node | ||
- interrupt | ||
Usage: required | ||
Value type: <u32> | ||
Definition: must be timer irq num defined by soc | ||
|
||
Examples: | ||
--------- | ||
|
||
timer0: timer@20a000 { | ||
compatible = "csky,gx6605s-timer"; | ||
reg = <0x0020a000 0x400>; | ||
clocks = <&dummy_apb_clk>; | ||
interrupts = <10>; | ||
interrupt-parent = <&intc>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
============================ | ||
C-SKY Multi-processors Timer | ||
============================ | ||
|
||
C-SKY multi-processors timer is designed for C-SKY SMP system and the | ||
regs is accessed by cpu co-processor 4 registers with mtcr/mfcr. | ||
|
||
- PTIM_CTLR "cr<0, 14>" Control reg to start reset timer. | ||
- PTIM_TSR "cr<1, 14>" Interrupt cleanup status reg. | ||
- PTIM_CCVR "cr<3, 14>" Current counter value reg. | ||
- PTIM_LVR "cr<6, 14>" Window value reg to triger next event. | ||
|
||
============================== | ||
timer node bindings definition | ||
============================== | ||
|
||
Description: Describes SMP timer | ||
|
||
PROPERTIES | ||
|
||
- compatible | ||
Usage: required | ||
Value type: <string> | ||
Definition: must be "csky,mptimer" | ||
- clocks | ||
Usage: required | ||
Value type: <node> | ||
Definition: must be input clk node | ||
- interrupts | ||
Usage: required | ||
Value type: <u32> | ||
Definition: must be timer irq num defined by soc | ||
|
||
Examples: | ||
--------- | ||
|
||
timer: timer { | ||
compatible = "csky,mptimer"; | ||
clocks = <&dummy_apb_clk>; | ||
interrupts = <16>; | ||
interrupt-parent = <&intc>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | ||
|
||
#include <linux/init.h> | ||
#include <linux/interrupt.h> | ||
#include <linux/sched_clock.h> | ||
|
||
#include "timer-of.h" | ||
|
||
#define CLKSRC_OFFSET 0x40 | ||
|
||
#define TIMER_STATUS 0x00 | ||
#define TIMER_VALUE 0x04 | ||
#define TIMER_CONTRL 0x10 | ||
#define TIMER_CONFIG 0x20 | ||
#define TIMER_DIV 0x24 | ||
#define TIMER_INI 0x28 | ||
|
||
#define GX6605S_STATUS_CLR BIT(0) | ||
#define GX6605S_CONTRL_RST BIT(0) | ||
#define GX6605S_CONTRL_START BIT(1) | ||
#define GX6605S_CONFIG_EN BIT(0) | ||
#define GX6605S_CONFIG_IRQ_EN BIT(1) | ||
|
||
static irqreturn_t gx6605s_timer_interrupt(int irq, void *dev) | ||
{ | ||
struct clock_event_device *ce = dev; | ||
void __iomem *base = timer_of_base(to_timer_of(ce)); | ||
|
||
writel_relaxed(GX6605S_STATUS_CLR, base + TIMER_STATUS); | ||
|
||
ce->event_handler(ce); | ||
|
||
return IRQ_HANDLED; | ||
} | ||
|
||
static int gx6605s_timer_set_oneshot(struct clock_event_device *ce) | ||
{ | ||
void __iomem *base = timer_of_base(to_timer_of(ce)); | ||
|
||
/* reset and stop counter */ | ||
writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL); | ||
|
||
/* enable with irq and start */ | ||
writel_relaxed(GX6605S_CONFIG_EN | GX6605S_CONFIG_IRQ_EN, | ||
base + TIMER_CONFIG); | ||
|
||
return 0; | ||
} | ||
|
||
static int gx6605s_timer_set_next_event(unsigned long delta, | ||
struct clock_event_device *ce) | ||
{ | ||
void __iomem *base = timer_of_base(to_timer_of(ce)); | ||
|
||
/* use reset to pause timer */ | ||
writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL); | ||
|
||
/* config next timeout value */ | ||
writel_relaxed(ULONG_MAX - delta, base + TIMER_INI); | ||
writel_relaxed(GX6605S_CONTRL_START, base + TIMER_CONTRL); | ||
|
||
return 0; | ||
} | ||
|
||
static int gx6605s_timer_shutdown(struct clock_event_device *ce) | ||
{ | ||
void __iomem *base = timer_of_base(to_timer_of(ce)); | ||
|
||
writel_relaxed(0, base + TIMER_CONTRL); | ||
writel_relaxed(0, base + TIMER_CONFIG); | ||
|
||
return 0; | ||
} | ||
|
||
static struct timer_of to = { | ||
.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, | ||
.clkevt = { | ||
.rating = 300, | ||
.features = CLOCK_EVT_FEAT_DYNIRQ | | ||
CLOCK_EVT_FEAT_ONESHOT, | ||
.set_state_shutdown = gx6605s_timer_shutdown, | ||
.set_state_oneshot = gx6605s_timer_set_oneshot, | ||
.set_next_event = gx6605s_timer_set_next_event, | ||
.cpumask = cpu_possible_mask, | ||
}, | ||
.of_irq = { | ||
.handler = gx6605s_timer_interrupt, | ||
.flags = IRQF_TIMER | IRQF_IRQPOLL, | ||
}, | ||
}; | ||
|
||
static u64 notrace gx6605s_sched_clock_read(void) | ||
{ | ||
void __iomem *base; | ||
|
||
base = timer_of_base(&to) + CLKSRC_OFFSET; | ||
|
||
return (u64)readl_relaxed(base + TIMER_VALUE); | ||
} | ||
|
||
static void gx6605s_clkevt_init(void __iomem *base) | ||
{ | ||
writel_relaxed(0, base + TIMER_DIV); | ||
writel_relaxed(0, base + TIMER_CONFIG); | ||
|
||
clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 2, | ||
ULONG_MAX); | ||
} | ||
|
||
static int gx6605s_clksrc_init(void __iomem *base) | ||
{ | ||
writel_relaxed(0, base + TIMER_DIV); | ||
writel_relaxed(0, base + TIMER_INI); | ||
|
||
writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL); | ||
|
||
writel_relaxed(GX6605S_CONFIG_EN, base + TIMER_CONFIG); | ||
|
||
writel_relaxed(GX6605S_CONTRL_START, base + TIMER_CONTRL); | ||
|
||
sched_clock_register(gx6605s_sched_clock_read, 32, timer_of_rate(&to)); | ||
|
||
return clocksource_mmio_init(base + TIMER_VALUE, "gx6605s", | ||
timer_of_rate(&to), 200, 32, clocksource_mmio_readl_up); | ||
} | ||
|
||
static int __init gx6605s_timer_init(struct device_node *np) | ||
{ | ||
int ret; | ||
|
||
/* | ||
* The timer driver is for nationalchip gx6605s SOC and there are two | ||
* same timer in gx6605s. We use one for clkevt and another for clksrc. | ||
* | ||
* The timer is mmio map to access, so we need give mmio address in dts. | ||
* | ||
* It provides a 32bit countup timer and interrupt will be caused by | ||
* count-overflow. | ||
* So we need set-next-event by ULONG_MAX - delta in TIMER_INI reg. | ||
* | ||
* The counter at 0x0 offset is clock event. | ||
* The counter at 0x40 offset is clock source. | ||
* They are the same in hardware, just different used by driver. | ||
*/ | ||
ret = timer_of_init(np, &to); | ||
if (ret) | ||
return ret; | ||
|
||
gx6605s_clkevt_init(timer_of_base(&to)); | ||
|
||
return gx6605s_clksrc_init(timer_of_base(&to) + CLKSRC_OFFSET); | ||
} | ||
TIMER_OF_DECLARE(csky_gx6605s_timer, "csky,gx6605s-timer", gx6605s_timer_init); |
Oops, something went wrong.