diff options
author | Raghu Gandham <Raghu.Gandham@imgtec.com> | 2013-04-10 17:30:12 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2013-05-09 11:55:21 -0400 |
commit | 0ab2b7d08ea7226dc72ff0f8c05f470566facf7c (patch) | |
tree | 7b791c6907a47733b1256da5e20600d182b36d40 /arch/mips | |
parent | 2675fa7c7b46842f82b2766b5abe80e16ce32977 (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/Kconfig | 12 | ||||
-rw-r--r-- | arch/mips/include/asm/gic.h | 5 | ||||
-rw-r--r-- | arch/mips/include/asm/time.h | 3 | ||||
-rw-r--r-- | arch/mips/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/kernel/cevt-gic.c | 104 | ||||
-rw-r--r-- | arch/mips/kernel/cevt-r4k.c | 6 | ||||
-rw-r--r-- | arch/mips/kernel/irq-gic.c | 31 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-int.c | 3 |
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 | |||
912 | config CEVT_R4K | 912 | config CEVT_R4K |
913 | bool | 913 | bool |
914 | 914 | ||
915 | config CEVT_GIC | ||
916 | bool | ||
917 | |||
915 | config CEVT_SB1250 | 918 | config 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 | ||
1825 | config 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 | |||
1822 | config BOARD_SCACHE | 1834 | config 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); |
375 | extern void gic_clocksource_init(unsigned int); | 375 | extern void gic_clocksource_init(unsigned int); |
376 | extern unsigned int gic_compare_int (void); | ||
376 | extern cycle_t gic_read_count(void); | 377 | extern cycle_t gic_read_count(void); |
378 | extern cycle_t gic_read_compare(void); | ||
379 | extern void gic_write_compare(cycle_t cnt); | ||
377 | extern void gic_send_ipi(unsigned int intr); | 380 | extern void gic_send_ipi(unsigned int intr); |
378 | extern unsigned int plat_ipi_call_int_xlate(unsigned int); | 381 | extern unsigned int plat_ipi_call_int_xlate(unsigned int); |
379 | extern unsigned int plat_ipi_resched_int_xlate(unsigned int); | 382 | extern 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); | |||
53 | extern unsigned int __weak get_c0_compare_int(void); | 53 | extern unsigned int __weak get_c0_compare_int(void); |
54 | extern int r4k_clockevent_init(void); | 54 | extern int r4k_clockevent_init(void); |
55 | extern int smtc_clockevent_init(void); | 55 | extern int smtc_clockevent_init(void); |
56 | extern int gic_clockevent_init(void); | ||
56 | 57 | ||
57 | static inline int mips_clockevent_init(void) | 58 | static 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 | |||
19 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o | 19 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o |
20 | obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o | 20 | obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o |
21 | obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o | 21 | obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o |
22 | obj-$(CONFIG_CEVT_GIC) += cevt-gic.o | ||
22 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o | 23 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o |
23 | obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o | 24 | obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o |
24 | obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o | 25 | obj-$(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 | |||
18 | DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device); | ||
19 | int gic_timer_irq_installed; | ||
20 | |||
21 | |||
22 | static 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 | |||
34 | void gic_set_clock_mode(enum clock_event_mode mode, | ||
35 | struct clock_event_device *evt) | ||
36 | { | ||
37 | /* Nothing to do ... */ | ||
38 | } | ||
39 | |||
40 | irqreturn_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 | |||
51 | struct irqaction gic_compare_irqaction = { | ||
52 | .handler = gic_compare_interrupt, | ||
53 | .flags = IRQF_PERCPU | IRQF_TIMER, | ||
54 | .name = "timer", | ||
55 | }; | ||
56 | |||
57 | |||
58 | void gic_event_handler(struct clock_event_device *dev) | ||
59 | { | ||
60 | } | ||
61 | |||
62 | int __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]; | |||
33 | static struct gic_pending_regs pending_regs[NR_CPUS]; | 33 | static struct gic_pending_regs pending_regs[NR_CPUS]; |
34 | static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; | 34 | static 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) |
37 | cycle_t gic_read_count(void) | 37 | cycle_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 | |||
50 | void 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 | |||
58 | cycle_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 | ||
51 | unsigned int gic_get_timer_pending(void) | 69 | unsigned 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 | ||
155 | unsigned 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 | |||
137 | unsigned int gic_get_int(void) | 166 | unsigned 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 */ |