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 COMPOSITE(IMX8MQ_CLK_ENET_AXI, "enet_axi", enet_axi_p, 0x8800, 0), 237 COMPOSITE(IMX8MQ_CLK_ENET_REF, "enet_ref", enet_ref_p, 0xa980, 0), 238 COMPOSITE(IMX8MQ_CLK_ENET_TIMER, "enet_timer", enet_timer_p, 0xaa00, 0), 239 COMPOSITE(IMX8MQ_CLK_ENET_PHY_REF, "enet_phy_ref", enet_phy_ref_p, 0xaa80, 0), 240 241 ROOT_GATE(IMX8MQ_CLK_ENET1_ROOT, "enet1_root_clk", "enet_axi", 0x40a0), 242 243 COMPOSITE(IMX8MQ_CLK_USB_BUS, "usb_bus", usb_bus_p, 0x8b80, 0), 244 COMPOSITE(IMX8MQ_CLK_USB_CORE_REF, "usb_core_ref", usb_core_phy_p, 0xb100, 0), 245 COMPOSITE(IMX8MQ_CLK_USB_PHY_REF, "usb_phy_ref", usb_core_phy_p, 0xb180, 0), 246 247 ROOT_GATE(IMX8MQ_CLK_USB1_CTRL_ROOT, "usb1_ctrl_root_clk", "usb_bus", 0x44d0), 248 ROOT_GATE(IMX8MQ_CLK_USB2_CTRL_ROOT, "usb2_ctrl_root_clk", "usb_bus", 0x44e0), 249 ROOT_GATE(IMX8MQ_CLK_USB1_PHY_ROOT, "usb1_phy_root_clk", "usb_phy_ref", 0x44f0), 250 ROOT_GATE(IMX8MQ_CLK_USB2_PHY_ROOT, "usb2_phy_root_clk", "usb_phy_ref", 0x4500), 251 252 COMPOSITE(IMX8MQ_CLK_I2C1, "i2c1", i2c_p, 0xad00, 0), 253 COMPOSITE(IMX8MQ_CLK_I2C2, "i2c2", i2c_p, 0xad80, 0), 254 COMPOSITE(IMX8MQ_CLK_I2C3, "i2c3", i2c_p, 0xae00, 0), 255 COMPOSITE(IMX8MQ_CLK_I2C4, "i2c4", i2c_p, 0xae80, 0), 256 257 ROOT_GATE(IMX8MQ_CLK_I2C1_ROOT, "i2c1_root_clk", "i2c1", 0x4170), 258 ROOT_GATE(IMX8MQ_CLK_I2C2_ROOT, "i2c2_root_clk", "i2c2", 0x4180), 259 ROOT_GATE(IMX8MQ_CLK_I2C3_ROOT, "i2c3_root_clk", "i2c3", 0x4190), 260 ROOT_GATE(IMX8MQ_CLK_I2C4_ROOT, "i2c4_root_clk", "i2c4", 0x41a0), 261 262 ROOT_GATE(IMX8MQ_CLK_GPIO1_ROOT, "gpio1_root_clk", "ipg_root", 0x40b0), 263 ROOT_GATE(IMX8MQ_CLK_GPIO2_ROOT, "gpio2_root_clk", "ipg_root", 0x40c0), 264 ROOT_GATE(IMX8MQ_CLK_GPIO3_ROOT, "gpio3_root_clk", "ipg_root", 0x40d0), 265 ROOT_GATE(IMX8MQ_CLK_GPIO4_ROOT, "gpio4_root_clk", "ipg_root", 0x40e0), 266 ROOT_GATE(IMX8MQ_CLK_GPIO5_ROOT, "gpio5_root_clk", "ipg_root", 0x40f0), 267 }; 268 269 struct ccm_softc { 270 device_t dev; 271 struct resource *mem_res; 272 struct clkdom *clkdom; 273 struct mtx mtx; 274 struct imx_clk *clks; 275 int nclks; 276 }; 277 278 static inline uint32_t 279 CCU_READ4(struct ccm_softc *sc, bus_size_t off) 280 { 281 282 return (bus_read_4(sc->mem_res, off)); 283 } 284 285 static inline void 286 CCU_WRITE4(struct ccm_softc *sc, bus_size_t off, uint32_t val) 287 { 288 289 bus_write_4(sc->mem_res, off, val); 290 } 291 292 static int 293 ccm_detach(device_t dev) 294 { 295 struct ccm_softc *sc; 296 297 sc = device_get_softc(dev); 298 299 if (sc->mem_res != NULL) 300 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 301 302 return (0); 303 } 304 305 static int 306 ccm_attach(device_t dev) 307 { 308 struct ccm_softc *sc; 309 int err, rid; 310 phandle_t node; 311 int i; 312 313 sc = device_get_softc(dev); 314 err = 0; 315 316 /* Allocate bus_space resources. */ 317 rid = 0; 318 sc->clks = imx_clks; 319 sc->nclks = nitems(imx_clks); 320 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 321 RF_ACTIVE); 322 if (sc->mem_res == NULL) { 323 device_printf(dev, "Cannot allocate memory resources\n"); 324 err = ENXIO; 325 goto out; 326 } 327 328 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 329 330 sc->clkdom = clkdom_create(dev); 331 if (sc->clkdom == NULL) 332 panic("Cannot create clkdom\n"); 333 334 for (i = 0; i < sc->nclks; i++) { 335 switch (sc->clks[i].type) { 336 case IMX_CLK_UNDEFINED: 337 break; 338 case IMX_CLK_LINK: 339 clknode_link_register(sc->clkdom, 340 sc->clks[i].clk.link); 341 break; 342 case IMX_CLK_FIXED: 343 clknode_fixed_register(sc->clkdom, 344 sc->clks[i].clk.fixed); 345 break; 346 case IMX_CLK_MUX: 347 imx_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux); 348 break; 349 case IMX_CLK_GATE: 350 imx_clk_gate_register(sc->clkdom, sc->clks[i].clk.gate); 351 break; 352 case IMX_CLK_COMPOSITE: 353 imx_clk_composite_register(sc->clkdom, sc->clks[i].clk.composite); 354 break; 355 case IMX_CLK_SSCG_PLL: 356 imx_clk_sscg_pll_register(sc->clkdom, sc->clks[i].clk.sscg_pll); 357 break; 358 case IMX_CLK_FRAC_PLL: 359 imx_clk_frac_pll_register(sc->clkdom, sc->clks[i].clk.frac_pll); 360 break; 361 case IMX_CLK_DIV: 362 clknode_div_register(sc->clkdom, sc->clks[i].clk.div); 363 break; 364 default: 365 device_printf(dev, "Unknown clock type %d\n", sc->clks[i].type); 366 return (ENXIO); 367 } 368 } 369 370 if (clkdom_finit(sc->clkdom) != 0) 371 panic("cannot finalize clkdom initialization\n"); 372 373 if (bootverbose) 374 clkdom_dump(sc->clkdom); 375 376 node = ofw_bus_get_node(dev); 377 clk_set_assigned(dev, node); 378 379 err = 0; 380 381 out: 382 383 if (err != 0) 384 ccm_detach(dev); 385 386 return (err); 387 } 388 389 static int 390 ccm_probe(device_t dev) 391 { 392 393 if (!ofw_bus_status_okay(dev)) 394 return (ENXIO); 395 396 if (ofw_bus_is_compatible(dev, "fsl,imx8mq-ccm") == 0) 397 return (ENXIO); 398 399 device_set_desc(dev, "Freescale i.MX8 Clock Control Module"); 400 401 return (BUS_PROBE_DEFAULT); 402 } 403 404 static int 405 imx_ccm_write_4(device_t dev, bus_addr_t addr, uint32_t val) 406 { 407 struct ccm_softc *sc; 408 409 sc = device_get_softc(dev); 410 CCU_WRITE4(sc, addr, val); 411 return (0); 412 } 413 414 static int 415 imx_ccm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) 416 { 417 struct ccm_softc *sc; 418 419 sc = device_get_softc(dev); 420 421 *val = CCU_READ4(sc, addr); 422 return (0); 423 } 424 425 static int 426 imx_ccm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) 427 { 428 struct ccm_softc *sc; 429 uint32_t reg; 430 431 sc = device_get_softc(dev); 432 433 reg = CCU_READ4(sc, addr); 434 reg &= ~clr; 435 reg |= set; 436 CCU_WRITE4(sc, addr, reg); 437 438 return (0); 439 } 440 441 static void 442 imx_ccm_device_lock(device_t dev) 443 { 444 struct ccm_softc *sc; 445 446 sc = device_get_softc(dev); 447 mtx_lock(&sc->mtx); 448 } 449 450 static void 451 imx_ccm_device_unlock(device_t dev) 452 { 453 struct ccm_softc *sc; 454 455 sc = device_get_softc(dev); 456 mtx_unlock(&sc->mtx); 457 } 458 459 static device_method_t ccm_methods[] = { 460 /* Device interface */ 461 DEVMETHOD(device_probe, ccm_probe), 462 DEVMETHOD(device_attach, ccm_attach), 463 DEVMETHOD(device_detach, ccm_detach), 464 465 /* clkdev interface */ 466 DEVMETHOD(clkdev_write_4, imx_ccm_write_4), 467 DEVMETHOD(clkdev_read_4, imx_ccm_read_4), 468 DEVMETHOD(clkdev_modify_4, imx_ccm_modify_4), 469 DEVMETHOD(clkdev_device_lock, imx_ccm_device_lock), 470 DEVMETHOD(clkdev_device_unlock, imx_ccm_device_unlock), 471 472 DEVMETHOD_END 473 }; 474 475 static driver_t ccm_driver = { 476 "ccm", 477 ccm_methods, 478 sizeof(struct ccm_softc) 479 }; 480 481 static devclass_t ccm_devclass; 482 483 EARLY_DRIVER_MODULE(ccm, simplebus, ccm_driver, ccm_devclass, 0, 0, 484 BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); 485