1 /* 2 * Copyright (C) 2000, 2001 Broadcom Corporation 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 #include <linux/clockchips.h> 19 #include <linux/interrupt.h> 20 #include <linux/percpu.h> 21 22 #include <asm/addrspace.h> 23 #include <asm/io.h> 24 #include <asm/time.h> 25 26 #include <asm/sibyte/sb1250.h> 27 #include <asm/sibyte/sb1250_regs.h> 28 #include <asm/sibyte/sb1250_int.h> 29 #include <asm/sibyte/sb1250_scd.h> 30 31 #define IMR_IP2_VAL K_INT_MAP_I0 32 #define IMR_IP3_VAL K_INT_MAP_I1 33 #define IMR_IP4_VAL K_INT_MAP_I2 34 35 /* 36 * The general purpose timer ticks at 1MHz independent if 37 * the rest of the system 38 */ 39 static void sibyte_set_mode(enum clock_event_mode mode, 40 struct clock_event_device *evt) 41 { 42 unsigned int cpu = smp_processor_id(); 43 void __iomem *cfg, *init; 44 45 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); 46 init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); 47 48 switch (mode) { 49 case CLOCK_EVT_MODE_PERIODIC: 50 __raw_writeq(0, cfg); 51 __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); 52 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 53 cfg); 54 break; 55 56 case CLOCK_EVT_MODE_ONESHOT: 57 /* Stop the timer until we actually program a shot */ 58 case CLOCK_EVT_MODE_SHUTDOWN: 59 __raw_writeq(0, cfg); 60 break; 61 62 case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ 63 case CLOCK_EVT_MODE_RESUME: 64 ; 65 } 66 } 67 68 static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) 69 { 70 unsigned int cpu = smp_processor_id(); 71 void __iomem *cfg, *init; 72 73 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); 74 init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); 75 76 __raw_writeq(0, cfg); 77 __raw_writeq(delta - 1, init); 78 __raw_writeq(M_SCD_TIMER_ENABLE, cfg); 79 80 return 0; 81 } 82 83 static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) 84 { 85 unsigned int cpu = smp_processor_id(); 86 struct clock_event_device *cd = dev_id; 87 void __iomem *cfg; 88 unsigned long tmode; 89 90 if (cd->mode == CLOCK_EVT_MODE_PERIODIC) 91 tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; 92 else 93 tmode = 0; 94 95 /* ACK interrupt */ 96 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); 97 ____raw_writeq(tmode, cfg); 98 99 cd->event_handler(cd); 100 101 return IRQ_HANDLED; 102 } 103 104 static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); 105 static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction); 106 static DEFINE_PER_CPU(char [18], sibyte_hpt_name); 107 108 void __cpuinit sb1250_clockevent_init(void) 109 { 110 unsigned int cpu = smp_processor_id(); 111 unsigned int irq = K_INT_TIMER_0 + cpu; 112 struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu); 113 struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); 114 unsigned char *name = per_cpu(sibyte_hpt_name, cpu); 115 116 /* Only have 4 general purpose timers, and we use last one as hpt */ 117 BUG_ON(cpu > 2); 118 119 sprintf(name, "sb1250-counter-%d", cpu); 120 cd->name = name; 121 cd->features = CLOCK_EVT_FEAT_PERIODIC | 122 CLOCK_EVT_FEAT_ONESHOT; 123 clockevent_set_clock(cd, V_SCD_TIMER_FREQ); 124 cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd); 125 cd->min_delta_ns = clockevent_delta2ns(2, cd); 126 cd->rating = 200; 127 cd->irq = irq; 128 cd->cpumask = cpumask_of(cpu); 129 cd->set_next_event = sibyte_next_event; 130 cd->set_mode = sibyte_set_mode; 131 clockevents_register_device(cd); 132 133 sb1250_mask_irq(cpu, irq); 134 135 /* 136 * Map the timer interrupt to IP[4] of this cpu 137 */ 138 __raw_writeq(IMR_IP4_VAL, 139 IOADDR(A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) + 140 (irq << 3))); 141 142 sb1250_unmask_irq(cpu, irq); 143 144 action->handler = sibyte_counter_handler; 145 action->flags = IRQF_DISABLED | IRQF_PERCPU; 146 action->name = name; 147 action->dev_id = cd; 148 149 irq_set_affinity(irq, cpumask_of(cpu)); 150 setup_irq(irq, action); 151 } 152