timer-tegra20.c 10.2 KB
Newer Older
Colin Cross's avatar
Colin Cross committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Copyright (C) 2010 Google, Inc.
 *
 * Author:
 *	Colin Cross <ccross@google.com>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

18 19 20 21 22
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
23
#include <linux/err.h>
Colin Cross's avatar
Colin Cross committed
24
#include <linux/interrupt.h>
25
#include <linux/of_address.h>
26
#include <linux/of_irq.h>
27
#include <linux/percpu.h>
28
#include <linux/sched_clock.h>
29 30 31
#include <linux/time.h>

#include "timer-of.h"
Colin Cross's avatar
Colin Cross committed
32

33
#ifdef CONFIG_ARM
Colin Cross's avatar
Colin Cross committed
34
#include <asm/mach/time.h>
35
#endif
Colin Cross's avatar
Colin Cross committed
36

37 38 39 40
#define RTC_SECONDS            0x08
#define RTC_SHADOW_SECONDS     0x0c
#define RTC_MILLISECONDS       0x10

Colin Cross's avatar
Colin Cross committed
41 42 43 44
#define TIMERUS_CNTR_1US 0x10
#define TIMERUS_USEC_CFG 0x14
#define TIMERUS_CNTR_FREEZE 0x4c

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#define TIMER_PTV		0x0
#define TIMER_PTV_EN		BIT(31)
#define TIMER_PTV_PER		BIT(30)
#define TIMER_PCR		0x4
#define TIMER_PCR_INTR_CLR	BIT(30)

#ifdef CONFIG_ARM
#define TIMER_CPU0		0x50 /* TIMER3 */
#else
#define TIMER_CPU0		0x90 /* TIMER10 */
#define TIMER10_IRQ_IDX		10
#define IRQ_IDX_FOR_CPU(cpu)	(TIMER10_IRQ_IDX + cpu)
#endif
#define TIMER_BASE_FOR_CPU(cpu) (TIMER_CPU0 + (cpu) * 8)

static u32 usec_config;
61
static void __iomem *timer_reg_base;
62
#ifdef CONFIG_ARM
63
static void __iomem *rtc_base;
64
static struct timespec64 persistent_ts;
65
static u64 persistent_ms, last_persistent_ms;
66
static struct delay_timer tegra_delay_timer;
67
#endif
Colin Cross's avatar
Colin Cross committed
68 69 70 71

static int tegra_timer_set_next_event(unsigned long cycles,
					 struct clock_event_device *evt)
{
72
	void __iomem *reg_base = timer_of_base(to_timer_of(evt));
Colin Cross's avatar
Colin Cross committed
73

74 75 76
	writel(TIMER_PTV_EN |
	       ((cycles > 1) ? (cycles - 1) : 0), /* n+1 scheme */
	       reg_base + TIMER_PTV);
Colin Cross's avatar
Colin Cross committed
77 78 79 80

	return 0;
}

81
static int tegra_timer_shutdown(struct clock_event_device *evt)
Colin Cross's avatar
Colin Cross committed
82
{
83 84 85 86 87
	void __iomem *reg_base = timer_of_base(to_timer_of(evt));

	writel(0, reg_base + TIMER_PTV);

	return 0;
88
}
Colin Cross's avatar
Colin Cross committed
89

90
static int tegra_timer_set_periodic(struct clock_event_device *evt)
91
{
92 93 94 95 96 97
	void __iomem *reg_base = timer_of_base(to_timer_of(evt));

	writel(TIMER_PTV_EN | TIMER_PTV_PER |
	       ((timer_of_rate(to_timer_of(evt)) / HZ) - 1),
	       reg_base + TIMER_PTV);

98 99 100
	return 0;
}

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
static irqreturn_t tegra_timer_isr(int irq, void *dev_id)
{
	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
	void __iomem *reg_base = timer_of_base(to_timer_of(evt));

	writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR);
	evt->event_handler(evt);

	return IRQ_HANDLED;
}

