generic_timer.c (269605) | generic_timer.c (271189) |
---|---|
1/*- 2 * Copyright (c) 2011 The FreeBSD Foundation 3 * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> 4 * All rights reserved. 5 * 6 * Based on mpcore_timer.c developed by Ben Gray <ben.r.gray@gmail.com> 7 * 8 * Redistribution and use in source and binary forms, with or without --- 21 unchanged lines hidden (view full) --- 30 * SUCH DAMAGE. 31 */ 32 33/** 34 * Cortex-A15 (and probably A7) Generic Timer 35 */ 36 37#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2011 The FreeBSD Foundation 3 * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> 4 * All rights reserved. 5 * 6 * Based on mpcore_timer.c developed by Ben Gray <ben.r.gray@gmail.com> 7 * 8 * Redistribution and use in source and binary forms, with or without --- 21 unchanged lines hidden (view full) --- 30 * SUCH DAMAGE. 31 */ 32 33/** 34 * Cortex-A15 (and probably A7) Generic Timer 35 */ 36 37#include <sys/cdefs.h> |
38__FBSDID("$FreeBSD: head/sys/arm/arm/generic_timer.c 269605 2014-08-05 18:51:51Z ian $"); | 38__FBSDID("$FreeBSD: head/sys/arm/arm/generic_timer.c 271189 2014-09-06 13:21:07Z andrew $"); |
39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/bus.h> 43#include <sys/kernel.h> 44#include <sys/module.h> 45#include <sys/malloc.h> 46#include <sys/rman.h> --- 15 unchanged lines hidden (view full) --- 62#define GT_CTRL_ENABLE (1 << 0) 63#define GT_CTRL_INT_MASK (1 << 1) 64#define GT_CTRL_INT_STAT (1 << 2) 65#define GT_REG_CTRL 0 66#define GT_REG_TVAL 1 67 68#define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ 69#define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ | 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/bus.h> 43#include <sys/kernel.h> 44#include <sys/module.h> 45#include <sys/malloc.h> 46#include <sys/rman.h> --- 15 unchanged lines hidden (view full) --- 62#define GT_CTRL_ENABLE (1 << 0) 63#define GT_CTRL_INT_MASK (1 << 1) 64#define GT_CTRL_INT_STAT (1 << 2) 65#define GT_REG_CTRL 0 66#define GT_REG_TVAL 1 67 68#define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ 69#define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ |
70#define GT_CNTKCTL_EVNTI (1 << 4) /* Virtual counter event bits */ | 70#define GT_CNTKCTL_EVNTI (0xf << 4) /* Virtual counter event bits */ |
71#define GT_CNTKCTL_EVNTDIR (1 << 3) /* Virtual counter event transition */ 72#define GT_CNTKCTL_EVNTEN (1 << 2) /* Enables virtual counter events */ 73#define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */ 74#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ 75 76struct arm_tmr_softc { 77 struct resource *res[4]; 78 void *ihl[4]; 79 uint32_t clkfreq; 80 struct eventtimer et; | 71#define GT_CNTKCTL_EVNTDIR (1 << 3) /* Virtual counter event transition */ 72#define GT_CNTKCTL_EVNTEN (1 << 2) /* Enables virtual counter events */ 73#define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */ 74#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ 75 76struct arm_tmr_softc { 77 struct resource *res[4]; 78 void *ihl[4]; 79 uint32_t clkfreq; 80 struct eventtimer et; |
81 bool physical; |
|
81}; 82 83static struct arm_tmr_softc *arm_tmr_sc = NULL; 84 85static struct resource_spec timer_spec[] = { 86 { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ 87 { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ 88 { SYS_RES_IRQ, 2, RF_ACTIVE }, /* Virt */ --- 7 unchanged lines hidden (view full) --- 96 .tc_name = "ARM MPCore Timecounter", 97 .tc_get_timecount = arm_tmr_get_timecount, 98 .tc_poll_pps = NULL, 99 .tc_counter_mask = ~0u, 100 .tc_frequency = 0, 101 .tc_quality = 1000, 102}; 103 | 82}; 83 84static struct arm_tmr_softc *arm_tmr_sc = NULL; 85 86static struct resource_spec timer_spec[] = { 87 { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ 88 { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ 89 { SYS_RES_IRQ, 2, RF_ACTIVE }, /* Virt */ --- 7 unchanged lines hidden (view full) --- 97 .tc_name = "ARM MPCore Timecounter", 98 .tc_get_timecount = arm_tmr_get_timecount, 99 .tc_poll_pps = NULL, 100 .tc_counter_mask = ~0u, 101 .tc_frequency = 0, 102 .tc_quality = 1000, 103}; 104 |
104static inline int | 105static int |
105get_freq(void) 106{ 107 uint32_t val; 108 | 106get_freq(void) 107{ 108 uint32_t val; 109 |
110 /* cntfrq */ |
|
109 __asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val)); 110 111 return (val); 112} 113 | 111 __asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val)); 112 113 return (val); 114} 115 |
114static inline int 115set_freq(uint32_t val) | 116static long 117get_cntxct(bool physical) |
116{ | 118{ |
119 uint64_t val; |
|
117 | 120 |
118 __asm volatile("mcr p15, 0, %[val], c14, c0, 0" : : 119 [val] "r" (val)); | |
120 isb(); | 121 isb(); |
122 if (physical) 123 /* cntpct */ 124 __asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (val)); 125 else 126 /* cntvct */ 127 __asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (val)); |
|
121 122 return (val); 123} 124 | 128 129 return (val); 130} 131 |
125 126static inline long 127get_cntpct(void) | 132static int 133set_ctrl(uint32_t val, bool physical) |
128{ | 134{ |
129 uint64_t val; | |
130 | 135 |
131 __asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (val)); 132 133 return (val); 134} 135 136static inline int 137set_ctrl(uint32_t val) 138{ 139 140 __asm volatile("mcr p15, 0, %[val], c14, c2, 1" : : 141 [val] "r" (val)); | 136 if (physical) 137 /* cntp_ctl */ 138 __asm volatile("mcr p15, 0, %[val], c14, c2, 1" : : 139 [val] "r" (val)); 140 else 141 /* cntv_ctl */ 142 __asm volatile("mcr p15, 0, %[val], c14, c3, 1" : : 143 [val] "r" (val)); |
142 isb(); 143 144 return (0); 145} 146 | 144 isb(); 145 146 return (0); 147} 148 |
147static inline int 148set_tval(uint32_t val) | 149static int 150set_tval(uint32_t val, bool physical) |
149{ 150 | 151{ 152 |
151 __asm volatile("mcr p15, 0, %[val], c14, c2, 0" : : 152 [val] "r" (val)); | 153 if (physical) 154 /* cntp_tval */ 155 __asm volatile("mcr p15, 0, %[val], c14, c2, 0" : : 156 [val] "r" (val)); 157 else 158 /* cntv_tval */ 159 __asm volatile("mcr p15, 0, %[val], c14, c3, 0" : : 160 [val] "r" (val)); |
153 isb(); 154 155 return (0); 156} 157 | 161 isb(); 162 163 return (0); 164} 165 |
158static inline int 159get_ctrl(void) | 166static int 167get_ctrl(bool physical) |
160{ 161 uint32_t val; 162 | 168{ 169 uint32_t val; 170 |
163 __asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); | 171 if (physical) 172 /* cntp_ctl */ 173 __asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); 174 else 175 /* cntv_ctl */ 176 __asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val)); |
164 165 return (val); 166} 167 | 177 178 return (val); 179} 180 |
168static inline int 169get_tval(void) 170{ 171 uint32_t val; 172 173 __asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val)); 174 175 return (val); 176} 177 178static inline void | 181static void |
179disable_user_access(void) 180{ 181 uint32_t cntkctl; 182 183 __asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl)); 184 cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN | 185 GT_CNTKCTL_EVNTEN | GT_CNTKCTL_PL0VCTEN | GT_CNTKCTL_PL0PCTEN); 186 __asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); 187 isb(); 188} 189 190static unsigned 191arm_tmr_get_timecount(struct timecounter *tc) 192{ 193 | 182disable_user_access(void) 183{ 184 uint32_t cntkctl; 185 186 __asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl)); 187 cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN | 188 GT_CNTKCTL_EVNTEN | GT_CNTKCTL_PL0VCTEN | GT_CNTKCTL_PL0PCTEN); 189 __asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); 190 isb(); 191} 192 193static unsigned 194arm_tmr_get_timecount(struct timecounter *tc) 195{ 196 |
194 return (get_cntpct()); | 197 return (get_cntxct(arm_tmr_sc->physical)); |
195} 196 197static int 198arm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 199{ 200 struct arm_tmr_softc *sc; 201 int counts, ctrl; 202 203 sc = (struct arm_tmr_softc *)et->et_priv; 204 205 if (first != 0) { 206 counts = ((uint32_t)et->et_frequency * first) >> 32; | 198} 199 200static int 201arm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 202{ 203 struct arm_tmr_softc *sc; 204 int counts, ctrl; 205 206 sc = (struct arm_tmr_softc *)et->et_priv; 207 208 if (first != 0) { 209 counts = ((uint32_t)et->et_frequency * first) >> 32; |
207 ctrl = get_ctrl(); | 210 ctrl = get_ctrl(sc->physical); |
208 ctrl &= ~GT_CTRL_INT_MASK; 209 ctrl |= GT_CTRL_ENABLE; | 211 ctrl &= ~GT_CTRL_INT_MASK; 212 ctrl |= GT_CTRL_ENABLE; |
210 set_tval(counts); 211 set_ctrl(ctrl); | 213 set_tval(counts, sc->physical); 214 set_ctrl(ctrl, sc->physical); |
212 return (0); 213 } 214 215 return (EINVAL); 216 217} 218 219static int 220arm_tmr_stop(struct eventtimer *et) 221{ | 215 return (0); 216 } 217 218 return (EINVAL); 219 220} 221 222static int 223arm_tmr_stop(struct eventtimer *et) 224{ |
225 struct arm_tmr_softc *sc; |
|
222 int ctrl; 223 | 226 int ctrl; 227 |
224 ctrl = get_ctrl(); | 228 sc = (struct arm_tmr_softc *)et->et_priv; 229 230 ctrl = get_ctrl(sc->physical); |
225 ctrl &= GT_CTRL_ENABLE; | 231 ctrl &= GT_CTRL_ENABLE; |
226 set_ctrl(ctrl); | 232 set_ctrl(ctrl, sc->physical); |
227 228 return (0); 229} 230 231static int 232arm_tmr_intr(void *arg) 233{ 234 struct arm_tmr_softc *sc; 235 int ctrl; 236 237 sc = (struct arm_tmr_softc *)arg; | 233 234 return (0); 235} 236 237static int 238arm_tmr_intr(void *arg) 239{ 240 struct arm_tmr_softc *sc; 241 int ctrl; 242 243 sc = (struct arm_tmr_softc *)arg; |
238 ctrl = get_ctrl(); | 244 ctrl = get_ctrl(sc->physical); |
239 if (ctrl & GT_CTRL_INT_STAT) { 240 ctrl |= GT_CTRL_INT_MASK; | 245 if (ctrl & GT_CTRL_INT_STAT) { 246 ctrl |= GT_CTRL_INT_MASK; |
241 set_ctrl(ctrl); | 247 set_ctrl(ctrl, sc->physical); |
242 } 243 244 if (sc->et.et_active) 245 sc->et.et_event_cb(&sc->et, sc->et.et_arg); 246 247 return (FILTER_HANDLED); 248} 249 --- 40 unchanged lines hidden (view full) --- 290 if (sc->clkfreq == 0) { 291 device_printf(dev, "No clock frequency specified\n"); 292 return (ENXIO); 293 } 294 295 if (bus_alloc_resources(dev, timer_spec, sc->res)) { 296 device_printf(dev, "could not allocate resources\n"); 297 return (ENXIO); | 248 } 249 250 if (sc->et.et_active) 251 sc->et.et_event_cb(&sc->et, sc->et.et_arg); 252 253 return (FILTER_HANDLED); 254} 255 --- 40 unchanged lines hidden (view full) --- 296 if (sc->clkfreq == 0) { 297 device_printf(dev, "No clock frequency specified\n"); 298 return (ENXIO); 299 } 300 301 if (bus_alloc_resources(dev, timer_spec, sc->res)) { 302 device_printf(dev, "could not allocate resources\n"); 303 return (ENXIO); |
298 }; | 304 } |
299 | 305 |
306 sc->physical = true; 307 |
|
300 arm_tmr_sc = sc; 301 | 308 arm_tmr_sc = sc; 309 |
302 /* Setup secure and non-secure IRQs handler */ 303 for (i = 0; i < 2; i++) { | 310 /* Setup secure, non-secure and virtual IRQs handler */ 311 for (i = 0; i < 3; i++) { |
304 error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, 305 arm_tmr_intr, NULL, sc, &sc->ihl[i]); 306 if (error) { 307 device_printf(dev, "Unable to alloc int resource.\n"); 308 return (ENXIO); 309 } 310 } 311 --- 64 unchanged lines hidden (view full) --- 376 * near that length of time and if they are, they should be hung 377 * out to dry. 378 */ 379 if (usec >= (0x80000000U / counts_per_usec)) 380 counts = (0x80000000U / counts_per_usec) - 1; 381 else 382 counts = usec * counts_per_usec; 383 | 312 error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, 313 arm_tmr_intr, NULL, sc, &sc->ihl[i]); 314 if (error) { 315 device_printf(dev, "Unable to alloc int resource.\n"); 316 return (ENXIO); 317 } 318 } 319 --- 64 unchanged lines hidden (view full) --- 384 * near that length of time and if they are, they should be hung 385 * out to dry. 386 */ 387 if (usec >= (0x80000000U / counts_per_usec)) 388 counts = (0x80000000U / counts_per_usec) - 1; 389 else 390 counts = usec * counts_per_usec; 391 |
384 first = get_cntpct(); | 392 first = get_cntxct(arm_tmr_sc->physical); |
385 386 while (counts > 0) { | 393 394 while (counts > 0) { |
387 last = get_cntpct(); | 395 last = get_cntxct(arm_tmr_sc->physical); |
388 counts -= (int32_t)(last - first); 389 first = last; 390 } 391} | 396 counts -= (int32_t)(last - first); 397 first = last; 398 } 399} |