Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 1 Jul 2020 00:33:16 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r362817 - in head/sys: arm/freescale/imx arm64/conf arm64/freescale arm64/freescale/imx arm64/freescale/imx/clk conf dev/ffec dev/uart modules/dtb/imx8
Message-ID:  <202007010033.0610XGUm037426@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gonzo
Date: Wed Jul  1 00:33:16 2020
New Revision: 362817
URL: https://svnweb.freebsd.org/changeset/base/362817

Log:
  Add i.MX 8M Quad support
  
  - Add CCM driver and clocks implementations for i.MX 8M
  - Add GPC driver for iMX8
  - Add clock tree for i.MX 8M Quad
  - Add clocks support and new compat strings (where required) for existing i.MX 6 UART, I2C, and GPIO drivers
  - Enable aarch64-compatible drivers form i.MX 6 in arm64 GENERIC kernel config
  - Add dtb/imx8 kernel module with DTBs for Nitrogen8M and iMX8MQ EVK
  
  With this patch both Nitrogen8M and iMX8MQ EVK boot with NFS root up to multiuser login prompt
  
  Reviewed by:	manu
  Differential Revision:	https://reviews.freebsd.org/D25274

Added:
  head/sys/arm64/freescale/
  head/sys/arm64/freescale/imx/
  head/sys/arm64/freescale/imx/clk/
  head/sys/arm64/freescale/imx/clk/imx_clk_composite.c   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_composite.h   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_frac_pll.c   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_frac_pll.h   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_gate.c   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_gate.h   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_mux.c   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_mux.h   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.c   (contents, props changed)
  head/sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.h   (contents, props changed)
  head/sys/arm64/freescale/imx/imx7gpc.c   (contents, props changed)
  head/sys/arm64/freescale/imx/imx8mq_ccm.c   (contents, props changed)
  head/sys/arm64/freescale/imx/imx8mq_ccm.h   (contents, props changed)
  head/sys/arm64/freescale/imx/imx_ccm_clk.h   (contents, props changed)
  head/sys/modules/dtb/imx8/
  head/sys/modules/dtb/imx8/Makefile   (contents, props changed)
Modified:
  head/sys/arm/freescale/imx/imx_gpio.c
  head/sys/arm/freescale/imx/imx_i2c.c
  head/sys/arm/freescale/imx/imx_iomux.c
  head/sys/arm64/conf/GENERIC
  head/sys/conf/files
  head/sys/conf/files.arm64
  head/sys/conf/options.arm64
  head/sys/dev/ffec/if_ffec.c
  head/sys/dev/uart/uart_dev_imx.c

Modified: head/sys/arm/freescale/imx/imx_gpio.c
==============================================================================
--- head/sys/arm/freescale/imx/imx_gpio.c	Wed Jul  1 00:24:55 2020	(r362816)
+++ head/sys/arm/freescale/imx/imx_gpio.c	Wed Jul  1 00:33:16 2020	(r362817)
@@ -57,6 +57,14 @@ __FBSDID("$FreeBSD$");
 #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 @@ struct imx51_gpio_softc {
 #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 @@ imx51_gpio_attach(device_t dev)
 {
 	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 @@ imx51_gpio_attach(device_t dev)
 
 	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,8 +878,19 @@ imx51_gpio_detach(device_t dev)
 {
 	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++) {

Modified: head/sys/arm/freescale/imx/imx_i2c.c
==============================================================================
--- head/sys/arm/freescale/imx/imx_i2c.c	Wed Jul  1 00:24:55 2020	(r362816)
+++ head/sys/arm/freescale/imx/imx_i2c.c	Wed Jul  1 00:33:16 2020	(r362817)
@@ -73,6 +73,14 @@ __FBSDID("$FreeBSD$");
 #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 clkdiv clkdiv_table[] = {
 };
 
 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 @@ struct i2c_softc {
 	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 @@ i2c_attach(device_t dev)
 	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 @@ i2c_detach(device_t dev)
 
 	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 @@ i2c_reset(device_t dev, u_char speed, u_char addr, u_c
 {
 	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 @@ i2c_reset(device_t dev, u_char speed, u_char addr, u_c
 	 * 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++) {

Modified: head/sys/arm/freescale/imx/imx_iomux.c
==============================================================================
--- head/sys/arm/freescale/imx/imx_iomux.c	Wed Jul  1 00:24:55 2020	(r362816)
+++ head/sys/arm/freescale/imx/imx_iomux.c	Wed Jul  1 00:33:16 2020	(r362817)
@@ -76,6 +76,7 @@ struct iomux_softc {
 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},

Modified: head/sys/arm64/conf/GENERIC
==============================================================================
--- head/sys/arm64/conf/GENERIC	Wed Jul  1 00:24:55 2020	(r362816)
+++ head/sys/arm64/conf/GENERIC	Wed Jul  1 00:33:16 2020	(r362817)
@@ -113,6 +113,7 @@ options 	SOC_ALLWINNER_A64
 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		al_eth		# Annapurna Alpine Ethernet NIC
 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 @@ device		rk_emmcphy
 
 # 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		rk_i2c		# RockChip I2C controller
 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 @@ options 	FDT
 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"

Added: head/sys/arm64/freescale/imx/clk/imx_clk_composite.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/freescale/imx/clk/imx_clk_composite.c	Wed Jul  1 00:33:16 2020	(r362817)
@@ -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, &reg);
+	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);
+}

Added: head/sys/arm64/freescale/imx/clk/imx_clk_composite.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/freescale/imx/clk/imx_clk_composite.h	Wed Jul  1 00:33:16 2020	(r362817)
@@ -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_ */

Added: head/sys/arm64/freescale/imx/clk/imx_clk_frac_pll.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/freescale/imx/clk/imx_clk_frac_pll.c	Wed Jul  1 00:33:16 2020	(r362817)
@@ -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);
+}

Added: head/sys/arm64/freescale/imx/clk/imx_clk_frac_pll.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/freescale/imx/clk/imx_clk_frac_pll.h	Wed Jul  1 00:33:16 2020	(r362817)
@@ -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_ */

Added: head/sys/arm64/freescale/imx/clk/imx_clk_gate.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/freescale/imx/clk/imx_clk_gate.c	Wed Jul  1 00:33:16 2020	(r362817)
@@ -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, &reg);
+	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);
+}

Added: head/sys/arm64/freescale/imx/clk/imx_clk_gate.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/freescale/imx/clk/imx_clk_gate.h	Wed Jul  1 00:33:16 2020	(r362817)
@@ -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_ */

Added: head/sys/arm64/freescale/imx/clk/imx_clk_mux.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/freescale/imx/clk/imx_clk_mux.c	Wed Jul  1 00:33:16 2020	(r362817)
@@ -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

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202007010033.0610XGUm037426>