1d865bea4SRalf Baechle /* 2d865bea4SRalf Baechle * i8253.c 8253/PIT functions 3d865bea4SRalf Baechle * 4d865bea4SRalf Baechle */ 5d865bea4SRalf Baechle #include <linux/clockchips.h> 6d865bea4SRalf Baechle #include <linux/init.h> 7d865bea4SRalf Baechle #include <linux/interrupt.h> 8d865bea4SRalf Baechle #include <linux/jiffies.h> 9d865bea4SRalf Baechle #include <linux/module.h> 10631330f5SRalf Baechle #include <linux/smp.h> 11d865bea4SRalf Baechle #include <linux/spinlock.h> 12ca4d3e67SDavid Howells #include <linux/irq.h> 13d865bea4SRalf Baechle 14d865bea4SRalf Baechle #include <asm/delay.h> 15d865bea4SRalf Baechle #include <asm/i8253.h> 16d865bea4SRalf Baechle #include <asm/io.h> 17dd3db6ebSRalf Baechle #include <asm/time.h> 18d865bea4SRalf Baechle 19ced918ebSThomas Gleixner DEFINE_RAW_SPINLOCK(i8253_lock); 20a05e623fSRalf Baechle EXPORT_SYMBOL(i8253_lock); 21d865bea4SRalf Baechle 22d865bea4SRalf Baechle /* 23d865bea4SRalf Baechle * Initialize the PIT timer. 24d865bea4SRalf Baechle * 25d865bea4SRalf Baechle * This is also called after resume to bring the PIT into operation again. 26d865bea4SRalf Baechle */ 27d865bea4SRalf Baechle static void init_pit_timer(enum clock_event_mode mode, 28d865bea4SRalf Baechle struct clock_event_device *evt) 29d865bea4SRalf Baechle { 30ced918ebSThomas Gleixner raw_spin_lock(&i8253_lock); 31d865bea4SRalf Baechle 32d865bea4SRalf Baechle switch(mode) { 33d865bea4SRalf Baechle case CLOCK_EVT_MODE_PERIODIC: 34d865bea4SRalf Baechle /* binary, mode 2, LSB/MSB, ch 0 */ 35d865bea4SRalf Baechle outb_p(0x34, PIT_MODE); 36d865bea4SRalf Baechle outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ 37d865bea4SRalf Baechle outb(LATCH >> 8 , PIT_CH0); /* MSB */ 38d865bea4SRalf Baechle break; 39d865bea4SRalf Baechle 40d865bea4SRalf Baechle case CLOCK_EVT_MODE_SHUTDOWN: 41d865bea4SRalf Baechle case CLOCK_EVT_MODE_UNUSED: 42d865bea4SRalf Baechle if (evt->mode == CLOCK_EVT_MODE_PERIODIC || 43d865bea4SRalf Baechle evt->mode == CLOCK_EVT_MODE_ONESHOT) { 44d865bea4SRalf Baechle outb_p(0x30, PIT_MODE); 45d865bea4SRalf Baechle outb_p(0, PIT_CH0); 46d865bea4SRalf Baechle outb_p(0, PIT_CH0); 47d865bea4SRalf Baechle } 48d865bea4SRalf Baechle break; 49d865bea4SRalf Baechle 50d865bea4SRalf Baechle case CLOCK_EVT_MODE_ONESHOT: 51d865bea4SRalf Baechle /* One shot setup */ 52d865bea4SRalf Baechle outb_p(0x38, PIT_MODE); 53d865bea4SRalf Baechle break; 54d865bea4SRalf Baechle 55d865bea4SRalf Baechle case CLOCK_EVT_MODE_RESUME: 56d865bea4SRalf Baechle /* Nothing to do here */ 57d865bea4SRalf Baechle break; 58d865bea4SRalf Baechle } 59ced918ebSThomas Gleixner raw_spin_unlock(&i8253_lock); 60d865bea4SRalf Baechle } 61d865bea4SRalf Baechle 62d865bea4SRalf Baechle /* 63d865bea4SRalf Baechle * Program the next event in oneshot mode 64d865bea4SRalf Baechle * 65d865bea4SRalf Baechle * Delta is given in PIT ticks 66d865bea4SRalf Baechle */ 67d865bea4SRalf Baechle static int pit_next_event(unsigned long delta, struct clock_event_device *evt) 68d865bea4SRalf Baechle { 69ced918ebSThomas Gleixner raw_spin_lock(&i8253_lock); 70d865bea4SRalf Baechle outb_p(delta & 0xff , PIT_CH0); /* LSB */ 71d865bea4SRalf Baechle outb(delta >> 8 , PIT_CH0); /* MSB */ 72ced918ebSThomas Gleixner raw_spin_unlock(&i8253_lock); 73d865bea4SRalf Baechle 74d865bea4SRalf Baechle return 0; 75d865bea4SRalf Baechle } 76d865bea4SRalf Baechle 77d865bea4SRalf Baechle /* 78d865bea4SRalf Baechle * On UP the PIT can serve all of the possible timer functions. On SMP systems 79d865bea4SRalf Baechle * it can be solely used for the global tick. 80d865bea4SRalf Baechle * 81d865bea4SRalf Baechle * The profiling and update capabilites are switched off once the local apic is 82d865bea4SRalf Baechle * registered. This mechanism replaces the previous #ifdef LOCAL_APIC - 83d865bea4SRalf Baechle * !using_apic_timer decisions in do_timer_interrupt_hook() 84d865bea4SRalf Baechle */ 851ea6428cSDmitri Vorobiev static struct clock_event_device pit_clockevent = { 86d865bea4SRalf Baechle .name = "pit", 87d865bea4SRalf Baechle .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 88d865bea4SRalf Baechle .set_mode = init_pit_timer, 89d865bea4SRalf Baechle .set_next_event = pit_next_event, 90d865bea4SRalf Baechle .irq = 0, 91d865bea4SRalf Baechle }; 92d865bea4SRalf Baechle 93dd3db6ebSRalf Baechle static irqreturn_t timer_interrupt(int irq, void *dev_id) 94d865bea4SRalf Baechle { 95d865bea4SRalf Baechle pit_clockevent.event_handler(&pit_clockevent); 96d865bea4SRalf Baechle 97d865bea4SRalf Baechle return IRQ_HANDLED; 98d865bea4SRalf Baechle } 99d865bea4SRalf Baechle 100d865bea4SRalf Baechle static struct irqaction irq0 = { 101d865bea4SRalf Baechle .handler = timer_interrupt, 102f45e5183SWu Zhangjin .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, 103d865bea4SRalf Baechle .name = "timer" 104d865bea4SRalf Baechle }; 105d865bea4SRalf Baechle 106d865bea4SRalf Baechle /* 107d865bea4SRalf Baechle * Initialize the conversion factor and the min/max deltas of the clock event 108d865bea4SRalf Baechle * structure and register the clock event source with the framework. 109d865bea4SRalf Baechle */ 110d865bea4SRalf Baechle void __init setup_pit_timer(void) 111d865bea4SRalf Baechle { 112dd3db6ebSRalf Baechle struct clock_event_device *cd = &pit_clockevent; 113dd3db6ebSRalf Baechle unsigned int cpu = smp_processor_id(); 114dd3db6ebSRalf Baechle 115d865bea4SRalf Baechle /* 116d865bea4SRalf Baechle * Start pit with the boot cpu mask and make it global after the 117d865bea4SRalf Baechle * IO_APIC has been initialized. 118d865bea4SRalf Baechle */ 119320ab2b0SRusty Russell cd->cpumask = cpumask_of(cpu); 120dd3db6ebSRalf Baechle clockevent_set_clock(cd, CLOCK_TICK_RATE); 121dd3db6ebSRalf Baechle cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd); 122dd3db6ebSRalf Baechle cd->min_delta_ns = clockevent_delta2ns(0xF, cd); 123dd3db6ebSRalf Baechle clockevents_register_device(cd); 124d865bea4SRalf Baechle 125d865bea4SRalf Baechle setup_irq(0, &irq0); 126d865bea4SRalf Baechle } 127d865bea4SRalf Baechle 128d865bea4SRalf Baechle static int __init init_pit_clocksource(void) 129d865bea4SRalf Baechle { 130d865bea4SRalf Baechle if (num_possible_cpus() > 1) /* PIT does not scale! */ 131d865bea4SRalf Baechle return 0; 132d865bea4SRalf Baechle 133*798778b8SRussell King return clocksource_i8253_init(); 134d865bea4SRalf Baechle } 135d865bea4SRalf Baechle arch_initcall(init_pit_clocksource); 136