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/kernel | |
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/kernel')
-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 |
4 files changed, 141 insertions, 1 deletions
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; |