static void tegra_timer_suspend(struct clock_event_device *evt)
{
	void __iomem *reg_base = timer_of_base(to_timer_of(evt));

	writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR);
}

static void tegra_timer_resume(struct clock_event_device *evt)
{
	writel(usec_config, timer_reg_base + TIMERUS_USEC_CFG);
}

#ifdef CONFIG_ARM64
static DEFINE_PER_CPU(struct timer_of, tegra_to) = {
	.flags = TIMER_OF_CLOCK | TIMER_OF_BASE,

	.clkevt = {
		.name = "tegra_timer",
		.rating = 460,
		.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
		.set_next_event = tegra_timer_set_next_event,
		.set_state_shutdown = tegra_timer_shutdown,
		.set_state_periodic = tegra_timer_set_periodic,
		.set_state_oneshot = tegra_timer_shutdown,
		.tick_resume = tegra_timer_shutdown,
		.suspend = tegra_timer_suspend,
		.resume = tegra_timer_resume,
	},
};

static int tegra_timer_setup(unsigned int cpu)
143
{
144 145 146 147 148 149 150 151
	struct timer_of *to = per_cpu_ptr(&tegra_to, cpu);

	irq_force_affinity(to->clkevt.irq, cpumask_of(cpu));
	enable_irq(to->clkevt.irq);

	clockevents_config_and_register(&to->clkevt, timer_of_rate(to),
					1, /* min */
					0x1fffffff); /* 29 bits */
152 153

	return 0;
Colin Cross's avatar
Colin Cross committed
154 155
}

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
static int tegra_timer_stop(unsigned int cpu)
{
	struct timer_of *to = per_cpu_ptr(&tegra_to, cpu);

	to->clkevt.set_state_shutdown(&to->clkevt);
	disable_irq_nosync(to->clkevt.irq);

	return 0;
}
#else /* CONFIG_ARM */
static struct timer_of tegra_to = {
	.flags = TIMER_OF_CLOCK | TIMER_OF_BASE | TIMER_OF_IRQ,

	.clkevt = {
		.name = "tegra_timer",
		.rating	= 300,
		.features = CLOCK_EVT_FEAT_ONESHOT |
			    CLOCK_EVT_FEAT_PERIODIC |
			    CLOCK_EVT_FEAT_DYNIRQ,
		.set_next_event	= tegra_timer_set_next_event,
		.set_state_shutdown = tegra_timer_shutdown,
		.set_state_periodic = tegra_timer_set_periodic,
		.set_state_oneshot = tegra_timer_shutdown,
		.tick_resume = tegra_timer_shutdown,
		.suspend = tegra_timer_suspend,
		.resume = tegra_timer_resume,
		.cpumask = cpu_possible_mask,
	},

	.of_irq = {
		.index = 2,
		.flags = IRQF_TIMER | IRQF_TRIGGER_HIGH,
		.handler = tegra_timer_isr,
	},
Colin Cross's avatar
Colin Cross committed
190 191
};

192
static u64 notrace tegra_read_sched_clock(void)
193
{
194 195 196 197 198 199
	return readl(timer_reg_base + TIMERUS_CNTR_1US);
}

static unsigned long tegra_delay_timer_read_counter_long(void)
{
	return readl(timer_reg_base + TIMERUS_CNTR_1US);
Colin Cross's avatar
Colin Cross committed
200 201
}

202 203 204 205 206 207
/*
 * tegra_rtc_read - Reads the Tegra RTC registers
 * Care must be taken that this funciton is not called while the
 * tegra_rtc driver could be executing to avoid race conditions
 * on the RTC shadow register
 */
208
static u64 tegra_rtc_read_ms(void)
209 210 211 212 213 214 215
{
	u32 ms = readl(rtc_base + RTC_MILLISECONDS);
	u32 s = readl(rtc_base + RTC_SHADOW_SECONDS);
	return (u64)s * MSEC_PER_SEC + ms;
}

