1 /* 2 * Copytight (C) 1999, 2000, 05, 06 Ralf Baechle (ralf@linux-mips.org) 3 * Copytight (C) 1999, 2000 Silicon Graphics, Inc. 4 */ 5 #include <linux/bcd.h> 6 #include <linux/clockchips.h> 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> 16 17 #include <asm/time.h> 18 #include <asm/pgtable.h> 19 #include <asm/sgialib.h> 20 #include <asm/sn/ioc3.h> 21 #include <asm/m48t35.h> 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 29 #define TICK_SIZE (tick_nsec / 1000) 30 31 #if 0 32 static int set_rtc_mmss(unsigned long nowtime) 33 { 34 int retval = 0; 35 int real_seconds, real_minutes, cmos_minutes; 36 struct m48t35_rtc *rtc; 37 nasid_t nid; 38 39 nid = get_nasid(); 40 rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + 41 IOC3_BYTEBUS_DEV0); 42 43 rtc->control |= M48T35_RTC_READ; 44 cmos_minutes = BCD2BIN(rtc->min); 45 rtc->control &= ~M48T35_RTC_READ; 46 47 /* 48 * Since we're only adjusting minutes and seconds, don't interfere with 49 * hour overflow. This avoids messing with unknown time zones but 50 * requires your RTC not to be off by more than 15 minutes 51 */ 52 real_seconds = nowtime % 60; 53 real_minutes = nowtime / 60; 54 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) 55 real_minutes += 30; /* correct for half hour time zone */ 56 real_minutes %= 60; 57 58 if (abs(real_minutes - cmos_minutes) < 30) { 59 real_seconds = BIN2BCD(real_seconds); 60 real_minutes = BIN2BCD(real_minutes); 61 rtc->control |= M48T35_RTC_SET; 62 rtc->sec = real_seconds; 63 rtc->min = real_minutes; 64 rtc->control &= ~M48T35_RTC_SET; 65 } else { 66 printk(KERN_WARNING 67 "set_rtc_mmss: can't update from %d to %d\n", 68 cmos_minutes, real_minutes); 69 retval = -1; 70 } 71 72 return retval; 73 } 74 #endif 75 76 /* Includes for ioc3_init(). */ 77 #include <asm/sn/types.h> 78 #include <asm/sn/sn0/addrs.h> 79 #include <asm/sn/sn0/hubni.h> 80 #include <asm/sn/sn0/hubio.h> 81 #include <asm/pci/bridge.h> 82 83 unsigned long read_persistent_clock(void) 84 { 85 unsigned int year, month, date, hour, min, sec; 86 struct m48t35_rtc *rtc; 87 nasid_t nid; 88 89 nid = get_nasid(); 90 rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + 91 IOC3_BYTEBUS_DEV0); 92 93 rtc->control |= M48T35_RTC_READ; 94 sec = rtc->sec; 95 min = rtc->min; 96 hour = rtc->hour; 97 date = rtc->date; 98 month = rtc->month; 99 year = rtc->year; 100 rtc->control &= ~M48T35_RTC_READ; 101 102 sec = BCD2BIN(sec); 103 min = BCD2BIN(min); 104 hour = BCD2BIN(hour); 105 date = BCD2BIN(date); 106 month = BCD2BIN(month); 107 year = BCD2BIN(year); 108 109 year += 1970; 110 111 return mktime(year, month, date, hour, min, sec); 112 } 113 114 static void enable_rt_irq(unsigned int irq) 115 { 116 } 117 118 static void disable_rt_irq(unsigned int irq) 119 { 120 } 121 122 static struct irq_chip rt_irq_type = { 123 .name = "SN HUB RT timer", 124 .ack = disable_rt_irq, 125 .mask = disable_rt_irq, 126 .mask_ack = disable_rt_irq, 127 .unmask = enable_rt_irq, 128 .eoi = enable_rt_irq, 129 }; 130 131 static int rt_next_event(unsigned long delta, struct clock_event_device *evt) 132 { 133 unsigned int cpu = smp_processor_id(); 134 int slice = cputoslice(cpu); 135 unsigned long cnt; 136 137 cnt = LOCAL_HUB_L(PI_RT_COUNT); 138 cnt += delta; 139 LOCAL_HUB_S(PI_RT_COMPARE_A + PI_COUNT_OFFSET * slice, cnt); 140 141 return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; 142 } 143 144 static void rt_set_mode(enum clock_event_mode mode, 145 struct clock_event_device *evt) 146 { 147 switch (mode) { 148 case CLOCK_EVT_MODE_ONESHOT: 149 /* The only mode supported */ 150 break; 151 152 case CLOCK_EVT_MODE_PERIODIC: 153 case CLOCK_EVT_MODE_UNUSED: 154 case CLOCK_EVT_MODE_SHUTDOWN: 155 case CLOCK_EVT_MODE_RESUME: 156 /* Nothing to do */ 157 break; 158 } 159 } 160 161 int rt_timer_irq; 162 163 static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent); 164 static DEFINE_PER_CPU(char [11], hub_rt_name); 165 166 static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id) 167 { 168 unsigned int cpu = smp_processor_id(); 169 struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu); 170 int slice = cputoslice(cpu); 171 172 /* 173 * Ack 174 */ 175 LOCAL_HUB_S(PI_RT_PEND_A + PI_COUNT_OFFSET * slice, 0); 176 cd->event_handler(cd); 177 178 return IRQ_HANDLED; 179 } 180 181 struct irqaction hub_rt_irqaction = { 182 .handler = hub_rt_counter_handler, 183 .flags = IRQF_DISABLED | IRQF_PERCPU, 184 .name = "hub-rt", 185 }; 186 187 /* 188 * This is a hack; we really need to figure these values out dynamically 189 * 190 * Since 800 ns works very well with various HUB frequencies, such as 191 * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time. 192 * 193 * Ralf: which clock rate is used to feed the counter? 194 */ 195 #define NSEC_PER_CYCLE 800 196 #define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE) 197 198 void __cpuinit hub_rt_clock_event_init(void) 199 { 200 unsigned int cpu = smp_processor_id(); 201 struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu); 202 unsigned char *name = per_cpu(hub_rt_name, cpu); 203 int irq = rt_timer_irq; 204 205 sprintf(name, "hub-rt %d", cpu); 206 cd->name = name; 207 cd->features = CLOCK_EVT_FEAT_ONESHOT; 208 clockevent_set_clock(cd, CYCLES_PER_SEC); 209 cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd); 210 cd->min_delta_ns = clockevent_delta2ns(0x300, cd); 211 cd->rating = 200; 212 cd->irq = irq; 213 cd->cpumask = cpumask_of_cpu(cpu); 214 cd->set_next_event = rt_next_event; 215 cd->set_mode = rt_set_mode; 216 clockevents_register_device(cd); 217 } 218 219 static void __init hub_rt_clock_event_global_init(void) 220 { 221 int irq; 222 223 do { 224 smp_wmb(); 225 irq = rt_timer_irq; 226 if (irq) 227 break; 228 229 irq = allocate_irqno(); 230 if (irq < 0) 231 panic("Allocation of irq number for timer failed"); 232 } while (xchg(&rt_timer_irq, irq)); 233 234 set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq); 235 setup_irq(irq, &hub_rt_irqaction); 236 } 237 238 static cycle_t hub_rt_read(void) 239 { 240 return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); 241 } 242 243 struct clocksource hub_rt_clocksource = { 244 .name = "HUB-RT", 245 .rating = 200, 246 .read = hub_rt_read, 247 .mask = CLOCKSOURCE_MASK(52), 248 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 249 }; 250 251 static void __init hub_rt_clocksource_init(void) 252 { 253 struct clocksource *cs = &hub_rt_clocksource; 254 255 clocksource_set_clock(cs, CYCLES_PER_SEC); 256 clocksource_register(cs); 257 } 258 259 void __init plat_time_init(void) 260 { 261 hub_rt_clocksource_init(); 262 hub_rt_clock_event_global_init(); 263 hub_rt_clock_event_init(); 264 } 265 266 void __cpuinit cpu_time_init(void) 267 { 268 lboard_t *board; 269 klcpu_t *cpu; 270 int cpuid; 271 272 /* Don't use ARCS. ARCS is fragile. Klconfig is simple and sane. */ 273 board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27); 274 if (!board) 275 panic("Can't find board info for myself."); 276 277 cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX; 278 cpu = (klcpu_t *) KLCF_COMP(board, cpuid); 279 if (!cpu) 280 panic("No information about myself?"); 281 282 printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); 283 284 set_c0_status(SRB_TIMOCLK); 285 } 286 287 void __cpuinit hub_rtc_init(cnodeid_t cnode) 288 { 289 /* 290 * We only need to initialize the current node. 291 * If this is not the current node then it is a cpuless 292 * node and timeouts will not happen there. 293 */ 294 if (get_compact_nodeid() == cnode) { 295 LOCAL_HUB_S(PI_RT_EN_A, 1); 296 LOCAL_HUB_S(PI_RT_EN_B, 1); 297 LOCAL_HUB_S(PI_PROF_EN_A, 0); 298 LOCAL_HUB_S(PI_PROF_EN_B, 0); 299 LOCAL_HUB_S(PI_RT_COUNT, 0); 300 LOCAL_HUB_S(PI_RT_PEND_A, 0); 301 LOCAL_HUB_S(PI_RT_PEND_B, 0); 302 } 303 } 304