* [PATCH v4 0/2] clocksource: Add renesas-ostm timer driver @ 2017-01-26 2:07 Chris Brandt 2017-01-26 2:07 ` Chris Brandt 2017-01-26 2:07 ` Chris Brandt 0 siblings, 2 replies; 7+ messages in thread From: Chris Brandt @ 2017-01-26 2:07 UTC (permalink / raw) To: Rob Herring, Mark Rutland, Simon Horman, Magnus Damm, Russell King, Daniel Lezcano, Thomas Gleixner, Geert Uytterhoeven Cc: devicetree, linux-renesas-soc, Chris Brandt This patch set adds a new clocksource driver that uses the OS Timer (OSTM) that exists in the R7S72100 (RZ/A1) SoC. The operation of the driver was tested with a simple user application that does multiple calls to nanosleep() and gettimeofday(). The purpose of adding this driver is to get better time keeping accuracy over the default MTU2 clocksource timer. v4: * Added more details to commit log * Kconfig: SYS_SUPPORTS_RENESAS_OSTM to just RENESAS_OSTM * removed all MODULE code (this driver is builtin only) * removed items from 'struct ostm_device' * changed ioread8 to readb * explain endless while loop * removed un-needed vars like 'ret' * removed WARN_ON(!clockevent_state_oneshot(ced)); * removed "failed to allocate memory" message * remove pm_runtime calls * remove "earlytimer" register (only for sh, not arm) * convert from platform driver to CLOCKSOURCE_OF_DECLARE * ostm_probe code is now in ostm_init v3: * Changed ostm@fcfec000 to timer@fcfec000 * Added power-domains to nodes v2: * The biggest change was now the channels are independent of each other and have separate nodes in the DT. The first probed will be set up as a clock source, and any additional channels probed will become a clock event. Chris Brandt (2): dt-bindings: document renesas-ostm timer clocksource: Add renesas-ostm timer driver .../devicetree/bindings/timer/renesas,ostm.txt | 30 +++ arch/arm/mach-shmobile/Kconfig | 1 + drivers/clocksource/Kconfig | 7 + drivers/clocksource/Makefile | 1 + drivers/clocksource/renesas-ostm.c | 262 +++++++++++++++++++++ 5 files changed, 301 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/renesas,ostm.txt create mode 100644 drivers/clocksource/renesas-ostm.c -- 2.10.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 1/2] dt-bindings: document renesas-ostm timer @ 2017-01-26 2:07 ` Chris Brandt 0 siblings, 0 replies; 7+ messages in thread From: Chris Brandt @ 2017-01-26 2:07 UTC (permalink / raw) To: Rob Herring, Mark Rutland, Simon Horman, Magnus Damm, Russell King, Daniel Lezcano, Thomas Gleixner, Geert Uytterhoeven Cc: devicetree, linux-renesas-soc, Chris Brandt Signed-off-by: Chris Brandt <chris.brandt@renesas.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> --- v3: * changed ostm@fcfec000 to timer@fcfec000 in example * added power-domains in example v2: * remove sw implementation specific portions --- .../devicetree/bindings/timer/renesas,ostm.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/renesas,ostm.txt diff --git a/Documentation/devicetree/bindings/timer/renesas,ostm.txt b/Documentation/devicetree/bindings/timer/renesas,ostm.txt new file mode 100644 index 0000000..be3ae0f --- /dev/null +++ b/Documentation/devicetree/bindings/timer/renesas,ostm.txt @@ -0,0 +1,30 @@ +* Renesas OS Timer (OSTM) + +The OSTM is a multi-channel 32-bit timer/counter with fixed clock +source that can operate in either interval count down timer or free-running +compare match mode. + +Channels are independent from each other. + +Required Properties: + + - compatible: must be one or more of the following: + - "renesas,r7s72100-ostm" for the r7s72100 OSTM + - "renesas,ostm" for any OSTM + This is a fallback for the above renesas,*-ostm entries + + - reg: base address and length of the register block for a timer channel. + + - interrupts: interrupt specifier for the timer channel. + + - clocks: clock specifier for the timer channel. + +Example: R7S72100 (RZ/A1H) OSTM node + + ostm0: timer@fcfec000 { + compatible = "renesas,r7s72100-ostm", "renesas,ostm"; + reg = <0xfcfec000 0x30>; + interrupts = <GIC_SPI 102 IRQ_TYPE_EDGE_RISING>; + clocks = <&mstp5_clks R7S72100_CLK_OSTM0>; + power-domains = <&cpg_clocks>; + }; -- 2.10.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 1/2] dt-bindings: document renesas-ostm timer @ 2017-01-26 2:07 ` Chris Brandt 0 siblings, 0 replies; 7+ messages in thread From: Chris Brandt @ 2017-01-26 2:07 UTC (permalink / raw) To: Rob Herring, Mark Rutland, Simon Horman, Magnus Damm, Russell King, Daniel Lezcano, Thomas Gleixner, Geert Uytterhoeven Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA, Chris Brandt Signed-off-by: Chris Brandt <chris.brandt-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> Reviewed-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org> --- v3: * changed ostm@fcfec000 to timer@fcfec000 in example * added power-domains in example v2: * remove sw implementation specific portions --- .../devicetree/bindings/timer/renesas,ostm.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/renesas,ostm.txt diff --git a/Documentation/devicetree/bindings/timer/renesas,ostm.txt b/Documentation/devicetree/bindings/timer/renesas,ostm.txt new file mode 100644 index 0000000..be3ae0f --- /dev/null +++ b/Documentation/devicetree/bindings/timer/renesas,ostm.txt @@ -0,0 +1,30 @@ +* Renesas OS Timer (OSTM) + +The OSTM is a multi-channel 32-bit timer/counter with fixed clock +source that can operate in either interval count down timer or free-running +compare match mode. + +Channels are independent from each other. + +Required Properties: + + - compatible: must be one or more of the following: + - "renesas,r7s72100-ostm" for the r7s72100 OSTM + - "renesas,ostm" for any OSTM + This is a fallback for the above renesas,*-ostm entries + + - reg: base address and length of the register block for a timer channel. + + - interrupts: interrupt specifier for the timer channel. + + - clocks: clock specifier for the timer channel. + +Example: R7S72100 (RZ/A1H) OSTM node + + ostm0: timer@fcfec000 { + compatible = "renesas,r7s72100-ostm", "renesas,ostm"; + reg = <0xfcfec000 0x30>; + interrupts = <GIC_SPI 102 IRQ_TYPE_EDGE_RISING>; + clocks = <&mstp5_clks R7S72100_CLK_OSTM0>; + power-domains = <&cpg_clocks>; + }; -- 2.10.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 2/2] clocksource: Add renesas-ostm timer driver @ 2017-01-26 2:07 ` Chris Brandt 0 siblings, 0 replies; 7+ messages in thread From: Chris Brandt @ 2017-01-26 2:07 UTC (permalink / raw) To: Rob Herring, Mark Rutland, Simon Horman, Magnus Damm, Russell King, Daniel Lezcano, Thomas Gleixner, Geert Uytterhoeven Cc: devicetree, linux-renesas-soc, Chris Brandt This patch adds a OSTM driver for the Renesas architecture. The OS Timer (OSTM) has independent channels that can be used as a freerun or interval times. This driver uses the first probed device as a clocksource and then any additional devices as clock events. Signed-off-by: Chris Brandt <chris.brandt@renesas.com> --- v3: * Added more details to commit log * Kconfig: SYS_SUPPORTS_RENESAS_OSTM to just RENESAS_OSTM * removed all MODULE code (this driver is builtin only) * removed items from 'struct ostm_device' * changed ioread8 to readb * explain endless while loop * removed un-needed vars like 'ret' * removed WARN_ON(!clockevent_state_oneshot(ced)); * removed "failed to allocate memory" message * remove pm_runtime calls * remove "earlytimer" register (only for sh, not arm) * convert from platform driver to CLOCKSOURCE_OF_DECLARE * ostm_probe code is now in ostm_init v2: * changed implementation to be independent channel nodes --- arch/arm/mach-shmobile/Kconfig | 1 + drivers/clocksource/Kconfig | 7 + drivers/clocksource/Makefile | 1 + drivers/clocksource/renesas-ostm.c | 262 +++++++++++++++++++++++++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 drivers/clocksource/renesas-ostm.c diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 2bb4b09..ad7d604 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -57,6 +57,7 @@ config ARCH_R7S72100 select PM select PM_GENERIC_DOMAINS select SYS_SUPPORTS_SH_MTU2 + select RENESAS_OSTM config ARCH_R8A73A4 bool "R-Mobile APE6 (R8A73A40)" diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4866f7a..a0786a6 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -467,6 +467,13 @@ config SH_TIMER_MTU2 Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas. This hardware comes with 16 bit-timer registers. +config RENESAS_OSTM + bool "Renesas OSTM timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables the support for the Renesas OSTM. + config SH_TIMER_TMU bool "Renesas TMU timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index a14111e..bbd163b 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o +obj-$(CONFIG_RENESAS_OSTM) += renesas-ostm.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_EM_TIMER_STI) += em_sti.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c new file mode 100644 index 0000000..757bd71 --- /dev/null +++ b/drivers/clocksource/renesas-ostm.c @@ -0,0 +1,262 @@ +/* + * Renesas Timer Support - OSTM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/sched_clock.h> +#include <linux/slab.h> + +/* + * The OSTM contains independent channels. + * The first OSTM channel probed will be set up as a free running + * clocksource. Additionally we will use this clocksource for the system + * schedule timer sched_clock(). + * + * The second (or more) channel probed will be set up as an interrupt + * driven clock event. + */ + +struct ostm_device { + void __iomem *base; + unsigned long ticks_per_jiffy; + struct clock_event_device ced; +}; + +static void __iomem *system_clock; /* For sched_clock() */ + +/* OSTM REGISTERS */ +#define OSTM_CMP 0x000 /* RW,32 */ +#define OSTM_CNT 0x004 /* R,32 */ +#define OSTM_TE 0x010 /* R,8 */ +#define OSTM_TS 0x014 /* W,8 */ +#define OSTM_TT 0x018 /* W,8 */ +#define OSTM_CTL 0x020 /* RW,8 */ + +#define TE 0x01 +#define TS 0x01 +#define TT 0x01 +#define CTL_PERIODIC 0x00 +#define CTL_ONESHOT 0x02 +#define CTL_FREERUN 0x02 + +static struct ostm_device *ced_to_ostm(struct clock_event_device *ced) +{ + return container_of(ced, struct ostm_device, ced); +} + +static void ostm_timer_stop(struct ostm_device *ostm) +{ + if (readb(ostm->base + OSTM_TE) & TE) { + iowrite8(TT, ostm->base + OSTM_TT); + + /* + * Read back the register simply to confirm the write operation + * has completed since I/O writes can sometimes get queued by + * the bus architecture. + */ + while (readb(ostm->base + OSTM_TE) & TE) + ; + } +} + +static int __init ostm_init_clksrc(struct ostm_device *ostm, unsigned long rate) +{ + /* + * irq not used (clock sources don't use interrupts) + */ + + ostm_timer_stop(ostm); + + iowrite32(0, ostm->base + OSTM_CMP); + iowrite8(CTL_FREERUN, ostm->base + OSTM_CTL); + iowrite8(TS, ostm->base + OSTM_TS); + + return clocksource_mmio_init(ostm->base + OSTM_CNT, + "ostm", rate, + 300, 32, clocksource_mmio_readl_up); +} + +static u64 notrace ostm_read_sched_clock(void) +{ + return readl(system_clock); +} + +static void __init ostm_init_sched_clock(struct ostm_device *ostm, + unsigned long rate) +{ + system_clock = ostm->base + OSTM_CNT; + sched_clock_register(ostm_read_sched_clock, 32, rate); +} + +static int ostm_clock_event_next(unsigned long delta, + struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + iowrite32(delta, ostm->base + OSTM_CMP); + iowrite8(CTL_ONESHOT, ostm->base + OSTM_CTL); + iowrite8(TS, ostm->base + OSTM_TS); + + return 0; +} + +static int ostm_shutdown(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + return 0; +} +static int ostm_set_periodic(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) + ostm_timer_stop(ostm); + + iowrite32(ostm->ticks_per_jiffy - 1, ostm->base + OSTM_CMP); + iowrite8(CTL_PERIODIC, ostm->base + OSTM_CTL); + iowrite8(TS, ostm->base + OSTM_TS); + + return 0; +} + +static int ostm_set_oneshot(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + return 0; +} + +static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id) +{ + struct ostm_device *ostm = dev_id; + + if (clockevent_state_oneshot(&ostm->ced)) + ostm_timer_stop(ostm); + + /* notify clockevent layer */ + if (ostm->ced.event_handler) + ostm->ced.event_handler(&ostm->ced); + + return IRQ_HANDLED; +} + +static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq, + unsigned long rate) +{ + struct clock_event_device *ced = &ostm->ced; + int ret = -ENXIO; + + ret = request_irq(irq, ostm_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, + "ostm", ostm); + if (ret) { + pr_err("ostm: failed to request irq\n"); + return ret; + } + + ced->name = "ostm"; + ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; + ced->set_state_shutdown = ostm_shutdown; + ced->set_state_periodic = ostm_set_periodic; + ced->set_state_oneshot = ostm_set_oneshot; + ced->set_next_event = ostm_clock_event_next; + ced->shift = 32; + ced->rating = 300; + ced->cpumask = cpumask_of(0); + clockevents_config_and_register(ced, rate, 0xf, 0xffffffff); + + return 0; +} + +static int __init ostm_init(struct device_node *np) +{ + struct ostm_device *ostm; + int ret = -EFAULT; + struct clk *ostm_clk; + int irq; + unsigned long rate; + + ostm = kzalloc(sizeof(*ostm), GFP_KERNEL); + if (!ostm) + return -ENOMEM; + + ostm->base = of_iomap(np, 0); + if (!ostm->base) { + pr_err("ostm: failed to remap I/O memory\n"); + goto err; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq < 0) { + pr_err("ostm: Failed to get irq\n"); + goto err; + } + + ostm_clk = of_clk_get(np, 0); + if (IS_ERR(ostm_clk)) { + pr_err("ostm: Failed to get clock\n"); + ostm_clk = NULL; + goto err; + } + + ret = clk_prepare_enable(ostm_clk); + if (ret) { + pr_err("ostm: Failed to enable clock\n"); + goto err; + } + + rate = clk_get_rate(ostm_clk); + ostm->ticks_per_jiffy = (rate + HZ / 2) / HZ; + + /* + * First probed device will be used as system clocksource. Any + * additional devices will be used as clock events. + */ + if (!system_clock) { + ret = ostm_init_clksrc(ostm, rate); + + if (!ret) { + ostm_init_sched_clock(ostm, rate); + pr_info("ostm: used for clocksource\n"); + } + + } else { + ret = ostm_init_clkevt(ostm, irq, rate); + + if (!ret) + pr_info("ostm: used for clock events\n"); + } + +err: + if (ret) { + clk_disable_unprepare(ostm_clk); + iounmap(ostm->base); + kfree(ostm); + return ret; + } + + return 0; +} + +CLOCKSOURCE_OF_DECLARE(ostm, "renesas,ostm", ostm_init); -- 2.10.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 2/2] clocksource: Add renesas-ostm timer driver @ 2017-01-26 2:07 ` Chris Brandt 0 siblings, 0 replies; 7+ messages in thread From: Chris Brandt @ 2017-01-26 2:07 UTC (permalink / raw) To: Rob Herring, Mark Rutland, Simon Horman, Magnus Damm, Russell King, Daniel Lezcano, Thomas Gleixner, Geert Uytterhoeven Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA, Chris Brandt This patch adds a OSTM driver for the Renesas architecture. The OS Timer (OSTM) has independent channels that can be used as a freerun or interval times. This driver uses the first probed device as a clocksource and then any additional devices as clock events. Signed-off-by: Chris Brandt <chris.brandt-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> --- v3: * Added more details to commit log * Kconfig: SYS_SUPPORTS_RENESAS_OSTM to just RENESAS_OSTM * removed all MODULE code (this driver is builtin only) * removed items from 'struct ostm_device' * changed ioread8 to readb * explain endless while loop * removed un-needed vars like 'ret' * removed WARN_ON(!clockevent_state_oneshot(ced)); * removed "failed to allocate memory" message * remove pm_runtime calls * remove "earlytimer" register (only for sh, not arm) * convert from platform driver to CLOCKSOURCE_OF_DECLARE * ostm_probe code is now in ostm_init v2: * changed implementation to be independent channel nodes --- arch/arm/mach-shmobile/Kconfig | 1 + drivers/clocksource/Kconfig | 7 + drivers/clocksource/Makefile | 1 + drivers/clocksource/renesas-ostm.c | 262 +++++++++++++++++++++++++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 drivers/clocksource/renesas-ostm.c diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 2bb4b09..ad7d604 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -57,6 +57,7 @@ config ARCH_R7S72100 select PM select PM_GENERIC_DOMAINS select SYS_SUPPORTS_SH_MTU2 + select RENESAS_OSTM config ARCH_R8A73A4 bool "R-Mobile APE6 (R8A73A40)" diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4866f7a..a0786a6 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -467,6 +467,13 @@ config SH_TIMER_MTU2 Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas. This hardware comes with 16 bit-timer registers. +config RENESAS_OSTM + bool "Renesas OSTM timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables the support for the Renesas OSTM. + config SH_TIMER_TMU bool "Renesas TMU timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index a14111e..bbd163b 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o +obj-$(CONFIG_RENESAS_OSTM) += renesas-ostm.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_EM_TIMER_STI) += em_sti.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c new file mode 100644 index 0000000..757bd71 --- /dev/null +++ b/drivers/clocksource/renesas-ostm.c @@ -0,0 +1,262 @@ +/* + * Renesas Timer Support - OSTM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/sched_clock.h> +#include <linux/slab.h> + +/* + * The OSTM contains independent channels. + * The first OSTM channel probed will be set up as a free running + * clocksource. Additionally we will use this clocksource for the system + * schedule timer sched_clock(). + * + * The second (or more) channel probed will be set up as an interrupt + * driven clock event. + */ + +struct ostm_device { + void __iomem *base; + unsigned long ticks_per_jiffy; + struct clock_event_device ced; +}; + +static void __iomem *system_clock; /* For sched_clock() */ + +/* OSTM REGISTERS */ +#define OSTM_CMP 0x000 /* RW,32 */ +#define OSTM_CNT 0x004 /* R,32 */ +#define OSTM_TE 0x010 /* R,8 */ +#define OSTM_TS 0x014 /* W,8 */ +#define OSTM_TT 0x018 /* W,8 */ +#define OSTM_CTL 0x020 /* RW,8 */ + +#define TE 0x01 +#define TS 0x01 +#define TT 0x01 +#define CTL_PERIODIC 0x00 +#define CTL_ONESHOT 0x02 +#define CTL_FREERUN 0x02 + +static struct ostm_device *ced_to_ostm(struct clock_event_device *ced) +{ + return container_of(ced, struct ostm_device, ced); +} + +static void ostm_timer_stop(struct ostm_device *ostm) +{ + if (readb(ostm->base + OSTM_TE) & TE) { + iowrite8(TT, ostm->base + OSTM_TT); + + /* + * Read back the register simply to confirm the write operation + * has completed since I/O writes can sometimes get queued by + * the bus architecture. + */ + while (readb(ostm->base + OSTM_TE) & TE) + ; + } +} + +static int __init ostm_init_clksrc(struct ostm_device *ostm, unsigned long rate) +{ + /* + * irq not used (clock sources don't use interrupts) + */ + + ostm_timer_stop(ostm); + + iowrite32(0, ostm->base + OSTM_CMP); + iowrite8(CTL_FREERUN, ostm->base + OSTM_CTL); + iowrite8(TS, ostm->base + OSTM_TS); + + return clocksource_mmio_init(ostm->base + OSTM_CNT, + "ostm", rate, + 300, 32, clocksource_mmio_readl_up); +} + +static u64 notrace ostm_read_sched_clock(void) +{ + return readl(system_clock); +} + +static void __init ostm_init_sched_clock(struct ostm_device *ostm, + unsigned long rate) +{ + system_clock = ostm->base + OSTM_CNT; + sched_clock_register(ostm_read_sched_clock, 32, rate); +} + +static int ostm_clock_event_next(unsigned long delta, + struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + iowrite32(delta, ostm->base + OSTM_CMP); + iowrite8(CTL_ONESHOT, ostm->base + OSTM_CTL); + iowrite8(TS, ostm->base + OSTM_TS); + + return 0; +} + +static int ostm_shutdown(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + return 0; +} +static int ostm_set_periodic(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) + ostm_timer_stop(ostm); + + iowrite32(ostm->ticks_per_jiffy - 1, ostm->base + OSTM_CMP); + iowrite8(CTL_PERIODIC, ostm->base + OSTM_CTL); + iowrite8(TS, ostm->base + OSTM_TS); + + return 0; +} + +static int ostm_set_oneshot(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + return 0; +} + +static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id) +{ + struct ostm_device *ostm = dev_id; + + if (clockevent_state_oneshot(&ostm->ced)) + ostm_timer_stop(ostm); + + /* notify clockevent layer */ + if (ostm->ced.event_handler) + ostm->ced.event_handler(&ostm->ced); + + return IRQ_HANDLED; +} + +static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq, + unsigned long rate) +{ + struct clock_event_device *ced = &ostm->ced; + int ret = -ENXIO; + + ret = request_irq(irq, ostm_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, + "ostm", ostm); + if (ret) { + pr_err("ostm: failed to request irq\n"); + return ret; + } + + ced->name = "ostm"; + ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; + ced->set_state_shutdown = ostm_shutdown; + ced->set_state_periodic = ostm_set_periodic; + ced->set_state_oneshot = ostm_set_oneshot; + ced->set_next_event = ostm_clock_event_next; + ced->shift = 32; + ced->rating = 300; + ced->cpumask = cpumask_of(0); + clockevents_config_and_register(ced, rate, 0xf, 0xffffffff); + + return 0; +} + +static int __init ostm_init(struct device_node *np) +{ + struct ostm_device *ostm; + int ret = -EFAULT; + struct clk *ostm_clk; + int irq; + unsigned long rate; + + ostm = kzalloc(sizeof(*ostm), GFP_KERNEL); + if (!ostm) + return -ENOMEM; + + ostm->base = of_iomap(np, 0); + if (!ostm->base) { + pr_err("ostm: failed to remap I/O memory\n"); + goto err; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq < 0) { + pr_err("ostm: Failed to get irq\n"); + goto err; + } + + ostm_clk = of_clk_get(np, 0); + if (IS_ERR(ostm_clk)) { + pr_err("ostm: Failed to get clock\n"); + ostm_clk = NULL; + goto err; + } + + ret = clk_prepare_enable(ostm_clk); + if (ret) { + pr_err("ostm: Failed to enable clock\n"); + goto err; + } + + rate = clk_get_rate(ostm_clk); + ostm->ticks_per_jiffy = (rate + HZ / 2) / HZ; + + /* + * First probed device will be used as system clocksource. Any + * additional devices will be used as clock events. + */ + if (!system_clock) { + ret = ostm_init_clksrc(ostm, rate); + + if (!ret) { + ostm_init_sched_clock(ostm, rate); + pr_info("ostm: used for clocksource\n"); + } + + } else { + ret = ostm_init_clkevt(ostm, irq, rate); + + if (!ret) + pr_info("ostm: used for clock events\n"); + } + +err: + if (ret) { + clk_disable_unprepare(ostm_clk); + iounmap(ostm->base); + kfree(ostm); + return ret; + } + + return 0; +} + +CLOCKSOURCE_OF_DECLARE(ostm, "renesas,ostm", ostm_init); -- 2.10.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v4 2/2] clocksource: Add renesas-ostm timer driver 2017-01-26 2:07 ` Chris Brandt (?) @ 2017-01-26 9:24 ` Daniel Lezcano 2017-01-26 13:07 ` Chris Brandt -1 siblings, 1 reply; 7+ messages in thread From: Daniel Lezcano @ 2017-01-26 9:24 UTC (permalink / raw) To: Chris Brandt Cc: Rob Herring, Mark Rutland, Simon Horman, Magnus Damm, Russell King, Thomas Gleixner, Geert Uytterhoeven, devicetree, linux-renesas-soc On Wed, Jan 25, 2017 at 09:07:07PM -0500, Chris Brandt wrote: > This patch adds a OSTM driver for the Renesas architecture. > The OS Timer (OSTM) has independent channels that can be > used as a freerun or interval times. > This driver uses the first probed device as a clocksource > and then any additional devices as clock events. > > Signed-off-by: Chris Brandt <chris.brandt@renesas.com> > --- > v3: > * Added more details to commit log > * Kconfig: SYS_SUPPORTS_RENESAS_OSTM to just RENESAS_OSTM > * removed all MODULE code (this driver is builtin only) > * removed items from 'struct ostm_device' > * changed ioread8 to readb The iowrite* conversion is missing. s/iowrite8/writeb/ s/iowrite32/writel/ Other than that the driver looks good to me. Thanks. -- Daniel ^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: [PATCH v4 2/2] clocksource: Add renesas-ostm timer driver 2017-01-26 9:24 ` Daniel Lezcano @ 2017-01-26 13:07 ` Chris Brandt 0 siblings, 0 replies; 7+ messages in thread From: Chris Brandt @ 2017-01-26 13:07 UTC (permalink / raw) To: Daniel Lezcano Cc: Rob Herring, Mark Rutland, Simon Horman, Magnus Damm, Russell King, Thomas Gleixner, Geert Uytterhoeven, devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org Hi Daniel, On Thursday, January 26, 2017, Daniel Lezcano wrote: > > --- > > v3: > > * Added more details to commit log > > * Kconfig: SYS_SUPPORTS_RENESAS_OSTM to just RENESAS_OSTM > > * removed all MODULE code (this driver is builtin only) > > * removed items from 'struct ostm_device' > > * changed ioread8 to readb > > The iowrite* conversion is missing. > > s/iowrite8/writeb/ > s/iowrite32/writel/ > > Other than that the driver looks good to me. Ugh. I missed that. Thanks! Chris ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-01-26 13:07 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-01-26 2:07 [PATCH v4 0/2] clocksource: Add renesas-ostm timer driver Chris Brandt 2017-01-26 2:07 ` [PATCH v4 1/2] dt-bindings: document renesas-ostm timer Chris Brandt 2017-01-26 2:07 ` Chris Brandt 2017-01-26 2:07 ` [PATCH v4 2/2] clocksource: Add renesas-ostm timer driver Chris Brandt 2017-01-26 2:07 ` Chris Brandt 2017-01-26 9:24 ` Daniel Lezcano 2017-01-26 13:07 ` Chris Brandt
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.