timer-fttmr010.c 7.7 KB
Newer Older
1
/*
2
 * Faraday Technology FTTMR010 timer driver
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
 *
 * Based on a rewrite of arch/arm/mach-gemini/timer.c:
 * Copyright (C) 2001-2006 Storlink, Corp.
 * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
 */
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/sched_clock.h>
19
#include <linux/clk.h>
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

/*
 * Register definitions for the timers
 */
#define TIMER1_COUNT		(0x00)
#define TIMER1_LOAD		(0x04)
#define TIMER1_MATCH1		(0x08)
#define TIMER1_MATCH2		(0x0c)
#define TIMER2_COUNT		(0x10)
#define TIMER2_LOAD		(0x14)
#define TIMER2_MATCH1		(0x18)
#define TIMER2_MATCH2		(0x1c)
#define TIMER3_COUNT		(0x20)
#define TIMER3_LOAD		(0x24)
#define TIMER3_MATCH1		(0x28)
#define TIMER3_MATCH2		(0x2c)
#define TIMER_CR		(0x30)
#define TIMER_INTR_STATE	(0x34)
#define TIMER_INTR_MASK		(0x38)

#define TIMER_1_CR_ENABLE	(1 << 0)
#define TIMER_1_CR_CLOCK	(1 << 1)
#define TIMER_1_CR_INT		(1 << 2)
#define TIMER_2_CR_ENABLE	(1 << 3)
#define TIMER_2_CR_CLOCK	(1 << 4)
#define TIMER_2_CR_INT		(1 << 5)
#define TIMER_3_CR_ENABLE	(1 << 6)
#define TIMER_3_CR_CLOCK	(1 << 7)
#define TIMER_3_CR_INT		(1 << 8)
#define TIMER_1_CR_UPDOWN	(1 << 9)
#define TIMER_2_CR_UPDOWN	(1 << 10)
#define TIMER_3_CR_UPDOWN	(1 << 11)
#define TIMER_DEFAULT_FLAGS	(TIMER_1_CR_UPDOWN | \
				 TIMER_3_CR_ENABLE | \
				 TIMER_3_CR_UPDOWN)

#define TIMER_1_INT_MATCH1	(1 << 0)
#define TIMER_1_INT_MATCH2	(1 << 1)
#define TIMER_1_INT_OVERFLOW	(1 << 2)
#define TIMER_2_INT_MATCH1	(1 << 3)
#define TIMER_2_INT_MATCH2	(1 << 4)
#define TIMER_2_INT_OVERFLOW	(1 << 5)
#define TIMER_3_INT_MATCH1	(1 << 6)
#define TIMER_3_INT_MATCH2	(1 << 7)
#define TIMER_3_INT_OVERFLOW	(1 << 8)
#define TIMER_INT_ALL_MASK	0x1ff

static unsigned int tick_rate;
static void __iomem *base;

70
static u64 notrace fttmr010_read_sched_clock(void)
71 72 73 74
{
	return readl(base + TIMER3_COUNT);
}

75
static int fttmr010_timer_set_next_event(unsigned long cycles,
76 77 78 79 80 81 82 83 84 85 86 87 88
				       struct clock_event_device *evt)
{
	u32 cr;

	/* Setup the match register */
	cr = readl(base + TIMER1_COUNT);
	writel(cr + cycles, base + TIMER1_MATCH1);
	if (readl(base + TIMER1_COUNT) - cr > cycles)
		return -ETIME;

	return 0;
}

89
static int fttmr010_timer_shutdown(struct clock_event_device *evt)
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
{
	u32 cr;

	/*
	 * Disable also for oneshot: the set_next() call will arm the timer
	 * instead.
	 */
	/* Stop timer and interrupt. */
	cr = readl(base + TIMER_CR);
	cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
	writel(cr, base + TIMER_CR);

	/* Setup counter start from 0 */
	writel(0, base + TIMER1_COUNT);
	writel(0, base + TIMER1_LOAD);

	/* enable interrupt */
	cr = readl(base + TIMER_INTR_MASK);
	cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
	cr |= TIMER_1_INT_MATCH1;
	writel(cr, base + TIMER_INTR_MASK);

	/* start the timer */
	cr = readl(base + TIMER_CR);
	cr |= TIMER_1_CR_ENABLE;
	writel(cr, base + TIMER_CR);

	return 0;
}

120
static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
{
	u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
	u32 cr;

	/* Stop timer and interrupt */
	cr = readl(base + TIMER_CR);
	cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
	writel(cr, base + TIMER_CR);

	/* Setup timer to fire at 1/HT intervals. */
	cr = 0xffffffff - (period - 1);
	writel(cr, base + TIMER1_COUNT);
	writel(cr, base + TIMER1_LOAD);

	/* enable interrupt on overflow */
	cr = readl(base + TIMER_INTR_MASK);
	cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
	cr |= TIMER_1_INT_OVERFLOW;
	writel(cr, base + TIMER_INTR_MASK);

	/* Start the timer */
	cr = readl(base + TIMER_CR);
	cr |= TIMER_1_CR_ENABLE;
	cr |= TIMER_1_CR_INT;
	writel(cr, base + TIMER_CR);

	return 0;
}

