1 /* Copyright (c) 2007 Microsoft 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Microsoft 15 * 16 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30 /* 31 * support for ARM cortexa8 Performance Monitor Counters 32 * based on arm11_pmc.c 33 */ 34 35 #include <sys/cdefs.h> 36 /* __KERNEL_RCSID(0, "$NetBSD: cortex_pmc.c,v 1.1 2010/06/19 19:44:57 matt Exp $"); */ 37 #include "opt_perfctrs.h" 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/time.h> 43 #include <sys/timetc.h> 44 #include <dev/clock_subr.h> 45 #include <arm/armreg.h> 46 #include <arm/cpufunc.h> 47 48 #ifndef CORTEX_PMC_CCNT_HZ 49 # define CORTEX_PMC_CCNT_HZ 400000000 /* 400MHz */ 50 #endif 51 52 void cortexa8_pmc_ccnt_init(void); 53 54 #define COUNTS_PER_USEC (CORTEX_PMC_CCNT_HZ / 1000000) 55 56 static uint32_t counts_per_wrap = ~0UL; /* XXX off by 1 */ 57 58 #define PMNC "c9, c12, 0" 59 #define CCNT "c9, c13, 0" 60 61 static inline uint32_t 62 cortexa8_pmc_ctrl_read(void) 63 { 64 uint32_t val; 65 66 __asm volatile ("mrc p15, 0, %0, " PMNC : "=r" (val)); 67 68 return val; 69 } 70 71 static inline void 72 cortexa8_pmc_ctrl_write(uint32_t val) 73 { 74 __asm volatile ("mcr p15, 0, %0, " PMNC :: "r" (val)); 75 } 76 77 static inline uint32_t 78 cortexa8_pmc_ccnt_read(void) 79 { 80 uint32_t val; 81 82 __asm volatile ("mrc p15, 0, %0, " CCNT : "=r" (val)); 83 84 return val; 85 } 86 87 static inline void 88 cortexa8_pmc_ccnt_write(uint32_t val) 89 { 90 __asm volatile ("mcr p15, 0, %0, c9, c12, 2" :: "r" (CORTEX_CNTENC_C)); 91 __asm volatile ("mcr p15, 0, %0, " CCNT :: "r" (val)); 92 __asm volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r" (CORTEX_CNTENS_C)); 93 } 94 95 /* 96 * enable the PMC CCNT for delay() 97 */ 98 void 99 cortexa8_pmc_ccnt_init(void) 100 { 101 uint32_t val; 102 103 val = ARM11_PMCCTL_E | ARM11_PMCCTL_P | ARM11_PMCCTL_C; 104 105 cortexa8_pmc_ctrl_write(val); 106 __asm volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r" (CORTEX_CNTENS_C)); 107 } 108 109 /* 110 * delay - for "at least" arg usec 111 * 112 * NOTE: at 400MHz we are restricted to (uint32_t)~0 "counts" 113 * if this is a problem, accumulate counts in LL vars 114 */ 115 #define DELAY_ARG_LIMIT (((uint32_t)~0) / COUNTS_PER_USEC) /* about 10 sec */ 116 void 117 delay(u_int arg) 118 { 119 uint32_t ctrl; 120 uint32_t cur; 121 uint32_t last; 122 uint32_t delta = 0; 123 uint32_t usecs = 0; 124 125 if (arg > DELAY_ARG_LIMIT) 126 panic("delay: arg %u overflow, limit is %d usec\n", arg, DELAY_ARG_LIMIT); 127 128 last = cortexa8_pmc_ccnt_read(); 129 delta = usecs = 0; 130 while (arg > usecs) { 131 cur = cortexa8_pmc_ccnt_read(); 132 133 /* overflow flag is moved to a separate register 134 and is not read from PMC Control Register */ 135 __asm volatile ("mrc p15, 0, %0, c9, c12, 3" : "=r" (ctrl)); 136 if(ctrl & CORTEX_CNTOFL_C){ 137 /* Reset overflow flag for cycle counter in overflow register */ 138 __asm volatile ("mcr p15, 0, %0, c9, c12, 3" :: "r" (CORTEX_CNTOFL_C)); 139 delta += (last + (counts_per_wrap - cur)); 140 } else { 141 delta += (cur - last); 142 } 143 last = cur; 144 if (delta >= COUNTS_PER_USEC) { 145 usecs += delta / COUNTS_PER_USEC; 146 delta %= COUNTS_PER_USEC; 147 } 148 } 149 } 150