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 */

Reply via email to