/* Use TIMER1 as clock event */
151
static struct clock_event_device fttmr010_clockevent = {
152 153 154 155 156 157
	.name			= "TIMER1",
	/* Reasonably fast and accurate clock event */
	.rating			= 300,
	.shift                  = 32,
	.features		= CLOCK_EVT_FEAT_PERIODIC |
				  CLOCK_EVT_FEAT_ONESHOT,
158 159 160 161 162
	.set_next_event		= fttmr010_timer_set_next_event,
	.set_state_shutdown	= fttmr010_timer_shutdown,
	.set_state_periodic	= fttmr010_timer_set_periodic,
	.set_state_oneshot	= fttmr010_timer_shutdown,
	.tick_resume		= fttmr010_timer_shutdown,
163 164 165 166 167
};

/*
 * IRQ handler for the timer
 */
168
static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
169
{
170
	struct clock_event_device *evt = &fttmr010_clockevent;
171 172 173 174 175

	evt->event_handler(evt);
	return IRQ_HANDLED;
}

176 177
static struct irqaction fttmr010_timer_irq = {
	.name		= "Faraday FTTMR010 Timer Tick",
178
	.flags		= IRQF_TIMER,
179
	.handler	= fttmr010_timer_interrupt,
180 181
};

182
static int __init fttmr010_timer_common_init(struct device_node *np)
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
{
	int irq;

	base = of_iomap(np, 0);
	if (!base) {
		pr_err("Can't remap registers");
		return -ENXIO;
	}
	/* IRQ for timer 1 */
	irq = irq_of_parse_and_map(np, 0);
	if (irq <= 0) {
		pr_err("Can't parse IRQ");
		return -EINVAL;
	}

	/*
	 * Reset the interrupt mask and status
	 */
	writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK);
	writel(0, base + TIMER_INTR_STATE);
	writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR);

	/*
	 * Setup free-running clocksource timer (interrupts
	 * disabled.)
	 */
	writel(0, base + TIMER3_COUNT);
	writel(0, base + TIMER3_LOAD);
	writel(0, base + TIMER3_MATCH1);
	writel(0, base + TIMER3_MATCH2);
	clocksource_mmio_init(base + TIMER3_COUNT,
214
			      "fttmr010_clocksource", tick_rate,
215
			      300, 32, clocksource_mmio_readl_up);
216
	sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate);
217 218 219 220 221 222 223 224

	/*
	 * Setup clockevent timer (interrupt-driven.)
	 */
	writel(0, base + TIMER1_COUNT);
	writel(0, base + TIMER1_LOAD);
	writel(0, base + TIMER1_MATCH1);
	writel(0, base + TIMER1_MATCH2);
225 226 227
	setup_irq(irq, &fttmr010_timer_irq);
	fttmr010_clockevent.cpumask = cpumask_of(0);
	clockevents_config_and_register(&fttmr010_clockevent, tick_rate,
228 229 230 231
					1, 0xffffffff);

	return 0;
}
232 233 234 235 236 237 238 239 240

static int __init fttmr010_timer_of_init(struct device_node *np)
{
	/*
	 * These implementations require a clock reference.
	 * FIXME: we currently only support clocking using PCLK
	 * and using EXTCLK is not supported in the driver.
	 */
	struct clk *clk;
241
	int ret;
242 243 244

	clk = of_clk_get_by_name(np, "PCLK");
	if (IS_ERR(clk)) {
245
		pr_err("could not get PCLK\n");
246 247
		return PTR_ERR(clk);
	}
248 249 250 251 252
	ret = clk_prepare_enable(clk);
	if (ret) {
		pr_err("failed to enable PCLK\n");
		return ret;
	}
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	tick_rate = clk_get_rate(clk);

	return fttmr010_timer_common_init(np);
}
CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_of_init);

/*
 * Gemini-specific: relevant registers in the global syscon
 */
#define GLOBAL_STATUS		0x04
#define CPU_AHB_RATIO_MASK	(0x3 << 18)
#define CPU_AHB_1_1		(0x0 << 18)
#define CPU_AHB_3_2		(0x1 << 18)
#define CPU_AHB_24_13		(0x2 << 18)
#define CPU_AHB_2_1		(0x3 << 18)
#define REG_TO_AHB_SPEED(reg)	((((reg) >> 15) & 0x7) * 10 + 130)

static int __init gemini_timer_of_init(struct device_node *np)
{
	static struct regmap *map;
	int ret;
	u32 val;

	map = syscon_regmap_lookup_by_phandle(np, "syscon");
	if (IS_ERR(map)) {
		pr_err("Can't get regmap for syscon handle\n");
		return -ENODEV;
	}
	ret = regmap_read(map, GLOBAL_STATUS, &val);
	if (ret) {
		pr_err("Can't read syscon status register\n");
		return -ENXIO;
	}

	tick_rate = REG_TO_AHB_SPEED(val) * 1000000;
	pr_info("Bus: %dMHz ", tick_rate / 1000000);

	tick_rate /= 6;		/* APB bus run AHB*(1/6) */

	switch (val & CPU_AHB_RATIO_MASK) {
	case CPU_AHB_1_1:
		pr_cont("(1/1)\n");
		break;
	case CPU_AHB_3_2:
		pr_cont("(3/2)\n");
		break;
	case CPU_AHB_24_13:
		pr_cont("(24/13)\n");
		break;
	case CPU_AHB_2_1:
		pr_cont("(2/1)\n");
		break;
	}

	return fttmr010_timer_common_init(np);
}
309
CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", gemini_timer_of_init);