/*
216
 * tegra_read_persistent_clock64 -  Return time from a persistent clock.
217 218 219
 *
 * Reads the time from a source which isn't disabled during PM, the
 * 32k sync timer.  Convert the cycles elapsed since last read into
220
 * nsecs and adds to a monotonically increasing timespec64.
221 222 223 224
 * Care must be taken that this funciton is not called while the
 * tegra_rtc driver could be executing to avoid race conditions
 * on the RTC shadow register
 */
225
static void tegra_read_persistent_clock64(struct timespec64 *ts)
226 227 228 229 230 231 232
{
	u64 delta;

	last_persistent_ms = persistent_ms;
	persistent_ms = tegra_rtc_read_ms();
	delta = persistent_ms - last_persistent_ms;

233 234 235
	timespec64_add_ns(&persistent_ts, delta * NSEC_PER_MSEC);
	*ts = persistent_ts;
}
236
#endif
237

238
static int tegra_timer_common_init(struct device_node *np, struct timer_of *to)
Colin Cross's avatar
Colin Cross committed
239
{
240
	int ret = 0;
241

242 243 244
	ret = timer_of_init(np, to);
	if (ret < 0)
		goto out;
245

246
	timer_reg_base = timer_of_base(to);
247

248 249 250 251 252 253
	/*
	 * Configure microsecond timers to have 1MHz clock
	 * Config register is 0xqqww, where qq is "dividend", ww is "divisor"
	 * Uses n+1 scheme
	 */
	switch (timer_of_rate(to)) {
Colin Cross's avatar
Colin Cross committed
254
	case 12000000:
255 256 257 258
		usec_config = 0x000b; /* (11+1)/(0+1) */
		break;
	case 12800000:
		usec_config = 0x043f; /* (63+1)/(4+1) */
Colin Cross's avatar
Colin Cross committed
259 260
		break;
	case 13000000:
261 262 263 264
		usec_config = 0x000c; /* (12+1)/(0+1) */
		break;
	case 16800000:
		usec_config = 0x0453; /* (83+1)/(4+1) */
Colin Cross's avatar
Colin Cross committed
265 266
		break;
	case 19200000:
267
		usec_config = 0x045f; /* (95+1)/(4+1) */
Colin Cross's avatar
Colin Cross committed
268 269
		break;
	case 26000000:
270 271 272 273 274 275 276
		usec_config = 0x0019; /* (25+1)/(0+1) */
		break;
	case 38400000:
		usec_config = 0x04bf; /* (191+1)/(4+1) */
		break;
	case 48000000:
		usec_config = 0x002f; /* (47+1)/(0+1) */
Colin Cross's avatar
Colin Cross committed
277 278
		break;
	default:
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 309 310 311 312
		ret = -EINVAL;
		goto out;
	}

	writel(usec_config, timer_of_base(to) + TIMERUS_USEC_CFG);

out:
	return ret;
}

