diff options
author | Zoltan Herpai <wigyori@uid0.hu> | 2014-02-05 08:42:28 +0000 |
---|---|---|
committer | Zoltan Herpai <wigyori@uid0.hu> | 2014-02-05 08:42:28 +0000 |
commit | c957af0a0f6a2c45b9b3c84f45f4a3aa44d293c6 (patch) | |
tree | f8e3bda571dab7f80fdd240541ed8bd1d39b179e /target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch | |
parent | 66543935db1d7eab23fc43b381e56dbd4424b499 (diff) | |
download | mtk-20170518-c957af0a0f6a2c45b9b3c84f45f4a3aa44d293c6.zip mtk-20170518-c957af0a0f6a2c45b9b3c84f45f4a3aa44d293c6.tar.gz mtk-20170518-c957af0a0f6a2c45b9b3c84f45f4a3aa44d293c6.tar.bz2 |
sunxi: initial 3.13 support
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
SVN-Revision: 39471
Diffstat (limited to 'target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch')
-rw-r--r-- | target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch b/target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch new file mode 100644 index 0000000..db54eb8 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch @@ -0,0 +1,297 @@ +From 3bf30f6381f9287eb99ce096bf2fa327a69c8a71 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Thu, 7 Nov 2013 12:01:48 +0100 +Subject: [PATCH] clocksource: Add Allwinner SoCs HS timers driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Most of the Allwinner SoCs (at this time, all but the A10) also have a +High Speed timers that are not using the 24MHz oscillator as a source +but rather the AHB clock running much faster. + +The IP is slightly different between the A10s/A13 and the one used in +the A20/A31, since the latter have 4 timers available, while the former +have only 2 of them. + +[dlezcano] : Fixed conflict with b788beda "Order Kconfig options + alphabetically" + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Tested-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> +--- + .../bindings/timer/allwinner,sun5i-a13-hstimer.txt | 22 +++ + arch/arm/mach-sunxi/Kconfig | 1 + + drivers/clocksource/Kconfig | 4 + + drivers/clocksource/Makefile | 1 + + drivers/clocksource/timer-sun5i.c | 192 +++++++++++++++++++++ + 5 files changed, 220 insertions(+) + create mode 100644 Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt + create mode 100644 drivers/clocksource/timer-sun5i.c + +diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt +new file mode 100644 +index 0000000..7c26154 +--- /dev/null ++++ b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt +@@ -0,0 +1,22 @@ ++Allwinner SoCs High Speed Timer Controller ++ ++Required properties: ++ ++- compatible : should be "allwinner,sun5i-a13-hstimer" or ++ "allwinner,sun7i-a20-hstimer" ++- reg : Specifies base physical address and size of the registers. ++- interrupts : The interrupts of these timers (2 for the sun5i IP, 4 for the sun7i ++ one) ++- clocks: phandle to the source clock (usually the AHB clock) ++ ++Example: ++ ++timer@01c60000 { ++ compatible = "allwinner,sun7i-a20-hstimer"; ++ reg = <0x01c60000 0x1000>; ++ interrupts = <0 51 1>, ++ <0 52 1>, ++ <0 53 1>, ++ <0 54 1>; ++ clocks = <&ahb1_gates 19>; ++}; +diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig +index e3457b9..547004c 100644 +--- a/arch/arm/mach-sunxi/Kconfig ++++ b/arch/arm/mach-sunxi/Kconfig +@@ -13,3 +13,4 @@ config ARCH_SUNXI + select PINCTRL_SUNXI + select SPARSE_IRQ + select SUN4I_TIMER ++ select SUN5I_HSTIMER +diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +index 634c4d6..cd6950f 100644 +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -37,6 +37,10 @@ config SUN4I_TIMER + select CLKSRC_MMIO + bool + ++config SUN5I_HSTIMER ++ select CLKSRC_MMIO ++ bool ++ + config VT8500_TIMER + bool + +diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile +index 33621ef..358358d 100644 +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o + obj-$(CONFIG_ARCH_MXS) += mxs_timer.o + obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o + obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o ++obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o + obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o + obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o + obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o +diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c +new file mode 100644 +index 0000000..bddc522 +--- /dev/null ++++ b/drivers/clocksource/timer-sun5i.c +@@ -0,0 +1,192 @@ ++/* ++ * Allwinner SoCs hstimer driver. ++ * ++ * Copyright (C) 2013 Maxime Ripard ++ * ++ * Maxime Ripard <maxime.ripard@free-electrons.com> ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/clockchips.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++#include <linux/irqreturn.h> ++#include <linux/sched_clock.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_irq.h> ++ ++#define TIMER_IRQ_EN_REG 0x00 ++#define TIMER_IRQ_EN(val) BIT(val) ++#define TIMER_IRQ_ST_REG 0x04 ++#define TIMER_CTL_REG(val) (0x20 * (val) + 0x10) ++#define TIMER_CTL_ENABLE BIT(0) ++#define TIMER_CTL_RELOAD BIT(1) ++#define TIMER_CTL_CLK_PRES(val) (((val) & 0x7) << 4) ++#define TIMER_CTL_ONESHOT BIT(7) ++#define TIMER_INTVAL_LO_REG(val) (0x20 * (val) + 0x14) ++#define TIMER_INTVAL_HI_REG(val) (0x20 * (val) + 0x18) ++#define TIMER_CNTVAL_LO_REG(val) (0x20 * (val) + 0x1c) ++#define TIMER_CNTVAL_HI_REG(val) (0x20 * (val) + 0x20) ++ ++#define TIMER_SYNC_TICKS 3 ++ ++static void __iomem *timer_base; ++static u32 ticks_per_jiffy; ++ ++/* ++ * When we disable a timer, we need to wait at least for 2 cycles of ++ * the timer source clock. We will use for that the clocksource timer ++ * that is already setup and runs at the same frequency than the other ++ * timers, and we never will be disabled. ++ */ ++static void sun5i_clkevt_sync(void) ++{ ++ u32 old = readl(timer_base + TIMER_CNTVAL_LO_REG(1)); ++ ++ while ((old - readl(timer_base + TIMER_CNTVAL_LO_REG(1))) < TIMER_SYNC_TICKS) ++ cpu_relax(); ++} ++ ++static void sun5i_clkevt_time_stop(u8 timer) ++{ ++ u32 val = readl(timer_base + TIMER_CTL_REG(timer)); ++ writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); ++ ++ sun5i_clkevt_sync(); ++} ++ ++static void sun5i_clkevt_time_setup(u8 timer, u32 delay) ++{ ++ writel(delay, timer_base + TIMER_INTVAL_LO_REG(timer)); ++} ++ ++static void sun5i_clkevt_time_start(u8 timer, bool periodic) ++{ ++ u32 val = readl(timer_base + TIMER_CTL_REG(timer)); ++ ++ if (periodic) ++ val &= ~TIMER_CTL_ONESHOT; ++ else ++ val |= TIMER_CTL_ONESHOT; ++ ++ writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, ++ timer_base + TIMER_CTL_REG(timer)); ++} ++ ++static void sun5i_clkevt_mode(enum clock_event_mode mode, ++ struct clock_event_device *clk) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ sun5i_clkevt_time_stop(0); ++ sun5i_clkevt_time_setup(0, ticks_per_jiffy); ++ sun5i_clkevt_time_start(0, true); ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ sun5i_clkevt_time_stop(0); ++ sun5i_clkevt_time_start(0, false); ++ break; ++ case CLOCK_EVT_MODE_UNUSED: ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ default: ++ sun5i_clkevt_time_stop(0); ++ break; ++ } ++} ++ ++static int sun5i_clkevt_next_event(unsigned long evt, ++ struct clock_event_device *unused) ++{ ++ sun5i_clkevt_time_stop(0); ++ sun5i_clkevt_time_setup(0, evt - TIMER_SYNC_TICKS); ++ sun5i_clkevt_time_start(0, false); ++ ++ return 0; ++} ++ ++static struct clock_event_device sun5i_clockevent = { ++ .name = "sun5i_tick", ++ .rating = 340, ++ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, ++ .set_mode = sun5i_clkevt_mode, ++ .set_next_event = sun5i_clkevt_next_event, ++}; ++ ++ ++static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *evt = (struct clock_event_device *)dev_id; ++ ++ writel(0x1, timer_base + TIMER_IRQ_ST_REG); ++ evt->event_handler(evt); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction sun5i_timer_irq = { ++ .name = "sun5i_timer0", ++ .flags = IRQF_TIMER | IRQF_IRQPOLL, ++ .handler = sun5i_timer_interrupt, ++ .dev_id = &sun5i_clockevent, ++}; ++ ++static u32 sun5i_timer_sched_read(void) ++{ ++ return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1)); ++} ++ ++static void __init sun5i_timer_init(struct device_node *node) ++{ ++ unsigned long rate; ++ struct clk *clk; ++ int ret, irq; ++ u32 val; ++ ++ timer_base = of_iomap(node, 0); ++ if (!timer_base) ++ panic("Can't map registers"); ++ ++ irq = irq_of_parse_and_map(node, 0); ++ if (irq <= 0) ++ panic("Can't parse IRQ"); ++ ++ clk = of_clk_get(node, 0); ++ if (IS_ERR(clk)) ++ panic("Can't get timer clock"); ++ clk_prepare_enable(clk); ++ rate = clk_get_rate(clk); ++ ++ writel(~0, timer_base + TIMER_INTVAL_LO_REG(1)); ++ writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, ++ timer_base + TIMER_CTL_REG(1)); ++ ++ setup_sched_clock(sun5i_timer_sched_read, 32, rate); ++ clocksource_mmio_init(timer_base + TIMER_CNTVAL_LO_REG(1), node->name, ++ rate, 340, 32, clocksource_mmio_readl_down); ++ ++ ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); ++ ++ ret = setup_irq(irq, &sun5i_timer_irq); ++ if (ret) ++ pr_warn("failed to setup irq %d\n", irq); ++ ++ /* Enable timer0 interrupt */ ++ val = readl(timer_base + TIMER_IRQ_EN_REG); ++ writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); ++ ++ sun5i_clockevent.cpumask = cpu_possible_mask; ++ sun5i_clockevent.irq = irq; ++ ++ clockevents_config_and_register(&sun5i_clockevent, rate, ++ TIMER_SYNC_TICKS, 0xffffffff); ++} ++CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer", ++ sun5i_timer_init); ++CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", ++ sun5i_timer_init); +-- +1.8.5.1 + |