Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
54d0a216 | 2 | * Copytight (C) 1999, 2000, 05, 06 Ralf Baechle (ralf@linux-mips.org) |
1da177e4 LT |
3 | * Copytight (C) 1999, 2000 Silicon Graphics, Inc. |
4 | */ | |
5 | #include <linux/bcd.h> | |
e887b245 | 6 | #include <linux/clockchips.h> |
1da177e4 LT |
7 | #include <linux/init.h> |
8 | #include <linux/kernel.h> | |
9 | #include <linux/sched.h> | |
10 | #include <linux/interrupt.h> | |
11 | #include <linux/kernel_stat.h> | |
12 | #include <linux/param.h> | |
13 | #include <linux/time.h> | |
14 | #include <linux/timex.h> | |
15 | #include <linux/mm.h> | |
3ec066cd | 16 | #include <linux/platform_device.h> |
1da177e4 LT |
17 | |
18 | #include <asm/time.h> | |
19 | #include <asm/pgtable.h> | |
20 | #include <asm/sgialib.h> | |
21 | #include <asm/sn/ioc3.h> | |
1da177e4 LT |
22 | #include <asm/sn/klconfig.h> |
23 | #include <asm/sn/arch.h> | |
24 | #include <asm/sn/addrs.h> | |
25 | #include <asm/sn/sn_private.h> | |
26 | #include <asm/sn/sn0/ip27.h> | |
27 | #include <asm/sn/sn0/hub.h> | |
28 | ||
1da177e4 LT |
29 | #define TICK_SIZE (tick_nsec / 1000) |
30 | ||
1da177e4 LT |
31 | /* Includes for ioc3_init(). */ |
32 | #include <asm/sn/types.h> | |
33 | #include <asm/sn/sn0/addrs.h> | |
34 | #include <asm/sn/sn0/hubni.h> | |
35 | #include <asm/sn/sn0/hubio.h> | |
36 | #include <asm/pci/bridge.h> | |
37 | ||
06d428d7 RB |
38 | static void enable_rt_irq(unsigned int irq) |
39 | { | |
40 | } | |
41 | ||
42 | static void disable_rt_irq(unsigned int irq) | |
43 | { | |
44 | } | |
45 | ||
46 | static struct irq_chip rt_irq_type = { | |
47 | .name = "SN HUB RT timer", | |
48 | .ack = disable_rt_irq, | |
49 | .mask = disable_rt_irq, | |
50 | .mask_ack = disable_rt_irq, | |
51 | .unmask = enable_rt_irq, | |
52 | .eoi = enable_rt_irq, | |
53 | }; | |
54 | ||
55 | static int rt_next_event(unsigned long delta, struct clock_event_device *evt) | |
e887b245 RB |
56 | { |
57 | unsigned int cpu = smp_processor_id(); | |
c8925297 | 58 | int slice = cputoslice(cpu); |
e887b245 RB |
59 | unsigned long cnt; |
60 | ||
61 | cnt = LOCAL_HUB_L(PI_RT_COUNT); | |
62 | cnt += delta; | |
725d7b36 | 63 | LOCAL_HUB_S(PI_RT_COMPARE_A + PI_COUNT_OFFSET * slice, cnt); |
e887b245 RB |
64 | |
65 | return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; | |
66 | } | |
67 | ||
68 | static void rt_set_mode(enum clock_event_mode mode, | |
69 | struct clock_event_device *evt) | |
70 | { | |
71 | switch (mode) { | |
06d428d7 | 72 | case CLOCK_EVT_MODE_ONESHOT: |
e887b245 RB |
73 | /* The only mode supported */ |
74 | break; | |
75 | ||
06d428d7 | 76 | case CLOCK_EVT_MODE_PERIODIC: |
e887b245 RB |
77 | case CLOCK_EVT_MODE_UNUSED: |
78 | case CLOCK_EVT_MODE_SHUTDOWN: | |
e887b245 RB |
79 | case CLOCK_EVT_MODE_RESUME: |
80 | /* Nothing to do */ | |
81 | break; | |
82 | } | |
83 | } | |
84 | ||
d0e7ba06 | 85 | int rt_timer_irq; |
e887b245 | 86 | |
b32bb803 TB |
87 | static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent); |
88 | static DEFINE_PER_CPU(char [11], hub_rt_name); | |
89 | ||
06d428d7 | 90 | static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id) |
e887b245 | 91 | { |
e887b245 | 92 | unsigned int cpu = smp_processor_id(); |
b32bb803 | 93 | struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu); |
725d7b36 | 94 | int slice = cputoslice(cpu); |
e887b245 | 95 | |
725d7b36 RB |
96 | /* |
97 | * Ack | |
98 | */ | |
c8925297 | 99 | LOCAL_HUB_S(PI_RT_PEND_A + PI_COUNT_OFFSET * slice, 0); |
e887b245 RB |
100 | cd->event_handler(cd); |
101 | ||
102 | return IRQ_HANDLED; | |
103 | } | |
104 | ||
06d428d7 RB |
105 | struct irqaction hub_rt_irqaction = { |
106 | .handler = hub_rt_counter_handler, | |
107 | .flags = IRQF_DISABLED | IRQF_PERCPU, | |
108 | .name = "hub-rt", | |
3c009442 RB |
109 | }; |
110 | ||
e887b245 RB |
111 | /* |
112 | * This is a hack; we really need to figure these values out dynamically | |
113 | * | |
114 | * Since 800 ns works very well with various HUB frequencies, such as | |
115 | * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time. | |
116 | * | |
117 | * Ralf: which clock rate is used to feed the counter? | |
118 | */ | |
119 | #define NSEC_PER_CYCLE 800 | |
120 | #define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE) | |
121 | ||
b32bb803 | 122 | void __cpuinit hub_rt_clock_event_init(void) |
1da177e4 | 123 | { |
e887b245 | 124 | unsigned int cpu = smp_processor_id(); |
06d428d7 RB |
125 | struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu); |
126 | unsigned char *name = per_cpu(hub_rt_name, cpu); | |
127 | int irq = rt_timer_irq; | |
128 | ||
129 | sprintf(name, "hub-rt %d", cpu); | |
b32bb803 TB |
130 | cd->name = name; |
131 | cd->features = CLOCK_EVT_FEAT_ONESHOT; | |
06d428d7 RB |
132 | clockevent_set_clock(cd, CYCLES_PER_SEC); |
133 | cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd); | |
134 | cd->min_delta_ns = clockevent_delta2ns(0x300, cd); | |
b32bb803 TB |
135 | cd->rating = 200; |
136 | cd->irq = irq; | |
320ab2b0 | 137 | cd->cpumask = cpumask_of(cpu); |
b32bb803 TB |
138 | cd->set_next_event = rt_next_event; |
139 | cd->set_mode = rt_set_mode; | |
e887b245 | 140 | clockevents_register_device(cd); |
06d428d7 RB |
141 | } |
142 | ||
143 | static void __init hub_rt_clock_event_global_init(void) | |
144 | { | |
d0e7ba06 | 145 | int irq; |
06d428d7 RB |
146 | |
147 | do { | |
148 | smp_wmb(); | |
149 | irq = rt_timer_irq; | |
150 | if (irq) | |
151 | break; | |
152 | ||
153 | irq = allocate_irqno(); | |
154 | if (irq < 0) | |
155 | panic("Allocation of irq number for timer failed"); | |
156 | } while (xchg(&rt_timer_irq, irq)); | |
e887b245 RB |
157 | |
158 | set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq); | |
06d428d7 | 159 | setup_irq(irq, &hub_rt_irqaction); |
1da177e4 LT |
160 | } |
161 | ||
8e19608e | 162 | static cycle_t hub_rt_read(struct clocksource *cs) |
16b7b2ac AN |
163 | { |
164 | return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); | |
165 | } | |
166 | ||
06d428d7 | 167 | struct clocksource hub_rt_clocksource = { |
e887b245 | 168 | .name = "HUB-RT", |
87b2335d RB |
169 | .rating = 200, |
170 | .read = hub_rt_read, | |
171 | .mask = CLOCKSOURCE_MASK(52), | |
87b2335d RB |
172 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
173 | }; | |
174 | ||
06d428d7 | 175 | static void __init hub_rt_clocksource_init(void) |
1da177e4 | 176 | { |
06d428d7 RB |
177 | struct clocksource *cs = &hub_rt_clocksource; |
178 | ||
179 | clocksource_set_clock(cs, CYCLES_PER_SEC); | |
180 | clocksource_register(cs); | |
1da177e4 LT |
181 | } |
182 | ||
e887b245 RB |
183 | void __init plat_time_init(void) |
184 | { | |
06d428d7 RB |
185 | hub_rt_clocksource_init(); |
186 | hub_rt_clock_event_global_init(); | |
b32bb803 | 187 | hub_rt_clock_event_init(); |
e887b245 RB |
188 | } |
189 | ||
06d428d7 | 190 | void __cpuinit cpu_time_init(void) |
1da177e4 LT |
191 | { |
192 | lboard_t *board; | |
193 | klcpu_t *cpu; | |
194 | int cpuid; | |
195 | ||
196 | /* Don't use ARCS. ARCS is fragile. Klconfig is simple and sane. */ | |
197 | board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27); | |
198 | if (!board) | |
199 | panic("Can't find board info for myself."); | |
200 | ||
201 | cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX; | |
202 | cpu = (klcpu_t *) KLCF_COMP(board, cpuid); | |
203 | if (!cpu) | |
204 | panic("No information about myself?"); | |
205 | ||
206 | printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); | |
207 | ||
208 | set_c0_status(SRB_TIMOCLK); | |
209 | } | |
210 | ||
234fcd14 | 211 | void __cpuinit hub_rtc_init(cnodeid_t cnode) |
1da177e4 | 212 | { |
3ec066cd | 213 | |
1da177e4 LT |
214 | /* |
215 | * We only need to initialize the current node. | |
216 | * If this is not the current node then it is a cpuless | |
217 | * node and timeouts will not happen there. | |
218 | */ | |
219 | if (get_compact_nodeid() == cnode) { | |
1da177e4 LT |
220 | LOCAL_HUB_S(PI_RT_EN_A, 1); |
221 | LOCAL_HUB_S(PI_RT_EN_B, 1); | |
222 | LOCAL_HUB_S(PI_PROF_EN_A, 0); | |
223 | LOCAL_HUB_S(PI_PROF_EN_B, 0); | |
1da177e4 LT |
224 | LOCAL_HUB_S(PI_RT_COUNT, 0); |
225 | LOCAL_HUB_S(PI_RT_PEND_A, 0); | |
1da177e4 LT |
226 | LOCAL_HUB_S(PI_RT_PEND_B, 0); |
227 | } | |
228 | } | |
3ec066cd TB |
229 | |
230 | static int __init sgi_ip27_rtc_devinit(void) | |
231 | { | |
232 | struct resource res; | |
233 | ||
234 | memset(&res, 0, sizeof(res)); | |
235 | res.start = XPHYSADDR(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base + | |
236 | IOC3_BYTEBUS_DEV0); | |
237 | res.end = res.start + 32767; | |
238 | res.flags = IORESOURCE_MEM; | |
239 | ||
240 | return IS_ERR(platform_device_register_simple("rtc-m48t35", -1, | |
241 | &res, 1)); | |
242 | } | |
243 | ||
244 | /* | |
245 | * kludge make this a device_initcall after ioc3 resource conflicts | |
246 | * are resolved | |
247 | */ | |
248 | late_initcall(sgi_ip27_rtc_devinit); |