#ifdef CONFIG_ARM64
static int __init tegra_init_timer(struct device_node *np)
{
	int cpu, ret = 0;
	struct timer_of *to;

	to = this_cpu_ptr(&tegra_to);
	ret = tegra_timer_common_init(np, to);
	if (ret < 0)
		goto out;

	for_each_possible_cpu(cpu) {
		struct timer_of *cpu_to;

		cpu_to = per_cpu_ptr(&tegra_to, cpu);
		cpu_to->of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(cpu);
		cpu_to->of_clk.rate = timer_of_rate(to);
		cpu_to->clkevt.cpumask = cpumask_of(cpu);
		cpu_to->clkevt.irq =
			irq_of_parse_and_map(np, IRQ_IDX_FOR_CPU(cpu));
		if (!cpu_to->clkevt.irq) {
			pr_err("%s: can't map IRQ for CPU%d\n",
			       __func__, cpu);
			ret = -EINVAL;
313
			goto out_irq;
314 315 316 317 318 319 320 321 322
		}

		irq_set_status_flags(cpu_to->clkevt.irq, IRQ_NOAUTOEN);
		ret = request_irq(cpu_to->clkevt.irq, tegra_timer_isr,
				  IRQF_TIMER | IRQF_NOBALANCING,
				  cpu_to->clkevt.name, &cpu_to->clkevt);
		if (ret) {
			pr_err("%s: cannot setup irq %d for CPU%d\n",
				__func__, cpu_to->clkevt.irq, cpu);
323 324
			irq_dispose_mapping(cpu_to->clkevt.irq);
			cpu_to->clkevt.irq = 0;
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
			goto out_irq;
		}
	}

	cpuhp_setup_state(CPUHP_AP_TEGRA_TIMER_STARTING,
			  "AP_TEGRA_TIMER_STARTING", tegra_timer_setup,
			  tegra_timer_stop);

	return ret;
out_irq:
	for_each_possible_cpu(cpu) {
		struct timer_of *cpu_to;

		cpu_to = per_cpu_ptr(&tegra_to, cpu);
		if (cpu_to->clkevt.irq) {
			free_irq(cpu_to->clkevt.irq, &cpu_to->clkevt);
			irq_dispose_mapping(cpu_to->clkevt.irq);
		}
Colin Cross's avatar
Colin Cross committed
343
	}
344 345

	to->of_base.base = timer_reg_base;
346 347 348 349 350 351 352 353 354 355 356 357
out:
	timer_of_cleanup(to);
	return ret;
}
#else /* CONFIG_ARM */
static int __init tegra_init_timer(struct device_node *np)
{
	int ret = 0;

	ret = tegra_timer_common_init(np, &tegra_to);
	if (ret < 0)
		goto out;
Colin Cross's avatar
Colin Cross committed
358

359 360
	tegra_to.of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(0);
	tegra_to.of_clk.rate = 1000000; /* microsecond timer */
361

362 363
	sched_clock_register(tegra_read_sched_clock, 32,
			     timer_of_rate(&tegra_to));
364
	ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,
365 366
				    "timer_us", timer_of_rate(&tegra_to),
				    300, 32, clocksource_mmio_readl_up);
367
	if (ret) {
368
		pr_err("Failed to register clocksource\n");
369
		goto out;
Colin Cross's avatar
Colin Cross committed
370 371
	}

372 373
	tegra_delay_timer.read_current_timer =
			tegra_delay_timer_read_counter_long;
374
	tegra_delay_timer.freq = timer_of_rate(&tegra_to);
375 376
	register_current_timer_delay(&tegra_delay_timer);

377 378 379 380
	clockevents_config_and_register(&tegra_to.clkevt,
					timer_of_rate(&tegra_to),
					0x1,
					0x1fffffff);
Colin Cross's avatar
Colin Cross committed
381

382 383 384
	return ret;
out:
	timer_of_cleanup(&tegra_to);
385

386
	return ret;
387 388
}

389
static int __init tegra20_init_rtc(struct device_node *np)
390 391 392 393 394
{
	struct clk *clk;

	rtc_base = of_iomap(np, 0);
	if (!rtc_base) {
395
		pr_err("Can't map RTC registers\n");
396
		return -ENXIO;
397 398 399 400 401 402
	}

	/*
	 * rtc registers are used by read_persistent_clock, keep the rtc clock
	 * enabled
	 */
403
	clk = of_clk_get(np, 0);
404 405 406 407 408
	if (IS_ERR(clk))
		pr_warn("Unable to get rtc-tegra clock\n");
	else
		clk_prepare_enable(clk);

409
	return register_persistent_clock(tegra_read_persistent_clock64);
Colin Cross's avatar
Colin Cross committed
410
}
411
TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);
412 413 414
#endif
TIMER_OF_DECLARE(tegra210_timer, "nvidia,tegra210-timer", tegra_init_timer);
TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra_init_timer);