1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Based on linux/arch/mips/kernel/cevt-r4k.c, 7 * linux/arch/mips/jmr3927/rbhma3100/setup.c 8 * 9 * Copyright 2001 MontaVista Software Inc. 10 * Copyright (C) 2000-2001 Toshiba Corporation 11 * Copyright (C) 2007 MIPS Technologies, Inc. 12 * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org> 13 */ 14 #include <linux/init.h> 15 #include <linux/interrupt.h> 16 #include <linux/irq.h> 17 #include <linux/sched_clock.h> 18 #include <asm/time.h> 19 #include <asm/txx9tmr.h> 20 21 #define TCR_BASE (TXx9_TMTCR_CCDE | TXx9_TMTCR_CRE | TXx9_TMTCR_TMODE_ITVL) 22 #define TIMER_CCD 0 /* 1/2 */ 23 #define TIMER_CLK(imclk) ((imclk) / (2 << TIMER_CCD)) 24 25 struct txx9_clocksource { 26 struct clocksource cs; 27 struct txx9_tmr_reg __iomem *tmrptr; 28 }; 29 30 static u64 txx9_cs_read(struct clocksource *cs) 31 { 32 struct txx9_clocksource *txx9_cs = 33 container_of(cs, struct txx9_clocksource, cs); 34 return __raw_readl(&txx9_cs->tmrptr->trr); 35 } 36 37 /* Use 1 bit smaller width to use full bits in that width */ 38 #define TXX9_CLOCKSOURCE_BITS (TXX9_TIMER_BITS - 1) 39 40 static struct txx9_clocksource txx9_clocksource = { 41 .cs = { 42 .name = "TXx9", 43 .rating = 200, 44 .read = txx9_cs_read, 45 .mask = CLOCKSOURCE_MASK(TXX9_CLOCKSOURCE_BITS), 46 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 47 }, 48 }; 49 50 static u64 notrace txx9_read_sched_clock(void) 51 { 52 return __raw_readl(&txx9_clocksource.tmrptr->trr); 53 } 54 55 void __init txx9_clocksource_init(unsigned long baseaddr, 56 unsigned int imbusclk) 57 { 58 struct txx9_tmr_reg __iomem *tmrptr; 59 60 clocksource_register_hz(&txx9_clocksource.cs, TIMER_CLK(imbusclk)); 61 62 tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); 63 __raw_writel(TCR_BASE, &tmrptr->tcr); 64 __raw_writel(0, &tmrptr->tisr); 65 __raw_writel(TIMER_CCD, &tmrptr->ccdr); 66 __raw_writel(TXx9_TMITMR_TZCE, &tmrptr->itmr); 67 __raw_writel(1 << TXX9_CLOCKSOURCE_BITS, &tmrptr->cpra); 68 __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); 69 txx9_clocksource.tmrptr = tmrptr; 70 71 sched_clock_register(txx9_read_sched_clock, TXX9_CLOCKSOURCE_BITS, 72 TIMER_CLK(imbusclk)); 73 } 74 75 struct txx9_clock_event_device { 76 struct clock_event_device cd; 77 struct txx9_tmr_reg __iomem *tmrptr; 78 }; 79 80 static void txx9tmr_stop_and_clear(struct txx9_tmr_reg __iomem *tmrptr) 81 { 82 /* stop and reset counter */ 83 __raw_writel(TCR_BASE, &tmrptr->tcr); 84 /* clear pending interrupt */ 85 __raw_writel(0, &tmrptr->tisr); 86 } 87 88 static int txx9tmr_set_state_periodic(struct clock_event_device *evt) 89 { 90 struct txx9_clock_event_device *txx9_cd = 91 container_of(evt, struct txx9_clock_event_device, cd); 92 struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; 93 94 txx9tmr_stop_and_clear(tmrptr); 95 96 __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, &tmrptr->itmr); 97 /* start timer */ 98 __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> evt->shift, 99 &tmrptr->cpra); 100 __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); 101 return 0; 102 } 103 104 static int txx9tmr_set_state_oneshot(struct clock_event_device *evt) 105 { 106 struct txx9_clock_event_device *txx9_cd = 107 container_of(evt, struct txx9_clock_event_device, cd); 108 struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; 109 110 txx9tmr_stop_and_clear(tmrptr); 111 __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); 112 return 0; 113 } 114 115 static int txx9tmr_set_state_shutdown(struct clock_event_device *evt) 116 { 117 struct txx9_clock_event_device *txx9_cd = 118 container_of(evt, struct txx9_clock_event_device, cd); 119 struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; 120 121 txx9tmr_stop_and_clear(tmrptr); 122 __raw_writel(0, &tmrptr->itmr); 123 return 0; 124 } 125 126 static int txx9tmr_tick_resume(struct clock_event_device *evt) 127 { 128 struct txx9_clock_event_device *txx9_cd = 129 container_of(evt, struct txx9_clock_event_device, cd); 130 struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; 131 132 txx9tmr_stop_and_clear(tmrptr); 133 __raw_writel(TIMER_CCD, &tmrptr->ccdr); 134 __raw_writel(0, &tmrptr->itmr); 135 return 0; 136 } 137 138 static int txx9tmr_set_next_event(unsigned long delta, 139 struct clock_event_device *evt) 140 { 141 struct txx9_clock_event_device *txx9_cd = 142 container_of(evt, struct txx9_clock_event_device, cd); 143 struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; 144 145 txx9tmr_stop_and_clear(tmrptr); 146 /* start timer */ 147 __raw_writel(delta, &tmrptr->cpra); 148 __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); 149 return 0; 150 } 151 152 static struct txx9_clock_event_device txx9_clock_event_device = { 153 .cd = { 154 .name = "TXx9", 155 .features = CLOCK_EVT_FEAT_PERIODIC | 156 CLOCK_EVT_FEAT_ONESHOT, 157 .rating = 200, 158 .set_state_shutdown = txx9tmr_set_state_shutdown, 159 .set_state_periodic = txx9tmr_set_state_periodic, 160 .set_state_oneshot = txx9tmr_set_state_oneshot, 161 .tick_resume = txx9tmr_tick_resume, 162 .set_next_event = txx9tmr_set_next_event, 163 }, 164 }; 165 166 static irqreturn_t txx9tmr_interrupt(int irq, void *dev_id) 167 { 168 struct txx9_clock_event_device *txx9_cd = dev_id; 169 struct clock_event_device *cd = &txx9_cd->cd; 170 struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; 171 172 __raw_writel(0, &tmrptr->tisr); /* ack interrupt */ 173 cd->event_handler(cd); 174 return IRQ_HANDLED; 175 } 176 177 void __init txx9_clockevent_init(unsigned long baseaddr, int irq, 178 unsigned int imbusclk) 179 { 180 struct clock_event_device *cd = &txx9_clock_event_device.cd; 181 struct txx9_tmr_reg __iomem *tmrptr; 182 183 tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); 184 txx9tmr_stop_and_clear(tmrptr); 185 __raw_writel(TIMER_CCD, &tmrptr->ccdr); 186 __raw_writel(0, &tmrptr->itmr); 187 txx9_clock_event_device.tmrptr = tmrptr; 188 189 clockevent_set_clock(cd, TIMER_CLK(imbusclk)); 190 cd->max_delta_ns = 191 clockevent_delta2ns(0xffffffff >> (32 - TXX9_TIMER_BITS), cd); 192 cd->max_delta_ticks = 0xffffffff >> (32 - TXX9_TIMER_BITS); 193 cd->min_delta_ns = clockevent_delta2ns(0xf, cd); 194 cd->min_delta_ticks = 0xf; 195 cd->irq = irq; 196 cd->cpumask = cpumask_of(0); 197 clockevents_register_device(cd); 198 if (request_irq(irq, txx9tmr_interrupt, IRQF_PERCPU | IRQF_TIMER, 199 "txx9tmr", &txx9_clock_event_device)) 200 pr_err("Failed to request irq %d (txx9tmr)\n", irq); 201 printk(KERN_INFO "TXx9: clockevent device at 0x%lx, irq %d\n", 202 baseaddr, irq); 203 } 204 205 void __init txx9_tmr_init(unsigned long baseaddr) 206 { 207 struct txx9_tmr_reg __iomem *tmrptr; 208 209 tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); 210 /* Start once to make CounterResetEnable effective */ 211 __raw_writel(TXx9_TMTCR_CRE | TXx9_TMTCR_TCE, &tmrptr->tcr); 212 /* Stop and reset the counter */ 213 __raw_writel(TXx9_TMTCR_CRE, &tmrptr->tcr); 214 __raw_writel(0, &tmrptr->tisr); 215 __raw_writel(0xffffffff, &tmrptr->cpra); 216 __raw_writel(0, &tmrptr->itmr); 217 __raw_writel(0, &tmrptr->ccdr); 218 __raw_writel(0, &tmrptr->pgmr); 219 iounmap(tmrptr); 220 } 221
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.