diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-03 15:06:09 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-03 15:06:09 -0500 |
commit | 8fd5e7a2d9574b3cac1c9264ad1aed3b613ed6fe (patch) | |
tree | 5696f5d31c6c75b71bfc4852fb234b773e266cfe /drivers/clocksource | |
parent | 529e5fbcd8d3cb48cf824ac8fde91cc80a9e985f (diff) | |
parent | c60ac31542e93499b58dcfc1e3f6550ba5b5728e (diff) |
Merge tag 'metag-v3.9-rc1-v4' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag
Pull new ImgTec Meta architecture from James Hogan:
"This adds core architecture support for Imagination's Meta processor
cores, followed by some later miscellaneous arch/metag cleanups and
fixes which I kept separate to ease review:
- Support for basic Meta 1 (ATP) and Meta 2 (HTP) core architecture
- A few fixes all over, particularly for symbol prefixes
- A few privilege protection fixes
- Several cleanups (setup.c includes, split out a lot of
metag_ksyms.c)
- Fix some missing exports
- Convert hugetlb to use vm_unmapped_area()
- Copy device tree to non-init memory
- Provide dma_get_sgtable()"
* tag 'metag-v3.9-rc1-v4' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag: (61 commits)
metag: Provide dma_get_sgtable()
metag: prom.h: remove declaration of metag_dt_memblock_reserve()
metag: copy devicetree to non-init memory
metag: cleanup metag_ksyms.c includes
metag: move mm/init.c exports out of metag_ksyms.c
metag: move usercopy.c exports out of metag_ksyms.c
metag: move setup.c exports out of metag_ksyms.c
metag: move kick.c exports out of metag_ksyms.c
metag: move traps.c exports out of metag_ksyms.c
metag: move irq enable out of irqflags.h on SMP
genksyms: fix metag symbol prefix on crc symbols
metag: hugetlb: convert to vm_unmapped_area()
metag: export clear_page and copy_page
metag: export metag_code_cache_flush_all
metag: protect more non-MMU memory regions
metag: make TXPRIVEXT bits explicit
metag: kernel/setup.c: sort includes
perf: Enable building perf tools for Meta
metag: add boot time LNKGET/LNKSET check
metag: add __init to metag_cache_probe()
...
Diffstat (limited to 'drivers/clocksource')
-rw-r--r-- | drivers/clocksource/Kconfig | 5 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
-rw-r--r-- | drivers/clocksource/metag_generic.c | 198 |
3 files changed, 204 insertions, 0 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e920cbe519fa..e507ab7df60b 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -62,3 +62,8 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK | |||
62 | 62 | ||
63 | config ARM_ARCH_TIMER | 63 | config ARM_ARCH_TIMER |
64 | bool | 64 | bool |
65 | |||
66 | config CLKSRC_METAG_GENERIC | ||
67 | def_bool y if METAG | ||
68 | help | ||
69 | This option enables support for the Meta per-thread timers. | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 7d671b85a98e..4d8283aec5b5 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -21,3 +21,4 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o | |||
21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o | 21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o |
22 | 22 | ||
23 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o | 23 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
24 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o | ||
diff --git a/drivers/clocksource/metag_generic.c b/drivers/clocksource/metag_generic.c new file mode 100644 index 000000000000..ade7513a11d1 --- /dev/null +++ b/drivers/clocksource/metag_generic.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2013 Imagination Technologies Ltd. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | * | ||
16 | * | ||
17 | * Support for Meta per-thread timers. | ||
18 | * | ||
19 | * Meta hardware threads have 2 timers. The background timer (TXTIMER) is used | ||
20 | * as a free-running time base (hz clocksource), and the interrupt timer | ||
21 | * (TXTIMERI) is used for the timer interrupt (clock event). Both counters | ||
22 | * traditionally count at approximately 1MHz. | ||
23 | */ | ||
24 | |||
25 | #include <clocksource/metag_generic.h> | ||
26 | #include <linux/cpu.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/sched.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/param.h> | ||
31 | #include <linux/time.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/proc_fs.h> | ||
34 | #include <linux/clocksource.h> | ||
35 | #include <linux/clockchips.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | |||
38 | #include <asm/clock.h> | ||
39 | #include <asm/hwthread.h> | ||
40 | #include <asm/core_reg.h> | ||
41 | #include <asm/metag_mem.h> | ||
42 | #include <asm/tbx.h> | ||
43 | |||
44 | #define HARDWARE_FREQ 1000000 /* 1MHz */ | ||
45 | #define HARDWARE_DIV 1 /* divide by 1 = 1MHz clock */ | ||
46 | #define HARDWARE_TO_NS_SHIFT 10 /* convert ticks to ns */ | ||
47 | |||
48 | static unsigned int hwtimer_freq = HARDWARE_FREQ; | ||
49 | static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); | ||
50 | static DEFINE_PER_CPU(char [11], local_clockevent_name); | ||
51 | |||
52 | static int metag_timer_set_next_event(unsigned long delta, | ||
53 | struct clock_event_device *dev) | ||
54 | { | ||
55 | __core_reg_set(TXTIMERI, -delta); | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static void metag_timer_set_mode(enum clock_event_mode mode, | ||
60 | struct clock_event_device *evt) | ||
61 | { | ||
62 | switch (mode) { | ||
63 | case CLOCK_EVT_MODE_ONESHOT: | ||
64 | case CLOCK_EVT_MODE_RESUME: | ||
65 | break; | ||
66 | |||
67 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
68 | /* We should disable the IRQ here */ | ||
69 | break; | ||
70 | |||
71 | case CLOCK_EVT_MODE_PERIODIC: | ||
72 | case CLOCK_EVT_MODE_UNUSED: | ||
73 | WARN_ON(1); | ||
74 | break; | ||
75 | }; | ||
76 | } | ||
77 | |||
78 | static cycle_t metag_clocksource_read(struct clocksource *cs) | ||
79 | { | ||
80 | return __core_reg_get(TXTIMER); | ||
81 | } | ||
82 | |||
83 | static struct clocksource clocksource_metag = { | ||
84 | .name = "META", | ||
85 | .rating = 200, | ||
86 | .mask = CLOCKSOURCE_MASK(32), | ||
87 | .read = metag_clocksource_read, | ||
88 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
89 | }; | ||
90 | |||
91 | static irqreturn_t metag_timer_interrupt(int irq, void *dummy) | ||
92 | { | ||
93 | struct clock_event_device *evt = &__get_cpu_var(local_clockevent); | ||
94 | |||
95 | evt->event_handler(evt); | ||
96 | |||
97 | return IRQ_HANDLED; | ||
98 | } | ||
99 | |||
100 | static struct irqaction metag_timer_irq = { | ||
101 | .name = "META core timer", | ||
102 | .handler = metag_timer_interrupt, | ||
103 | .flags = IRQF_TIMER | IRQF_IRQPOLL | IRQF_PERCPU, | ||
104 | }; | ||
105 | |||
106 | unsigned long long sched_clock(void) | ||
107 | { | ||
108 | unsigned long long ticks = __core_reg_get(TXTIMER); | ||
109 | return ticks << HARDWARE_TO_NS_SHIFT; | ||
110 | } | ||
111 | |||
112 | static void __cpuinit arch_timer_setup(unsigned int cpu) | ||
113 | { | ||
114 | unsigned int txdivtime; | ||
115 | struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); | ||
116 | char *name = per_cpu(local_clockevent_name, cpu); | ||
117 | |||
118 | txdivtime = __core_reg_get(TXDIVTIME); | ||
119 | |||
120 | txdivtime &= ~TXDIVTIME_DIV_BITS; | ||
121 | txdivtime |= (HARDWARE_DIV & TXDIVTIME_DIV_BITS); | ||
122 | |||
123 | __core_reg_set(TXDIVTIME, txdivtime); | ||
124 | |||
125 | sprintf(name, "META %d", cpu); | ||
126 | clk->name = name; | ||
127 | clk->features = CLOCK_EVT_FEAT_ONESHOT, | ||
128 | |||
129 | clk->rating = 200, | ||
130 | clk->shift = 12, | ||
131 | clk->irq = tbisig_map(TBID_SIGNUM_TRT), | ||
132 | clk->set_mode = metag_timer_set_mode, | ||
133 | clk->set_next_event = metag_timer_set_next_event, | ||
134 | |||
135 | clk->mult = div_sc(hwtimer_freq, NSEC_PER_SEC, clk->shift); | ||
136 | clk->max_delta_ns = clockevent_delta2ns(0x7fffffff, clk); | ||
137 | clk->min_delta_ns = clockevent_delta2ns(0xf, clk); | ||
138 | clk->cpumask = cpumask_of(cpu); | ||
139 | |||
140 | clockevents_register_device(clk); | ||
141 | |||
142 | /* | ||
143 | * For all non-boot CPUs we need to synchronize our free | ||
144 | * running clock (TXTIMER) with the boot CPU's clock. | ||
145 | * | ||
146 | * While this won't be accurate, it should be close enough. | ||
147 | */ | ||
148 | if (cpu) { | ||
149 | unsigned int thread0 = cpu_2_hwthread_id[0]; | ||
150 | unsigned long val; | ||
151 | |||
152 | val = core_reg_read(TXUCT_ID, TXTIMER_REGNUM, thread0); | ||
153 | __core_reg_set(TXTIMER, val); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | ||
158 | unsigned long action, void *hcpu) | ||
159 | { | ||
160 | int cpu = (long)hcpu; | ||
161 | |||
162 | switch (action) { | ||
163 | case CPU_STARTING: | ||
164 | case CPU_STARTING_FROZEN: | ||
165 | arch_timer_setup(cpu); | ||
166 | break; | ||
167 | } | ||
168 | |||
169 | return NOTIFY_OK; | ||
170 | } | ||
171 | |||
172 | static struct notifier_block __cpuinitdata arch_timer_cpu_nb = { | ||
173 | .notifier_call = arch_timer_cpu_notify, | ||
174 | }; | ||
175 | |||
176 | int __init metag_generic_timer_init(void) | ||
177 | { | ||
178 | /* | ||
179 | * On Meta 2 SoCs, the actual frequency of the timer is based on the | ||
180 | * Meta core clock speed divided by an integer, so it is only | ||
181 | * approximately 1MHz. Calculating the real frequency here drastically | ||
182 | * reduces clock skew on these SoCs. | ||
183 | */ | ||
184 | #ifdef CONFIG_METAG_META21 | ||
185 | hwtimer_freq = get_coreclock() / (metag_in32(EXPAND_TIMER_DIV) + 1); | ||
186 | #endif | ||
187 | clocksource_register_hz(&clocksource_metag, hwtimer_freq); | ||
188 | |||
189 | setup_irq(tbisig_map(TBID_SIGNUM_TRT), &metag_timer_irq); | ||
190 | |||
191 | /* Configure timer on boot CPU */ | ||
192 | arch_timer_setup(smp_processor_id()); | ||
193 | |||
194 | /* Hook cpu boot to configure other CPU's timers */ | ||
195 | register_cpu_notifier(&arch_timer_cpu_nb); | ||
196 | |||
197 | return 0; | ||
198 | } | ||