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
This commit is contained in:
parent
39ca7ca568
commit
94bc2117b4
@ -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,9 +878,20 @@ 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++) {
|
||||
if (sc->gpio_ih[irq])
|
||||
|
@ -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_char *oldadr)
|
||||
{
|
||||
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_char *oldadr)
|
||||
* 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++) {
|
||||
|
@ -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},
|
||||
|
@ -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"
|
||||
|
309
sys/arm64/freescale/imx/clk/imx_clk_composite.c
Normal file
309
sys/arm64/freescale/imx/clk/imx_clk_composite.c
Normal file
@ -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);
|
||||
}
|
45
sys/arm64/freescale/imx/clk/imx_clk_composite.h
Normal file
45
sys/arm64/freescale/imx/clk/imx_clk_composite.h
Normal file
@ -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_ */
|
177
sys/arm64/freescale/imx/clk/imx_clk_frac_pll.c
Normal file
177
sys/arm64/freescale/imx/clk/imx_clk_frac_pll.c
Normal file
@ -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);
|
||||
}
|
42
sys/arm64/freescale/imx/clk/imx_clk_frac_pll.h
Normal file
42
sys/arm64/freescale/imx/clk/imx_clk_frac_pll.h
Normal file
@ -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_ */
|
117
sys/arm64/freescale/imx/clk/imx_clk_gate.c
Normal file
117
sys/arm64/freescale/imx/clk/imx_clk_gate.c
Normal file
@ -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);
|
||||
}
|
45
sys/arm64/freescale/imx/clk/imx_clk_gate.h
Normal file
45
sys/arm64/freescale/imx/clk/imx_clk_gate.h
Normal file
@ -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_ */
|
138
sys/arm64/freescale/imx/clk/imx_clk_mux.c
Normal file
138
sys/arm64/freescale/imx/clk/imx_clk_mux.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
#include <arm64/freescale/imx/clk/imx_clk_mux.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
|
||||
#define WR4(_clk, off, val) \
|
||||
CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
|
||||
#define RD4(_clk, off, val) \
|
||||
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
|
||||
#define MD4(_clk, off, clr, set ) \
|
||||
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
|
||||
#define DEVICE_LOCK(_clk) \
|
||||
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
|
||||
#define DEVICE_UNLOCK(_clk) \
|
||||
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
|
||||
|
||||
static int imx_clk_mux_init(struct clknode *clk, device_t dev);
|
||||
static int imx_clk_mux_set_mux(struct clknode *clk, int idx);
|
||||
|
||||
struct imx_clk_mux_sc {
|
||||
uint32_t offset;
|
||||
uint32_t shift;
|
||||
uint32_t mask;
|
||||
int mux_flags;
|
||||
};
|
||||
|
||||
static clknode_method_t imx_clk_mux_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, imx_clk_mux_init),
|
||||
CLKNODEMETHOD(clknode_set_mux, imx_clk_mux_set_mux),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
DEFINE_CLASS_1(imx_clk_mux, imx_clk_mux_class, imx_clk_mux_methods,
|
||||
sizeof(struct imx_clk_mux_sc), clknode_class);
|
||||
|
||||
|
||||
static int
|
||||
imx_clk_mux_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
uint32_t reg;
|
||||
struct imx_clk_mux_sc *sc;
|
||||
int rv;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
rv = RD4(clk, sc->offset, ®);
|
||||
DEVICE_UNLOCK(clk);
|
||||
if (rv != 0) {
|
||||
return (rv);
|
||||
}
|
||||
reg = (reg >> sc->shift) & sc->mask;
|
||||
clknode_init_parent_idx(clk, reg);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
imx_clk_mux_set_mux(struct clknode *clk, int idx)
|
||||
{
|
||||
uint32_t reg;
|
||||
struct imx_clk_mux_sc *sc;
|
||||
int rv;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
rv = MD4(clk, sc->offset, sc->mask << sc->shift,
|
||||
((idx & sc->mask) << sc->shift));
|
||||
if (rv != 0) {
|
||||
DEVICE_UNLOCK(clk);
|
||||
return (rv);
|
||||
}
|
||||
RD4(clk, sc->offset, ®);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
imx_clk_mux_register(struct clkdom *clkdom, struct imx_clk_mux_def *clkdef)
|
||||
{
|
||||
struct clknode *clk;
|
||||
struct imx_clk_mux_sc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &imx_clk_mux_class, &clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
sc->offset = clkdef->offset;
|
||||
sc->shift = clkdef->shift;
|
||||
sc->mask = (1 << clkdef->width) - 1;
|
||||
sc->mux_flags = clkdef->mux_flags;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
return (0);
|
||||
}
|
45
sys/arm64/freescale/imx/clk/imx_clk_mux.h
Normal file
45
sys/arm64/freescale/imx/clk/imx_clk_mux.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef _IMX_CLK_MUX_H_
|
||||
#define _IMX_CLK_MUX_H_
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
struct imx_clk_mux_def {
|
||||
struct clknode_init_def clkdef;
|
||||
uint32_t offset;
|
||||
uint32_t shift;
|
||||
uint32_t width;
|
||||
int mux_flags;
|
||||
};
|
||||
|
||||
int imx_clk_mux_register(struct clkdom *clkdom, struct imx_clk_mux_def *clkdef);
|
||||
|
||||
#endif /* _IMX_CLK_MUX_H_ */
|
195
sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.c
Normal file
195
sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.c
Normal file
@ -0,0 +1,195 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
#include <arm64/freescale/imx/clk/imx_clk_sscg_pll.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
|
||||
struct imx_clk_sscg_pll_sc {
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
#define WRITE4(_clk, off, val) \
|
||||
CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
|
||||
#define READ4(_clk, off, val) \
|
||||
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
|
||||
#define DEVICE_LOCK(_clk) \
|
||||
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
|
||||
#define DEVICE_UNLOCK(_clk) \
|
||||
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
|
||||
|
||||
#define CFG0 0x00
|
||||
#define CFG0_PLL_LOCK (1 << 31)
|
||||
#define CFG0_PD (1 << 7)
|
||||
#define CFG0_BYPASS2 (1 << 5)
|
||||
#define CFG0_BYPASS1 (1 << 4)
|
||||
#define CFG1 0x04
|
||||
#define CFG2 0x08
|
||||
#define CFG2_DIVR1_MASK (7 << 25)
|
||||
#define CFG2_DIVR1_SHIFT 25
|
||||
#define CFG2_DIVR2_MASK (0x3f << 19)
|
||||
#define CFG2_DIVR2_SHIFT 19
|
||||
#define CFG2_DIVF1_MASK (0x3f << 13)
|
||||
#define CFG2_DIVF1_SHIFT 13
|
||||
#define CFG2_DIVF2_MASK (0x3f << 7)
|
||||
#define CFG2_DIVF2_SHIFT 7
|
||||
#define CFG2_DIV_MASK (0x3f << 1)
|
||||
#define CFG2_DIV_SHIFT 1
|
||||
|
||||
#if 0
|
||||
#define dprintf(format, arg...) \
|
||||
printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
|
||||
#else
|
||||
#define dprintf(format, arg...)
|
||||
#endif
|
||||
|
||||
static int
|
||||
imx_clk_sscg_pll_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
struct imx_clk_sscg_pll_sc *sc;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
if (clknode_get_parents_num(clk) > 1) {
|
||||
device_printf(clknode_get_device(clk),
|
||||
"error: SSCG PLL does not support more than one parent yet\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
clknode_init_parent_idx(clk, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
imx_clk_sscg_pll_set_gate(struct clknode *clk, bool enable)
|
||||
{
|
||||
struct imx_clk_sscg_pll_sc *sc;
|
||||
uint32_t cfg0;
|
||||
int timeout;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset + CFG0, &cfg0);
|
||||
if (enable)
|
||||
cfg0 &= ~(CFG0_PD);
|
||||
else
|
||||
cfg0 |= CFG0_PD;
|
||||
WRITE4(clk, sc->offset + CFG0, cfg0);
|
||||
|
||||
/* Reading lock */
|
||||
if (enable) {
|
||||
for (timeout = 1000; timeout; timeout--) {
|
||||
READ4(clk, sc->offset + CFG0, &cfg0);
|
||||
if (cfg0 & CFG0_PLL_LOCK)
|
||||
break;
|
||||
DELAY(1);
|
||||
}
|
||||
}
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
imx_clk_sscg_pll_recalc(struct clknode *clk, uint64_t *freq)
|
||||
{
|
||||
struct imx_clk_sscg_pll_sc *sc;
|
||||
uint32_t cfg0, cfg2;
|
||||
int divr1, divr2, divf1, divf2, div;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset + CFG0, &cfg0);
|
||||
READ4(clk, sc->offset + CFG2, &cfg2);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
/* PLL is bypassed */
|
||||
if (cfg0 & CFG0_BYPASS2)
|
||||
return (0);
|
||||
|
||||
divr1 = (cfg2 & CFG2_DIVR1_MASK) >> CFG2_DIVR1_SHIFT;
|
||||
divr2 = (cfg2 & CFG2_DIVR2_MASK) >> CFG2_DIVR2_SHIFT;
|
||||
divf1 = (cfg2 & CFG2_DIVF1_MASK) >> CFG2_DIVF1_SHIFT;
|
||||
divf2 = (cfg2 & CFG2_DIVF2_MASK) >> CFG2_DIVF2_SHIFT;
|
||||
div = (cfg2 & CFG2_DIV_MASK) >> CFG2_DIV_SHIFT;
|
||||
|
||||
if (cfg0 & CFG0_BYPASS1) {
|
||||
*freq = *freq / ((divr2 + 1) * (div + 1));
|
||||
return (0);
|
||||
}
|
||||
|
||||
*freq *= 2 * (divf1 + 1) * (divf2 + 1);
|
||||
*freq /= (divr1 + 1) * (divr2 + 1) * (div + 1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static clknode_method_t imx_clk_sscg_pll_clknode_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, imx_clk_sscg_pll_init),
|
||||
CLKNODEMETHOD(clknode_set_gate, imx_clk_sscg_pll_set_gate),
|
||||
CLKNODEMETHOD(clknode_recalc_freq, imx_clk_sscg_pll_recalc),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(imx_clk_sscg_pll_clknode, imx_clk_sscg_pll_clknode_class,
|
||||
imx_clk_sscg_pll_clknode_methods, sizeof(struct imx_clk_sscg_pll_sc),
|
||||
clknode_class);
|
||||
|
||||
int
|
||||
imx_clk_sscg_pll_register(struct clkdom *clkdom,
|
||||
struct imx_clk_sscg_pll_def *clkdef)
|
||||
{
|
||||
struct clknode *clk;
|
||||
struct imx_clk_sscg_pll_sc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &imx_clk_sscg_pll_clknode_class,
|
||||
&clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
sc->offset = clkdef->offset;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
return (0);
|
||||
}
|
42
sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.h
Normal file
42
sys/arm64/freescale/imx/clk/imx_clk_sscg_pll.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _IMX_CLK_SSCG_PLL_H_
|
||||
#define _IMX_CLK_SSCG_PLL_H_
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
struct imx_clk_sscg_pll_def {
|
||||
struct clknode_init_def clkdef;
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
int imx_clk_sscg_pll_register(struct clkdom *clkdom, struct imx_clk_sscg_pll_def *clkdef);
|
||||
|
||||
#endif /* _IMX_CLK_SSCG_PLL_H_ */
|
263
sys/arm64/freescale/imx/imx7gpc.c
Normal file
263
sys/arm64/freescale/imx/imx7gpc.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/intr.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include "pic_if.h"
|
||||
|
||||
struct imx7gpc_softc {
|
||||
device_t dev;
|
||||
struct resource *memres;
|
||||
device_t parent;
|
||||
};
|
||||
|
||||
static struct ofw_compat_data compat_data[] = {
|
||||
{ "fsl,imx7gpc", 1},
|
||||
{ "fsl,imx8mq-gpc", 1},
|
||||
{ NULL, 0}
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
imx7gpc_read_4(struct imx7gpc_softc *sc, int reg)
|
||||
{
|
||||
|
||||
return (bus_read_4(sc->memres, reg));
|
||||
}
|
||||
|
||||
static inline void
|
||||
imx7gpc_write_4(struct imx7gpc_softc *sc, int reg, uint32_t val)
|
||||
{
|
||||
|
||||
bus_write_4(sc->memres, reg, val);
|
||||
}
|
||||
|
||||
static int
|
||||
imx7gpc_activate_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
|
||||
}
|
||||
|
||||
static void
|
||||
imx7gpc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
PIC_DISABLE_INTR(sc->parent, isrc);
|
||||
}
|
||||
|
||||
static void
|
||||
imx7gpc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
PIC_ENABLE_INTR(sc->parent, isrc);
|
||||
}
|
||||
|
||||
static int
|
||||
imx7gpc_map_intr(device_t dev, struct intr_map_data *data,
|
||||
struct intr_irqsrc **isrcp)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_MAP_INTR(sc->parent, data, isrcp));
|
||||
}
|
||||
|
||||
static int
|
||||
imx7gpc_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
|
||||
}
|
||||
|
||||
static int
|
||||
imx7gpc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
|
||||
}
|
||||
|
||||
static int
|
||||
imx7gpc_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
|
||||
}
|
||||
|
||||
static void
|
||||
imx7gpc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
PIC_PRE_ITHREAD(sc->parent, isrc);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
imx7gpc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
PIC_POST_ITHREAD(sc->parent, isrc);
|
||||
}
|
||||
|
||||
static void
|
||||
imx7gpc_post_filter(device_t dev, struct intr_irqsrc *isrc)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
PIC_POST_FILTER(sc->parent, isrc);
|
||||
}
|
||||
|
||||
#ifdef SMP
|
||||
static int
|
||||
imx7gpc_bind_intr(device_t dev, struct intr_irqsrc *isrc)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_BIND_INTR(sc->parent, isrc));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
imx7gpc_probe(device_t dev)
|
||||
{
|
||||
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "General Power Controller");
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
imx7gpc_attach(device_t dev)
|
||||
{
|
||||
struct imx7gpc_softc *sc = device_get_softc(dev);
|
||||
phandle_t node;
|
||||
phandle_t parent_xref;
|
||||
int i, rv;
|
||||
|
||||
sc->dev = dev;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
|
||||
rv = OF_getencprop(node, "interrupt-parent", &parent_xref,
|
||||
sizeof(parent_xref));
|
||||
if (rv <= 0) {
|
||||
device_printf(dev, "Can't read parent node property\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
sc->parent = OF_device_from_xref(parent_xref);
|
||||
if (sc->parent == NULL) {
|
||||
device_printf(dev, "Can't find parent controller\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
|
||||
i = 0;
|
||||
sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i,
|
||||
RF_ACTIVE);
|
||||
if (sc->memres == NULL) {
|
||||
device_printf(dev, "could not allocate resources\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* TODO: power up OTG domain and unmask all interrupts */
|
||||
|
||||
if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, i, sc->memres);
|
||||
device_printf(dev, "Cannot register PIC\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t imx7gpc_methods[] = {
|
||||
DEVMETHOD(device_probe, imx7gpc_probe),
|
||||
DEVMETHOD(device_attach, imx7gpc_attach),
|
||||
|
||||
/* Interrupt controller interface */
|
||||
DEVMETHOD(pic_activate_intr, imx7gpc_activate_intr),
|
||||
DEVMETHOD(pic_disable_intr, imx7gpc_disable_intr),
|
||||
DEVMETHOD(pic_enable_intr, imx7gpc_enable_intr),
|
||||
DEVMETHOD(pic_map_intr, imx7gpc_map_intr),
|
||||
DEVMETHOD(pic_deactivate_intr, imx7gpc_deactivate_intr),
|
||||
DEVMETHOD(pic_setup_intr, imx7gpc_setup_intr),
|
||||
DEVMETHOD(pic_teardown_intr, imx7gpc_teardown_intr),
|
||||
DEVMETHOD(pic_pre_ithread, imx7gpc_pre_ithread),
|
||||
DEVMETHOD(pic_post_ithread, imx7gpc_post_ithread),
|
||||
DEVMETHOD(pic_post_filter, imx7gpc_post_filter),
|
||||
#ifdef SMP
|
||||
DEVMETHOD(pic_bind_intr, imx7gpc_bind_intr),
|
||||
#endif
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t imx7gpc_driver = {
|
||||
"imx7gpc",
|
||||
imx7gpc_methods,
|
||||
sizeof(struct imx7gpc_softc),
|
||||
};
|
||||
|
||||
static devclass_t imx7gpc_devclass;
|
||||
|
||||
EARLY_DRIVER_MODULE(imx7gpc, ofwbus, imx7gpc_driver, imx7gpc_devclass, 0, 0,
|
||||
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
|
||||
EARLY_DRIVER_MODULE(imx7gpc, simplebus, imx7gpc_driver, imx7gpc_devclass, 0, 0,
|
||||
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
|
484
sys/arm64/freescale/imx/imx8mq_ccm.c
Normal file
484
sys/arm64/freescale/imx/imx8mq_ccm.c
Normal file
@ -0,0 +1,484 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Clocks driver for Freescale i.MX8MQ SoC
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <arm64/freescale/imx/imx_ccm_clk.h>
|
||||
#include <arm64/freescale/imx/imx8mq_ccm.h>
|
||||
#include <arm64/freescale/imx/clk/imx_clk_gate.h>
|
||||
#include <arm64/freescale/imx/clk/imx_clk_mux.h>
|
||||
#include <arm64/freescale/imx/clk/imx_clk_composite.h>
|
||||
#include <arm64/freescale/imx/clk/imx_clk_sscg_pll.h>
|
||||
#include <arm64/freescale/imx/clk/imx_clk_frac_pll.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
|
||||
static const char *pll_ref_p[] = {
|
||||
"osc_25m", "osc_27m", "dummy", "dummy"
|
||||
};
|
||||
static const char *sys3_pll_out_p[] = {
|
||||
"sys3_pll1_ref_sel"
|
||||
};
|
||||
static const char * arm_pll_bypass_p[] = {
|
||||
"arm_pll", "arm_pll_ref_sel"
|
||||
};
|
||||
static const char * gpu_pll_bypass_p[] = {
|
||||
"gpu_pll", "gpu_pll_ref_sel"
|
||||
};
|
||||
static const char * vpu_pll_bypass_p[] = {
|
||||
"vpu_pll", "vpu_pll_ref_sel"
|
||||
};
|
||||
static const char * audio_pll1_bypass_p[] = {
|
||||
"audio_pll1", "audio_pll1_ref_sel"
|
||||
};
|
||||
static const char * audio_pll2_bypass_p[] = {
|
||||
"audio_pll2", "audio_pll2_ref_sel"
|
||||
};
|
||||
static const char * video_pll1_bypass_p[] = {
|
||||
"video_pll1", "video_pll1_ref_sel"
|
||||
};
|
||||
static const char *uart_p[] = {
|
||||
"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m", "sys3_pll_out",
|
||||
"clk_ext2", "clk_ext4", "audio_pll2_out"
|
||||
};
|
||||
static const char *usdhc_p[] = {
|
||||
"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m", "audio_pll2_out",
|
||||
"sys1_pll_266m", "sys3_pll_out", "sys1_pll_100m"
|
||||
};
|
||||
static const char *enet_axi_p[] = {
|
||||
"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m", "sys2_pll_200m",
|
||||
"audio_pll1_out", "video_pll1_out", "sys3_pll_out"
|
||||
};
|
||||
static const char *enet_ref_p[] = {
|
||||
"osc_25m", "sys2_pll_125m", "sys2_pll_500m", "sys2_pll_100m", "sys1_pll_160m",
|
||||
"audio_pll1_out", "video_pll1_out", "clk_ext4"
|
||||
};
|
||||
static const char *enet_timer_p[] = {
|
||||
"osc_25m", "sys2_pll_100m", "audio_pll1_out", "clk_ext1", "clk_ext2", "clk_ext3",
|
||||
"clk_ext4", "video_pll1_out"
|
||||
};
|
||||
static const char *enet_phy_ref_p[] = {
|
||||
"osc_25m", "sys2_pll_50m", "sys2_pll_125m", "sys2_pll_500m", "audio_pll1_out",
|
||||
"video_pll1_out", "audio_pll2_out"
|
||||
};
|
||||
static const char *usb_bus_p[] = {
|
||||
"osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_100m", "sys2_pll_200m",
|
||||
"clk_ext2", "clk_ext4", "audio_pll2_out"
|
||||
};
|
||||
static const char *usb_core_phy_p[] = {
|
||||
"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m", "sys2_pll_200m",
|
||||
"clk_ext2", "clk_ext3", "audio_pll2_out"
|
||||
};
|
||||
static const char *i2c_p[] = {
|
||||
"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll_out", "audio_pll1_out",
|
||||
"video_pll1_out", "audio_pll2_out", "sys1_pll_133m"
|
||||
};
|
||||
static const char *ahb_p[] = {
|
||||
"osc_25m", "sys1_pll_133m", "sys1_pll_800m", "sys1_pll_400m", "sys2_pll_125m",
|
||||
"sys3_pll_out", "audio_pll1_out", "video_pll1_out"
|
||||
};
|
||||
|
||||
static struct imx_clk imx_clks[] = {
|
||||
FIXED(IMX8MQ_CLK_DUMMY, "dummy", 0),
|
||||
|
||||
LINK(IMX8MQ_CLK_32K, "ckil"),
|
||||
LINK(IMX8MQ_CLK_25M, "osc_25m"),
|
||||
LINK(IMX8MQ_CLK_27M, "osc_27m"),
|
||||
LINK(IMX8MQ_CLK_EXT1, "clk_ext1"),
|
||||
LINK(IMX8MQ_CLK_EXT2, "clk_ext2"),
|
||||
LINK(IMX8MQ_CLK_EXT3, "clk_ext3"),
|
||||
LINK(IMX8MQ_CLK_EXT4, "clk_ext4"),
|
||||
|
||||
FIXED(IMX8MQ_SYS1_PLL_OUT, "sys1_pll_out", 800000000),
|
||||
FIXED(IMX8MQ_SYS2_PLL_OUT, "sys2_pll_out", 1000000000),
|
||||
SSCG_PLL(IMX8MQ_SYS3_PLL_OUT, "sys3_pll_out", sys3_pll_out_p, 0x48),
|
||||
|
||||
MUX(IMX8MQ_ARM_PLL_REF_SEL, "arm_pll_ref_sel", pll_ref_p, 0, 0x28, 16, 2),
|
||||
MUX(IMX8MQ_GPU_PLL_REF_SEL, "gpu_pll_ref_sel", pll_ref_p, 0, 0x18, 16, 2),
|
||||
MUX(IMX8MQ_VPU_PLL_REF_SEL, "vpu_pll_ref_sel", pll_ref_p, 0, 0x20, 16, 2),
|
||||
MUX(IMX8MQ_AUDIO_PLL1_REF_SEL, "audio_pll1_ref_sel", pll_ref_p, 0, 0x0, 16, 2),
|
||||
MUX(IMX8MQ_AUDIO_PLL2_REF_SEL, "audio_pll2_ref_sel", pll_ref_p, 0, 0x8, 16, 2),
|
||||
MUX(IMX8MQ_VIDEO_PLL1_REF_SEL, "video_pll1_ref_sel", pll_ref_p, 0, 0x10, 16, 2),
|
||||
MUX(IMX8MQ_SYS3_PLL1_REF_SEL, "sys3_pll1_ref_sel", pll_ref_p, 0, 0x48, 0, 2),
|
||||
MUX(IMX8MQ_DRAM_PLL1_REF_SEL, "dram_pll1_ref_sel", pll_ref_p, 0, 0x60, 0, 2),
|
||||
MUX(IMX8MQ_VIDEO2_PLL1_REF_SEL, "video2_pll1_ref_sel", pll_ref_p, 0, 0x54, 0, 2),
|
||||
|
||||
DIV(IMX8MQ_ARM_PLL_REF_DIV, "arm_pll_ref_div", "arm_pll_ref_sel", 0x28, 5, 6),
|
||||
DIV(IMX8MQ_GPU_PLL_REF_DIV, "gpu_pll_ref_div", "gpu_pll_ref_sel", 0x18, 5, 6),
|
||||
DIV(IMX8MQ_VPU_PLL_REF_DIV, "vpu_pll_ref_div", "vpu_pll_ref_sel", 0x20, 5, 6),
|
||||
DIV(IMX8MQ_AUDIO_PLL1_REF_DIV, "audio_pll1_ref_div", "audio_pll1_ref_sel", 0x0, 5, 6),
|
||||
DIV(IMX8MQ_AUDIO_PLL2_REF_DIV, "audio_pll2_ref_div", "audio_pll2_ref_sel", 0x8, 5, 6),
|
||||
DIV(IMX8MQ_VIDEO_PLL1_REF_DIV, "video_pll1_ref_div", "video_pll1_ref_sel", 0x10, 5, 6),
|
||||
|
||||
FRAC_PLL(IMX8MQ_ARM_PLL, "arm_pll", "arm_pll_ref_div", 0x28),
|
||||
FRAC_PLL(IMX8MQ_GPU_PLL, "gpu_pll", "gpu_pll_ref_div", 0x18),
|
||||
FRAC_PLL(IMX8MQ_VPU_PLL, "vpu_pll", "vpu_pll_ref_div", 0x20),
|
||||
FRAC_PLL(IMX8MQ_AUDIO_PLL1, "audio_pll1", "audio_pll1_ref_div", 0x0),
|
||||
FRAC_PLL(IMX8MQ_AUDIO_PLL2, "audio_pll2", "audio_pll2_ref_div", 0x8),
|
||||
FRAC_PLL(IMX8MQ_VIDEO_PLL1, "video_pll1", "video_pll1_ref_div", 0x10),
|
||||
|
||||
/* ARM_PLL needs SET_PARENT flag */
|
||||
MUX(IMX8MQ_ARM_PLL_BYPASS, "arm_pll_bypass", arm_pll_bypass_p, 0, 0x28, 14, 1),
|
||||
MUX(IMX8MQ_GPU_PLL_BYPASS, "gpu_pll_bypass", gpu_pll_bypass_p, 0, 0x18, 14, 1),
|
||||
MUX(IMX8MQ_VPU_PLL_BYPASS, "vpu_pll_bypass", vpu_pll_bypass_p, 0, 0x20, 14, 1),
|
||||
MUX(IMX8MQ_AUDIO_PLL1_BYPASS, "audio_pll1_bypass", audio_pll1_bypass_p, 0, 0x0, 14, 1),
|
||||
MUX(IMX8MQ_AUDIO_PLL2_BYPASS, "audio_pll2_bypass", audio_pll2_bypass_p, 0, 0x8, 14, 1),
|
||||
MUX(IMX8MQ_VIDEO_PLL1_BYPASS, "video_pll1_bypass", video_pll1_bypass_p, 0, 0x10, 14, 1),
|
||||
|
||||
GATE(IMX8MQ_ARM_PLL_OUT, "arm_pll_out", "arm_pll_bypass", 0x28, 21),
|
||||
GATE(IMX8MQ_GPU_PLL_OUT, "gpu_pll_out", "gpu_pll_bypass", 0x18, 21),
|
||||
GATE(IMX8MQ_VPU_PLL_OUT, "vpu_pll_out", "vpu_pll_bypass", 0x20, 21),
|
||||
GATE(IMX8MQ_AUDIO_PLL1_OUT, "audio_pll1_out", "audio_pll1_bypass", 0x0, 21),
|
||||
GATE(IMX8MQ_AUDIO_PLL2_OUT, "audio_pll2_out", "audio_pll2_bypass", 0x8, 21),
|
||||
GATE(IMX8MQ_VIDEO_PLL1_OUT, "video_pll1_out", "video_pll1_bypass", 0x10, 21),
|
||||
|
||||
GATE(IMX8MQ_SYS1_PLL_40M_CG, "sys1_pll_40m_cg", "sys1_pll_out", 0x30, 9),
|
||||
GATE(IMX8MQ_SYS1_PLL_80M_CG, "sys1_pll_80m_cg", "sys1_pll_out", 0x30, 11),
|
||||
GATE(IMX8MQ_SYS1_PLL_100M_CG, "sys1_pll_100m_cg", "sys1_pll_out", 0x30, 13),
|
||||
GATE(IMX8MQ_SYS1_PLL_133M_CG, "sys1_pll_133m_cg", "sys1_pll_out", 0x30, 15),
|
||||
GATE(IMX8MQ_SYS1_PLL_160M_CG, "sys1_pll_160m_cg", "sys1_pll_out", 0x30, 17),
|
||||
GATE(IMX8MQ_SYS1_PLL_200M_CG, "sys1_pll_200m_cg", "sys1_pll_out", 0x30, 19),
|
||||
GATE(IMX8MQ_SYS1_PLL_266M_CG, "sys1_pll_266m_cg", "sys1_pll_out", 0x30, 21),
|
||||
GATE(IMX8MQ_SYS1_PLL_400M_CG, "sys1_pll_400m_cg", "sys1_pll_out", 0x30, 23),
|
||||
GATE(IMX8MQ_SYS1_PLL_800M_CG, "sys1_pll_800m_cg", "sys1_pll_out", 0x30, 25),
|
||||
|
||||
FFACT(IMX8MQ_SYS1_PLL_40M, "sys1_pll_40m", "sys1_pll_40m_cg", 1, 20),
|
||||
FFACT(IMX8MQ_SYS1_PLL_80M, "sys1_pll_80m", "sys1_pll_80m_cg", 1, 10),
|
||||
FFACT(IMX8MQ_SYS1_PLL_100M, "sys1_pll_100m", "sys1_pll_100m_cg", 1, 8),
|
||||
FFACT(IMX8MQ_SYS1_PLL_133M, "sys1_pll_133m", "sys1_pll_133m_cg", 1, 6),
|
||||
FFACT(IMX8MQ_SYS1_PLL_160M, "sys1_pll_160m", "sys1_pll_160m_cg", 1, 5),
|
||||
FFACT(IMX8MQ_SYS1_PLL_200M, "sys1_pll_200m", "sys1_pll_200m_cg", 1, 4),
|
||||
FFACT(IMX8MQ_SYS1_PLL_266M, "sys1_pll_266m", "sys1_pll_266m_cg", 1, 3),
|
||||
FFACT(IMX8MQ_SYS1_PLL_400M, "sys1_pll_400m", "sys1_pll_400m_cg", 1, 2),
|
||||
FFACT(IMX8MQ_SYS1_PLL_800M, "sys1_pll_800m", "sys1_pll_800m_cg", 1, 1),
|
||||
|
||||
GATE(IMX8MQ_SYS2_PLL_50M_CG, "sys2_pll_50m_cg", "sys2_pll_out", 0x3c, 9),
|
||||
GATE(IMX8MQ_SYS2_PLL_100M_CG, "sys2_pll_100m_cg", "sys2_pll_out", 0x3c, 11),
|
||||
GATE(IMX8MQ_SYS2_PLL_125M_CG, "sys2_pll_125m_cg", "sys2_pll_out", 0x3c, 13),
|
||||
GATE(IMX8MQ_SYS2_PLL_166M_CG, "sys2_pll_166m_cg", "sys2_pll_out", 0x3c, 15),
|
||||
GATE(IMX8MQ_SYS2_PLL_200M_CG, "sys2_pll_200m_cg", "sys2_pll_out", 0x3c, 17),
|
||||
GATE(IMX8MQ_SYS2_PLL_250M_CG, "sys2_pll_250m_cg", "sys2_pll_out", 0x3c, 19),
|
||||
GATE(IMX8MQ_SYS2_PLL_333M_CG, "sys2_pll_333m_cg", "sys2_pll_out", 0x3c, 21),
|
||||
GATE(IMX8MQ_SYS2_PLL_500M_CG, "sys2_pll_500m_cg", "sys2_pll_out", 0x3c, 23),
|
||||
GATE(IMX8MQ_SYS2_PLL_1000M_CG, "sys2_pll_1000m_cg", "sys2_pll_out", 0x3c, 25),
|
||||
|
||||
FFACT(IMX8MQ_SYS2_PLL_50M, "sys2_pll_50m", "sys2_pll_50m_cg", 1, 20),
|
||||
FFACT(IMX8MQ_SYS2_PLL_100M, "sys2_pll_100m", "sys2_pll_100m_cg", 1, 10),
|
||||
FFACT(IMX8MQ_SYS2_PLL_125M, "sys2_pll_125m", "sys2_pll_125m_cg", 1, 8),
|
||||
FFACT(IMX8MQ_SYS2_PLL_166M, "sys2_pll_166m", "sys2_pll_166m_cg", 1, 6),
|
||||
FFACT(IMX8MQ_SYS2_PLL_200M, "sys2_pll_200m", "sys2_pll_200m_cg", 1, 5),
|
||||
FFACT(IMX8MQ_SYS2_PLL_250M, "sys2_pll_250m", "sys2_pll_250m_cg", 1, 4),
|
||||
FFACT(IMX8MQ_SYS2_PLL_333M, "sys2_pll_333m", "sys2_pll_333m_cg", 1, 3),
|
||||
FFACT(IMX8MQ_SYS2_PLL_500M, "sys2_pll_500m", "sys2_pll_500m_cg", 1, 2),
|
||||
FFACT(IMX8MQ_SYS2_PLL_1000M, "sys2_pll_1000m", "sys2_pll_1000m_cg", 1, 1),
|
||||
|
||||
COMPOSITE(IMX8MQ_CLK_AHB, "ahb", ahb_p, 0x9000, 0),
|
||||
DIV(IMX8MQ_CLK_IPG_ROOT, "ipg_root", "ahb", 0x9080, 0, 1),
|
||||
|
||||
COMPOSITE(IMX8MQ_CLK_UART1, "uart1", uart_p, 0xaf00, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_UART2, "uart2", uart_p, 0xaf80, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_UART3, "uart3", uart_p, 0xb000, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_UART4, "uart4", uart_p, 0xb080, 0),
|
||||
|
||||
ROOT_GATE(IMX8MQ_CLK_UART1_ROOT, "uart1_root_clk", "uart1", 0x4490),
|
||||
ROOT_GATE(IMX8MQ_CLK_UART2_ROOT, "uart2_root_clk", "uart2", 0x44a0),
|
||||
ROOT_GATE(IMX8MQ_CLK_UART3_ROOT, "uart3_root_clk", "uart3", 0x44b0),
|
||||
ROOT_GATE(IMX8MQ_CLK_UART4_ROOT, "uart4_root_clk", "uart4", 0x44c0),
|
||||
|
||||
COMPOSITE(IMX8MQ_CLK_USDHC1, "usdhc1", usdhc_p, 0xac00, CLK_SET_ROUND_DOWN),
|
||||
COMPOSITE(IMX8MQ_CLK_USDHC2, "usdhc2", usdhc_p, 0xac80, CLK_SET_ROUND_DOWN),
|
||||
|
||||
ROOT_GATE(IMX8MQ_CLK_USDHC1_ROOT, "usdhc1_root_clk", "usdhc1", 0x4510),
|
||||
ROOT_GATE(IMX8MQ_CLK_USDHC2_ROOT, "usdhc2_root_clk", "usdhc2", 0x4520),
|
||||
|
||||
COMPOSITE(IMX8MQ_CLK_ENET_AXI, "enet_axi", enet_axi_p, 0x8800, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_ENET_REF, "enet_ref", enet_ref_p, 0xa980, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_ENET_TIMER, "enet_timer", enet_timer_p, 0xaa00, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_ENET_PHY_REF, "enet_phy_ref", enet_phy_ref_p, 0xaa80, 0),
|
||||
|
||||
ROOT_GATE(IMX8MQ_CLK_ENET1_ROOT, "enet1_root_clk", "enet_axi", 0x40a0),
|
||||
|
||||
COMPOSITE(IMX8MQ_CLK_USB_BUS, "usb_bus", usb_bus_p, 0x8b80, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_USB_CORE_REF, "usb_core_ref", usb_core_phy_p, 0xb100, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_USB_PHY_REF, "usb_phy_ref", usb_core_phy_p, 0xb180, 0),
|
||||
|
||||
ROOT_GATE(IMX8MQ_CLK_USB1_CTRL_ROOT, "usb1_ctrl_root_clk", "usb_bus", 0x44d0),
|
||||
ROOT_GATE(IMX8MQ_CLK_USB2_CTRL_ROOT, "usb2_ctrl_root_clk", "usb_bus", 0x44e0),
|
||||
ROOT_GATE(IMX8MQ_CLK_USB1_PHY_ROOT, "usb1_phy_root_clk", "usb_phy_ref", 0x44f0),
|
||||
ROOT_GATE(IMX8MQ_CLK_USB2_PHY_ROOT, "usb2_phy_root_clk", "usb_phy_ref", 0x4500),
|
||||
|
||||
COMPOSITE(IMX8MQ_CLK_I2C1, "i2c1", i2c_p, 0xad00, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_I2C2, "i2c2", i2c_p, 0xad80, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_I2C3, "i2c3", i2c_p, 0xae00, 0),
|
||||
COMPOSITE(IMX8MQ_CLK_I2C4, "i2c4", i2c_p, 0xae80, 0),
|
||||
|
||||
ROOT_GATE(IMX8MQ_CLK_I2C1_ROOT, "i2c1_root_clk", "i2c1", 0x4170),
|
||||
ROOT_GATE(IMX8MQ_CLK_I2C2_ROOT, "i2c2_root_clk", "i2c2", 0x4180),
|
||||
ROOT_GATE(IMX8MQ_CLK_I2C3_ROOT, "i2c3_root_clk", "i2c3", 0x4190),
|
||||
ROOT_GATE(IMX8MQ_CLK_I2C4_ROOT, "i2c4_root_clk", "i2c4", 0x41a0),
|
||||
|
||||
ROOT_GATE(IMX8MQ_CLK_GPIO1_ROOT, "gpio1_root_clk", "ipg_root", 0x40b0),
|
||||
ROOT_GATE(IMX8MQ_CLK_GPIO2_ROOT, "gpio2_root_clk", "ipg_root", 0x40c0),
|
||||
ROOT_GATE(IMX8MQ_CLK_GPIO3_ROOT, "gpio3_root_clk", "ipg_root", 0x40d0),
|
||||
ROOT_GATE(IMX8MQ_CLK_GPIO4_ROOT, "gpio4_root_clk", "ipg_root", 0x40e0),
|
||||
ROOT_GATE(IMX8MQ_CLK_GPIO5_ROOT, "gpio5_root_clk", "ipg_root", 0x40f0),
|
||||
};
|
||||
|
||||
struct ccm_softc {
|
||||
device_t dev;
|
||||
struct resource *mem_res;
|
||||
struct clkdom *clkdom;
|
||||
struct mtx mtx;
|
||||
struct imx_clk *clks;
|
||||
int nclks;
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
CCU_READ4(struct ccm_softc *sc, bus_size_t off)
|
||||
{
|
||||
|
||||
return (bus_read_4(sc->mem_res, off));
|
||||
}
|
||||
|
||||
static inline void
|
||||
CCU_WRITE4(struct ccm_softc *sc, bus_size_t off, uint32_t val)
|
||||
{
|
||||
|
||||
bus_write_4(sc->mem_res, off, val);
|
||||
}
|
||||
|
||||
static int
|
||||
ccm_detach(device_t dev)
|
||||
{
|
||||
struct ccm_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (sc->mem_res != NULL)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ccm_attach(device_t dev)
|
||||
{
|
||||
struct ccm_softc *sc;
|
||||
int err, rid;
|
||||
phandle_t node;
|
||||
int i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
err = 0;
|
||||
|
||||
/* Allocate bus_space resources. */
|
||||
rid = 0;
|
||||
sc->clks = imx_clks;
|
||||
sc->nclks = nitems(imx_clks);
|
||||
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
||||
RF_ACTIVE);
|
||||
if (sc->mem_res == NULL) {
|
||||
device_printf(dev, "Cannot allocate memory resources\n");
|
||||
err = ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
|
||||
|
||||
sc->clkdom = clkdom_create(dev);
|
||||
if (sc->clkdom == NULL)
|
||||
panic("Cannot create clkdom\n");
|
||||
|
||||
for (i = 0; i < sc->nclks; i++) {
|
||||
switch (sc->clks[i].type) {
|
||||
case IMX_CLK_UNDEFINED:
|
||||
break;
|
||||
case IMX_CLK_LINK:
|
||||
clknode_link_register(sc->clkdom,
|
||||
sc->clks[i].clk.link);
|
||||
break;
|
||||
case IMX_CLK_FIXED:
|
||||
clknode_fixed_register(sc->clkdom,
|
||||
sc->clks[i].clk.fixed);
|
||||
break;
|
||||
case IMX_CLK_MUX:
|
||||
imx_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
|
||||
break;
|
||||
case IMX_CLK_GATE:
|
||||
imx_clk_gate_register(sc->clkdom, sc->clks[i].clk.gate);
|
||||
break;
|
||||
case IMX_CLK_COMPOSITE:
|
||||
imx_clk_composite_register(sc->clkdom, sc->clks[i].clk.composite);
|
||||
break;
|
||||
case IMX_CLK_SSCG_PLL:
|
||||
imx_clk_sscg_pll_register(sc->clkdom, sc->clks[i].clk.sscg_pll);
|
||||
break;
|
||||
case IMX_CLK_FRAC_PLL:
|
||||
imx_clk_frac_pll_register(sc->clkdom, sc->clks[i].clk.frac_pll);
|
||||
break;
|
||||
case IMX_CLK_DIV:
|
||||
clknode_div_register(sc->clkdom, sc->clks[i].clk.div);
|
||||
break;
|
||||
default:
|
||||
device_printf(dev, "Unknown clock type %d\n", sc->clks[i].type);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
if (clkdom_finit(sc->clkdom) != 0)
|
||||
panic("cannot finalize clkdom initialization\n");
|
||||
|
||||
if (bootverbose)
|
||||
clkdom_dump(sc->clkdom);
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
clk_set_assigned(dev, node);
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
|
||||
if (err != 0)
|
||||
ccm_detach(dev);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
ccm_probe(device_t dev)
|
||||
{
|
||||
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (ofw_bus_is_compatible(dev, "fsl,imx8mq-ccm") == 0)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "Freescale i.MX8 Clock Control Module");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
imx_ccm_write_4(device_t dev, bus_addr_t addr, uint32_t val)
|
||||
{
|
||||
struct ccm_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
CCU_WRITE4(sc, addr, val);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
imx_ccm_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
|
||||
{
|
||||
struct ccm_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
*val = CCU_READ4(sc, addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
imx_ccm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
|
||||
{
|
||||
struct ccm_softc *sc;
|
||||
uint32_t reg;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
reg = CCU_READ4(sc, addr);
|
||||
reg &= ~clr;
|
||||
reg |= set;
|
||||
CCU_WRITE4(sc, addr, reg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
imx_ccm_device_lock(device_t dev)
|
||||
{
|
||||
struct ccm_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_lock(&sc->mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
imx_ccm_device_unlock(device_t dev)
|
||||
{
|
||||
struct ccm_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_unlock(&sc->mtx);
|
||||
}
|
||||
|
||||
static device_method_t ccm_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, ccm_probe),
|
||||
DEVMETHOD(device_attach, ccm_attach),
|
||||
DEVMETHOD(device_detach, ccm_detach),
|
||||
|
||||
/* clkdev interface */
|
||||
DEVMETHOD(clkdev_write_4, imx_ccm_write_4),
|
||||
DEVMETHOD(clkdev_read_4, imx_ccm_read_4),
|
||||
DEVMETHOD(clkdev_modify_4, imx_ccm_modify_4),
|
||||
DEVMETHOD(clkdev_device_lock, imx_ccm_device_lock),
|
||||
DEVMETHOD(clkdev_device_unlock, imx_ccm_device_unlock),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t ccm_driver = {
|
||||
"ccm",
|
||||
ccm_methods,
|
||||
sizeof(struct ccm_softc)
|
||||
};
|
||||
|
||||
static devclass_t ccm_devclass;
|
||||
|
||||
EARLY_DRIVER_MODULE(ccm, simplebus, ccm_driver, ccm_devclass, 0, 0,
|
||||
BUS_PASS_CPU + BUS_PASS_ORDER_EARLY);
|
173
sys/arm64/freescale/imx/imx8mq_ccm.h
Normal file
173
sys/arm64/freescale/imx/imx8mq_ccm.h
Normal file
@ -0,0 +1,173 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef __IMX8MQ_CCM_H__
|
||||
#define __IMX8MQ_CCM_H__
|
||||
|
||||
#define IMX8MQ_CLK_DUMMY 0
|
||||
#define IMX8MQ_CLK_32K 1
|
||||
#define IMX8MQ_CLK_25M 2
|
||||
#define IMX8MQ_CLK_27M 3
|
||||
#define IMX8MQ_CLK_EXT1 4
|
||||
#define IMX8MQ_CLK_EXT2 5
|
||||
#define IMX8MQ_CLK_EXT3 6
|
||||
#define IMX8MQ_CLK_EXT4 7
|
||||
|
||||
#define IMX8MQ_ARM_PLL_REF_SEL 8
|
||||
#define IMX8MQ_ARM_PLL_REF_DIV 9
|
||||
#define IMX8MQ_ARM_PLL 10
|
||||
#define IMX8MQ_ARM_PLL_BYPASS 11
|
||||
#define IMX8MQ_ARM_PLL_OUT 12
|
||||
|
||||
#define IMX8MQ_GPU_PLL_REF_SEL 13
|
||||
#define IMX8MQ_GPU_PLL_REF_DIV 14
|
||||
#define IMX8MQ_GPU_PLL 15
|
||||
#define IMX8MQ_GPU_PLL_BYPASS 16
|
||||
#define IMX8MQ_GPU_PLL_OUT 17
|
||||
|
||||
#define IMX8MQ_VPU_PLL_REF_SEL 18
|
||||
#define IMX8MQ_VPU_PLL_REF_DIV 19
|
||||
#define IMX8MQ_VPU_PLL 20
|
||||
#define IMX8MQ_VPU_PLL_BYPASS 21
|
||||
#define IMX8MQ_VPU_PLL_OUT 22
|
||||
|
||||
#define IMX8MQ_AUDIO_PLL1_REF_SEL 23
|
||||
#define IMX8MQ_AUDIO_PLL1_REF_DIV 24
|
||||
#define IMX8MQ_AUDIO_PLL1 25
|
||||
#define IMX8MQ_AUDIO_PLL1_BYPASS 26
|
||||
#define IMX8MQ_AUDIO_PLL1_OUT 27
|
||||
|
||||
#define IMX8MQ_AUDIO_PLL2_REF_SEL 28
|
||||
#define IMX8MQ_AUDIO_PLL2_REF_DIV 29
|
||||
#define IMX8MQ_AUDIO_PLL2 30
|
||||
#define IMX8MQ_AUDIO_PLL2_BYPASS 31
|
||||
#define IMX8MQ_AUDIO_PLL2_OUT 32
|
||||
|
||||
#define IMX8MQ_VIDEO_PLL1_REF_SEL 33
|
||||
#define IMX8MQ_VIDEO_PLL1_REF_DIV 34
|
||||
#define IMX8MQ_VIDEO_PLL1 35
|
||||
#define IMX8MQ_VIDEO_PLL1_BYPASS 36
|
||||
#define IMX8MQ_VIDEO_PLL1_OUT 37
|
||||
|
||||
#define IMX8MQ_SYS3_PLL1_REF_SEL 54
|
||||
#define IMX8MQ_SYS3_PLL1 56
|
||||
|
||||
#define IMX8MQ_DRAM_PLL1_REF_SEL 62
|
||||
|
||||
#define IMX8MQ_SYS1_PLL_40M 70
|
||||
#define IMX8MQ_SYS1_PLL_80M 71
|
||||
#define IMX8MQ_SYS1_PLL_100M 72
|
||||
#define IMX8MQ_SYS1_PLL_133M 73
|
||||
#define IMX8MQ_SYS1_PLL_160M 74
|
||||
#define IMX8MQ_SYS1_PLL_200M 75
|
||||
#define IMX8MQ_SYS1_PLL_266M 76
|
||||
#define IMX8MQ_SYS1_PLL_400M 77
|
||||
#define IMX8MQ_SYS1_PLL_800M 78
|
||||
|
||||
#define IMX8MQ_SYS2_PLL_50M 79
|
||||
#define IMX8MQ_SYS2_PLL_100M 80
|
||||
#define IMX8MQ_SYS2_PLL_125M 81
|
||||
#define IMX8MQ_SYS2_PLL_166M 82
|
||||
#define IMX8MQ_SYS2_PLL_200M 83
|
||||
#define IMX8MQ_SYS2_PLL_250M 84
|
||||
#define IMX8MQ_SYS2_PLL_333M 85
|
||||
#define IMX8MQ_SYS2_PLL_500M 86
|
||||
#define IMX8MQ_SYS2_PLL_1000M 87
|
||||
|
||||
#define IMX8MQ_CLK_ENET_AXI 104
|
||||
#define IMX8MQ_CLK_USB_BUS 110
|
||||
|
||||
#define IMX8MQ_CLK_AHB 116
|
||||
|
||||
#define IMX8MQ_CLK_ENET_REF 137
|
||||
#define IMX8MQ_CLK_ENET_TIMER 138
|
||||
#define IMX8MQ_CLK_ENET_PHY_REF 139
|
||||
#define IMX8MQ_CLK_USDHC1 142
|
||||
#define IMX8MQ_CLK_USDHC2 143
|
||||
#define IMX8MQ_CLK_I2C1 144
|
||||
#define IMX8MQ_CLK_I2C2 145
|
||||
#define IMX8MQ_CLK_I2C3 146
|
||||
#define IMX8MQ_CLK_I2C4 147
|
||||
#define IMX8MQ_CLK_UART1 148
|
||||
#define IMX8MQ_CLK_UART2 149
|
||||
#define IMX8MQ_CLK_UART3 150
|
||||
#define IMX8MQ_CLK_UART4 151
|
||||
#define IMX8MQ_CLK_USB_CORE_REF 152
|
||||
#define IMX8MQ_CLK_USB_PHY_REF 153
|
||||
|
||||
#define IMX8MQ_CLK_ENET1_ROOT 182
|
||||
#define IMX8MQ_CLK_I2C1_ROOT 184
|
||||
#define IMX8MQ_CLK_I2C2_ROOT 185
|
||||
#define IMX8MQ_CLK_I2C3_ROOT 186
|
||||
#define IMX8MQ_CLK_I2C4_ROOT 187
|
||||
#define IMX8MQ_CLK_UART1_ROOT 202
|
||||
#define IMX8MQ_CLK_UART2_ROOT 203
|
||||
#define IMX8MQ_CLK_UART3_ROOT 204
|
||||
#define IMX8MQ_CLK_UART4_ROOT 205
|
||||
#define IMX8MQ_CLK_USB1_CTRL_ROOT 206
|
||||
#define IMX8MQ_CLK_USB2_CTRL_ROOT 207
|
||||
#define IMX8MQ_CLK_USB1_PHY_ROOT 208
|
||||
#define IMX8MQ_CLK_USB2_PHY_ROOT 209
|
||||
#define IMX8MQ_CLK_USDHC1_ROOT 210
|
||||
#define IMX8MQ_CLK_USDHC2_ROOT 211
|
||||
|
||||
#define IMX8MQ_SYS1_PLL_OUT 231
|
||||
#define IMX8MQ_SYS2_PLL_OUT 232
|
||||
#define IMX8MQ_SYS3_PLL_OUT 233
|
||||
|
||||
#define IMX8MQ_CLK_IPG_ROOT 236
|
||||
|
||||
#define IMX8MQ_CLK_GPIO1_ROOT 259
|
||||
#define IMX8MQ_CLK_GPIO2_ROOT 260
|
||||
#define IMX8MQ_CLK_GPIO3_ROOT 261
|
||||
#define IMX8MQ_CLK_GPIO4_ROOT 262
|
||||
#define IMX8MQ_CLK_GPIO5_ROOT 263
|
||||
|
||||
#define IMX8MQ_VIDEO2_PLL1_REF_SEL 266
|
||||
|
||||
#define IMX8MQ_SYS1_PLL_40M_CG 267
|
||||
#define IMX8MQ_SYS1_PLL_80M_CG 268
|
||||
#define IMX8MQ_SYS1_PLL_100M_CG 269
|
||||
#define IMX8MQ_SYS1_PLL_133M_CG 270
|
||||
#define IMX8MQ_SYS1_PLL_160M_CG 271
|
||||
#define IMX8MQ_SYS1_PLL_200M_CG 272
|
||||
#define IMX8MQ_SYS1_PLL_266M_CG 273
|
||||
#define IMX8MQ_SYS1_PLL_400M_CG 274
|
||||
#define IMX8MQ_SYS1_PLL_800M_CG 275
|
||||
#define IMX8MQ_SYS2_PLL_50M_CG 276
|
||||
#define IMX8MQ_SYS2_PLL_100M_CG 277
|
||||
#define IMX8MQ_SYS2_PLL_125M_CG 278
|
||||
#define IMX8MQ_SYS2_PLL_166M_CG 279
|
||||
#define IMX8MQ_SYS2_PLL_200M_CG 280
|
||||
#define IMX8MQ_SYS2_PLL_250M_CG 281
|
||||
#define IMX8MQ_SYS2_PLL_333M_CG 282
|
||||
#define IMX8MQ_SYS2_PLL_500M_CG 283
|
||||
#define IMX8MQ_SYS2_PLL_1000M_CG 284
|
||||
|
||||
#endif
|
212
sys/arm64/freescale/imx/imx_ccm_clk.h
Normal file
212
sys/arm64/freescale/imx/imx_ccm_clk.h
Normal file
@ -0,0 +1,212 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef IMX6_CCM_CLK_H
|
||||
#define IMX6_CCM_CLK_H
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
#include <dev/extres/clk/clk_div.h>
|
||||
#include <dev/extres/clk/clk_fixed.h>
|
||||
#include <dev/extres/clk/clk_gate.h>
|
||||
#include <dev/extres/clk/clk_link.h>
|
||||
|
||||
enum imx_clk_type {
|
||||
IMX_CLK_UNDEFINED = 0,
|
||||
IMX_CLK_FIXED,
|
||||
IMX_CLK_LINK,
|
||||
IMX_CLK_MUX,
|
||||
IMX_CLK_GATE,
|
||||
IMX_CLK_COMPOSITE,
|
||||
IMX_CLK_SSCG_PLL,
|
||||
IMX_CLK_FRAC_PLL,
|
||||
IMX_CLK_DIV,
|
||||
};
|
||||
|
||||
struct imx_clk {
|
||||
enum imx_clk_type type;
|
||||
union {
|
||||
struct clk_fixed_def *fixed;
|
||||
struct clk_link_def *link;
|
||||
struct imx_clk_mux_def *mux;
|
||||
struct imx_clk_gate_def *gate;
|
||||
struct imx_clk_composite_def *composite;
|
||||
struct imx_clk_sscg_pll_def *sscg_pll;
|
||||
struct imx_clk_frac_pll_def *frac_pll;
|
||||
struct clk_div_def *div;
|
||||
} clk;
|
||||
};
|
||||
|
||||
/* Linked clock. */
|
||||
#define LINK(_id, _name) \
|
||||
{ \
|
||||
.type = IMX_CLK_LINK, \
|
||||
.clk.link = &(struct clk_link_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = NULL, \
|
||||
.clkdef.parent_cnt = 0, \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* Complex clock without divider (multiplexer only). */
|
||||
#define MUX(_id, _name, _pn, _f, _mo, _ms, _mw) \
|
||||
{ \
|
||||
.type = IMX_CLK_MUX, \
|
||||
.clk.mux = &(struct imx_clk_mux_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = _pn, \
|
||||
.clkdef.parent_cnt = nitems(_pn), \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.offset = _mo, \
|
||||
.shift = _ms, \
|
||||
.width = _mw, \
|
||||
.mux_flags = _f, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* Fixed frequency clock */
|
||||
#define FIXED(_id, _name, _freq) \
|
||||
{ \
|
||||
.type = IMX_CLK_FIXED, \
|
||||
.clk.fixed = &(struct clk_fixed_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.freq = _freq, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* Fixed factor multipier/divider. */
|
||||
#define FFACT(_id, _name, _pname, _mult, _div) \
|
||||
{ \
|
||||
.type = IMX_CLK_FIXED, \
|
||||
.clk.fixed = &(struct clk_fixed_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = (const char *[]){_pname}, \
|
||||
.clkdef.parent_cnt = 1, \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.mult = _mult, \
|
||||
.div = _div, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* Clock gate */
|
||||
#define GATE(_id, _name, _pname, _o, _shift) \
|
||||
{ \
|
||||
.type = IMX_CLK_GATE, \
|
||||
.clk.gate = &(struct imx_clk_gate_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = (const char *[]){_pname}, \
|
||||
.clkdef.parent_cnt = 1, \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.offset = _o, \
|
||||
.shift = _shift, \
|
||||
.mask = 1, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* Root clock gate */
|
||||
#define ROOT_GATE(_id, _name, _pname, _reg) \
|
||||
{ \
|
||||
.type = IMX_CLK_GATE, \
|
||||
.clk.gate = &(struct imx_clk_gate_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = (const char *[]){_pname}, \
|
||||
.clkdef.parent_cnt = 1, \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.offset = _reg, \
|
||||
.shift = 0, \
|
||||
.mask = 3, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* Composite clock with GATE, MUX, PRE_DIV, and POST_DIV */
|
||||
#define COMPOSITE(_id, _name, _pn, _o, _flags) \
|
||||
{ \
|
||||
.type = IMX_CLK_COMPOSITE, \
|
||||
.clk.composite = &(struct imx_clk_composite_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = _pn, \
|
||||
.clkdef.parent_cnt = nitems(_pn), \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.offset = _o, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* SSCG PLL */
|
||||
#define SSCG_PLL(_id, _name, _pn, _o) \
|
||||
{ \
|
||||
.type = IMX_CLK_SSCG_PLL, \
|
||||
.clk.composite = &(struct imx_clk_composite_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = _pn, \
|
||||
.clkdef.parent_cnt = nitems(_pn), \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.offset = _o, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* Fractional PLL */
|
||||
#define FRAC_PLL(_id, _name, _pname, _o) \
|
||||
{ \
|
||||
.type = IMX_CLK_FRAC_PLL, \
|
||||
.clk.frac_pll = &(struct imx_clk_frac_pll_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = (const char *[]){_pname}, \
|
||||
.clkdef.parent_cnt = 1, \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.offset = _o, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define DIV(_id, _name, _pname, _o, _shift, _width) \
|
||||
{ \
|
||||
.type = IMX_CLK_DIV, \
|
||||
.clk.div = &(struct clk_div_def) { \
|
||||
.clkdef.id = _id, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = (const char *[]){_pname}, \
|
||||
.clkdef.parent_cnt = 1, \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.offset = _o, \
|
||||
.i_shift = _shift, \
|
||||
.i_width = _width, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#endif
|
@ -3172,6 +3172,7 @@ dev/uart/uart_bus_scc.c optional uart scc
|
||||
dev/uart/uart_core.c optional uart
|
||||
dev/uart/uart_cpu_acpi.c optional uart acpi
|
||||
dev/uart/uart_dbg.c optional uart gdb
|
||||
dev/uart/uart_dev_imx.c optional uart uart_imx fdt
|
||||
dev/uart/uart_dev_msm.c optional uart uart_msm fdt
|
||||
dev/uart/uart_dev_mvebu.c optional uart uart_mvebu
|
||||
dev/uart/uart_dev_ns8250.c optional uart uart_ns8250 | uart uart_snps
|
||||
|
@ -395,3 +395,18 @@ arm64/rockchip/clk/rk_clk_pll.c optional fdt soc_rockchip_rk3328 | fdt soc_rock
|
||||
arm64/rockchip/clk/rk3328_cru.c optional fdt soc_rockchip_rk3328
|
||||
arm64/rockchip/clk/rk3399_cru.c optional fdt soc_rockchip_rk3399
|
||||
arm64/rockchip/clk/rk3399_pmucru.c optional fdt soc_rockchip_rk3399
|
||||
|
||||
# i.MX8 Clock support
|
||||
arm64/freescale/imx/imx8mq_ccm.c optional fdt soc_freescale_imx8
|
||||
arm64/freescale/imx/clk/imx_clk_gate.c optional fdt soc_freescale_imx8
|
||||
arm64/freescale/imx/clk/imx_clk_mux.c optional fdt soc_freescale_imx8
|
||||
arm64/freescale/imx/clk/imx_clk_composite.c optional fdt soc_freescale_imx8
|
||||
arm64/freescale/imx/clk/imx_clk_sscg_pll.c optional fdt soc_freescale_imx8
|
||||
arm64/freescale/imx/clk/imx_clk_frac_pll.c optional fdt soc_freescale_imx8
|
||||
|
||||
# iMX drivers
|
||||
arm/freescale/imx/imx_gpio.c optional gpio
|
||||
arm/freescale/imx/imx_i2c.c optional fsliic
|
||||
arm/freescale/imx/imx_machdep.c standard
|
||||
arm64/freescale/imx/imx7gpc.c optional fdt soc_freescale_imx8
|
||||
dev/ffec/if_ffec.c optional ffec
|
||||
|
@ -22,6 +22,7 @@ SOC_ALLWINNER_H6 opt_soc.h
|
||||
SOC_BRCM_BCM2837 opt_soc.h
|
||||
SOC_BRCM_BCM2838 opt_soc.h
|
||||
SOC_CAVM_THUNDERX opt_soc.h
|
||||
SOC_FREESCALE_IMX8 opt_soc.h
|
||||
SOC_HISI_HI6220 opt_soc.h
|
||||
SOC_INTEL_STRATIX10 opt_soc.h
|
||||
SOC_MARVELL_8K opt_soc.h
|
||||
|
@ -123,6 +123,7 @@ static struct ofw_compat_data compat_data[] = {
|
||||
{"fsl,imx53-fec", FECTYPE_IMX53},
|
||||
{"fsl,imx6q-fec", FECTYPE_IMX6 | FECFLAG_RACC | FECFLAG_GBE },
|
||||
{"fsl,imx6ul-fec", FECTYPE_IMX6 | FECFLAG_RACC },
|
||||
{"fsl,imx6sx-fec", FECTYPE_IMX6 | FECFLAG_RACC },
|
||||
{"fsl,imx7d-fec", FECTYPE_IMX6 | FECFLAG_RACC | FECFLAG_GBE |
|
||||
FECFLAG_AVB },
|
||||
{"fsl,mvf600-fec", FECTYPE_MVF | FECFLAG_RACC },
|
||||
|
@ -40,13 +40,21 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/fdt.h>
|
||||
|
||||
#include <dev/uart/uart.h>
|
||||
#include <dev/uart/uart_cpu.h>
|
||||
#include <dev/uart/uart_cpu_fdt.h>
|
||||
#include <dev/uart/uart_bus.h>
|
||||
#include <dev/uart/uart_dev_imx.h>
|
||||
|
||||
#if defined(EXT_RESOURCES) && defined(__aarch64__)
|
||||
#define IMX_ENABLE_CLOCKS
|
||||
#endif
|
||||
|
||||
#ifdef IMX_ENABLE_CLOCKS
|
||||
#include <dev/extres/clk/clk.h>
|
||||
#endif
|
||||
|
||||
#include "uart_if.h"
|
||||
|
||||
#include <arm/freescale/imx/imx_ccmvar.h>
|
||||
@ -125,7 +133,7 @@ imx_uart_getbaud(struct uart_bas *bas)
|
||||
*/
|
||||
i = (GETREG(bas, REG(UFCR)) & IMXUART_UFCR_RFDIV_MASK) >>
|
||||
IMXUART_UFCR_RFDIV_SHIFT;
|
||||
rate = imx_ccm_uart_hz() / predivs[i];
|
||||
rate = bas->rclk / predivs[i];
|
||||
ubir = GETREG(bas, REG(UBIR)) + 1;
|
||||
ubmr = GETREG(bas, REG(UBMR)) + 1;
|
||||
baud = ((rate / 16 ) * ubir) / ubmr;
|
||||
@ -193,8 +201,8 @@ imx_uart_init(struct uart_bas *bas, int baudrate, int databits,
|
||||
* Note that a quirk of the hardware requires that both UBIR and UBMR be
|
||||
* set back to back in order for the change to take effect.
|
||||
*/
|
||||
if (baudrate > 0) {
|
||||
baseclk = imx_ccm_uart_hz();
|
||||
if ((baudrate > 0) && (bas->rclk != 0)) {
|
||||
baseclk = bas->rclk;
|
||||
reg = GETREG(bas, REG(UFCR));
|
||||
reg = (reg & ~IMXUART_UFCR_RFDIV_MASK) | IMXUART_UFCR_RFDIV_DIV1;
|
||||
SETREG(bas, REG(UFCR), reg);
|
||||
@ -323,6 +331,42 @@ UART_FDT_CLASS_AND_DEVICE(compat_data);
|
||||
i = (i & s) ? (i & ~s) | d : i; \
|
||||
}
|
||||
|
||||
#ifdef IMX_ENABLE_CLOCKS
|
||||
static int
|
||||
imx_uart_setup_clocks(struct uart_softc *sc)
|
||||
{
|
||||
struct uart_bas *bas;
|
||||
clk_t ipgclk, perclk;
|
||||
uint64_t freq;
|
||||
int error;
|
||||
|
||||
bas = &sc->sc_bas;
|
||||
|
||||
if (clk_get_by_ofw_name(sc->sc_dev, 0, "ipg", &ipgclk) != 0)
|
||||
return (ENOENT);
|
||||
|
||||
if (clk_get_by_ofw_name(sc->sc_dev, 0, "per", &perclk) != 0) {
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
error = clk_enable(ipgclk);
|
||||
if (error != 0) {
|
||||
device_printf(sc->sc_dev, "cannot enable ipg clock\n");
|
||||
return (error);
|
||||
}
|
||||
|
||||
error = clk_get_freq(perclk, &freq);
|
||||
if (error != 0) {
|
||||
device_printf(sc->sc_dev, "cannot get frequency\n");
|
||||
return (error);
|
||||
}
|
||||
|
||||
bas->rclk = (uint32_t)freq;
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
imx_uart_bus_attach(struct uart_softc *sc)
|
||||
{
|
||||
@ -330,6 +374,15 @@ imx_uart_bus_attach(struct uart_softc *sc)
|
||||
struct uart_devinfo *di;
|
||||
|
||||
bas = &sc->sc_bas;
|
||||
|
||||
#ifdef IMX_ENABLE_CLOCKS
|
||||
int error = imx_uart_setup_clocks(sc);
|
||||
if (error)
|
||||
return (error);
|
||||
#else
|
||||
bas->rclk = imx_ccm_uart_hz();
|
||||
#endif
|
||||
|
||||
if (sc->sc_sysdev != NULL) {
|
||||
di = sc->sc_sysdev;
|
||||
imx_uart_init(bas, di->baudrate, di->databits, di->stopbits,
|
||||
|
7
sys/modules/dtb/imx8/Makefile
Normal file
7
sys/modules/dtb/imx8/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
# All the dts files for imx8 systems we support.
|
||||
DTS= \
|
||||
freescale/imx8mq-evk.dts \
|
||||
freescale/imx8mq-nitrogen.dts
|
||||
|
||||
.include <bsd.dtb.mk>
|
Loading…
Reference in New Issue
Block a user