1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 /* 32 * Clocks driver for Freescale i.MX8MQ SoC 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/mutex.h> 40 #include <sys/bus.h> 41 #include <sys/rman.h> 42 43 #include <dev/ofw/ofw_bus.h> 44 #include <dev/ofw/ofw_bus_subr.h> 45 46 #include <machine/bus.h> 47 48 #include <arm64/freescale/imx/imx_ccm_clk.h> 49 #include <arm64/freescale/imx/imx8mq_ccm.h> 50 #include <arm64/freescale/imx/clk/imx_clk_gate.h> 51 #include <arm64/freescale/imx/clk/imx_clk_mux.h> 52 #include <arm64/freescale/imx/clk/imx_clk_composite.h> 53 #include <arm64/freescale/imx/clk/imx_clk_sscg_pll.h> 54 #include <arm64/freescale/imx/clk/imx_clk_frac_pll.h> 55 56 #include "clkdev_if.h" 57 58 static const char *pll_ref_p[] = { 59 "osc_25m", "osc_27m", "dummy", "dummy" 60 }; 61 static const char *sys3_pll_out_p[] = { 62 "sys3_pll1_ref_sel" 63 }; 64 static const char * arm_pll_bypass_p[] = { 65 "arm_pll", "arm_pll_ref_sel" 66 }; 67 static const char * gpu_pll_bypass_p[] = { 68 "gpu_pll", "gpu_pll_ref_sel" 69 }; 70 static const char * vpu_pll_bypass_p[] = { 71 "vpu_pll", "vpu_pll_ref_sel" 72 }; 73 static const char * audio_pll1_bypass_p[] = { 74 "audio_pll1", "audio_pll1_ref_sel" 75 }; 76 static const char * audio_pll2_bypass_p[] = { 77 "audio_pll2", "audio_pll2_ref_sel" 78 }; 79 static const char * video_pll1_bypass_p[] = { 80 "video_pll1", "video_pll1_ref_sel" 81 }; 82 static const char *uart_p[] = { 83 "osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m", "sys3_pll_out", 84 "clk_ext2", "clk_ext4", "audio_pll2_out" 85 }; 86 static const char *usdhc_p[] = { 87 "osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m", "audio_pll2_out", 88 "sys1_pll_266m", "sys3_pll_out", "sys1_pll_100m" 89 }; 90 static const char *enet_axi_p[] = { 91 "osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m", "sys2_pll_200m", 92 "audio_pll1_out", "video_pll1_out", "sys3_pll_out" 93 }; 94 static const char *enet_ref_p[] = { 95 "osc_25m", "sys2_pll_125m", "sys2_pll_500m", "sys2_pll_100m", "sys1_pll_160m", 96 "audio_pll1_out", "video_pll1_out", "clk_ext4" 97 }; 98 static const char *enet_timer_p[] = { 99 "osc_25m", "sys2_pll_100m", "audio_pll1_out", "clk_ext1", "clk_ext2", "clk_ext3", 100 "clk_ext4", "video_pll1_out" 101 }; 102 static const char *enet_phy_ref_p[] = { 103 "osc_25m", "sys2_pll_50m", "sys2_pll_125m", "sys2_pll_500m", "audio_pll1_out", 104 "video_pll1_out", "audio_pll2_out" 105 }; 106 static const char *usb_bus_p[] = { 107 "osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_100m", "sys2_pll_200m", 108 "clk_ext2", "clk_ext4", "audio_pll2_out" 109 }; 110 static const char *usb_core_phy_p[] = { 111 "osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m", "sys2_pll_200m", 112 "clk_ext2", "clk_ext3", "audio_pll2_out" 113 }; 114 static const char *i2c_p[] = { 115 "osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll_out", "audio_pll1_out", 116 "video_pll1_out", "audio_pll2_out", "sys1_pll_133m" 117 }; 118 static const char *ahb_p[] = { 119 "osc_25m", "sys1_pll_133m", "sys1_pll_800m", "sys1_pll_400m", "sys2_pll_125m", 120 "sys3_pll_out", "audio_pll1_out", "video_pll1_out" 121 }; 122 123 static struct imx_clk imx_clks[] = { 124 FIXED(IMX8MQ_CLK_DUMMY, "dummy", 0), 125 126 LINK(IMX8MQ_CLK_32K, "ckil"), 127 LINK(IMX8MQ_CLK_25M, "osc_25m"), 128 LINK(IMX8MQ_CLK_27M, "osc_27m"), 129 LINK(IMX8MQ_CLK_EXT1, "clk_ext1"), 130 LINK(IMX8MQ_CLK_EXT2, "clk_ext2"), 131 LINK(IMX8MQ_CLK_EXT3, "clk_ext3"), 132 LINK(IMX8MQ_CLK_EXT4, "clk_ext4"), 133 134 FIXED(IMX8MQ_SYS1_PLL_OUT, "sys1_pll_out", 800000000), 135 FIXED(IMX8MQ_SYS2_PLL_OUT, "sys2_pll_out", 1000000000), 136 SSCG_PLL(IMX8MQ_SYS3_PLL_OUT, "sys3_pll_out", sys3_pll_out_p, 0x48), 137 138 MUX(IMX8MQ_ARM_PLL_REF_SEL, "arm_pll_ref_sel", pll_ref_p, 0, 0x28, 16, 2), 139 MUX(IMX8MQ_GPU_PLL_REF_SEL, "gpu_pll_ref_sel", pll_ref_p, 0, 0x18, 16, 2), 140 MUX(IMX8MQ_VPU_PLL_REF_SEL, "vpu_pll_ref_sel", pll_ref_p, 0, 0x20, 16, 2), 141 MUX(IMX8MQ_AUDIO_PLL1_REF_SEL, "audio_pll1_ref_sel", pll_ref_p, 0, 0x0, 16, 2), 142 MUX(IMX8MQ_AUDIO_PLL2_REF_SEL, "audio_pll2_ref_sel", pll_ref_p, 0, 0x8, 16, 2), 143 MUX(IMX8MQ_VIDEO_PLL1_REF_SEL, "video_pll1_ref_sel", pll_ref_p, 0, 0x10, 16, 2), 144 MUX(IMX8MQ_SYS3_PLL1_REF_SEL, "sys3_pll1_ref_sel", pll_ref_p, 0, 0x48, 0, 2), 145 MUX(IMX8MQ_DRAM_PLL1_REF_SEL, "dram_pll1_ref_sel", pll_ref_p, 0, 0x60, 0, 2), 146 MUX(IMX8MQ_VIDEO2_PLL1_REF_SEL, "video2_pll1_ref_sel", pll_ref_p, 0, 0x54, 0, 2), 147 148 DIV(IMX8MQ_ARM_PLL_REF_DIV, "arm_pll_ref_div", "arm_pll_ref_sel", 0x28, 5, 6), 149 DIV(IMX8MQ_GPU_PLL_REF_DIV, "gpu_pll_ref_div", "gpu_pll_ref_sel", 0x18, 5, 6), 150 DIV(IMX8MQ_VPU_PLL_REF_DIV, "vpu_pll_ref_div", "vpu_pll_ref_sel", 0x20, 5, 6), 151 DIV(IMX8MQ_AUDIO_PLL1_REF_DIV, "audio_pll1_ref_div", "audio_pll1_ref_sel", 0x0, 5, 6), 152 DIV(IMX8MQ_AUDIO_PLL2_REF_DIV, "audio_pll2_ref_div", "audio_pll2_ref_sel", 0x8, 5, 6), 153 DIV(IMX8MQ_VIDEO_PLL1_REF_DIV, "video_pll1_ref_div", "video_pll1_ref_sel", 0x10, 5, 6), 154 155 FRAC_PLL(IMX8MQ_ARM_PLL, "arm_pll", "arm_pll_ref_div", 0x28), 156 FRAC_PLL(IMX8MQ_GPU_PLL, "gpu_pll", "gpu_pll_ref_div", 0x18), 157 FRAC_PLL(IMX8MQ_VPU_PLL, "vpu_pll", "vpu_pll_ref_div", 0x20), 158 FRAC_PLL(IMX8MQ_AUDIO_PLL1, "audio_pll1", "audio_pll1_ref_div", 0x0), 159 FRAC_PLL(IMX8MQ_AUDIO_PLL2, "audio_pll2", "audio_pll2_ref_div", 0x8), 160 FRAC_PLL(IMX8MQ_VIDEO_PLL1, "video_pll1", "video_pll1_ref_div", 0x10), 161 162 /* ARM_PLL needs SET_PARENT flag */ 163 MUX(IMX8MQ_ARM_PLL_BYPASS, "arm_pll_bypass", arm_pll_bypass_p, 0, 0x28, 14, 1), 164 MUX(IMX8MQ_GPU_PLL_BYPASS, "gpu_pll_bypass", gpu_pll_bypass_p, 0, 0x18, 14, 1), 165 MUX(IMX8MQ_VPU_PLL_BYPASS, "vpu_pll_bypass", vpu_pll_bypass_p, 0, 0x20, 14, 1), 166 MUX(IMX8MQ_AUDIO_PLL1_BYPASS, "audio_pll1_bypass", audio_pll1_bypass_p, 0, 0x0, 14, 1), 167 MUX(IMX8MQ_AUDIO_PLL2_BYPASS, "audio_pll2_bypass", audio_pll2_bypass_p, 0, 0x8, 14, 1), 168 MUX(IMX8MQ_VIDEO_PLL1_BYPASS, "video_pll1_bypass", video_pll1_bypass_p, 0, 0x10, 14, 1), 169 170 GATE(IMX8MQ_ARM_PLL_OUT, "arm_pll_out", "arm_pll_bypass", 0x28, 21), 171 GATE(IMX8MQ_GPU_PLL_OUT, "gpu_pll_out", "gpu_pll_bypass", 0x18, 21), 172 GATE(IMX8MQ_VPU_PLL_OUT, "vpu_pll_out", "vpu_pll_bypass", 0x20, 21), 173 GATE(IMX8MQ_AUDIO_PLL1_OUT, "audio_pll1_out", "audio_pll1_bypass", 0x0, 21), 174 GATE(IMX8MQ_AUDIO_PLL2_OUT, "audio_pll2_out", "audio_pll2_bypass", 0x8, 21), 175 GATE(IMX8MQ_VIDEO_PLL1_OUT, "video_pll1_out", "video_pll1_bypass", 0x10, 21), 176 177 GATE(IMX8MQ_SYS1_PLL_40M_CG, "sys1_pll_40m_cg", "sys1_pll_out", 0x30, 9), 178 GATE(IMX8MQ_SYS1_PLL_80M_CG, "sys1_pll_80m_cg", "sys1_pll_out", 0x30, 11), 179 GATE(IMX8MQ_SYS1_PLL_100M_CG, "sys1_pll_100m_cg", "sys1_pll_out", 0x30, 13), 180 GATE(IMX8MQ_SYS1_PLL_133M_CG, "sys1_pll_133m_cg", "sys1_pll_out", 0x30, 15), 181 GATE(IMX8MQ_SYS1_PLL_160M_CG, "sys1_pll_160m_cg", "sys1_pll_out", 0x30, 17), 182 GATE(IMX8MQ_SYS1_PLL_200M_CG, "sys1_pll_200m_cg", "sys1_pll_out", 0x30, 19), 183 GATE(IMX8MQ_SYS1_PLL_266M_CG, "sys1_pll_266m_cg", "sys1_pll_out", 0x30, 21), 184 GATE(IMX8MQ_SYS1_PLL_400M_CG, "sys1_pll_400m_cg", "sys1_pll_out", 0x30, 23), 185 GATE(IMX8MQ_SYS1_PLL_800M_CG, "sys1_pll_800m_cg", "sys1_pll_out", 0x30, 25), 186 187 FFACT(IMX8MQ_SYS1_PLL_40M, "sys1_pll_40m", "sys1_pll_40m_cg", 1, 20), 188 FFACT(IMX8MQ_SYS1_PLL_80M, "sys1_pll_80m", "sys1_pll_80m_cg", 1, 10), 189 FFACT(IMX8MQ_SYS1_PLL_100M, "sys1_pll_100m", "sys1_pll_100m_cg", 1, 8), 190 FFACT(IMX8MQ_SYS1_PLL_133M, "sys1_pll_133m", "sys1_pll_133m_cg", 1, 6), 191 FFACT(IMX8MQ_SYS1_PLL_160M, "sys1_pll_160m", "sys1_pll_160m_cg", 1, 5), 192 FFACT(IMX8MQ_SYS1_PLL_200M, "sys1_pll_200m", "sys1_pll_200m_cg", 1, 4), 193 FFACT(IMX8MQ_SYS1_PLL_266M, "sys1_pll_266m", "sys1_pll_266m_cg", 1, 3), 194 FFACT(IMX8MQ_SYS1_PLL_400M, "sys1_pll_400m", "sys1_pll_400m_cg", 1, 2), 195 FFACT(IMX8MQ_SYS1_PLL_800M, "sys1_pll_800m", "sys1_pll_800m_cg", 1, 1), 196 197 GATE(IMX8MQ_SYS2_PLL_50M_CG, "sys2_pll_50m_cg", "sys2_pll_out", 0x3c, 9), 198 GATE(IMX8MQ_SYS2_PLL_100M_CG, "sys2_pll_100m_cg", "sys2_pll_out", 0x3c, 11), 199 GATE(IMX8MQ_SYS2_PLL_125M_CG, "sys2_pll_125m_cg", "sys2_pll_out", 0x3c, 13), 200 GATE(IMX8MQ_SYS2_PLL_166M_CG, "sys2_pll_166m_cg", "sys2_pll_out", 0x3c, 15), 201 GATE(IMX8MQ_SYS2_PLL_200M_CG, "sys2_pll_200m_cg", "sys2_pll_out", 0x3c, 17), 202 GATE(IMX8MQ_SYS2_PLL_250M_CG, "sys2_pll_250m_cg", "sys2_pll_out", 0x3c, 19), 203 GATE(IMX8MQ_SYS2_PLL_333M_CG, "sys2_pll_333m_cg", "sys2_pll_out", 0x3c, 21), 204 GATE(IMX8MQ_SYS2_PLL_500M_CG, "sys2_pll_500m_cg", "sys2_pll_out", 0x3c, 23), 205 GATE(IMX8MQ_SYS2_PLL_1000M_CG, "sys2_pll_1000m_cg", "sys2_pll_out", 0x3c, 25), 206 207 FFACT(IMX8MQ_SYS2_PLL_50M, "sys2_pll_50m", "sys2_pll_50m_cg", 1, 20), 208 FFACT(IMX8MQ_SYS2_PLL_100M, "sys2_pll_100m", "sys2_pll_100m_cg", 1, 10), 209 FFACT(IMX8MQ_SYS2_PLL_125M, "sys2_pll_125m", "sys2_pll_125m_cg", 1, 8), 210 FFACT(IMX8MQ_SYS2_PLL_166M, "sys2_pll_166m", "sys2_pll_166m_cg", 1, 6), 211 FFACT(IMX8MQ_SYS2_PLL_200M, "sys2_pll_200m", "sys2_pll_200m_cg", 1, 5), 212 FFACT(IMX8MQ_SYS2_PLL_250M, "sys2_pll_250m", "sys2_pll_250m_cg", 1, 4), 213 FFACT(IMX8MQ_SYS2_PLL_333M, "sys2_pll_333m", "sys2_pll_333m_cg", 1, 3), 214 FFACT(IMX8MQ_SYS2_PLL_500M, "sys2_pll_500m", "sys2_pll_500m_cg", 1, 2), 215 FFACT(IMX8MQ_SYS2_PLL_1000M, "sys2_pll_1000m", "sys2_pll_1000m_cg", 1, 1), 216 217 COMPOSITE(IMX8MQ_CLK_AHB, "ahb", ahb_p, 0x9000, 0), 218 DIV(IMX8MQ_CLK_IPG_ROOT, "ipg_root", "ahb", 0x9080, 0, 1), 219 220 COMPOSITE(IMX8MQ_CLK_UART1, "uart1", uart_p, 0xaf00, 0), 221 COMPOSITE(IMX8MQ_CLK_UART2, "uart2", uart_p, 0xaf80, 0), 222 COMPOSITE(IMX8MQ_CLK_UART3, "uart3", uart_p, 0xb000, 0), 223 COMPOSITE(IMX8MQ_CLK_UART4, "uart4", uart_p, 0xb080, 0), 224 225 ROOT_GATE(IMX8MQ_CLK_UART1_ROOT, "uart1_root_clk", "uart1", 0x4490), 226 ROOT_GATE(IMX8MQ_CLK_UART2_ROOT, "uart2_root_clk", "uart2", 0x44a0), 227 ROOT_GATE(IMX8MQ_CLK_UART3_ROOT, "uart3_root_clk", "uart3", 0x44b0), 228 ROOT_GATE(IMX8MQ_CLK_UART4_ROOT, "uart4_root_clk", "uart4", 0x44c0), 229 230 COMPOSITE(IMX8MQ_CLK_USDHC1, "usdhc1", usdhc_p, 0xac00, CLK_SET_ROUND_DOWN), 231 COMPOSITE(IMX8MQ_CLK_USDHC2, "usdhc2", usdhc_p, 0xac80, CLK_SET_ROUND_DOWN), 232 233 ROOT_GATE(IMX8MQ_CLK_USDHC1_ROOT, "usdhc1_root_clk", "usdhc1", 0x4510), 234 ROOT_GATE(IMX8MQ_CLK_USDHC2_ROOT, "usdhc2_root_clk", "usdhc2", 0x4520), 235 236 ROOT_GATE(IMX8MQ_CLK_TMU_ROOT, "tmu_root_clk", "ipg_root", 0x4620), 237 238 COMPOSITE(IMX8MQ_CLK_ENET_AXI, "enet_axi", enet_axi_p, 0x8800, 0), 239 COMPOSITE(IMX8MQ_CLK_ENET_REF, "enet_ref", enet_ref_p, 0xa980, 0), 240 COMPOSITE(IMX8MQ_CLK_ENET_TIMER, "enet_timer", enet_timer_p, 0xaa00, 0), 241 COMPOSITE(IMX8MQ_CLK_ENET_PHY_REF, "enet_phy_ref", enet_phy_ref_p, 0xaa80, 0), 242 243 ROOT_GATE(IMX8MQ_CLK_ENET1_ROOT, "enet1_root_clk", "enet_axi", 0x40a0), 244 245 COMPOSITE(IMX8MQ_CLK_USB_BUS, "usb_bus", usb_bus_p, 0x8b80, 0), 246 COMPOSITE(IMX8MQ_CLK_USB_CORE_REF, "usb_core_ref", usb_core_phy_p, 0xb100, 0), 247 COMPOSITE(IMX8MQ_CLK_USB_PHY_REF, "usb_phy_ref", usb_core_phy_p, 0xb180, 0), 248 249 ROOT_GATE(IMX8MQ_CLK_USB1_CTRL_ROOT, "usb1_ctrl_root_clk", "usb_bus", 0x44d0), 250 ROOT_GATE(IMX8MQ_CLK_USB2_CTRL_ROOT, "usb2_ctrl_root_clk", "usb_bus", 0x44e0), 251 ROOT_GATE(IMX8MQ_CLK_USB1_PHY_ROOT, "usb1_phy_root_clk", "usb_phy_ref", 0x44f0), 252 ROOT_GATE(IMX8MQ_CLK_USB2_PHY_ROOT, "usb2_phy_root_clk", "usb_phy_ref", 0x4500), 253 254 COMPOSITE(IMX8MQ_CLK_I2C1, "i2c1", i2c_p, 0xad00, 0), 255 COMPOSITE(IMX8MQ_CLK_I2C2, "i2c2", i2c_p, 0xad80, 0), 256 COMPOSITE(IMX8MQ_CLK_I2C3, "i2c3", i2c_p, 0xae00, 0), 257 COMPOSITE(IMX8MQ_CLK_I2C4, "i2c4", i2c_p, 0xae80, 0), 258 259 ROOT_GATE(IMX8MQ_CLK_I2C1_ROOT, "i2c1_root_clk", "i2c1", 0x4170), 260 ROOT_GATE(IMX8MQ_CLK_I2C2_ROOT, "i2c2_root_clk", "i2c2", 0x4180), 261 ROOT_GATE(IMX8MQ_CLK_I2C3_ROOT, "i2c3_root_clk", "i2c3", 0x4190), 262 ROOT_GATE(IMX8MQ_CLK_I2C4_ROOT, "i2c4_root_clk", "i2c4", 0x41a0), 263 264 ROOT_GATE(IMX8MQ_CLK_GPIO1_ROOT, "gpio1_root_clk", "ipg_root", 0x40b0), 265 ROOT_GATE(IMX8MQ_CLK_GPIO2_ROOT, "gpio2_root_clk", "ipg_root", 0x40c0), 266 ROOT_GATE(IMX8MQ_CLK_GPIO3_ROOT, "gpio3_root_clk", "ipg_root", 0x40d0), 267 ROOT_GATE(IMX8MQ_CLK_GPIO4_ROOT, "gpio4_root_clk", "ipg_root", 0x40e0), 268 ROOT_GATE(IMX8MQ_CLK_GPIO5_ROOT, "gpio5_root_clk", "ipg_root", 0x40f0), 269 }; 270 271 struct ccm_softc { 272 device_t dev; 273 struct resource *mem_res; 274 struct clkdom *clkdom; 275 struct mtx mtx; 276 struct imx_clk *clks; 277 int nclks; 278 }; 279 280 static inline uint32_t 281 CCU_READ4(struct ccm_softc *sc, bus_size_t off) 282 { 283 284 return (bus_read_4(sc->mem_res, off)); 285 } 286 287 static inline void 288 CCU_WRITE4(struct ccm_softc *sc, bus_size_t off, uint32_t val) 289 { 290 291 bus_write_4(sc->mem_res, off, val); 292 } 293 294 static int 295 ccm_detach(device_t dev) 296 { 297 struct ccm_softc *sc; 298 299 sc = device_get_softc(dev); 300 301 if (sc->mem_res != NULL) 302 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 303 304 return (0); 305 } 306 307 static int 308 ccm_attach(device_t dev) 309 { 310 struct ccm_softc *sc; 311 int err, rid; 312 phandle_t node; 313 int i; 314 315 sc = device_get_softc(dev); 316 err = 0; 317 318 /* Allocate bus_space resources. */ 319 rid = 0; 320 sc->clks = imx_clks; 321 sc->nclks = nitems(imx_clks); 322 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 323 RF_ACTIVE); 324 if (sc->mem_res == NULL) { 325 device_printf(dev, "Cannot allocate memory resources\n"); 326 err = ENXIO; 327 goto out; 328 } 329 330 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 331 332 sc->clkdom = clkdom_create(dev); 333 if (sc->clkdom == NULL) 334 panic("Cannot create clkdom\n"); 335 336 for (i = 0; i < sc->nclks; i++) { 337 switch (sc->clks[i].type) { 338 case IMX_CLK_UNDEFINED: 339 break; 340 case IMX_CLK_LINK: 341 clknode_link_register(sc->clkdom, 342 sc->clks[i].clk.link); 343 break; 344 case IMX_CLK_FIXED: 345 clknode_fixed_register(sc->clkdom, 346 sc->clks[i].clk.fixed); 347 break; 348 case IMX_CLK_MUX: 349 imx_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux); 350 break; 351 case IMX_CLK_GATE: 352 imx_clk_gate_register(sc->clkdom, sc->clks[i].clk.gate); 353 break; 354 case IMX_CLK_COMPOSITE: 355 imx_clk_composite_register(sc->clkdom, sc->clks[i].clk.composite); 356 break; 357 case IMX_CLK_SSCG_PLL: 358 imx_clk_sscg_pll_register(sc->clkdom, sc->clks[i].clk.sscg_pll); 359 break; 360 case IMX_CLK_FRAC_PLL: 361 imx_clk_frac_pll_register(sc->clkdom, sc->clks[i].clk.frac_pll); 362 break; 363 case IMX_CLK_DIV: 364 clknode_div_register(sc->clkdom, sc->clks[i].clk.div); 365 break; 366 default: 367 device_printf(dev, "Unknown clock type %d\n", sc->clks[i].type); 368 return (ENXIO); 369 } 370 } 371 372 if (clkdom_finit(sc->clkdom) != 0) 373 panic("cannot finalize clkdom initialization\n"); 374 375 if (bootverbose) 376 clkdom_dump(sc->clkdom); 377 378 node = ofw_bus_get_node(dev); 379 clk_set_assigned(dev, node); 380 381 err = 0; 382 383 out: 384 385 if (err != 0) 386 ccm_detach(dev); 387 388 return (err); 389 } 390 391 static int 392 ccm_probe(device_t dev) 393 { 394 395 if (!ofw_bus_status_okay(dev)) 396 return (ENXIO); 397 398 if (ofw_bus_is_compatible(dev, "fsl,imx8mq-ccm") == 0) 399 return (ENXIO); 400 401 device_set_desc(dev, "Freescale i.MX8 Clock Control Module"); 402 403 return (BUS_PROBE_DEFAULT); 404 } 405 406 static int 407 imx_ccm_write_4(device_t dev, bus_addr_t addr, uint32_t val) 408 { 409 struct ccm_softc *sc; 410 411 sc = device_get_softc(dev); 412 CCU_WRITE4(sc, addr, val); 413 return (0); 414 } 415 416 static int 417 imx_ccm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) 418 { 419 struct ccm_softc *sc; 420 421 sc = device_get_softc(dev); 422 423 *val = CCU_READ4(sc, addr); 424 return (0); 425 } 426 427 static int 428 imx_ccm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) 429 { 430 struct ccm_softc *sc; 431 uint32_t reg; 432 433 sc = device_get_softc(dev); 434 435 reg = CCU_READ4(sc, addr); 436 reg &= ~clr; 437 reg |= set; 438 CCU_WRITE4(sc, addr, reg); 439 440 return (0); 441 } 442 443 static void 444 imx_ccm_device_lock(device_t dev) 445 { 446 struct ccm_softc *sc; 447 448 sc = device_get_softc(dev); 449 mtx_lock(&sc->mtx); 450 } 451 452 static void 453 imx_ccm_device_unlock(device_t dev) 454 { 455 struct ccm_softc *sc; 456 457 sc = device_get_softc(dev); 458 mtx_unlock(&sc->mtx); 459 } 460 461 static device_method_t ccm_methods[] = { 462 /* Device interface */ 463 DEVMETHOD(device_probe, ccm_probe), 464 DEVMETHOD(device_attach, ccm_attach), 465 DEVMETHOD(device_detach, ccm_detach), 466 467 /* clkdev interface */ 468 DEVMETHOD(clkdev_write_4, imx_ccm_write_4), 469 DEVMETHOD(clkdev_read_4, imx_ccm_read_4), 470 DEVMETHOD(clkdev_modify_4, imx_ccm_modify_4), 471 DEVMETHOD(clkdev_device_lock, imx_ccm_device_lock), 472 DEVMETHOD(clkdev_device_unlock, imx_ccm_device_unlock), 473 474 DEVMETHOD_END 475 }; 476 477 static driver_t ccm_driver = { 478 "ccm", 479 ccm_methods, 480 sizeof(struct ccm_softc) 481 }; 482 483 EARLY_DRIVER_MODULE(ccm, simplebus, ccm_driver, 0, 0, 484 BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); 485