Module Name: src Committed By: hkenken Date: Thu Jun 20 08:16:20 UTC 2019
Modified Files: src/sys/arch/arm/imx: files.imx6 if_enet_imx6.c if_enetvar.h imx6_ahcisata.c imx6_ccm.c imx6_ccmreg.h imx6_ccmvar.h imx6_i2c.c imx6_pcie.c imx6_usb.c imx6_usbphy.c imx6_usdhc.c imxi2cvar.h imxusbvar.h src/sys/arch/evbarm/nitrogen6: nitrogen6_usb.c Log Message: Add support for clk subsystem in imx6 CCM driver. To generate a diff of this commit: cvs rdiff -u -r1.14 -r1.15 src/sys/arch/arm/imx/files.imx6 cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/imx/if_enet_imx6.c cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/imx/if_enetvar.h \ src/sys/arch/arm/imx/imx6_i2c.c src/sys/arch/arm/imx/imxi2cvar.h cvs rdiff -u -r1.8 -r1.9 src/sys/arch/arm/imx/imx6_ahcisata.c \ src/sys/arch/arm/imx/imx6_pcie.c cvs rdiff -u -r1.9 -r1.10 src/sys/arch/arm/imx/imx6_ccm.c \ src/sys/arch/arm/imx/imx6_ccmreg.h cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/imx/imx6_ccmvar.h cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/imx/imx6_usb.c \ src/sys/arch/arm/imx/imxusbvar.h cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/imx/imx6_usbphy.c cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/imx/imx6_usdhc.c cvs rdiff -u -r1.4 -r1.5 src/sys/arch/evbarm/nitrogen6/nitrogen6_usb.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/imx/files.imx6 diff -u src/sys/arch/arm/imx/files.imx6:1.14 src/sys/arch/arm/imx/files.imx6:1.15 --- src/sys/arch/arm/imx/files.imx6:1.14 Wed Jun 20 07:05:37 2018 +++ src/sys/arch/arm/imx/files.imx6 Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -# $NetBSD: files.imx6,v 1.14 2018/06/20 07:05:37 hkenken Exp $ +# $NetBSD: files.imx6,v 1.15 2019/06/20 08:16:19 hkenken Exp $ # # Configuration info for the Freescale i.MX6 # @@ -32,12 +32,15 @@ attach imxpcie at axi file arch/arm/imx/imx6_pcie.c imxpcie # iMX6 Clock Control Module -device imxccm +device imxccm : clk attach imxccm at axi file arch/arm/imx/imx6_ccm.c imxccm needs-flag defflag opt_imx6clk.h IMXCCMDEBUG defparam opt_imx6clk.h IMX6_OSC_FREQ defparam opt_imx6clk.h IMX6_CKIL_FREQ +defparam opt_imx6clk.h IMX6_CKIH_FREQ +defparam opt_imx6clk.h IMX6_ANACLK1_FREQ +defparam opt_imx6clk.h IMX6_ANACLK2_FREQ # iMX6 Enhanced Periodic Interrupt Timer device imxclock Index: src/sys/arch/arm/imx/if_enet_imx6.c diff -u src/sys/arch/arm/imx/if_enet_imx6.c:1.3 src/sys/arch/arm/imx/if_enet_imx6.c:1.4 --- src/sys/arch/arm/imx/if_enet_imx6.c:1.3 Fri Jun 9 18:14:59 2017 +++ src/sys/arch/arm/imx/if_enet_imx6.c Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_enet_imx6.c,v 1.3 2017/06/09 18:14:59 ryo Exp $ */ +/* $NetBSD: if_enet_imx6.c,v 1.4 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_enet_imx6.c,v 1.3 2017/06/09 18:14:59 ryo Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_enet_imx6.c,v 1.4 2019/06/20 08:16:19 hkenken Exp $"); #include "locators.h" #include "imxccm.h" @@ -47,6 +47,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_enet_imx6 #include <arm/imx/if_enetreg.h> #include <arm/imx/if_enetvar.h> +static int enet_init_clocks(struct enet_softc *); + int enet_match(device_t parent __unused, struct cfdata *match __unused, void *aux) { @@ -108,28 +110,9 @@ enet_attach(device_t parent, device_t se sc->sc_enaddr[5] = eaddr + sc->sc_unit; #endif -#if NIMXCCM > 0 - /* PLL power up */ - if (imx6_pll_power(CCM_ANALOG_PLL_ENET, 1, - CCM_ANALOG_PLL_ENET_ENABLE) != 0) { - aprint_error_dev(sc->sc_dev, - "couldn't enable CCM_ANALOG_PLL_ENET\n"); - return; - } - if (IMX6_CHIPID_MAJOR(imx6_chip_id()) == CHIPID_MAJOR_IMX6UL) { uint32_t v; - /* iMX6UL */ - if ((imx6_pll_power(CCM_ANALOG_PLL_ENET, 1, - CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN) != 0) || - (imx6_pll_power(CCM_ANALOG_PLL_ENET, 1, - CCM_ANALOG_PLL_ENET_ENET2_125M_EN) != 0)) { - aprint_error_dev(sc->sc_dev, - "couldn't enable CCM_ANALOG_PLL_ENET\n"); - return; - } - v = iomux_read(IMX6UL_IOMUX_GPR1); switch (sc->sc_unit) { case 0: @@ -144,11 +127,42 @@ enet_attach(device_t parent, device_t se iomux_write(IMX6UL_IOMUX_GPR1, v); } - sc->sc_pllclock = imx6_get_clock(IMX6CLK_PLL6); -#else - sc->sc_pllclock = 50000000; -#endif + sc->sc_clk_enet = imx6_get_clock("enet"); + if (sc->sc_clk_enet == NULL) { + aprint_error(": couldn't get clock enet\n"); + return; + } + sc->sc_clk_enet_ref = imx6_get_clock("enet_ref"); + if (sc->sc_clk_enet_ref == NULL) { + aprint_error(": couldn't get clock enet_ref\n"); + return; + } + if (enet_init_clocks(sc) != 0) { + aprint_error_dev(self, "couldn't init clocks\n"); + return; + } + + sc->sc_pllclock = clk_get_rate(sc->sc_clk_enet_ref); enet_attach_common(self, aa->aa_iot, aa->aa_dmat, aa->aa_addr, aa->aa_size, aa->aa_irq); } + +static int +enet_init_clocks(struct enet_softc *sc) +{ + int error; + + error = clk_enable(sc->sc_clk_enet); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable enet: %d\n", error); + return error; + } + error = clk_enable(sc->sc_clk_enet_ref); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable enet-ref: %d\n", error); + return error; + } + + return 0; +} Index: src/sys/arch/arm/imx/if_enetvar.h diff -u src/sys/arch/arm/imx/if_enetvar.h:1.2 src/sys/arch/arm/imx/if_enetvar.h:1.3 --- src/sys/arch/arm/imx/if_enetvar.h:1.2 Fri Jun 9 18:14:59 2017 +++ src/sys/arch/arm/imx/if_enetvar.h Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_enetvar.h,v 1.2 2017/06/09 18:14:59 ryo Exp $ */ +/* $NetBSD: if_enetvar.h,v 1.3 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org> @@ -61,6 +61,9 @@ struct enet_softc { int sc_rgmii; unsigned int sc_pllclock; + struct clk *sc_clk_enet; + struct clk *sc_clk_enet_ref; + /* interrupts */ void *sc_ih; void *sc_ih2; /* for i.MX7 */ Index: src/sys/arch/arm/imx/imx6_i2c.c diff -u src/sys/arch/arm/imx/imx6_i2c.c:1.2 src/sys/arch/arm/imx/imx6_i2c.c:1.3 --- src/sys/arch/arm/imx/imx6_i2c.c:1.2 Fri Mar 27 05:31:23 2015 +++ src/sys/arch/arm/imx/imx6_i2c.c Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: imx6_i2c.c,v 1.2 2015/03/27 05:31:23 hkenken Exp $ */ +/* $NetBSD: imx6_i2c.c,v 1.3 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: imx6_i2c.c,v 1.2 2015/03/27 05:31:23 hkenken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: imx6_i2c.c,v 1.3 2019/06/20 08:16:19 hkenken Exp $"); #include "opt_imx.h" @@ -65,11 +65,34 @@ void imxi2c_attach(device_t parent __unused, device_t self, void *aux) { struct axi_attach_args *aa = aux; + struct imxi2c_softc *sc = device_private(self); if (aa->aa_size <= 0) aa->aa_size = I2C_SIZE; - imxi2c_set_freq(self, imx6_get_clock(IMX6CLK_PERCLK), 400000); + switch (device_unit(self)) { + case 0: + sc->sc_clk = imx6_get_clock("i2c1"); + break; + case 1: + sc->sc_clk = imx6_get_clock("i2c2"); + break; + case 2: + sc->sc_clk = imx6_get_clock("i2c3"); + break; + } + if (sc->sc_clk == NULL) { + aprint_error(": couldn't get clock sata\n"); + return; + } + + int error = clk_enable(sc->sc_clk); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable: %d\n", error); + return; + } + + imxi2c_set_freq(self, clk_get_rate(sc->sc_clk), 400000); imxi2c_attach_common(parent, self, aa->aa_iot, aa->aa_addr, aa->aa_size, aa->aa_irq, 0); } Index: src/sys/arch/arm/imx/imxi2cvar.h diff -u src/sys/arch/arm/imx/imxi2cvar.h:1.2 src/sys/arch/arm/imx/imxi2cvar.h:1.3 --- src/sys/arch/arm/imx/imxi2cvar.h:1.2 Fri Mar 27 05:31:23 2015 +++ src/sys/arch/arm/imx/imxi2cvar.h Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: imxi2cvar.h,v 1.2 2015/03/27 05:31:23 hkenken Exp $ */ +/* $NetBSD: imxi2cvar.h,v 1.3 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2012, 2015 Genetec Corporation. All rights reserved. @@ -36,6 +36,8 @@ struct imxi2c_softc { device_t sc_dev; struct motoi2c_softc sc_motoi2c; struct motoi2c_settings sc_motoi2c_settings; + + struct clk *sc_clk; }; int imxi2c_attach_common(device_t, device_t, Index: src/sys/arch/arm/imx/imx6_ahcisata.c diff -u src/sys/arch/arm/imx/imx6_ahcisata.c:1.8 src/sys/arch/arm/imx/imx6_ahcisata.c:1.9 --- src/sys/arch/arm/imx/imx6_ahcisata.c:1.8 Wed Jun 20 05:53:19 2018 +++ src/sys/arch/arm/imx/imx6_ahcisata.c Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: imx6_ahcisata.c,v 1.8 2018/06/20 05:53:19 hkenken Exp $ */ +/* $NetBSD: imx6_ahcisata.c,v 1.9 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: imx6_ahcisata.c,v 1.8 2018/06/20 05:53:19 hkenken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: imx6_ahcisata.c,v 1.9 2019/06/20 08:16:19 hkenken Exp $"); #include "locators.h" #include "opt_imx.h" @@ -47,23 +47,28 @@ __KERNEL_RCSID(0, "$NetBSD: imx6_ahcisat #include <dev/ic/ahcisatavar.h> struct imx_ahci_softc { + struct ahci_softc sc_ahcisc; + device_t sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; void *sc_ih; - struct ahci_softc sc_ahcisc; + struct clk *sc_clk_sata; + struct clk *sc_clk_sata_ref; + struct clk *sc_clk_ahb; }; static int imx6_ahcisata_match(device_t, cfdata_t, void *); static void imx6_ahcisata_attach(device_t, device_t, void *); static int imx6_ahcisata_detach(device_t, int); -static int imx6_ahcisata_init(struct imx_ahci_softc *); static int imx6_ahcisata_phy_ctrl(struct imx_ahci_softc *, uint32_t, int); static int imx6_ahcisata_phy_addr(struct imx_ahci_softc *, uint32_t); static int imx6_ahcisata_phy_write(struct imx_ahci_softc *, uint32_t, uint16_t); static int imx6_ahcisata_phy_read(struct imx_ahci_softc *, uint32_t); +static int imx6_ahcisata_init(struct imx_ahci_softc *); +static int imx6_ahcisata_init_clocks(struct imx_ahci_softc *); CFATTACH_DECL_NEW(imx6_ahcisata, sizeof(struct imx_ahci_softc), imx6_ahcisata_match, imx6_ahcisata_attach, imx6_ahcisata_detach, NULL); @@ -114,6 +119,26 @@ imx6_ahcisata_attach(device_t parent, de return; } + sc->sc_clk_sata = imx6_get_clock("sata"); + if (sc->sc_clk_sata == NULL) { + aprint_error(": couldn't get clock sata\n"); + return; + } + sc->sc_clk_sata_ref = imx6_get_clock("sata_ref"); + if (sc->sc_clk_sata_ref == NULL) { + aprint_error(": couldn't get clock sata_ref\n"); + return; + } + sc->sc_clk_ahb = imx6_get_clock("ahb"); + if (sc->sc_clk_ahb == NULL) { + aprint_error(": couldn't get clock ahb\n"); + return; + } + if (imx6_ahcisata_init_clocks(sc) != 0) { + aprint_error_dev(self, "couldn't init clocks\n"); + return; + } + if (imx6_ahcisata_init(sc) != 0) { aprint_error_dev(self, "couldn't init ahci\n"); return; @@ -262,21 +287,6 @@ imx6_ahcisata_init(struct imx_ahci_softc uint32_t v; int timeout, pllstat; - /* AHCISATA clock enable */ - v = imx6_ccm_read(CCM_CCGR5); - imx6_ccm_write(CCM_CCGR5, v | __SHIFTIN(3, CCM_CCGR5_SATA_CLK_ENABLE)); - - /* PLL power up */ - if (imx6_pll_power(CCM_ANALOG_PLL_ENET, 1, - CCM_ANALOG_PLL_ENET_ENABLE_100M) != 0) { - aprint_error_dev(sc->sc_dev, - "couldn't enable CCM_ANALOG_PLL_ENET\n"); - return -1; - } - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_ENET); - v |= CCM_ANALOG_PLL_ENET_ENABLE_100M; - imx6_ccm_analog_write(CCM_ANALOG_PLL_ENET, v); - v = iomux_read(IOMUX_GPR13); /* clear */ v &= ~(IOMUX_GPR13_SATA_PHY_8(7) | @@ -332,7 +342,32 @@ imx6_ahcisata_init(struct imx_ahci_softc /* set 1ms-timer = AHB clock / 1000 */ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS, - imx6_get_clock(IMX6CLK_AHB) / 1000); + clk_get_rate(sc->sc_clk_ahb) / 1000); return 0; } + +static int +imx6_ahcisata_init_clocks(struct imx_ahci_softc *sc) +{ + int error; + + error = clk_enable(sc->sc_clk_sata); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable sata: %d\n", error); + return error; + } + error = clk_enable(sc->sc_clk_sata_ref); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable sata-ref: %d\n", error); + return error; + } + error = clk_enable(sc->sc_clk_ahb); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable anb: %d\n", error); + return error; + } + + return 0; +} + Index: src/sys/arch/arm/imx/imx6_pcie.c diff -u src/sys/arch/arm/imx/imx6_pcie.c:1.8 src/sys/arch/arm/imx/imx6_pcie.c:1.9 --- src/sys/arch/arm/imx/imx6_pcie.c:1.8 Fri Mar 1 09:25:59 2019 +++ src/sys/arch/arm/imx/imx6_pcie.c Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: imx6_pcie.c,v 1.8 2019/03/01 09:25:59 msaitoh Exp $ */ +/* $NetBSD: imx6_pcie.c,v 1.9 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2016 Genetec Corporation. All rights reserved. @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: imx6_pcie.c,v 1.8 2019/03/01 09:25:59 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: imx6_pcie.c,v 1.9 2019/06/20 08:16:19 hkenken Exp $"); #include "opt_pci.h" @@ -104,6 +104,10 @@ struct imx6pcie_softc { int32_t sc_gpio_reset_active; int32_t sc_gpio_pwren; int32_t sc_gpio_pwren_active; + + struct clk *sc_clk_pcie_axi; + struct clk *sc_clk_lvds1_gate; + struct clk *sc_clk_pcie_ref; }; #define PCIE_CONF_LOCK(s) (s) = disable_interrupts(I32_bit) @@ -160,41 +164,28 @@ imx6pcie_valid_device(struct imx6pcie_so return 1; } -static void -imx6pcie_clock_enable(struct imx6pcie_softc *sc) +static int +imx6pcie_init_clocks(struct imx6pcie_softc *sc) { - uint32_t v; + int error; - v = imx6_ccm_analog_read(CCM_ANALOG_MISC1); - v &= ~CCM_ANALOG_MISC1_LVDS_CLK1_IBEN; - v &= ~CCM_ANALOG_MISC1_LVDS_CLK1_SRC; - v |= CCM_ANALOG_MISC1_LVDS_CLK1_OBEN; - v |= CCM_ANALOG_MISC1_LVDS_CLK1_SRC_SATA; - imx6_ccm_analog_write(CCM_ANALOG_MISC1, v); - - /* select PCIe clock source from axi */ - v = imx6_ccm_read(CCM_CBCMR); - v &= ~CCM_CBCMR_PCIE_AXI_CLK_SEL; - imx6_ccm_write(CCM_CBCMR, v); - - /* AHCISATA clock enable */ - v = imx6_ccm_read(CCM_CCGR5); - v |= __SHIFTIN(3, CCM_CCGR5_SATA_CLK_ENABLE); - imx6_ccm_write(CCM_CCGR5, v); - - /* PCIe clock enable */ - v = imx6_ccm_read(CCM_CCGR4); - v |= __SHIFTIN(3, CCM_CCGR4_PCIE_ROOT_ENABLE); - imx6_ccm_write(CCM_CCGR4, v); - - /* PLL power up */ - if (imx6_pll_power(CCM_ANALOG_PLL_ENET, 1, - CCM_ANALOG_PLL_ENET_ENABLE_125M | - CCM_ANALOG_PLL_ENET_ENABLE_100M) != 0) { - aprint_error_dev(sc->sc_dev, - "couldn't enable CCM_ANALOG_PLL_ENET\n"); - return; + error = clk_enable(sc->sc_clk_pcie_axi); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable pcie_axi: %d\n", error); + return error; + } + error = clk_enable(sc->sc_clk_lvds1_gate); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable lvds1_gate: %d\n", error); + return error; } + error = clk_enable(sc->sc_clk_pcie_ref); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable pcie_ref: %d\n", error); + return error; + } + + return 0; } static int @@ -375,8 +366,6 @@ imx6pcie_deassert_core_reset(struct imx6 } #endif - imx6pcie_clock_enable(sc); - v = iomux_read(IOMUX_GPR1); #if defined(IMX6DQP) @@ -545,6 +534,8 @@ imx6pcie_match(device_t parent, cfdata_t switch (aa->aa_addr) { case (IMX6_PCIE_BASE): return 1; + default: + break; } return 0; @@ -583,6 +574,24 @@ imx6pcie_attach(device_t parent, device_ imx6_set_gpio(self, "imx6pcie-pwren-gpio", &sc->sc_gpio_pwren, &sc->sc_gpio_pwren_active, GPIO_DIR_OUT); + sc->sc_clk_pcie_axi = imx6_get_clock("pcie_axi"); + if (sc->sc_clk_pcie_axi == NULL) { + aprint_error(": couldn't get clock pcie_axi\n"); + return; + } + sc->sc_clk_lvds1_gate = imx6_get_clock("lvds1_gate"); + if (sc->sc_clk_lvds1_gate == NULL) { + aprint_error(": couldn't get clock lvds1_gate\n"); + return; + } + sc->sc_clk_pcie_ref = imx6_get_clock("pcie_ref_125m"); + if (sc->sc_clk_pcie_ref == NULL) { + aprint_error(": couldn't get clock pcie_ref\n"); + return; + } + + imx6pcie_init_clocks(sc); + imx6pcie_linkup(sc); TAILQ_INIT(&sc->sc_intrs); Index: src/sys/arch/arm/imx/imx6_ccm.c diff -u src/sys/arch/arm/imx/imx6_ccm.c:1.9 src/sys/arch/arm/imx/imx6_ccm.c:1.10 --- src/sys/arch/arm/imx/imx6_ccm.c:1.9 Wed Jun 20 07:05:37 2018 +++ src/sys/arch/arm/imx/imx6_ccm.c Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: imx6_ccm.c,v 1.9 2018/06/20 07:05:37 hkenken Exp $ */ +/* $NetBSD: imx6_ccm.c,v 1.10 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2010-2012, 2014 Genetec Corporation. All rights reserved. @@ -25,13 +25,12 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - /* * Clock Controller Module (CCM) for i.MX6 */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: imx6_ccm.c,v 1.9 2018/06/20 07:05:37 hkenken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: imx6_ccm.c,v 1.10 2019/06/20 08:16:19 hkenken Exp $"); #include "opt_imx.h" #include "opt_imx6clk.h" @@ -59,37 +58,607 @@ __KERNEL_RCSID(0, "$NetBSD: imx6_ccm.c,v #include <arm/imx/imx6var.h> #include <arm/imx/imx6_reg.h> +#include <dev/clk/clk_backend.h> + struct imxccm_softc { device_t sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; bus_space_handle_t sc_ioh_analog; - /* for sysctl */ - struct sysctllog *sc_log; - int sc_sysctlnode_pll1_arm; - int sc_sysctlnode_pll2_sys; - int sc_sysctlnode_pll3_usb1; - int sc_sysctlnode_pll7_usb2; - int sc_sysctlnode_pll4_audio; - int sc_sysctlnode_pll5_video; - int sc_sysctlnode_pll6_enet; -/* int sc_sysctlnode_pll8_mlb; */ - int sc_sysctlnode_arm; - int sc_sysctlnode_periph; - int sc_sysctlnode_ahb; - int sc_sysctlnode_ipg; - int sc_sysctlnode_axi; + struct clk_domain sc_clkdom; +}; + +/* Clock Parents Tables */ +static const char *step_p[] = { + "osc", + "pll2_pfd2_396m" +}; + +static const char *pll1_sw_p[] = { + "pll1_sys", + "step" +}; + +static const char *periph_pre_p[] = { + "pll2_bus", + "pll2_pfd2_396m", + "pll2_pfd0_352m", + "pll2_198m" +}; + +static const char *periph_clk2_p[] = { + "pll3_usb_otg", + "osc", + "osc", + "dummy" +}; + +static const char *periph2_clk2_p[] = { + "pll3_usb_otg", + "pll2_bus" +}; + +static const char *axi_p[] = { + "periph", + "pll2_pfd2_396m", + "periph", + "pll3_pfd1_540m" +}; + +static const char *audio_p[] = { + "pll4_audio_div", + "pll3_pfd2_508m", + "pll3_pfd3_454m", + "pll3_usb_otg" +}; + +static const char *gpu2d_core_p[] = { + "axi", + "pll3_usb_otg", + "pll2_pfd0_352m", + "pll2_pfd2_396m" +}; + +static const char *gpu3d_core_p[] = { + "mmdc_ch0_axi", + "pll3_usb_otg", + "pll2_pfd1_594m", + "pll2_pfd2_396m" +}; + +static const char *gpu3d_shader_p[] = { + "mmdc_ch0_axi", + "pll3_usb_otg", + "pll2_pfd1_594m", + "pll3_pfd0_720m" +}; + +static const char *ipu_p[] = { + "mmdc_ch0_axi", + "pll2_pfd2_396m", + "pll3_120m", + "pll3_pfd1_540m" +}; + +static const char *pll_bypass_src_p[] = { + "osc", + "lvds1_in", + "lvds2_in", + "dummy" +}; + +static const char *pll1_bypass_p[] = { + "pll1", + "pll1_bypass_src" +}; + +static const char *pll2_bypass_p[] = { + "pll2", + "pll2_bypass_src" +}; + +static const char *pll3_bypass_p[] = { + "pll3", + "pll3_bypass_src" +}; + +static const char *pll4_bypass_p[] = { + "pll4", + "pll4_bypass_src" +}; + +static const char *pll5_bypass_p[] = { + "pll5", + "pll5_bypass_src" +}; + +static const char *pll6_bypass_p[] = { + "pll6", + "pll6_bypass_src" +}; + +static const char *pll7_bypass_p[] = { + "pll7", + "pll7_bypass_src" }; -struct imxccm_softc *ccm_softc; +static const char *ipu_di_pre_p[] = { + "mmdc_ch0_axi", + "pll3_usb_otg", + "pll5_video_div", + "pll2_pfd0_352m", + "pll2_pfd2_396m", + "pll3_pfd1_540m" +}; + +static const char *ipu1_di0_p[] = { + "ipu1_di0_pre", + "dummy", + "dummy", + "ldb_di0", + "ldb_di1" +}; + +static const char *ipu1_di1_p[] = { + "ipu1_di1_pre", + "dummy", + "dummy", + "ldb_di0", + "ldb_di1" +}; + +static const char *ipu2_di0_p[] = { + "ipu2_di0_pre", + "dummy", + "dummy", + "ldb_di0", + "ldb_di1" +}; + +static const char *ipu2_di1_p[] = { + "ipu2_di1_pre", + "dummy", + "dummy", + "ldb_di0", + "ldb_di1" +}; + +static const char *ldb_di_p[] = { + "pll5_video_div", + "pll2_pfd0_352m", + "pll2_pfd2_396m", + "mmdc_ch1_axi", + "pll3_usb_otg" +}; + +static const char *periph_p[] = { + "periph_pre", + "periph_clk2" +}; + +static const char *periph2_p[] = { + "periph2_pre", + "periph2_clk2" +}; + +static const char *vdo_axi_p[] = { + "axi", + "ahb" +}; + +static const char *vpu_axi_p[] = { + "axi", + "pll2_pfd2_396m", + "pll2_pfd0_352m" +}; + +static const char *cko1_p[] = { + "pll3_usb_otg", + "pll2_bus", + "pll1_sys", + "pll5_video_div", + "dummy", + "axi", + "enfc", + "ipu1_di0", + "ipu1_di1", + "ipu2_di0", + "ipu2_di1", + "ahb", + "ipg", + "ipg_per", + "ckil", + "pll4_audio_div" +}; + +static const char *cko2_p[] = { + "mmdc_ch0_axi", + "mmdc_ch1_axi", + "usdhc4", + "usdhc1", + "gpu2d_axi", + "dummy", + "ecspi_root", + "gpu3d_axi", + "usdhc3", + "dummy", + "arm", + "ipu1", + "ipu2", + "vdo_axi", + "osc", + "gpu2d_core", + "gpu3d_core", + "usdhc2", + "ssi1", + "ssi2", + "ssi3", + "gpu3d_shader", + "vpu_axi", + "can_root", + "ldb_di0", + "ldb_di1", + "esai_extal", + "eim_slow", + "uart_serial", + "spdif", + "asrc", + "hsi_tx" +}; + +static const char *cko_p[] = { + "cko1", + "cko2" +}; + +static const char *hsi_tx_p[] = { + "pll3_120m", + "pll2_pfd2_396m" +}; + +static const char *pcie_axi_p[] = { + "axi", + "ahb" +}; + +static const char *ssi_p[] = { + "pll3_pfd2_508m", + "pll3_pfd3_454m", + "pll4_audio_div" +}; + +static const char *usdhc_p[] = { + "pll2_pfd2_396m", + "pll2_pfd0_352m" +}; + +static const char *eim_p[] = { + "pll2_pfd2_396m", + "pll3_usb_otg", + "axi", + "pll2_pfd0_352m" +}; + +static const char *eim_slow_p[] = { + "axi", + "pll3_usb_otg", + "pll2_pfd2_396m", + "pll2_pfd0_352m" +}; + +static const char *enfc_p[] = { + "pll2_pfd0_352m", + "pll2_bus", + "pll3_usb_otg", + "pll2_pfd2_396m" +}; + +static const char *lvds_p[] = { + "dummy", + "dummy", + "dummy", + "dummy", + "dummy", + "dummy", + "pll4_audio", + "pll5_video", + "pll8_mlb", + "enet_ref", + "pcie_ref_125m", + "sata_ref_100m" +}; + +/* Clock Divider Tables */ +static const int enet_ref_tbl[] = { 20, 10, 5, 4, 0 }; +static const int post_div_tbl[] = { 4, 2, 1, 0 }; +static const int audiovideo_div_tbl[] = { 1, 2, 1, 4, 0 }; + +static struct imx6_clk imx6_clks[] = { + CLK_FIXED("dummy", 0), + + CLK_FIXED("ckil", IMX6_CKIL_FREQ), + CLK_FIXED("ckih", IMX6_CKIH_FREQ), + CLK_FIXED("osc", IMX6_OSC_FREQ), + CLK_FIXED("anaclk1", IMX6_ANACLK1_FREQ), + CLK_FIXED("anaclk2", IMX6_ANACLK2_FREQ), + + CLK_FIXED_FACTOR("sata_ref", "pll6_enet", 5, 1), + CLK_FIXED_FACTOR("pcie_ref", "pll6_enet", 4, 1), + CLK_FIXED_FACTOR("pll2_198m", "pll2_pfd2_396m", 2, 1), + CLK_FIXED_FACTOR("pll3_120m", "pll3_usb_otg", 4, 1), + CLK_FIXED_FACTOR("pll3_80m", "pll3_usb_otg", 6, 1), + CLK_FIXED_FACTOR("pll3_60m", "pll3_usb_otg", 8, 1), + CLK_FIXED_FACTOR("twd", "arm", 2, 1), + CLK_FIXED_FACTOR("gpt_3m", "osc", 8, 1), + CLK_FIXED_FACTOR("video_27m", "pll3_pfd1_540m", 20, 1), + CLK_FIXED_FACTOR("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1), + CLK_FIXED_FACTOR("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1), + CLK_FIXED_FACTOR("ldb_di0_div_3_5", "ldb_di0_sel", 7, 2), + CLK_FIXED_FACTOR("ldb_di1_div_3_5", "ldb_di1_sel", 7, 2), + + CLK_PFD("pll2_pfd0_352m", "pll2_bus", PFD_528, 0), + CLK_PFD("pll2_pfd1_594m", "pll2_bus", PFD_528, 1), + CLK_PFD("pll2_pfd2_396m", "pll2_bus", PFD_528, 2), + CLK_PFD("pll3_pfd0_720m", "pll3_usb_otg", PFD_480, 0), + CLK_PFD("pll3_pfd1_540m", "pll3_usb_otg", PFD_480, 1), + CLK_PFD("pll3_pfd2_508m", "pll3_usb_otg", PFD_480, 2), + CLK_PFD("pll3_pfd3_454m", "pll3_usb_otg", PFD_480, 3), + + CLK_PLL("pll1", "osc", SYS, PLL_ARM, DIV_SELECT, POWERDOWN, 0), + CLK_PLL("pll2", "osc", GENNERIC, PLL_SYS, DIV_SELECT, POWERDOWN, 0), + CLK_PLL("pll3", "osc", USB, PLL_USB1, DIV_SELECT, POWER, 0), + CLK_PLL("pll4", "osc", AUDIO_VIDEO, PLL_AUDIO, DIV_SELECT, POWERDOWN, 0), + CLK_PLL("pll5", "osc", AUDIO_VIDEO, PLL_VIDEO, DIV_SELECT, POWERDOWN, 0), + CLK_PLL("pll6", "osc", ENET, PLL_ENET, DIV_SELECT, POWERDOWN, 500000000), + CLK_PLL("pll7", "osc", USB, PLL_USB2, DIV_SELECT, POWER, 0), + + CLK_DIV("periph_clk2", "periph_clk2_sel", CBCDR, PERIPH_CLK2_PODF), + CLK_DIV("periph2_clk2", "periph2_clk2_sel", CBCDR, PERIPH2_CLK2_PODF), + CLK_DIV("ipg", "ahb", CBCDR, IPG_PODF), + CLK_DIV("esai_pred", "esai_sel", CS1CDR, ESAI_CLK_PRED), + CLK_DIV("esai_podf", "esai_pred", CS1CDR, ESAI_CLK_PODF), + CLK_DIV("asrc_pred", "asrc_sel", CDCDR, SPDIF1_CLK_PRED), + CLK_DIV("asrc_podf", "asrc_pred", CDCDR, SPDIF1_CLK_PODF), + CLK_DIV("spdif_pred", "spdif_sel", CDCDR, SPDIF0_CLK_PRED), + CLK_DIV("spdif_podf", "spdif_pred", CDCDR, SPDIF0_CLK_PODF), + CLK_DIV("ecspi_root", "pll3_60m", CSCDR2, ECSPI_CLK_PODF), + CLK_DIV("can_root", "pll3_60m", CSCMR2, CAN_CLK_PODF), + CLK_DIV("uart_serial_podf", "pll3_80m", CSCDR1, UART_CLK_PODF), + CLK_DIV("gpu2d_core_podf", "gpu2d_core_sel", CBCMR, GPU2D_CORE_CLK_PODF), + CLK_DIV("gpu3d_core_podf", "gpu3d_core_sel", CBCMR, GPU3D_CORE_PODF), + CLK_DIV("gpu3d_shader", "gpu3d_shader_sel", CBCMR, GPU3D_SHADER_PODF), + CLK_DIV("ipu1_podf", "ipu1_sel", CSCDR3, IPU1_HSP_PODF), + CLK_DIV("ipu2_podf", "ipu2_sel", CSCDR3, IPU2_HSP_PODF), + CLK_DIV("ldb_di0_podf", "ldb_di0_div_3_5", CSCMR2, LDB_DI0_IPU_DIV), + CLK_DIV("ldb_di1_podf", "ldb_di1_div_3_5", CSCMR2, LDB_DI1_IPU_DIV), + CLK_DIV("ipu1_di0_pre", "ipu1_di0_pre_sel", CHSCCDR, IPU1_DI0_PODF), + CLK_DIV("ipu1_di1_pre", "ipu1_di1_pre_sel", CHSCCDR, IPU1_DI1_PODF), + CLK_DIV("ipu2_di0_pre", "ipu2_di0_pre_sel", CSCDR2, IPU2_DI0_PODF), + CLK_DIV("ipu2_di1_pre", "ipu2_di1_pre_sel", CSCDR2, IPU2_DI1_PODF), + CLK_DIV("hsi_tx_podf", "hsi_tx_sel", CDCDR, HSI_TX_PODF), + CLK_DIV("ssi1_pred", "ssi1_sel", CS1CDR, SSI1_CLK_PRED), + CLK_DIV("ssi1_podf", "ssi1_pred", CS1CDR, SSI1_CLK_PODF), + CLK_DIV("ssi2_pred", "ssi2_sel", CS2CDR, SSI2_CLK_PRED), + CLK_DIV("ssi2_podf", "ssi2_pred", CS2CDR, SSI2_CLK_PODF), + CLK_DIV("ssi3_pred", "ssi3_sel", CS1CDR, SSI3_CLK_PRED), + CLK_DIV("ssi3_podf", "ssi3_pred", CS1CDR, SSI3_CLK_PODF), + CLK_DIV("usdhc1_podf", "usdhc1_sel", CSCDR1, USDHC1_PODF), + CLK_DIV("usdhc2_podf", "usdhc2_sel", CSCDR1, USDHC2_PODF), + CLK_DIV("usdhc3_podf", "usdhc3_sel", CSCDR1, USDHC3_PODF), + CLK_DIV("usdhc4_podf", "usdhc4_sel", CSCDR1, USDHC4_PODF), + CLK_DIV("enfc_pred", "enfc_sel", CS2CDR, ENFC_CLK_PRED), + CLK_DIV("enfc_podf", "enfc_pred", CS2CDR, ENFC_CLK_PODF), + CLK_DIV("vpu_axi_podf", "vpu_axi_sel", CSCDR1, VPU_AXI_PODF), + CLK_DIV("cko1_podf", "cko1_sel", CCOSR, CLKO1_DIV), + CLK_DIV("cko2_podf", "cko2_sel", CCOSR, CLKO2_DIV), + CLK_DIV("ipg_per", "ipg", CSCMR1, PERCLK_PODF), + CLK_DIV("eim_podf", "eim_sel", CSCMR1, ACLK_PODF), + CLK_DIV("eim_slow_podf", "eim_slow_sel", CSCMR1, ACLK_EIM_SLOW_PODF), + + CLK_DIV_BUSY("axi", "axi_sel", CBCDR, AXI_PODF, CDHIPR, AXI_PODF_BUSY), + CLK_DIV_BUSY("mmdc_ch0_axi_podf", "periph", CBCDR, MMDC_CH0_AXI_PODF, CDHIPR, MMDC_CH0_PODF_BUSY), + CLK_DIV_BUSY("mmdc_ch1_axi_podf", "periph2", CBCDR, MMDC_CH1_AXI_PODF, CDHIPR, MMDC_CH1_PODF_BUSY), + CLK_DIV_BUSY("arm", "pll1_sw", CACRR, ARM_PODF, CDHIPR, ARM_PODF_BUSY), + CLK_DIV_BUSY("ahb", "periph", CBCDR, AHB_PODF, CDHIPR, AHB_PODF_BUSY), + + CLK_DIV_TABLE("pll4_post_div", "pll4_audio", PLL_AUDIO, POST_DIV_SELECT, post_div_tbl), + CLK_DIV_TABLE("pll4_audio_div", "pll4_post_div", MISC2, AUDIO_DIV_LSB, audiovideo_div_tbl), + CLK_DIV_TABLE("pll5_post_div", "pll5_video", PLL_VIDEO, POST_DIV_SELECT, post_div_tbl), + CLK_DIV_TABLE("pll5_video_div", "pll5_post_div", MISC2, VIDEO_DIV, audiovideo_div_tbl), + CLK_DIV_TABLE("enet_ref", "pll6_enet", PLL_ENET, DIV_SELECT, enet_ref_tbl), + + CLK_MUX("step", step_p, CCM, CCSR, STEP_SEL), + CLK_MUX("pll1_sw", pll1_sw_p, CCM, CCSR, PLL1_SW_CLK_SEL), + CLK_MUX("periph_pre", periph_pre_p, CCM, CBCMR, PRE_PERIPH_CLK_SEL), + CLK_MUX("periph2_pre", periph_pre_p, CCM, CBCMR, PRE_PERIPH2_CLK_SEL), + CLK_MUX("periph_clk2_sel", periph_clk2_p, CCM,CBCMR, PERIPH_CLK2_SEL), + CLK_MUX("periph2_clk2_sel", periph2_clk2_p, CCM,CBCMR, PERIPH2_CLK2_SEL), + CLK_MUX("axi_sel", axi_p, CCM, CBCDR, AXI_SEL), + CLK_MUX("asrc_sel", audio_p, CCM, CDCDR, SPDIF1_CLK_SEL), + CLK_MUX("spdif_sel", audio_p, CCM, CDCDR, SPDIF0_CLK_SEL), + CLK_MUX("gpu2d_core_sel", gpu2d_core_p, CCM, CBCMR, GPU2D_CLK_SEL), + CLK_MUX("gpu3d_core_sel", gpu3d_core_p, CCM, CBCMR, GPU3D_CORE_CLK_SEL), + CLK_MUX("gpu3d_shader_sel", gpu3d_shader_p, CCM,CBCMR, GPU3D_SHADER_CLK_SEL), + CLK_MUX("esai_sel", audio_p, CCM, CSCMR2, ESAI_CLK_SEL), + CLK_MUX("ipu1_sel", ipu_p, CCM, CSCDR3, IPU1_HSP_CLK_SEL), + CLK_MUX("ipu2_sel", ipu_p, CCM, CSCDR3, IPU2_HSP_CLK_SEL), + CLK_MUX("ipu1_di0_pre_sel", ipu_di_pre_p, CCM, CHSCCDR, IPU1_DI0_PRE_CLK_SEL), + CLK_MUX("ipu1_di1_pre_sel", ipu_di_pre_p, CCM, CHSCCDR, IPU1_DI1_PRE_CLK_SEL), + CLK_MUX("ipu2_di0_pre_sel", ipu_di_pre_p, CCM, CSCDR2, IPU2_DI0_PRE_CLK_SEL), + CLK_MUX("ipu2_di1_pre_sel", ipu_di_pre_p, CCM, CSCDR2, IPU2_DI1_PRE_CLK_SEL), + CLK_MUX("ipu1_di0_sel", ipu1_di0_p, CCM, CHSCCDR, IPU1_DI0_CLK_SEL), + CLK_MUX("ipu1_di1_sel", ipu1_di1_p, CCM, CHSCCDR, IPU1_DI1_CLK_SEL), + CLK_MUX("ipu2_di0_sel", ipu2_di0_p, CCM, CSCDR2, IPU2_DI0_CLK_SEL), + CLK_MUX("ipu2_di1_sel", ipu2_di1_p, CCM, CSCDR2, IPU2_DI1_CLK_SEL), + CLK_MUX("ldb_di0_sel", ldb_di_p, CCM, CS2CDR, LDB_DI0_CLK_SEL), + CLK_MUX("ldb_di1_sel", ldb_di_p, CCM, CS2CDR, LDB_DI1_CLK_SEL), + CLK_MUX("vdo_axi_sel", vdo_axi_p, CCM, CBCMR, VDOAXI_CLK_SEL), + CLK_MUX("vpu_axi_sel", vpu_axi_p, CCM, CBCMR, VPU_AXI_CLK_SEL), + CLK_MUX("cko1_sel", cko1_p, CCM, CCOSR, CLKO1_SEL), + CLK_MUX("cko2_sel", cko2_p, CCM, CCOSR, CLKO2_SEL), + CLK_MUX("cko", cko_p, CCM, CCOSR, CLK_OUT_SEL), + CLK_MUX("hsi_tx_sel", hsi_tx_p, CCM, CDCDR, HSI_TX_CLK_SEL), + CLK_MUX("pcie_axi_sel", pcie_axi_p, CCM, CBCMR, PCIE_AXI_CLK_SEL), + CLK_MUX("ssi1_sel", ssi_p, CCM, CSCMR1, SSI1_CLK_SEL), + CLK_MUX("ssi2_sel", ssi_p, CCM, CSCMR1, SSI2_CLK_SEL), + CLK_MUX("ssi3_sel", ssi_p, CCM, CSCMR1, SSI3_CLK_SEL), + CLK_MUX("usdhc1_sel", usdhc_p, CCM, CSCMR1, USDHC1_CLK_SEL), + CLK_MUX("usdhc2_sel", usdhc_p, CCM, CSCMR1, USDHC2_CLK_SEL), + CLK_MUX("usdhc3_sel", usdhc_p, CCM, CSCMR1, USDHC3_CLK_SEL), + CLK_MUX("usdhc4_sel", usdhc_p, CCM, CSCMR1, USDHC4_CLK_SEL), + CLK_MUX("eim_sel", eim_p, CCM, CSCMR1, ACLK_SEL), + CLK_MUX("eim_slow_sel", eim_slow_p, CCM, CSCMR1, ACLK_EIM_SLOW_SEL), + CLK_MUX("enfc_sel", enfc_p, CCM, CS2CDR, ENFC_CLK_SEL), + + CLK_MUX("pll1_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_ARM, BYPASS_CLK_SRC), + CLK_MUX("pll2_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_SYS, BYPASS_CLK_SRC), + CLK_MUX("pll3_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_USB1, BYPASS_CLK_SRC), + CLK_MUX("pll4_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_AUDIO, BYPASS_CLK_SRC), + CLK_MUX("pll5_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_VIDEO, BYPASS_CLK_SRC), + CLK_MUX("pll6_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_ENET, BYPASS_CLK_SRC), + CLK_MUX("pll7_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_USB2, BYPASS_CLK_SRC), + CLK_MUX("pll1_bypass", pll1_bypass_p, CCM_ANALOG, PLL_ARM, BYPASS), + CLK_MUX("pll2_bypass", pll2_bypass_p, CCM_ANALOG, PLL_SYS, BYPASS), + CLK_MUX("pll3_bypass", pll3_bypass_p, CCM_ANALOG, PLL_USB1, BYPASS), + CLK_MUX("pll4_bypass", pll4_bypass_p, CCM_ANALOG, PLL_AUDIO, BYPASS), + CLK_MUX("pll5_bypass", pll5_bypass_p, CCM_ANALOG, PLL_VIDEO, BYPASS), + CLK_MUX("pll6_bypass", pll6_bypass_p, CCM_ANALOG, PLL_ENET, BYPASS), + CLK_MUX("pll7_bypass", pll7_bypass_p, CCM_ANALOG, PLL_USB2, BYPASS), + + CLK_MUX("lvds1_sel", lvds_p, CCM_ANALOG, MISC1, LVDS_CLK1_SRC), + CLK_MUX("lvds2_sel", lvds_p, CCM_ANALOG, MISC1, LVDS_CLK2_SRC), + + CLK_MUX_BUSY("periph", periph_p, CBCDR, PERIPH_CLK_SEL, CDHIPR, PERIPH_CLK_SEL_BUSY), + CLK_MUX_BUSY("periph2", periph2_p, CBCDR, PERIPH2_CLK_SEL, CDHIPR, PERIPH2_CLK_SEL_BUSY), + + CLK_GATE("apbh_dma", "usdhc3", CCM, CCGR0, APBHDMA_HCLK_ENABLE), + CLK_GATE("asrc", "asrc_podf", CCM, CCGR0, ASRC_CLK_ENABLE), + CLK_GATE("asrc_ipg", "ahb", CCM, CCGR0, ASRC_CLK_ENABLE), + CLK_GATE("asrc_mem", "ahb", CCM, CCGR0, ASRC_CLK_ENABLE), + CLK_GATE("caam_mem", "ahb", CCM, CCGR0, CAAM_SECURE_MEM_CLK_ENABLE), + CLK_GATE("caam_aclk", "ahb", CCM, CCGR0, CAAM_WRAPPER_ACLK_ENABLE), + CLK_GATE("caam_ipg", "ipg", CCM, CCGR0, CAAM_WRAPPER_IPG_ENABLE), + CLK_GATE("can1_ipg", "ipg", CCM, CCGR0, CAN1_CLK_ENABLE), + CLK_GATE("can1_serial", "can_root", CCM, CCGR0, CAN1_SERIAL_CLK_ENABLE), + CLK_GATE("can2_ipg", "ipg", CCM, CCGR0, CAN2_CLK_ENABLE), + CLK_GATE("can2_serial", "can_root", CCM, CCGR0, CAN2_SERIAL_CLK_ENABLE), + CLK_GATE("ecspi1", "ecspi_root", CCM, CCGR1, ECSPI1_CLK_ENABLE), + CLK_GATE("ecspi2", "ecspi_root", CCM, CCGR1, ECSPI2_CLK_ENABLE), + CLK_GATE("ecspi3", "ecspi_root", CCM, CCGR1, ECSPI3_CLK_ENABLE), + CLK_GATE("ecspi4", "ecspi_root", CCM, CCGR1, ECSPI4_CLK_ENABLE), + CLK_GATE("ecspi5", "ecspi_root", CCM, CCGR1, ECSPI5_CLK_ENABLE), + CLK_GATE("enet", "ipg", CCM, CCGR1, ENET_CLK_ENABLE), + CLK_GATE("esai_extal", "esai_podf", CCM, CCGR1, ESAI_CLK_ENABLE), + CLK_GATE("esai_ipg", "ahb", CCM, CCGR1, ESAI_CLK_ENABLE), + CLK_GATE("esai_mem", "ahb", CCM, CCGR1, ESAI_CLK_ENABLE), + CLK_GATE("gpt_ipg", "ipg", CCM, CCGR1, GPT_CLK_ENABLE), + CLK_GATE("gpt_ipg_per", "ipg_per", CCM, CCGR1, GPT_SERIAL_CLK_ENABLE), + CLK_GATE("gpu2d_core", "gpu2d_core_podf", CCM, CCGR1, GPU2D_CLK_ENABLE), + CLK_GATE("gpu3d_core", "gpu3d_core_podf", CCM, CCGR1, GPU3D_CLK_ENABLE), + CLK_GATE("hdmi_iahb", "ahb", CCM, CCGR2, HDMI_TX_IAHBCLK_ENABLE), + CLK_GATE("hdmi_isfr", "video_27m", CCM, CCGR2, HDMI_TX_ISFRCLK_ENABLE), + CLK_GATE("i2c1", "ipg_per", CCM, CCGR2, I2C1_SERIAL_CLK_ENABLE), + CLK_GATE("i2c2", "ipg_per", CCM, CCGR2, I2C2_SERIAL_CLK_ENABLE), + CLK_GATE("i2c3", "ipg_per", CCM, CCGR2, I2C3_SERIAL_CLK_ENABLE), + CLK_GATE("iim", "ipg", CCM, CCGR2, IIM_CLK_ENABLE), + CLK_GATE("enfc", "enfc_podf", CCM, CCGR2, IOMUX_IPT_CLK_IO_CLK_ENABLE), + CLK_GATE("vdoa", "vdo_axi", CCM, CCGR2, IPSYNC_VDOA_IPG_CLK_ENABLE), + CLK_GATE("ipu1", "ipu1_podf", CCM, CCGR3, IPU1_IPU_CLK_ENABLE), + CLK_GATE("ipu1_di0", "ipu1_di0_sel", CCM, CCGR3, IPU1_IPU_DI0_CLK_ENABLE), + CLK_GATE("ipu1_di1", "ipu1_di1_sel", CCM, CCGR3, IPU1_IPU_DI1_CLK_ENABLE), + CLK_GATE("ipu2", "ipu2_podf", CCM, CCGR3, IPU2_IPU_CLK_ENABLE), + CLK_GATE("ipu2_di0", "ipu2_di0_sel", CCM, CCGR3, IPU2_IPU_DI0_CLK_ENABLE), + CLK_GATE("ldb_di0", "ldb_di0_podf", CCM, CCGR3, LDB_DI0_CLK_ENABLE), + CLK_GATE("ldb_di1", "ldb_di1_podf", CCM, CCGR3, LDB_DI1_CLK_ENABLE), + CLK_GATE("ipu2_di1", "ipu2_di1_sel", CCM, CCGR3, IPU2_IPU_DI1_CLK_ENABLE), + CLK_GATE("hsi_tx", "hsi_tx_podf", CCM, CCGR3, MIPI_CORE_CFG_CLK_ENABLE), + CLK_GATE("mipi_core_cfg", "video_27m", CCM, CCGR3, MIPI_CORE_CFG_CLK_ENABLE), + CLK_GATE("mipi_ipg", "ipg", CCM, CCGR3, MIPI_CORE_CFG_CLK_ENABLE), + CLK_GATE("mlb", "axi", CCM, CCGR3, MLB_CLK_ENABLE), + CLK_GATE("mmdc_ch0_axi", "mmdc_ch0_axi_podf", CCM, CCGR3, MMDC_CORE_ACLK_FAST_CORE_P0_ENABLE), + CLK_GATE("mmdc_ch1_axi", "mmdc_ch1_axi_podf", CCM, CCGR3, MMDC_CORE_ACLK_FAST_CORE_P1_ENABLE), + CLK_GATE("ocram", "ahb", CCM, CCGR3, OCRAM_CLK_ENABLE), + CLK_GATE("openvg_axi", "axi", CCM, CCGR3, OPENVGAXICLK_CLK_ROOT_ENABLE), + CLK_GATE("pcie_axi", "pcie_axi_sel", CCM, CCGR4, PCIE_ROOT_ENABLE), + CLK_GATE("per1_bch", "usdhc3", CCM, CCGR4, PL301_MX6QPER1_BCHCLK_ENABLE), + CLK_GATE("pwm1", "ipg_per", CCM, CCGR4, PWM1_CLK_ENABLE), + CLK_GATE("pwm2", "ipg_per", CCM, CCGR4, PWM2_CLK_ENABLE), + CLK_GATE("pwm3", "ipg_per", CCM, CCGR4, PWM3_CLK_ENABLE), + CLK_GATE("pwm4", "ipg_per", CCM, CCGR4, PWM4_CLK_ENABLE), + CLK_GATE("gpmi_bch_apb", "usdhc3", CCM, CCGR4, RAWNAND_U_BCH_INPUT_APB_CLK_ENABLE), + CLK_GATE("gpmi_bch", "usdhc4", CCM, CCGR4, RAWNAND_U_GPMI_BCH_INPUT_BCH_CLK_ENABLE), + CLK_GATE("gpmi_io", "enfc", CCM, CCGR4, RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_CLK_ENABLE), + CLK_GATE("gpmi_apb", "usdhc3", CCM, CCGR4, RAWNAND_U_GPMI_INPUT_APB_CLK_ENABLE), + CLK_GATE("rom", "ahb", CCM, CCGR5, ROM_CLK_ENABLE), + CLK_GATE("sata", "ahb", CCM, CCGR5, SATA_CLK_ENABLE), + CLK_GATE("sdma", "ahb", CCM, CCGR5, SDMA_CLK_ENABLE), + CLK_GATE("spba", "ipg", CCM, CCGR5, SPBA_CLK_ENABLE), + CLK_GATE("spdif", "spdif_podf", CCM, CCGR5, SPDIF_CLK_ENABLE), + CLK_GATE("spdif_gclk", "ipg", CCM, CCGR5, SPDIF_CLK_ENABLE), + CLK_GATE("ssi1_ipg", "ipg", CCM, CCGR5, SSI1_CLK_ENABLE), + CLK_GATE("ssi2_ipg", "ipg", CCM, CCGR5, SSI2_CLK_ENABLE), + CLK_GATE("ssi3_ipg", "ipg", CCM, CCGR5, SSI3_CLK_ENABLE), + CLK_GATE("ssi1", "ssi1_podf", CCM, CCGR5, SSI1_CLK_ENABLE), + CLK_GATE("ssi2", "ssi2_podf", CCM, CCGR5, SSI2_CLK_ENABLE), + CLK_GATE("ssi3", "ssi3_podf", CCM, CCGR5, SSI3_CLK_ENABLE), + CLK_GATE("uart_ipg", "ipg", CCM, CCGR5, UART_CLK_ENABLE), + CLK_GATE("uart_serial", "uart_serial_podf", CCM, CCGR5, UART_SERIAL_CLK_ENABLE), + CLK_GATE("usboh3", "ipg", CCM, CCGR6, USBOH3_CLK_ENABLE), + CLK_GATE("usdhc1", "usdhc1_podf", CCM, CCGR6, USDHC1_CLK_ENABLE), + CLK_GATE("usdhc2", "usdhc2_podf", CCM, CCGR6, USDHC2_CLK_ENABLE), + CLK_GATE("usdhc3", "usdhc3_podf", CCM, CCGR6, USDHC3_CLK_ENABLE), + CLK_GATE("usdhc4", "usdhc4_podf", CCM, CCGR6, USDHC4_CLK_ENABLE), + CLK_GATE("eim_slow", "eim_slow_podf", CCM, CCGR6, EIM_SLOW_CLK_ENABLE), + CLK_GATE("vdo_axi", "vdo_axi_sel", CCM, CCGR6, VDOAXICLK_CLK_ENABLE), + CLK_GATE("vpu_axi", "vpu_axi_podf", CCM, CCGR6, VPU_CLK_ENABLE), + CLK_GATE("cko1", "cko1_podf", CCM, CCOSR, CLKO1_EN), + CLK_GATE("cko2", "cko2_podf", CCM, CCOSR, CLKO2_EN), + + CLK_GATE("sata_ref_100m", "sata_ref", CCM_ANALOG, PLL_ENET, ENABLE_100M), + CLK_GATE("pcie_ref_125m", "pcie_ref", CCM_ANALOG, PLL_ENET, ENABLE_125M), + + CLK_GATE("pll1_sys", "pll1_bypass", CCM_ANALOG, PLL_ARM, ENABLE), + CLK_GATE("pll2_bus", "pll2_bypass", CCM_ANALOG, PLL_SYS, ENABLE), + CLK_GATE("pll3_usb_otg", "pll3_bypass", CCM_ANALOG, PLL_USB1, ENABLE), + CLK_GATE("pll4_audio", "pll4_bypass", CCM_ANALOG, PLL_AUDIO, ENABLE), + CLK_GATE("pll5_video", "pll5_bypass", CCM_ANALOG, PLL_VIDEO, ENABLE), + CLK_GATE("pll6_enet", "pll6_bypass", CCM_ANALOG, PLL_ENET, ENABLE), + CLK_GATE("pll7_usb_host", "pll7_bypass", CCM_ANALOG, PLL_USB2, ENABLE), + + CLK_GATE("usbphy1", "pll3_usb_otg", CCM_ANALOG, PLL_USB1, RESERVED), + CLK_GATE("usbphy2", "pll7_usb_host", CCM_ANALOG, PLL_USB2, RESERVED), + + CLK_GATE_EXCLUSIVE("lvds1_gate", "lvds1_sel", CCM_ANALOG, MISC1, LVDS_CLK1_OBEN, LVDS_CLK1_IBEN), + CLK_GATE_EXCLUSIVE("lvds2_gate", "lvds2_sel", CCM_ANALOG, MISC1, LVDS_CLK2_OBEN, LVDS_CLK2_IBEN), +}; + +static struct imx6_clk *imx6_clk_find(const char *); + +static void imxccm_init_clocks(struct imxccm_softc *); +static struct clk *imxccm_clk_get(void *, const char *); +static void imxccm_clk_put(void *, struct clk *); +static u_int imxccm_clk_get_rate(void *, struct clk *); +static int imxccm_clk_set_rate(void *, struct clk *, u_int); +static int imxccm_clk_enable(void *, struct clk *); +static int imxccm_clk_disable(void *, struct clk *); +static int imxccm_clk_set_parent(void *, struct clk *, struct clk *); +static struct clk *imxccm_clk_get_parent(void *, struct clk *); + +static const struct clk_funcs imxccm_clk_funcs = { + .get = imxccm_clk_get, + .put = imxccm_clk_put, + .get_rate = imxccm_clk_get_rate, + .set_rate = imxccm_clk_set_rate, + .enable = imxccm_clk_enable, + .disable = imxccm_clk_disable, + .set_parent = imxccm_clk_set_parent, + .get_parent = imxccm_clk_get_parent, +}; static int imxccm_match(device_t, cfdata_t, void *); static void imxccm_attach(device_t, device_t, void *); -static int imxccm_sysctl_freq_helper(SYSCTLFN_PROTO); -static int imxccm_sysctl_setup(struct imxccm_softc *); - CFATTACH_DECL_NEW(imxccm, sizeof(struct imxccm_softc), imxccm_match, imxccm_attach, NULL, NULL); @@ -98,9 +667,6 @@ imxccm_match(device_t parent, cfdata_t c { struct axi_attach_args *aa = aux; - if (ccm_softc != NULL) - return 0; - if (aa->aa_addr == IMX6_AIPS1_BASE + AIPS1_CCM_BASE) return 1; @@ -114,10 +680,8 @@ imxccm_attach(device_t parent, device_t struct axi_attach_args *aa = aux; bus_space_tag_t iot = aa->aa_iot; - ccm_softc = sc; sc->sc_dev = self; sc->sc_iot = iot; - sc->sc_log = NULL; if (bus_space_map(iot, aa->aa_addr, AIPS1_CCM_SIZE, 0, &sc->sc_ioh)) { aprint_error(": can't map CCM registers\n"); @@ -131,817 +695,571 @@ imxccm_attach(device_t parent, device_t return; } - aprint_normal(": Clock Control Module\n"); aprint_naive("\n"); + aprint_normal(": Clock Control Module\n"); + + sc->sc_clkdom.name = device_xname(self); + sc->sc_clkdom.funcs = &imxccm_clk_funcs; + sc->sc_clkdom.priv = sc; + for (u_int n = 0; n < __arraycount(imx6_clks); n++) { + imx6_clks[n].base.domain = &sc->sc_clkdom; + clk_attach(&imx6_clks[n].base); + } - imxccm_sysctl_setup(sc); + imxccm_init_clocks(sc); - aprint_verbose_dev(self, "PLL_ARM clock=%d\n", - imx6_get_clock(IMX6CLK_PLL1)); - aprint_verbose_dev(self, "PLL_SYS clock=%d\n", - imx6_get_clock(IMX6CLK_PLL2)); - aprint_verbose_dev(self, "PLL_USB1 clock=%d\n", - imx6_get_clock(IMX6CLK_PLL3)); - aprint_verbose_dev(self, "PLL_USB2 clock=%d\n", - imx6_get_clock(IMX6CLK_PLL7)); - aprint_verbose_dev(self, "PLL_AUDIO clock=%d\n", - imx6_get_clock(IMX6CLK_PLL4)); - aprint_verbose_dev(self, "PLL_VIDEO clock=%d\n", - imx6_get_clock(IMX6CLK_PLL5)); - aprint_verbose_dev(self, "PLL_ENET clock=%d\n", - imx6_get_clock(IMX6CLK_PLL6)); - aprint_verbose_dev(self, "PLL_MLB clock=%d\n", - imx6_get_clock(IMX6CLK_PLL7)); - - aprint_verbose_dev(self, "IMX6CLK_PLL2_PFD0=%d\n", - imx6_get_clock(IMX6CLK_PLL2_PFD0)); - aprint_verbose_dev(self, "IMX6CLK_PLL2_PFD1=%d\n", - imx6_get_clock(IMX6CLK_PLL2_PFD1)); - aprint_verbose_dev(self, "IMX6CLK_PLL2_PFD2=%d\n", - imx6_get_clock(IMX6CLK_PLL2_PFD2)); - aprint_verbose_dev(self, "IMX6CLK_PLL3_PFD0=%d\n", - imx6_get_clock(IMX6CLK_PLL3_PFD0)); - aprint_verbose_dev(self, "IMX6CLK_PLL3_PFD1=%d\n", - imx6_get_clock(IMX6CLK_PLL3_PFD1)); - aprint_verbose_dev(self, "IMX6CLK_PLL3_PFD2=%d\n", - imx6_get_clock(IMX6CLK_PLL3_PFD2)); - aprint_verbose_dev(self, "IMX6CLK_PLL3_PFD3=%d\n", - imx6_get_clock(IMX6CLK_PLL3_PFD3)); - aprint_verbose_dev(self, "IMX6CLK_ARM_ROOT=%d\n", - imx6_get_clock(IMX6CLK_ARM_ROOT)); - aprint_verbose_dev(self, "IMX6CLK_PERIPH=%d\n", - imx6_get_clock(IMX6CLK_PERIPH)); - aprint_verbose_dev(self, "IMX6CLK_AHB=%d\n", - imx6_get_clock(IMX6CLK_AHB)); - aprint_verbose_dev(self, "IMX6CLK_IPG=%d\n", - imx6_get_clock(IMX6CLK_IPG)); - aprint_verbose_dev(self, "IMX6CLK_AXI=%d\n", - imx6_get_clock(IMX6CLK_AXI)); - - aprint_verbose_dev(self, "IMX6CLK_USDHC1=%d\n", - imx6_get_clock(IMX6CLK_USDHC1)); - aprint_verbose_dev(self, "IMX6CLK_USDHC2=%d\n", - imx6_get_clock(IMX6CLK_USDHC2)); - aprint_verbose_dev(self, "IMX6CLK_USDHC3=%d\n", - imx6_get_clock(IMX6CLK_USDHC3)); - aprint_verbose_dev(self, "IMX6CLK_USDHC4=%d\n", - imx6_get_clock(IMX6CLK_USDHC4)); + for (int n = 0; n < __arraycount(imx6_clks); n++) { + struct clk *clk = &imx6_clks[n].base; + struct clk *clk_parent = clk_get_parent(clk); + const char *parent_str = clk_parent ? clk_parent->name : "none"; + aprint_verbose_dev(self, "%s (%s): %u Hz\n", clk->name, + parent_str, clk_get_rate(clk)); + } } -static int -imxccm_sysctl_setup(struct imxccm_softc *sc) +struct clk * +imx6_get_clock(const char *name) { - const struct sysctlnode *node, *imxnode, *freqnode, *pllnode; - int rv; + struct imx6_clk *iclk; + iclk = imx6_clk_find(name); - rv = sysctl_createv(&sc->sc_log, 0, NULL, &node, - CTLFLAG_PERMANENT, CTLTYPE_NODE, - "machdep", NULL, - NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL); - if (rv != 0) - goto fail; - - rv = sysctl_createv(&sc->sc_log, 0, &node, &imxnode, - 0, CTLTYPE_NODE, - "imx6", NULL, - NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - - rv = sysctl_createv(&sc->sc_log, 0, &imxnode, &freqnode, - 0, CTLTYPE_NODE, - "frequency", NULL, - NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - - rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &pllnode, - 0, CTLTYPE_NODE, - "pll", NULL, - NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - - rv = sysctl_createv(&sc->sc_log, 0, &pllnode, &node, - CTLFLAG_READWRITE, CTLTYPE_INT, - "arm", SYSCTL_DESCR("frequency of ARM clock (PLL1)"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_pll1_arm= node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &pllnode, &node, - 0, CTLTYPE_INT, - "system", SYSCTL_DESCR("frequency of system clock (PLL2)"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_pll2_sys = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &pllnode, &node, - 0, CTLTYPE_INT, - "usb1", SYSCTL_DESCR("frequency of USB1 clock (PLL3)"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_pll3_usb1 = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &pllnode, &node, - 0, CTLTYPE_INT, - "usb2", SYSCTL_DESCR("frequency of USB2 clock (PLL7)"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_pll7_usb2 = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &pllnode, &node, - 0, CTLTYPE_INT, - "audio", SYSCTL_DESCR("frequency of AUDIO clock (PLL4)"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_pll4_audio = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &pllnode, &node, - 0, CTLTYPE_INT, - "video", SYSCTL_DESCR("frequency of VIDEO clock (PLL5)"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_pll5_video = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &pllnode, &node, - 0, CTLTYPE_INT, - "enet", SYSCTL_DESCR("frequency of ENET clock (PLL6)"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_pll6_enet = node->sysctl_num; - -#if 0 - rv = sysctl_createv(&sc->sc_log, 0, &pllnode, &node, - 0, CTLTYPE_INT, - "mlb", SYSCTL_DESCR("frequency of MediaLinkBus clock (PLL8)"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_pll8_mlb = node->sysctl_num; -#endif + if (iclk == NULL) + return NULL; - rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node, - CTLFLAG_READWRITE, CTLTYPE_INT, - "arm", SYSCTL_DESCR("frequency of ARM Root clock"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_arm = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node, - 0, CTLTYPE_INT, - "peripheral", SYSCTL_DESCR("current frequency of Peripheral clock"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_periph = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node, - 0, CTLTYPE_INT, - "ahb", SYSCTL_DESCR("current frequency of AHB clock"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_ahb = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node, - 0, CTLTYPE_INT, - "ipg", SYSCTL_DESCR("current frequency of IPG clock"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_ipg = node->sysctl_num; - - rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node, - 0, CTLTYPE_INT, - "axi", SYSCTL_DESCR("current frequency of AXI clock"), - imxccm_sysctl_freq_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); - if (rv != 0) - goto fail; - sc->sc_sysctlnode_axi = node->sysctl_num; + return &iclk->base; +} - return 0; +static struct imx6_clk * +imx6_clk_find(const char *name) +{ + if (name == NULL) + return NULL; + + for (int n = 0; n < __arraycount(imx6_clks); n++) { + if (strcmp(imx6_clks[n].base.name, name) == 0) + return &imx6_clks[n]; + } + + return NULL; +} - fail: - aprint_error_dev(sc->sc_dev, "cannot initialize sysctl (err=%d)\n", rv); +struct imxccm_init_parent { + const char *clock; + const char *parent; +} imxccm_init_parents[] = { + { "pll1_bypass", "pll1" }, + { "pll2_bypass", "pll2" }, + { "pll3_bypass", "pll3" }, + { "pll4_bypass", "pll4" }, + { "pll5_bypass", "pll5" }, + { "pll6_bypass", "pll6" }, + { "pll7_bypass", "pll7" }, + { "lvds1_sel", "sata_ref_100m" }, +}; - sysctl_teardown(&sc->sc_log); - sc->sc_log = NULL; +static void +imxccm_init_clocks(struct imxccm_softc *sc) +{ + struct clk *clk; + struct clk *clk_parent; - return -1; + for (u_int n = 0; n < __arraycount(imxccm_init_parents); n++) { + clk = clk_get(&sc->sc_clkdom, imxccm_init_parents[n].clock); + KASSERT(clk != NULL); + clk_parent = clk_get(&sc->sc_clkdom, imxccm_init_parents[n].parent); + KASSERT(clk_parent != NULL); + + int error = clk_set_parent(clk, clk_parent); + if (error) { + aprint_error_dev(sc->sc_dev, + "couldn't set '%s' parent to '%s': %d\n", + clk->name, clk_parent->name, error); + } + clk_put(clk_parent); + clk_put(clk); + } } -static int -imxccm_sysctl_freq_helper(SYSCTLFN_ARGS) +static u_int +imxccm_clk_get_rate_pll_generic(struct imxccm_softc *sc, struct imx6_clk *iclk, + const u_int rate_parent) { - struct sysctlnode node; - struct imxccm_softc *sc; - int value, ovalue, err; - - node = *rnode; - sc = node.sysctl_data; - - /* for sysctl read */ - if (rnode->sysctl_num == sc->sc_sysctlnode_pll1_arm) - value = imx6_get_clock(IMX6CLK_PLL1); - else if (rnode->sysctl_num == sc->sc_sysctlnode_pll2_sys) - value = imx6_get_clock(IMX6CLK_PLL2); - else if (rnode->sysctl_num == sc->sc_sysctlnode_pll3_usb1) - value = imx6_get_clock(IMX6CLK_PLL3); - else if (rnode->sysctl_num == sc->sc_sysctlnode_pll7_usb2) - value = imx6_get_clock(IMX6CLK_PLL7); - else if (rnode->sysctl_num == sc->sc_sysctlnode_pll4_audio) - value = imx6_get_clock(IMX6CLK_PLL4); - else if (rnode->sysctl_num == sc->sc_sysctlnode_pll5_video) - value = imx6_get_clock(IMX6CLK_PLL5); - else if (rnode->sysctl_num == sc->sc_sysctlnode_pll6_enet) - value = imx6_get_clock(IMX6CLK_PLL6); -#if 0 - else if (rnode->sysctl_num == sc->sc_sysctlnode_pll8_mlb) - value = imx6_get_clock(IMX6CLK_PLL8); -#endif - else if (rnode->sysctl_num == sc->sc_sysctlnode_arm) - value = imx6_get_clock(IMX6CLK_ARM_ROOT); - else if (rnode->sysctl_num == sc->sc_sysctlnode_periph) - value = imx6_get_clock(IMX6CLK_PERIPH); - else if (rnode->sysctl_num == sc->sc_sysctlnode_ipg) - value = imx6_get_clock(IMX6CLK_IPG); - else if (rnode->sysctl_num == sc->sc_sysctlnode_axi) - value = imx6_get_clock(IMX6CLK_AXI); - else - return EOPNOTSUPP; + struct imx6_clk_pll *pll = &iclk->clk.pll; -#ifdef SYSCTL_BY_MHZ - value /= 1000 * 1000; /* Hz -> MHz */ -#endif - ovalue = value; + KASSERT((pll->type == IMX6_CLK_PLL_GENNERIC) || + (pll->type == IMX6_CLK_PLL_USB)); - node.sysctl_data = &value; - err = sysctl_lookup(SYSCTLFN_CALL(&node)); - if (err != 0 || newp == NULL) - return err; + uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, pll->reg); + uint32_t div = __SHIFTOUT(v, pll->mask); - /* for sysctl write */ - if (value == ovalue) - return 0; + return rate_parent * ((div == 1) ? 22 : 20); +} -#ifdef SYSCTL_BY_MHZ - value *= 1000 * 1000; /* MHz -> Hz */ -#endif +static u_int +imxccm_clk_get_rate_pll_sys(struct imxccm_softc *sc, struct imx6_clk *iclk, + const u_int rate_parent) +{ + struct imx6_clk_pll *pll = &iclk->clk.pll; - if (rnode->sysctl_num == sc->sc_sysctlnode_arm) - return imx6_set_clock(IMX6CLK_ARM_ROOT, value); + KASSERT(pll->type == IMX6_CLK_PLL_SYS); - return 0; + uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, pll->reg); + uint32_t div = __SHIFTOUT(v, pll->mask); + + return rate_parent * div / 2; } +#define PLL_AUDIO_VIDEO_NUM_OFFSET 0x10 +#define PLL_AUDIO_VIDEO_DENOM_OFFSET 0x20 -uint32_t -imx6_ccm_read(uint32_t reg) +static u_int +imxccm_clk_get_rate_pll_audio_video(struct imxccm_softc *sc, + struct imx6_clk *iclk, const u_int rate_parent) { - if (ccm_softc == NULL) - return 0; + struct imx6_clk_pll *pll = &iclk->clk.pll; + uint64_t freq; + + KASSERT(pll->type == IMX6_CLK_PLL_AUDIO_VIDEO); + + uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, pll->reg); + uint32_t div = __SHIFTOUT(v, pll->mask); + uint32_t num = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, + pll->reg + PLL_AUDIO_VIDEO_NUM_OFFSET); + uint32_t denom = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, + pll->reg + PLL_AUDIO_VIDEO_DENOM_OFFSET); + + uint64_t tmp = rate_parent * num / denom; + freq = (uint64_t)rate_parent * div + tmp; - return bus_space_read_4(ccm_softc->sc_iot, ccm_softc->sc_ioh, reg); + return freq; } -void -imx6_ccm_write(uint32_t reg, uint32_t val) +static u_int +imxccm_clk_get_rate_pll_enet(struct imxccm_softc *sc, + struct imx6_clk *iclk, const u_int rate_parent) { - if (ccm_softc == NULL) - return; + struct imx6_clk_pll *pll = &iclk->clk.pll; - bus_space_write_4(ccm_softc->sc_iot, ccm_softc->sc_ioh, reg, val); -} + KASSERT(pll->type == IMX6_CLK_PLL_ENET); + return pll->ref; +} -uint32_t -imx6_ccm_analog_read(uint32_t reg) +static u_int +imxccm_clk_get_rate_fixed_factor(struct imxccm_softc *sc, struct imx6_clk *iclk) { - if (ccm_softc == NULL) - return 0; + struct imx6_clk_fixed_factor *fixed_factor = &iclk->clk.fixed_factor; + struct imx6_clk *parent; - return bus_space_read_4(ccm_softc->sc_iot, ccm_softc->sc_ioh_analog, - reg); + KASSERT(iclk->type == IMX6_CLK_FIXED_FACTOR); + + parent = imx6_clk_find(iclk->parent); + KASSERT(parent != NULL); + + const u_int rate_parent = imxccm_clk_get_rate(sc, &parent->base); + + return rate_parent * fixed_factor->mult / fixed_factor->div; } -void -imx6_ccm_analog_write(uint32_t reg, uint32_t val) +static u_int +imxccm_clk_get_rate_pll(struct imxccm_softc *sc, struct imx6_clk *iclk) { - if (ccm_softc == NULL) - return; + struct imx6_clk_pll *pll = &iclk->clk.pll; + struct imx6_clk *parent; + + KASSERT(iclk->type == IMX6_CLK_PLL); - bus_space_write_4(ccm_softc->sc_iot, ccm_softc->sc_ioh_analog, reg, - val); + parent = imx6_clk_find(iclk->parent); + KASSERT(parent != NULL); + + const u_int rate_parent = imxccm_clk_get_rate(sc, &parent->base); + + switch(pll->type) { + case IMX6_CLK_PLL_GENNERIC: + return imxccm_clk_get_rate_pll_generic(sc, iclk, rate_parent); + case IMX6_CLK_PLL_SYS: + return imxccm_clk_get_rate_pll_sys(sc, iclk, rate_parent); + case IMX6_CLK_PLL_USB: + return imxccm_clk_get_rate_pll_generic(sc, iclk, rate_parent); + case IMX6_CLK_PLL_AUDIO_VIDEO: + return imxccm_clk_get_rate_pll_audio_video(sc, iclk, rate_parent); + case IMX6_CLK_PLL_ENET: + return imxccm_clk_get_rate_pll_enet(sc, iclk, rate_parent); + default: + panic("imx6: unknown pll type %d", iclk->type); + } } -int -imx6_set_clock(enum imx6_clock_id clk, uint32_t freq) +static u_int +imxccm_clk_get_rate_div(struct imxccm_softc *sc, struct imx6_clk *iclk) { - uint32_t v; + struct imx6_clk_div *div = &iclk->clk.div; + struct imx6_clk *parent; - if (ccm_softc == NULL) - return 0; + KASSERT(iclk->type == IMX6_CLK_DIV); - switch (clk) { - case IMX6CLK_ARM_ROOT: - { - uint32_t pll; - int cacrr; - - for (cacrr = 7; cacrr >= 0; cacrr--) { - pll = (uint64_t)freq * (cacrr + 1) * 2 / IMX6_OSC_FREQ; - if (pll >= 54 && pll <= 108) { - - v = imx6_ccm_read(CCM_CACRR); - v &= ~CCM_CACRR_ARM_PODF; - imx6_ccm_write(CCM_CACRR, - v | __SHIFTIN(cacrr, CCM_CACRR_ARM_PODF)); - - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_ARM); - v &= ~CCM_ANALOG_PLL_ARM_DIV_SELECT; - imx6_ccm_analog_write(CCM_ANALOG_PLL_ARM, - v | __SHIFTIN(pll, CCM_ANALOG_PLL_ARM_DIV_SELECT)); + parent = imx6_clk_find(iclk->parent); + KASSERT(parent != NULL); - v = imx6_get_clock(IMX6CLK_ARM_ROOT); - cpufreq_set_all(v); -#ifdef CPU_CORTEXA9 - a9tmr_update_freq(v / IMX6_PERIPHCLK_N); -#endif - return 0; - } - } - return EINVAL; - } - break; + u_int rate = imxccm_clk_get_rate(sc, &parent->base); - default: - aprint_error_dev(ccm_softc->sc_dev, - "clock %d: not supported yet\n", clk); - return EINVAL; + bus_space_handle_t ioh; + if (div->base == IMX6_CLK_REG_CCM_ANALOG) + ioh = sc->sc_ioh_analog; + else + ioh = sc->sc_ioh; + + uint32_t v = bus_space_read_4(sc->sc_iot, ioh, div->reg); + uint32_t n = __SHIFTOUT(v, div->mask); + + if (div->type == IMX6_CLK_DIV_TABLE) { + KASSERT(div->tbl != NULL); + + for (int i = 0; div->tbl[i] != 0; i++) + if (div->tbl[i] == n) + rate /= div->tbl[i]; + } else { + rate /= n + 1; } - return 0; + return rate; } -uint32_t -imx6_get_clock(enum imx6_clock_id clk) +static u_int +imxccm_clk_get_rate_pfd(struct imxccm_softc *sc, struct imx6_clk *iclk) { - uint32_t d, denom, num, sel, v; - uint64_t freq; + struct imx6_clk_pfd *pfd = &iclk->clk.pfd; + struct imx6_clk *parent; - if (ccm_softc == NULL) - return 0; + KASSERT(iclk->type == IMX6_CLK_PFD); - switch (clk) { - /* CLOCK SWITCHER */ - case IMX6CLK_PLL1: - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_ARM); - freq = IMX6_OSC_FREQ * (v & CCM_ANALOG_PLL_ARM_DIV_SELECT) / 2; - break; - case IMX6CLK_PLL2: - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_SYS); - freq = IMX6_OSC_FREQ * ((v & CCM_ANALOG_PLL_SYS_DIV_SELECT) ? 22 : 20); - break; - case IMX6CLK_PLL3: - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_USB1); - freq = IMX6_OSC_FREQ * ((v & CCM_ANALOG_PLL_USB1_DIV_SELECT) ? 22 : 20); - break; + parent = imx6_clk_find(iclk->parent); + KASSERT(parent != NULL); - case IMX6CLK_PLL4: - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_AUDIO); - d = __SHIFTOUT(v, CCM_ANALOG_PLL_AUDIO_DIV_SELECT); - num = imx6_ccm_analog_read(CCM_ANALOG_PLL_AUDIO_NUM); - denom = imx6_ccm_analog_read(CCM_ANALOG_PLL_AUDIO_DENOM); - freq = (uint64_t)IMX6_OSC_FREQ * (d + num / denom); - d = __SHIFTOUT(v, CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT); - freq = freq >> (2 - d); - break; + const u_int rate_parent = imxccm_clk_get_rate(sc, &parent->base); - case IMX6CLK_PLL5: - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_VIDEO); - d = __SHIFTOUT(v, CCM_ANALOG_PLL_VIDEO_DIV_SELECT); - num = imx6_ccm_analog_read(CCM_ANALOG_PLL_VIDEO_NUM); - denom = imx6_ccm_analog_read(CCM_ANALOG_PLL_VIDEO_DENOM); - freq = (uint64_t)IMX6_OSC_FREQ * (d + num / denom); - d = __SHIFTOUT(v, CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT); - freq = freq >> (2 - d); - break; + uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, pfd->reg); + uint32_t n = __SHIFTOUT(v, __BITS(5, 0) << (pfd->index * 8)); - case IMX6CLK_PLL6: - /* XXX: iMX6UL has 2 div. which? */ - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_ENET); - switch (v & CCM_ANALOG_PLL_ENET_DIV_SELECT) { - case 0: - freq = 25 * 1000 * 1000; - break; - case 1: - freq = 50 * 1000 * 1000; - break; - case 2: - freq = 100 * 1000 * 1000; - break; - case 3: - freq = 125 * 1000 * 1000; + KASSERT(n != 0); + + return (rate_parent * 18) / n; +} + +static int +imxccm_clk_mux_wait(struct imxccm_softc *sc, struct imx6_clk_mux *mux) +{ + KASSERT(mux->busy_reg == 0); + KASSERT(mux->busy_mask == 0); + + bus_space_handle_t ioh; + if (mux->base == IMX6_CLK_REG_CCM_ANALOG) + ioh = sc->sc_ioh_analog; + else + ioh = sc->sc_ioh; + + while (bus_space_read_4(sc->sc_iot, ioh, mux->busy_reg) & mux->busy_mask) + delay(10); + + return 0; +} + +static int +imxccm_clk_set_parent_mux(struct imxccm_softc *sc, + struct imx6_clk *iclk, struct clk *parent) +{ + struct imx6_clk_mux *mux = &iclk->clk.mux; + const char *pname = parent->name; + u_int sel; + + KASSERT(iclk->type == IMX6_CLK_MUX); + + for (sel = 0; sel < mux->nparents; sel++) + if (strcmp(pname, mux->parents[sel]) == 0) break; - } - break; - case IMX6CLK_PLL7: - v = imx6_ccm_analog_read(CCM_ANALOG_PLL_USB2); - freq = IMX6_OSC_FREQ * ((v & CCM_ANALOG_PLL_DIV_SELECT) ? 22 : 20); - break; -#if 0 - case IMX6CLK_PLL8: - /* XXX notyet */ - break; -#endif + if (sel == mux->nparents) + return EINVAL; - case IMX6CLK_PLL2_PFD0: - freq = imx6_get_clock(IMX6CLK_PLL2); - v = imx6_ccm_analog_read(CCM_ANALOG_PFD_528); - freq = freq * 18 / __SHIFTOUT(v, CCM_ANALOG_PFD_528_PFD0_FRAC); - break; - case IMX6CLK_PLL2_PFD1: - freq = imx6_get_clock(IMX6CLK_PLL2); - v = imx6_ccm_analog_read(CCM_ANALOG_PFD_528); - freq = freq * 18 / __SHIFTOUT(v, CCM_ANALOG_PFD_528_PFD1_FRAC); - break; - case IMX6CLK_PLL2_PFD2: - freq = imx6_get_clock(IMX6CLK_PLL2); - v = imx6_ccm_analog_read(CCM_ANALOG_PFD_528); - freq = freq * 18 / __SHIFTOUT(v, CCM_ANALOG_PFD_528_PFD2_FRAC); - break; - case IMX6CLK_PLL3_PFD3: - freq = imx6_get_clock(IMX6CLK_PLL3); - v = imx6_ccm_analog_read(CCM_ANALOG_PFD_480); - freq = freq * 18 / __SHIFTOUT(v, CCM_ANALOG_PFD_480_PFD3_FRAC); - break; - case IMX6CLK_PLL3_PFD2: - freq = imx6_get_clock(IMX6CLK_PLL3); - v = imx6_ccm_analog_read(CCM_ANALOG_PFD_480); - freq = freq * 18 / __SHIFTOUT(v, CCM_ANALOG_PFD_480_PFD2_FRAC); - break; - case IMX6CLK_PLL3_PFD1: - freq = imx6_get_clock(IMX6CLK_PLL3); - v = imx6_ccm_analog_read(CCM_ANALOG_PFD_480); - freq = freq * 18 / __SHIFTOUT(v, CCM_ANALOG_PFD_480_PFD1_FRAC); - break; - case IMX6CLK_PLL3_PFD0: - freq = imx6_get_clock(IMX6CLK_PLL3); - v = imx6_ccm_analog_read(CCM_ANALOG_PFD_480); - freq = freq * 18 / __SHIFTOUT(v, CCM_ANALOG_PFD_480_PFD0_FRAC); - break; + bus_space_handle_t ioh; + if (mux->base == IMX6_CLK_REG_CCM_ANALOG) + ioh = sc->sc_ioh_analog; + else + ioh = sc->sc_ioh; - /* CLOCK ROOT GEN */ - case IMX6CLK_ARM_ROOT: - freq = imx6_get_clock(IMX6CLK_PLL1); - v = __SHIFTOUT(imx6_ccm_read(CCM_CACRR), CCM_CACRR_ARM_PODF); - freq = freq / (v + 1); - break; + uint32_t v = bus_space_read_4(sc->sc_iot, ioh, mux->reg); + v &= ~mux->mask; + v |= __SHIFTIN(sel, mux->mask); - case IMX6CLK_PERIPH: - v = imx6_ccm_read(CCM_CBCDR); - if (v & CCM_CBCDR_PERIPH_CLK_SEL) { - v = imx6_ccm_read(CCM_CBCMR); - sel = __SHIFTOUT(v, CCM_CBCMR_PERIPH_CLK2_SEL); - switch (sel) { - case 0: - freq = imx6_get_clock(IMX6CLK_PLL3); - break; - case 1: - case 2: - freq = IMX6_OSC_FREQ; - break; - case 3: - freq = 0; - aprint_error_dev(ccm_softc->sc_dev, - "IMX6CLK_PERIPH: CCM_CBCMR:CCM_CBCMR_PERIPH_CLK2_SEL is set reserved value\n"); - break; - } - } else { - v = imx6_ccm_read(CCM_CBCMR); - sel = __SHIFTOUT(v, CCM_CBCMR_PRE_PERIPH_CLK_SEL); - switch (sel) { - case 0: - freq = imx6_get_clock(IMX6CLK_PLL2); - break; - case 1: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2); - break; - case 2: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD0); - break; - case 3: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2) / 2; - break; - } - } - break; - case IMX6CLK_AHB: - freq = imx6_get_clock(IMX6CLK_PERIPH); - v = imx6_ccm_read(CCM_CBCDR); - freq = freq / (__SHIFTOUT(v, CCM_CBCDR_AHB_PODF) + 1); - break; - case IMX6CLK_IPG: - freq = imx6_get_clock(IMX6CLK_AHB); - v = imx6_ccm_read(CCM_CBCDR); - freq = freq / (__SHIFTOUT(v, CCM_CBCDR_IPG_PODF) + 1); - break; - case IMX6CLK_AXI: - v = imx6_ccm_read(CCM_CBCDR); - if (v & CCM_CBCDR_AXI_SEL) { - if (v & CCM_CBCDR_AXI_ALT_SEL) { - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2); - } else { - freq = imx6_get_clock(IMX6CLK_PLL3_PFD1); - } - } else { - freq = imx6_get_clock(IMX6CLK_PERIPH); - freq = freq / (__SHIFTOUT(v, CCM_CBCDR_AXI_PODF) + 1); - } - break; + bus_space_write_4(sc->sc_iot, ioh, mux->reg, v); - case IMX6CLK_USDHC1: - v = imx6_ccm_read(CCM_CSCMR1); - freq = imx6_get_clock((v & CCM_CSCMR1_USDHC1_CLK_SEL) ? - IMX6CLK_PLL2_PFD0 : IMX6CLK_PLL2_PFD2); - v = imx6_ccm_read(CCM_CSCDR1); - freq = freq / (__SHIFTOUT(v, CCM_CSCDR1_USDHC1_PODF) + 1); - break; - case IMX6CLK_USDHC2: - v = imx6_ccm_read(CCM_CSCMR1); - freq = imx6_get_clock((v & CCM_CSCMR1_USDHC2_CLK_SEL) ? - IMX6CLK_PLL2_PFD0 : IMX6CLK_PLL2_PFD2); - v = imx6_ccm_read(CCM_CSCDR1); - freq = freq / (__SHIFTOUT(v, CCM_CSCDR1_USDHC2_PODF) + 1); - break; - case IMX6CLK_USDHC3: - v = imx6_ccm_read(CCM_CSCMR1); - freq = imx6_get_clock((v & CCM_CSCMR1_USDHC3_CLK_SEL) ? - IMX6CLK_PLL2_PFD0 : IMX6CLK_PLL2_PFD2); - v = imx6_ccm_read(CCM_CSCDR1); - freq = freq / (__SHIFTOUT(v, CCM_CSCDR1_USDHC3_PODF) + 1); - break; - case IMX6CLK_USDHC4: - v = imx6_ccm_read(CCM_CSCMR1); - freq = imx6_get_clock((v & CCM_CSCMR1_USDHC4_CLK_SEL) ? - IMX6CLK_PLL2_PFD0 : IMX6CLK_PLL2_PFD2); - v = imx6_ccm_read(CCM_CSCDR1); - freq = freq / (__SHIFTOUT(v, CCM_CSCDR1_USDHC4_PODF) + 1); - break; + iclk->parent = pname; - case IMX6CLK_PERCLK: - freq = imx6_get_clock(IMX6CLK_IPG); - v = imx6_ccm_read(CCM_CSCMR1); - freq = freq / (__SHIFTOUT(v, CCM_CSCMR1_PERCLK_PODF) + 1); - break; + if (mux->type == IMX6_CLK_MUX_BUSY) + imxccm_clk_mux_wait(sc, mux); - case IMX6CLK_MMDC_CH1_CLK_ROOT: - freq = imx6_get_clock(IMX6CLK_MMDC_CH1); - v = __SHIFTOUT(imx6_ccm_read(CCM_CBCDR), CCM_CBCDR_MMDC_CH1_AXI_PODF); - freq = freq / (v + 1); - break; + return 0; +} - case IMX6CLK_MMDC_CH0_CLK_ROOT: - freq = imx6_get_clock(IMX6CLK_MMDC_CH0); - v = __SHIFTOUT(imx6_ccm_read(CCM_CBCDR), CCM_CBCDR_MMDC_CH0_AXI_PODF); - freq = freq / (v + 1); - break; +static struct imx6_clk * +imxccm_clk_get_parent_mux(struct imxccm_softc *sc, struct imx6_clk *iclk) +{ + struct imx6_clk_mux *mux = &iclk->clk.mux; - case IMX6CLK_MMDC_CH0: - case IMX6CLK_MMDC_CH1: - v = imx6_ccm_read(CCM_CBCMR); - sel = (clk == IMX6CLK_MMDC_CH0) ? - __SHIFTOUT(v, CCM_CBCMR_PRE_PERIPH_CLK_SEL) : - __SHIFTOUT(v, CCM_CBCMR_PRE_PERIPH2_CLK_SEL); - switch (sel) { - case 0: - freq = imx6_get_clock(IMX6CLK_PLL2); - break; - case 1: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2); - break; - case 2: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD0); - break; - case 3: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2) / 2; - break; - } - break; + KASSERT(iclk->type == IMX6_CLK_MUX); - case IMX6CLK_IPU1_HSP_CLK_ROOT: - v = imx6_ccm_read(CCM_CSCDR3); - switch (__SHIFTOUT(v, CCM_CSCDR3_IPU1_HSP_CLK_SEL)) { - case 0: - freq = imx6_get_clock(IMX6CLK_MMDC_CH0); - break; - case 1: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2); - break; - case 2: - freq = imx6_get_clock(IMX6CLK_PLL3) / 4; - break; - case 3: - freq = imx6_get_clock(IMX6CLK_PLL3_PFD1); - break; - } - v = __SHIFTOUT(v, CCM_CSCDR3_IPU1_HSP_CLK_SEL); - freq = freq / (v + 1); - break; - case IMX6CLK_IPU2_HSP_CLK_ROOT: - v = imx6_ccm_read(CCM_CSCDR3); - switch (__SHIFTOUT(v, CCM_CSCDR3_IPU2_HSP_CLK_SEL)) { - case 0: - freq = imx6_get_clock(IMX6CLK_MMDC_CH0); - break; - case 1: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2); - break; - case 2: - freq = imx6_get_clock(IMX6CLK_PLL3) / 4; - break; - case 3: - freq = imx6_get_clock(IMX6CLK_PLL3_PFD1); - break; - } - v = __SHIFTOUT(v, CCM_CSCDR3_IPU2_HSP_CLK_SEL); - freq = freq / (v + 1); - break; + bus_space_handle_t ioh; + if (mux->base == IMX6_CLK_REG_CCM_ANALOG) + ioh = sc->sc_ioh_analog; + else + ioh = sc->sc_ioh; - case IMX6CLK_IPU1_DI0_CLK_ROOT: - case IMX6CLK_IPU1_DI1_CLK_ROOT: - v = imx6_ccm_read(CCM_CHSCCDR); - sel = (clk == IMX6CLK_IPU1_DI0_CLK_ROOT) ? - __SHIFTOUT(v, CCM_CHSCCDR_IPU1_DI0_CLK_SEL) : - __SHIFTOUT(v, CCM_CHSCCDR_IPU1_DI1_CLK_SEL); - switch (sel) { - case 0: - sel = (clk == IMX6CLK_IPU1_DI0_CLK_ROOT) ? - __SHIFTOUT(v, CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL) : - __SHIFTOUT(v, CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL); - switch (sel) { - case 0: - freq = imx6_get_clock(IMX6CLK_MMDC_CH0); - break; - case 1: - freq = imx6_get_clock(IMX6CLK_PLL3); - break; - case 2: - freq = imx6_get_clock(IMX6CLK_PLL5); - break; - case 3: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD0); - break; - case 4: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2); - break; - case 5: - freq = imx6_get_clock(IMX6CLK_PLL3_PFD1); - break; - default: - /* reserved */ - freq = 0; - } - if (clk == IMX6CLK_IPU1_DI0_CLK_ROOT) - freq = freq / (__SHIFTOUT(v, CCM_CHSCCDR_IPU1_DI0_PODF) + 1); - else - freq = freq / (__SHIFTOUT(v, CCM_CHSCCDR_IPU1_DI1_PODF) + 1); - break; - case 1: - case 2: - /* IPP_DI[01]_CLK is an external clock */ - freq = 0; - break; - case 3: - freq = imx6_get_clock(IMX6CLK_LDB_DI0_IPU); - break; - case 4: - freq = imx6_get_clock(IMX6CLK_LDB_DI1_IPU); - break; - default: - /* reserved */ - freq = 0; - } - break; + uint32_t v = bus_space_read_4(sc->sc_iot, ioh, mux->reg); + u_int sel = __SHIFTOUT(v, mux->mask); - case IMX6CLK_LDB_DI0_SERIAL_CLK_ROOT: - case IMX6CLK_LDB_DI1_SERIAL_CLK_ROOT: - v = imx6_ccm_read(CCM_CS2CDR); - sel = (clk == IMX6CLK_LDB_DI0_SERIAL_CLK_ROOT) ? - __SHIFTOUT(v, CCM_CS2CDR_LDB_DI0_CLK_SEL) : - __SHIFTOUT(v, CCM_CS2CDR_LDB_DI1_CLK_SEL); - switch (sel) { - case 0: - freq = imx6_get_clock(IMX6CLK_PLL5); - break; - case 1: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD0); - break; - case 2: - freq = imx6_get_clock(IMX6CLK_PLL2_PFD2); - break; - case 3: - freq = imx6_get_clock(IMX6CLK_MMDC_CH1); - break; - case 4: - freq = imx6_get_clock(IMX6CLK_PLL3); - break; - case 5: - default: - /* reserved */ - freq = 0; - } - break; + KASSERT(sel < mux->nparents); - case IMX6CLK_LDB_DI0_IPU: - freq = imx6_get_clock(IMX6CLK_LDB_DI0_SERIAL_CLK_ROOT); - v = imx6_ccm_read(CCM_CSCMR2); - if (!ISSET(v, CCM_CSCMR2_LDB_DI0_IPU_DIV)) - freq *= 2; - freq /= 7; - break; - case IMX6CLK_LDB_DI1_IPU: - freq = imx6_get_clock(IMX6CLK_LDB_DI1_SERIAL_CLK_ROOT); - v = imx6_ccm_read(CCM_CSCMR2); - if (!ISSET(v, CCM_CSCMR2_LDB_DI1_IPU_DIV)) - freq *= 2; - freq /= 7; - break; + iclk->parent = mux->parents[sel]; + + return imx6_clk_find(iclk->parent); +} + +static int +imxccm_clk_set_rate_pll(struct imxccm_softc *sc, + struct imx6_clk *eclk, u_int rate) +{ + /* ToDo */ + + return EOPNOTSUPP; +} + +/* + * CLK Driver APIs + */ +static struct clk * +imxccm_clk_get(void *priv, const char *name) +{ + struct imx6_clk *iclk; + + iclk = imx6_clk_find(name); + if (iclk == NULL) + return NULL; + + atomic_inc_uint(&iclk->refcnt); + + return &iclk->base; +} + +static void +imxccm_clk_put(void *priv, struct clk *clk) +{ + struct imx6_clk *iclk = (struct imx6_clk *)clk; + + KASSERT(iclk->refcnt > 0); + atomic_dec_uint(&iclk->refcnt); +} + +static u_int +imxccm_clk_get_rate(void *priv, struct clk *clk) +{ + struct imx6_clk *iclk = (struct imx6_clk *)clk; + struct clk *parent; + struct imxccm_softc *sc = priv; + + switch (iclk->type) { + case IMX6_CLK_FIXED: + return iclk->clk.fixed.rate; + case IMX6_CLK_FIXED_FACTOR: + return imxccm_clk_get_rate_fixed_factor(sc, iclk); + case IMX6_CLK_PLL: + return imxccm_clk_get_rate_pll(sc, iclk); + case IMX6_CLK_MUX: + case IMX6_CLK_GATE: + parent = imxccm_clk_get_parent(sc, clk); + return imxccm_clk_get_rate(sc, parent); + case IMX6_CLK_DIV: + return imxccm_clk_get_rate_div(sc, iclk); + case IMX6_CLK_PFD: + return imxccm_clk_get_rate_pfd(sc, iclk); default: - aprint_error_dev(ccm_softc->sc_dev, - "clock %d: not supported yet\n", clk); - return 0; + panic("imx6: unknown clk type %d", iclk->type); } +} - return freq; +static int +imxccm_clk_set_rate(void *priv, struct clk *clk, u_int rate) +{ + struct imx6_clk *iclk = (struct imx6_clk *)clk; + struct imxccm_softc *sc = priv; + + switch (iclk->type) { + case IMX6_CLK_FIXED: + case IMX6_CLK_FIXED_FACTOR: + return EIO; + case IMX6_CLK_PLL: + return imxccm_clk_set_rate_pll(sc, iclk, rate); + case IMX6_CLK_MUX: + return EIO; + case IMX6_CLK_GATE: + case IMX6_CLK_DIV: + case IMX6_CLK_PFD: + return EINVAL; + default: + panic("imx6: unknown clk type %d", iclk->type); + } } -int -imx6_pll_power(uint32_t pllreg, int on, uint32_t en) +static int +imxccm_clk_enable_pll(struct imxccm_softc *sc, struct imx6_clk *iclk, bool enable) { - uint32_t v; - int timeout; + struct imx6_clk_pll *pll = &iclk->clk.pll; - switch (pllreg) { - case CCM_ANALOG_PLL_USB1: - case CCM_ANALOG_PLL_USB2: - v = imx6_ccm_analog_read(pllreg); - if (on) { - v |= en; - v &= ~CCM_ANALOG_PLL_BYPASS; - } else { - v &= ~en; - } - imx6_ccm_analog_write(pllreg, v); + KASSERT(iclk->type == IMX6_CLK_PLL); + + /* Power up bit */ + if (pll->type == IMX6_CLK_PLL_USB) + enable = !enable; + + bus_space_handle_t ioh = sc->sc_ioh_analog; + uint32_t v = bus_space_read_4(sc->sc_iot, ioh, pll->reg); + if (__SHIFTOUT(v, pll->powerdown) != enable) return 0; + if (enable) + v &= ~pll->powerdown; + else + v |= pll->powerdown; + bus_space_write_4(sc->sc_iot, ioh, pll->reg, v); - case CCM_ANALOG_PLL_ENET: - v = imx6_ccm_analog_read(pllreg); - if (on) - v &= ~CCM_ANALOG_PLL_ENET_POWERDOWN; - else - v |= CCM_ANALOG_PLL_ENET_POWERDOWN; - imx6_ccm_analog_write(pllreg, v); - - for (timeout = 100000; timeout > 0; timeout--) { - if (imx6_ccm_analog_read(pllreg) & - CCM_ANALOG_PLL_ENET_LOCK) - break; - } - if (timeout <= 0) - break; + /* wait look */ + while (!(bus_space_read_4(sc->sc_iot, ioh, pll->reg) & CCM_ANALOG_PLL_LOCK)) + delay(10); - v |= CCM_ANALOG_PLL_ENET_ENABLE; - if (on) { - v &= ~CCM_ANALOG_PLL_ENET_BYPASS; - imx6_ccm_analog_write(pllreg, v); - v |= en; - } else { - v &= ~en; - } - imx6_ccm_analog_write(pllreg, v); + return 0; +} + +static int +imxccm_clk_enable_gate(struct imxccm_softc *sc, struct imx6_clk *iclk, bool enable) +{ + struct imx6_clk_gate *gate = &iclk->clk.gate; + + KASSERT(iclk->type == IMX6_CLK_GATE); + + bus_space_handle_t ioh; + if (gate->base == IMX6_CLK_REG_CCM_ANALOG) + ioh = sc->sc_ioh_analog; + else + ioh = sc->sc_ioh; + + uint32_t v = bus_space_read_4(sc->sc_iot, ioh, gate->reg); + if (enable) { + if (gate->exclusive_mask) + v &= ~gate->exclusive_mask; + v |= gate->mask; + } else { + if (gate->exclusive_mask) + v |= gate->exclusive_mask; + v &= ~gate->mask; + } + bus_space_write_4(sc->sc_iot, ioh, gate->reg, v); + + return 0; +} + +static int +imxccm_clk_enable(void *priv, struct clk *clk) +{ + struct imx6_clk *iclk = (struct imx6_clk *)clk; + struct imx6_clk *parent = NULL; + struct imxccm_softc *sc = priv; + + if ((parent = imx6_clk_find(iclk->parent)) != NULL) + imxccm_clk_enable(sc, &parent->base); + + switch (iclk->type) { + case IMX6_CLK_FIXED: + case IMX6_CLK_FIXED_FACTOR: + return 0; /* always on */ + case IMX6_CLK_PLL: + return imxccm_clk_enable_pll(sc, iclk, true); + case IMX6_CLK_MUX: + case IMX6_CLK_DIV: + case IMX6_CLK_PFD: return 0; + case IMX6_CLK_GATE: + return imxccm_clk_enable_gate(sc, iclk, true); + default: + panic("imx6: unknown clk type %d", iclk->type); + } +} - case CCM_ANALOG_PLL_ARM: - case CCM_ANALOG_PLL_SYS: - case CCM_ANALOG_PLL_AUDIO: - case CCM_ANALOG_PLL_VIDEO: - case CCM_ANALOG_PLL_MLB: - /* notyet */ +static int +imxccm_clk_disable(void *priv, struct clk *clk) +{ + struct imx6_clk *iclk = (struct imx6_clk *)clk; + struct imxccm_softc *sc = priv; + + switch (iclk->type) { + case IMX6_CLK_FIXED: + case IMX6_CLK_FIXED_FACTOR: + return EINVAL; /* always on */ + case IMX6_CLK_PLL: + return imxccm_clk_enable_pll(sc, iclk, false); + case IMX6_CLK_MUX: + case IMX6_CLK_DIV: + case IMX6_CLK_PFD: + return EINVAL; + case IMX6_CLK_GATE: + return imxccm_clk_enable_gate(sc, iclk, false); default: + panic("imx6: unknown clk type %d", iclk->type); + } +} + +static int +imxccm_clk_set_parent(void *priv, struct clk *clk, struct clk *parent) +{ + struct imx6_clk *iclk = (struct imx6_clk *)clk; + struct imxccm_softc *sc = priv; + + switch (iclk->type) { + case IMX6_CLK_FIXED: + case IMX6_CLK_FIXED_FACTOR: + case IMX6_CLK_PLL: + case IMX6_CLK_GATE: + case IMX6_CLK_DIV: + case IMX6_CLK_PFD: + return EINVAL; + case IMX6_CLK_MUX: + return imxccm_clk_set_parent_mux(sc, iclk, parent); + default: + panic("imx6: unknown clk type %d", iclk->type); + } +} + +static struct clk * +imxccm_clk_get_parent(void *priv, struct clk *clk) +{ + struct imx6_clk *iclk = (struct imx6_clk *)clk; + struct imx6_clk *parent = NULL; + struct imxccm_softc *sc = priv; + + switch (iclk->type) { + case IMX6_CLK_FIXED: + case IMX6_CLK_FIXED_FACTOR: + case IMX6_CLK_PLL: + case IMX6_CLK_GATE: + case IMX6_CLK_DIV: + case IMX6_CLK_PFD: + if (iclk->parent != NULL) + parent = imx6_clk_find(iclk->parent); break; + case IMX6_CLK_MUX: + parent = imxccm_clk_get_parent_mux(sc, iclk); + break; + default: + panic("imx6: unknown clk type %d", iclk->type); } - return -1; + return (struct clk *)parent; } Index: src/sys/arch/arm/imx/imx6_ccmreg.h diff -u src/sys/arch/arm/imx/imx6_ccmreg.h:1.9 src/sys/arch/arm/imx/imx6_ccmreg.h:1.10 --- src/sys/arch/arm/imx/imx6_ccmreg.h:1.9 Sun Sep 16 09:25:46 2018 +++ src/sys/arch/arm/imx/imx6_ccmreg.h Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: imx6_ccmreg.h,v 1.9 2018/09/16 09:25:46 skrll Exp $ */ +/* $NetBSD: imx6_ccmreg.h,v 1.10 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2014 Ryo Shimizu <r...@nerv.org> @@ -41,11 +41,20 @@ #define IMX6_PERIPHCLK_N 2 #endif +#ifndef IMX6_CKIL_FREQ +#define IMX6_CKIL_FREQ 32768 +#endif +#ifndef IMX6_CKIH_FREQ +#define IMX6_CKIH_FREQ 0 +#endif #ifndef IMX6_OSC_FREQ #define IMX6_OSC_FREQ (24 * 1000 * 1000) /* 24MHz */ #endif -#ifndef IMX6_CKIL_FREQ -#define IMX6_CKIL_FREQ 32768 +#ifndef IMX6_ANACLK1_FREQ +#define IMX6_ANACLK1_FREQ 0 +#endif +#ifndef IMX6_ANACLK2_FREQ +#define IMX6_ANACLK2_FREQ 0 #endif #define CCM_CCR 0x00000000 @@ -321,6 +330,7 @@ #define CCM_ANALOG_PLL_USB1_CLR 0x00000018 #define CCM_ANALOG_PLL_USB1_TOG 0x0000001c #define CCM_ANALOG_PLL_USB1_LOCK __BIT(31) +#define CCM_ANALOG_PLL_USB1_RESERVED __BIT(20) #define CCM_ANALOG_PLL_USB1_BYPASS __BIT(16) #define CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC __BITS(15, 14) #define CCM_ANALOG_PLL_USB1_ENABLE __BIT(13) @@ -333,6 +343,7 @@ #define CCM_ANALOG_PLL_USB2_CLR 0x00000028 #define CCM_ANALOG_PLL_USB2_TOG 0x0000002c #define CCM_ANALOG_PLL_USB2_LOCK __BIT(31) +#define CCM_ANALOG_PLL_USB2_RESERVED __BIT(20) #define CCM_ANALOG_PLL_USB2_BYPASS __BIT(16) #define CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC __BITS(15, 14) #define CCM_ANALOG_PLL_USB2_ENABLE __BIT(13) @@ -436,6 +447,7 @@ #define CCM_ANALOG_MISC1_LVDS_CLK1_SRC __BITS(4, 0) #define CCM_ANALOG_MISC1_LVDS_CLK1_SRC_PCIE __SHIFTIN(0xa, CCM_ANALOG_MISC1_LVDS_CLK1_SRC) #define CCM_ANALOG_MISC1_LVDS_CLK1_SRC_SATA __SHIFTIN(0xb, CCM_ANALOG_MISC1_LVDS_CLK1_SRC) +#define CCM_ANALOG_MISC1_LVDS_CLK2_SRC __BITS(9, 5) #define CCM_ANALOG_MISC1_LVDS_CLK1_OBEN __BIT(10) #define CCM_ANALOG_MISC1_LVDS_CLK2_OBEN __BIT(11) #define CCM_ANALOG_MISC1_LVDS_CLK1_IBEN __BIT(12) Index: src/sys/arch/arm/imx/imx6_ccmvar.h diff -u src/sys/arch/arm/imx/imx6_ccmvar.h:1.5 src/sys/arch/arm/imx/imx6_ccmvar.h:1.6 --- src/sys/arch/arm/imx/imx6_ccmvar.h:1.5 Thu Nov 9 05:57:23 2017 +++ src/sys/arch/arm/imx/imx6_ccmvar.h Thu Jun 20 08:16:19 2019 @@ -1,6 +1,6 @@ -/* $NetBSD: imx6_ccmvar.h,v 1.5 2017/11/09 05:57:23 hkenken Exp $ */ +/* $NetBSD: imx6_ccmvar.h,v 1.6 2019/06/20 08:16:19 hkenken Exp $ */ /* - * Copyright (c) 2012 Genetec Corporation. All rights reserved. + * Copyright (c) 2012,2019 Genetec Corporation. All rights reserved. * Written by Hashimoto Kenichi for Genetec Corporation. * * Redistribution and use in source and binary forms, with or without @@ -28,58 +28,530 @@ #ifndef _ARM_IMX_IMX6_CCMVAR_H_ #define _ARM_IMX_IMX6_CCMVAR_H_ -enum imx6_clock_id { - IMX6CLK_PLL1, /* = PLL_ARM */ - IMX6CLK_PLL2, /* = PLL_SYS = 528_PLL (24MHz * 22) */ - IMX6CLK_PLL3, /* = PLL_USB1 = 480_PLL1 */ - /* (USB/OTG PHY, 480PFD0-480PFD3, 24MHz*20) */ - IMX6CLK_PLL4, /* = PLL_AUDIO */ - IMX6CLK_PLL5, /* = PLL_VIDEO */ - IMX6CLK_PLL6, /* = PLL_ENET (20MHz = 24MHz * 5/6) */ - IMX6CLK_PLL7, /* = PLL_USB2 (USB2 PHY, HOST PHY, 24MHz*20) */ - IMX6CLK_PLL8, /* = PLL_MLB (Media Link Bus) */ - IMX6CLK_PLL2_PFD0, - IMX6CLK_PLL2_PFD1, - IMX6CLK_PLL2_PFD2, - IMX6CLK_PLL3_PFD0, - IMX6CLK_PLL3_PFD1, - IMX6CLK_PLL3_PFD2, - IMX6CLK_PLL3_PFD3, - - IMX6CLK_ARM_ROOT, /* CPU clock of ARM core */ - IMX6CLK_PERIPH, - IMX6CLK_AHB, - IMX6CLK_IPG, - IMX6CLK_AXI, - IMX6CLK_MMDC_CH0, - IMX6CLK_MMDC_CH1, - IMX6CLK_MMDC_CH0_CLK_ROOT, - IMX6CLK_MMDC_CH1_CLK_ROOT, - - IMX6CLK_USDHC1, - IMX6CLK_USDHC2, - IMX6CLK_USDHC3, - IMX6CLK_USDHC4, - - IMX6CLK_PERCLK, - - IMX6CLK_IPU1_HSP_CLK_ROOT, - IMX6CLK_IPU2_HSP_CLK_ROOT, - IMX6CLK_IPU1_DI0_CLK_ROOT, - IMX6CLK_IPU1_DI1_CLK_ROOT, - IMX6CLK_LDB_DI0_IPU, - IMX6CLK_LDB_DI0_SERIAL_CLK_ROOT, - IMX6CLK_LDB_DI1_IPU, - IMX6CLK_LDB_DI1_SERIAL_CLK_ROOT, -}; - -uint32_t imx6_get_clock(enum imx6_clock_id); -int imx6_set_clock(enum imx6_clock_id, uint32_t); -int imx6_pll_power(uint32_t, int, uint32_t); - -uint32_t imx6_ccm_read(uint32_t); -void imx6_ccm_write(uint32_t, uint32_t); -uint32_t imx6_ccm_analog_read(uint32_t); -void imx6_ccm_analog_write(uint32_t, uint32_t); +#include <dev/clk/clk.h> +#include <dev/clk/clk_backend.h> + +struct clk *imx6_get_clock(const char *name); + +/* Clock IDs */ +#define IMX6CLK_DUMMY 0 +#define IMX6CLK_CKIL 1 +#define IMX6CLK_CKIH 2 +#define IMX6CLK_OSC 3 +#define IMX6CLK_PLL2_PFD0_352M 4 +#define IMX6CLK_PLL2_PFD1_594M 5 +#define IMX6CLK_PLL2_PFD2_396M 6 +#define IMX6CLK_PLL3_PFD0_720M 7 +#define IMX6CLK_PLL3_PFD1_540M 8 +#define IMX6CLK_PLL3_PFD2_508M 9 +#define IMX6CLK_PLL3_PFD3_454M 10 +#define IMX6CLK_PLL2_198M 11 +#define IMX6CLK_PLL3_120M 12 +#define IMX6CLK_PLL3_80M 13 +#define IMX6CLK_PLL3_60M 14 +#define IMX6CLK_TWD 15 +#define IMX6CLK_STEP 16 +#define IMX6CLK_PLL1_SW 17 +#define IMX6CLK_PERIPH_PRE 18 +#define IMX6CLK_PERIPH2_PRE 19 +#define IMX6CLK_PERIPH_CLK2_SEL 20 +#define IMX6CLK_PERIPH2_CLK2_SEL 21 +#define IMX6CLK_AXI_SEL 22 +#define IMX6CLK_ESAI_SEL 23 +#define IMX6CLK_ASRC_SEL 24 +#define IMX6CLK_SPDIF_SEL 25 +#define IMX6CLK_GPU2D_AXI 26 +#define IMX6CLK_GPU3D_AXI 27 +#define IMX6CLK_GPU2D_CORE_SEL 28 +#define IMX6CLK_GPU3D_CORE_SEL 29 +#define IMX6CLK_GPU3D_SHADER_SEL 30 +#define IMX6CLK_IPU1_SEL 31 +#define IMX6CLK_IPU2_SEL 32 +#define IMX6CLK_LDB_DI0_SEL 33 +#define IMX6CLK_LDB_DI1_SEL 34 +#define IMX6CLK_IPU1_DI0_PRE_SEL 35 +#define IMX6CLK_IPU1_DI1_PRE_SEL 36 +#define IMX6CLK_IPU2_DI0_PRE_SEL 37 +#define IMX6CLK_IPU2_DI1_PRE_SEL 38 +#define IMX6CLK_IPU1_DI0_SEL 39 +#define IMX6CLK_IPU1_DI1_SEL 40 +#define IMX6CLK_IPU2_DI0_SEL 41 +#define IMX6CLK_IPU2_DI1_SEL 42 +#define IMX6CLK_HSI_TX_SEL 43 +#define IMX6CLK_PCIE_AXI_SEL 44 +#define IMX6CLK_SSI1_SEL 45 +#define IMX6CLK_SSI2_SEL 46 +#define IMX6CLK_SSI3_SEL 47 +#define IMX6CLK_USDHC1_SEL 48 +#define IMX6CLK_USDHC2_SEL 49 +#define IMX6CLK_USDHC3_SEL 50 +#define IMX6CLK_USDHC4_SEL 51 +#define IMX6CLK_ENFC_SEL 52 +#define IMX6CLK_EIM_SEL 53 +#define IMX6CLK_EIM_SLOW_SEL 54 +#define IMX6CLK_VDO_AXI_SEL 55 +#define IMX6CLK_VPU_AXI_SEL 56 +#define IMX6CLK_CKO1_SEL 57 +#define IMX6CLK_PERIPH 58 +#define IMX6CLK_PERIPH2 59 +#define IMX6CLK_PERIPH_CLK2 60 +#define IMX6CLK_PERIPH2_CLK2 61 +#define IMX6CLK_IPG 62 +#define IMX6CLK_IPG_PER 63 +#define IMX6CLK_ESAI_PRED 64 +#define IMX6CLK_ESAI_PODF 65 +#define IMX6CLK_ASRC_PRED 66 +#define IMX6CLK_ASRC_PODF 67 +#define IMX6CLK_SPDIF_PRED 68 +#define IMX6CLK_SPDIF_PODF 69 +#define IMX6CLK_CAN_ROOT 70 +#define IMX6CLK_ECSPI_ROOT 71 +#define IMX6CLK_GPU2D_CORE_PODF 72 +#define IMX6CLK_GPU3D_CORE_PODF 73 +#define IMX6CLK_GPU3D_SHADER 74 +#define IMX6CLK_IPU1_PODF 75 +#define IMX6CLK_IPU2_PODF 76 +#define IMX6CLK_LDB_DI0_PODF 77 +#define IMX6CLK_LDB_DI1_PODF 78 +#define IMX6CLK_IPU1_DI0_PRE 79 +#define IMX6CLK_IPU1_DI1_PRE 80 +#define IMX6CLK_IPU2_DI0_PRE 81 +#define IMX6CLK_IPU2_DI1_PRE 82 +#define IMX6CLK_HSI_TX_PODF 83 +#define IMX6CLK_SSI1_PRED 84 +#define IMX6CLK_SSI1_PODF 85 +#define IMX6CLK_SSI2_PRED 86 +#define IMX6CLK_SSI2_PODF 87 +#define IMX6CLK_SSI3_PRED 88 +#define IMX6CLK_SSI3_PODF 89 +#define IMX6CLK_UART_SERIAL_PODF 90 +#define IMX6CLK_USDHC1_PODF 91 +#define IMX6CLK_USDHC2_PODF 92 +#define IMX6CLK_USDHC3_PODF 93 +#define IMX6CLK_USDHC4_PODF 94 +#define IMX6CLK_ENFC_PRED 95 +#define IMX6CLK_ENFC_PODF 96 +#define IMX6CLK_EIM_PODF 97 +#define IMX6CLK_EIM_SLOW_PODF 98 +#define IMX6CLK_VPU_AXI_PODF 99 +#define IMX6CLK_CKO1_PODF 100 +#define IMX6CLK_AXI 101 +#define IMX6CLK_MMDC_CH0_AXI_PODF 102 +#define IMX6CLK_MMDC_CH1_AXI_PODF 103 +#define IMX6CLK_ARM 104 +#define IMX6CLK_AHB 105 +#define IMX6CLK_APBH_DMA 106 +#define IMX6CLK_ASRC 107 +#define IMX6CLK_CAN1_IPG 108 +#define IMX6CLK_CAN1_SERIAL 109 +#define IMX6CLK_CAN2_IPG 110 +#define IMX6CLK_CAN2_SERIAL 111 +#define IMX6CLK_ECSPI1 112 +#define IMX6CLK_ECSPI2 113 +#define IMX6CLK_ECSPI3 114 +#define IMX6CLK_ECSPI4 115 +#define IMX6CLK_ECSPI5 116 /* i.MX6Q */ +#define IMX6CLK_I2C4 116 /* i.MX6DL */ +#define IMX6CLK_ENET 117 +#define IMX6CLK_ESAI_EXTAL 118 +#define IMX6CLK_GPT_IPG 119 +#define IMX6CLK_GPT_IPG_PER 120 +#define IMX6CLK_GPU2D_CORE 121 +#define IMX6CLK_GPU3D_CORE 122 +#define IMX6CLK_HDMI_IAHB 123 +#define IMX6CLK_HDMI_ISFR 124 +#define IMX6CLK_I2C1 125 +#define IMX6CLK_I2C2 126 +#define IMX6CLK_I2C3 127 +#define IMX6CLK_IIM 128 +#define IMX6CLK_ENFC 129 +#define IMX6CLK_IPU1 130 +#define IMX6CLK_IPU1_DI0 131 +#define IMX6CLK_IPU1_DI1 132 +#define IMX6CLK_IPU2 133 +#define IMX6CLK_IPU2_DI0 134 +#define IMX6CLK_LDB_DI0 135 +#define IMX6CLK_LDB_DI1 136 +#define IMX6CLK_IPU2_DI1 137 +#define IMX6CLK_HSI_TX 138 +#define IMX6CLK_MLB 139 +#define IMX6CLK_MMDC_CH0_AXI 140 +#define IMX6CLK_MMDC_CH1_AXI 141 +#define IMX6CLK_OCRAM 142 +#define IMX6CLK_OPENVG_AXI 143 +#define IMX6CLK_PCIE_AXI 144 +#define IMX6CLK_PWM1 145 +#define IMX6CLK_PWM2 146 +#define IMX6CLK_PWM3 147 +#define IMX6CLK_PWM4 148 +#define IMX6CLK_PER1_BCH 149 +#define IMX6CLK_GPMI_BCH_APB 150 +#define IMX6CLK_GPMI_BCH 151 +#define IMX6CLK_GPMI_IO 152 +#define IMX6CLK_GPMI_APB 153 +#define IMX6CLK_SATA 154 +#define IMX6CLK_SDMA 155 +#define IMX6CLK_SPBA 156 +#define IMX6CLK_SSI1 157 +#define IMX6CLK_SSI2 158 +#define IMX6CLK_SSI3 159 +#define IMX6CLK_UART_IPG 160 +#define IMX6CLK_UART_SERIAL 161 +#define IMX6CLK_USBOH3 162 +#define IMX6CLK_USDHC1 163 +#define IMX6CLK_USDHC2 164 +#define IMX6CLK_USDHC3 165 +#define IMX6CLK_USDHC4 166 +#define IMX6CLK_VDO_AXI 167 +#define IMX6CLK_VPU_AXI 168 +#define IMX6CLK_CKO1 169 +#define IMX6CLK_PLL1_SYS 170 +#define IMX6CLK_PLL2_BUS 171 +#define IMX6CLK_PLL3_USB_OTG 172 +#define IMX6CLK_PLL4_AUDIO 173 +#define IMX6CLK_PLL5_VIDEO 174 +#define IMX6CLK_PLL8_MLB 175 +#define IMX6CLK_PLL7_USB_HOST 176 +#define IMX6CLK_PLL6_ENET 177 +#define IMX6CLK_SSI1_IPG 178 +#define IMX6CLK_SSI2_IPG 179 +#define IMX6CLK_SSI3_IPG 180 +#define IMX6CLK_ROM 181 +#define IMX6CLK_USBPHY1 182 +#define IMX6CLK_USBPHY2 183 +#define IMX6CLK_LDB_DI0_DIV_3_5 184 +#define IMX6CLK_LDB_DI1_DIV_3_5 185 +#define IMX6CLK_SATA_REF 186 +#define IMX6CLK_SATA_REF_100M 187 +#define IMX6CLK_PCIE_REF 188 +#define IMX6CLK_PCIE_REF_125M 189 +#define IMX6CLK_ENET_REF 190 +#define IMX6CLK_USBPHY1_GATE 191 +#define IMX6CLK_USBPHY2_GATE 192 +#define IMX6CLK_PLL4_POST_DIV 193 +#define IMX6CLK_PLL5_POST_DIV 194 +#define IMX6CLK_PLL5_VIDEO_DIV 195 +#define IMX6CLK_EIM_SLOW 196 +#define IMX6CLK_SPDIF 197 +#define IMX6CLK_CKO2_SEL 198 +#define IMX6CLK_CKO2_PODF 199 +#define IMX6CLK_CKO2 200 +#define IMX6CLK_CKO 201 +#define IMX6CLK_VDOA 202 +#define IMX6CLK_PLL4_AUDIO_DIV 203 +#define IMX6CLK_LVDS1_SEL 204 +#define IMX6CLK_LVDS2_SEL 205 +#define IMX6CLK_LVDS1_GATE 206 +#define IMX6CLK_LVDS2_GATE 207 +#define IMX6CLK_ESAI_IPG 208 +#define IMX6CLK_ESAI_MEM 209 +#define IMX6CLK_ASRC_IPG 210 +#define IMX6CLK_ASRC_MEM 211 +#define IMX6CLK_LVDS1_IN 212 +#define IMX6CLK_LVDS2_IN 213 +#define IMX6CLK_ANACLK1 214 +#define IMX6CLK_ANACLK2 215 +#define IMX6CLK_PLL1_BYPASS_SRC 216 +#define IMX6CLK_PLL2_BYPASS_SRC 217 +#define IMX6CLK_PLL3_BYPASS_SRC 218 +#define IMX6CLK_PLL4_BYPASS_SRC 219 +#define IMX6CLK_PLL5_BYPASS_SRC 220 +#define IMX6CLK_PLL6_BYPASS_SRC 221 +#define IMX6CLK_PLL7_BYPASS_SRC 222 +#define IMX6CLK_PLL1 223 +#define IMX6CLK_PLL2 224 +#define IMX6CLK_PLL3 225 +#define IMX6CLK_PLL4 226 +#define IMX6CLK_PLL5 227 +#define IMX6CLK_PLL6 228 +#define IMX6CLK_PLL7 229 +#define IMX6CLK_PLL1_BYPASS 230 +#define IMX6CLK_PLL2_BYPASS 231 +#define IMX6CLK_PLL3_BYPASS 232 +#define IMX6CLK_PLL4_BYPASS 233 +#define IMX6CLK_PLL5_BYPASS 234 +#define IMX6CLK_PLL6_BYPASS 235 +#define IMX6CLK_PLL7_BYPASS 236 +#define IMX6CLK_GPT_3M 237 +#define IMX6CLK_VIDEO_27M 238 +#define IMX6CLK_MIPI_CORE_CFG 239 +#define IMX6CLK_MIPI_IPG 240 +#define IMX6CLK_CAAM_MEM 241 +#define IMX6CLK_CAAM_ACLK 242 +#define IMX6CLK_CAAM_IPG 243 +#define IMX6CLK_SPDIF_GCLK 244 +#define IMX6CLK_UART_SEL 245 +#define IMX6CLK_IPG_PER_SEL 246 +#define IMX6CLK_ECSPI_SEL 247 +#define IMX6CLK_CAN_SEL 248 +#define IMX6CLK_MMDC_CH1_AXI_CG 249 +#define IMX6CLK_PRE0 250 +#define IMX6CLK_PRE1 251 +#define IMX6CLK_PRE2 252 +#define IMX6CLK_PRE3 253 +#define IMX6CLK_PRG0_AXI 254 +#define IMX6CLK_PRG1_AXI 255 +#define IMX6CLK_PRG0_APB 256 +#define IMX6CLK_PRG1_APB 257 +#define IMX6CLK_PRE_AXI 258 +#define IMX6CLK_MLB_SEL 259 +#define IMX6CLK_MLB_PODF 260 +#define IMX6CLK_END 261 + +enum imx6_clk_type { + IMX6_CLK_FIXED, + IMX6_CLK_FIXED_FACTOR, + IMX6_CLK_PLL, + IMX6_CLK_MUX, + IMX6_CLK_GATE, + IMX6_CLK_PFD, + IMX6_CLK_DIV, +}; + +enum imx6_clk_reg { + IMX6_CLK_REG_CCM, + IMX6_CLK_REG_CCM_ANALOG, +}; + +enum imx6_clk_pll_type { + IMX6_CLK_PLL_GENNERIC, + IMX6_CLK_PLL_SYS, + IMX6_CLK_PLL_USB, + IMX6_CLK_PLL_AUDIO_VIDEO, + IMX6_CLK_PLL_ENET, +}; + +enum imx6_clk_div_type { + IMX6_CLK_DIV_NORMAL, + IMX6_CLK_DIV_BUSY, + IMX6_CLK_DIV_TABLE, +}; + +enum imx6_clk_mux_type { + IMX6_CLK_MUX_NORMAL, + IMX6_CLK_MUX_BUSY, +}; + +struct imx6_clk_fixed { + u_int rate; +}; + +struct imx6_clk_fixed_factor { + u_int div; + u_int mult; +}; + +struct imx6_clk_pfd { + uint32_t reg; + int index; +}; + +struct imx6_clk_pll { + enum imx6_clk_pll_type type; + uint32_t reg; + uint32_t mask; + uint32_t powerdown; + unsigned long ref; +}; + +struct imx6_clk_div { + enum imx6_clk_div_type type; + enum imx6_clk_reg base; + uint32_t reg; + uint32_t mask; + uint32_t busy_reg; + uint32_t busy_mask; + const int *tbl; +}; + +struct imx6_clk_mux { + enum imx6_clk_mux_type type; + enum imx6_clk_reg base; + uint32_t reg; + uint32_t mask; + const char **parents; + u_int nparents; + uint32_t busy_reg; + uint32_t busy_mask; +}; + +struct imx6_clk_gate { + enum imx6_clk_reg base; + uint32_t reg; + uint32_t mask; + uint32_t exclusive_mask; +}; + +struct imx6_clk { + struct clk base; /* must be first */ + + const char *parent; + u_int refcnt; + + enum imx6_clk_type type; + union { + struct imx6_clk_fixed fixed; + struct imx6_clk_fixed_factor fixed_factor; + struct imx6_clk_pfd pfd; + struct imx6_clk_pll pll; + struct imx6_clk_div div; + struct imx6_clk_mux mux; + struct imx6_clk_gate gate; + } clk; +}; + +#define CLK_FIXED(_name, _rate) { \ + .base = { .name = (_name) }, \ + .type = IMX6_CLK_FIXED, \ + .clk = { \ + .fixed = { \ + .rate = (_rate), \ + } \ + } \ +} + +#define CLK_FIXED_FACTOR(_name, _parent, _div, _mult) { \ + .base = { .name = (_name) }, \ + .type = IMX6_CLK_FIXED_FACTOR, \ + .parent = (_parent), \ + .clk = { \ + .fixed_factor = { \ + .div = (_div), \ + .mult = (_mult), \ + } \ + } \ +} + +#define CLK_PFD(_name, _parent, _reg, _index) { \ + .base = { .name = (_name) }, \ + .type = IMX6_CLK_PFD, \ + .parent = (_parent), \ + .clk = { \ + .pfd = { \ + .reg = (CCM_ANALOG_##_reg), \ + .index = (_index), \ + } \ + } \ +} + +#define CLK_PLL(_name, _parent, _type, _reg, _mask, _powerdown, _ref) { \ + .base = { .name = (_name) }, \ + .type = IMX6_CLK_PLL, \ + .parent = (_parent), \ + .clk = { \ + .pll = { \ + .type = (IMX6_CLK_PLL_##_type), \ + .reg = (CCM_ANALOG_##_reg), \ + .mask = (CCM_ANALOG_##_reg##_##_mask), \ + .powerdown = (CCM_ANALOG_##_reg##_##_powerdown), \ + .ref = (_ref), \ + } \ + } \ +} + +#define CLK_DIV(_name, _parent, _reg, _mask) { \ + .base = { .name = (_name) }, \ + .type = IMX6_CLK_DIV, \ + .parent = (_parent), \ + .clk = { \ + .div = { \ + .type = (IMX6_CLK_DIV_NORMAL), \ + .base = (IMX6_CLK_REG_CCM), \ + .reg = (CCM_##_reg), \ + .mask = (CCM_##_reg##_##_mask), \ + } \ + } \ +} + +#define CLK_DIV_BUSY(_name, _parent, _reg, _mask, _busy_reg, _busy_mask) { \ + .base = { .name = (_name) }, \ + .type = IMX6_CLK_DIV, \ + .parent = (_parent), \ + .clk = { \ + .div = { \ + .type = (IMX6_CLK_DIV_BUSY), \ + .base = (IMX6_CLK_REG_CCM), \ + .reg = (CCM_##_reg), \ + .mask = (CCM_##_reg##_##_mask), \ + .busy_reg = (CCM_##_busy_reg), \ + .busy_mask = (CCM_##_busy_reg##_##_busy_mask) \ + } \ + } \ +} + +#define CLK_DIV_TABLE(_name, _parent, _reg, _mask, _tbl) { \ + .base = { .name = (_name) }, \ + .type = IMX6_CLK_DIV, \ + .parent = (_parent), \ + .clk = { \ + .div = { \ + .type = (IMX6_CLK_DIV_TABLE), \ + .base = (IMX6_CLK_REG_CCM_ANALOG), \ + .reg = (CCM_ANALOG_##_reg), \ + .mask = (CCM_ANALOG_##_reg##_##_mask), \ + .tbl = (_tbl) \ + } \ + } \ +} + +#define CLK_MUX(_name, _parents, _base, _reg, _mask) { \ + .base = { .name = (_name), .flags = CLK_SET_RATE_PARENT }, \ + .type = IMX6_CLK_MUX, \ + .clk = { \ + .mux = { \ + .type = (IMX6_CLK_MUX_NORMAL), \ + .base = (IMX6_CLK_REG_##_base), \ + .reg = (_base##_##_reg), \ + .mask = (_base##_##_reg##_##_mask), \ + .parents = (_parents), \ + .nparents = __arraycount(_parents) \ + } \ + } \ +} + +#define CLK_MUX_BUSY(_name, _parents, _reg, _mask, _busy_reg, _busy_mask) { \ + .base = { .name = (_name), .flags = CLK_SET_RATE_PARENT }, \ + .type = IMX6_CLK_MUX, \ + .clk = { \ + .mux = { \ + .type = (IMX6_CLK_MUX_BUSY), \ + .base = (IMX6_CLK_REG_CCM), \ + .reg = (CCM_##_reg), \ + .mask = (CCM_##_reg##_##_mask), \ + .parents = (_parents), \ + .nparents = __arraycount(_parents), \ + .busy_reg = (CCM_##_busy_reg), \ + .busy_mask = (CCM_##_busy_reg##_##_busy_mask) \ + } \ + } \ +} + +#define CLK_GATE(_name, _parent, _base, _reg, _mask) { \ + .base = { .name = (_name), .flags = CLK_SET_RATE_PARENT }, \ + .type = IMX6_CLK_GATE, \ + .parent = (_parent), \ + .clk = { \ + .gate = { \ + .base = (IMX6_CLK_REG_##_base), \ + .reg = (_base##_##_reg), \ + .mask = (_base##_##_reg##_##_mask), \ + .exclusive_mask = 0 \ + } \ + } \ +} + +#define CLK_GATE_EXCLUSIVE(_name, _parent, _base, _reg, _mask, _exclusive_mask) { \ + .base = { .name = (_name), .flags = CLK_SET_RATE_PARENT }, \ + .type = IMX6_CLK_GATE, \ + .parent = (_parent), \ + .clk = { \ + .gate = { \ + .base = (IMX6_CLK_REG_##_base), \ + .reg = (_base##_##_reg), \ + .mask = (_base##_##_reg##_##_mask), \ + .exclusive_mask = (_base##_##_reg##_##_exclusive_mask) \ + } \ + } \ +} #endif /* _ARM_IMX_IMX6_CCMVAR_H_ */ Index: src/sys/arch/arm/imx/imx6_usb.c diff -u src/sys/arch/arm/imx/imx6_usb.c:1.4 src/sys/arch/arm/imx/imx6_usb.c:1.5 --- src/sys/arch/arm/imx/imx6_usb.c:1.4 Wed May 23 10:42:05 2018 +++ src/sys/arch/arm/imx/imx6_usb.c Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: imx6_usb.c,v 1.4 2018/05/23 10:42:05 hkenken Exp $ */ +/* $NetBSD: imx6_usb.c,v 1.5 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2012 Genetec Corporation. All rights reserved. @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: imx6_usb.c,v 1.4 2018/05/23 10:42:05 hkenken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: imx6_usb.c,v 1.5 2019/06/20 08:16:19 hkenken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -48,31 +48,38 @@ __KERNEL_RCSID(0, "$NetBSD: imx6_usb.c,v #include <arm/imx/imx6var.h> #include <arm/imx/imx6_ccmreg.h> #include <arm/imx/imx6_ccmvar.h> +#include <arm/imx/imx6_usbreg.h> #include <arm/imx/imxusbvar.h> #include "locators.h" static int imxusbc_search(device_t, cfdata_t, const int *, void *); static int imxusbc_print(void *, const char *); +static int imxusbc_init_clocks(struct imxusbc_softc *); int imxusbc_attach_common(device_t parent, device_t self, bus_space_tag_t iot) { struct imxusbc_softc *sc; - uint32_t v; sc = device_private(self); sc->sc_iot = iot; /* Map entire USBOH registers. Host controller drivers * re-use subregions of this. */ - if (bus_space_map(iot, IMX6_AIPS2_BASE + AIPS2_USBOH_BASE, /* XXX */ + if (bus_space_map(iot, IMX6_AIPS2_BASE + AIPS2_USBOH_BASE, AIPS2_USBOH_SIZE, 0, &sc->sc_ioh)) return -1; - /* USBOH3 clock enable */ - v = imx6_ccm_read(CCM_CCGR6); - imx6_ccm_write(CCM_CCGR6, v | __SHIFTIN(3, CCM_CCGR6_USBOH3_CLK_ENABLE)); + sc->sc_clk = imx6_get_clock("usboh3"); + if (sc->sc_clk == NULL) { + aprint_error(": couldn't get clock usboh3\n"); + return -1; + } + if (imxusbc_init_clocks(sc) != 0) { + aprint_error_dev(self, "couldn't init clocks\n"); + return -1; + } /* attach OTG/EHCI host controllers */ config_search_ia(imxusbc_search, self, "imxusbc", NULL); @@ -110,3 +117,18 @@ imxusbc_print(void *aux, const char *nam aprint_normal(" unit %d intr %d", iaa->aa_unit, iaa->aa_irq); return UNCONF; } + +static int +imxusbc_init_clocks(struct imxusbc_softc *sc) +{ + int error; + + error = clk_enable(sc->sc_clk); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable usboh3: %d\n", error); + return error; + } + + return 0; +} + Index: src/sys/arch/arm/imx/imxusbvar.h diff -u src/sys/arch/arm/imx/imxusbvar.h:1.4 src/sys/arch/arm/imx/imxusbvar.h:1.5 --- src/sys/arch/arm/imx/imxusbvar.h:1.4 Tue May 17 06:44:46 2016 +++ src/sys/arch/arm/imx/imxusbvar.h Thu Jun 20 08:16:19 2019 @@ -1,3 +1,30 @@ +/* $NetBSD: imxusbvar.h,v 1.5 2019/06/20 08:16:19 hkenken Exp $ */ +/* + * Copyright (c) 2019 Genetec Corporation. All rights reserved. + * Written by Hashimoto Kenichi for Genetec Corporation. + * + * 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 GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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. + */ + #ifndef _ARM_IMX_IMXUSBVAR_H #define _ARM_IMX_IMXUSBVAR_H @@ -13,6 +40,8 @@ struct imxusbc_softc { bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + struct clk *sc_clk; + /* filled in by platform dependent param & routine */ bus_size_t sc_ehci_size; void (* sc_init_md_hook)(struct imxehci_softc *); Index: src/sys/arch/arm/imx/imx6_usbphy.c diff -u src/sys/arch/arm/imx/imx6_usbphy.c:1.1 src/sys/arch/arm/imx/imx6_usbphy.c:1.2 --- src/sys/arch/arm/imx/imx6_usbphy.c:1.1 Thu Nov 9 05:57:23 2017 +++ src/sys/arch/arm/imx/imx6_usbphy.c Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: imx6_usbphy.c,v 1.1 2017/11/09 05:57:23 hkenken Exp $ */ +/* $NetBSD: imx6_usbphy.c,v 1.2 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2017 Genetec Corporation. All rights reserved. @@ -32,7 +32,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: imx6_usbphy.c,v 1.1 2017/11/09 05:57:23 hkenken Exp $"); +__KERNEL_RCSID(1, "$NetBSD: imx6_usbphy.c,v 1.2 2019/06/20 08:16:19 hkenken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -53,12 +53,15 @@ __KERNEL_RCSID(1, "$NetBSD: imx6_usbphy. #include <arm/imx/imx6_reg.h> #include <arm/imx/imx6var.h> +#include <arm/imx/imx6_ccmvar.h> #include <arm/imx/imx6_usbphyreg.h> struct imx6_usbphy_softc { device_t sc_dev; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; + + struct clk *sc_clk; }; static int imx6_usbphy_match(device_t, cfdata_t, void *); @@ -73,7 +76,7 @@ CFATTACH_DECL_NEW(imxusbphy, sizeof(stru bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) static int -imx6_usbphy_enable(device_t dev, void *priv, bool enable) +imx6_usbphy_enable(device_t dev, bool enable) { struct imx6_usbphy_softc * const sc = device_private(dev); @@ -99,6 +102,20 @@ imx6_usbphy_enable(device_t dev, void *p } static int +imx6_usbphy_init_clocks(device_t dev) +{ + struct imx6_usbphy_softc * const sc = device_private(dev); + + int error = clk_enable(sc->sc_clk); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't enable: %d\n", error); + return error; + } + + return 0; +} + +static int imx6_usbphy_match(device_t parent, cfdata_t cf, void *aux) { struct axi_attach_args *aa = aux; @@ -132,8 +149,18 @@ imx6_usbphy_attach(device_t parent, devi return; } + switch (device_unit(self)) { + case 0: + sc->sc_clk = imx6_get_clock("usbphy1"); + break; + case 1: + sc->sc_clk = imx6_get_clock("usbphy2"); + break; + } + aprint_naive("\n"); aprint_normal(": USB PHY\n"); - imx6_usbphy_enable(self, NULL, true); + imx6_usbphy_init_clocks(self); + imx6_usbphy_enable(self, true); } Index: src/sys/arch/arm/imx/imx6_usdhc.c diff -u src/sys/arch/arm/imx/imx6_usdhc.c:1.6 src/sys/arch/arm/imx/imx6_usdhc.c:1.7 --- src/sys/arch/arm/imx/imx6_usdhc.c:1.6 Wed May 23 10:42:05 2018 +++ src/sys/arch/arm/imx/imx6_usdhc.c Thu Jun 20 08:16:19 2019 @@ -1,5 +1,4 @@ -/* $NetBSD: imx6_usdhc.c,v 1.6 2018/05/23 10:42:05 hkenken Exp $ */ - +/* $NetBSD: imx6_usdhc.c,v 1.7 2019/06/20 08:16:19 hkenken Exp $ */ /*- * Copyright (c) 2012 Genetec Corporation. All rights reserved. * Written by Hiroyuki Bessho for Genetec Corporation. @@ -28,9 +27,8 @@ * SUCH DAMAGE. */ - #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: imx6_usdhc.c,v 1.6 2018/05/23 10:42:05 hkenken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: imx6_usdhc.c,v 1.7 2019/06/20 08:16:19 hkenken Exp $"); #include "imxgpio.h" @@ -53,19 +51,23 @@ __KERNEL_RCSID(0, "$NetBSD: imx6_usdhc.c #include <arm/imx/imx6_ccmreg.h> #include <arm/imx/imxgpiovar.h> - struct sdhc_axi_softc { struct sdhc_softc sc_sdhc; + /* we have only one slot */ struct sdhc_host *sc_hosts[1]; int32_t sc_gpio_cd; int32_t sc_gpio_cd_active; + void *sc_ih; + + struct clk *sc_clk; }; static int sdhc_match(device_t, cfdata_t, void *); static void sdhc_attach(device_t, device_t, void *); static int imx6_sdhc_card_detect(struct sdhc_softc *); +static int imx6_sdhc_init_clocks(struct sdhc_axi_softc *); CFATTACH_DECL_NEW(sdhc_axi, sizeof(struct sdhc_axi_softc), sdhc_match, sdhc_attach, NULL, NULL); @@ -89,25 +91,6 @@ sdhc_match(device_t parent, cfdata_t cf, return 0; } -static int -imx6_sdhc_card_detect(struct sdhc_softc *ssc) -{ - int detect; -#if NIMXGPIO > 0 - struct sdhc_axi_softc *sc; - - sc = device_private(ssc->sc_dev); - if (sc->sc_gpio_cd >= 0) { - detect = gpio_data_read(sc->sc_gpio_cd); - if (sc->sc_gpio_cd_active == GPIO_PIN_LOW) - detect = !detect; - } else -#endif - detect = 1; - - return detect; -} - static void sdhc_attach(device_t parent, device_t self, void *aux) { @@ -115,7 +98,6 @@ sdhc_attach(device_t parent, device_t se struct axi_attach_args *aa = aux; bus_space_tag_t iot = aa->aa_iot; bus_space_handle_t ioh; - u_int perclk = 0, v; sc->sc_sdhc.sc_dev = self; sc->sc_sdhc.sc_dmat = aa->aa_dmat; @@ -131,36 +113,37 @@ sdhc_attach(device_t parent, device_t se switch (aa->aa_addr) { case IMX6_AIPS2_BASE + AIPS2_USDHC1_BASE: - v = imx6_ccm_read(CCM_CCGR6); - imx6_ccm_write(CCM_CCGR6, v | __SHIFTIN(3, CCM_CCGR6_USDHC1_CLK_ENABLE)); - perclk = imx6_get_clock(IMX6CLK_USDHC1); + sc->sc_clk = imx6_get_clock("usdhc1"); imx6_set_gpio(self, "usdhc1-cd-gpio", &sc->sc_gpio_cd, &sc->sc_gpio_cd_active, GPIO_DIR_IN); break; case IMX6_AIPS2_BASE + AIPS2_USDHC2_BASE: - v = imx6_ccm_read(CCM_CCGR6); - imx6_ccm_write(CCM_CCGR6, v | __SHIFTIN(3, CCM_CCGR6_USDHC2_CLK_ENABLE)); - perclk = imx6_get_clock(IMX6CLK_USDHC2); + sc->sc_clk = imx6_get_clock("usdhc2"); imx6_set_gpio(self, "usdhc2-cd-gpio", &sc->sc_gpio_cd, &sc->sc_gpio_cd_active, GPIO_DIR_IN); break; case IMX6_AIPS2_BASE + AIPS2_USDHC3_BASE: - v = imx6_ccm_read(CCM_CCGR6); - imx6_ccm_write(CCM_CCGR6, v | __SHIFTIN(3, CCM_CCGR6_USDHC3_CLK_ENABLE)); - perclk = imx6_get_clock(IMX6CLK_USDHC3); + sc->sc_clk = imx6_get_clock("usdhc3"); imx6_set_gpio(self, "usdhc3-cd-gpio", &sc->sc_gpio_cd, &sc->sc_gpio_cd_active, GPIO_DIR_IN); break; case IMX6_AIPS2_BASE + AIPS2_USDHC4_BASE: - v = imx6_ccm_read(CCM_CCGR6); - imx6_ccm_write(CCM_CCGR6, v | __SHIFTIN(3, CCM_CCGR6_USDHC4_CLK_ENABLE)); - perclk = imx6_get_clock(IMX6CLK_USDHC4); + sc->sc_clk = imx6_get_clock("usdhc4"); imx6_set_gpio(self, "usdhc4-cd-gpio", &sc->sc_gpio_cd, &sc->sc_gpio_cd_active, GPIO_DIR_IN); break; } - sc->sc_sdhc.sc_clkbase = perclk / 1000; + if (sc->sc_clk == NULL) { + aprint_error(": couldn't get clock usdhc\n"); + return; + } + if (imx6_sdhc_init_clocks(sc) != 0) { + aprint_error_dev(self, "couldn't init clocks\n"); + return; + } + + sc->sc_sdhc.sc_clkbase = clk_get_rate(sc->sc_clk) / 1000; sc->sc_sdhc.sc_flags |= SDHC_FLAG_USE_DMA | SDHC_FLAG_NO_PWR0 | @@ -189,3 +172,36 @@ sdhc_attach(device_t parent, device_t se aprint_error_dev(self, "can't establish power hook\n"); } } + +static int +imx6_sdhc_card_detect(struct sdhc_softc *ssc) +{ + int detect; +#if NIMXGPIO > 0 + struct sdhc_axi_softc *sc; + + sc = device_private(ssc->sc_dev); + if (sc->sc_gpio_cd >= 0) { + detect = gpio_data_read(sc->sc_gpio_cd); + if (sc->sc_gpio_cd_active == GPIO_PIN_LOW) + detect = !detect; + } else +#endif + detect = 1; + + return detect; +} + +static int +imx6_sdhc_init_clocks(struct sdhc_axi_softc *sc) +{ + int error; + + error = clk_enable(sc->sc_clk); + if (error) { + aprint_error_dev(sc->sc_sdhc.sc_dev, "couldn't enable: %d\n", error); + return error; + } + + return 0; +} Index: src/sys/arch/evbarm/nitrogen6/nitrogen6_usb.c diff -u src/sys/arch/evbarm/nitrogen6/nitrogen6_usb.c:1.4 src/sys/arch/evbarm/nitrogen6/nitrogen6_usb.c:1.5 --- src/sys/arch/evbarm/nitrogen6/nitrogen6_usb.c:1.4 Wed Jun 20 07:05:37 2018 +++ src/sys/arch/evbarm/nitrogen6/nitrogen6_usb.c Thu Jun 20 08:16:19 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: nitrogen6_usb.c,v 1.4 2018/06/20 07:05:37 hkenken Exp $ */ +/* $NetBSD: nitrogen6_usb.c,v 1.5 2019/06/20 08:16:19 hkenken Exp $ */ /* * Copyright (c) 2013 Genetec Corporation. All rights reserved. @@ -27,7 +27,7 @@ * */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nitrogen6_usb.c,v 1.4 2018/06/20 07:05:37 hkenken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nitrogen6_usb.c,v 1.5 2019/06/20 08:16:19 hkenken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -123,18 +123,6 @@ init_otg(struct imxehci_softc *sc) sc->sc_iftype = IMXUSBC_IF_UTMI_WIDE; - /* USB1 power */ - imx6_ccm_analog_write(USB_ANALOG_USB1_CHRG_DETECT, - USB_ANALOG_USB_CHRG_DETECT_EN_B | - USB_ANALOG_USB_CHRG_DETECT_CHK_CHRG_B); - imx6_pll_power(CCM_ANALOG_PLL_USB1, 1, CCM_ANALOG_PLL_ENABLE); - imx6_ccm_analog_write(CCM_ANALOG_PLL_USB1_CLR, - CCM_ANALOG_PLL_BYPASS); - imx6_ccm_analog_write(CCM_ANALOG_PLL_USB1_SET, - CCM_ANALOG_PLL_ENABLE | - CCM_ANALOG_PLL_POWER | - CCM_ANALOG_PLL_EN_USB_CLK); - imxehci_reset(sc); v = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBNC_USB_OTG_CTRL); @@ -153,16 +141,6 @@ init_h1(struct imxehci_softc *sc) sc->sc_iftype = IMXUSBC_IF_UTMI_WIDE; - imx6_ccm_analog_write(USB_ANALOG_USB2_CHRG_DETECT, - USB_ANALOG_USB_CHRG_DETECT_EN_B | - USB_ANALOG_USB_CHRG_DETECT_CHK_CHRG_B); - imx6_ccm_analog_write(CCM_ANALOG_PLL_USB2_CLR, - CCM_ANALOG_PLL_BYPASS); - imx6_ccm_analog_write(CCM_ANALOG_PLL_USB2_SET, - CCM_ANALOG_PLL_ENABLE | - CCM_ANALOG_PLL_POWER | - CCM_ANALOG_PLL_EN_USB_CLK); - v = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBNC_USB_UH1_CTRL); v |= USBNC_USB_UH1_CTRL_OVER_CUR_POL; v |= USBNC_USB_UH1_CTRL_OVER_CUR_DIS;