diff options
author | 2018-04-02 16:47:39 +0000 | |
---|---|---|
committer | 2018-04-02 16:47:39 +0000 | |
commit | 4bed6a7dd2465f9ccb015ce1b28548c7d48c7517 (patch) | |
tree | a7b7c09583941fb16b9f9062667850f1f3e5a8d4 /sys/dev/fdt/imxccm.c | |
parent | Add dwpcie(4), a (minimal) driver for the Synopsys Designware PCIe core in (diff) | |
download | wireguard-openbsd-4bed6a7dd2465f9ccb015ce1b28548c7d48c7517.tar.xz wireguard-openbsd-4bed6a7dd2465f9ccb015ce1b28548c7d48c7517.zip |
Move imxccm(4) to sys/dev/fdt.
Diffstat (limited to 'sys/dev/fdt/imxccm.c')
-rw-r--r-- | sys/dev/fdt/imxccm.c | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/sys/dev/fdt/imxccm.c b/sys/dev/fdt/imxccm.c new file mode 100644 index 00000000000..4153b754fde --- /dev/null +++ b/sys/dev/fdt/imxccm.c @@ -0,0 +1,619 @@ +/* $OpenBSD: imxccm.c,v 1.1 2018/04/02 16:47:39 patrick Exp $ */ +/* + * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#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/fdt.h> + +/* registers */ +#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 + +/* ANALOG */ +#define CCM_ANALOG_PLL_ARM 0x4000 +#define CCM_ANALOG_PLL_ARM_SET 0x4004 +#define CCM_ANALOG_PLL_ARM_CLR 0x4008 +#define CCM_ANALOG_PLL_USB1 0x4010 +#define CCM_ANALOG_PLL_USB1_SET 0x4014 +#define CCM_ANALOG_PLL_USB1_CLR 0x4018 +#define CCM_ANALOG_PLL_USB2 0x4020 +#define CCM_ANALOG_PLL_USB2_SET 0x4024 +#define CCM_ANALOG_PLL_USB2_CLR 0x4028 +#define CCM_ANALOG_PLL_SYS 0x4030 +#define CCM_ANALOG_USB1_CHRG_DETECT 0x41b0 +#define CCM_ANALOG_USB1_CHRG_DETECT_SET 0x41b4 +#define CCM_ANALOG_USB1_CHRG_DETECT_CLR 0x41b8 +#define CCM_ANALOG_USB2_CHRG_DETECT 0x4210 +#define CCM_ANALOG_USB2_CHRG_DETECT_SET 0x4214 +#define CCM_ANALOG_USB2_CHRG_DETECT_CLR 0x4218 +#define CCM_ANALOG_DIGPROG 0x4260 +#define CCM_ANALOG_PLL_ENET 0x40e0 +#define CCM_ANALOG_PLL_ENET_SET 0x40e4 +#define CCM_ANALOG_PLL_ENET_CLR 0x40e8 +#define CCM_ANALOG_PFD_480 0x40f0 +#define CCM_ANALOG_PFD_480_SET 0x40f4 +#define CCM_ANALOG_PFD_480_CLR 0x40f8 +#define CCM_ANALOG_PFD_528 0x4100 +#define CCM_ANALOG_PFD_528_SET 0x4104 +#define CCM_ANALOG_PFD_528_CLR 0x4108 +#define CCM_PMU_MISC1 0x4160 + +/* bits and bytes */ +#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_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_ARM_DIV_SELECT_MASK 0x7f +#define CCM_ANALOG_PLL_ARM_BYPASS (1 << 16) +#define CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK 0x1 +#define CCM_ANALOG_PLL_USB1_EN_USB_CLKS (1 << 6) +#define CCM_ANALOG_PLL_USB1_POWER (1 << 12) +#define CCM_ANALOG_PLL_USB1_ENABLE (1 << 13) +#define CCM_ANALOG_PLL_USB1_BYPASS (1 << 16) +#define CCM_ANALOG_PLL_USB1_LOCK (1 << 31) +#define CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK 0x1 +#define CCM_ANALOG_PLL_USB2_EN_USB_CLKS (1 << 6) +#define CCM_ANALOG_PLL_USB2_POWER (1 << 12) +#define CCM_ANALOG_PLL_USB2_ENABLE (1 << 13) +#define CCM_ANALOG_PLL_USB2_BYPASS (1 << 16) +#define CCM_ANALOG_PLL_USB2_LOCK (1U << 31) +#define CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK 0x1 +#define CCM_ANALOG_USB1_CHRG_DETECT_CHK_CHRG_B (1 << 19) +#define CCM_ANALOG_USB1_CHRG_DETECT_EN_B (1 << 20) +#define CCM_ANALOG_USB2_CHRG_DETECT_CHK_CHRG_B (1 << 19) +#define CCM_ANALOG_USB2_CHRG_DETECT_EN_B (1 << 20) +#define CCM_ANALOG_DIGPROG_MINOR_MASK 0xff +#define CCM_ANALOG_PLL_ENET_DIV_125M (1 << 11) +#define CCM_ANALOG_PLL_ENET_POWERDOWN (1 << 12) +#define CCM_ANALOG_PLL_ENET_ENABLE (1 << 13) +#define CCM_ANALOG_PLL_ENET_BYPASS (1 << 16) +#define CCM_ANALOG_PLL_ENET_125M_PCIE (1 << 19) +#define CCM_ANALOG_PLL_ENET_100M_SATA (1 << 20) +#define CCM_ANALOG_PLL_ENET_LOCK (1U << 31) +#define CCM_ANALOG_PFD_480_PFDx_FRAC(x, y) (((x) >> ((y) << 3)) & 0x3f) +#define CCM_ANALOG_PFD_528_PFDx_FRAC(x, y) (((x) >> ((y) << 3)) & 0x3f) +#define CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_SATA (0xB << 0) +#define CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_MASK (0x1f << 0) +#define CCM_PMU_MISC1_LVDSCLK1_OBEN (1 << 10) +#define CCM_PMU_MISC1_LVDSCLK1_IBEN (1 << 12) + +#define HCLK_FREQ 24000000 +#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 { + uint8_t reg; + uint8_t pos; + uint8_t parent; +}; + +#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; + + struct imxccm_gate *sc_gates; + int sc_ngates; + struct clock_device sc_cd; +}; + +enum clocks { + /* OSC */ + OSC, /* 24 MHz OSC */ + + /* PLLs */ + ARM_PLL1, /* ARM core PLL */ + SYS_PLL2, /* System PLL: 528 MHz */ + USB1_PLL3, /* OTG USB PLL: 480 MHz */ + USB2_PLL, /* Host USB PLL: 480 MHz */ + AUD_PLL4, /* Audio PLL */ + VID_PLL5, /* Video PLL */ + ENET_PLL6, /* ENET PLL */ + MLB_PLL, /* MLB PLL */ + + /* SYS_PLL2 PFDs */ + SYS_PLL2_PFD0, /* 352 MHz */ + SYS_PLL2_PFD1, /* 594 MHz */ + SYS_PLL2_PFD2, /* 396 MHz */ + + /* USB1_PLL3 PFDs */ + USB1_PLL3_PFD0, /* 720 MHz */ + USB1_PLL3_PFD1, /* 540 MHz */ + USB1_PLL3_PFD2, /* 508.2 MHz */ + USB1_PLL3_PFD3, /* 454.7 MHz */ +}; + +int imxccm_match(struct device *, void *, void *); +void imxccm_attach(struct device *parent, struct device *self, void *args); + +struct cfattach imxccm_ca = { + sizeof (struct imxccm_softc), imxccm_match, imxccm_attach +}; + +struct cfdriver imxccm_cd = { + NULL, "imxccm", DV_DULL +}; + +uint32_t imxccm_decode_pll(struct imxccm_softc *, enum clocks, uint32_t); +uint32_t imxccm_get_pll2_pfd(struct imxccm_softc *, unsigned int); +uint32_t imxccm_get_pll3_pfd(struct imxccm_softc *, unsigned int); +uint32_t imxccm_get_armclk(struct imxccm_softc *); +void imxccm_armclk_set_parent(struct imxccm_softc *, enum 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 *); +void imxccm_enable(void *, uint32_t *, int); +uint32_t imxccm_get_frequency(void *, uint32_t *); +void imxccm_enable_pll_usb1(struct imxccm_softc *); +void imxccm_enable_pll_usb2(struct imxccm_softc *); +void imxccm_enable_pll_enet(struct imxccm_softc *); +void imxccm_enable_enet(struct imxccm_softc *); +void imxccm_enable_sata(struct imxccm_softc *); + +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")); +} + +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 + 0x1000, 0, &sc->sc_ioh)) + panic("%s: bus_space_map failed!", __func__); + + 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(": imx6 rev 1.%d CPU freq: %d MHz", + HREAD4(sc, CCM_ANALOG_DIGPROG) & CCM_ANALOG_DIGPROG_MINOR_MASK, + imxccm_get_armclk(sc) / 1000000); + + 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; + clock_register(&sc->sc_cd); +} + +uint32_t +imxccm_decode_pll(struct imxccm_softc *sc, enum clocks pll, uint32_t freq) +{ + uint32_t div; + + switch (pll) { + case ARM_PLL1: + if (HREAD4(sc, CCM_ANALOG_PLL_ARM) + & CCM_ANALOG_PLL_ARM_BYPASS) + return freq; + div = HREAD4(sc, CCM_ANALOG_PLL_ARM) + & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK; + return (freq * div) / 2; + case SYS_PLL2: + div = HREAD4(sc, CCM_ANALOG_PLL_SYS) + & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK; + return freq * (20 + (div << 1)); + case USB1_PLL3: + div = HREAD4(sc, CCM_ANALOG_PLL_USB2) + & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK; + return freq * (20 + (div << 1)); + default: + return 0; + } +} + +uint32_t +imxccm_get_pll2_pfd(struct imxccm_softc *sc, unsigned int pfd) +{ + return imxccm_decode_pll(sc, SYS_PLL2, HCLK_FREQ) * 18ULL + / CCM_ANALOG_PFD_528_PFDx_FRAC(HREAD4(sc, CCM_ANALOG_PFD_528), pfd); +} + +uint32_t +imxccm_get_pll3_pfd(struct imxccm_softc *sc, unsigned int pfd) +{ + return imxccm_decode_pll(sc, USB1_PLL3, HCLK_FREQ) * 18ULL + / CCM_ANALOG_PFD_480_PFDx_FRAC(HREAD4(sc, CCM_ANALOG_PFD_480), pfd); +} + +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 imxccm_decode_pll(sc, ARM_PLL1, HCLK_FREQ); + else if (ccsr & CCM_CCSR_STEP_SEL) + return imxccm_get_pll2_pfd(sc, 2); + else + return HCLK_FREQ; +} + +void +imxccm_armclk_set_parent(struct imxccm_softc *sc, enum clocks clock) +{ + switch (clock) + { + case ARM_PLL1: + /* jump onto pll1 */ + HCLR4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); + /* put step clk on OSC, power saving */ + HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); + break; + case OSC: + /* put step clk on OSC */ + HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); + /* jump onto step clk */ + HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); + break; + case SYS_PLL2_PFD2: + /* put step clk on pll2-pfd2 400 MHz */ + HSET4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); + /* jump onto step clk */ + HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); + break; + default: + panic("%s: parent not possible for arm clk", __func__); + } +} + +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; + + // Odd bitsetting. Damn you. + 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 = imxccm_get_pll2_pfd(sc, 0); // 352 MHz + else + clkroot = imxccm_get_pll2_pfd(sc, 2); // 396 MHz + + 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 imxccm_decode_pll(sc, 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 imxccm_decode_pll(sc, SYS_PLL2, HCLK_FREQ); + case 1: + return imxccm_get_pll2_pfd(sc, 2); // 396 MHz + case 2: + return imxccm_get_pll2_pfd(sc, 0); // 352 MHz + case 3: + return imxccm_get_pll2_pfd(sc, 2) / 2; // 198 MHz + } + } +} + +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_enable(void *cookie, uint32_t *cells, int on) +{ + struct imxccm_softc *sc = cookie; + uint32_t idx = cells[0]; + uint8_t reg, pos; + + /* Dummy clock. */ + if (idx == 0) + return; + + if (sc->sc_gates == imx6_gates) { + switch (idx) { + case IMX6_CLK_USBPHY1: + imxccm_enable_pll_usb1(sc); + return; + case IMX6_CLK_USBPHY2: + imxccm_enable_pll_usb2(sc); + return; + case IMX6_CLK_SATA_REF_100: + imxccm_enable_sata(sc); + return; + case IMX6_CLK_ENET_REF: + imxccm_enable_enet(sc); + return; + default: + break; + } + } + + if (idx >= sc->sc_ngates || sc->sc_gates[idx].reg == 0) { + 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 parent; + + /* Dummy clock. */ + 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 (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 { + 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_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; +} + +void +imxccm_enable_pll_enet(struct imxccm_softc *sc) +{ + if (HREAD4(sc, CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_ENABLE) + return; + + HCLR4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_POWERDOWN); + + HSET4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_ENABLE); + + while(!(HREAD4(sc, CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_LOCK)); + + HCLR4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_BYPASS); +} + +void +imxccm_enable_enet(struct imxccm_softc *sc) +{ + imxccm_enable_pll_enet(sc); + HWRITE4(sc, CCM_ANALOG_PLL_ENET_SET, CCM_ANALOG_PLL_ENET_DIV_125M); +} + +void +imxccm_enable_sata(struct imxccm_softc *sc) +{ + imxccm_enable_pll_enet(sc); + HWRITE4(sc, CCM_ANALOG_PLL_ENET_SET, CCM_ANALOG_PLL_ENET_100M_SATA); +} + +void +imxccm_enable_pll_usb1(struct imxccm_softc *sc) +{ + HWRITE4(sc, CCM_ANALOG_PLL_USB1_CLR, CCM_ANALOG_PLL_USB1_BYPASS); + + HWRITE4(sc, CCM_ANALOG_PLL_USB1_SET, + CCM_ANALOG_PLL_USB1_ENABLE + | CCM_ANALOG_PLL_USB1_POWER + | CCM_ANALOG_PLL_USB1_EN_USB_CLKS); +} + +void +imxccm_enable_pll_usb2(struct imxccm_softc *sc) +{ + HWRITE4(sc, CCM_ANALOG_PLL_USB2_CLR, CCM_ANALOG_PLL_USB2_BYPASS); + + HWRITE4(sc, CCM_ANALOG_PLL_USB2_SET, + CCM_ANALOG_PLL_USB2_ENABLE + | CCM_ANALOG_PLL_USB2_POWER + | CCM_ANALOG_PLL_USB2_EN_USB_CLKS); +} |