123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /*
- * linux/arch/arm/kernel/arch_timer.c
- *
- * Copyright (C) 2011 ARM Ltd.
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/delay.h>
- #include <linux/device.h>
- #include <linux/smp.h>
- #include <linux/cpu.h>
- #include <linux/jiffies.h>
- #include <linux/clockchips.h>
- #include <linux/interrupt.h>
- #include <linux/of_irq.h>
- #include <linux/io.h>
- #include <asm/cputype.h>
- #include <asm/delay.h>
- #include <asm/localtimer.h>
- #include <asm/arch_timer.h>
- #include <asm/system_info.h>
- #include <asm/sched_clock.h>
- static unsigned long arch_timer_rate;
- enum ppi_nr {
- PHYS_SECURE_PPI,
- PHYS_NONSECURE_PPI,
- VIRT_PPI,
- HYP_PPI,
- MAX_TIMER_PPI
- };
- static int arch_timer_ppi[MAX_TIMER_PPI];
- static struct clock_event_device __percpu **arch_timer_evt;
- static struct delay_timer arch_delay_timer;
- static bool arch_timer_use_virtual = true;
- /*
- * Architected system timer support.
- */
- #define ARCH_TIMER_CTRL_ENABLE (1 << 0)
- #define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
- #define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
- #define ARCH_TIMER_REG_CTRL 0
- #define ARCH_TIMER_REG_FREQ 1
- #define ARCH_TIMER_REG_TVAL 2
- #define ARCH_TIMER_PHYS_ACCESS 0
- #define ARCH_TIMER_VIRT_ACCESS 1
- /*
- * These register accessors are marked inline so the compiler can
- * nicely work out which register we want, and chuck away the rest of
- * the code. At least it does so with a recent GCC (4.6.3).
- */
- static inline void arch_timer_reg_write(const int access, const int reg, u32 val)
- {
- if (access == ARCH_TIMER_PHYS_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
- break;
- }
- }
- if (access == ARCH_TIMER_VIRT_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mcr p15, 0, %0, c14, c3, 0" : : "r" (val));
- break;
- }
- }
- isb();
- }
- static inline u32 arch_timer_reg_read(const int access, const int reg)
- {
- u32 val = 0;
- if (access == ARCH_TIMER_PHYS_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
- break;
- case ARCH_TIMER_REG_FREQ:
- asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
- break;
- }
- }
- if (access == ARCH_TIMER_VIRT_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mrc p15, 0, %0, c14, c3, 0" : "=r" (val));
- break;
- }
- }
- return val;
- }
- static inline cycle_t arch_timer_counter_read(const int access)
- {
- cycle_t cval = 0;
- if (access == ARCH_TIMER_PHYS_ACCESS)
- asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
- if (access == ARCH_TIMER_VIRT_ACCESS)
- asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
- return cval;
- }
- static inline cycle_t arch_counter_get_cntpct(void)
- {
- return arch_timer_counter_read(ARCH_TIMER_PHYS_ACCESS);
- }
- static inline cycle_t arch_counter_get_cntvct(void)
- {
- return arch_timer_counter_read(ARCH_TIMER_VIRT_ACCESS);
- }
- static irqreturn_t inline timer_handler(const int access,
- struct clock_event_device *evt)
- {
- unsigned long ctrl;
- ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
- if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
- ctrl |= ARCH_TIMER_CTRL_IT_MASK;
- arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
- evt->event_handler(evt);
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
- }
- static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id)
- {
- struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
- return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt);
- }
- static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
- {
- struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
- return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
- }
- static inline void timer_set_mode(const int access, int mode)
- {
- unsigned long ctrl;
- switch (mode) {
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
- ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
- arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
- break;
- default:
- break;
|