summaryrefslogtreecommitdiff
path: root/arch/arm/mach-iop32x/time.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-17 01:48:14 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-17 01:48:14 +0300
commit2b97c39514a6130f38b14227a36d9cd37e650a9d (patch)
treedfc6ae0eb6c7acd46d170bd4d2c34e2d90bcf264 /arch/arm/mach-iop32x/time.c
parentd0a16fe934383ecdb605ab9312d700fb9099f75e (diff)
parent0366977480c43a221e4309f242d1144e85a368c3 (diff)
downloadlinux-2b97c39514a6130f38b14227a36d9cd37e650a9d.tar.xz
Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC platform updates from Arnd Bergmann: "The main change this time around is a cleanup of some of the oldest platforms based on the XScale and ARM9 CPU cores, which are between 10 and 20 years old. The Kendin/Micrel/Microchip KS8695, Winbond/Nuvoton W90x900 and Intel IOP33x/IOP13xx platforms are removed after we determined that nobody is using them any more. The TI Davinci and NXP LPC32xx platforms on the other hand are still in active use and are converted to the ARCH_MULTIPLATFORM build, meaning that we can compile a kernel that works on these along with most other ARMv5 platforms. Changes toward that goal are also merged for IOP32x, but additional work is needed to complete this. Patches for the remaining ARMv5 platforms have started but need more work and some testing. Support for the new ASpeed AST2600 gets added, this is based on the Cortex-A7 ARMv7 core, and is a newer version of the existing ARMv5 and ARMv6 chips in the same family. Other changes include a cleanup of the ST-Ericsson ux500 platform and the move of the TI Davinci platform to a new clocksource driver" [ The changes had marked INTEL_IOP_ADMA and USB_LPC32XX as being buildable on other platforms through COMPILE_TEST, but that causes new warnings that I most definitely do not want to see during the merge window as that could hide other issues. So the COMPILE_TEST option got disabled for them again - Linus ] * tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (61 commits) ARM: multi_v5_defconfig: make DaVinci part of the ARM v5 multiplatform build ARM: davinci: support multiplatform build for ARM v5 arm64: exynos: Enable exynos-chipid driver ARM: OMAP2+: Delete an unnecessary kfree() call in omap_hsmmc_pdata_init() ARM: OMAP2+: move platform-specific asm-offset.h to arch/arm/mach-omap2 ARM: davinci: dm646x: Fix a typo in the comment ARM: davinci: dm646x: switch to using the clocksource driver ARM: davinci: dm644x: switch to using the clocksource driver ARM: aspeed: Enable SMP boot ARM: aspeed: Add ASPEED AST2600 architecture ARM: aspeed: Select timer in each SoC dt-bindings: arm: cpus: Add ASPEED SMP ARM: imx: stop adjusting ar8031 phy tx delay mailmap: map old company name to new one @microchip.com MAINTAINERS: at91: remove the TC entry MAINTAINERS: at91: Collect all pinctrl/gpio drivers in same entry ARM: at91: move platform-specific asm-offset.h to arch/arm/mach-at91 MAINTAINERS: Extend patterns for Samsung SoC, Security Subsystem and clock drivers ARM: s3c64xx: squash samsung_usb_phy.h into setup-usb-phy.c ARM: debug-ll: Add support for r7s9210 ...
Diffstat (limited to 'arch/arm/mach-iop32x/time.c')
-rw-r--r--arch/arm/mach-iop32x/time.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/arch/arm/mach-iop32x/time.c b/arch/arm/mach-iop32x/time.c
new file mode 100644
index 000000000000..18a4df5c1baa
--- /dev/null
+++ b/arch/arm/mach-iop32x/time.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * arch/arm/plat-iop/time.c
+ *
+ * Timer code for IOP32x and IOP33x based systems
+ *
+ * Author: Deepak Saxena <dsaxena@mvista.com>
+ *
+ * Copyright 2002-2003 MontaVista Software Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+#include <linux/io.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/export.h>
+#include <linux/sched_clock.h>
+#include <asm/irq.h>
+#include <linux/uaccess.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#include "hardware.h"
+#include "irqs.h"
+
+/*
+ * Minimum clocksource/clockevent timer range in seconds
+ */
+#define IOP_MIN_RANGE 4
+
+/*
+ * IOP clocksource (free-running timer 1).
+ */
+static u64 notrace iop_clocksource_read(struct clocksource *unused)
+{
+ return 0xffffffffu - read_tcr1();
+}
+
+static struct clocksource iop_clocksource = {
+ .name = "iop_timer1",
+ .rating = 300,
+ .read = iop_clocksource_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ * IOP sched_clock() implementation via its clocksource.
+ */
+static u64 notrace iop_read_sched_clock(void)
+{
+ return 0xffffffffu - read_tcr1();
+}
+
+/*
+ * IOP clockevents (interrupting timer 0).
+ */
+static int iop_set_next_event(unsigned long delta,
+ struct clock_event_device *unused)
+{
+ u32 tmr = IOP_TMR_PRIVILEGED | IOP_TMR_RATIO_1_1;
+
+ BUG_ON(delta == 0);
+ write_tmr0(tmr & ~(IOP_TMR_EN | IOP_TMR_RELOAD));
+ write_tcr0(delta);
+ write_tmr0((tmr & ~IOP_TMR_RELOAD) | IOP_TMR_EN);
+
+ return 0;
+}
+
+static unsigned long ticks_per_jiffy;
+
+static int iop_set_periodic(struct clock_event_device *evt)
+{
+ u32 tmr = read_tmr0();
+
+ write_tmr0(tmr & ~IOP_TMR_EN);
+ write_tcr0(ticks_per_jiffy - 1);
+ write_trr0(ticks_per_jiffy - 1);
+ tmr |= (IOP_TMR_RELOAD | IOP_TMR_EN);
+
+ write_tmr0(tmr);
+ return 0;
+}
+
+static int iop_set_oneshot(struct clock_event_device *evt)
+{
+ u32 tmr = read_tmr0();
+
+ /* ->set_next_event sets period and enables timer */
+ tmr &= ~(IOP_TMR_RELOAD | IOP_TMR_EN);
+ write_tmr0(tmr);
+ return 0;
+}
+
+static int iop_shutdown(struct clock_event_device *evt)
+{
+ u32 tmr = read_tmr0();
+
+ tmr &= ~IOP_TMR_EN;
+ write_tmr0(tmr);
+ return 0;
+}
+
+static int iop_resume(struct clock_event_device *evt)
+{
+ u32 tmr = read_tmr0();
+
+ tmr |= IOP_TMR_EN;
+ write_tmr0(tmr);
+ return 0;
+}
+
+static struct clock_event_device iop_clockevent = {
+ .name = "iop_timer0",
+ .features = CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 300,
+ .set_next_event = iop_set_next_event,
+ .set_state_shutdown = iop_shutdown,
+ .set_state_periodic = iop_set_periodic,
+ .tick_resume = iop_resume,
+ .set_state_oneshot = iop_set_oneshot,
+};
+
+static irqreturn_t
+iop_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ write_tisr(1);
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction iop_timer_irq = {
+ .name = "IOP Timer Tick",
+ .handler = iop_timer_interrupt,
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .dev_id = &iop_clockevent,
+};
+
+static unsigned long iop_tick_rate;
+unsigned long get_iop_tick_rate(void)
+{
+ return iop_tick_rate;
+}
+EXPORT_SYMBOL(get_iop_tick_rate);
+
+void __init iop_init_time(unsigned long tick_rate)
+{
+ u32 timer_ctl;
+
+ sched_clock_register(iop_read_sched_clock, 32, tick_rate);
+
+ ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ);
+ iop_tick_rate = tick_rate;
+
+ timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
+ IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
+
+ /*
+ * Set up interrupting clockevent timer 0.
+ */
+ write_tmr0(timer_ctl & ~IOP_TMR_EN);
+ write_tisr(1);
+ setup_irq(IRQ_IOP32X_TIMER0, &iop_timer_irq);
+ iop_clockevent.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&iop_clockevent, tick_rate,
+ 0xf, 0xfffffffe);
+
+ /*
+ * Set up free-running clocksource timer 1.
+ */
+ write_trr1(0xffffffff);
+ write_tcr1(0xffffffff);
+ write_tmr1(timer_ctl);
+ clocksource_register_hz(&iop_clocksource, tick_rate);
+}