From: Mark Salter <msalter@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: linux-arch@vger.kernel.org, Aurelien Jacquiot <a-jacquiot@ti.com>,
Mark Salter <msalter@redhat.com>,
Thomas Gleixner <tglx@linutronix.de>
Subject: [PATCH v4 11/24] C6X: time management
Date: Tue, 4 Oct 2011 12:43:48 -0400 [thread overview]
Message-ID: <1317746641-26725-12-git-send-email-msalter@redhat.com> (raw)
In-Reply-To: <1317746641-26725-1-git-send-email-msalter@redhat.com>
From: Aurelien Jacquiot <a-jacquiot@ti.com>
Original port to early 2.6 kernel using TI COFF toolchain.
Brought up to date by Mark Salter <msalter@redhat.com>
Signed-off-by: Aurelien Jacquiot <a-jacquiot@ti.com>
Signed-off-by: Mark Salter <msalter@redhat.com>
CC: Thomas Gleixner <tglx@linutronix.de>
---
arch/c6x/include/asm/timer64.h | 6 +
arch/c6x/include/asm/timex.h | 33 ++++++
arch/c6x/kernel/time.c | 65 +++++++++++
arch/c6x/platforms/timer64.c | 236 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 340 insertions(+), 0 deletions(-)
create mode 100644 arch/c6x/include/asm/timer64.h
create mode 100644 arch/c6x/include/asm/timex.h
create mode 100644 arch/c6x/kernel/time.c
create mode 100644 arch/c6x/platforms/timer64.c
diff --git a/arch/c6x/include/asm/timer64.h b/arch/c6x/include/asm/timer64.h
new file mode 100644
index 0000000..bbe27bb
--- /dev/null
+++ b/arch/c6x/include/asm/timer64.h
@@ -0,0 +1,6 @@
+#ifndef _C6X_TIMER64_H
+#define _C6X_TIMER64_H
+
+extern void __init timer64_init(void);
+
+#endif /* _C6X_TIMER64_H */
diff --git a/arch/c6x/include/asm/timex.h b/arch/c6x/include/asm/timex.h
new file mode 100644
index 0000000..508c3ec
--- /dev/null
+++ b/arch/c6x/include/asm/timex.h
@@ -0,0 +1,33 @@
+/*
+ * Port on Texas Instruments TMS320C6x architecture
+ *
+ * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ * Modified for 2.6.34: Mark Salter <msalter@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_TIMEX_H
+#define _ASM_C6X_TIMEX_H
+
+#define CLOCK_TICK_RATE ((1000 * 1000000UL) / 6)
+
+/* 64-bit timestamp */
+typedef unsigned long long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+ unsigned l, h;
+
+ asm volatile (" dint\n"
+ " mvc .s2 TSCL,%0\n"
+ " mvc .s2 TSCH,%1\n"
+ " rint\n"
+ : "=b"(l), "=b"(h));
+ return ((cycles_t)h << 32) | l;
+}
+
+#endif /* _ASM_C6X_TIMEX_H */
diff --git a/arch/c6x/kernel/time.c b/arch/c6x/kernel/time.c
new file mode 100644
index 0000000..4c9f136
--- /dev/null
+++ b/arch/c6x/kernel/time.c
@@ -0,0 +1,65 @@
+/*
+ * Port on Texas Instruments TMS320C6x architecture
+ *
+ * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/profile.h>
+
+#include <asm/timer64.h>
+
+static u32 sched_clock_multiplier;
+#define SCHED_CLOCK_SHIFT 16
+
+static cycle_t tsc_read(struct clocksource *cs)
+{
+ return get_cycles();
+}
+
+static struct clocksource clocksource_tsc = {
+ .name = "timestamp",
+ .rating = 300,
+ .read = tsc_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ * scheduler clock - returns current time in nanoseconds.
+ */
+u64 sched_clock(void)
+{
+ u64 tsc = get_cycles();
+
+ return (tsc * sched_clock_multiplier) >> SCHED_CLOCK_SHIFT;
+}
+
+void time_init(void)
+{
+ u64 tmp = (u64)NSEC_PER_SEC << SCHED_CLOCK_SHIFT;
+
+ do_div(tmp, c6x_core_freq);
+ sched_clock_multiplier = tmp;
+
+ clocksource_register_hz(&clocksource_tsc, c6x_core_freq);
+
+ /* write anything into TSCL to enable counting */
+ set_creg(TSCL, 0);
+
+ /* probe for timer64 event timer */
+ timer64_init();
+}
diff --git a/arch/c6x/platforms/timer64.c b/arch/c6x/platforms/timer64.c
new file mode 100644
index 0000000..7834158
--- /dev/null
+++ b/arch/c6x/platforms/timer64.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2010, 2011 Texas Instruments Incorporated
+ * Contributed by: Mark Salter (msalter@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <asm/soc.h>
+#include <asm/dscr.h>
+#include <asm/timer64.h>
+
+struct timer_regs {
+ u32 reserved0;
+ u32 emumgt;
+ u32 reserved1;
+ u32 reserved2;
+ u32 cntlo;
+ u32 cnthi;
+ u32 prdlo;
+ u32 prdhi;
+ u32 tcr;
+ u32 tgcr;
+ u32 wdtcr;
+};
+
+static struct timer_regs __iomem *timer;
+
+#define TCR_TSTATLO 0x001
+#define TCR_INVOUTPLO 0x002
+#define TCR_INVINPLO 0x004
+#define TCR_CPLO 0x008
+#define TCR_ENAMODELO_ONCE 0x040
+#define TCR_ENAMODELO_CONT 0x080
+#define TCR_ENAMODELO_MASK 0x0c0
+#define TCR_PWIDLO_MASK 0x030
+#define TCR_CLKSRCLO 0x100
+#define TCR_TIENLO 0x200
+#define TCR_TSTATHI (0x001 << 16)
+#define TCR_INVOUTPHI (0x002 << 16)
+#define TCR_CPHI (0x008 << 16)
+#define TCR_PWIDHI_MASK (0x030 << 16)
+#define TCR_ENAMODEHI_ONCE (0x040 << 16)
+#define TCR_ENAMODEHI_CONT (0x080 << 16)
+#define TCR_ENAMODEHI_MASK (0x0c0 << 16)
+
+#define TGCR_TIMLORS 0x001
+#define TGCR_TIMHIRS 0x002
+#define TGCR_TIMMODE_UD32 0x004
+#define TGCR_TIMMODE_WDT64 0x008
+#define TGCR_TIMMODE_CD32 0x00c
+#define TGCR_TIMMODE_MASK 0x00c
+#define TGCR_PSCHI_MASK (0x00f << 8)
+#define TGCR_TDDRHI_MASK (0x00f << 12)
+
+/*
+ * Timer clocks are divided down from the CPU clock
+ * The divisor is in the EMUMGTCLKSPD register
+ */
+#define TIMER_DIVISOR \
+ ((soc_readl(&timer->emumgt) & (0xf << 16)) >> 16)
+
+#define TIMER64_RATE (c6x_core_freq / TIMER_DIVISOR)
+
+#define TIMER64_MODE_DISABLED 0
+#define TIMER64_MODE_ONE_SHOT TCR_ENAMODELO_ONCE
+#define TIMER64_MODE_PERIODIC TCR_ENAMODELO_CONT
+
+static int timer64_mode;
+static int timer64_devstate_id = -1;
+
+static void timer64_config(unsigned long period)
+{
+ u32 tcr = soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK;
+
+ soc_writel(tcr, &timer->tcr);
+ soc_writel(period - 1, &timer->prdlo);
+ soc_writel(0, &timer->cntlo);
+ tcr |= timer64_mode;
+ soc_writel(tcr, &timer->tcr);
+}
+
+static void timer64_enable(void)
+{
+ u32 val;
+
+ if (timer64_devstate_id >= 0)
+ dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_ENABLED);
+
+ /* disable timer, reset count */
+ soc_writel(soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK, &timer->tcr);
+ soc_writel(0, &timer->prdlo);
+
+ /* use internal clock and 1 cycle pulse width */
+ val = soc_readl(&timer->tcr);
+ soc_writel(val & ~(TCR_CLKSRCLO | TCR_PWIDLO_MASK), &timer->tcr);
+
+ /* dual 32-bit unchained mode */
+ val = soc_readl(&timer->tgcr) & ~TGCR_TIMMODE_MASK;
+ soc_writel(val, &timer->tgcr);
+ soc_writel(val | (TGCR_TIMLORS | TGCR_TIMMODE_UD32), &timer->tgcr);
+}
+
+static void timer64_disable(void)
+{
+ /* disable timer, reset count */
+ soc_writel(soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK, &timer->tcr);
+ soc_writel(0, &timer->prdlo);
+
+ if (timer64_devstate_id >= 0)
+ dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_DISABLED);
+}
+
+static int next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ timer64_config(delta);
+ return 0;
+}
+
+static void set_clock_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ timer64_enable();
+ timer64_mode = TIMER64_MODE_PERIODIC;
+ timer64_config(TIMER64_RATE / HZ);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ timer64_enable();
+ timer64_mode = TIMER64_MODE_ONE_SHOT;
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ timer64_mode = TIMER64_MODE_DISABLED;
+ timer64_disable();
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device t64_clockevent_device = {
+ .name = "TIMER64_EVT32_TIMER",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .rating = 200,
+ .set_mode = set_clock_mode,
+ .set_next_event = next_event,
+};
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = &t64_clockevent_device;
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction timer_iact = {
+ .name = "timer",
+ .flags = IRQF_TIMER,
+ .handler = timer_interrupt,
+ .dev_id = &t64_clockevent_device,
+};
+
+void __init timer64_init(void)
+{
+ struct clock_event_device *cd = &t64_clockevent_device;
+ struct device_node *np, *first = NULL;
+ u32 val;
+ int err, found = 0;
+
+ for_each_compatible_node(np, NULL, "ti,c64x+timer64") {
+ err = of_property_read_u32(np, "ti,core-mask", &val);
+ if (!err) {
+ if (val & (1 << get_coreid())) {
+ found = 1;
+ break;
+ }
+ } else if (!first)
+ first = np;
+ }
+ if (!found) {
+ /* try first one with no core-mask */
+ if (first)
+ np = of_node_get(first);
+ else {
+ pr_debug("Cannot find ti,c64x+timer64 timer.\n");
+ return;
+ }
+ }
+
+ timer = of_iomap(np, 0);
+ if (!timer) {
+ pr_debug("%s: Cannot map timer registers.\n", np->full_name);
+ goto out;
+ }
+ pr_debug("%s: Timer registers=%p.\n", np->full_name, timer);
+
+ cd->irq = irq_of_parse_and_map(np, 0);
+ if (cd->irq == NO_IRQ) {
+ pr_debug("%s: Cannot find interrupt.\n", np->full_name);
+ iounmap(timer);
+ goto out;
+ }
+
+ /* If there is a device state control, save the ID. */
+ err = of_property_read_u32(np, "ti,dscr-dev-enable", &val);
+ if (!err)
+ timer64_devstate_id = val;
+
+ pr_debug("%s: Timer irq=%d.\n", np->full_name, cd->irq);
+
+ clockevents_calc_mult_shift(cd, c6x_core_freq / TIMER_DIVISOR, 5);
+
+ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
+ cd->min_delta_ns = clockevent_delta2ns(250, cd);
+
+ cd->cpumask = cpumask_of(smp_processor_id());
+
+ clockevents_register_device(cd);
+ setup_irq(cd->irq, &timer_iact);
+
+out:
+ of_node_put(np);
+ return;
+}
--
1.7.6.2
next prev parent reply other threads:[~2011-10-04 16:43 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-04 16:43 [PATCH v4 00/24] C6X: New architecture Mark Salter
2011-10-04 16:43 ` [PATCH v4 01/24] fix default __strnlen_user macro Mark Salter
2011-10-04 16:43 ` [PATCH v4 02/24] fixed generic page.h for non-zero PAGE_OFFSET Mark Salter
2011-10-04 16:43 ` [PATCH v4 03/24] add ELF machine define for TI C6X DSPs Mark Salter
2011-10-04 16:43 ` [PATCH v4 04/24] add missing __iomem to generic iounmap declaration Mark Salter
2011-10-04 16:43 ` [PATCH v4 05/24] C6X: build infrastructure Mark Salter
2011-10-04 19:11 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 06/24] C6X: early boot code Mark Salter
2011-10-04 19:11 ` Arnd Bergmann
[not found] ` <1317746641-26725-1-git-send-email-msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2011-10-04 16:43 ` [PATCH v4 07/24] C6X: devicetree support Mark Salter
2011-10-04 16:43 ` Mark Salter
2011-10-04 19:24 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 08/24] C6X: memory management and DMA support Mark Salter
2011-10-04 19:10 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 09/24] C6X: process management Mark Salter
2011-10-04 16:43 ` [PATCH v4 10/24] C6X: signal management Mark Salter
2011-10-04 16:43 ` Mark Salter [this message]
2011-10-04 18:04 ` [PATCH v4 11/24] C6X: time management Thomas Gleixner
2011-10-04 19:13 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 12/24] C6X: interrupt handling Mark Salter
2011-10-04 18:06 ` Thomas Gleixner
2011-10-04 19:12 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 13/24] C6X: syscalls Mark Salter
2011-10-04 16:43 ` [PATCH v4 14/24] C6X: build infrastructure Mark Salter
2011-10-04 16:43 ` [PATCH v4 15/24] C6X: clocks Mark Salter
2011-10-04 16:43 ` [PATCH v4 16/24] C6X: cache control Mark Salter
2011-10-04 16:43 ` [PATCH v4 17/24] C6X: loadable module support Mark Salter
2011-10-04 19:08 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 18/24] C6X: ptrace support Mark Salter
2011-10-04 19:07 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 19/24] C6X: headers Mark Salter
2011-10-04 18:06 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 20/24] C6X: library code Mark Salter
2011-10-04 18:04 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 21/24] C6X: general SoC support Mark Salter
2011-10-04 19:23 ` Arnd Bergmann
2011-10-04 16:43 ` [PATCH v4 22/24] C6X: EMIF - External Memory Interface Mark Salter
2011-10-04 16:44 ` [PATCH v4 23/24] C6X: DSCR - Device State Configuration Registers Mark Salter
2011-10-04 16:44 ` [PATCH v4 24/24] C6X: MAINTAINERS Mark Salter
2011-10-04 19:27 ` [PATCH v4 00/24] C6X: New architecture Arnd Bergmann
2011-10-05 12:52 ` Mark Salter
2011-10-05 16:16 ` Arnd Bergmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1317746641-26725-12-git-send-email-msalter@redhat.com \
--to=msalter@redhat.com \
--cc=a-jacquiot@ti.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.