Module Name: src Committed By: jmcneill Date: Thu Oct 26 23:28:15 UTC 2017
Modified Files: src/sys/arch/arm/ti: files.ti ti_com.c src/sys/arch/evbarm/conf: TI Added Files: src/sys/arch/arm/ti: am3_prcm.c ti_prcm.c ti_prcm.h Log Message: Add support for enabling modules specified in ti,hwmods property. Very primitive am3xxx prcm driver added to validate it, needs work. To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/ti/am3_prcm.c \ src/sys/arch/arm/ti/ti_prcm.c src/sys/arch/arm/ti/ti_prcm.h cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/ti/files.ti cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/ti/ti_com.c cvs rdiff -u -r1.1 -r1.2 src/sys/arch/evbarm/conf/TI Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/ti/files.ti diff -u src/sys/arch/arm/ti/files.ti:1.1 src/sys/arch/arm/ti/files.ti:1.2 --- src/sys/arch/arm/ti/files.ti:1.1 Thu Oct 26 01:16:32 2017 +++ src/sys/arch/arm/ti/files.ti Thu Oct 26 23:28:15 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.ti,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ +# $NetBSD: files.ti,v 1.2 2017/10/26 23:28:15 jmcneill Exp $ # include arch/arm/pic/files.pic @@ -15,11 +15,20 @@ file arch/arm/arm/bus_space_a4x.S file arch/arm/ti/ti_platform.c -# interrupt controller +# Interrupt controller device omapintc: pic, pic_splfuncs attach omapintc at fdt file arch/arm/ti/ti_omapintc.c omapintc +# PRCM +define ti_prcm +file arch/arm/ti/ti_prcm.c ti_prcm + +# PRCM (AM3xxx) +device am3prcm: ti_prcm +attach am3prcm at fdt with am3_prcm +file arch/arm/ti/am3_prcm.c am3_prcm + # UART attach com at fdt with ti_com file arch/arm/ti/ti_com.c ti_com needs-flag @@ -29,6 +38,7 @@ device omaptimer attach omaptimer at fdt file arch/arm/ti/ti_omaptimer.c omaptimer +# Ethernet device cpsw: ether, ifnet, arp, mii, mii_phy attach cpsw at fdt file arch/arm/ti/if_cpsw.c cpsw Index: src/sys/arch/arm/ti/ti_com.c diff -u src/sys/arch/arm/ti/ti_com.c:1.2 src/sys/arch/arm/ti/ti_com.c:1.3 --- src/sys/arch/arm/ti/ti_com.c:1.2 Thu Oct 26 10:56:57 2017 +++ src/sys/arch/arm/ti/ti_com.c Thu Oct 26 23:28:15 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ti_com.c,v 1.2 2017/10/26 10:56:57 jmcneill Exp $ */ +/* $NetBSD: ti_com.c,v 1.3 2017/10/26 23:28:15 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> @@ -28,7 +28,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: ti_com.c,v 1.2 2017/10/26 10:56:57 jmcneill Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ti_com.c,v 1.3 2017/10/26 23:28:15 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -42,6 +42,8 @@ __KERNEL_RCSID(1, "$NetBSD: ti_com.c,v 1 #include <dev/fdt/fdtvar.h> +#include <arch/arm/ti/ti_prcm.h> + static int ti_com_match(device_t, cfdata_t, void *); static void ti_com_attach(device_t, device_t, void *); @@ -77,6 +79,7 @@ ti_com_attach(device_t parent, device_t bus_space_handle_t bsh; bus_space_tag_t bst; char intrstr[128]; + struct clk *hwmod; bus_addr_t addr; bus_size_t size; int error; @@ -103,6 +106,13 @@ ti_com_attach(device_t parent, device_t return; } + hwmod = ti_prcm_get_hwmod(phandle, 0); + KASSERT(hwmod != NULL); + if (clk_enable(hwmod) != 0) { + aprint_error(": couldn't enable module\n"); + return; + } + COM_INIT_REGS(sc->sc_regs, bst, bsh, addr); com_attach_subr(sc); Index: src/sys/arch/evbarm/conf/TI diff -u src/sys/arch/evbarm/conf/TI:1.1 src/sys/arch/evbarm/conf/TI:1.2 --- src/sys/arch/evbarm/conf/TI:1.1 Thu Oct 26 01:16:32 2017 +++ src/sys/arch/evbarm/conf/TI Thu Oct 26 23:28:14 2017 @@ -1,4 +1,4 @@ -# $NetBSD: TI,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ +# $NetBSD: TI,v 1.2 2017/10/26 23:28:14 jmcneill Exp $ # include "arch/evbarm/conf/std.ti" @@ -34,9 +34,11 @@ fdt* at fdtbus? cpus* at fdt? pass 0 cpu* at cpus? +am3prcm* at fdt? pass 1 + com* at fdt? -omapintc* at fdt? pass 1 +omapintc* at fdt? pass 2 omaptimer* at fdt? fregulator* at fdt? Added files: Index: src/sys/arch/arm/ti/am3_prcm.c diff -u /dev/null src/sys/arch/arm/ti/am3_prcm.c:1.1 --- /dev/null Thu Oct 26 23:28:15 2017 +++ src/sys/arch/arm/ti/am3_prcm.c Thu Oct 26 23:28:15 2017 @@ -0,0 +1,139 @@ +/* $NetBSD: am3_prcm.c,v 1.1 2017/10/26 23:28:15 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +__KERNEL_RCSID(1, "$NetBSD: am3_prcm.c,v 1.1 2017/10/26 23:28:15 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> +#include <sys/systm.h> + +#include <dev/fdt/fdtvar.h> + +#define TI_PRCM_PRIVATE +#include <arm/ti/ti_prcm.h> + +#define AM3_PRCM_CM_PER 0x0000 +#define AM3_PRCM_CM_WKUP 0x0400 +#define AM3_PRCM_CM_DPLL 0x0500 +#define AM3_PRCM_CM_MPU 0x0600 +#define AM3_PRCM_CM_DEVICE 0x0700 +#define AM3_PRCM_CM_RTC 0x0800 +#define AM3_PRCM_CM_GFX 0x0900 +#define AM3_PRCM_CM_CEFUSE 0x0a00 + +#define AM3_PRCM_CLKCTRL_MODULEMODE __BITS(1,0) +#define AM3_PRCM_CLKCTRL_MODULEMODE_ENABLE 0x2 + +static int am3_prcm_match(device_t, cfdata_t, void *); +static void am3_prcm_attach(device_t, device_t, void *); + +static int +am3_prcm_hwmod_enable(struct ti_prcm_softc *sc, struct ti_prcm_clk *tc, int enable) +{ + uint32_t val; + + val = PRCM_READ(sc, tc->u.hwmod.reg); + val &= ~AM3_PRCM_CLKCTRL_MODULEMODE; + if (enable) + val |= __SHIFTIN(AM3_PRCM_CLKCTRL_MODULEMODE_ENABLE, + AM3_PRCM_CLKCTRL_MODULEMODE); + PRCM_WRITE(sc, tc->u.hwmod.reg, val); + + return 0; +} + +#define AM3_PRCM_HWMOD_PER(_name, _reg, _parent) \ + TI_PRCM_HWMOD((_name), AM3_PRCM_CM_PER + (_reg), (_parent), am3_prcm_hwmod_enable) +#define AM3_PRCM_HWMOD_WKUP(_name, _reg, _parent) \ + TI_PRCM_HWMOD((_name), AM3_PRCM_CM_WKUP + (_reg), (_parent), am3_prcm_hwmod_enable) + +static const char * const compatible[] = { + "ti,am3-prcm", + NULL +}; + +CFATTACH_DECL_NEW(am3_prcm, sizeof(struct ti_prcm_softc), + am3_prcm_match, am3_prcm_attach, NULL, NULL); + +static struct ti_prcm_clk am3_prcm_clks[] = { + /* XXX until we get a proper clock tree */ + TI_PRCM_FIXED("FIXED_32K", 32768), + TI_PRCM_FIXED("FIXED_48MHZ", 48000000), + TI_PRCM_FIXED("FIXED_96MHZ", 96000000), + TI_PRCM_FIXED_FACTOR("PERIPH_CLK", 1, 1, "FIXED_48MHZ"), + TI_PRCM_FIXED_FACTOR("MMC_CLK", 1, 1, "FIXED_96MHZ"), + + AM3_PRCM_HWMOD_PER("uart1", 0x6c, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("uart2", 0x70, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("uart3", 0x74, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("uart4", 0x78, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("uart5", 0x38, "PERIPH_CLK"), + + AM3_PRCM_HWMOD_WKUP("timer0", 0x10, "FIXED_32K"), + AM3_PRCM_HWMOD_PER("timer2", 0x80, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("timer3", 0x84, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("timer4", 0x88, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("timer5", 0xec, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("timer6", 0xf0, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("timer7", 0x7c, "PERIPH_CLK"), + + AM3_PRCM_HWMOD_PER("mmc0", 0x3c, "MMC_CLK"), + AM3_PRCM_HWMOD_PER("mmc1", 0xf4, "MMC_CLK"), + AM3_PRCM_HWMOD_PER("mmc2", 0xf8, "MMC_CLK"), +}; + +static int +am3_prcm_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +am3_prcm_attach(device_t parent, device_t self, void *aux) +{ + struct ti_prcm_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + + sc->sc_dev = self; + sc->sc_phandle = faa->faa_phandle; + sc->sc_bst = faa->faa_bst; + + sc->sc_clks = am3_prcm_clks; + sc->sc_nclks = __arraycount(am3_prcm_clks); + + if (ti_prcm_attach(sc) != 0) + return; + + aprint_naive("\n"); + aprint_normal(": AM3xxx PRCM\n"); +} Index: src/sys/arch/arm/ti/ti_prcm.c diff -u /dev/null src/sys/arch/arm/ti/ti_prcm.c:1.1 --- /dev/null Thu Oct 26 23:28:15 2017 +++ src/sys/arch/arm/ti/ti_prcm.c Thu Oct 26 23:28:15 2017 @@ -0,0 +1,257 @@ +/* $NetBSD: ti_prcm.c,v 1.1 2017/10/26 23:28:15 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: ti_prcm.c,v 1.1 2017/10/26 23:28:15 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/cpu.h> +#include <sys/device.h> + +#include <dev/fdt/fdtvar.h> + +#include <dev/clk/clk_backend.h> + +#define TI_PRCM_PRIVATE +#include <arm/ti/ti_prcm.h> + +static struct ti_prcm_softc *prcm_softc = NULL; + +static struct clk * +ti_prcm_clock_get(void *priv, const char *name) +{ + struct ti_prcm_softc * const sc = priv; + struct ti_prcm_clk *clk; + + clk = ti_prcm_clock_find(sc, name); + if (clk == NULL) + return NULL; + + return &clk->base; +} + +static void +ti_prcm_clock_put(void *priv, struct clk *clk) +{ +} + +static u_int +ti_prcm_clock_get_rate(void *priv, struct clk *clkp) +{ + struct ti_prcm_softc * const sc = priv; + struct ti_prcm_clk *clk = (struct ti_prcm_clk *)clkp; + struct clk *clkp_parent; + + if (clk->get_rate) + return clk->get_rate(sc, clk); + + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) { + aprint_error("%s: no parent for %s\n", __func__, clk->base.name); + return 0; + } + + return clk_get_rate(clkp_parent); +} + +static int +ti_prcm_clock_set_rate(void *priv, struct clk *clkp, u_int rate) +{ + struct ti_prcm_softc * const sc = priv; + struct ti_prcm_clk *clk = (struct ti_prcm_clk *)clkp; + struct clk *clkp_parent; + + if (clkp->flags & CLK_SET_RATE_PARENT) { + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) { + aprint_error("%s: no parent for %s\n", __func__, clk->base.name); + return ENXIO; + } + return clk_set_rate(clkp_parent, rate); + } + + if (clk->set_rate) + return clk->set_rate(sc, clk, rate); + + return ENXIO; +} + +static int +ti_prcm_clock_enable(void *priv, struct clk *clkp) +{ + struct ti_prcm_softc * const sc = priv; + struct ti_prcm_clk *clk = (struct ti_prcm_clk *)clkp; + struct clk *clkp_parent; + int error = 0; + + clkp_parent = clk_get_parent(clkp); + if (clkp_parent != NULL) { + error = clk_enable(clkp_parent); + if (error != 0) + return error; + } + + if (clk->enable) + error = clk->enable(sc, clk, 1); + + return error; +} + +static int +ti_prcm_clock_disable(void *priv, struct clk *clkp) +{ + struct ti_prcm_softc * const sc = priv; + struct ti_prcm_clk *clk = (struct ti_prcm_clk *)clkp; + int error = EINVAL; + + if (clk->enable) + error = clk->enable(sc, clk, 0); + + return error; +} + +static int +ti_prcm_clock_set_parent(void *priv, struct clk *clkp, + struct clk *clkp_parent) +{ + struct ti_prcm_softc * const sc = priv; + struct ti_prcm_clk *clk = (struct ti_prcm_clk *)clkp; + + if (clk->set_parent == NULL) + return EINVAL; + + return clk->set_parent(sc, clk, clkp_parent->name); +} + +static struct clk * +ti_prcm_clock_get_parent(void *priv, struct clk *clkp) +{ + struct ti_prcm_softc * const sc = priv; + struct ti_prcm_clk *clk = (struct ti_prcm_clk *)clkp; + struct ti_prcm_clk *clk_parent; + const char *parent; + + if (clk->get_parent == NULL) + return NULL; + + parent = clk->get_parent(sc, clk); + if (parent == NULL) + return NULL; + + clk_parent = ti_prcm_clock_find(sc, parent); + if (clk_parent != NULL) + return &clk_parent->base; + + /* No parent in this domain, try FDT */ + return fdtbus_clock_get(sc->sc_phandle, parent); +} + +static const struct clk_funcs ti_prcm_clock_funcs = { + .get = ti_prcm_clock_get, + .put = ti_prcm_clock_put, + .get_rate = ti_prcm_clock_get_rate, + .set_rate = ti_prcm_clock_set_rate, + .enable = ti_prcm_clock_enable, + .disable = ti_prcm_clock_disable, + .set_parent = ti_prcm_clock_set_parent, + .get_parent = ti_prcm_clock_get_parent, +}; + +struct ti_prcm_clk * +ti_prcm_clock_find(struct ti_prcm_softc *sc, const char *name) +{ + for (int i = 0; i < sc->sc_nclks; i++) { + if (sc->sc_clks[i].base.name == NULL) + continue; + if (strcmp(sc->sc_clks[i].base.name, name) == 0) + return &sc->sc_clks[i]; + } + + return NULL; +} + +int +ti_prcm_attach(struct ti_prcm_softc *sc) +{ + bus_addr_t addr; + bus_size_t size; + int i; + + if (fdtbus_get_reg(sc->sc_phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return ENXIO; + } + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return ENXIO; + } + + sc->sc_clkdom.funcs = &ti_prcm_clock_funcs; + sc->sc_clkdom.priv = sc; + for (i = 0; i < sc->sc_nclks; i++) + sc->sc_clks[i].base.domain = &sc->sc_clkdom; + + KASSERT(prcm_softc == NULL); + prcm_softc = sc; + + return 0; +} + +struct clk * +ti_prcm_get_hwmod(const int phandle, u_int index) +{ + struct ti_prcm_clk *tc; + const char *hwmods, *p; + int len, resid; + u_int n; + + KASSERTMSG(prcm_softc != NULL, "prcm driver not attached"); + + hwmods = fdtbus_get_prop(phandle, "ti,hwmods", &len); + if (len <= 0) + return NULL; + + p = hwmods; + for (n = 0, resid = len; resid > 0; n++) { + if (n == index) { + tc = ti_prcm_clock_find(prcm_softc, p); + if (tc == NULL) { + aprint_error_dev(prcm_softc->sc_dev, + "no hwmod with name '%s'\n", p); + return NULL; + } + KASSERT(tc->type == TI_PRCM_HWMOD); + return &tc->base; + } + resid -= strlen(p); + p += strlen(p) + 1; + } + + return NULL; +} Index: src/sys/arch/arm/ti/ti_prcm.h diff -u /dev/null src/sys/arch/arm/ti/ti_prcm.h:1.1 --- /dev/null Thu Oct 26 23:28:15 2017 +++ src/sys/arch/arm/ti/ti_prcm.h Thu Oct 26 23:28:15 2017 @@ -0,0 +1,169 @@ +/* $NetBSD: ti_prcm.h,v 1.1 2017/10/26 23:28:15 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ARM_TI_PRCM_H +#define _ARM_TI_PRCM_H + +#ifdef TI_PRCM_PRIVATE + +#include <dev/clk/clk_backend.h> + +struct ti_prcm_clk; +struct ti_prcm_softc; + +enum ti_prcm_clktype { + TI_PRCM_UNKNOWN, + TI_PRCM_FIXED, + TI_PRCM_FIXED_FACTOR, + TI_PRCM_HWMOD, +}; + +struct ti_prcm_fixed { + u_int rate; +}; + +struct ti_prcm_fixed_factor { + u_int mult; + u_int div; + const char *parent; +}; + +struct ti_prcm_hwmod { + bus_size_t reg; + const char *parent; +}; + +struct ti_prcm_clk { + struct clk base; + enum ti_prcm_clktype type; + union { + struct ti_prcm_fixed fixed; + struct ti_prcm_fixed_factor fixed_factor; + struct ti_prcm_hwmod hwmod; + } u; + + int (*enable)(struct ti_prcm_softc *, + struct ti_prcm_clk *, int); + u_int (*get_rate)(struct ti_prcm_softc *, + struct ti_prcm_clk *); + int (*set_rate)(struct ti_prcm_softc *, + struct ti_prcm_clk *, u_int); + const char * (*get_parent)(struct ti_prcm_softc *, + struct ti_prcm_clk *); + int (*set_parent)(struct ti_prcm_softc *, + struct ti_prcm_clk *, + const char *); +}; + +int ti_prcm_attach(struct ti_prcm_softc *); +struct ti_prcm_clk *ti_prcm_clock_find(struct ti_prcm_softc *, const char *); + +static inline u_int +ti_prcm_fixed_get_rate(struct ti_prcm_softc *sc, struct ti_prcm_clk *tc) +{ + KASSERT(tc->type == TI_PRCM_FIXED); + return tc->u.fixed.rate; +} + +#define TI_PRCM_FIXED(_name, _rate) \ + { \ + .type = TI_PRCM_FIXED, .base.name = (_name), \ + .u.fixed.rate = (_rate), \ + .get_rate = ti_prcm_fixed_get_rate, \ + } + +static inline u_int +ti_prcm_fixed_factor_get_rate(struct ti_prcm_softc *sc, struct ti_prcm_clk *tc) +{ + KASSERT(tc->type == TI_PRCM_FIXED_FACTOR); + struct ti_prcm_clk *tc_parent; + + tc_parent = ti_prcm_clock_find(sc, tc->u.fixed_factor.parent); + KASSERT(tc_parent != NULL); + + const u_int mult = tc->u.fixed_factor.mult; + const u_int div = tc->u.fixed_factor.div; + + return (clk_get_rate(&tc_parent->base) * mult) / div; +} + +static inline const char * +ti_prcm_fixed_factor_get_parent(struct ti_prcm_softc *sc, struct ti_prcm_clk *tc) +{ + KASSERT(tc->type == TI_PRCM_FIXED_FACTOR); + return tc->u.fixed_factor.parent; +} + +#define TI_PRCM_FIXED_FACTOR(_name, _mult, _div, _parent) \ + { \ + .type = TI_PRCM_FIXED_FACTOR, .base.name = (_name), \ + .u.fixed_factor.mult = (_mult), \ + .u.fixed_factor.div = (_div), \ + .u.fixed_factor.parent = (_parent), \ + .get_rate = ti_prcm_fixed_factor_get_rate, \ + .get_parent = ti_prcm_fixed_factor_get_parent, \ + } + +static inline const char * +ti_prcm_hwmod_get_parent(struct ti_prcm_softc *sc, struct ti_prcm_clk *tc) +{ + KASSERT(tc->type == TI_PRCM_HWMOD); + return tc->u.hwmod.parent; +} + +#define TI_PRCM_HWMOD(_name, _reg, _parent, _enable) \ + { \ + .type = TI_PRCM_HWMOD, .base.name = (_name), \ + .u.hwmod.reg = (_reg), \ + .u.hwmod.parent = (_parent), \ + .enable = (_enable), \ + .get_parent = ti_prcm_hwmod_get_parent, \ + } + +struct ti_prcm_softc { + device_t sc_dev; + int sc_phandle; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + + struct clk_domain sc_clkdom; + + struct ti_prcm_clk *sc_clks; + u_int sc_nclks; +}; + +#define PRCM_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define PRCM_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +#endif /* !TI_PRCM_PRIVATE */ + +struct clk * ti_prcm_get_hwmod(const int, u_int); + +#endif /* !_ARM_TI_PRCM_H */