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, ®); + 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, ®); + 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>