0001
0002
0003
0004
0005
0006 #include <linux/bcd.h>
0007 #include <linux/clockchips.h>
0008 #include <linux/init.h>
0009 #include <linux/kernel.h>
0010 #include <linux/sched.h>
0011 #include <linux/sched_clock.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/kernel_stat.h>
0014 #include <linux/param.h>
0015 #include <linux/smp.h>
0016 #include <linux/time.h>
0017 #include <linux/timex.h>
0018 #include <linux/mm.h>
0019 #include <linux/platform_device.h>
0020
0021 #include <asm/time.h>
0022 #include <asm/sgialib.h>
0023 #include <asm/sn/klconfig.h>
0024 #include <asm/sn/arch.h>
0025 #include <asm/sn/addrs.h>
0026 #include <asm/sn/agent.h>
0027
0028 #include "ip27-common.h"
0029
0030 static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
0031 {
0032 unsigned int cpu = smp_processor_id();
0033 int slice = cputoslice(cpu);
0034 unsigned long cnt;
0035
0036 cnt = LOCAL_HUB_L(PI_RT_COUNT);
0037 cnt += delta;
0038 LOCAL_HUB_S(PI_RT_COMPARE_A + PI_COUNT_OFFSET * slice, cnt);
0039
0040 return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0;
0041 }
0042
0043 static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
0044 static DEFINE_PER_CPU(char [11], hub_rt_name);
0045
0046 static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
0047 {
0048 unsigned int cpu = smp_processor_id();
0049 struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
0050 int slice = cputoslice(cpu);
0051
0052
0053
0054
0055 LOCAL_HUB_S(PI_RT_PEND_A + PI_COUNT_OFFSET * slice, 0);
0056 cd->event_handler(cd);
0057
0058 return IRQ_HANDLED;
0059 }
0060
0061 struct irqaction hub_rt_irqaction = {
0062 .handler = hub_rt_counter_handler,
0063 .percpu_dev_id = &hub_rt_clockevent,
0064 .flags = IRQF_PERCPU | IRQF_TIMER,
0065 .name = "hub-rt",
0066 };
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 #define NSEC_PER_CYCLE 800
0077 #define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE)
0078
0079 void hub_rt_clock_event_init(void)
0080 {
0081 unsigned int cpu = smp_processor_id();
0082 struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
0083 unsigned char *name = per_cpu(hub_rt_name, cpu);
0084
0085 sprintf(name, "hub-rt %d", cpu);
0086 cd->name = name;
0087 cd->features = CLOCK_EVT_FEAT_ONESHOT;
0088 clockevent_set_clock(cd, CYCLES_PER_SEC);
0089 cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd);
0090 cd->max_delta_ticks = 0xfffffffffffff;
0091 cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
0092 cd->min_delta_ticks = 0x300;
0093 cd->rating = 200;
0094 cd->irq = IP27_RT_TIMER_IRQ;
0095 cd->cpumask = cpumask_of(cpu);
0096 cd->set_next_event = rt_next_event;
0097 clockevents_register_device(cd);
0098
0099 enable_percpu_irq(IP27_RT_TIMER_IRQ, IRQ_TYPE_NONE);
0100 }
0101
0102 static void __init hub_rt_clock_event_global_init(void)
0103 {
0104 irq_set_handler(IP27_RT_TIMER_IRQ, handle_percpu_devid_irq);
0105 irq_set_percpu_devid(IP27_RT_TIMER_IRQ);
0106 setup_percpu_irq(IP27_RT_TIMER_IRQ, &hub_rt_irqaction);
0107 }
0108
0109 static u64 hub_rt_read(struct clocksource *cs)
0110 {
0111 return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
0112 }
0113
0114 struct clocksource hub_rt_clocksource = {
0115 .name = "HUB-RT",
0116 .rating = 200,
0117 .read = hub_rt_read,
0118 .mask = CLOCKSOURCE_MASK(52),
0119 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
0120 };
0121
0122 static u64 notrace hub_rt_read_sched_clock(void)
0123 {
0124 return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
0125 }
0126
0127 static void __init hub_rt_clocksource_init(void)
0128 {
0129 struct clocksource *cs = &hub_rt_clocksource;
0130
0131 clocksource_register_hz(cs, CYCLES_PER_SEC);
0132
0133 sched_clock_register(hub_rt_read_sched_clock, 52, CYCLES_PER_SEC);
0134 }
0135
0136 void __init plat_time_init(void)
0137 {
0138 hub_rt_clocksource_init();
0139 hub_rt_clock_event_global_init();
0140 hub_rt_clock_event_init();
0141 }
0142
0143 void hub_rtc_init(nasid_t nasid)
0144 {
0145
0146
0147
0148
0149
0150
0151 if (get_nasid() == nasid) {
0152 LOCAL_HUB_S(PI_RT_EN_A, 1);
0153 LOCAL_HUB_S(PI_RT_EN_B, 1);
0154 LOCAL_HUB_S(PI_PROF_EN_A, 0);
0155 LOCAL_HUB_S(PI_PROF_EN_B, 0);
0156 LOCAL_HUB_S(PI_RT_COUNT, 0);
0157 LOCAL_HUB_S(PI_RT_PEND_A, 0);
0158 LOCAL_HUB_S(PI_RT_PEND_B, 0);
0159 }
0160 }