a9tmr_fdt.c revision 1.7
11.7Sthorpej/* $NetBSD: a9tmr_fdt.c,v 1.7 2021/08/07 16:18:43 thorpej Exp $ */ 21.1Shkenken 31.1Shkenken/*- 41.1Shkenken * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca> 51.1Shkenken * All rights reserved. 61.1Shkenken * 71.1Shkenken * Redistribution and use in source and binary forms, with or without 81.1Shkenken * modification, are permitted provided that the following conditions 91.1Shkenken * are met: 101.1Shkenken * 1. Redistributions of source code must retain the above copyright 111.1Shkenken * notice, this list of conditions and the following disclaimer. 121.1Shkenken * 2. Redistributions in binary form must reproduce the above copyright 131.1Shkenken * notice, this list of conditions and the following disclaimer in the 141.1Shkenken * documentation and/or other materials provided with the distribution. 151.1Shkenken * 161.1Shkenken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.1Shkenken * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.1Shkenken * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.1Shkenken * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.1Shkenken * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.1Shkenken * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.1Shkenken * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.1Shkenken * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.1Shkenken * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Shkenken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Shkenken * SUCH DAMAGE. 271.1Shkenken */ 281.1Shkenken 291.1Shkenken#include <sys/cdefs.h> 301.7Sthorpej__KERNEL_RCSID(0, "$NetBSD: a9tmr_fdt.c,v 1.7 2021/08/07 16:18:43 thorpej Exp $"); 311.1Shkenken 321.1Shkenken#include <sys/param.h> 331.1Shkenken#include <sys/bus.h> 341.1Shkenken#include <sys/device.h> 351.1Shkenken#include <sys/intr.h> 361.1Shkenken#include <sys/systm.h> 371.1Shkenken#include <sys/kernel.h> 381.1Shkenken#include <sys/kmem.h> 391.1Shkenken 401.1Shkenken#include <arm/cortex/a9tmr_intr.h> 411.1Shkenken#include <arm/cortex/mpcore_var.h> 421.1Shkenken#include <arm/cortex/a9tmr_var.h> 431.1Shkenken 441.1Shkenken#include <dev/fdt/fdtvar.h> 451.1Shkenken#include <arm/fdt/arm_fdtvar.h> 461.1Shkenken 471.1Shkenkenstatic int a9tmr_fdt_match(device_t, cfdata_t, void *); 481.1Shkenkenstatic void a9tmr_fdt_attach(device_t, device_t, void *); 491.1Shkenken 501.1Shkenkenstatic void a9tmr_fdt_cpu_hatch(void *, struct cpu_info *); 511.3Sjmcneillstatic void a9tmr_fdt_speed_changed(device_t); 521.1Shkenken 531.3Sjmcneillstruct a9tmr_fdt_softc { 541.3Sjmcneill device_t sc_dev; 551.3Sjmcneill struct clk *sc_clk; 561.3Sjmcneill}; 571.3Sjmcneill 581.3SjmcneillCFATTACH_DECL_NEW(a9tmr_fdt, sizeof(struct a9tmr_fdt_softc), 591.3Sjmcneill a9tmr_fdt_match, a9tmr_fdt_attach, NULL, NULL); 601.1Shkenken 611.5Sthorpejstatic const struct device_compatible_entry compat_data[] = { 621.5Sthorpej { .compat = "arm,cortex-a5-global-timer" }, 631.5Sthorpej { .compat = "arm,cortex-a9-global-timer" }, 641.5Sthorpej DEVICE_COMPAT_EOL 651.5Sthorpej}; 661.5Sthorpej 671.1Shkenkenstatic int 681.1Shkenkena9tmr_fdt_match(device_t parent, cfdata_t cf, void *aux) 691.1Shkenken{ 701.1Shkenken struct fdt_attach_args * const faa = aux; 711.1Shkenken 721.5Sthorpej return of_compatible_match(faa->faa_phandle, compat_data); 731.1Shkenken} 741.1Shkenken 751.1Shkenkenstatic void 761.1Shkenkena9tmr_fdt_attach(device_t parent, device_t self, void *aux) 771.1Shkenken{ 781.3Sjmcneill struct a9tmr_fdt_softc * const sc = device_private(self); 791.1Shkenken struct fdt_attach_args * const faa = aux; 801.1Shkenken const int phandle = faa->faa_phandle; 811.1Shkenken bus_space_handle_t bsh; 821.1Shkenken 831.3Sjmcneill sc->sc_dev = self; 841.3Sjmcneill sc->sc_clk = fdtbus_clock_get_index(phandle, 0); 851.3Sjmcneill if (sc->sc_clk == NULL) { 861.1Shkenken aprint_error(": couldn't get clock\n"); 871.1Shkenken return; 881.1Shkenken } 891.3Sjmcneill if (clk_enable(sc->sc_clk) != 0) { 901.1Shkenken aprint_error(": couldn't enable clock\n"); 911.1Shkenken return; 921.1Shkenken } 931.1Shkenken 941.3Sjmcneill uint32_t rate = clk_get_rate(sc->sc_clk); 951.1Shkenken prop_dictionary_t dict = device_properties(self); 961.1Shkenken prop_dictionary_set_uint32(dict, "frequency", rate); 971.1Shkenken 981.1Shkenken char intrstr[128]; 991.1Shkenken if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 1001.1Shkenken aprint_error(": failed to decode interrupt\n"); 1011.1Shkenken return; 1021.1Shkenken } 1031.1Shkenken 1041.2Sjmcneill aprint_naive("\n"); 1051.2Sjmcneill aprint_normal("\n"); 1061.2Sjmcneill 1071.4Sryo void *ih = fdtbus_intr_establish_xname(phandle, 0, IPL_CLOCK, 1081.4Sryo FDT_INTR_MPSAFE, a9tmr_intr, NULL, device_xname(self)); 1091.1Shkenken if (ih == NULL) { 1101.1Shkenken aprint_error_dev(self, "couldn't install interrupt handler\n"); 1111.1Shkenken return; 1121.1Shkenken } 1131.1Shkenken aprint_normal_dev(self, "interrupting on %s\n", intrstr); 1141.1Shkenken 1151.1Shkenken bus_addr_t addr; 1161.1Shkenken bus_size_t size; 1171.1Shkenken if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 1181.1Shkenken aprint_error(": couldn't get distributor address\n"); 1191.1Shkenken return; 1201.1Shkenken } 1211.1Shkenken if (bus_space_map(faa->faa_bst, addr, size, 0, &bsh)) { 1221.1Shkenken aprint_error(": couldn't map registers\n"); 1231.1Shkenken return; 1241.1Shkenken } 1251.1Shkenken 1261.1Shkenken struct mpcore_attach_args mpcaa = { 1271.1Shkenken .mpcaa_name = "arma9tmr", 1281.1Shkenken .mpcaa_memt = faa->faa_bst, 1291.1Shkenken .mpcaa_memh = bsh, 1301.1Shkenken .mpcaa_irq = -1, 1311.1Shkenken }; 1321.1Shkenken 1331.7Sthorpej config_found(self, &mpcaa, NULL, CFARGS_NONE); 1341.1Shkenken 1351.1Shkenken arm_fdt_cpu_hatch_register(self, a9tmr_fdt_cpu_hatch); 1361.1Shkenken arm_fdt_timer_register(a9tmr_cpu_initclocks); 1371.3Sjmcneill 1381.3Sjmcneill pmf_event_register(self, PMFE_SPEED_CHANGED, a9tmr_fdt_speed_changed, true); 1391.1Shkenken} 1401.1Shkenken 1411.1Shkenkenstatic void 1421.1Shkenkena9tmr_fdt_cpu_hatch(void *priv, struct cpu_info *ci) 1431.1Shkenken{ 1441.1Shkenken a9tmr_init_cpu_clock(ci); 1451.1Shkenken} 1461.3Sjmcneill 1471.3Sjmcneillstatic void 1481.3Sjmcneilla9tmr_fdt_speed_changed(device_t dev) 1491.3Sjmcneill{ 1501.3Sjmcneill struct a9tmr_fdt_softc * const sc = device_private(dev); 1511.3Sjmcneill prop_dictionary_t dict = device_properties(dev); 1521.3Sjmcneill uint32_t rate; 1531.3Sjmcneill 1541.3Sjmcneill rate = clk_get_rate(sc->sc_clk); 1551.3Sjmcneill prop_dictionary_set_uint32(dict, "frequency", rate); 1561.3Sjmcneill 1571.3Sjmcneill a9tmr_update_freq(rate); 1581.3Sjmcneill} 159