#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/socket.h>
#include <sys/timeout.h>
#include <machine/intr.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_clock.h>
#include <dev/ofw/ofw_misc.h>
#include <dev/ofw/ofw_regulator.h>
#include <dev/ofw/fdt.h>
#include <dev/fdt/imxanatopvar.h>
#define CCM_CCR 0x00
#define CCM_CCDR 0x04
#define CCM_CSR 0x08
#define CCM_CCSR 0x0c
#define CCM_CACRR 0x10
#define CCM_CBCDR 0x14
#define CCM_CBCMR 0x18
#define CCM_CSCMR1 0x1c
#define CCM_CSCMR2 0x20
#define CCM_CSCDR1 0x24
#define CCM_CS1CDR 0x28
#define CCM_CS2CDR 0x2c
#define CCM_CDCDR 0x30
#define CCM_CHSCCDR 0x34
#define CCM_CSCDR2 0x38
#define CCM_CSCDR3 0x3c
#define CCM_CSCDR4 0x40
#define CCM_CDHIPR 0x48
#define CCM_CDCR 0x4c
#define CCM_CTOR 0x50
#define CCM_CLPCR 0x54
#define CCM_CISR 0x58
#define CCM_CIMR 0x5c
#define CCM_CCOSR 0x60
#define CCM_CGPR 0x64
#define CCM_CCGR0 0x68
#define CCM_CCGR1 0x6c
#define CCM_CCGR2 0x70
#define CCM_CCGR3 0x74
#define CCM_CCGR4 0x78
#define CCM_CCGR5 0x7c
#define CCM_CCGR6 0x80
#define CCM_CCGR7 0x84
#define CCM_CMEOR 0x88
#define CCM_CCSR_PLL3_SW_CLK_SEL (1 << 0)
#define CCM_CCSR_PLL2_SW_CLK_SEL (1 << 1)
#define CCM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
#define CCM_CCSR_STEP_SEL (1 << 8)
#define CCM_CBCDR_IPG_PODF_SHIFT 8
#define CCM_CBCDR_IPG_PODF_MASK 0x3
#define CCM_CBCDR_AHB_PODF_SHIFT 10
#define CCM_CBCDR_AHB_PODF_MASK 0x7
#define CCM_CBCDR_PERIPH_CLK_SEL_SHIFT 25
#define CCM_CBCDR_PERIPH_CLK_SEL_MASK 0x1
#define CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT 12
#define CCM_CBCMR_PERIPH_CLK2_SEL_MASK 0x3
#define CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT 18
#define CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK 0x3
#define CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x) ((x) + 15)
#define CCM_CSCDR1_USDHCx_CLK_SEL_MASK 0x1
#define CCM_CSCDR1_USDHCx_PODF_MASK 0x7
#define CCM_CSCDR1_UART_PODF_MASK 0x7
#define CCM_CSCDR2_ECSPI_PODF_SHIFT 19
#define CCM_CSCDR2_ECSPI_PODF_MASK 0x7
#define CCM_CCGR1_ENET (3 << 10)
#define CCM_CCGR4_125M_PCIE (3 << 0)
#define CCM_CCGR5_100M_SATA (3 << 4)
#define CCM_CSCMR1_PERCLK_CLK_PODF_MASK 0x1f
#define CCM_CSCMR1_PERCLK_CLK_SEL_MASK (1 << 6)
#define CCM_ANALOG_PLL_USB1 0x0010
#define CCM_ANALOG_PLL_USB1_SET 0x0014
#define CCM_ANALOG_PLL_USB1_CLR 0x0018
#define CCM_ANALOG_PLL_USB1_LOCK (1U << 31)
#define CCM_ANALOG_PLL_USB1_BYPASS (1 << 16)
#define CCM_ANALOG_PLL_USB1_ENABLE (1 << 13)
#define CCM_ANALOG_PLL_USB1_POWER (1 << 12)
#define CCM_ANALOG_PLL_USB1_EN_USB_CLKS (1 << 6)
#define CCM_ANALOG_PLL_USB2 0x0020
#define CCM_ANALOG_PLL_USB2_SET 0x0024
#define CCM_ANALOG_PLL_USB2_CLR 0x0028
#define CCM_ANALOG_PLL_USB2_LOCK (1U << 31)
#define CCM_ANALOG_PLL_USB2_BYPASS (1 << 16)
#define CCM_ANALOG_PLL_USB2_ENABLE (1 << 13)
#define CCM_ANALOG_PLL_USB2_POWER (1 << 12)
#define CCM_ANALOG_PLL_USB2_EN_USB_CLKS (1 << 6)
#define CCM_ANALOG_PLL_ENET 0x00e0
#define CCM_ANALOG_PLL_ENET_SET 0x00e4
#define CCM_ANALOG_PLL_ENET_CLR 0x00e8
#define CCM_ANALOG_PLL_ENET_LOCK (1U << 31)
#define CCM_ANALOG_PLL_ENET_ENABLE_100M (1 << 20)
#define CCM_ANALOG_PLL_ENET_BYPASS (1 << 16)
#define CCM_ANALOG_PLL_ENET_ENABLE (1 << 13)
#define CCM_ANALOG_PLL_ENET_POWERDOWN (1 << 12)
#define CCM_ANALOG_PLL_ENET_ENABLE_CLK_125MHZ (1 << 10)
#define CCM_14XX_IMX8M_ARM_PLL_GNRL_CTL 0x84
#define CCM_14XX_IMX8M_ARM_PLL_DIV_CTL 0x88
#define CCM_14XX_IMX8M_SYS_PLL1_GNRL_CTL 0x94
#define CCM_14XX_IMX8M_SYS_PLL1_DIV_CTL 0x98
#define CCM_INT_PLL_LOCK (1U << 31)
#define CCM_INT_PLL_LOCK_SEL (1 << 29)
#define CCM_INT_PLL_RST (1 << 9)
#define CCM_INT_PLL_BYPASS (1 << 4)
#define CCM_INT_PLL_MAIN_DIV_SHIFT 12
#define CCM_INT_PLL_MAIN_DIV_MASK 0x3ff
#define CCM_INT_PLL_PRE_DIV_SHIFT 4
#define CCM_INT_PLL_PRE_DIV_MASK 0x3f
#define CCM_INT_PLL_POST_DIV_SHIFT 0
#define CCM_INT_PLL_POST_DIV_MASK 0x7
#define CCM_FRAC_IMX8M_ARM_PLL0 0x28
#define CCM_FRAC_IMX8M_ARM_PLL1 0x2c
#define CCM_FRAC_PLL_LOCK (1U << 31)
#define CCM_FRAC_PLL_ENABLE (1 << 21)
#define CCM_FRAC_PLL_POWERDOWN (1 << 19)
#define CCM_FRAC_PLL_REFCLK_SEL_SHIFT 16
#define CCM_FRAC_PLL_REFCLK_SEL_MASK 0x3
#define CCM_FRAC_PLL_LOCK_SEL (1 << 15)
#define CCM_FRAC_PLL_BYPASS (1 << 14)
#define CCM_FRAC_PLL_COUNTCLK_SEL (1 << 13)
#define CCM_FRAC_PLL_NEWDIV_VAL (1 << 12)
#define CCM_FRAC_PLL_NEWDIV_ACK (1 << 11)
#define CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT 5
#define CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK 0x3f
#define CCM_FRAC_PLL_OUTPUT_DIV_VAL_SHIFT 0
#define CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK 0x1f
#define CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT 7
#define CCM_FRAC_PLL_FRAC_DIV_CTL_MASK 0x1ffffff
#define CCM_FRAC_PLL_INT_DIV_CTL_SHIFT 0
#define CCM_FRAC_PLL_INT_DIV_CTL_MASK 0x7f
#define CCM_FRAC_PLL_DENOM (1 << 24)
#define CCM_FRAC_IMX8M_PLLOUT_DIV_CFG 0x78
#define CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT 20
#define CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK 0x7
#define HCLK_FREQ 24000000
#define PLL3_60M 60000000
#define PLL3_80M 80000000
#define HREAD4(sc, reg) \
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val) \
bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define HSET4(sc, reg, bits) \
HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
#define HCLR4(sc, reg, bits) \
HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
struct imxccm_gate {
uint16_t reg;
uint8_t pos;
uint16_t parent;
};
struct imxccm_divider {
uint16_t reg;
uint16_t shift;
uint16_t mask;
uint16_t parent;
uint16_t fixed;
};
struct imxccm_mux {
uint16_t reg;
uint16_t shift;
uint16_t mask;
};
#include "imxccm_clocks.h"
struct imxccm_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
int sc_node;
uint32_t sc_phandle;
struct regmap *sc_anatop;
const struct imxccm_gate *sc_gates;
int sc_ngates;
const struct imxccm_divider *sc_divs;
int sc_ndivs;
const struct imxccm_mux *sc_muxs;
int sc_nmuxs;
const struct imxccm_divider *sc_predivs;
int sc_npredivs;
struct clock_device sc_cd;
};
int imxccm_match(struct device *, void *, void *);
void imxccm_attach(struct device *parent, struct device *self, void *args);
const struct cfattach imxccm_ca = {
sizeof (struct imxccm_softc), imxccm_match, imxccm_attach
};
struct cfdriver imxccm_cd = {
NULL, "imxccm", DV_DULL
};
uint32_t imxccm_get_armclk(struct imxccm_softc *);
void imxccm_armclk_set_parent(struct imxccm_softc *, enum imxanatop_clocks);
uint32_t imxccm_get_usdhx(struct imxccm_softc *, int x);
uint32_t imxccm_get_periphclk(struct imxccm_softc *);
uint32_t imxccm_get_ahbclk(struct imxccm_softc *);
uint32_t imxccm_get_ipgclk(struct imxccm_softc *);
uint32_t imxccm_get_ipg_perclk(struct imxccm_softc *);
uint32_t imxccm_get_uartclk(struct imxccm_softc *);
uint32_t imxccm_imx8mm_enet(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mm_ahb(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mm_i2c(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mm_uart(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mm_usdhc(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mp_enet_qos_timer(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mp_enet_qos(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mp_hsio_axi(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mq_ecspi(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mq_enet(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mq_ahb(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mq_i2c(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mq_pwm(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t);
uint32_t imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t);
int imxccm_imx8m_set_div(struct imxccm_softc *, uint32_t, uint64_t, uint64_t);
void imxccm_enable(void *, uint32_t *, int);
uint32_t imxccm_get_frequency(void *, uint32_t *);
int imxccm_set_frequency(void *, uint32_t *, uint32_t);
int imxccm_set_parent(void *, uint32_t *, uint32_t *);
int
imxccm_match(struct device *parent, void *match, void *aux)
{
struct fdt_attach_args *faa = aux;
return (OF_is_compatible(faa->fa_node, "fsl,imx6q-ccm") ||
OF_is_compatible(faa->fa_node, "fsl,imx6sl-ccm") ||
OF_is_compatible(faa->fa_node, "fsl,imx6sx-ccm") ||
OF_is_compatible(faa->fa_node, "fsl,imx6ul-ccm") ||
OF_is_compatible(faa->fa_node, "fsl,imx7d-ccm") ||
OF_is_compatible(faa->fa_node, "fsl,imx8mm-ccm") ||
OF_is_compatible(faa->fa_node, "fsl,imx8mp-ccm") ||
OF_is_compatible(faa->fa_node, "fsl,imx8mq-ccm"));
}
void
imxccm_attach(struct device *parent, struct device *self, void *aux)
{
struct imxccm_softc *sc = (struct imxccm_softc *)self;
struct fdt_attach_args *faa = aux;
KASSERT(faa->fa_nreg >= 1);
sc->sc_node = faa->fa_node;
sc->sc_iot = faa->fa_iot;
if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
faa->fa_reg[0].size, 0, &sc->sc_ioh))
panic("%s: bus_space_map failed!", __func__);
sc->sc_phandle = OF_getpropint(sc->sc_node, "phandle", 0);
if (OF_is_compatible(sc->sc_node, "fsl,imx8mm-ccm")) {
sc->sc_anatop = regmap_bycompatible("fsl,imx8mm-anatop");
KASSERT(sc->sc_anatop != NULL);
sc->sc_gates = imx8mm_gates;
sc->sc_ngates = nitems(imx8mm_gates);
sc->sc_divs = imx8mm_divs;
sc->sc_ndivs = nitems(imx8mm_divs);
sc->sc_muxs = imx8mm_muxs;
sc->sc_nmuxs = nitems(imx8mm_muxs);
sc->sc_predivs = imx8mm_predivs;
sc->sc_npredivs = nitems(imx8mm_predivs);
} else if (OF_is_compatible(sc->sc_node, "fsl,imx8mp-ccm")) {
sc->sc_anatop = regmap_bycompatible("fsl,imx8mp-anatop");
KASSERT(sc->sc_anatop != NULL);
sc->sc_gates = imx8mp_gates;
sc->sc_ngates = nitems(imx8mp_gates);
sc->sc_divs = imx8mp_divs;
sc->sc_ndivs = nitems(imx8mp_divs);
sc->sc_muxs = imx8mp_muxs;
sc->sc_nmuxs = nitems(imx8mp_muxs);
sc->sc_predivs = imx8mp_predivs;
sc->sc_npredivs = nitems(imx8mp_predivs);
} else if (OF_is_compatible(sc->sc_node, "fsl,imx8mq-ccm")) {
sc->sc_anatop = regmap_bycompatible("fsl,imx8mq-anatop");
KASSERT(sc->sc_anatop != NULL);
sc->sc_gates = imx8mq_gates;
sc->sc_ngates = nitems(imx8mq_gates);
sc->sc_divs = imx8mq_divs;
sc->sc_ndivs = nitems(imx8mq_divs);
sc->sc_muxs = imx8mq_muxs;
sc->sc_nmuxs = nitems(imx8mq_muxs);
sc->sc_predivs = imx8mq_predivs;
sc->sc_npredivs = nitems(imx8mq_predivs);
} else if (OF_is_compatible(sc->sc_node, "fsl,imx7d-ccm")) {
sc->sc_gates = imx7d_gates;
sc->sc_ngates = nitems(imx7d_gates);
sc->sc_divs = imx7d_divs;
sc->sc_ndivs = nitems(imx7d_divs);
sc->sc_muxs = imx7d_muxs;
sc->sc_nmuxs = nitems(imx7d_muxs);
} else if (OF_is_compatible(sc->sc_node, "fsl,imx6ul-ccm")) {
sc->sc_gates = imx6ul_gates;
sc->sc_ngates = nitems(imx6ul_gates);
} else {
sc->sc_gates = imx6_gates;
sc->sc_ngates = nitems(imx6_gates);
}
printf("\n");
sc->sc_cd.cd_node = faa->fa_node;
sc->sc_cd.cd_cookie = sc;
sc->sc_cd.cd_enable = imxccm_enable;
sc->sc_cd.cd_get_frequency = imxccm_get_frequency;
sc->sc_cd.cd_set_frequency = imxccm_set_frequency;
sc->sc_cd.cd_set_parent = imxccm_set_parent;
clock_register(&sc->sc_cd);
}
uint32_t
imxccm_get_armclk(struct imxccm_softc *sc)
{
uint32_t ccsr = HREAD4(sc, CCM_CCSR);
if (!(ccsr & CCM_CCSR_PLL1_SW_CLK_SEL))
return imxanatop_decode_pll(ARM_PLL1, HCLK_FREQ);
else if (ccsr & CCM_CCSR_STEP_SEL)
return imxanatop_get_pll2_pfd(2);
else
return HCLK_FREQ;
}
void
imxccm_armclk_set_parent(struct imxccm_softc *sc, enum imxanatop_clocks clock)
{
switch (clock)
{
case ARM_PLL1:
HCLR4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
break;
case OSC:
HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
break;
case SYS_PLL2_PFD2:
HSET4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
break;
default:
panic("%s: parent not possible for arm clk", __func__);
}
}
uint32_t
imxccm_get_ecspiclk(struct imxccm_softc *sc)
{
uint32_t clkroot = PLL3_60M;
uint32_t podf = HREAD4(sc, CCM_CSCDR2);
podf >>= CCM_CSCDR2_ECSPI_PODF_SHIFT;
podf &= CCM_CSCDR2_ECSPI_PODF_MASK;
return clkroot / (podf + 1);
}
unsigned int
imxccm_get_usdhx(struct imxccm_softc *sc, int x)
{
uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1);
uint32_t cscdr1 = HREAD4(sc, CCM_CSCDR1);
uint32_t podf, clkroot;
if (x == 1)
podf = ((cscdr1 >> 11) & CCM_CSCDR1_USDHCx_PODF_MASK);
else
podf = ((cscdr1 >> (10 + 3*x)) & CCM_CSCDR1_USDHCx_PODF_MASK);
if (cscmr1 & (1 << CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x)))
clkroot = imxanatop_get_pll2_pfd(0);
else
clkroot = imxanatop_get_pll2_pfd(2);
return clkroot / (podf + 1);
}
uint32_t
imxccm_get_uartclk(struct imxccm_softc *sc)
{
uint32_t clkroot = PLL3_80M;
uint32_t podf = HREAD4(sc, CCM_CSCDR1) & CCM_CSCDR1_UART_PODF_MASK;
return clkroot / (podf + 1);
}
uint32_t
imxccm_get_periphclk(struct imxccm_softc *sc)
{
if ((HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_PERIPH_CLK_SEL_SHIFT)
& CCM_CBCDR_PERIPH_CLK_SEL_MASK) {
switch((HREAD4(sc, CCM_CBCMR)
>> CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT) & CCM_CBCMR_PERIPH_CLK2_SEL_MASK) {
case 0:
return imxanatop_decode_pll(USB1_PLL3, HCLK_FREQ);
case 1:
case 2:
return HCLK_FREQ;
default:
return 0;
}
} else {
switch((HREAD4(sc, CCM_CBCMR)
>> CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT) & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) {
default:
case 0:
return imxanatop_decode_pll(SYS_PLL2, HCLK_FREQ);
case 1:
return imxanatop_get_pll2_pfd(2);
case 2:
return imxanatop_get_pll2_pfd(0);
case 3:
return imxanatop_get_pll2_pfd(2) / 2;
}
}
}
uint32_t
imxccm_get_ahbclk(struct imxccm_softc *sc)
{
uint32_t ahb_podf;
ahb_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_AHB_PODF_SHIFT)
& CCM_CBCDR_AHB_PODF_MASK;
return imxccm_get_periphclk(sc) / (ahb_podf + 1);
}
uint32_t
imxccm_get_ipgclk(struct imxccm_softc *sc)
{
uint32_t ipg_podf;
ipg_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_IPG_PODF_SHIFT)
& CCM_CBCDR_IPG_PODF_MASK;
return imxccm_get_ahbclk(sc) / (ipg_podf + 1);
}
uint32_t
imxccm_get_ipg_perclk(struct imxccm_softc *sc)
{
uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1);
uint32_t freq, ipg_podf;
if (sc->sc_gates == imx6ul_gates &&
cscmr1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK)
freq = HCLK_FREQ;
else
freq = imxccm_get_ipgclk(sc);
ipg_podf = cscmr1 & CCM_CSCMR1_PERCLK_CLK_PODF_MASK;
return freq / (ipg_podf + 1);
}
void
imxccm_imx6_enable_pll_enet(struct imxccm_softc *sc, int on)
{
KASSERT(on);
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_CLR,
CCM_ANALOG_PLL_ENET_POWERDOWN);
while ((regmap_read_4(sc->sc_anatop,
CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_LOCK) == 0)
;
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_CLR,
CCM_ANALOG_PLL_ENET_BYPASS);
}
void
imxccm_imx6_enable_pll_usb1(struct imxccm_softc *sc, int on)
{
KASSERT(on);
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_SET,
CCM_ANALOG_PLL_USB1_POWER);
while ((regmap_read_4(sc->sc_anatop,
CCM_ANALOG_PLL_USB1) & CCM_ANALOG_PLL_USB1_LOCK) == 0)
;
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_CLR,
CCM_ANALOG_PLL_USB1_BYPASS);
}
void
imxccm_imx6_enable_pll_usb2(struct imxccm_softc *sc, int on)
{
KASSERT(on);
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_SET,
CCM_ANALOG_PLL_USB2_POWER);
while ((regmap_read_4(sc->sc_anatop,
CCM_ANALOG_PLL_USB2) & CCM_ANALOG_PLL_USB2_LOCK) == 0)
;
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_CLR,
CCM_ANALOG_PLL_USB2_BYPASS);
}
uint32_t
imxccm_imx7d_enet(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc");
case 7:
return 392000000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx7d_i2c(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc");
case 1:
return 120000000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx7d_uart(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc");
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx7d_usdhc(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc");
case 1:
return 392000000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mm_get_pll(struct imxccm_softc *sc, uint32_t idx)
{
uint64_t main_div, pre_div, post_div, div;
uint32_t pll0, pll1;
uint64_t freq;
switch (idx) {
case IMX8MM_ARM_PLL:
pll0 = regmap_read_4(sc->sc_anatop,
CCM_14XX_IMX8M_ARM_PLL_GNRL_CTL);
pll1 = regmap_read_4(sc->sc_anatop,
CCM_14XX_IMX8M_ARM_PLL_DIV_CTL);
div = 1;
break;
default:
printf("%s: 0x%08x\n", __func__, idx);
return 0;
}
freq = clock_get_frequency(sc->sc_node, "osc_24m");
if (pll0 & CCM_INT_PLL_BYPASS)
return freq;
main_div = (pll1 >> CCM_INT_PLL_MAIN_DIV_SHIFT) &
CCM_INT_PLL_MAIN_DIV_MASK;
pre_div = (pll1 >> CCM_INT_PLL_PRE_DIV_SHIFT) &
CCM_INT_PLL_PRE_DIV_MASK;
post_div = (pll1 >> CCM_INT_PLL_POST_DIV_SHIFT) &
CCM_INT_PLL_POST_DIV_MASK;
freq = freq * main_div;
freq = freq / (pre_div * (1 << post_div) * div);
return freq;
}
int
imxccm_imx8mm_set_pll(struct imxccm_softc *sc, uint32_t idx, uint64_t freq)
{
uint64_t main_div, pre_div, post_div;
uint32_t pll0, pll1, reg;
int i;
switch (idx) {
case IMX8MM_ARM_PLL:
pre_div = 3;
switch (freq) {
case 1800000000U:
main_div = 225;
post_div = 0;
break;
case 1600000000U:
main_div = 200;
post_div = 0;
break;
case 1200000000U:
main_div = 300;
post_div = 1;
break;
case 1000000000U:
main_div = 250;
post_div = 1;
break;
case 800000000U:
main_div = 200;
post_div = 1;
break;
case 750000000U:
main_div = 250;
post_div = 2;
break;
case 700000000U:
main_div = 350;
post_div = 2;
break;
case 600000000U:
main_div = 300;
post_div = 2;
break;
default:
printf("%s: 0x%08x\n", __func__, idx);
return -1;
}
pll0 = CCM_14XX_IMX8M_ARM_PLL_GNRL_CTL;
pll1 = CCM_14XX_IMX8M_ARM_PLL_DIV_CTL;
break;
default:
printf("%s: 0x%08x\n", __func__, idx);
return -1;
}
regmap_write_4(sc->sc_anatop, pll0,
regmap_read_4(sc->sc_anatop, pll0) |
CCM_INT_PLL_LOCK_SEL);
regmap_write_4(sc->sc_anatop, pll0,
regmap_read_4(sc->sc_anatop, pll0) &
~CCM_INT_PLL_RST);
regmap_write_4(sc->sc_anatop, pll1,
main_div << CCM_INT_PLL_MAIN_DIV_SHIFT |
pre_div << CCM_INT_PLL_PRE_DIV_SHIFT |
post_div << CCM_INT_PLL_POST_DIV_SHIFT);
delay(3);
regmap_write_4(sc->sc_anatop, pll0,
regmap_read_4(sc->sc_anatop, pll0) |
CCM_INT_PLL_RST);
for (i = 0; i < 5000; i++) {
reg = regmap_read_4(sc->sc_anatop, pll0);
if (reg & CCM_INT_PLL_LOCK)
break;
delay(10);
}
if (i == 5000)
printf("%s: timeout\n", __func__);
regmap_write_4(sc->sc_anatop, pll0,
regmap_read_4(sc->sc_anatop, pll0) &
~CCM_INT_PLL_BYPASS);
return 0;
}
uint32_t
imxccm_imx8mm_enet(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_24m");
case 1:
return 266 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mm_ahb(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_24m");
case 1:
return 133 * 1000 * 1000;
case 2:
return 800 * 1000 * 1000;
case 3:
return 400 * 1000 * 1000;
case 4:
return 125 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mm_i2c(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_24m");
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mm_uart(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_24m");
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mm_usdhc(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_24m");
case 1:
return 400 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mp_enet_qos(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_24m");
case 1:
return 125 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mp_enet_qos_timer(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_24m");
case 1:
return 100 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mp_hsio_axi(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_24m");
case 1:
return 500 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_ecspi(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_25m");
case 1:
return 200 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_enet(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_25m");
case 1:
return 266 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_ahb(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_25m");
case 1:
return 133 * 1000 * 1000;
case 2:
return 800 * 1000 * 1000;
case 3:
return 400 * 1000 * 1000;
case 4:
return 125 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_i2c(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_25m");
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_pwm(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_25m");
case 1:
return 100 * 1000 * 1000;
case 2:
return 160 * 1000 * 1000;
case 3:
return 40 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_25m");
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_25m");
case 1:
return 400 * 1000 * 1000;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t mux;
if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
return 0;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux >>= sc->sc_muxs[idx].shift;
mux &= sc->sc_muxs[idx].mask;
switch (mux) {
case 0:
return clock_get_frequency(sc->sc_node, "osc_25m");
case 1:
if (idx == IMX8MQ_CLK_USB_CORE_REF ||
idx == IMX8MQ_CLK_USB_PHY_REF)
return 100 * 1000 * 1000;
if (idx == IMX8MQ_CLK_USB_BUS)
return 500 * 1000 * 1000;
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
}
uint32_t
imxccm_imx8mq_get_pll(struct imxccm_softc *sc, uint32_t idx)
{
uint32_t divr_val, divq_val, divf_val;
uint32_t divff, divfi;
uint32_t pllout_div;
uint32_t pll0, pll1;
uint32_t freq;
uint32_t mux;
pllout_div = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_PLLOUT_DIV_CFG);
switch (idx) {
case IMX8MQ_ARM_PLL:
pll0 = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_ARM_PLL0);
pll1 = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_ARM_PLL1);
pllout_div >>= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT;
pllout_div &= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK;
break;
default:
printf("%s: 0x%08x\n", __func__, idx);
return 0;
}
if (pll0 & CCM_FRAC_PLL_POWERDOWN)
return 0;
if ((pll0 & CCM_FRAC_PLL_ENABLE) == 0)
return 0;
mux = (pll0 >> CCM_FRAC_PLL_REFCLK_SEL_SHIFT) &
CCM_FRAC_PLL_REFCLK_SEL_MASK;
switch (mux) {
case 0:
freq = clock_get_frequency(sc->sc_node, "osc_25m");
break;
case 1:
case 2:
freq = clock_get_frequency(sc->sc_node, "osc_27m");
break;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return 0;
}
if (pll0 & CCM_FRAC_PLL_BYPASS)
return freq;
divr_val = (pll0 >> CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT) &
CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK;
divq_val = pll0 & CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK;
divff = (pll1 >> CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT) &
CCM_FRAC_PLL_FRAC_DIV_CTL_MASK;
divfi = pll1 & CCM_FRAC_PLL_INT_DIV_CTL_MASK;
divf_val = 1 + divfi + divff / CCM_FRAC_PLL_DENOM;
freq = freq / (divr_val + 1) * 8 * divf_val / ((divq_val + 1) * 2);
return freq / (pllout_div + 1);
}
int
imxccm_imx8mq_set_pll(struct imxccm_softc *sc, uint32_t idx, uint64_t freq)
{
uint64_t divff, divfi, divr;
uint32_t pllout_div;
uint32_t pll0, pll1;
uint32_t mux, reg;
uint64_t pfreq;
int i;
pllout_div = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_PLLOUT_DIV_CFG);
switch (idx) {
case IMX8MQ_ARM_PLL:
pll0 = CCM_FRAC_IMX8M_ARM_PLL0;
pll1 = CCM_FRAC_IMX8M_ARM_PLL1;
pllout_div >>= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT;
pllout_div &= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK;
KASSERT(pllout_div == 0);
divr = 5;
break;
default:
printf("%s: 0x%08x\n", __func__, idx);
return -1;
}
reg = regmap_read_4(sc->sc_anatop, pll0);
mux = (reg >> CCM_FRAC_PLL_REFCLK_SEL_SHIFT) &
CCM_FRAC_PLL_REFCLK_SEL_MASK;
switch (mux) {
case 0:
pfreq = clock_get_frequency(sc->sc_node, "osc_25m");
break;
case 1:
case 2:
pfreq = clock_get_frequency(sc->sc_node, "osc_27m");
break;
default:
printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
return -1;
}
freq *= divr;
freq *= 2;
pfreq *= 8;
divfi = freq / pfreq;
divff = (uint64_t)(freq - divfi * pfreq);
divff = (divff * CCM_FRAC_PLL_DENOM) / pfreq;
reg = regmap_read_4(sc->sc_anatop, pll1);
reg &= ~(CCM_FRAC_PLL_FRAC_DIV_CTL_MASK << CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT);
reg |= divff << CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT;
reg &= ~(CCM_FRAC_PLL_INT_DIV_CTL_MASK << CCM_FRAC_PLL_INT_DIV_CTL_SHIFT);
reg |= (divfi - 1) << CCM_FRAC_PLL_INT_DIV_CTL_SHIFT;
regmap_write_4(sc->sc_anatop, pll1, reg);
reg = regmap_read_4(sc->sc_anatop, pll0);
reg &= ~CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK;
reg &= ~(CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK << CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT);
reg |= (divr - 1) << CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT;
regmap_write_4(sc->sc_anatop, pll0, reg);
reg = regmap_read_4(sc->sc_anatop, pll0);
reg |= CCM_FRAC_PLL_NEWDIV_VAL;
regmap_write_4(sc->sc_anatop, pll0, reg);
for (i = 0; i < 5000; i++) {
reg = regmap_read_4(sc->sc_anatop, pll0);
if (reg & CCM_FRAC_PLL_BYPASS)
break;
if (reg & CCM_FRAC_PLL_POWERDOWN)
break;
if (reg & CCM_FRAC_PLL_NEWDIV_ACK)
break;
delay(10);
}
if (i == 5000)
printf("%s: timeout\n", __func__);
reg = regmap_read_4(sc->sc_anatop, pll0);
reg &= ~CCM_FRAC_PLL_NEWDIV_VAL;
regmap_write_4(sc->sc_anatop, pll0, reg);
return 0;
}
int
imxccm_imx8m_set_div(struct imxccm_softc *sc, uint32_t idx, uint64_t freq,
uint64_t parent_freq)
{
uint64_t div;
uint32_t reg;
if (parent_freq < freq) {
printf("%s: parent frequency too low (0x%08x)\n",
__func__, idx);
return -1;
}
imxccm_enable(sc, &idx, 1);
div = 0;
while (parent_freq / (div + 1) > freq)
div++;
reg = HREAD4(sc, sc->sc_divs[idx].reg);
reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift);
reg |= (div << sc->sc_divs[idx].shift);
HWRITE4(sc, sc->sc_divs[idx].reg, reg);
HCLR4(sc, sc->sc_predivs[idx].reg,
sc->sc_predivs[idx].mask << sc->sc_predivs[idx].shift);
return 0;
}
void
imxccm_enable_parent(struct imxccm_softc *sc, uint32_t parent, int on)
{
if (on)
imxccm_enable(sc, &parent, on);
}
void
imxccm_enable(void *cookie, uint32_t *cells, int on)
{
struct imxccm_softc *sc = cookie;
uint32_t idx = cells[0], parent;
uint32_t pcells[2];
uint16_t reg;
uint8_t pos;
if (idx == 0)
return;
if (sc->sc_gates == imx8mm_gates) {
switch (idx) {
case IMX8MM_CLK_PCIE1_CTRL:
case IMX8MM_CLK_PCIE2_CTRL:
pcells[0] = sc->sc_phandle;
pcells[1] = IMX8MM_SYS_PLL2_250M;
imxccm_set_parent(cookie, &idx, pcells);
break;
case IMX8MM_CLK_PCIE1_PHY:
case IMX8MM_CLK_PCIE2_PHY:
pcells[0] = sc->sc_phandle;
pcells[1] = IMX8MM_SYS_PLL2_100M;
imxccm_set_parent(cookie, &idx, pcells);
break;
}
} else if (sc->sc_gates == imx8mq_gates) {
switch (idx) {
case IMX8MQ_CLK_32K:
return;
case IMX8MQ_CLK_PCIE1_CTRL:
case IMX8MQ_CLK_PCIE2_CTRL:
pcells[0] = sc->sc_phandle;
pcells[1] = IMX8MQ_SYS2_PLL_250M;
imxccm_set_parent(cookie, &idx, pcells);
break;
case IMX8MQ_CLK_PCIE1_PHY:
case IMX8MQ_CLK_PCIE2_PHY:
pcells[0] = sc->sc_phandle;
pcells[1] = IMX8MQ_SYS2_PLL_100M;
imxccm_set_parent(cookie, &idx, pcells);
break;
}
} else if (sc->sc_gates == imx7d_gates) {
if (sc->sc_anatop == NULL) {
sc->sc_anatop = regmap_bycompatible("fsl,imx7d-anatop");
KASSERT(sc->sc_anatop);
}
switch (idx) {
case IMX7D_PLL_ENET_MAIN_125M_CLK:
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_SET,
CCM_ANALOG_PLL_ENET_ENABLE_CLK_125MHZ);
return;
default:
break;
}
} else if (sc->sc_gates == imx6_gates) {
if (sc->sc_anatop == NULL) {
sc->sc_anatop = regmap_bycompatible("fsl,imx6q-anatop");
KASSERT(sc->sc_anatop);
}
switch (idx) {
case IMX6_CLK_PLL3:
imxccm_imx6_enable_pll_usb1(sc, on);
return;
case IMX6_CLK_PLL6:
imxccm_imx6_enable_pll_enet(sc, on);
return;
case IMX6_CLK_PLL7:
imxccm_imx6_enable_pll_usb2(sc, on);
return;
case IMX6_CLK_PLL3_USB_OTG:
imxccm_enable_parent(sc, IMX6_CLK_PLL3, on);
regmap_write_4(sc->sc_anatop,
on ? CCM_ANALOG_PLL_USB1_SET : CCM_ANALOG_PLL_USB1_CLR,
CCM_ANALOG_PLL_USB1_ENABLE);
return;
case IMX6_CLK_PLL6_ENET:
imxccm_enable_parent(sc, IMX6_CLK_PLL6, on);
regmap_write_4(sc->sc_anatop,
on ? CCM_ANALOG_PLL_ENET_SET : CCM_ANALOG_PLL_ENET_CLR,
CCM_ANALOG_PLL_ENET_ENABLE);
return;
case IMX6_CLK_PLL7_USB_HOST:
imxccm_enable_parent(sc, IMX6_CLK_PLL7, on);
regmap_write_4(sc->sc_anatop,
on ? CCM_ANALOG_PLL_USB2_SET : CCM_ANALOG_PLL_USB2_CLR,
CCM_ANALOG_PLL_USB2_ENABLE);
return;
case IMX6_CLK_USBPHY1:
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_SET,
CCM_ANALOG_PLL_USB1_EN_USB_CLKS);
imxccm_enable_parent(sc, IMX6_CLK_PLL3_USB_OTG, on);
return;
case IMX6_CLK_USBPHY2:
regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_SET,
CCM_ANALOG_PLL_USB2_EN_USB_CLKS);
imxccm_enable_parent(sc, IMX6_CLK_PLL7_USB_HOST, on);
return;
case IMX6_CLK_SATA_REF_100:
imxccm_enable_parent(sc, IMX6_CLK_PLL6_ENET, on);
regmap_write_4(sc->sc_anatop,
on ? CCM_ANALOG_PLL_ENET_SET : CCM_ANALOG_PLL_ENET_CLR,
CCM_ANALOG_PLL_ENET_ENABLE_100M);
return;
case IMX6_CLK_ENET_REF:
imxccm_enable_parent(sc, IMX6_CLK_PLL6_ENET, on);
return;
case IMX6_CLK_IPG:
case IMX6_CLK_IPG_PER:
case IMX6_CLK_ECSPI_ROOT:
return;
default:
break;
}
}
if (on) {
if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
parent = sc->sc_gates[idx].parent;
imxccm_enable(sc, &parent, on);
}
if (idx < sc->sc_ndivs && sc->sc_divs[idx].parent) {
parent = sc->sc_divs[idx].parent;
imxccm_enable(sc, &parent, on);
}
}
if (idx >= sc->sc_ngates || sc->sc_gates[idx].reg == 0) {
if ((idx < sc->sc_ndivs && sc->sc_divs[idx].reg != 0) ||
(idx < sc->sc_nmuxs && sc->sc_muxs[idx].reg != 0))
return;
printf("%s: 0x%08x\n", __func__, idx);
return;
}
reg = sc->sc_gates[idx].reg;
pos = sc->sc_gates[idx].pos;
if (on)
HSET4(sc, reg, 0x3 << (2 * pos));
else
HCLR4(sc, reg, 0x3 << (2 * pos));
}
uint32_t
imxccm_get_frequency(void *cookie, uint32_t *cells)
{
struct imxccm_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t div, pre, reg, parent;
uint32_t freq;
if (idx == 0)
return 0;
if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
parent = sc->sc_gates[idx].parent;
return imxccm_get_frequency(sc, &parent);
}
if (idx < sc->sc_ndivs && sc->sc_divs[idx].parent) {
div = HREAD4(sc, sc->sc_divs[idx].reg);
div = div >> sc->sc_divs[idx].shift;
div = div & sc->sc_divs[idx].mask;
parent = sc->sc_divs[idx].parent;
return imxccm_get_frequency(sc, &parent) / (div + 1);
}
if (sc->sc_gates == imx8mm_gates) {
switch (idx) {
case IMX8MM_CLK_ARM:
parent = IMX8MM_ARM_PLL;
return imxccm_get_frequency(sc, &parent);
case IMX8MM_ARM_PLL:
return imxccm_imx8mm_get_pll(sc, idx);
}
if (idx < sc->sc_ngates && sc->sc_gates[idx].reg &&
idx < sc->sc_ndivs && sc->sc_divs[idx].reg &&
idx < sc->sc_npredivs && sc->sc_predivs[idx].reg) {
switch (idx) {
case IMX8MM_CLK_ENET_AXI:
freq = imxccm_imx8mm_enet(sc, idx);
break;
case IMX8MM_CLK_AHB:
freq = imxccm_imx8mm_ahb(sc, idx);
break;
case IMX8MM_CLK_I2C1:
case IMX8MM_CLK_I2C2:
case IMX8MM_CLK_I2C3:
case IMX8MM_CLK_I2C4:
freq = imxccm_imx8mm_i2c(sc, idx);
break;
case IMX8MM_CLK_UART1:
case IMX8MM_CLK_UART2:
case IMX8MM_CLK_UART3:
case IMX8MM_CLK_UART4:
freq = imxccm_imx8mm_uart(sc, idx);
break;
case IMX8MM_CLK_USDHC1:
case IMX8MM_CLK_USDHC2:
case IMX8MM_CLK_USDHC3:
freq = imxccm_imx8mm_usdhc(sc, idx);
break;
default:
printf("%s: 0x%08x\n", __func__, idx);
return 0;
}
reg = HREAD4(sc, sc->sc_divs[idx].reg);
div = reg >> sc->sc_divs[idx].shift;
div = div & sc->sc_divs[idx].mask;
pre = reg >> sc->sc_predivs[idx].shift;
pre = pre & sc->sc_predivs[idx].mask;
return ((freq / (pre + 1)) / (div + 1));
}
} else if (sc->sc_gates == imx8mp_gates) {
if (idx < sc->sc_ngates && sc->sc_gates[idx].reg &&
idx < sc->sc_ndivs && sc->sc_divs[idx].reg &&
idx < sc->sc_npredivs && sc->sc_predivs[idx].reg) {
switch (idx) {
case IMX8MP_CLK_ENET_AXI:
freq = imxccm_imx8mm_enet(sc, idx);
break;
case IMX8MP_CLK_AHB:
freq = imxccm_imx8mm_ahb(sc, idx);
break;
case IMX8MP_CLK_I2C1:
case IMX8MP_CLK_I2C2:
case IMX8MP_CLK_I2C3:
case IMX8MP_CLK_I2C4:
case IMX8MP_CLK_I2C5:
case IMX8MP_CLK_I2C6:
freq = imxccm_imx8mm_i2c(sc, idx);
break;
case IMX8MP_CLK_UART1:
case IMX8MP_CLK_UART2:
case IMX8MP_CLK_UART3:
case IMX8MP_CLK_UART4:
freq = imxccm_imx8mm_uart(sc, idx);
break;
case IMX8MP_CLK_USDHC1:
case IMX8MP_CLK_USDHC2:
case IMX8MP_CLK_USDHC3:
freq = imxccm_imx8mm_usdhc(sc, idx);
break;
case IMX8MP_CLK_ENET_QOS:
freq = imxccm_imx8mp_enet_qos(sc, idx);
break;
case IMX8MP_CLK_ENET_QOS_TIMER:
freq = imxccm_imx8mp_enet_qos_timer(sc, idx);
break;
case IMX8MP_CLK_HSIO_AXI:
freq = imxccm_imx8mp_hsio_axi(sc, idx);
break;
default:
printf("%s: 0x%08x\n", __func__, idx);
return 0;
}
reg = HREAD4(sc, sc->sc_divs[idx].reg);
div = reg >> sc->sc_divs[idx].shift;
div = div & sc->sc_divs[idx].mask;
pre = reg >> sc->sc_predivs[idx].shift;
pre = pre & sc->sc_predivs[idx].mask;
return ((freq / (pre + 1)) / (div + 1));
}
} else if (sc->sc_gates == imx8mq_gates) {
switch (idx) {
case IMX8MQ_CLK_ARM:
parent = IMX8MQ_ARM_PLL;
return imxccm_get_frequency(sc, &parent);
case IMX8MQ_ARM_PLL:
return imxccm_imx8mq_get_pll(sc, idx);
}
if (idx < sc->sc_ngates && sc->sc_gates[idx].reg &&
idx < sc->sc_ndivs && sc->sc_divs[idx].reg &&
idx < sc->sc_npredivs && sc->sc_predivs[idx].reg) {
switch (idx) {
case IMX8MQ_CLK_ENET_AXI:
freq = imxccm_imx8mq_enet(sc, idx);
break;
case IMX8MQ_CLK_AHB:
freq = imxccm_imx8mq_ahb(sc, idx);
break;
case IMX8MQ_CLK_I2C1:
case IMX8MQ_CLK_I2C2:
case IMX8MQ_CLK_I2C3:
case IMX8MQ_CLK_I2C4:
freq = imxccm_imx8mq_i2c(sc, idx);
break;
case IMX8MQ_CLK_UART1:
case IMX8MQ_CLK_UART2:
case IMX8MQ_CLK_UART3:
case IMX8MQ_CLK_UART4:
freq = imxccm_imx8mq_uart(sc, idx);
break;
case IMX8MQ_CLK_USDHC1:
case IMX8MQ_CLK_USDHC2:
freq = imxccm_imx8mq_usdhc(sc, idx);
break;
case IMX8MQ_CLK_USB_BUS:
case IMX8MQ_CLK_USB_CORE_REF:
case IMX8MQ_CLK_USB_PHY_REF:
freq = imxccm_imx8mq_usb(sc, idx);
break;
case IMX8MQ_CLK_ECSPI1:
case IMX8MQ_CLK_ECSPI2:
case IMX8MQ_CLK_ECSPI3:
freq = imxccm_imx8mq_ecspi(sc, idx);
break;
case IMX8MQ_CLK_PWM1:
case IMX8MQ_CLK_PWM2:
case IMX8MQ_CLK_PWM3:
case IMX8MQ_CLK_PWM4:
freq = imxccm_imx8mq_pwm(sc, idx);
break;
default:
printf("%s: 0x%08x\n", __func__, idx);
return 0;
}
reg = HREAD4(sc, sc->sc_divs[idx].reg);
div = reg >> sc->sc_divs[idx].shift;
div = div & sc->sc_divs[idx].mask;
pre = reg >> sc->sc_predivs[idx].shift;
pre = pre & sc->sc_predivs[idx].mask;
return ((freq / (pre + 1)) / (div + 1));
}
} else if (sc->sc_gates == imx7d_gates) {
switch (idx) {
case IMX7D_ENET_AXI_ROOT_SRC:
return imxccm_imx7d_enet(sc, idx);
case IMX7D_I2C1_ROOT_SRC:
case IMX7D_I2C2_ROOT_SRC:
case IMX7D_I2C3_ROOT_SRC:
case IMX7D_I2C4_ROOT_SRC:
return imxccm_imx7d_i2c(sc, idx);
case IMX7D_UART1_ROOT_SRC:
case IMX7D_UART2_ROOT_SRC:
case IMX7D_UART3_ROOT_SRC:
case IMX7D_UART4_ROOT_SRC:
case IMX7D_UART5_ROOT_SRC:
case IMX7D_UART6_ROOT_SRC:
case IMX7D_UART7_ROOT_SRC:
return imxccm_imx7d_uart(sc, idx);
case IMX7D_USDHC1_ROOT_SRC:
case IMX7D_USDHC2_ROOT_SRC:
case IMX7D_USDHC3_ROOT_SRC:
return imxccm_imx7d_usdhc(sc, idx);
}
} else if (sc->sc_gates == imx6ul_gates) {
switch (idx) {
case IMX6UL_CLK_ARM:
return imxccm_get_armclk(sc);
case IMX6UL_CLK_IPG:
return imxccm_get_ipgclk(sc);
case IMX6UL_CLK_PERCLK:
return imxccm_get_ipg_perclk(sc);
case IMX6UL_CLK_UART1_SERIAL:
return imxccm_get_uartclk(sc);
case IMX6UL_CLK_USDHC1:
case IMX6UL_CLK_USDHC2:
return imxccm_get_usdhx(sc, idx - IMX6UL_CLK_USDHC1 + 1);
}
} else if (sc->sc_gates == imx6_gates) {
switch (idx) {
case IMX6_CLK_AHB:
return imxccm_get_ahbclk(sc);
case IMX6_CLK_ARM:
return imxccm_get_armclk(sc);
case IMX6_CLK_IPG:
return imxccm_get_ipgclk(sc);
case IMX6_CLK_IPG_PER:
return imxccm_get_ipg_perclk(sc);
case IMX6_CLK_ECSPI_ROOT:
return imxccm_get_ecspiclk(sc);
case IMX6_CLK_UART_SERIAL:
return imxccm_get_uartclk(sc);
case IMX6_CLK_USDHC1:
case IMX6_CLK_USDHC2:
case IMX6_CLK_USDHC3:
case IMX6_CLK_USDHC4:
return imxccm_get_usdhx(sc, idx - IMX6_CLK_USDHC1 + 1);
}
}
printf("%s: 0x%08x\n", __func__, idx);
return 0;
}
int
imxccm_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
{
struct imxccm_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t reg, div, parent, parent_freq;
uint32_t pcells[2];
int ret;
if (sc->sc_divs == imx8mm_divs) {
switch (idx) {
case IMX8MM_CLK_ARM:
parent = IMX8MM_CLK_A53_SRC;
return imxccm_set_frequency(cookie, &parent, freq);
case IMX8MM_CLK_A53_SRC:
pcells[0] = sc->sc_phandle;
pcells[1] = IMX8MM_SYS_PLL1_800M;
ret = imxccm_set_parent(cookie, &idx, pcells);
if (ret)
return ret;
ret = imxccm_imx8mm_set_pll(sc, IMX8MM_ARM_PLL, freq);
pcells[0] = sc->sc_phandle;
pcells[1] = IMX8MM_ARM_PLL_OUT;
imxccm_set_parent(cookie, &idx, pcells);
return ret;
case IMX8MM_CLK_USDHC1_ROOT:
case IMX8MM_CLK_USDHC2_ROOT:
case IMX8MM_CLK_USDHC3_ROOT:
parent = sc->sc_gates[idx].parent;
return imxccm_set_frequency(sc, &parent, freq);
case IMX8MM_CLK_USDHC1:
case IMX8MM_CLK_USDHC2:
case IMX8MM_CLK_USDHC3:
parent_freq = imxccm_imx8mm_usdhc(sc, idx);
return imxccm_imx8m_set_div(sc, idx, freq, parent_freq);
}
} else if (sc->sc_divs == imx8mp_divs) {
switch (idx) {
case IMX8MP_CLK_ENET_QOS:
parent_freq = imxccm_imx8mp_enet_qos(sc, idx);
return imxccm_imx8m_set_div(sc, idx, freq, parent_freq);
case IMX8MP_CLK_ENET_QOS_TIMER:
parent_freq = imxccm_imx8mp_enet_qos_timer(sc, idx);
return imxccm_imx8m_set_div(sc, idx, freq, parent_freq);
case IMX8MP_CLK_HSIO_AXI:
parent_freq = imxccm_imx8mp_hsio_axi(sc, idx);
return imxccm_imx8m_set_div(sc, idx, freq, parent_freq);
}
} else if (sc->sc_divs == imx8mq_divs) {
switch (idx) {
case IMX8MQ_CLK_ARM:
parent = IMX8MQ_CLK_A53_SRC;
return imxccm_set_frequency(cookie, &parent, freq);
case IMX8MQ_CLK_A53_SRC:
pcells[0] = sc->sc_phandle;
pcells[1] = IMX8MQ_SYS1_PLL_800M;
ret = imxccm_set_parent(cookie, &idx, pcells);
if (ret)
return ret;
ret = imxccm_imx8mq_set_pll(sc, IMX8MQ_ARM_PLL, freq);
pcells[0] = sc->sc_phandle;
pcells[1] = IMX8MQ_ARM_PLL_OUT;
imxccm_set_parent(cookie, &idx, pcells);
return ret;
case IMX8MQ_CLK_USB_BUS:
case IMX8MQ_CLK_USB_CORE_REF:
case IMX8MQ_CLK_USB_PHY_REF:
if (imxccm_get_frequency(sc, cells) != freq)
break;
return 0;
case IMX8MQ_CLK_USDHC1:
case IMX8MQ_CLK_USDHC2:
parent_freq = imxccm_imx8mq_usdhc(sc, idx);
return imxccm_imx8m_set_div(sc, idx, freq, parent_freq);
}
} else if (sc->sc_divs == imx7d_divs) {
switch (idx) {
case IMX7D_USDHC1_ROOT_CLK:
case IMX7D_USDHC2_ROOT_CLK:
case IMX7D_USDHC3_ROOT_CLK:
parent = sc->sc_gates[idx].parent;
return imxccm_set_frequency(sc, &parent, freq);
case IMX7D_USDHC1_ROOT_DIV:
case IMX7D_USDHC2_ROOT_DIV:
case IMX7D_USDHC3_ROOT_DIV:
parent = sc->sc_divs[idx].parent;
parent_freq = imxccm_get_frequency(sc, &parent);
div = 0;
while (parent_freq / (div + 1) > freq)
div++;
reg = HREAD4(sc, sc->sc_divs[idx].reg);
reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift);
reg |= (div << sc->sc_divs[idx].shift);
HWRITE4(sc, sc->sc_divs[idx].reg, reg);
return 0;
}
}
printf("%s: 0x%08x %x\n", __func__, idx, freq);
return -1;
}
int
imxccm_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells)
{
struct imxccm_softc *sc = cookie;
uint32_t idx = cells[0];
uint32_t pidx;
uint32_t mux;
if (pcells[0] != sc->sc_phandle) {
printf("%s: 0x%08x parent 0x%08x\n", __func__, idx, pcells[0]);
return -1;
}
pidx = pcells[1];
if (sc->sc_muxs == imx8mm_muxs) {
switch (idx) {
case IMX8MM_CLK_A53_SRC:
if (pidx != IMX8MM_ARM_PLL_OUT &&
pidx != IMX8MM_SYS_PLL1_800M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
if (pidx == IMX8MM_ARM_PLL_OUT)
mux |= (0x1 << sc->sc_muxs[idx].shift);
if (pidx == IMX8MM_SYS_PLL1_800M)
mux |= (0x4 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MM_CLK_USB_BUS:
if (pidx != IMX8MM_SYS_PLL2_500M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MM_CLK_USB_CORE_REF:
case IMX8MM_CLK_USB_PHY_REF:
if (pidx != IMX8MM_SYS_PLL1_100M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MM_CLK_PCIE1_CTRL:
case IMX8MM_CLK_PCIE2_CTRL:
if (pidx != IMX8MM_SYS_PLL2_250M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MM_CLK_PCIE1_PHY:
case IMX8MM_CLK_PCIE2_PHY:
if (pidx != IMX8MM_SYS_PLL2_100M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
}
} else if (sc->sc_muxs == imx8mp_muxs) {
switch (idx) {
case IMX8MP_CLK_ENET_AXI:
if (pidx != IMX8MP_SYS_PLL1_266M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MP_CLK_PCIE_PHY:
if (pidx != IMX8MP_CLK_24M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x0 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MP_CLK_PCIE_AUX:
if (pidx != IMX8MP_SYS_PLL2_50M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x2 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MP_CLK_ENET_QOS:
if (pidx != IMX8MP_SYS_PLL2_125M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MP_CLK_ENET_QOS_TIMER:
if (pidx != IMX8MP_SYS_PLL2_100M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MP_CLK_USB_PHY_REF:
if (pidx != IMX8MP_CLK_24M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x0 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MP_CLK_HSIO_AXI:
if (pidx != IMX8MP_SYS_PLL2_500M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
}
} else if (sc->sc_muxs == imx8mq_muxs) {
switch (idx) {
case IMX8MQ_CLK_A53_SRC:
if (pidx != IMX8MQ_ARM_PLL_OUT &&
pidx != IMX8MQ_SYS1_PLL_800M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
if (pidx == IMX8MQ_ARM_PLL_OUT)
mux |= (0x1 << sc->sc_muxs[idx].shift);
if (pidx == IMX8MQ_SYS1_PLL_800M)
mux |= (0x4 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MQ_CLK_USB_BUS:
if (pidx != IMX8MQ_SYS2_PLL_500M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MQ_CLK_USB_CORE_REF:
case IMX8MQ_CLK_USB_PHY_REF:
if (pidx != IMX8MQ_SYS1_PLL_100M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MQ_CLK_PCIE1_CTRL:
case IMX8MQ_CLK_PCIE2_CTRL:
if (pidx != IMX8MQ_SYS2_PLL_250M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
case IMX8MQ_CLK_PCIE1_PHY:
case IMX8MQ_CLK_PCIE2_PHY:
if (pidx != IMX8MQ_SYS2_PLL_100M)
break;
mux = HREAD4(sc, sc->sc_muxs[idx].reg);
mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
mux |= (0x1 << sc->sc_muxs[idx].shift);
HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
return 0;
}
}
printf("%s: 0x%08x 0x%08x\n", __func__, idx, pidx);
return -1;
}