1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021, 2022 Soren Schmidt <sos@deepcore.dk> 5 * Copyright (c) 2023, Emmanuel Vadot <manu@freebsd.org> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/bus.h> 32 #include <sys/rman.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <machine/bus.h> 36 37 #include <dev/fdt/simplebus.h> 38 39 #include <dev/ofw/ofw_bus.h> 40 #include <dev/ofw/ofw_bus_subr.h> 41 42 #include <dev/clk/clk_div.h> 43 #include <dev/clk/clk_fixed.h> 44 #include <dev/clk/clk_mux.h> 45 46 #include <dev/clk/rockchip/rk_cru.h> 47 #include <contrib/device-tree/include/dt-bindings/clock/rk3568-cru.h> 48 49 50 #define CRU_PLLSEL_CON(x) ((x) * 0x20) 51 #define CRU_CLKSEL_CON(x) ((x) * 0x4 + 0x100) 52 #define CRU_CLKGATE_CON(x) ((x) * 0x4 + 0x180) 53 54 /* PLL clock */ 55 #define RK_PLL(_id, _name, _pnames, _off, _shift) \ 56 { \ 57 .type = RK3328_CLK_PLL, \ 58 .clk.pll = &(struct rk_clk_pll_def) { \ 59 .clkdef.id = _id, \ 60 .clkdef.name = _name, \ 61 .clkdef.parent_names = _pnames, \ 62 .clkdef.parent_cnt = nitems(_pnames), \ 63 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 64 .base_offset = CRU_PLLSEL_CON(_off), \ 65 .mode_reg = 0x80, \ 66 .mode_shift = _shift, \ 67 .rates = rk3568_pll_rates, \ 68 }, \ 69 } 70 71 extern struct rk_clk_pll_rate rk3568_pll_rates[]; 72 73 /* Parent clock defines */ 74 PLIST(mux_pll_p) = { "xin24m" }; 75 PLIST(xin24m_32k_p) = { "xin24m", "clk_rtc_32k" }; 76 PLIST(sclk_uart0_p) = { "sclk_uart0_div", "sclk_uart0_frac", "xin24m" }; 77 PLIST(sclk_uart0_div_p) = { "ppll", "usb480m", "cpll", "gpll" }; 78 PLIST(clk_rtc32k_pmu_p) = { "clk_32k_pvtm", "xin32k", "clk_osc0_div32k" }; 79 PLIST(clk_usbphy0_ref_p) = { "clk_ref24m", "xin_osc0_usbphy0_g" }; 80 PLIST(clk_usbphy1_ref_p) = { "clk_ref24m", "xin_osc0_usbphy1_g" }; 81 PLIST(clk_mipidsiphy0_ref_p) = { "clk_ref24m", "xin_osc0_mipidsiphy0_g" }; 82 PLIST(clk_mipidsiphy1_ref_p) = { "clk_ref24m", "xin_osc0_mipidsiphy1_g" }; 83 PLIST(clk_wifi_p) = { "clk_wifi_osc0", "clk_wifi_div" }; 84 PLIST(clk_pciephy0_ref_p) = { "clk_pciephy0_osc0", "clk_pciephy0_div" }; 85 PLIST(clk_pciephy1_ref_p) = { "clk_pciephy1_osc0", "clk_pciephy1_div" }; 86 PLIST(clk_pciephy2_ref_p) = { "clk_pciephy2_osc0", "clk_pciephy2_div" }; 87 PLIST(clk_hdmi_ref_p) = { "hpll", "hpll_ph0" }; 88 PLIST(clk_pdpmu_p) = { "ppll", "gpll" }; 89 PLIST(clk_pwm0_p) = { "xin24m", "clk_pdpmu" }; 90 91 /* CLOCKS */ 92 static struct rk_clk rk3568_clks[] = { 93 /* External clocks */ 94 LINK("xin24m"), 95 LINK("cpll"), 96 LINK("gpll"), 97 LINK("usb480m"), 98 LINK("clk_32k_pvtm"), 99 100 /* Fixed clocks */ 101 FFACT(0, "ppll_ph0", "ppll", 1, 2), 102 FFACT(0, "ppll_ph180", "ppll", 1, 2), 103 FFACT(0, "hpll_ph0", "hpll", 1, 2), 104 105 /* PLL's */ 106 RK_PLL(PLL_PPLL, "ppll", mux_pll_p, 0, 0), 107 RK_PLL(PLL_HPLL, "hpll", mux_pll_p, 2, 2), 108 109 /* PMUCRU_PMUCLKSEL_CON00 */ 110 CDIV(0, "xin_osc0_div_div", "xin24m", 0, 0, 0, 5), 111 MUX(0, "clk_rtc_32k_mux", clk_rtc32k_pmu_p, 0, 0, 6, 2), 112 113 /* PMUCRU_PMUCLKSEL_CON01 */ 114 FRACT(0, "clk_osc0_div32k", "xin24m", 0, 1), 115 116 /* PMUCRU_PMUCLKSEL_CON02 */ 117 CDIV(0, "pclk_pdpmu_pre", "clk_pdpmu", 0, 2, 0, 5), 118 MUX(CLK_PDPMU, "clk_pdpmu", clk_pdpmu_p, 0, 2, 15, 1), 119 120 /* PMUCRU_PMUCLKSEL_CON03 */ 121 CDIV(0, "clk_i2c0_div", "clk_pdpmu", 0, 3, 0, 7), 122 123 /* PMUCRU_PMUCLKSEL_CON04 */ 124 CDIV(0, "sclk_uart0_div_div", "sclk_uart0_div_sel", 0, 4, 0, 7), 125 MUX(0, "sclk_uart0_div_sel", sclk_uart0_div_p, 0, 4, 8, 2), 126 MUX(0, "sclk_uart0_mux", sclk_uart0_p, 0, 4, 10, 2), 127 128 /* PMUCRU_PMUCLKSEL_CON05 */ 129 FRACT(0, "sclk_uart0_frac_div", "sclk_uart0_div", 0, 5), 130 131 /* PMUCRU_PMUCLKSEL_CON06 */ 132 CDIV(0, "clk_pwm0_div", "clk_pwm0_sel", 0, 6, 0, 7), 133 MUX(0, "clk_pwm0_sel", clk_pwm0_p, 0, 6, 7, 1), 134 MUX(0, "dbclk_gpio0_sel", xin24m_32k_p, 0, 6, 15, 1), 135 136 /* PMUCRU_PMUCLKSEL_CON07 */ 137 CDIV(0, "clk_ref24m_div", "clk_pdpmu", 0, 7, 0, 6), 138 139 /* PMUCRU_PMUCLKSEL_CON08 */ 140 MUX(CLK_USBPHY0_REF, "clk_usbphy0_ref", clk_usbphy0_ref_p, 0, 8, 0, 1), 141 MUX(CLK_USBPHY1_REF, "clk_usbphy1_ref", clk_usbphy1_ref_p, 0, 8, 1, 1), 142 MUX(CLK_MIPIDSIPHY0_REF, "clk_mipidsiphy0_ref", clk_mipidsiphy0_ref_p, 0, 8, 2, 1), 143 MUX(CLK_MIPIDSIPHY1_REF, "clk_mipidsiphy1_ref", clk_mipidsiphy1_ref_p, 0, 8, 3, 1), 144 MUX(CLK_HDMI_REF, "clk_hdmi_ref", clk_hdmi_ref_p, 0, 8, 7, 1), 145 CDIV(0, "clk_wifi_div_div", "clk_pdpmu", 0, 8, 8, 6), 146 MUX(CLK_WIFI, "clk_wifi", clk_wifi_p, 0, 8, 15, 1), 147 148 /* PMUCRU_PMUCLKSEL_CON09 */ 149 CDIV(0, "clk_pciephy0_div_div", "ppll_ph0", 0, 9, 0, 3), 150 MUX(CLK_PCIEPHY0_REF, "clk_pciephy0_ref", 151 clk_pciephy0_ref_p, 0, 9, 3, 1), 152 CDIV(0, "clk_pciephy1_div_div", "ppll_ph0", 0, 9, 4, 3), 153 MUX(CLK_PCIEPHY1_REF, "clk_pciephy1_ref", 154 clk_pciephy1_ref_p, 0, 9, 7, 1), 155 CDIV(0, "clk_pciephy2_div_div", "ppll_ph0", 0, 9, 8, 3), 156 MUX(CLK_PCIEPHY2_REF, "clk_pciephy2_ref", 157 clk_pciephy2_ref_p, 0, 9, 11, 1), 158 }; 159 160 /* GATES */ 161 static struct rk_cru_gate rk3568_gates[] = { 162 /* PMUCRU_PMUGATE_CON00 */ 163 GATE(XIN_OSC0_DIV, "xin_osc0_div", "xin_osc0_div_div", 0, 0), 164 GATE(CLK_RTC_32K, "clk_rtc_32k", "clk_rtc_32k_mux", 0, 1), 165 GATE(PCLK_PDPMU, "pclk_pdpmu", "pclk_pdpmu_pre", 0, 2), 166 GATE(PCLK_PMU, "pclk_pmu", "pclk_pdpmu", 0, 6), 167 GATE(CLK_PMU, "clk_pmu", "xin24m", 0, 7), 168 169 /* PMUCRU_PMUGATE_CON01 */ 170 GATE(PCLK_I2C0, "pclk_i2c0", "pclk_pdpmu", 1, 0), 171 GATE(CLK_I2C0, "clk_i2c0", "clk_i2c0_div", 1, 1), 172 GATE(PCLK_UART0, "pclk_uart0", "pclk_pdpmu", 1, 2), 173 GATE(CLK_UART0_DIV, "sclk_uart0_div", "sclk_uart0_div_div", 1, 3), 174 GATE(CLK_UART0_FRAC, "sclk_uart0_frac", "sclk_uart0_frac_div", 1, 4), 175 GATE(SCLK_UART0, "sclk_uart0", "sclk_uart0_mux", 1, 5), 176 GATE(PCLK_PWM0, "pclk_pwm0", "pclk_pdpmu", 1, 6), 177 GATE(CLK_PWM0, "clk_pwm0", "clk_pwm0_div", 1, 7), 178 GATE(CLK_CAPTURE_PWM0_NDFT, "clk_capture_pwm0_ndft", "xin24m", 1, 8), 179 GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pdpmu", 1, 9), 180 GATE(DBCLK_GPIO0, "dbclk_gpio0", "dbclk_gpio0_sel", 1, 10), 181 GATE(PCLK_PMUPVTM, "pclk_pmupvtm", "pclk_pdpmu", 1, 11), 182 GATE(CLK_PMUPVTM, "clk_pmupvtm", "xin24m", 1, 12), 183 GATE(CLK_CORE_PMUPVTM, "clk_core_pmupvtm", "xin24m", 1, 13), 184 185 /* PMUCRU_PMUGATE_CON02 */ 186 GATE(CLK_REF24M, "clk_ref24m", "clk_ref24m_div", 2, 0), 187 GATE(XIN_OSC0_USBPHY0_G, "xin_osc0_usbphy0_g", "xin24m", 2, 1), 188 GATE(XIN_OSC0_USBPHY1_G, "xin_osc0_usbphy1_g", "xin24m", 2, 2), 189 GATE(XIN_OSC0_MIPIDSIPHY0_G, "xin_osc0_mipidsiphy0_g", "xin24m", 2, 3), 190 GATE(XIN_OSC0_MIPIDSIPHY1_G, "xin_osc0_mipidsiphy1_g", "xin24m", 2, 4), 191 GATE(CLK_WIFI_DIV, "clk_wifi_div", "clk_wifi_div_div", 2, 5), 192 GATE(CLK_WIFI_OSC0, "clk_wifi_osc0", "xin24m", 2, 6), 193 GATE(CLK_PCIEPHY0_DIV, "clk_pciephy0_div", "clk_pciephy0_div_div", 2, 7), 194 GATE(CLK_PCIEPHY0_OSC0, "clk_pciephy0_osc0", "xin24m", 2, 8), 195 GATE(CLK_PCIEPHY1_DIV, "clk_pciephy1_div", "clk_pciephy1_div_div", 2, 9), 196 GATE(CLK_PCIEPHY1_OSC0, "clk_pciephy1_osc0", "xin24m", 2, 10), 197 GATE(CLK_PCIEPHY2_DIV, "clk_pciephy2_div", "clk_pciephy2_div_div", 2, 11), 198 GATE(CLK_PCIEPHY2_OSC0, "clk_pciephy2_osc0", "xin24m", 2, 12), 199 GATE(CLK_PCIE30PHY_REF_M, "clk_pcie30phy_ref_m", "ppll_ph0", 2, 13), 200 GATE(CLK_PCIE30PHY_REF_N, "clk_pcie30phy_ref_n", "ppll_ph180", 2, 14), 201 GATE(XIN_OSC0_EDPPHY_G, "xin_osc0_edpphy_g", "xin24m", 2, 15), 202 }; 203 204 static int 205 rk3568_pmucru_probe(device_t dev) 206 { 207 208 if (!ofw_bus_status_okay(dev)) 209 return (ENXIO); 210 211 if (ofw_bus_is_compatible(dev, "rockchip,rk3568-pmucru")) { 212 device_set_desc(dev, "Rockchip RK3568 PMU Clock & Reset Unit"); 213 return (BUS_PROBE_DEFAULT); 214 } 215 216 return (ENXIO); 217 } 218 219 static int 220 rk3568_pmucru_attach(device_t dev) 221 { 222 struct rk_cru_softc *sc; 223 224 sc = device_get_softc(dev); 225 sc->dev = dev; 226 sc->clks = rk3568_clks; 227 sc->nclks = nitems(rk3568_clks); 228 sc->gates = rk3568_gates; 229 sc->ngates = nitems(rk3568_gates); 230 sc->reset_offset = 0x200; 231 sc->reset_num = 4; 232 233 return (rk_cru_attach(dev)); 234 } 235 236 static device_method_t methods[] = { 237 /* Device interface */ 238 DEVMETHOD(device_probe, rk3568_pmucru_probe), 239 DEVMETHOD(device_attach, rk3568_pmucru_attach), 240 241 DEVMETHOD_END 242 }; 243 244 DEFINE_CLASS_1(rk3568_pmucru, rk3568_pmucru_driver, methods, 245 sizeof(struct rk_cru_softc), rk_cru_driver); 246 247 EARLY_DRIVER_MODULE(rk3568_pmucru, simplebus, rk3568_pmucru_driver, 248 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 249