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 <m...@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 <m...@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 <go...@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 <go...@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 <m...@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 <m...@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 <m...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to