1 /* $NetBSD: imxclock.c,v 1.7 2014/07/25 07:49:56 hkenken Exp $ */ 2 /* 3 * Copyright (c) 2009, 2010 Genetec corp. All rights reserved. 4 * Written by Hashimoto Kenichi for Genetec corp. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORP. 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * common part for i.MX31 and i.MX51 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: imxclock.c,v 1.7 2014/07/25 07:49:56 hkenken Exp $"); 34 35 #include "opt_imx.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/evcnt.h> 41 #include <sys/atomic.h> 42 #include <sys/time.h> 43 #include <sys/timetc.h> 44 45 #include <sys/types.h> 46 #include <sys/device.h> 47 48 #include <machine/intr.h> 49 #include <sys/bus.h> 50 51 #include <arm/cpu.h> 52 #include <arm/armreg.h> 53 #include <arm/cpufunc.h> 54 55 #include <arm/imx/imxclockvar.h> 56 #include <arm/imx/imxepitreg.h> 57 58 static u_int imx_epit_get_timecount(struct timecounter *); 59 static int imxclock_intr(void *); 60 61 static struct timecounter imx_epit_timecounter = { 62 imx_epit_get_timecount, /* get_timecount */ 63 0, /* no poll_pps */ 64 0xffffffff, /* counter_mask */ 65 0, /* frequency */ 66 "epit", /* name */ 67 100, /* quality */ 68 NULL, /* prev */ 69 NULL, /* next */ 70 }; 71 72 static volatile uint32_t imxclock_base; 73 struct imxclock_softc *imxclock = NULL; 74 75 void 76 cpu_initclocks(void) 77 { 78 uint32_t reg; 79 u_int freq; 80 81 if (epit1_sc != NULL) 82 imxclock = epit1_sc; 83 else if (epit2_sc != NULL) 84 imxclock = epit2_sc; 85 else 86 panic("%s: driver has not been initialized!", __FUNCTION__); 87 88 freq = imxclock_get_timerfreq(imxclock); 89 imx_epit_timecounter.tc_frequency = freq; 90 tc_init(&imx_epit_timecounter); 91 92 aprint_verbose_dev(imxclock->sc_dev, 93 "timer clock frequency %d\n", freq); 94 95 imxclock->sc_reload_value = freq / hz - 1; 96 97 /* stop timers */ 98 bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh, EPIT_EPITCR, 0); 99 100 aprint_normal("clock: hz=%d stathz = %d\n", hz, stathz); 101 102 bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh, EPIT_EPITLR, 103 imxclock->sc_reload_value); 104 bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh, EPIT_EPITCMPR, 0); 105 106 reg = EPITCR_ENMOD | EPITCR_IOVW | EPITCR_RLD | imxclock->sc_clksrc; 107 bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh, 108 EPIT_EPITCR, reg); 109 reg |= EPITCR_EN | EPITCR_OCIEN | EPITCR_WAITEN | EPITCR_DOZEN | 110 EPITCR_STOPEN; 111 bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh, 112 EPIT_EPITCR, reg); 113 114 epit1_sc->sc_ih = intr_establish(imxclock->sc_intr, IPL_CLOCK, 115 IST_LEVEL, imxclock_intr, NULL); 116 } 117 118 void 119 setstatclockrate(int schz) 120 { 121 } 122 123 static int 124 imxclock_intr(void *arg) 125 { 126 struct imxclock_softc *sc = imxclock; 127 128 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPIT_EPITSR, 1); 129 atomic_add_32(&imxclock_base, sc->sc_reload_value); 130 131 hardclock((struct clockframe *)arg); 132 133 return 1; 134 } 135 136 u_int 137 imx_epit_get_timecount(struct timecounter *tc) 138 { 139 uint32_t counter; 140 uint32_t base; 141 u_int oldirqstate; 142 143 oldirqstate = disable_interrupts(I32_bit); 144 counter = bus_space_read_4(imxclock->sc_iot, imxclock->sc_ioh, EPIT_EPITCNT); 145 base = imxclock_base; 146 restore_interrupts(oldirqstate); 147 148 return base - counter; 149 } 150