Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157573681
D25274.id73120.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
80 KB
Referenced Files
None
Subscribers
None
D25274.id73120.diff
View Options
Index: sys/arm/freescale/imx/imx_gpio.c
===================================================================
--- sys/arm/freescale/imx/imx_gpio.c
+++ sys/arm/freescale/imx/imx_gpio.c
@@ -57,6 +57,14 @@
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#if defined(EXT_RESOURCES) && defined(__aarch64__)
+#define IMX_ENABLE_CLOCKS
+#endif
+
+#ifdef IMX_ENABLE_CLOCKS
+#include <dev/extres/clk/clk.h>
+#endif
+
#include "gpio_if.h"
#ifdef INTRNG
@@ -119,13 +127,17 @@
#ifdef INTRNG
struct gpio_irqsrc gpio_pic_irqsrc[NGPIO];
#endif
+#ifdef IMX_ENABLE_CLOCKS
+ clk_t clk;
+#endif
};
static struct ofw_compat_data compat_data[] = {
- {"fsl,imx6q-gpio", 1},
- {"fsl,imx53-gpio", 1},
- {"fsl,imx51-gpio", 1},
- {NULL, 0}
+ {"fsl,imx8mq-gpio", 1},
+ {"fsl,imx6q-gpio", 1},
+ {"fsl,imx53-gpio", 1},
+ {"fsl,imx51-gpio", 1},
+ {NULL, 0}
};
static struct resource_spec imx_gpio_spec[] = {
@@ -788,6 +800,9 @@
{
struct imx51_gpio_softc *sc;
int i, irq, unit;
+#ifdef IMX_ENABLE_CLOCKS
+ int err;
+#endif
sc = device_get_softc(dev);
sc->dev = dev;
@@ -795,6 +810,19 @@
mtx_init(&sc->sc_mtx, device_get_nameunit(sc->dev), NULL, MTX_SPIN);
+#ifdef IMX_ENABLE_CLOCKS
+ if (clk_get_by_ofw_index(sc->dev, 0, 0, &sc->clk) != 0) {
+ device_printf(dev, "could not get clock");
+ return (ENOENT);
+ }
+
+ err = clk_enable(sc->clk);
+ if (err != 0) {
+ device_printf(sc->dev, "could not enable ipg clock\n");
+ return (err);
+ }
+#endif
+
if (bus_alloc_resources(dev, imx_gpio_spec, sc->sc_res)) {
device_printf(dev, "could not allocate resources\n");
bus_release_resources(dev, imx_gpio_spec, sc->sc_res);
@@ -850,9 +878,20 @@
{
int irq;
struct imx51_gpio_softc *sc;
+#ifdef IMX_ENABLE_CLOCKS
+ int error;
+#endif
sc = device_get_softc(dev);
+#ifdef IMX_ENABLE_CLOCKS
+ error = clk_disable(sc->clk);
+ if (error != 0) {
+ device_printf(sc->dev, "could not disable ipg clock\n");
+ return (error);
+ }
+#endif
+
gpiobus_detach_bus(dev);
for (irq = 0; irq < NUM_IRQRES; irq++) {
if (sc->gpio_ih[irq])
Index: sys/arm/freescale/imx/imx_i2c.c
===================================================================
--- sys/arm/freescale/imx/imx_i2c.c
+++ sys/arm/freescale/imx/imx_i2c.c
@@ -73,6 +73,14 @@
#include <dev/fdt/fdt_pinctrl.h>
#include <dev/gpio/gpiobusvar.h>
+#if defined(EXT_RESOURCES) && defined(__aarch64__)
+#define IMX_ENABLE_CLOCKS
+#endif
+
+#ifdef IMX_ENABLE_CLOCKS
+#include <dev/extres/clk/clk.h>
+#endif
+
#define I2C_ADDR_REG 0x00 /* I2C slave address register */
#define I2C_FDR_REG 0x04 /* I2C frequency divider register */
#define I2C_CONTROL_REG 0x08 /* I2C control register */
@@ -125,6 +133,7 @@
};
static struct ofw_compat_data compat_data[] = {
+ {"fsl,imx21-i2c", 1},
{"fsl,imx6q-i2c", 1},
{"fsl,imx-i2c", 1},
{NULL, 0}
@@ -141,6 +150,9 @@
gpio_pin_t rb_sdapin;
u_int debug;
u_int slave;
+#ifdef IMX_ENABLE_CLOCKS
+ clk_t ipgclk;
+#endif
};
#define DEVICE_DEBUGF(sc, lvl, fmt, args...) \
@@ -385,6 +397,19 @@
sc->dev = dev;
sc->rid = 0;
+#ifdef IMX_ENABLE_CLOCKS
+ if (clk_get_by_ofw_index(sc->dev, 0, 0, &sc->ipgclk) != 0) {
+ device_printf(dev, "could not get ipg clock");
+ return (ENOENT);
+ }
+
+ err = clk_enable(sc->ipgclk);
+ if (err != 0) {
+ device_printf(sc->dev, "could not enable ipg clock\n");
+ return (err);
+ }
+#endif
+
sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid,
RF_ACTIVE);
if (sc->res == NULL) {
@@ -459,6 +484,14 @@
sc = device_get_softc(dev);
+#ifdef IMX_ENABLE_CLOCKS
+ error = clk_disable(sc->ipgclk);
+ if (error != 0) {
+ device_printf(sc->dev, "could not disable ipg clock\n");
+ return (error);
+ }
+#endif
+
if ((error = bus_generic_detach(sc->dev)) != 0) {
device_printf(sc->dev, "cannot detach child devices\n");
return (error);
@@ -571,6 +604,10 @@
{
struct i2c_softc *sc;
u_int busfreq, div, i, ipgfreq;
+#ifdef IMX_ENABLE_CLOCKS
+ int err;
+ uint64_t freq;
+#endif
sc = device_get_softc(dev);
@@ -580,7 +617,16 @@
* Look up the divisor that gives the nearest speed that doesn't exceed
* the configured value for the bus.
*/
+#ifdef IMX_ENABLE_CLOCKS
+ err = clk_get_freq(sc->ipgclk, &freq);
+ if (err != 0) {
+ device_printf(sc->dev, "cannot get frequency\n");
+ return (err);
+ }
+ ipgfreq = (int32_t)freq;
+#else
ipgfreq = imx_ccm_ipg_hz();
+#endif
busfreq = IICBUS_GET_FREQUENCY(sc->iicbus, speed);
div = howmany(ipgfreq, busfreq);
for (i = 0; i < nitems(clkdiv_table); i++) {
Index: sys/arm/freescale/imx/imx_iomux.c
===================================================================
--- sys/arm/freescale/imx/imx_iomux.c
+++ sys/arm/freescale/imx/imx_iomux.c
@@ -76,6 +76,7 @@
static struct iomux_softc *iomux_sc;
static struct ofw_compat_data compat_data[] = {
+ {"fsl,imx8mq-iomuxc", true},
{"fsl,imx6dl-iomuxc", true},
{"fsl,imx6q-iomuxc", true},
{"fsl,imx6sl-iomuxc", true},
Index: sys/arm/freescale/imx/imx_wdog.c
===================================================================
--- sys/arm/freescale/imx/imx_wdog.c
+++ sys/arm/freescale/imx/imx_wdog.c
@@ -153,6 +153,7 @@
imx_wdog_intr(void *arg)
{
struct imx_wdog_softc *sc = arg;
+ vm_offset_t physaddr;
/*
* When configured for external reset, the actual reset is supposed to
@@ -165,7 +166,8 @@
* configured, and it will wait for 1 second for it to take effect, then
* it will do a software reset as a fallback.
*/
- imx_wdog_cpu_reset(BUS_SPACE_PHYSADDR(sc->sc_res[MEMRES], WDOG_CR_REG));
+ physaddr = rman_get_start(sc->sc_res[MEMRES]) + WDOG_CR_REG;
+ imx_wdog_cpu_reset(physaddr);
return (FILTER_HANDLED); /* unreached */
}
Index: sys/arm64/conf/GENERIC
===================================================================
--- sys/arm64/conf/GENERIC
+++ sys/arm64/conf/GENERIC
@@ -113,6 +113,7 @@
options SOC_ALLWINNER_H5
options SOC_ALLWINNER_H6
options SOC_CAVM_THUNDERX
+options SOC_FREESCALE_IMX8MQ
options SOC_HISI_HI6220
options SOC_INTEL_STRATIX10
options SOC_BRCM_BCM2837
@@ -172,6 +173,7 @@
device dwc_rk # Rockchip Designware
device dwc_socfpga # Altera SOCFPGA Ethernet MAC
device genet # Broadcom on RPi4
+device ffec # iMX FFEC
# Etherswitch devices
device etherswitch # Enable etherswitch support
@@ -205,6 +207,7 @@
# Serial (COM) ports
device uart # Generic UART driver
+device uart_imx # iMX8 UART
device uart_msm # Qualcomm MSM UART driver
device uart_mu # RPI3 aux port
device uart_mvebu # Armada 3700 UART driver
@@ -265,6 +268,7 @@
device syr827 # Silergy SYR827 PMIC
device sy8106a # SY8106A Buck Regulator
device vf_i2c # Freescale Vybrid I2C controller
+device fsliic # Freescale iMX I2C controller
# Clock and reset controllers
device aw_ccu # Allwinner clock controller
@@ -281,6 +285,7 @@
# Watchdog controllers
device aw_wdog # Allwinner Watchdog
+device imxwdt # i.MX8 Watchdog
# Power management controllers
device axp81x # X-Powers AXP81x PMIC
@@ -352,4 +357,4 @@
device acpi
# DTBs
-makeoptions MODULES_EXTRA="dtb/allwinner dtb/mv dtb/rockchip dtb/rpi"
+makeoptions MODULES_EXTRA="dtb/allwinner dtb/imx8 dtb/mv dtb/rockchip dtb/rpi"
Index: sys/arm64/freescale/imx/clk/imx_clk_composite.h
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_composite.h
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2018 Emmanuel Vadot <manu@FreeBSD.org>
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+
+#ifndef _IMX_CLK_COMPOSITE_H_
+#define _IMX_CLK_COMPOSITE_H_
+
+#include <dev/extres/clk/clk.h>
+
+struct imx_clk_composite_def {
+ struct clknode_init_def clkdef;
+
+ uint32_t offset;
+ uint32_t flags;
+};
+
+int imx_clk_composite_register(struct clkdom *clkdom,
+ struct imx_clk_composite_def *clkdef);
+
+#endif /* _IMX_CLK_COMPOSITE_H_ */
Index: sys/arm64/freescale/imx/clk/imx_clk_composite.c
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_composite.c
@@ -0,0 +1,309 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
+ *
+ * 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 <dev/extres/clk/clk.h>
+
+#include <arm64/freescale/imx/clk/imx_clk_composite.h>
+
+#include "clkdev_if.h"
+
+#define TARGET_ROOT_ENABLE (1 << 28)
+#define TARGET_ROOT_MUX(n) ((n) << 24)
+#define TARGET_ROOT_MUX_MASK (7 << 24)
+#define TARGET_ROOT_MUX_SHIFT 24
+#define TARGET_ROOT_PRE_PODF(n) ((((n) - 1) & 0x7) << 16)
+#define TARGET_ROOT_PRE_PODF_MASK (0x7 << 16)
+#define TARGET_ROOT_PRE_PODF_SHIFT 16
+#define TARGET_ROOT_PRE_PODF_MAX 7
+#define TARGET_ROOT_POST_PODF(n) ((((n) - 1) & 0x3f) << 0)
+#define TARGET_ROOT_POST_PODF_MASK (0x3f << 0)
+#define TARGET_ROOT_POST_PODF_SHIFT 0
+#define TARGET_ROOT_POST_PODF_MAX 0x3f
+
+struct imx_clk_composite_sc {
+ uint32_t offset;
+ uint32_t flags;
+};
+
+#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))
+
+#define IMX_CLK_COMPOSITE_MASK_SHIFT 16
+
+#if 0
+#define dprintf(format, arg...) \
+ printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
+#else
+#define dprintf(format, arg...)
+#endif
+
+static int
+imx_clk_composite_init(struct clknode *clk, device_t dev)
+{
+ struct imx_clk_composite_sc *sc;
+ uint32_t val, idx;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ DEVICE_UNLOCK(clk);
+ idx = (val & TARGET_ROOT_MUX_MASK) >> TARGET_ROOT_MUX_SHIFT;
+
+ clknode_init_parent_idx(clk, idx);
+
+ return (0);
+}
+
+static int
+imx_clk_composite_set_gate(struct clknode *clk, bool enable)
+{
+ struct imx_clk_composite_sc *sc;
+ uint32_t val = 0;
+
+ sc = clknode_get_softc(clk);
+
+ dprintf("%sabling gate\n", enable ? "En" : "Dis");
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ if (enable)
+ val |= TARGET_ROOT_ENABLE;
+ else
+ val &= ~(TARGET_ROOT_ENABLE);
+ WRITE4(clk, sc->offset, val);
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static int
+imx_clk_composite_set_mux(struct clknode *clk, int index)
+{
+ struct imx_clk_composite_sc *sc;
+ uint32_t val = 0;
+
+ sc = clknode_get_softc(clk);
+
+ dprintf("Set mux to %d\n", index);
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ val &= ~(TARGET_ROOT_MUX_MASK);
+ val |= TARGET_ROOT_MUX(index);
+ WRITE4(clk, sc->offset, val);
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static int
+imx_clk_composite_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct imx_clk_composite_sc *sc;
+ uint32_t reg, pre_div, post_div;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, ®);
+ DEVICE_UNLOCK(clk);
+
+ pre_div = ((reg & TARGET_ROOT_PRE_PODF_MASK)
+ >> TARGET_ROOT_PRE_PODF_SHIFT) + 1;
+ post_div = ((reg & TARGET_ROOT_POST_PODF_MASK)
+ >> TARGET_ROOT_POST_PODF_SHIFT) + 1;
+
+ dprintf("parent_freq=%ju, div=%u\n", *freq, div);
+ *freq = *freq / pre_div / post_div;
+ dprintf("Final freq=%ju\n", *freq);
+ return (0);
+}
+
+static int
+imx_clk_composite_find_best(uint64_t fparent, uint64_t ftarget,
+ uint32_t *pre_div, uint32_t *post_div, int flags)
+{
+ uint32_t prediv, postdiv, best_prediv, best_postdiv;
+ int64_t diff, best_diff;
+ uint64_t cur;
+
+ best_diff = INT64_MAX;
+ for (prediv = 1; prediv <= TARGET_ROOT_PRE_PODF_MAX + 1; prediv++) {
+ for (postdiv = 1; postdiv <= TARGET_ROOT_POST_PODF_MAX + 1; postdiv++) {
+ cur= fparent / prediv / postdiv;
+ diff = (int64_t)ftarget - (int64_t)cur;
+ if (flags & CLK_SET_ROUND_DOWN) {
+ if (diff >= 0 && diff < best_diff) {
+ best_diff = diff;
+ best_prediv = prediv;
+ best_postdiv = postdiv;
+ }
+ }
+ else if (flags & CLK_SET_ROUND_UP) {
+ if (diff <= 0 && abs(diff) < best_diff) {
+ best_diff = diff;
+ best_prediv = prediv;
+ best_postdiv = postdiv;
+ }
+ }
+ else {
+ if (abs(diff) < best_diff) {
+ best_diff = abs(diff);
+ best_prediv = prediv;
+ best_postdiv = postdiv;
+ }
+ }
+ }
+ }
+
+ if (best_diff == INT64_MAX)
+ return (ERANGE);
+
+ *pre_div = best_prediv;
+ *post_div = best_postdiv;
+
+ return (0);
+}
+
+static int
+imx_clk_composite_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct imx_clk_composite_sc *sc;
+ struct clknode *p_clk;
+ const char **p_names;
+ int p_idx, best_parent;
+ int64_t best_diff, diff;
+ int32_t best_pre_div, best_post_div, pre_div, post_div;
+ uint64_t cur, best;
+ uint32_t val;
+
+ sc = clknode_get_softc(clk);
+ dprintf("Finding best parent/div for target freq of %ju\n", *fout);
+ p_names = clknode_get_parent_names(clk);
+
+ best_diff = 0;
+
+ for (p_idx = 0; p_idx != clknode_get_parents_num(clk); p_idx++) {
+ p_clk = clknode_find_by_name(p_names[p_idx]);
+ clknode_get_freq(p_clk, &fparent);
+ dprintf("Testing with parent %s (%d) at freq %ju\n",
+ clknode_get_name(p_clk), p_idx, fparent);
+
+ if (!imx_clk_composite_find_best(fparent, *fout, &pre_div, &post_div, sc->flags))
+ continue;
+ cur = fparent / pre_div / post_div;
+ diff = abs((int64_t)*fout - (int64_t)cur);
+ if (diff < best_diff) {
+ best = cur;
+ best_diff = diff;
+ best_pre_div = pre_div;
+ best_post_div = pre_div;
+ best_parent = p_idx;
+ dprintf("Best parent so far %s (%d) with best freq at "
+ "%ju\n", clknode_get_name(p_clk), p_idx, best);
+ }
+ }
+
+ *stop = 1;
+ if (best_diff == INT64_MAX)
+ return (ERANGE);
+
+ if ((flags & CLK_SET_DRYRUN) != 0) {
+ *fout = best;
+ return (0);
+ }
+
+ p_idx = clknode_get_parent_idx(clk);
+ if (p_idx != best_parent) {
+ dprintf("Switching parent index from %d to %d\n", p_idx,
+ best_parent);
+ clknode_set_parent_by_idx(clk, best_parent);
+ }
+
+ dprintf("Setting dividers to pre=%d, post=%d\n", best_pre_div, best_post_div);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ val &= ~(TARGET_ROOT_PRE_PODF_MASK | TARGET_ROOT_POST_PODF_MASK);
+ val |= TARGET_ROOT_PRE_PODF(pre_div);
+ val |= TARGET_ROOT_POST_PODF(post_div);
+ DEVICE_UNLOCK(clk);
+
+ *fout = best;
+ return (0);
+}
+
+static clknode_method_t imx_clk_composite_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, imx_clk_composite_init),
+ CLKNODEMETHOD(clknode_set_gate, imx_clk_composite_set_gate),
+ CLKNODEMETHOD(clknode_set_mux, imx_clk_composite_set_mux),
+ CLKNODEMETHOD(clknode_recalc_freq, imx_clk_composite_recalc),
+ CLKNODEMETHOD(clknode_set_freq, imx_clk_composite_set_freq),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(imx_clk_composite_clknode, imx_clk_composite_clknode_class,
+ imx_clk_composite_clknode_methods, sizeof(struct imx_clk_composite_sc),
+ clknode_class);
+
+int
+imx_clk_composite_register(struct clkdom *clkdom,
+ struct imx_clk_composite_def *clkdef)
+{
+ struct clknode *clk;
+ struct imx_clk_composite_sc *sc;
+
+ clk = clknode_create(clkdom, &imx_clk_composite_clknode_class,
+ &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+
+ sc->offset = clkdef->offset;
+ sc->flags = clkdef->flags;
+
+ clknode_register(clkdom, clk);
+
+ return (0);
+}
Index: sys/arm64/freescale/imx/clk/imx_clk_frac_pll.h
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_frac_pll.h
@@ -0,0 +1,42 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+
+#ifndef _IMX_CLK_FRAC_PLL_H_
+#define _IMX_CLK_FRAC_PLL_H_
+
+#include <dev/extres/clk/clk.h>
+
+struct imx_clk_frac_pll_def {
+ struct clknode_init_def clkdef;
+ uint32_t offset;
+};
+
+int imx_clk_frac_pll_register(struct clkdom *clkdom, struct imx_clk_frac_pll_def *clkdef);
+
+#endif /* _IMX_CLK_FRAC_PLL_H_ */
Index: sys/arm64/freescale/imx/clk/imx_clk_frac_pll.c
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_frac_pll.c
@@ -0,0 +1,177 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ *
+ * 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 <dev/extres/clk/clk.h>
+
+#include <arm64/freescale/imx/clk/imx_clk_frac_pll.h>
+
+#include "clkdev_if.h"
+
+struct imx_clk_frac_pll_sc {
+ uint32_t 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))
+
+#define CFG0 0
+#define CFG0_PLL_LOCK (1 << 31)
+#define CFG0_PD (1 << 19)
+#define CFG0_BYPASS (1 << 14)
+#define CFG0_NEWDIV_VAL (1 << 12)
+#define CFG0_NEWDIV_ACK (1 << 11)
+#define CFG0_OUTPUT_DIV_MASK (0x1f << 0)
+#define CFG0_OUTPUT_DIV_SHIFT 0
+#define CFG1 4
+#define CFG1_FRAC_DIV_MASK (0xffffff << 7)
+#define CFG1_FRAC_DIV_SHIFT 7
+#define CFG1_INT_DIV_MASK (0x7f << 0)
+#define CFG1_INT_DIV_SHIFT 0
+
+#if 0
+#define dprintf(format, arg...) \
+ printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
+#else
+#define dprintf(format, arg...)
+#endif
+
+static int
+imx_clk_frac_pll_init(struct clknode *clk, device_t dev)
+{
+
+ clknode_init_parent_idx(clk, 0);
+ return (0);
+}
+
+static int
+imx_clk_frac_pll_set_gate(struct clknode *clk, bool enable)
+{
+ struct imx_clk_frac_pll_sc *sc;
+ uint32_t cfg0;
+ int timeout;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset + CFG0, &cfg0);
+ if (enable)
+ cfg0 &= ~(CFG0_PD);
+ else
+ cfg0 |= CFG0_PD;
+ WRITE4(clk, sc->offset + CFG0, cfg0);
+
+ /* Wait for PLL to lock */
+ if (enable && ((cfg0 & CFG0_BYPASS) == 0)) {
+ for (timeout = 1000; timeout; timeout--) {
+ READ4(clk, sc->offset + CFG0, &cfg0);
+ if (cfg0 & CFG0_PLL_LOCK)
+ break;
+ DELAY(1);
+ }
+ }
+
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static int
+imx_clk_frac_pll_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct imx_clk_frac_pll_sc *sc;
+ uint32_t cfg0, cfg1;
+ uint64_t div, divfi, divff, divf_val;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset + CFG0, &cfg0);
+ READ4(clk, sc->offset + CFG1, &cfg1);
+ DEVICE_UNLOCK(clk);
+
+ div = (cfg0 & CFG0_OUTPUT_DIV_MASK) >> CFG0_OUTPUT_DIV_SHIFT;
+ div = (div + 1) * 2;
+ divff = (cfg1 & CFG1_FRAC_DIV_MASK) >> CFG1_FRAC_DIV_SHIFT;
+ divfi = (cfg1 & CFG1_INT_DIV_MASK) >> CFG1_INT_DIV_SHIFT;
+
+ /* PLL is bypassed */
+ if (cfg0 & CFG0_BYPASS)
+ return (0);
+
+ divf_val = 1 + divfi + (divff/0x1000000);
+ *freq = *freq * 8 * divf_val / div;
+
+ return (0);
+}
+
+static clknode_method_t imx_clk_frac_pll_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, imx_clk_frac_pll_init),
+ CLKNODEMETHOD(clknode_set_gate, imx_clk_frac_pll_set_gate),
+ CLKNODEMETHOD(clknode_recalc_freq, imx_clk_frac_pll_recalc),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(imx_clk_frac_pll_clknode, imx_clk_frac_pll_clknode_class,
+ imx_clk_frac_pll_clknode_methods, sizeof(struct imx_clk_frac_pll_sc),
+ clknode_class);
+
+int
+imx_clk_frac_pll_register(struct clkdom *clkdom,
+ struct imx_clk_frac_pll_def *clkdef)
+{
+ struct clknode *clk;
+ struct imx_clk_frac_pll_sc *sc;
+
+ clk = clknode_create(clkdom, &imx_clk_frac_pll_clknode_class,
+ &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+
+ sc->offset = clkdef->offset;
+
+ clknode_register(clkdom, clk);
+
+ return (0);
+}
Index: sys/arm64/freescale/imx/clk/imx_clk_gate.h
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_gate.h
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2018 Emmanuel Vadot <manu@FreeBSD.org>
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+
+#ifndef _IMX_CLK_GATE_H_
+#define _IMX_CLK_GATE_H_
+
+#include <dev/extres/clk/clk.h>
+
+struct imx_clk_gate_def {
+ struct clknode_init_def clkdef;
+ uint32_t offset;
+ uint32_t shift;
+ uint32_t mask;
+ int gate_flags;
+};
+
+int imx_clk_gate_register(struct clkdom *clkdom, struct imx_clk_gate_def *clkdef);
+
+#endif /* _IMX_CLK_GATE_H_ */
Index: sys/arm64/freescale/imx/clk/imx_clk_gate.c
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_gate.c
@@ -0,0 +1,117 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm64/freescale/imx/clk/imx_clk_gate.h>
+
+#include "clkdev_if.h"
+
+#define WR4(_clk, off, val) \
+ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
+#define RD4(_clk, off, val) \
+ CLKDEV_READ_4(clknode_get_device(_clk), off, val)
+#define MD4(_clk, off, clr, set ) \
+ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
+
+static int imx_clk_gate_init(struct clknode *clk, device_t dev);
+static int imx_clk_gate_set_gate(struct clknode *clk, bool enable);
+struct imx_clk_gate_sc {
+ uint32_t offset;
+ uint32_t shift;
+ uint32_t mask;
+ int gate_flags;
+};
+
+static clknode_method_t imx_clk_gate_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, imx_clk_gate_init),
+ CLKNODEMETHOD(clknode_set_gate, imx_clk_gate_set_gate),
+ CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(imx_clk_gate, imx_clk_gate_class, imx_clk_gate_methods,
+ sizeof(struct imx_clk_gate_sc), clknode_class);
+
+static int
+imx_clk_gate_init(struct clknode *clk, device_t dev)
+{
+
+ clknode_init_parent_idx(clk, 0);
+ return(0);
+}
+
+static int
+imx_clk_gate_set_gate(struct clknode *clk, bool enable)
+{
+ uint32_t reg;
+ struct imx_clk_gate_sc *sc;
+ int rv;
+
+ sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
+ rv = MD4(clk, sc->offset, sc->mask << sc->shift,
+ (enable ? sc->mask : 0) << sc->shift);
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
+ return (rv);
+ }
+ RD4(clk, sc->offset, ®);
+ DEVICE_UNLOCK(clk);
+ return(0);
+}
+
+int
+imx_clk_gate_register(struct clkdom *clkdom, struct imx_clk_gate_def *clkdef)
+{
+ struct clknode *clk;
+ struct imx_clk_gate_sc *sc;
+
+ clk = clknode_create(clkdom, &imx_clk_gate_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+ sc->offset = clkdef->offset;
+ sc->shift = clkdef->shift;
+ sc->mask = clkdef->mask;
+ sc->gate_flags = clkdef->gate_flags;
+
+ clknode_register(clkdom, clk);
+ return (0);
+}
Index: sys/arm64/freescale/imx/clk/imx_clk_mux.h
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_mux.h
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+#ifndef _IMX_CLK_MUX_H_
+#define _IMX_CLK_MUX_H_
+
+#include <dev/extres/clk/clk.h>
+
+struct imx_clk_mux_def {
+ struct clknode_init_def clkdef;
+ uint32_t offset;
+ uint32_t shift;
+ uint32_t width;
+ int mux_flags;
+};
+
+int imx_clk_mux_register(struct clkdom *clkdom, struct imx_clk_mux_def *clkdef);
+
+#endif /* _IMX_CLK_MUX_H_ */
Index: sys/arm64/freescale/imx/clk/imx_clk_mux.c
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_mux.c
@@ -0,0 +1,138 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm64/freescale/imx/clk/imx_clk_mux.h>
+
+#include "clkdev_if.h"
+
+#define WR4(_clk, off, val) \
+ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
+#define RD4(_clk, off, val) \
+ CLKDEV_READ_4(clknode_get_device(_clk), off, val)
+#define MD4(_clk, off, clr, set ) \
+ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
+
+static int imx_clk_mux_init(struct clknode *clk, device_t dev);
+static int imx_clk_mux_set_mux(struct clknode *clk, int idx);
+
+struct imx_clk_mux_sc {
+ uint32_t offset;
+ uint32_t shift;
+ uint32_t mask;
+ int mux_flags;
+};
+
+static clknode_method_t imx_clk_mux_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, imx_clk_mux_init),
+ CLKNODEMETHOD(clknode_set_mux, imx_clk_mux_set_mux),
+ CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(imx_clk_mux, imx_clk_mux_class, imx_clk_mux_methods,
+ sizeof(struct imx_clk_mux_sc), clknode_class);
+
+
+static int
+imx_clk_mux_init(struct clknode *clk, device_t dev)
+{
+ uint32_t reg;
+ struct imx_clk_mux_sc *sc;
+ int rv;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ rv = RD4(clk, sc->offset, ®);
+ DEVICE_UNLOCK(clk);
+ if (rv != 0) {
+ return (rv);
+ }
+ reg = (reg >> sc->shift) & sc->mask;
+ clknode_init_parent_idx(clk, reg);
+ return(0);
+}
+
+static int
+imx_clk_mux_set_mux(struct clknode *clk, int idx)
+{
+ uint32_t reg;
+ struct imx_clk_mux_sc *sc;
+ int rv;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ rv = MD4(clk, sc->offset, sc->mask << sc->shift,
+ ((idx & sc->mask) << sc->shift));
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
+ return (rv);
+ }
+ RD4(clk, sc->offset, ®);
+ DEVICE_UNLOCK(clk);
+
+ return(0);
+}
+
+int
+imx_clk_mux_register(struct clkdom *clkdom, struct imx_clk_mux_def *clkdef)
+{
+ struct clknode *clk;
+ struct imx_clk_mux_sc *sc;
+
+ clk = clknode_create(clkdom, &imx_clk_mux_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+ sc->offset = clkdef->offset;
+ sc->shift = clkdef->shift;
+ sc->mask = (1 << clkdef->width) - 1;
+ sc->mux_flags = clkdef->mux_flags;
+
+ clknode_register(clkdom, clk);
+ return (0);
+}
Index: sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.h
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.h
@@ -0,0 +1,42 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+
+#ifndef _IMX_CLK_SSCG_PLL_H_
+#define _IMX_CLK_SSCG_PLL_H_
+
+#include <dev/extres/clk/clk.h>
+
+struct imx_clk_sscg_pll_def {
+ struct clknode_init_def clkdef;
+ uint32_t offset;
+};
+
+int imx_clk_sscg_pll_register(struct clkdom *clkdom, struct imx_clk_sscg_pll_def *clkdef);
+
+#endif /* _IMX_CLK_SSCG_PLL_H_ */
Index: sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.c
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.c
@@ -0,0 +1,195 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ *
+ * 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 <dev/extres/clk/clk.h>
+
+#include <arm64/freescale/imx/clk/imx_clk_sscg_pll.h>
+
+#include "clkdev_if.h"
+
+struct imx_clk_sscg_pll_sc {
+ uint32_t 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))
+
+#define CFG0 0x00
+#define CFG0_PLL_LOCK (1 << 31)
+#define CFG0_PD (1 << 7)
+#define CFG0_BYPASS2 (1 << 5)
+#define CFG0_BYPASS1 (1 << 4)
+#define CFG1 0x04
+#define CFG2 0x08
+#define CFG2_DIVR1_MASK (7 << 25)
+#define CFG2_DIVR1_SHIFT 25
+#define CFG2_DIVR2_MASK (0x3f << 19)
+#define CFG2_DIVR2_SHIFT 19
+#define CFG2_DIVF1_MASK (0x3f << 13)
+#define CFG2_DIVF1_SHIFT 13
+#define CFG2_DIVF2_MASK (0x3f << 7)
+#define CFG2_DIVF2_SHIFT 7
+#define CFG2_DIV_MASK (0x3f << 1)
+#define CFG2_DIV_SHIFT 1
+
+#if 0
+#define dprintf(format, arg...) \
+ printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
+#else
+#define dprintf(format, arg...)
+#endif
+
+static int
+imx_clk_sscg_pll_init(struct clknode *clk, device_t dev)
+{
+ struct imx_clk_sscg_pll_sc *sc;
+
+ sc = clknode_get_softc(clk);
+ if (clknode_get_parents_num(clk) > 1) {
+ device_printf(clknode_get_device(clk),
+ "error: SSCG PLL does not support more than one parent yet\n");
+ return (EINVAL);
+ }
+ clknode_init_parent_idx(clk, 0);
+
+ return (0);
+}
+
+static int
+imx_clk_sscg_pll_set_gate(struct clknode *clk, bool enable)
+{
+ struct imx_clk_sscg_pll_sc *sc;
+ uint32_t cfg0;
+ int timeout;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset + CFG0, &cfg0);
+ if (enable)
+ cfg0 &= ~(CFG0_PD);
+ else
+ cfg0 |= CFG0_PD;
+ WRITE4(clk, sc->offset + CFG0, cfg0);
+
+ /* Reading lock */
+ if (enable) {
+ for (timeout = 1000; timeout; timeout--) {
+ READ4(clk, sc->offset + CFG0, &cfg0);
+ if (cfg0 & CFG0_PLL_LOCK)
+ break;
+ DELAY(1);
+ }
+ }
+
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static int
+imx_clk_sscg_pll_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct imx_clk_sscg_pll_sc *sc;
+ uint32_t cfg0, cfg2;
+ int divr1, divr2, divf1, divf2, div;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset + CFG0, &cfg0);
+ READ4(clk, sc->offset + CFG2, &cfg2);
+ DEVICE_UNLOCK(clk);
+
+ divr1 = (cfg2 & CFG2_DIVR1_MASK) >> CFG2_DIVR1_SHIFT;
+ divr2 = (cfg2 & CFG2_DIVR2_MASK) >> CFG2_DIVR2_SHIFT;
+ divf1 = (cfg2 & CFG2_DIVF1_MASK) >> CFG2_DIVF1_SHIFT;
+ divf2 = (cfg2 & CFG2_DIVF2_MASK) >> CFG2_DIVF2_SHIFT;
+ div = (cfg2 & CFG2_DIV_MASK) >> CFG2_DIV_SHIFT;
+
+ /* PLL is bypassed */
+ if (cfg0 & CFG0_BYPASS2)
+ return (0);
+
+ if (cfg0 & CFG0_BYPASS1) {
+ *freq = *freq / ((divr2 + 1) * (div + 1));
+ return (0);
+ }
+
+ *freq *= 2 * (divf1 + 1) * (divf2 + 1);
+ *freq /= (divr1 + 1) * (divr2 + 1) * (div + 1);
+
+ return (0);
+}
+
+static clknode_method_t imx_clk_sscg_pll_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, imx_clk_sscg_pll_init),
+ CLKNODEMETHOD(clknode_set_gate, imx_clk_sscg_pll_set_gate),
+ CLKNODEMETHOD(clknode_recalc_freq, imx_clk_sscg_pll_recalc),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(imx_clk_sscg_pll_clknode, imx_clk_sscg_pll_clknode_class,
+ imx_clk_sscg_pll_clknode_methods, sizeof(struct imx_clk_sscg_pll_sc),
+ clknode_class);
+
+int
+imx_clk_sscg_pll_register(struct clkdom *clkdom,
+ struct imx_clk_sscg_pll_def *clkdef)
+{
+ struct clknode *clk;
+ struct imx_clk_sscg_pll_sc *sc;
+
+ clk = clknode_create(clkdom, &imx_clk_sscg_pll_clknode_class,
+ &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+
+ sc->offset = clkdef->offset;
+
+ clknode_register(clkdom, clk);
+
+ return (0);
+}
Index: sys/arm64/freescale/imx/imx7gpc.c
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/imx7gpc.c
@@ -0,0 +1,267 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Oleksandr Rybalko under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "pic_if.h"
+
+struct imx7gpc_softc {
+ device_t dev;
+ struct resource *memres;
+ device_t parent;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ { "fsl,imx7gpc", 1},
+ { "fsl,imx8mq-gpc", 1},
+ { NULL, 0}
+};
+
+static inline uint32_t
+imx7gpc_read_4(struct imx7gpc_softc *sc, int reg)
+{
+
+ return (bus_read_4(sc->memres, reg));
+}
+
+static inline void
+imx7gpc_write_4(struct imx7gpc_softc *sc, int reg, uint32_t val)
+{
+
+ bus_write_4(sc->memres, reg, val);
+}
+
+static int
+imx7gpc_activate_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
+}
+
+static void
+imx7gpc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ PIC_DISABLE_INTR(sc->parent, isrc);
+}
+
+static void
+imx7gpc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ PIC_ENABLE_INTR(sc->parent, isrc);
+}
+
+static int
+imx7gpc_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ return (PIC_MAP_INTR(sc->parent, data, isrcp));
+}
+
+static int
+imx7gpc_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
+}
+
+static int
+imx7gpc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
+}
+
+static int
+imx7gpc_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
+}
+
+static void
+imx7gpc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ PIC_PRE_ITHREAD(sc->parent, isrc);
+}
+
+
+static void
+imx7gpc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ PIC_POST_ITHREAD(sc->parent, isrc);
+}
+
+static void
+imx7gpc_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ PIC_POST_FILTER(sc->parent, isrc);
+}
+
+#ifdef SMP
+static int
+imx7gpc_bind_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+
+ return (PIC_BIND_INTR(sc->parent, isrc));
+}
+#endif
+
+static int
+imx7gpc_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "General Power Controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+imx7gpc_attach(device_t dev)
+{
+ struct imx7gpc_softc *sc = device_get_softc(dev);
+ phandle_t node;
+ phandle_t parent_xref;
+ int i, rv;
+
+ sc->dev = dev;
+
+ node = ofw_bus_get_node(dev);
+
+ rv = OF_getencprop(node, "interrupt-parent", &parent_xref,
+ sizeof(parent_xref));
+ if (rv <= 0) {
+ device_printf(dev, "Can't read parent node property\n");
+ return (ENXIO);
+ }
+ sc->parent = OF_device_from_xref(parent_xref);
+ if (sc->parent == NULL) {
+ device_printf(dev, "Can't find parent controller\n");
+ return (ENXIO);
+ }
+
+
+ i = 0;
+ sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i,
+ RF_ACTIVE);
+ if (sc->memres == NULL) {
+ device_printf(dev, "could not allocate resources\n");
+ return (ENXIO);
+ }
+
+ /* TODO: power up OTG domain and unmask all interrupts */
+
+ if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
+ bus_release_resource(dev, SYS_RES_MEMORY, i, sc->memres);
+ device_printf(dev, "Cannot register PIC\n");
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static device_method_t imx7gpc_methods[] = {
+ DEVMETHOD(device_probe, imx7gpc_probe),
+ DEVMETHOD(device_attach, imx7gpc_attach),
+
+ /* Interrupt controller interface */
+ DEVMETHOD(pic_activate_intr, imx7gpc_activate_intr),
+ DEVMETHOD(pic_disable_intr, imx7gpc_disable_intr),
+ DEVMETHOD(pic_enable_intr, imx7gpc_enable_intr),
+ DEVMETHOD(pic_map_intr, imx7gpc_map_intr),
+ DEVMETHOD(pic_deactivate_intr, imx7gpc_deactivate_intr),
+ DEVMETHOD(pic_setup_intr, imx7gpc_setup_intr),
+ DEVMETHOD(pic_teardown_intr, imx7gpc_teardown_intr),
+ DEVMETHOD(pic_pre_ithread, imx7gpc_pre_ithread),
+ DEVMETHOD(pic_post_ithread, imx7gpc_post_ithread),
+ DEVMETHOD(pic_post_filter, imx7gpc_post_filter),
+#ifdef SMP
+ DEVMETHOD(pic_bind_intr, imx7gpc_bind_intr),
+#endif
+
+ DEVMETHOD_END
+};
+
+static driver_t imx7gpc_driver = {
+ "imx7gpc",
+ imx7gpc_methods,
+ sizeof(struct imx7gpc_softc),
+};
+
+static devclass_t imx7gpc_devclass;
+
+EARLY_DRIVER_MODULE(imx7gpc, ofwbus, imx7gpc_driver, imx7gpc_devclass, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(imx7gpc, simplebus, imx7gpc_driver, imx7gpc_devclass, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
Index: sys/arm64/freescale/imx/imx8mq_ccm.c
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/imx8mq_ccm.c
@@ -0,0 +1,486 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Clocks and power control driver for Freescale i.MX6 family of SoCs.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+
+#include <arm64/freescale/imx/imx_ccm_clk.h>
+#include <arm64/freescale/imx/clk/imx_clk_gate.h>
+#include <arm64/freescale/imx/clk/imx_clk_mux.h>
+#include <arm64/freescale/imx/clk/imx_clk_composite.h>
+#include <arm64/freescale/imx/clk/imx_clk_sscg_pll.h>
+#include <arm64/freescale/imx/clk/imx_clk_frac_pll.h>
+
+#include <gnu/dts/include/dt-bindings/clock/imx8mq-clock.h>
+
+#include "clkdev_if.h"
+
+static const char *pll_ref_p[] = {
+ "osc_25m", "osc_27m", "dummy", "dummy"
+};
+static const char *sys3_pll_out_p[] = {
+ "sys3_pll1_ref_sel"
+};
+static const char * arm_pll_bypass_p[] = {
+ "arm_pll", "arm_pll_ref_sel"
+};
+static const char * gpu_pll_bypass_p[] = {
+ "gpu_pll", "gpu_pll_ref_sel"
+};
+static const char * vpu_pll_bypass_p[] = {
+ "vpu_pll", "vpu_pll_ref_sel"
+};
+static const char * audio_pll1_bypass_p[] = {
+ "audio_pll1", "audio_pll1_ref_sel"
+};
+static const char * audio_pll2_bypass_p[] = {
+ "audio_pll2", "audio_pll2_ref_sel"
+};
+static const char * video_pll1_bypass_p[] = {
+ "video_pll1", "video_pll1_ref_sel"
+};
+static const char *uart_p[] = {
+ "osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m", "sys3_pll_out",
+ "clk_ext2", "clk_ext4", "audio_pll2_out"
+};
+static const char *usdhc_p[] = {
+ "osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m", "audio_pll2_out",
+ "sys1_pll_266m", "sys3_pll_out", "sys1_pll_100m"
+};
+static const char *enet_axi_p[] = {
+ "osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m", "sys2_pll_200m",
+ "audio_pll1_out", "video_pll1_out", "sys3_pll_out"
+};
+static const char *enet_ref_p[] = {
+ "osc_25m", "sys2_pll_125m", "sys2_pll_500m", "sys2_pll_100m", "sys1_pll_160m",
+ "audio_pll1_out", "video_pll1_out", "clk_ext4"
+};
+static const char *enet_timer_p[] = {
+ "osc_25m", "sys2_pll_100m", "audio_pll1_out", "clk_ext1", "clk_ext2", "clk_ext3",
+ "clk_ext4", "video_pll1_out"
+};
+static const char *enet_phy_ref_p[] = {
+ "osc_25m", "sys2_pll_50m", "sys2_pll_125m", "sys2_pll_500m", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out"
+};
+static const char *usb_bus_p[] = {
+ "osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_100m", "sys2_pll_200m",
+ "clk_ext2", "clk_ext4", "audio_pll2_out"
+};
+static const char *usb_core_phy_p[] = {
+ "osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m", "sys2_pll_200m",
+ "clk_ext2", "clk_ext3", "audio_pll2_out"
+};
+static const char *i2c_p[] = {
+ "osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys1_pll_133m"
+};
+static const char *ahb_p[] = {
+ "osc_25m", "sys1_pll_133m", "sys1_pll_800m", "sys1_pll_400m", "sys2_pll_125m",
+ "sys3_pll_out", "audio_pll1_out", "video_pll1_out"
+};
+
+static struct imx_clk imx_clks[] = {
+ FIXED(IMX8MQ_CLK_DUMMY, "dummy", 0),
+
+ LINK(IMX8MQ_CLK_32K, "ckil"),
+ LINK(IMX8MQ_CLK_25M, "osc_25m"),
+ LINK(IMX8MQ_CLK_27M, "osc_27m"),
+ LINK(IMX8MQ_CLK_EXT1, "clk_ext1"),
+ LINK(IMX8MQ_CLK_EXT2, "clk_ext2"),
+ LINK(IMX8MQ_CLK_EXT3, "clk_ext3"),
+ LINK(IMX8MQ_CLK_EXT4, "clk_ext4"),
+
+ FIXED(IMX8MQ_SYS1_PLL_OUT, "sys1_pll_out", 800000000),
+ FIXED(IMX8MQ_SYS2_PLL_OUT, "sys2_pll_out", 1000000000),
+ SSCG_PLL(IMX8MQ_SYS3_PLL_OUT, "sys3_pll_out", sys3_pll_out_p, 0x48),
+
+ MUX(IMX8MQ_ARM_PLL_REF_SEL, "arm_pll_ref_sel", pll_ref_p, 0, 0x28, 16, 2),
+ MUX(IMX8MQ_GPU_PLL_REF_SEL, "gpu_pll_ref_sel", pll_ref_p, 0, 0x18, 16, 2),
+ MUX(IMX8MQ_VPU_PLL_REF_SEL, "vpu_pll_ref_sel", pll_ref_p, 0, 0x20, 16, 2),
+ MUX(IMX8MQ_AUDIO_PLL1_REF_SEL, "audio_pll1_ref_sel", pll_ref_p, 0, 0x0, 16, 2),
+ MUX(IMX8MQ_AUDIO_PLL2_REF_SEL, "audio_pll2_ref_sel", pll_ref_p, 0, 0x8, 16, 2),
+ MUX(IMX8MQ_VIDEO_PLL1_REF_SEL, "video_pll1_ref_sel", pll_ref_p, 0, 0x10, 16, 2),
+ MUX(IMX8MQ_SYS3_PLL1_REF_SEL, "sys3_pll1_ref_sel", pll_ref_p, 0, 0x48, 0, 2),
+ MUX(IMX8MQ_DRAM_PLL1_REF_SEL, "dram_pll1_ref_sel", pll_ref_p, 0, 0x60, 0, 2),
+ MUX(IMX8MQ_VIDEO2_PLL1_REF_SEL, "video2_pll1_ref_sel", pll_ref_p, 0, 0x54, 0, 2),
+
+ DIV(IMX8MQ_ARM_PLL_REF_DIV, "arm_pll_ref_div", "arm_pll_ref_sel", 0x28, 5, 6),
+ DIV(IMX8MQ_GPU_PLL_REF_DIV, "gpu_pll_ref_div", "gpu_pll_ref_sel", 0x18, 5, 6),
+ DIV(IMX8MQ_VPU_PLL_REF_DIV, "vpu_pll_ref_div", "vpu_pll_ref_sel", 0x20, 5, 6),
+ DIV(IMX8MQ_AUDIO_PLL1_REF_DIV, "audio_pll1_ref_div", "audio_pll1_ref_sel", 0x0, 5, 6),
+ DIV(IMX8MQ_AUDIO_PLL2_REF_DIV, "audio_pll2_ref_div", "audio_pll2_ref_sel", 0x8, 5, 6),
+ DIV(IMX8MQ_VIDEO_PLL1_REF_DIV, "video_pll1_ref_div", "video_pll1_ref_sel", 0x10, 5, 6),
+
+ FRAC_PLL(IMX8MQ_ARM_PLL, "arm_pll", "arm_pll_ref_div", 0x28),
+ FRAC_PLL(IMX8MQ_GPU_PLL, "gpu_pll", "gpu_pll_ref_div", 0x18),
+ FRAC_PLL(IMX8MQ_VPU_PLL, "vpu_pll", "vpu_pll_ref_div", 0x20),
+ FRAC_PLL(IMX8MQ_AUDIO_PLL1, "audio_pll1", "audio_pll1_ref_div", 0x0),
+ FRAC_PLL(IMX8MQ_AUDIO_PLL2, "audio_pll2", "audio_pll2_ref_div", 0x8),
+ FRAC_PLL(IMX8MQ_VIDEO_PLL1, "video_pll1", "video_pll1_ref_div", 0x10),
+
+ /* ARM_PLL needs SET_PARENT flag */
+ MUX(IMX8MQ_ARM_PLL_BYPASS, "arm_pll_bypass", arm_pll_bypass_p, 0, 0x28, 14, 1),
+ MUX(IMX8MQ_GPU_PLL_BYPASS, "gpu_pll_bypass", gpu_pll_bypass_p, 0, 0x18, 14, 1),
+ MUX(IMX8MQ_VPU_PLL_BYPASS, "vpu_pll_bypass", vpu_pll_bypass_p, 0, 0x20, 14, 1),
+ MUX(IMX8MQ_AUDIO_PLL1_BYPASS, "audio_pll1_bypass", audio_pll1_bypass_p, 0, 0x0, 14, 1),
+ MUX(IMX8MQ_AUDIO_PLL2_BYPASS, "audio_pll2_bypass", audio_pll2_bypass_p, 0, 0x8, 14, 1),
+ MUX(IMX8MQ_VIDEO_PLL1_BYPASS, "video_pll1_bypass", video_pll1_bypass_p, 0, 0x10, 14, 1),
+
+ GATE(IMX8MQ_ARM_PLL_OUT, "arm_pll_out", "arm_pll_bypass", 0x28, 21),
+ GATE(IMX8MQ_GPU_PLL_OUT, "gpu_pll_out", "gpu_pll_bypass", 0x18, 21),
+ GATE(IMX8MQ_VPU_PLL_OUT, "vpu_pll_out", "vpu_pll_bypass", 0x20, 21),
+ GATE(IMX8MQ_AUDIO_PLL1_OUT, "audio_pll1_out", "audio_pll1_bypass", 0x0, 21),
+ GATE(IMX8MQ_AUDIO_PLL2_OUT, "audio_pll2_out", "audio_pll2_bypass", 0x8, 21),
+ GATE(IMX8MQ_VIDEO_PLL1_OUT, "video_pll1_out", "video_pll1_bypass", 0x10, 21),
+
+ GATE(IMX8MQ_SYS1_PLL_40M_CG, "sys1_pll_40m_cg", "sys1_pll_out", 0x30, 9),
+ GATE(IMX8MQ_SYS1_PLL_80M_CG, "sys1_pll_80m_cg", "sys1_pll_out", 0x30, 11),
+ GATE(IMX8MQ_SYS1_PLL_100M_CG, "sys1_pll_100m_cg", "sys1_pll_out", 0x30, 13),
+ GATE(IMX8MQ_SYS1_PLL_133M_CG, "sys1_pll_133m_cg", "sys1_pll_out", 0x30, 15),
+ GATE(IMX8MQ_SYS1_PLL_160M_CG, "sys1_pll_160m_cg", "sys1_pll_out", 0x30, 17),
+ GATE(IMX8MQ_SYS1_PLL_200M_CG, "sys1_pll_200m_cg", "sys1_pll_out", 0x30, 19),
+ GATE(IMX8MQ_SYS1_PLL_266M_CG, "sys1_pll_266m_cg", "sys1_pll_out", 0x30, 21),
+ GATE(IMX8MQ_SYS1_PLL_400M_CG, "sys1_pll_400m_cg", "sys1_pll_out", 0x30, 23),
+ GATE(IMX8MQ_SYS1_PLL_800M_CG, "sys1_pll_800m_cg", "sys1_pll_out", 0x30, 25),
+
+ FFACT(IMX8MQ_SYS1_PLL_40M, "sys1_pll_40m", "sys1_pll_40m_cg", 1, 20),
+ FFACT(IMX8MQ_SYS1_PLL_80M, "sys1_pll_80m", "sys1_pll_80m_cg", 1, 10),
+ FFACT(IMX8MQ_SYS1_PLL_100M, "sys1_pll_100m", "sys1_pll_100m_cg", 1, 8),
+ FFACT(IMX8MQ_SYS1_PLL_133M, "sys1_pll_133m", "sys1_pll_133m_cg", 1, 6),
+ FFACT(IMX8MQ_SYS1_PLL_160M, "sys1_pll_160m", "sys1_pll_160m_cg", 1, 5),
+ FFACT(IMX8MQ_SYS1_PLL_200M, "sys1_pll_200m", "sys1_pll_200m_cg", 1, 4),
+ FFACT(IMX8MQ_SYS1_PLL_266M, "sys1_pll_266m", "sys1_pll_266m_cg", 1, 3),
+ FFACT(IMX8MQ_SYS1_PLL_400M, "sys1_pll_400m", "sys1_pll_400m_cg", 1, 2),
+ FFACT(IMX8MQ_SYS1_PLL_800M, "sys1_pll_800m", "sys1_pll_800m_cg", 1, 1),
+
+ GATE(IMX8MQ_SYS2_PLL_50M_CG, "sys2_pll_50m_cg", "sys2_pll_out", 0x3c, 9),
+ GATE(IMX8MQ_SYS2_PLL_100M_CG, "sys2_pll_100m_cg", "sys2_pll_out", 0x3c, 11),
+ GATE(IMX8MQ_SYS2_PLL_125M_CG, "sys2_pll_125m_cg", "sys2_pll_out", 0x3c, 13),
+ GATE(IMX8MQ_SYS2_PLL_166M_CG, "sys2_pll_166m_cg", "sys2_pll_out", 0x3c, 15),
+ GATE(IMX8MQ_SYS2_PLL_200M_CG, "sys2_pll_200m_cg", "sys2_pll_out", 0x3c, 17),
+ GATE(IMX8MQ_SYS2_PLL_250M_CG, "sys2_pll_250m_cg", "sys2_pll_out", 0x3c, 19),
+ GATE(IMX8MQ_SYS2_PLL_333M_CG, "sys2_pll_333m_cg", "sys2_pll_out", 0x3c, 21),
+ GATE(IMX8MQ_SYS2_PLL_500M_CG, "sys2_pll_500m_cg", "sys2_pll_out", 0x3c, 23),
+ GATE(IMX8MQ_SYS2_PLL_1000M_CG, "sys2_pll_1000m_cg", "sys2_pll_out", 0x3c, 25),
+
+ FFACT(IMX8MQ_SYS2_PLL_50M, "sys2_pll_50m", "sys2_pll_50m_cg", 1, 20),
+ FFACT(IMX8MQ_SYS2_PLL_100M, "sys2_pll_100m", "sys2_pll_100m_cg", 1, 10),
+ FFACT(IMX8MQ_SYS2_PLL_125M, "sys2_pll_125m", "sys2_pll_125m_cg", 1, 8),
+ FFACT(IMX8MQ_SYS2_PLL_166M, "sys2_pll_166m", "sys2_pll_166m_cg", 1, 6),
+ FFACT(IMX8MQ_SYS2_PLL_200M, "sys2_pll_200m", "sys2_pll_200m_cg", 1, 5),
+ FFACT(IMX8MQ_SYS2_PLL_250M, "sys2_pll_250m", "sys2_pll_250m_cg", 1, 4),
+ FFACT(IMX8MQ_SYS2_PLL_333M, "sys2_pll_333m", "sys2_pll_333m_cg", 1, 3),
+ FFACT(IMX8MQ_SYS2_PLL_500M, "sys2_pll_500m", "sys2_pll_500m_cg", 1, 2),
+ FFACT(IMX8MQ_SYS2_PLL_1000M, "sys2_pll_1000m", "sys2_pll_1000m_cg", 1, 1),
+
+ COMPOSITE(IMX8MQ_CLK_AHB, "ahb", ahb_p, 0x9000, 0),
+ DIV(IMX8MQ_CLK_IPG_ROOT, "ipg_root", "ahb", 0x9080, 0, 1),
+
+ COMPOSITE(IMX8MQ_CLK_UART1, "uart1", uart_p, 0xaf00, 0),
+ COMPOSITE(IMX8MQ_CLK_UART2, "uart2", uart_p, 0xaf80, 0),
+ COMPOSITE(IMX8MQ_CLK_UART3, "uart3", uart_p, 0xb000, 0),
+ COMPOSITE(IMX8MQ_CLK_UART4, "uart4", uart_p, 0xb080, 0),
+
+ ROOT_GATE(IMX8MQ_CLK_UART1_ROOT, "uart1_root_clk", "uart1", 0x4490),
+ ROOT_GATE(IMX8MQ_CLK_UART2_ROOT, "uart2_root_clk", "uart2", 0x44a0),
+ ROOT_GATE(IMX8MQ_CLK_UART3_ROOT, "uart3_root_clk", "uart3", 0x44b0),
+ ROOT_GATE(IMX8MQ_CLK_UART4_ROOT, "uart4_root_clk", "uart4", 0x44c0),
+
+ COMPOSITE(IMX8MQ_CLK_USDHC1, "usdhc1", usdhc_p, 0xac00, CLK_SET_ROUND_DOWN),
+ COMPOSITE(IMX8MQ_CLK_USDHC2, "usdhc2", usdhc_p, 0xac80, CLK_SET_ROUND_DOWN),
+
+ ROOT_GATE(IMX8MQ_CLK_USDHC1_ROOT, "usdhc1_root_clk", "usdhc1", 0x4510),
+ ROOT_GATE(IMX8MQ_CLK_USDHC2_ROOT, "usdhc2_root_clk", "usdhc2", 0x4520),
+
+ COMPOSITE(IMX8MQ_CLK_ENET_AXI, "enet_axi", enet_axi_p, 0x8800, 0),
+ COMPOSITE(IMX8MQ_CLK_ENET_REF, "enet_ref", enet_ref_p, 0xa980, 0),
+ COMPOSITE(IMX8MQ_CLK_ENET_TIMER, "enet_timer", enet_timer_p, 0xaa00, 0),
+ COMPOSITE(IMX8MQ_CLK_ENET_PHY_REF, "enet_phy_ref", enet_phy_ref_p, 0xaa80, 0),
+
+ ROOT_GATE(IMX8MQ_CLK_ENET1_ROOT, "enet1_root_clk", "enet_axi", 0x40a0),
+
+ COMPOSITE(IMX8MQ_CLK_USB_BUS, "usb_bus", usb_bus_p, 0x8b80, 0),
+ COMPOSITE(IMX8MQ_CLK_USB_CORE_REF, "usb_core_ref", usb_core_phy_p, 0xb100, 0),
+ COMPOSITE(IMX8MQ_CLK_USB_PHY_REF, "usb_phy_ref", usb_core_phy_p, 0xb180, 0),
+
+ ROOT_GATE(IMX8MQ_CLK_USB1_CTRL_ROOT, "usb1_ctrl_root_clk", "usb_bus", 0x44d0),
+ ROOT_GATE(IMX8MQ_CLK_USB2_CTRL_ROOT, "usb2_ctrl_root_clk", "usb_bus", 0x44e0),
+ ROOT_GATE(IMX8MQ_CLK_USB1_PHY_ROOT, "usb1_phy_root_clk", "usb_phy_ref", 0x44f0),
+ ROOT_GATE(IMX8MQ_CLK_USB2_PHY_ROOT, "usb2_phy_root_clk", "usb_phy_ref", 0x4500),
+
+ COMPOSITE(IMX8MQ_CLK_I2C1, "i2c1", i2c_p, 0xad00, 0),
+ COMPOSITE(IMX8MQ_CLK_I2C2, "i2c2", i2c_p, 0xad80, 0),
+ COMPOSITE(IMX8MQ_CLK_I2C3, "i2c3", i2c_p, 0xae00, 0),
+ COMPOSITE(IMX8MQ_CLK_I2C4, "i2c4", i2c_p, 0xae80, 0),
+
+ ROOT_GATE(IMX8MQ_CLK_I2C1_ROOT, "i2c1_root_clk", "i2c1", 0x4170),
+ ROOT_GATE(IMX8MQ_CLK_I2C2_ROOT, "i2c2_root_clk", "i2c2", 0x4180),
+ ROOT_GATE(IMX8MQ_CLK_I2C3_ROOT, "i2c3_root_clk", "i2c3", 0x4190),
+ ROOT_GATE(IMX8MQ_CLK_I2C4_ROOT, "i2c4_root_clk", "i2c4", 0x41a0),
+
+ ROOT_GATE(IMX8MQ_CLK_GPIO1_ROOT, "gpio1_root_clk", "ipg_root", 0x40b0),
+ ROOT_GATE(IMX8MQ_CLK_GPIO2_ROOT, "gpio2_root_clk", "ipg_root", 0x40c0),
+ ROOT_GATE(IMX8MQ_CLK_GPIO3_ROOT, "gpio3_root_clk", "ipg_root", 0x40d0),
+ ROOT_GATE(IMX8MQ_CLK_GPIO4_ROOT, "gpio4_root_clk", "ipg_root", 0x40e0),
+ ROOT_GATE(IMX8MQ_CLK_GPIO5_ROOT, "gpio5_root_clk", "ipg_root", 0x40f0),
+};
+
+struct ccm_softc {
+ device_t dev;
+ struct resource *mem_res;
+ struct clkdom *clkdom;
+ struct mtx mtx;
+ struct imx_clk *clks;
+ int nclks;
+};
+
+static inline uint32_t
+CCU_READ4(struct ccm_softc *sc, bus_size_t off)
+{
+
+ return (bus_read_4(sc->mem_res, off));
+}
+
+static inline void
+CCU_WRITE4(struct ccm_softc *sc, bus_size_t off, uint32_t val)
+{
+
+ bus_write_4(sc->mem_res, off, val);
+}
+
+static int
+ccm_detach(device_t dev)
+{
+ struct ccm_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ return (0);
+}
+
+static int
+ccm_attach(device_t dev)
+{
+ struct ccm_softc *sc;
+ int err, rid;
+ phandle_t node;
+ int i;
+
+ sc = device_get_softc(dev);
+ err = 0;
+
+ /* Allocate bus_space resources. */
+ rid = 0;
+ sc->clks = imx_clks;
+ sc->nclks = nitems(imx_clks);
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ err = ENXIO;
+ goto out;
+ }
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ sc->clkdom = clkdom_create(dev);
+ if (sc->clkdom == NULL)
+ panic("Cannot create clkdom\n");
+
+ for (i = 0; i < sc->nclks; i++) {
+ switch (sc->clks[i].type) {
+ case IMX_CLK_UNDEFINED:
+ break;
+ case IMX_CLK_LINK:
+ clknode_link_register(sc->clkdom,
+ sc->clks[i].clk.link);
+ break;
+ case IMX_CLK_FIXED:
+ clknode_fixed_register(sc->clkdom,
+ sc->clks[i].clk.fixed);
+ break;
+ case IMX_CLK_MUX:
+ imx_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
+ break;
+ case IMX_CLK_GATE:
+ imx_clk_gate_register(sc->clkdom, sc->clks[i].clk.gate);
+ break;
+ case IMX_CLK_COMPOSITE:
+ imx_clk_composite_register(sc->clkdom, sc->clks[i].clk.composite);
+ break;
+ case IMX_CLK_SSCG_PLL:
+ imx_clk_sscg_pll_register(sc->clkdom, sc->clks[i].clk.sscg_pll);
+ break;
+ case IMX_CLK_FRAC_PLL:
+ imx_clk_frac_pll_register(sc->clkdom, sc->clks[i].clk.frac_pll);
+ break;
+ case IMX_CLK_DIV:
+ clknode_div_register(sc->clkdom, sc->clks[i].clk.div);
+ break;
+ default:
+ device_printf(dev, "Unknown clock type %d\n", sc->clks[i].type);
+ return (ENXIO);
+ }
+ }
+
+ if (clkdom_finit(sc->clkdom) != 0)
+ panic("cannot finalize clkdom initialization\n");
+
+ if (bootverbose)
+ clkdom_dump(sc->clkdom);
+
+ node = ofw_bus_get_node(dev);
+ clk_set_assigned(dev, node);
+
+ err = 0;
+
+out:
+
+ if (err != 0)
+ ccm_detach(dev);
+
+ return (err);
+}
+
+static int
+ccm_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_is_compatible(dev, "fsl,imx8mq-ccm") == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Freescale i.MX8 Clock Control Module");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+imx_ccm_write_4(device_t dev, bus_addr_t addr, uint32_t val)
+{
+ struct ccm_softc *sc;
+
+ sc = device_get_softc(dev);
+ CCU_WRITE4(sc, addr, val);
+ return (0);
+}
+
+static int
+imx_ccm_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
+{
+ struct ccm_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ *val = CCU_READ4(sc, addr);
+ return (0);
+}
+
+static int
+imx_ccm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
+{
+ struct ccm_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ reg = CCU_READ4(sc, addr);
+ reg &= ~clr;
+ reg |= set;
+ CCU_WRITE4(sc, addr, reg);
+
+ return (0);
+}
+
+static void
+imx_ccm_device_lock(device_t dev)
+{
+ struct ccm_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+static void
+imx_ccm_device_unlock(device_t dev)
+{
+ struct ccm_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+static device_method_t ccm_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ccm_probe),
+ DEVMETHOD(device_attach, ccm_attach),
+ DEVMETHOD(device_detach, ccm_detach),
+
+ /* clkdev interface */
+ DEVMETHOD(clkdev_write_4, imx_ccm_write_4),
+ DEVMETHOD(clkdev_read_4, imx_ccm_read_4),
+ DEVMETHOD(clkdev_modify_4, imx_ccm_modify_4),
+ DEVMETHOD(clkdev_device_lock, imx_ccm_device_lock),
+ DEVMETHOD(clkdev_device_unlock, imx_ccm_device_unlock),
+
+ DEVMETHOD_END
+};
+
+static driver_t ccm_driver = {
+ "ccm",
+ ccm_methods,
+ sizeof(struct ccm_softc)
+};
+
+static devclass_t ccm_devclass;
+
+EARLY_DRIVER_MODULE(ccm, simplebus, ccm_driver, ccm_devclass, 0, 0,
+ BUS_PASS_CPU + BUS_PASS_ORDER_EARLY);
Index: sys/arm64/freescale/imx/imx_ccm_clk.h
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/imx_ccm_clk.h
@@ -0,0 +1,213 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+
+#ifndef IMX6_CCM_CLK_H
+#define IMX6_CCM_CLK_H
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_gate.h>
+#include <dev/extres/clk/clk_link.h>
+
+enum imx_clk_type {
+ IMX_CLK_UNDEFINED = 0,
+ IMX_CLK_FIXED,
+ IMX_CLK_LINK,
+ IMX_CLK_MUX,
+ IMX_CLK_GATE,
+ IMX_CLK_COMPOSITE,
+ IMX_CLK_SSCG_PLL,
+ IMX_CLK_FRAC_PLL,
+ IMX_CLK_DIV,
+};
+
+struct imx_clk {
+ enum imx_clk_type type;
+ union {
+ struct clk_fixed_def *fixed;
+ struct clk_link_def *link;
+ struct imx_clk_mux_def *mux;
+ struct imx_clk_gate_def *gate;
+ struct imx_clk_composite_def *composite;
+ struct imx_clk_sscg_pll_def *sscg_pll;
+ struct imx_clk_frac_pll_def *frac_pll;
+ struct clk_div_def *div;
+ } clk;
+};
+
+/* Linked clock. */
+#define LINK(_id, _name) \
+{ \
+ .type = IMX_CLK_LINK, \
+ .clk.link = &(struct clk_link_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = NULL, \
+ .clkdef.parent_cnt = 0, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ }, \
+}
+
+/* Complex clock without divider (multiplexer only). */
+#define MUX(_id, _name, _pn, _f, _mo, _ms, _mw) \
+{ \
+ .type = IMX_CLK_MUX, \
+ .clk.mux = &(struct imx_clk_mux_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = _pn, \
+ .clkdef.parent_cnt = nitems(_pn), \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = _mo, \
+ .shift = _ms, \
+ .width = _mw, \
+ .mux_flags = _f, \
+ }, \
+}
+
+/* Fixed frequency clock */
+#define FIXED(_id, _name, _freq) \
+{ \
+ .type = IMX_CLK_FIXED, \
+ .clk.fixed = &(struct clk_fixed_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .freq = _freq, \
+ }, \
+}
+
+/* Fixed factor multipier/divider. */
+#define FFACT(_id, _name, _pname, _mult, _div) \
+{ \
+ .type = IMX_CLK_FIXED, \
+ .clk.fixed = &(struct clk_fixed_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = (const char *[]){_pname}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .mult = _mult, \
+ .div = _div, \
+ }, \
+}
+
+/* Clock gate */
+#define GATE(_id, _name, _pname, _o, _shift) \
+{ \
+ .type = IMX_CLK_GATE, \
+ .clk.gate = &(struct imx_clk_gate_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = (const char *[]){_pname}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = _o, \
+ .shift = _shift, \
+ .mask = 1, \
+ }, \
+}
+
+/* Root clock gate */
+#define ROOT_GATE(_id, _name, _pname, _reg) \
+{ \
+ .type = IMX_CLK_GATE, \
+ .clk.gate = &(struct imx_clk_gate_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = (const char *[]){_pname}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = _reg, \
+ .shift = 0, \
+ .mask = 3, \
+ }, \
+}
+
+/* Composite clock with GATE, MUX, PRE_DIV, and POST_DIV */
+#define COMPOSITE(_id, _name, _pn, _o, _flags) \
+{ \
+ .type = IMX_CLK_COMPOSITE, \
+ .clk.composite = &(struct imx_clk_composite_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = _pn, \
+ .clkdef.parent_cnt = nitems(_pn), \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = _o, \
+ .flags = _flags, \
+ }, \
+}
+
+/* SSCG PLL */
+#define SSCG_PLL(_id, _name, _pn, _o) \
+{ \
+ .type = IMX_CLK_SSCG_PLL, \
+ .clk.composite = &(struct imx_clk_composite_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = _pn, \
+ .clkdef.parent_cnt = nitems(_pn), \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = _o, \
+ }, \
+}
+
+/* Fractional PLL */
+#define FRAC_PLL(_id, _name, _pname, _o) \
+{ \
+ .type = IMX_CLK_FRAC_PLL, \
+ .clk.frac_pll = &(struct imx_clk_frac_pll_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = (const char *[]){_pname}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = _o, \
+ }, \
+}
+
+#define DIV(_id, _name, _pname, _o, _shift, _width) \
+{ \
+ .type = IMX_CLK_DIV, \
+ .clk.div = &(struct clk_div_def) { \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = (const char *[]){_pname}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = _o, \
+ .i_shift = _shift, \
+ .i_width = _width, \
+ }, \
+}
+
+#endif
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3172,6 +3172,7 @@
dev/uart/uart_core.c optional uart
dev/uart/uart_cpu_acpi.c optional uart acpi
dev/uart/uart_dbg.c optional uart gdb
+dev/uart/uart_dev_imx.c optional uart uart_imx fdt
dev/uart/uart_dev_msm.c optional uart uart_msm fdt
dev/uart/uart_dev_mvebu.c optional uart uart_mvebu
dev/uart/uart_dev_ns8250.c optional uart uart_ns8250 | uart uart_snps
Index: sys/conf/files.arm64
===================================================================
--- sys/conf/files.arm64
+++ sys/conf/files.arm64
@@ -388,3 +388,19 @@
arm64/rockchip/clk/rk3328_cru.c optional fdt soc_rockchip_rk3328
arm64/rockchip/clk/rk3399_cru.c optional fdt soc_rockchip_rk3399
arm64/rockchip/clk/rk3399_pmucru.c optional fdt soc_rockchip_rk3399
+
+# i.MX8 Clock support
+arm64/freescale/imx/imx8mq_ccm.c optional fdt soc_freescale_imx8mq
+arm64/freescale/imx/clk/imx_clk_gate.c optional fdt soc_freescale_imx8mq
+arm64/freescale/imx/clk/imx_clk_mux.c optional fdt soc_freescale_imx8mq
+arm64/freescale/imx/clk/imx_clk_composite.c optional fdt soc_freescale_imx8mq
+arm64/freescale/imx/clk/imx_clk_sscg_pll.c optional fdt soc_freescale_imx8mq
+arm64/freescale/imx/clk/imx_clk_frac_pll.c optional fdt soc_freescale_imx8mq
+
+# iMX drivers
+arm/freescale/imx/imx_gpio.c optional gpio
+arm/freescale/imx/imx_i2c.c optional fsliic
+arm/freescale/imx/imx_machdep.c standard
+arm/freescale/imx/imx_wdog.c optional imxwdt
+arm64/freescale/imx/imx7gpc.c optional fdt soc_freescale_imx8mq
+dev/ffec/if_ffec.c optional ffec
Index: sys/conf/options.arm64
===================================================================
--- sys/conf/options.arm64
+++ sys/conf/options.arm64
@@ -22,6 +22,7 @@
SOC_BRCM_BCM2837 opt_soc.h
SOC_BRCM_BCM2838 opt_soc.h
SOC_CAVM_THUNDERX opt_soc.h
+SOC_FREESCALE_IMX8MQ opt_soc.h
SOC_HISI_HI6220 opt_soc.h
SOC_INTEL_STRATIX10 opt_soc.h
SOC_MARVELL_8K opt_soc.h
Index: sys/dev/ffec/if_ffec.c
===================================================================
--- sys/dev/ffec/if_ffec.c
+++ sys/dev/ffec/if_ffec.c
@@ -123,6 +123,7 @@
{"fsl,imx53-fec", FECTYPE_IMX53},
{"fsl,imx6q-fec", FECTYPE_IMX6 | FECFLAG_RACC | FECFLAG_GBE },
{"fsl,imx6ul-fec", FECTYPE_IMX6 | FECFLAG_RACC },
+ {"fsl,imx6sx-fec", FECTYPE_IMX6 | FECFLAG_RACC },
{"fsl,imx7d-fec", FECTYPE_IMX6 | FECFLAG_RACC | FECFLAG_GBE |
FECFLAG_AVB },
{"fsl,mvf600-fec", FECTYPE_MVF | FECFLAG_RACC },
Index: sys/dev/uart/uart_dev_imx.c
===================================================================
--- sys/dev/uart/uart_dev_imx.c
+++ sys/dev/uart/uart_dev_imx.c
@@ -40,13 +40,21 @@
#include <sys/conf.h>
#include <sys/kdb.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_cpu.h>
#include <dev/uart/uart_cpu_fdt.h>
#include <dev/uart/uart_bus.h>
#include <dev/uart/uart_dev_imx.h>
+
+#if defined(EXT_RESOURCES) && defined(__aarch64__)
+#define IMX_ENABLE_CLOCKS
+#endif
+
+#ifdef IMX_ENABLE_CLOCKS
+#include <dev/extres/clk/clk.h>
+#endif
+
#include "uart_if.h"
#include <arm/freescale/imx/imx_ccmvar.h>
@@ -125,7 +133,7 @@
*/
i = (GETREG(bas, REG(UFCR)) & IMXUART_UFCR_RFDIV_MASK) >>
IMXUART_UFCR_RFDIV_SHIFT;
- rate = imx_ccm_uart_hz() / predivs[i];
+ rate = bas->rclk / predivs[i];
ubir = GETREG(bas, REG(UBIR)) + 1;
ubmr = GETREG(bas, REG(UBMR)) + 1;
baud = ((rate / 16 ) * ubir) / ubmr;
@@ -193,8 +201,8 @@
* Note that a quirk of the hardware requires that both UBIR and UBMR be
* set back to back in order for the change to take effect.
*/
- if (baudrate > 0) {
- baseclk = imx_ccm_uart_hz();
+ if ((baudrate > 0) && (bas->rclk != 0)) {
+ baseclk = bas->rclk;
reg = GETREG(bas, REG(UFCR));
reg = (reg & ~IMXUART_UFCR_RFDIV_MASK) | IMXUART_UFCR_RFDIV_DIV1;
SETREG(bas, REG(UFCR), reg);
@@ -323,6 +331,42 @@
i = (i & s) ? (i & ~s) | d : i; \
}
+#ifdef IMX_ENABLE_CLOCKS
+static int
+imx_uart_setup_clocks(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ clk_t ipgclk, perclk;
+ uint64_t freq;
+ int error;
+
+ bas = &sc->sc_bas;
+
+ if (clk_get_by_ofw_name(sc->sc_dev, 0, "ipg", &ipgclk) != 0)
+ return (ENOENT);
+
+ if (clk_get_by_ofw_name(sc->sc_dev, 0, "per", &perclk) != 0) {
+ return (ENOENT);
+ }
+
+ error = clk_enable(ipgclk);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "cannot enable ipg clock\n");
+ return (error);
+ }
+
+ error = clk_get_freq(perclk, &freq);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "cannot get frequency\n");
+ return (error);
+ }
+
+ bas->rclk = (uint32_t)freq;
+
+ return (0);
+}
+#endif
+
static int
imx_uart_bus_attach(struct uart_softc *sc)
{
@@ -330,6 +374,15 @@
struct uart_devinfo *di;
bas = &sc->sc_bas;
+
+#ifdef IMX_ENABLE_CLOCKS
+ int error = imx_uart_setup_clocks(sc);
+ if (error)
+ return (error);
+#else
+ bas->rclk = imx_ccm_uart_hz();
+#endif
+
if (sc->sc_sysdev != NULL) {
di = sc->sc_sysdev;
imx_uart_init(bas, di->baudrate, di->databits, di->stopbits,
Index: sys/modules/dtb/imx8/Makefile
===================================================================
--- /dev/null
+++ sys/modules/dtb/imx8/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+# All the dts files for imx6 systems we support.
+DTS= \
+ freescale/imx8mq-evk.dts \
+ freescale/imx8mq-nitrogen.dts
+
+.include <bsd.dtb.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, May 23, 11:32 PM (9 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33458851
Default Alt Text
D25274.id73120.diff (80 KB)
Attached To
Mode
D25274: Add iMX8MQ support
Attached
Detach File
Event Timeline
Log In to Comment