Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131424898
D25274.id73181.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
85 KB
Referenced Files
None
Subscribers
None
D25274.id73181.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/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_IMX8
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
@@ -352,4 +356,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);
+
+ /* PLL is bypassed */
+ if (cfg0 & CFG0_BYPASS2)
+ return (0);
+
+ 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;
+
+ 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,263 @@
+/*-
+ * 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.
+ */
+
+#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.h
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/imx8mq_ccm.h
@@ -0,0 +1,173 @@
+/*-
+ * 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 __IMX8MQ_CCM_H__
+#define __IMX8MQ_CCM_H__
+
+#define IMX8MQ_CLK_DUMMY 0
+#define IMX8MQ_CLK_32K 1
+#define IMX8MQ_CLK_25M 2
+#define IMX8MQ_CLK_27M 3
+#define IMX8MQ_CLK_EXT1 4
+#define IMX8MQ_CLK_EXT2 5
+#define IMX8MQ_CLK_EXT3 6
+#define IMX8MQ_CLK_EXT4 7
+
+#define IMX8MQ_ARM_PLL_REF_SEL 8
+#define IMX8MQ_ARM_PLL_REF_DIV 9
+#define IMX8MQ_ARM_PLL 10
+#define IMX8MQ_ARM_PLL_BYPASS 11
+#define IMX8MQ_ARM_PLL_OUT 12
+
+#define IMX8MQ_GPU_PLL_REF_SEL 13
+#define IMX8MQ_GPU_PLL_REF_DIV 14
+#define IMX8MQ_GPU_PLL 15
+#define IMX8MQ_GPU_PLL_BYPASS 16
+#define IMX8MQ_GPU_PLL_OUT 17
+
+#define IMX8MQ_VPU_PLL_REF_SEL 18
+#define IMX8MQ_VPU_PLL_REF_DIV 19
+#define IMX8MQ_VPU_PLL 20
+#define IMX8MQ_VPU_PLL_BYPASS 21
+#define IMX8MQ_VPU_PLL_OUT 22
+
+#define IMX8MQ_AUDIO_PLL1_REF_SEL 23
+#define IMX8MQ_AUDIO_PLL1_REF_DIV 24
+#define IMX8MQ_AUDIO_PLL1 25
+#define IMX8MQ_AUDIO_PLL1_BYPASS 26
+#define IMX8MQ_AUDIO_PLL1_OUT 27
+
+#define IMX8MQ_AUDIO_PLL2_REF_SEL 28
+#define IMX8MQ_AUDIO_PLL2_REF_DIV 29
+#define IMX8MQ_AUDIO_PLL2 30
+#define IMX8MQ_AUDIO_PLL2_BYPASS 31
+#define IMX8MQ_AUDIO_PLL2_OUT 32
+
+#define IMX8MQ_VIDEO_PLL1_REF_SEL 33
+#define IMX8MQ_VIDEO_PLL1_REF_DIV 34
+#define IMX8MQ_VIDEO_PLL1 35
+#define IMX8MQ_VIDEO_PLL1_BYPASS 36
+#define IMX8MQ_VIDEO_PLL1_OUT 37
+
+#define IMX8MQ_SYS3_PLL1_REF_SEL 54
+#define IMX8MQ_SYS3_PLL1 56
+
+#define IMX8MQ_DRAM_PLL1_REF_SEL 62
+
+#define IMX8MQ_SYS1_PLL_40M 70
+#define IMX8MQ_SYS1_PLL_80M 71
+#define IMX8MQ_SYS1_PLL_100M 72
+#define IMX8MQ_SYS1_PLL_133M 73
+#define IMX8MQ_SYS1_PLL_160M 74
+#define IMX8MQ_SYS1_PLL_200M 75
+#define IMX8MQ_SYS1_PLL_266M 76
+#define IMX8MQ_SYS1_PLL_400M 77
+#define IMX8MQ_SYS1_PLL_800M 78
+
+#define IMX8MQ_SYS2_PLL_50M 79
+#define IMX8MQ_SYS2_PLL_100M 80
+#define IMX8MQ_SYS2_PLL_125M 81
+#define IMX8MQ_SYS2_PLL_166M 82
+#define IMX8MQ_SYS2_PLL_200M 83
+#define IMX8MQ_SYS2_PLL_250M 84
+#define IMX8MQ_SYS2_PLL_333M 85
+#define IMX8MQ_SYS2_PLL_500M 86
+#define IMX8MQ_SYS2_PLL_1000M 87
+
+#define IMX8MQ_CLK_ENET_AXI 104
+#define IMX8MQ_CLK_USB_BUS 110
+
+#define IMX8MQ_CLK_AHB 116
+
+#define IMX8MQ_CLK_ENET_REF 137
+#define IMX8MQ_CLK_ENET_TIMER 138
+#define IMX8MQ_CLK_ENET_PHY_REF 139
+#define IMX8MQ_CLK_USDHC1 142
+#define IMX8MQ_CLK_USDHC2 143
+#define IMX8MQ_CLK_I2C1 144
+#define IMX8MQ_CLK_I2C2 145
+#define IMX8MQ_CLK_I2C3 146
+#define IMX8MQ_CLK_I2C4 147
+#define IMX8MQ_CLK_UART1 148
+#define IMX8MQ_CLK_UART2 149
+#define IMX8MQ_CLK_UART3 150
+#define IMX8MQ_CLK_UART4 151
+#define IMX8MQ_CLK_USB_CORE_REF 152
+#define IMX8MQ_CLK_USB_PHY_REF 153
+
+#define IMX8MQ_CLK_ENET1_ROOT 182
+#define IMX8MQ_CLK_I2C1_ROOT 184
+#define IMX8MQ_CLK_I2C2_ROOT 185
+#define IMX8MQ_CLK_I2C3_ROOT 186
+#define IMX8MQ_CLK_I2C4_ROOT 187
+#define IMX8MQ_CLK_UART1_ROOT 202
+#define IMX8MQ_CLK_UART2_ROOT 203
+#define IMX8MQ_CLK_UART3_ROOT 204
+#define IMX8MQ_CLK_UART4_ROOT 205
+#define IMX8MQ_CLK_USB1_CTRL_ROOT 206
+#define IMX8MQ_CLK_USB2_CTRL_ROOT 207
+#define IMX8MQ_CLK_USB1_PHY_ROOT 208
+#define IMX8MQ_CLK_USB2_PHY_ROOT 209
+#define IMX8MQ_CLK_USDHC1_ROOT 210
+#define IMX8MQ_CLK_USDHC2_ROOT 211
+
+#define IMX8MQ_SYS1_PLL_OUT 231
+#define IMX8MQ_SYS2_PLL_OUT 232
+#define IMX8MQ_SYS3_PLL_OUT 233
+
+#define IMX8MQ_CLK_IPG_ROOT 236
+
+#define IMX8MQ_CLK_GPIO1_ROOT 259
+#define IMX8MQ_CLK_GPIO2_ROOT 260
+#define IMX8MQ_CLK_GPIO3_ROOT 261
+#define IMX8MQ_CLK_GPIO4_ROOT 262
+#define IMX8MQ_CLK_GPIO5_ROOT 263
+
+#define IMX8MQ_VIDEO2_PLL1_REF_SEL 266
+
+#define IMX8MQ_SYS1_PLL_40M_CG 267
+#define IMX8MQ_SYS1_PLL_80M_CG 268
+#define IMX8MQ_SYS1_PLL_100M_CG 269
+#define IMX8MQ_SYS1_PLL_133M_CG 270
+#define IMX8MQ_SYS1_PLL_160M_CG 271
+#define IMX8MQ_SYS1_PLL_200M_CG 272
+#define IMX8MQ_SYS1_PLL_266M_CG 273
+#define IMX8MQ_SYS1_PLL_400M_CG 274
+#define IMX8MQ_SYS1_PLL_800M_CG 275
+#define IMX8MQ_SYS2_PLL_50M_CG 276
+#define IMX8MQ_SYS2_PLL_100M_CG 277
+#define IMX8MQ_SYS2_PLL_125M_CG 278
+#define IMX8MQ_SYS2_PLL_166M_CG 279
+#define IMX8MQ_SYS2_PLL_200M_CG 280
+#define IMX8MQ_SYS2_PLL_250M_CG 281
+#define IMX8MQ_SYS2_PLL_333M_CG 282
+#define IMX8MQ_SYS2_PLL_500M_CG 283
+#define IMX8MQ_SYS2_PLL_1000M_CG 284
+
+#endif
Index: sys/arm64/freescale/imx/imx8mq_ccm.c
===================================================================
--- /dev/null
+++ sys/arm64/freescale/imx/imx8mq_ccm.c
@@ -0,0 +1,484 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Clocks driver for Freescale i.MX8MQ SoC
+ */
+
+#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/imx8mq_ccm.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 "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,212 @@
+/*-
+ * 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 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,18 @@
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_imx8
+arm64/freescale/imx/clk/imx_clk_gate.c optional fdt soc_freescale_imx8
+arm64/freescale/imx/clk/imx_clk_mux.c optional fdt soc_freescale_imx8
+arm64/freescale/imx/clk/imx_clk_composite.c optional fdt soc_freescale_imx8
+arm64/freescale/imx/clk/imx_clk_sscg_pll.c optional fdt soc_freescale_imx8
+arm64/freescale/imx/clk/imx_clk_frac_pll.c optional fdt soc_freescale_imx8
+
+# 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
+arm64/freescale/imx/imx7gpc.c optional fdt soc_freescale_imx8
+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_IMX8 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 imx8 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
Wed, Oct 8, 10:19 PM (12 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23475602
Default Alt Text
D25274.id73181.diff (85 KB)
Attached To
Mode
D25274: Add iMX8MQ support
Attached
Detach File
Event Timeline
Log In to Comment