aboutsummaryrefslogtreecommitdiff
path: root/sys/arm/ti/clk/ti_clk_clkctrl.c
diff options
context:
space:
mode:
authorMichal Meloun <mmel@FreeBSD.org>2020-07-30 14:45:05 +0000
committerMichal Meloun <mmel@FreeBSD.org>2020-07-30 14:45:05 +0000
commit0050ea241584f931c6089f7b7a7aca3804131397 (patch)
tree63835a0ff1686af782321fa0acefd75a8511df8f /sys/arm/ti/clk/ti_clk_clkctrl.c
parent98369a6980f5448fa9ab8bde9f04ba10c4ca3c93 (diff)
downloadsrc-0050ea241584f931c6089f7b7a7aca3804131397.tar.gz
src-0050ea241584f931c6089f7b7a7aca3804131397.zip
Move Ti AM335x to dev/extres/clk framework.
Re-implement clocks for these SoC by using now standard extres/clk framework. This is necessary for future expansion of these. The new implementation is (due to the size of the patch) only the initial (minimum) version. It will be updated/expanded with a subsequent set of particular patches. This patch is also not tested on OMAP4 based boards (BeagleBone), so all possible issues should be (and will be) fixed by ASAP once identified. Submited by: Oskar Holmlund (oskar.holmlund@ohdata.se) Differential Revision: https://reviews.freebsd.org/D25118
Notes
Notes: svn path=/head/; revision=363700
Diffstat (limited to 'sys/arm/ti/clk/ti_clk_clkctrl.c')
-rw-r--r--sys/arm/ti/clk/ti_clk_clkctrl.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/sys/arm/ti/clk/ti_clk_clkctrl.c b/sys/arm/ti/clk/ti_clk_clkctrl.c
new file mode 100644
index 000000000000..6b2fff5e12bb
--- /dev/null
+++ b/sys/arm/ti/clk/ti_clk_clkctrl.c
@@ -0,0 +1,219 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm/ti/clk/ti_clk_clkctrl.h>
+
+#include "clkdev_if.h"
+
+#if 0
+#define DPRINTF(dev, msg...) device_printf(dev, msg)
+#else
+#define DPRINTF(dev, msg...)
+#endif
+
+/*
+ * clknode for clkctrl, implements gate and mux (for gpioc)
+ */
+
+#define GPIO_X_GDBCLK_MASK 0x00040000
+#define IDLEST_MASK 0x00030000
+#define MODULEMODE_MASK 0x00000003
+
+#define GPIOX_GDBCLK_ENABLE 0x00040000
+#define GPIOX_GDBCLK_DISABLE 0x00000000
+#define IDLEST_FUNC 0x00000000
+#define IDLEST_TRANS 0x00010000
+#define IDLEST_IDLE 0x00020000
+#define IDLEST_DISABLE 0x00030000
+
+#define MODULEMODE_DISABLE 0x0
+#define MODULEMODE_ENABLE 0x2
+
+struct ti_clkctrl_clknode_sc {
+ device_t dev;
+ bool gdbclk;
+ /* omap4-cm range.host + ti,clkctrl reg[0] */
+ uint32_t register_offset;
+};
+
+#define WRITE4(_clk, off, val) \
+ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
+#define READ4(_clk, off, val) \
+ CLKDEV_READ_4(clknode_get_device(_clk), off, val)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
+
+static int
+ti_clkctrl_init(struct clknode *clk, device_t dev)
+{
+ struct ti_clkctrl_clknode_sc *sc;
+
+ sc = clknode_get_softc(clk);
+ sc->dev = dev;
+
+ clknode_init_parent_idx(clk, 0);
+ return (0);
+}
+
+static int
+ti_clkctrl_set_gdbclk_gate(struct clknode *clk, bool enable)
+{
+ struct ti_clkctrl_clknode_sc *sc;
+ uint32_t val, gpio_x_gdbclk;
+ uint32_t timeout = 100;
+
+ sc = clknode_get_softc(clk);
+
+ READ4(clk, sc->register_offset, &val);
+ DPRINTF(sc->dev, "val(%x) & (%x | %x = %x)\n",
+ val, GPIO_X_GDBCLK_MASK, MODULEMODE_MASK,
+ GPIO_X_GDBCLK_MASK | MODULEMODE_MASK);
+
+ if (enable) {
+ val = val & MODULEMODE_MASK;
+ val |= GPIOX_GDBCLK_ENABLE;
+ } else {
+ val = val & MODULEMODE_MASK;
+ val |= GPIOX_GDBCLK_DISABLE;
+ }
+
+ DPRINTF(sc->dev, "val %x\n", val);
+ WRITE4(clk, sc->register_offset, val);
+
+ /* Wait */
+ while (timeout) {
+ READ4(clk, sc->register_offset, &val);
+ gpio_x_gdbclk = val & GPIO_X_GDBCLK_MASK;
+ if (enable && (gpio_x_gdbclk == GPIOX_GDBCLK_ENABLE))
+ break;
+ else if (!enable && (gpio_x_gdbclk == GPIOX_GDBCLK_DISABLE))
+ break;
+ DELAY(10);
+ timeout--;
+ }
+ if (timeout == 0) {
+ device_printf(sc->dev, "ti_clkctrl_set_gdbclk_gate: Timeout\n");
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+ti_clkctrl_set_gate(struct clknode *clk, bool enable)
+{
+ struct ti_clkctrl_clknode_sc *sc;
+ uint32_t val, idlest, module;
+ uint32_t timeout=100;
+ int err;
+
+ sc = clknode_get_softc(clk);
+
+ if (sc->gdbclk) {
+ err = ti_clkctrl_set_gdbclk_gate(clk, enable);
+ return (err);
+ }
+
+ READ4(clk, sc->register_offset, &val);
+
+ if (enable)
+ WRITE4(clk, sc->register_offset, MODULEMODE_ENABLE);
+ else
+ WRITE4(clk, sc->register_offset, MODULEMODE_DISABLE);
+
+ while (timeout) {
+ READ4(clk, sc->register_offset, &val);
+ idlest = val & IDLEST_MASK;
+ module = val & MODULEMODE_MASK;
+ if (enable &&
+ (idlest == IDLEST_FUNC || idlest == IDLEST_TRANS) &&
+ module == MODULEMODE_ENABLE)
+ break;
+ else if (!enable &&
+ idlest == IDLEST_DISABLE &&
+ module == MODULEMODE_DISABLE)
+ break;
+ DELAY(10);
+ timeout--;
+ }
+
+ if (timeout == 0) {
+ device_printf(sc->dev, "ti_clkctrl_set_gate: Timeout\n");
+ return (1);
+ }
+
+ return (0);
+}
+
+static clknode_method_t ti_clkctrl_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, ti_clkctrl_init),
+ CLKNODEMETHOD(clknode_set_gate, ti_clkctrl_set_gate),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(ti_clkctrl_clknode, ti_clkctrl_clknode_class,
+ ti_clkctrl_clknode_methods, sizeof(struct ti_clkctrl_clknode_sc),
+ clknode_class);
+
+int
+ti_clknode_clkctrl_register(struct clkdom *clkdom,
+ struct ti_clk_clkctrl_def *clkdef)
+{
+ struct clknode *clk;
+ struct ti_clkctrl_clknode_sc *sc;
+
+ clk = clknode_create(clkdom, &ti_clkctrl_clknode_class,
+ &clkdef->clkdef);
+
+ if (clk == NULL) {
+ return (1);
+ }
+
+ sc = clknode_get_softc(clk);
+ sc->register_offset = clkdef->register_offset;
+ sc->gdbclk = clkdef->gdbclk;
+
+ if (clknode_register(clkdom, clk) == NULL) {
+ return (2);
+ }
+ return (0);
+}