1f5bf0ee4SLinus Walleij /* 2f5bf0ee4SLinus Walleij * Faraday Technology FTTMR010 timer driver 3f5bf0ee4SLinus Walleij * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> 4f5bf0ee4SLinus Walleij * 5f5bf0ee4SLinus Walleij * Based on a rewrite of arch/arm/mach-gemini/timer.c: 6f5bf0ee4SLinus Walleij * Copyright (C) 2001-2006 Storlink, Corp. 7f5bf0ee4SLinus Walleij * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> 8f5bf0ee4SLinus Walleij */ 9f5bf0ee4SLinus Walleij #include <linux/interrupt.h> 10f5bf0ee4SLinus Walleij #include <linux/io.h> 11f5bf0ee4SLinus Walleij #include <linux/of.h> 12f5bf0ee4SLinus Walleij #include <linux/of_address.h> 13f5bf0ee4SLinus Walleij #include <linux/of_irq.h> 14f5bf0ee4SLinus Walleij #include <linux/clockchips.h> 15f5bf0ee4SLinus Walleij #include <linux/clocksource.h> 16f5bf0ee4SLinus Walleij #include <linux/sched_clock.h> 1728e71e2fSLinus Walleij #include <linux/clk.h> 18f5bf0ee4SLinus Walleij 19f5bf0ee4SLinus Walleij /* 20f5bf0ee4SLinus Walleij * Register definitions for the timers 21f5bf0ee4SLinus Walleij */ 22f5bf0ee4SLinus Walleij #define TIMER1_COUNT (0x00) 23f5bf0ee4SLinus Walleij #define TIMER1_LOAD (0x04) 24f5bf0ee4SLinus Walleij #define TIMER1_MATCH1 (0x08) 25f5bf0ee4SLinus Walleij #define TIMER1_MATCH2 (0x0c) 26f5bf0ee4SLinus Walleij #define TIMER2_COUNT (0x10) 27f5bf0ee4SLinus Walleij #define TIMER2_LOAD (0x14) 28f5bf0ee4SLinus Walleij #define TIMER2_MATCH1 (0x18) 29f5bf0ee4SLinus Walleij #define TIMER2_MATCH2 (0x1c) 30f5bf0ee4SLinus Walleij #define TIMER3_COUNT (0x20) 31f5bf0ee4SLinus Walleij #define TIMER3_LOAD (0x24) 32f5bf0ee4SLinus Walleij #define TIMER3_MATCH1 (0x28) 33f5bf0ee4SLinus Walleij #define TIMER3_MATCH2 (0x2c) 34f5bf0ee4SLinus Walleij #define TIMER_CR (0x30) 35f5bf0ee4SLinus Walleij #define TIMER_INTR_STATE (0x34) 36f5bf0ee4SLinus Walleij #define TIMER_INTR_MASK (0x38) 37f5bf0ee4SLinus Walleij 38f5bf0ee4SLinus Walleij #define TIMER_1_CR_ENABLE (1 << 0) 39f5bf0ee4SLinus Walleij #define TIMER_1_CR_CLOCK (1 << 1) 40f5bf0ee4SLinus Walleij #define TIMER_1_CR_INT (1 << 2) 41f5bf0ee4SLinus Walleij #define TIMER_2_CR_ENABLE (1 << 3) 42f5bf0ee4SLinus Walleij #define TIMER_2_CR_CLOCK (1 << 4) 43f5bf0ee4SLinus Walleij #define TIMER_2_CR_INT (1 << 5) 44f5bf0ee4SLinus Walleij #define TIMER_3_CR_ENABLE (1 << 6) 45f5bf0ee4SLinus Walleij #define TIMER_3_CR_CLOCK (1 << 7) 46f5bf0ee4SLinus Walleij #define TIMER_3_CR_INT (1 << 8) 47f5bf0ee4SLinus Walleij #define TIMER_1_CR_UPDOWN (1 << 9) 48f5bf0ee4SLinus Walleij #define TIMER_2_CR_UPDOWN (1 << 10) 49f5bf0ee4SLinus Walleij #define TIMER_3_CR_UPDOWN (1 << 11) 50f5bf0ee4SLinus Walleij #define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \ 51f5bf0ee4SLinus Walleij TIMER_3_CR_ENABLE | \ 52f5bf0ee4SLinus Walleij TIMER_3_CR_UPDOWN) 53f5bf0ee4SLinus Walleij 54f5bf0ee4SLinus Walleij #define TIMER_1_INT_MATCH1 (1 << 0) 55f5bf0ee4SLinus Walleij #define TIMER_1_INT_MATCH2 (1 << 1) 56f5bf0ee4SLinus Walleij #define TIMER_1_INT_OVERFLOW (1 << 2) 57f5bf0ee4SLinus Walleij #define TIMER_2_INT_MATCH1 (1 << 3) 58f5bf0ee4SLinus Walleij #define TIMER_2_INT_MATCH2 (1 << 4) 59f5bf0ee4SLinus Walleij #define TIMER_2_INT_OVERFLOW (1 << 5) 60f5bf0ee4SLinus Walleij #define TIMER_3_INT_MATCH1 (1 << 6) 61f5bf0ee4SLinus Walleij #define TIMER_3_INT_MATCH2 (1 << 7) 62f5bf0ee4SLinus Walleij #define TIMER_3_INT_OVERFLOW (1 << 8) 63f5bf0ee4SLinus Walleij #define TIMER_INT_ALL_MASK 0x1ff 64f5bf0ee4SLinus Walleij 65f5bf0ee4SLinus Walleij static unsigned int tick_rate; 66f5bf0ee4SLinus Walleij static void __iomem *base; 67f5bf0ee4SLinus Walleij 68f5bf0ee4SLinus Walleij static u64 notrace fttmr010_read_sched_clock(void) 69f5bf0ee4SLinus Walleij { 70f5bf0ee4SLinus Walleij return readl(base + TIMER3_COUNT); 71f5bf0ee4SLinus Walleij } 72f5bf0ee4SLinus Walleij 73f5bf0ee4SLinus Walleij static int fttmr010_timer_set_next_event(unsigned long cycles, 74f5bf0ee4SLinus Walleij struct clock_event_device *evt) 75f5bf0ee4SLinus Walleij { 76f5bf0ee4SLinus Walleij u32 cr; 77f5bf0ee4SLinus Walleij 78f5bf0ee4SLinus Walleij /* Setup the match register */ 79f5bf0ee4SLinus Walleij cr = readl(base + TIMER1_COUNT); 80f5bf0ee4SLinus Walleij writel(cr + cycles, base + TIMER1_MATCH1); 81f5bf0ee4SLinus Walleij if (readl(base + TIMER1_COUNT) - cr > cycles) 82f5bf0ee4SLinus Walleij return -ETIME; 83f5bf0ee4SLinus Walleij 84f5bf0ee4SLinus Walleij return 0; 85f5bf0ee4SLinus Walleij } 86f5bf0ee4SLinus Walleij 87f5bf0ee4SLinus Walleij static int fttmr010_timer_shutdown(struct clock_event_device *evt) 88f5bf0ee4SLinus Walleij { 89f5bf0ee4SLinus Walleij u32 cr; 90f5bf0ee4SLinus Walleij 91f5bf0ee4SLinus Walleij /* 92f5bf0ee4SLinus Walleij * Disable also for oneshot: the set_next() call will arm the timer 93f5bf0ee4SLinus Walleij * instead. 94f5bf0ee4SLinus Walleij */ 95f5bf0ee4SLinus Walleij /* Stop timer and interrupt. */ 96f5bf0ee4SLinus Walleij cr = readl(base + TIMER_CR); 97f5bf0ee4SLinus Walleij cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); 98f5bf0ee4SLinus Walleij writel(cr, base + TIMER_CR); 99f5bf0ee4SLinus Walleij 100f5bf0ee4SLinus Walleij /* Setup counter start from 0 */ 101f5bf0ee4SLinus Walleij writel(0, base + TIMER1_COUNT); 102f5bf0ee4SLinus Walleij writel(0, base + TIMER1_LOAD); 103f5bf0ee4SLinus Walleij 104f5bf0ee4SLinus Walleij /* enable interrupt */ 105f5bf0ee4SLinus Walleij cr = readl(base + TIMER_INTR_MASK); 106f5bf0ee4SLinus Walleij cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); 107f5bf0ee4SLinus Walleij cr |= TIMER_1_INT_MATCH1; 108f5bf0ee4SLinus Walleij writel(cr, base + TIMER_INTR_MASK); 109f5bf0ee4SLinus Walleij 110f5bf0ee4SLinus Walleij /* start the timer */ 111f5bf0ee4SLinus Walleij cr = readl(base + TIMER_CR); 112f5bf0ee4SLinus Walleij cr |= TIMER_1_CR_ENABLE; 113f5bf0ee4SLinus Walleij writel(cr, base + TIMER_CR); 114f5bf0ee4SLinus Walleij 115f5bf0ee4SLinus Walleij return 0; 116f5bf0ee4SLinus Walleij } 117f5bf0ee4SLinus Walleij 118f5bf0ee4SLinus Walleij static int fttmr010_timer_set_periodic(struct clock_event_device *evt) 119f5bf0ee4SLinus Walleij { 120f5bf0ee4SLinus Walleij u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ); 121f5bf0ee4SLinus Walleij u32 cr; 122f5bf0ee4SLinus Walleij 123f5bf0ee4SLinus Walleij /* Stop timer and interrupt */ 124f5bf0ee4SLinus Walleij cr = readl(base + TIMER_CR); 125f5bf0ee4SLinus Walleij cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); 126f5bf0ee4SLinus Walleij writel(cr, base + TIMER_CR); 127f5bf0ee4SLinus Walleij 128f5bf0ee4SLinus Walleij /* Setup timer to fire at 1/HT intervals. */ 129f5bf0ee4SLinus Walleij cr = 0xffffffff - (period - 1); 130f5bf0ee4SLinus Walleij writel(cr, base + TIMER1_COUNT); 131f5bf0ee4SLinus Walleij writel(cr, base + TIMER1_LOAD); 132f5bf0ee4SLinus Walleij 133f5bf0ee4SLinus Walleij /* enable interrupt on overflow */ 134f5bf0ee4SLinus Walleij cr = readl(base + TIMER_INTR_MASK); 135f5bf0ee4SLinus Walleij cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); 136f5bf0ee4SLinus Walleij cr |= TIMER_1_INT_OVERFLOW; 137f5bf0ee4SLinus Walleij writel(cr, base + TIMER_INTR_MASK); 138f5bf0ee4SLinus Walleij 139f5bf0ee4SLinus Walleij /* Start the timer */ 140f5bf0ee4SLinus Walleij cr = readl(base + TIMER_CR); 141f5bf0ee4SLinus Walleij cr |= TIMER_1_CR_ENABLE; 142f5bf0ee4SLinus Walleij cr |= TIMER_1_CR_INT; 143f5bf0ee4SLinus Walleij writel(cr, base + TIMER_CR); 144f5bf0ee4SLinus Walleij 145f5bf0ee4SLinus Walleij return 0; 146f5bf0ee4SLinus Walleij } 147f5bf0ee4SLinus Walleij 148f5bf0ee4SLinus Walleij /* Use TIMER1 as clock event */ 149f5bf0ee4SLinus Walleij static struct clock_event_device fttmr010_clockevent = { 150f5bf0ee4SLinus Walleij .name = "TIMER1", 151f5bf0ee4SLinus Walleij /* Reasonably fast and accurate clock event */ 152f5bf0ee4SLinus Walleij .rating = 300, 153f5bf0ee4SLinus Walleij .shift = 32, 154f5bf0ee4SLinus Walleij .features = CLOCK_EVT_FEAT_PERIODIC | 155f5bf0ee4SLinus Walleij CLOCK_EVT_FEAT_ONESHOT, 156f5bf0ee4SLinus Walleij .set_next_event = fttmr010_timer_set_next_event, 157f5bf0ee4SLinus Walleij .set_state_shutdown = fttmr010_timer_shutdown, 158f5bf0ee4SLinus Walleij .set_state_periodic = fttmr010_timer_set_periodic, 159f5bf0ee4SLinus Walleij .set_state_oneshot = fttmr010_timer_shutdown, 160f5bf0ee4SLinus Walleij .tick_resume = fttmr010_timer_shutdown, 161f5bf0ee4SLinus Walleij }; 162f5bf0ee4SLinus Walleij 163f5bf0ee4SLinus Walleij /* 164f5bf0ee4SLinus Walleij * IRQ handler for the timer 165f5bf0ee4SLinus Walleij */ 166f5bf0ee4SLinus Walleij static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) 167f5bf0ee4SLinus Walleij { 168f5bf0ee4SLinus Walleij struct clock_event_device *evt = &fttmr010_clockevent; 169f5bf0ee4SLinus Walleij 170f5bf0ee4SLinus Walleij evt->event_handler(evt); 171f5bf0ee4SLinus Walleij return IRQ_HANDLED; 172f5bf0ee4SLinus Walleij } 173f5bf0ee4SLinus Walleij 174f5bf0ee4SLinus Walleij static struct irqaction fttmr010_timer_irq = { 175f5bf0ee4SLinus Walleij .name = "Faraday FTTMR010 Timer Tick", 176f5bf0ee4SLinus Walleij .flags = IRQF_TIMER, 177f5bf0ee4SLinus Walleij .handler = fttmr010_timer_interrupt, 178f5bf0ee4SLinus Walleij }; 179f5bf0ee4SLinus Walleij 180*dd98442eSLinus Walleij static int __init fttmr010_timer_init(struct device_node *np) 181f5bf0ee4SLinus Walleij { 182f5bf0ee4SLinus Walleij int irq; 183*dd98442eSLinus Walleij struct clk *clk; 184*dd98442eSLinus Walleij int ret; 185*dd98442eSLinus Walleij 186*dd98442eSLinus Walleij /* 187*dd98442eSLinus Walleij * These implementations require a clock reference. 188*dd98442eSLinus Walleij * FIXME: we currently only support clocking using PCLK 189*dd98442eSLinus Walleij * and using EXTCLK is not supported in the driver. 190*dd98442eSLinus Walleij */ 191*dd98442eSLinus Walleij clk = of_clk_get_by_name(np, "PCLK"); 192*dd98442eSLinus Walleij if (IS_ERR(clk)) { 193*dd98442eSLinus Walleij pr_err("could not get PCLK\n"); 194*dd98442eSLinus Walleij return PTR_ERR(clk); 195*dd98442eSLinus Walleij } 196*dd98442eSLinus Walleij ret = clk_prepare_enable(clk); 197*dd98442eSLinus Walleij if (ret) { 198*dd98442eSLinus Walleij pr_err("failed to enable PCLK\n"); 199*dd98442eSLinus Walleij return ret; 200*dd98442eSLinus Walleij } 201*dd98442eSLinus Walleij tick_rate = clk_get_rate(clk); 202f5bf0ee4SLinus Walleij 203f5bf0ee4SLinus Walleij base = of_iomap(np, 0); 204f5bf0ee4SLinus Walleij if (!base) { 205f5bf0ee4SLinus Walleij pr_err("Can't remap registers"); 206f5bf0ee4SLinus Walleij return -ENXIO; 207f5bf0ee4SLinus Walleij } 208f5bf0ee4SLinus Walleij /* IRQ for timer 1 */ 209f5bf0ee4SLinus Walleij irq = irq_of_parse_and_map(np, 0); 210f5bf0ee4SLinus Walleij if (irq <= 0) { 211f5bf0ee4SLinus Walleij pr_err("Can't parse IRQ"); 212f5bf0ee4SLinus Walleij return -EINVAL; 213f5bf0ee4SLinus Walleij } 214f5bf0ee4SLinus Walleij 215f5bf0ee4SLinus Walleij /* 216f5bf0ee4SLinus Walleij * Reset the interrupt mask and status 217f5bf0ee4SLinus Walleij */ 218f5bf0ee4SLinus Walleij writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK); 219f5bf0ee4SLinus Walleij writel(0, base + TIMER_INTR_STATE); 220f5bf0ee4SLinus Walleij writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR); 221f5bf0ee4SLinus Walleij 222f5bf0ee4SLinus Walleij /* 223f5bf0ee4SLinus Walleij * Setup free-running clocksource timer (interrupts 224f5bf0ee4SLinus Walleij * disabled.) 225f5bf0ee4SLinus Walleij */ 226f5bf0ee4SLinus Walleij writel(0, base + TIMER3_COUNT); 227f5bf0ee4SLinus Walleij writel(0, base + TIMER3_LOAD); 228f5bf0ee4SLinus Walleij writel(0, base + TIMER3_MATCH1); 229f5bf0ee4SLinus Walleij writel(0, base + TIMER3_MATCH2); 230f5bf0ee4SLinus Walleij clocksource_mmio_init(base + TIMER3_COUNT, 231f5bf0ee4SLinus Walleij "fttmr010_clocksource", tick_rate, 232f5bf0ee4SLinus Walleij 300, 32, clocksource_mmio_readl_up); 233f5bf0ee4SLinus Walleij sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate); 234f5bf0ee4SLinus Walleij 235f5bf0ee4SLinus Walleij /* 236f5bf0ee4SLinus Walleij * Setup clockevent timer (interrupt-driven.) 237f5bf0ee4SLinus Walleij */ 238f5bf0ee4SLinus Walleij writel(0, base + TIMER1_COUNT); 239f5bf0ee4SLinus Walleij writel(0, base + TIMER1_LOAD); 240f5bf0ee4SLinus Walleij writel(0, base + TIMER1_MATCH1); 241f5bf0ee4SLinus Walleij writel(0, base + TIMER1_MATCH2); 242f5bf0ee4SLinus Walleij setup_irq(irq, &fttmr010_timer_irq); 243f5bf0ee4SLinus Walleij fttmr010_clockevent.cpumask = cpumask_of(0); 244f5bf0ee4SLinus Walleij clockevents_config_and_register(&fttmr010_clockevent, tick_rate, 245f5bf0ee4SLinus Walleij 1, 0xffffffff); 246f5bf0ee4SLinus Walleij 247f5bf0ee4SLinus Walleij return 0; 248f5bf0ee4SLinus Walleij } 249*dd98442eSLinus Walleij CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); 250*dd98442eSLinus Walleij CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); 251