1 1.19 andvar /* $NetBSD: ixp12x0_clk.c,v 1.19 2021/07/31 14:36:33 andvar Exp $ */ 2 1.1 ichiro 3 1.1 ichiro /* 4 1.1 ichiro * Copyright (c) 1997 Mark Brinicombe. 5 1.1 ichiro * Copyright (c) 1997 Causality Limited. 6 1.1 ichiro * All rights reserved. 7 1.1 ichiro * 8 1.1 ichiro * This code is derived from software contributed to The NetBSD Foundation 9 1.1 ichiro * by IWAMOTO Toshihiro and Ichiro FUKUHARA. 10 1.1 ichiro * 11 1.1 ichiro * Redistribution and use in source and binary forms, with or without 12 1.1 ichiro * modification, are permitted provided that the following conditions 13 1.1 ichiro * are met: 14 1.1 ichiro * 1. Redistributions of source code must retain the above copyright 15 1.1 ichiro * notice, this list of conditions and the following disclaimer. 16 1.1 ichiro * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 ichiro * notice, this list of conditions and the following disclaimer in the 18 1.1 ichiro * documentation and/or other materials provided with the distribution. 19 1.14 martin * 3. All advertising materials mentioning features or use of this software 20 1.14 martin * must display the following acknowledgement: 21 1.14 martin * This product includes software developed by the NetBSD 22 1.14 martin * Foundation, Inc. and its contributors. 23 1.14 martin * 4. Neither the name of The NetBSD Foundation nor the names of its 24 1.14 martin * contributors may be used to endorse or promote products derived 25 1.14 martin * from this software without specific prior written permission. 26 1.1 ichiro * 27 1.1 ichiro * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 1.1 ichiro * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 1.1 ichiro * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 1.1 ichiro * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 1.1 ichiro * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 1.1 ichiro * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 1.1 ichiro * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 1.1 ichiro * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 1.1 ichiro * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 1.1 ichiro * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 1.1 ichiro * POSSIBILITY OF SUCH DAMAGE. 38 1.1 ichiro */ 39 1.7 igy 40 1.7 igy #include <sys/cdefs.h> 41 1.19 andvar __KERNEL_RCSID(0, "$NetBSD: ixp12x0_clk.c,v 1.19 2021/07/31 14:36:33 andvar Exp $"); 42 1.1 ichiro 43 1.1 ichiro #include <sys/types.h> 44 1.1 ichiro #include <sys/param.h> 45 1.12 joerg #include <sys/atomic.h> 46 1.1 ichiro #include <sys/systm.h> 47 1.1 ichiro #include <sys/kernel.h> 48 1.1 ichiro #include <sys/time.h> 49 1.12 joerg #include <sys/timetc.h> 50 1.1 ichiro #include <sys/device.h> 51 1.1 ichiro 52 1.15 dyoung #include <sys/bus.h> 53 1.1 ichiro #include <machine/intr.h> 54 1.1 ichiro 55 1.1 ichiro #include <arm/cpufunc.h> 56 1.1 ichiro 57 1.1 ichiro #include <arm/ixp12x0/ixpsipvar.h> 58 1.1 ichiro 59 1.1 ichiro #include <arm/ixp12x0/ixp12x0_pcireg.h> 60 1.1 ichiro #include <arm/ixp12x0/ixp12x0_clkreg.h> 61 1.1 ichiro #include <arm/ixp12x0/ixp12x0var.h> 62 1.1 ichiro 63 1.16 chs static int ixpclk_match(device_t, cfdata_t, void *); 64 1.16 chs static void ixpclk_attach(device_t, device_t, void *); 65 1.1 ichiro 66 1.12 joerg static u_int ixpclk_get_timecount(struct timecounter *); 67 1.12 joerg 68 1.1 ichiro int gettick(void); 69 1.1 ichiro void rtcinit(void); 70 1.1 ichiro 71 1.1 ichiro /* callback functions for intr_functions */ 72 1.1 ichiro static int ixpclk_intr(void* arg); 73 1.1 ichiro 74 1.1 ichiro struct ixpclk_softc { 75 1.1 ichiro bus_addr_t sc_baseaddr; 76 1.1 ichiro bus_space_tag_t sc_iot; 77 1.1 ichiro bus_space_handle_t sc_ioh; 78 1.6 ichiro bus_space_handle_t sc_pll_ioh; 79 1.1 ichiro 80 1.17 skrll uint32_t sc_clock_count; 81 1.17 skrll uint32_t sc_count_per_usec; 82 1.17 skrll uint32_t sc_coreclock_freq; 83 1.1 ichiro }; 84 1.1 ichiro 85 1.1 ichiro #define XTAL_FREQ 3686400 /* 3.6864MHz */ 86 1.1 ichiro #define XTAL_FREQ3686400 87 1.1 ichiro #undef XTAL_FREQ3787800 88 1.1 ichiro #undef XTAL_FREQ3579500 89 1.1 ichiro #define MAX_CCF 22 90 1.1 ichiro 91 1.1 ichiro #if defined(XTAL_FREQ3686400) 92 1.17 skrll static uint32_t ccf_to_coreclock[MAX_CCF + 1] = { 93 1.1 ichiro 29491000, 94 1.1 ichiro 36865000, 95 1.1 ichiro 44237000, 96 1.1 ichiro 51610000, 97 1.1 ichiro 58982000, 98 1.1 ichiro 66355000, 99 1.1 ichiro 73728000, 100 1.1 ichiro 81101000, 101 1.1 ichiro 88474000, 102 1.1 ichiro 95846000, 103 1.1 ichiro 103219000, 104 1.1 ichiro 110592000, 105 1.1 ichiro 132710000, 106 1.1 ichiro 147456000, 107 1.1 ichiro 154829000, 108 1.1 ichiro 162202000, 109 1.1 ichiro 165890000, 110 1.1 ichiro 176947000, 111 1.1 ichiro 191693000, 112 1.1 ichiro 199066000, 113 1.1 ichiro 206438000, 114 1.1 ichiro 221184000, 115 1.1 ichiro 232243000, 116 1.1 ichiro }; 117 1.1 ichiro #elif defined(XTAL_FREQ3787800) 118 1.1 ichiro #elif defined(XTAL_FREQ3579500) 119 1.1 ichiro #else 120 1.1 ichiro #error 121 1.1 ichiro #endif 122 1.1 ichiro 123 1.1 ichiro static struct ixpclk_softc *ixpclk_sc = NULL; 124 1.1 ichiro 125 1.12 joerg static struct timecounter ixpclk_timecounter = { 126 1.18 rin .tc_get_timecount = ixpclk_get_timecount, 127 1.18 rin .tc_counter_mask = 0xffffffff, 128 1.18 rin .tc_name = "ixpclk", 129 1.18 rin .tc_quality = 100, 130 1.12 joerg }; 131 1.12 joerg 132 1.12 joerg static volatile uint32_t ixpclk_base; 133 1.12 joerg 134 1.1 ichiro #define TIMER_FREQUENCY 3686400 /* 3.6864MHz */ 135 1.1 ichiro #define TICKS_PER_MICROSECOND (TIMER_FREQUENCY/1000000) 136 1.1 ichiro 137 1.16 chs CFATTACH_DECL_NEW(ixpclk, sizeof(struct ixpclk_softc), 138 1.5 thorpej ixpclk_match, ixpclk_attach, NULL, NULL); 139 1.1 ichiro 140 1.1 ichiro #define GET_TIMER_VALUE(sc) (bus_space_read_4((sc)->sc_iot, \ 141 1.1 ichiro (sc)->sc_ioh, \ 142 1.1 ichiro IXPCLK_VALUE) \ 143 1.1 ichiro & IXPCL_CTV) 144 1.1 ichiro 145 1.1 ichiro static int 146 1.16 chs ixpclk_match(device_t parent, cfdata_t match, void *aux) 147 1.1 ichiro { 148 1.8 igy 149 1.6 ichiro return 2; 150 1.1 ichiro } 151 1.1 ichiro 152 1.1 ichiro static void 153 1.16 chs ixpclk_attach(device_t parent, device_t self, void *aux) 154 1.1 ichiro { 155 1.8 igy struct ixpclk_softc *sc; 156 1.8 igy struct ixpsip_attach_args *sa; 157 1.17 skrll uint32_t ccf; 158 1.12 joerg bool first_run = ixpclk_sc == NULL; 159 1.1 ichiro 160 1.1 ichiro printf("\n"); 161 1.1 ichiro 162 1.16 chs sc = device_private(self); 163 1.8 igy sa = aux; 164 1.1 ichiro sc->sc_iot = sa->sa_iot; 165 1.1 ichiro sc->sc_baseaddr = sa->sa_addr; 166 1.1 ichiro 167 1.1 ichiro /* using first timer for system ticks */ 168 1.1 ichiro if (ixpclk_sc == NULL) 169 1.1 ichiro ixpclk_sc = sc; 170 1.1 ichiro 171 1.1 ichiro if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, 172 1.1 ichiro &sc->sc_ioh)) 173 1.16 chs panic("%s: Cannot map registers", device_xname(self)); 174 1.6 ichiro if (bus_space_map(sa->sa_iot, sa->sa_addr + IXPCLK_PLL_CFG_OFFSET, 175 1.6 ichiro IXPCLK_PLL_CFG_SIZE, 0, &sc->sc_pll_ioh)) 176 1.16 chs panic("%s: Cannot map registers", device_xname(self)); 177 1.1 ichiro 178 1.1 ichiro /* disable all channel and clear interrupt status */ 179 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL, 180 1.1 ichiro IXPCL_DISABLE | IXPCL_PERIODIC | IXPCL_STP_CORE); 181 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, 0); 182 1.6 ichiro 183 1.6 ichiro 184 1.6 ichiro ccf = bus_space_read_4(sc->sc_iot, sc->sc_pll_ioh, 0) 185 1.6 ichiro & IXP12X0_PLL_CFG_CCF; 186 1.6 ichiro sc->sc_coreclock_freq = ccf_to_coreclock[ccf]; 187 1.6 ichiro 188 1.6 ichiro sc->sc_clock_count = sc->sc_coreclock_freq / hz; 189 1.6 ichiro sc->sc_count_per_usec = sc->sc_coreclock_freq / 1000000; 190 1.6 ichiro 191 1.6 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, IXPT_CLEAR); 192 1.6 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_LOAD, 193 1.6 ichiro sc->sc_clock_count); 194 1.6 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL, 195 1.6 ichiro IXPCL_ENABLE | IXPCL_PERIODIC | IXPCL_STP_CORE); 196 1.6 ichiro 197 1.12 joerg if (first_run) { 198 1.12 joerg ixpclk_timecounter.tc_frequency = sc->sc_coreclock_freq; 199 1.12 joerg tc_init(&ixpclk_timecounter); 200 1.12 joerg } 201 1.12 joerg 202 1.6 ichiro printf("%s: IXP12x0 Interval Timer (core clock %d.%03dMHz)\n", 203 1.16 chs device_xname(self), 204 1.6 ichiro sc->sc_coreclock_freq / 1000000, 205 1.6 ichiro (sc->sc_coreclock_freq % 1000000) / 1000); 206 1.1 ichiro } 207 1.1 ichiro 208 1.1 ichiro /* 209 1.1 ichiro * ixpclk_intr: 210 1.1 ichiro * 211 1.1 ichiro * Handle the hardclock interrupt. 212 1.1 ichiro */ 213 1.1 ichiro static int 214 1.1 ichiro ixpclk_intr(void *arg) 215 1.1 ichiro { 216 1.8 igy 217 1.1 ichiro bus_space_write_4(ixpclk_sc->sc_iot, ixpclk_sc->sc_ioh, 218 1.1 ichiro IXPCLK_CLEAR, 1); 219 1.1 ichiro 220 1.12 joerg atomic_add_32(&ixpclk_base, ixpclk_sc->sc_coreclock_freq); 221 1.12 joerg 222 1.1 ichiro hardclock((struct clockframe*) arg); 223 1.1 ichiro return (1); 224 1.1 ichiro } 225 1.1 ichiro 226 1.1 ichiro /* 227 1.1 ichiro * setstatclockrate: 228 1.1 ichiro * 229 1.1 ichiro * Set the rate of the statistics clock. 230 1.1 ichiro * 231 1.1 ichiro * We assume that hz is either stathz or profhz, and that neither 232 1.1 ichiro * will change after being set by cpu_initclocks(). We could 233 1.1 ichiro * recalculate the intervals here, but that would be a pain. 234 1.1 ichiro */ 235 1.1 ichiro void 236 1.9 he setstatclockrate(int newhz) 237 1.1 ichiro { 238 1.8 igy 239 1.1 ichiro /* use hardclock */ 240 1.1 ichiro 241 1.1 ichiro /* XXX should I use TIMER2? */ 242 1.1 ichiro } 243 1.1 ichiro 244 1.1 ichiro /* 245 1.1 ichiro * cpu_initclocks: 246 1.1 ichiro * 247 1.1 ichiro * Initialize the clock and get them going. 248 1.1 ichiro */ 249 1.1 ichiro void 250 1.8 igy cpu_initclocks(void) 251 1.1 ichiro { 252 1.8 igy struct ixpclk_softc* sc; 253 1.1 ichiro 254 1.8 igy sc = ixpclk_sc; 255 1.1 ichiro stathz = profhz = 0; 256 1.1 ichiro 257 1.1 ichiro printf("clock: hz = %d stathz = %d\n", hz, stathz); 258 1.1 ichiro 259 1.6 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL, 260 1.6 ichiro IXPCL_DISABLE); 261 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, IXPT_CLEAR); 262 1.1 ichiro 263 1.1 ichiro ixp12x0_intr_establish(IXPPCI_INTR_T1, IPL_CLOCK, ixpclk_intr, NULL); 264 1.1 ichiro 265 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_LOAD, 266 1.1 ichiro sc->sc_clock_count); 267 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL, 268 1.1 ichiro IXPCL_ENABLE | IXPCL_PERIODIC 269 1.1 ichiro | IXPCL_STP_CORE); 270 1.1 ichiro } 271 1.1 ichiro 272 1.1 ichiro int 273 1.8 igy gettick(void) 274 1.1 ichiro { 275 1.8 igy int counter; 276 1.8 igy u_int savedints; 277 1.8 igy 278 1.1 ichiro savedints = disable_interrupts(I32_bit); 279 1.1 ichiro counter = GET_TIMER_VALUE(ixpclk_sc); 280 1.1 ichiro restore_interrupts(savedints); 281 1.1 ichiro return counter; 282 1.1 ichiro } 283 1.1 ichiro 284 1.12 joerg static u_int 285 1.12 joerg ixpclk_get_timecount(struct timecounter *tc) 286 1.1 ichiro { 287 1.12 joerg u_int savedints, base, counter; 288 1.1 ichiro 289 1.12 joerg savedints = disable_interrupts(I32_bit); 290 1.12 joerg do { 291 1.12 joerg base = ixpclk_base; 292 1.12 joerg counter = GET_TIMER_VALUE(ixpclk_sc); 293 1.12 joerg } while (base != ixpclk_base); 294 1.12 joerg restore_interrupts(savedints); 295 1.1 ichiro 296 1.12 joerg return base - counter; 297 1.1 ichiro } 298 1.1 ichiro 299 1.1 ichiro /* 300 1.1 ichiro * delay: 301 1.1 ichiro * 302 1.1 ichiro * Delay for at least N microseconds. 303 1.1 ichiro */ 304 1.1 ichiro void 305 1.6 ichiro delay(unsigned int usecs) 306 1.1 ichiro { 307 1.17 skrll uint32_t count; 308 1.17 skrll uint32_t ticks; 309 1.17 skrll uint32_t otick; 310 1.17 skrll uint32_t delta; 311 1.6 ichiro int j; 312 1.8 igy int csec; 313 1.8 igy int usec; 314 1.1 ichiro 315 1.1 ichiro if (ixpclk_sc == NULL) { 316 1.1 ichiro #ifdef DEBUG 317 1.19 andvar printf("delay: called before start ixpclk\n"); 318 1.1 ichiro #endif 319 1.1 ichiro 320 1.6 ichiro csec = usecs / 10000; 321 1.6 ichiro usec = usecs % 10000; 322 1.6 ichiro 323 1.1 ichiro usecs = (TIMER_FREQUENCY / 100) * csec 324 1.1 ichiro + (TIMER_FREQUENCY / 100) * usec / 10000; 325 1.1 ichiro /* clock isn't initialized yet */ 326 1.1 ichiro for(; usecs > 0; usecs--) 327 1.1 ichiro for(j = 100; j > 0; j--) 328 1.1 ichiro ; 329 1.1 ichiro return; 330 1.1 ichiro } 331 1.1 ichiro 332 1.6 ichiro count = ixpclk_sc->sc_count_per_usec * usecs; 333 1.1 ichiro 334 1.1 ichiro otick = gettick(); 335 1.1 ichiro 336 1.6 ichiro for (;;) { 337 1.1 ichiro for(j = 100; j > 0; j--) 338 1.1 ichiro ; 339 1.6 ichiro 340 1.9 he ticks = gettick(); 341 1.9 he delta = otick < ticks 342 1.9 he ? ixpclk_sc->sc_clock_count + otick - ticks 343 1.9 he : otick - ticks; 344 1.1 ichiro 345 1.6 ichiro if (delta > count) 346 1.1 ichiro break; 347 1.6 ichiro 348 1.6 ichiro count -= delta; 349 1.9 he otick = ticks; 350 1.1 ichiro } 351 1.1 ichiro } 352