aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorRaghu Gandham <Raghu.Gandham@imgtec.com>2013-04-10 17:30:12 -0400
committerRalf Baechle <ralf@linux-mips.org>2013-05-09 11:55:21 -0400
commit0ab2b7d08ea7226dc72ff0f8c05f470566facf7c (patch)
tree7b791c6907a47733b1256da5e20600d182b36d40 /arch/mips
parent2675fa7c7b46842f82b2766b5abe80e16ce32977 (diff)
MIPS: Add new GIC clockevent driver.
Add new clockevent driver that uses the counter present on the MIPS Global Interrupt Controller. Signed-off-by: Raghu Gandham <Raghu.Gandham@imgtec.com> Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig12
-rw-r--r--arch/mips/include/asm/gic.h5
-rw-r--r--arch/mips/include/asm/time.h3
-rw-r--r--arch/mips/kernel/Makefile1
-rw-r--r--arch/mips/kernel/cevt-gic.c104
-rw-r--r--arch/mips/kernel/cevt-r4k.c6
-rw-r--r--arch/mips/kernel/irq-gic.c31
-rw-r--r--arch/mips/mti-malta/malta-int.c3
8 files changed, 163 insertions, 2 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 4b623056470e..44e29b64b139 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -912,6 +912,9 @@ config CEVT_GT641XX
912config CEVT_R4K 912config CEVT_R4K
913 bool 913 bool
914 914
915config CEVT_GIC
916 bool
917
915config CEVT_SB1250 918config CEVT_SB1250
916 bool 919 bool
917 920
@@ -1819,6 +1822,15 @@ config FORCE_MAX_ZONEORDER
1819 The page size is not necessarily 4KB. Keep this in mind 1822 The page size is not necessarily 4KB. Keep this in mind
1820 when choosing a value for this option. 1823 when choosing a value for this option.
1821 1824
1825config CEVT_GIC
1826 bool "Use GIC global counter for clock events"
1827 depends on IRQ_GIC && !(MIPS_SEAD3 || MIPS_MT_SMTC)
1828 help
1829 Use the GIC global counter for the clock events. The R4K clock
1830 event driver is always present, so if the platform ends up not
1831 detecting a GIC, it will fall back to the R4K timer for the
1832 generation of clock events.
1833
1822config BOARD_SCACHE 1834config BOARD_SCACHE
1823 bool 1835 bool
1824 1836
diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index 398cf548832a..7153b32de18e 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -202,7 +202,7 @@
202#define GIC_VPE_WD_COUNT0_OFS 0x0094 202#define GIC_VPE_WD_COUNT0_OFS 0x0094
203#define GIC_VPE_WD_INITIAL0_OFS 0x0098 203#define GIC_VPE_WD_INITIAL0_OFS 0x0098
204#define GIC_VPE_COMPARE_LO_OFS 0x00a0 204#define GIC_VPE_COMPARE_LO_OFS 0x00a0
205#define GIC_VPE_COMPARE_HI 0x00a4 205#define GIC_VPE_COMPARE_HI_OFS 0x00a4
206 206
207#define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100 207#define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100
208#define GIC_VPE_EIC_SS(intr) \ 208#define GIC_VPE_EIC_SS(intr) \
@@ -373,7 +373,10 @@ extern void gic_init(unsigned long gic_base_addr,
373 unsigned long gic_addrspace_size, struct gic_intr_map *intrmap, 373 unsigned long gic_addrspace_size, struct gic_intr_map *intrmap,
374 unsigned int intrmap_size, unsigned int irqbase); 374 unsigned int intrmap_size, unsigned int irqbase);
375extern void gic_clocksource_init(unsigned int); 375extern void gic_clocksource_init(unsigned int);
376extern unsigned int gic_compare_int (void);
376extern cycle_t gic_read_count(void); 377extern cycle_t gic_read_count(void);
378extern cycle_t gic_read_compare(void);
379extern void gic_write_compare(cycle_t cnt);
377extern void gic_send_ipi(unsigned int intr); 380extern void gic_send_ipi(unsigned int intr);
378extern unsigned int plat_ipi_call_int_xlate(unsigned int); 381extern unsigned int plat_ipi_call_int_xlate(unsigned int);
379extern unsigned int plat_ipi_resched_int_xlate(unsigned int); 382extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h
index 47842187ae42..2d7b9df4542d 100644
--- a/arch/mips/include/asm/time.h
+++ b/arch/mips/include/asm/time.h
@@ -53,11 +53,14 @@ extern int (*perf_irq)(void);
53extern unsigned int __weak get_c0_compare_int(void); 53extern unsigned int __weak get_c0_compare_int(void);
54extern int r4k_clockevent_init(void); 54extern int r4k_clockevent_init(void);
55extern int smtc_clockevent_init(void); 55extern int smtc_clockevent_init(void);
56extern int gic_clockevent_init(void);
56 57
57static inline int mips_clockevent_init(void) 58static inline int mips_clockevent_init(void)
58{ 59{
59#ifdef CONFIG_MIPS_MT_SMTC 60#ifdef CONFIG_MIPS_MT_SMTC
60 return smtc_clockevent_init(); 61 return smtc_clockevent_init();
62#elif defined(CONFIG_CEVT_GIC)
63 return (gic_clockevent_init() | r4k_clockevent_init());
61#elif defined(CONFIG_CEVT_R4K) 64#elif defined(CONFIG_CEVT_R4K)
62 return r4k_clockevent_init(); 65 return r4k_clockevent_init();
63#else 66#else
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index bab8b16706ca..3d95062173c7 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o
19obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o 19obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o
20obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o 20obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o
21obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o 21obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o
22obj-$(CONFIG_CEVT_GIC) += cevt-gic.o
22obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o 23obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o
23obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o 24obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o
24obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o 25obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o
diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c
new file mode 100644
index 000000000000..730eaf92c018
--- /dev/null
+++ b/arch/mips/kernel/cevt-gic.c
@@ -0,0 +1,104 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2013 Imagination Technologies Ltd.
7 */
8#include <linux/clockchips.h>
9#include <linux/interrupt.h>
10#include <linux/percpu.h>
11#include <linux/smp.h>
12#include <linux/irq.h>
13
14#include <asm/time.h>
15#include <asm/gic.h>
16#include <asm/mips-boards/maltaint.h>
17
18DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device);
19int gic_timer_irq_installed;
20
21
22static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
23{
24 u64 cnt;
25 int res;
26
27 cnt = gic_read_count();
28 cnt += (u64)delta;
29 gic_write_compare(cnt);
30 res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
31 return res;
32}
33
34void gic_set_clock_mode(enum clock_event_mode mode,
35 struct clock_event_device *evt)
36{
37 /* Nothing to do ... */
38}
39
40irqreturn_t gic_compare_interrupt(int irq, void *dev_id)
41{
42 struct clock_event_device *cd;
43 int cpu = smp_processor_id();
44
45 gic_write_compare(gic_read_compare());
46 cd = &per_cpu(gic_clockevent_device, cpu);
47 cd->event_handler(cd);
48 return IRQ_HANDLED;
49}
50
51struct irqaction gic_compare_irqaction = {
52 .handler = gic_compare_interrupt,
53 .flags = IRQF_PERCPU | IRQF_TIMER,
54 .name = "timer",
55};
56
57
58void gic_event_handler(struct clock_event_device *dev)
59{
60}
61
62int __cpuinit gic_clockevent_init(void)
63{
64 unsigned int cpu = smp_processor_id();
65 struct clock_event_device *cd;
66 unsigned int irq;
67
68 if (!cpu_has_counter || !gic_frequency)
69 return -ENXIO;
70
71 irq = MIPS_GIC_IRQ_BASE;
72
73 cd = &per_cpu(gic_clockevent_device, cpu);
74
75 cd->name = "MIPS GIC";
76 cd->features = CLOCK_EVT_FEAT_ONESHOT;
77
78 clockevent_set_clock(cd, gic_frequency);
79
80 /* Calculate the min / max delta */
81 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
82 cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
83
84 cd->rating = 300;
85 cd->irq = irq;
86 cd->cpumask = cpumask_of(cpu);
87 cd->set_next_event = gic_next_event;
88 cd->set_mode = gic_set_clock_mode;
89 cd->event_handler = gic_event_handler;
90
91 clockevents_register_device(cd);
92
93 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002);
94 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK);
95
96 if (gic_timer_irq_installed)
97 return 0;
98
99 gic_timer_irq_installed = 1;
100
101 setup_irq(irq, &gic_compare_irqaction);
102 irq_set_handler(irq, handle_percpu_irq);
103 return 0;
104}
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 0309aefbf713..0613f468f1ad 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -72,6 +72,9 @@ irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
72 /* Clear Count/Compare Interrupt */ 72 /* Clear Count/Compare Interrupt */
73 write_c0_compare(read_c0_compare()); 73 write_c0_compare(read_c0_compare());
74 cd = &per_cpu(mips_clockevent_device, cpu); 74 cd = &per_cpu(mips_clockevent_device, cpu);
75#ifdef CONFIG_CEVT_GIC
76 if (!gic_present)
77#endif
75 cd->event_handler(cd); 78 cd->event_handler(cd);
76 } 79 }
77 80
@@ -203,6 +206,9 @@ int __cpuinit r4k_clockevent_init(void)
203 cd->set_mode = mips_set_clock_mode; 206 cd->set_mode = mips_set_clock_mode;
204 cd->event_handler = mips_event_handler; 207 cd->event_handler = mips_event_handler;
205 208
209#ifdef CONFIG_CEVT_GIC
210 if (!gic_present)
211#endif
206 clockevents_register_device(cd); 212 clockevents_register_device(cd);
207 213
208 if (cp0_timer_irq_installed) 214 if (cp0_timer_irq_installed)
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
index 6a476e1d41eb..c01b307317a9 100644
--- a/arch/mips/kernel/irq-gic.c
+++ b/arch/mips/kernel/irq-gic.c
@@ -33,7 +33,7 @@ static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
33static struct gic_pending_regs pending_regs[NR_CPUS]; 33static struct gic_pending_regs pending_regs[NR_CPUS];
34static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; 34static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
35 35
36#ifdef CONFIG_CSRC_GIC 36#if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
37cycle_t gic_read_count(void) 37cycle_t gic_read_count(void)
38{ 38{
39 unsigned int hi, hi2, lo; 39 unsigned int hi, hi2, lo;
@@ -46,6 +46,24 @@ cycle_t gic_read_count(void)
46 46
47 return (((cycle_t) hi) << 32) + lo; 47 return (((cycle_t) hi) << 32) + lo;
48} 48}
49
50void gic_write_compare(cycle_t cnt)
51{
52 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI),
53 (int)(cnt >> 32));
54 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO),
55 (int)(cnt & 0xffffffff));
56}
57
58cycle_t gic_read_compare(void)
59{
60 unsigned int hi, lo;
61
62 GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), hi);
63 GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), lo);
64
65 return (((cycle_t) hi) << 32) + lo;
66}
49#endif 67#endif
50 68
51unsigned int gic_get_timer_pending(void) 69unsigned int gic_get_timer_pending(void)
@@ -134,6 +152,17 @@ static void __init vpe_local_setup(unsigned int numvpes)
134 } 152 }
135} 153}
136 154
155unsigned int gic_compare_int(void)
156{
157 unsigned int pending;
158
159 GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
160 if (pending & GIC_VPE_PEND_CMP_MSK)
161 return 1;
162 else
163 return 0;
164}
165
137unsigned int gic_get_int(void) 166unsigned int gic_get_int(void)
138{ 167{
139 unsigned int i; 168 unsigned int i;
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index 8e840c20629e..0a1339ac3ec8 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -133,6 +133,9 @@ static void malta_ipi_irqdispatch(void)
133{ 133{
134 int irq; 134 int irq;
135 135
136 if (gic_compare_int())
137 do_IRQ(MIPS_GIC_IRQ_BASE);
138
136 irq = gic_get_int(); 139 irq = gic_get_int();
137 if (irq < 0) 140 if (irq < 0)
138 return; /* interrupt has already been cleared */ 141 return; /* interrupt has already been cleared */