xref: /netbsd-src/sys/arch/arm/fdt/a9tmr_fdt.c (revision eb199291bdd129ab3a54490efcba2a1c7f97fc77)
1*eb199291Sjmcneill /* $NetBSD: a9tmr_fdt.c,v 1.8 2022/11/01 11:05:18 jmcneill Exp $ */
252049049Shkenken 
352049049Shkenken /*-
452049049Shkenken  * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
552049049Shkenken  * All rights reserved.
652049049Shkenken  *
752049049Shkenken  * Redistribution and use in source and binary forms, with or without
852049049Shkenken  * modification, are permitted provided that the following conditions
952049049Shkenken  * are met:
1052049049Shkenken  * 1. Redistributions of source code must retain the above copyright
1152049049Shkenken  *    notice, this list of conditions and the following disclaimer.
1252049049Shkenken  * 2. Redistributions in binary form must reproduce the above copyright
1352049049Shkenken  *    notice, this list of conditions and the following disclaimer in the
1452049049Shkenken  *    documentation and/or other materials provided with the distribution.
1552049049Shkenken  *
1652049049Shkenken  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1752049049Shkenken  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1852049049Shkenken  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1952049049Shkenken  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2052049049Shkenken  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2152049049Shkenken  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2252049049Shkenken  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2352049049Shkenken  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2452049049Shkenken  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2552049049Shkenken  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2652049049Shkenken  * SUCH DAMAGE.
2752049049Shkenken  */
2852049049Shkenken 
2952049049Shkenken #include <sys/cdefs.h>
30*eb199291Sjmcneill __KERNEL_RCSID(0, "$NetBSD: a9tmr_fdt.c,v 1.8 2022/11/01 11:05:18 jmcneill Exp $");
3152049049Shkenken 
3252049049Shkenken #include <sys/param.h>
3352049049Shkenken #include <sys/bus.h>
3452049049Shkenken #include <sys/device.h>
3552049049Shkenken #include <sys/intr.h>
3652049049Shkenken #include <sys/systm.h>
3752049049Shkenken #include <sys/kernel.h>
3852049049Shkenken #include <sys/kmem.h>
3952049049Shkenken 
4052049049Shkenken #include <arm/cortex/a9tmr_intr.h>
4152049049Shkenken #include <arm/cortex/mpcore_var.h>
4252049049Shkenken #include <arm/cortex/a9tmr_var.h>
4352049049Shkenken 
44*eb199291Sjmcneill #include <arm/armreg.h>
45*eb199291Sjmcneill 
4652049049Shkenken #include <dev/fdt/fdtvar.h>
4752049049Shkenken #include <arm/fdt/arm_fdtvar.h>
4852049049Shkenken 
4952049049Shkenken static int	a9tmr_fdt_match(device_t, cfdata_t, void *);
5052049049Shkenken static void	a9tmr_fdt_attach(device_t, device_t, void *);
5152049049Shkenken 
5252049049Shkenken static void	a9tmr_fdt_cpu_hatch(void *, struct cpu_info *);
538dbb374eSjmcneill static void	a9tmr_fdt_speed_changed(device_t);
5452049049Shkenken 
558dbb374eSjmcneill struct a9tmr_fdt_softc {
568dbb374eSjmcneill 	device_t	sc_dev;
578dbb374eSjmcneill 	struct clk	*sc_clk;
588dbb374eSjmcneill };
598dbb374eSjmcneill 
608dbb374eSjmcneill CFATTACH_DECL_NEW(a9tmr_fdt, sizeof(struct a9tmr_fdt_softc),
618dbb374eSjmcneill     a9tmr_fdt_match, a9tmr_fdt_attach, NULL, NULL);
6252049049Shkenken 
636e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
646e54367aSthorpej 	{ .compat = "arm,cortex-a5-global-timer" },
656e54367aSthorpej 	{ .compat = "arm,cortex-a9-global-timer" },
666e54367aSthorpej 	DEVICE_COMPAT_EOL
676e54367aSthorpej };
686e54367aSthorpej 
6952049049Shkenken static int
a9tmr_fdt_match(device_t parent,cfdata_t cf,void * aux)7052049049Shkenken a9tmr_fdt_match(device_t parent, cfdata_t cf, void *aux)
7152049049Shkenken {
7252049049Shkenken 	struct fdt_attach_args * const faa = aux;
7352049049Shkenken 
746e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
7552049049Shkenken }
7652049049Shkenken 
7752049049Shkenken static void
a9tmr_fdt_attach(device_t parent,device_t self,void * aux)7852049049Shkenken a9tmr_fdt_attach(device_t parent, device_t self, void *aux)
7952049049Shkenken {
808dbb374eSjmcneill 	struct a9tmr_fdt_softc * const sc = device_private(self);
8152049049Shkenken 	struct fdt_attach_args * const faa = aux;
8252049049Shkenken 	const int phandle = faa->faa_phandle;
8352049049Shkenken 	bus_space_handle_t bsh;
84*eb199291Sjmcneill 	uint32_t mpidr;
85*eb199291Sjmcneill 	bool is_hardclock;
8652049049Shkenken 
878dbb374eSjmcneill 	sc->sc_dev = self;
888dbb374eSjmcneill 	sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
898dbb374eSjmcneill 	if (sc->sc_clk == NULL) {
9052049049Shkenken 		aprint_error(": couldn't get clock\n");
9152049049Shkenken 		return;
9252049049Shkenken 	}
938dbb374eSjmcneill 	if (clk_enable(sc->sc_clk) != 0) {
9452049049Shkenken 		aprint_error(": couldn't enable clock\n");
9552049049Shkenken 		return;
9652049049Shkenken 	}
9752049049Shkenken 
988dbb374eSjmcneill 	uint32_t rate = clk_get_rate(sc->sc_clk);
9952049049Shkenken 	prop_dictionary_t dict = device_properties(self);
10052049049Shkenken 	prop_dictionary_set_uint32(dict, "frequency", rate);
10152049049Shkenken 
10252049049Shkenken 	char intrstr[128];
10352049049Shkenken 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
10452049049Shkenken 		aprint_error(": failed to decode interrupt\n");
10552049049Shkenken 		return;
10652049049Shkenken 	}
10752049049Shkenken 
108912cfa14Sjmcneill 	aprint_naive("\n");
109912cfa14Sjmcneill 	aprint_normal("\n");
110912cfa14Sjmcneill 
111*eb199291Sjmcneill 	mpidr = armreg_mpidr_read();
112*eb199291Sjmcneill 	is_hardclock = (mpidr & MPIDR_U) != 0;	/* Global timer for UP */
113*eb199291Sjmcneill 
114*eb199291Sjmcneill 	if (is_hardclock) {
11564e248edSryo 		void *ih = fdtbus_intr_establish_xname(phandle, 0, IPL_CLOCK,
11664e248edSryo 		    FDT_INTR_MPSAFE, a9tmr_intr, NULL, device_xname(self));
11752049049Shkenken 		if (ih == NULL) {
11852049049Shkenken 			aprint_error_dev(self, "couldn't install interrupt handler\n");
11952049049Shkenken 			return;
12052049049Shkenken 		}
12152049049Shkenken 		aprint_normal_dev(self, "interrupting on %s\n", intrstr);
122*eb199291Sjmcneill 	}
12352049049Shkenken 
12452049049Shkenken 	bus_addr_t addr;
12552049049Shkenken 	bus_size_t size;
12652049049Shkenken 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
12752049049Shkenken 		aprint_error(": couldn't get distributor address\n");
12852049049Shkenken 		return;
12952049049Shkenken 	}
13052049049Shkenken 	if (bus_space_map(faa->faa_bst, addr, size, 0, &bsh)) {
13152049049Shkenken 		aprint_error(": couldn't map registers\n");
13252049049Shkenken 		return;
13352049049Shkenken 	}
13452049049Shkenken 
13552049049Shkenken 	struct mpcore_attach_args mpcaa = {
13652049049Shkenken 		.mpcaa_name = "arma9tmr",
13752049049Shkenken 		.mpcaa_memt = faa->faa_bst,
13852049049Shkenken 		.mpcaa_memh = bsh,
13952049049Shkenken 		.mpcaa_irq = -1,
14052049049Shkenken 	};
14152049049Shkenken 
142c7fb772bSthorpej 	config_found(self, &mpcaa, NULL, CFARGS_NONE);
14352049049Shkenken 
144*eb199291Sjmcneill 	if (is_hardclock) {
14552049049Shkenken 		arm_fdt_cpu_hatch_register(self, a9tmr_fdt_cpu_hatch);
14652049049Shkenken 		arm_fdt_timer_register(a9tmr_cpu_initclocks);
147*eb199291Sjmcneill 	}
1488dbb374eSjmcneill 
1498dbb374eSjmcneill 	pmf_event_register(self, PMFE_SPEED_CHANGED, a9tmr_fdt_speed_changed, true);
15052049049Shkenken }
15152049049Shkenken 
15252049049Shkenken static void
a9tmr_fdt_cpu_hatch(void * priv,struct cpu_info * ci)15352049049Shkenken a9tmr_fdt_cpu_hatch(void *priv, struct cpu_info *ci)
15452049049Shkenken {
15552049049Shkenken 	a9tmr_init_cpu_clock(ci);
15652049049Shkenken }
1578dbb374eSjmcneill 
1588dbb374eSjmcneill static void
a9tmr_fdt_speed_changed(device_t dev)1598dbb374eSjmcneill a9tmr_fdt_speed_changed(device_t dev)
1608dbb374eSjmcneill {
1618dbb374eSjmcneill 	struct a9tmr_fdt_softc * const sc = device_private(dev);
1628dbb374eSjmcneill 	prop_dictionary_t dict = device_properties(dev);
1638dbb374eSjmcneill 	uint32_t rate;
1648dbb374eSjmcneill 
1658dbb374eSjmcneill 	rate = clk_get_rate(sc->sc_clk);
1668dbb374eSjmcneill 	prop_dictionary_set_uint32(dict, "frequency", rate);
1678dbb374eSjmcneill 
1688dbb374eSjmcneill 	a9tmr_update_freq(rate);
1698dbb374eSjmcneill }
170