1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2017,2018 Emmanuel Vadot <manu@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 ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * 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 * $FreeBSD$ 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD$"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/bus.h> 36#include <sys/rman.h> 37#include <sys/kernel.h> 38#include <sys/module.h> 39#include <machine/bus.h> 40 41#include <dev/fdt/simplebus.h> 42 43#include <dev/ofw/ofw_bus.h> 44#include <dev/ofw/ofw_bus_subr.h> 45 46#if defined(__aarch64__) 47#include "opt_soc.h" 48#endif 49 50#include <dev/extres/clk/clk_div.h> 51#include <dev/extres/clk/clk_fixed.h> 52#include <dev/extres/clk/clk_mux.h> 53 54#include <arm/allwinner/clkng/aw_ccung.h> 55 56#include <gnu/dts/include/dt-bindings/clock/sun8i-r-ccu.h> 57#include <gnu/dts/include/dt-bindings/reset/sun8i-r-ccu.h> 58 59/* Non-exported clocks */ 60#define CLK_AHB0 1 61#define CLK_APB0 2 62 63static struct aw_ccung_reset ccu_sun8i_r_resets[] = { 64 CCU_RESET(RST_APB0_IR, 0xb0, 1) 65 CCU_RESET(RST_APB0_TIMER, 0xb0, 2) 66 CCU_RESET(RST_APB0_RSB, 0xb0, 3) 67 CCU_RESET(RST_APB0_UART, 0xb0, 4) 68 CCU_RESET(RST_APB0_I2C, 0xb0, 6) 69}; 70 71static struct aw_ccung_gate ccu_sun8i_r_gates[] = { 72 CCU_GATE(CLK_APB0_PIO, "apb0-pio", "apb0", 0x28, 0) 73 CCU_GATE(CLK_APB0_IR, "apb0-ir", "apb0", 0x28, 1) 74 CCU_GATE(CLK_APB0_TIMER, "apb0-timer", "apb0", 0x28, 2) 75 CCU_GATE(CLK_APB0_RSB, "apb0-rsb", "apb0", 0x28, 3) 76 CCU_GATE(CLK_APB0_UART, "apb0-uart", "apb0", 0x28, 4) 77 CCU_GATE(CLK_APB0_I2C, "apb0-i2c", "apb0", 0x28, 6) 78 CCU_GATE(CLK_APB0_TWD, "apb0-twd", "apb0", 0x28, 7) 79}; 80 81static const char *ar100_parents[] = {"osc32k", "osc24M", "pll_periph0", "iosc"}; 82static const char *a83t_ar100_parents[] = {"osc16M-d512", "osc24M", "pll_periph", "osc16M"}; 83PREDIV_CLK(ar100_clk, CLK_AR100, /* id */ 84 "ar100", ar100_parents, /* name, parents */ 85 0x00, /* offset */ 86 16, 2, /* mux */ 87 4, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* div */ 88 8, 5, 0, AW_CLK_FACTOR_HAS_COND, /* prediv */ 89 16, 2, 2); /* prediv condition */ 90PREDIV_CLK(a83t_ar100_clk, CLK_AR100, /* id */ 91 "ar100", a83t_ar100_parents, /* name, parents */ 92 0x00, /* offset */ 93 16, 2, /* mux */ 94 4, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* div */ 95 8, 5, 0, AW_CLK_FACTOR_HAS_COND, /* prediv */ 96 16, 2, 2); /* prediv condition */ 97 98static const char *ahb0_parents[] = {"ar100"}; 99FIXED_CLK(ahb0_clk, 100 CLK_AHB0, /* id */ 101 "ahb0", /* name */ 102 ahb0_parents, /* parent */ 103 0, /* freq */ 104 1, /* mult */ 105 1, /* div */ 106 0); /* flags */ 107 108static const char *apb0_parents[] = {"ahb0"}; 109DIV_CLK(apb0_clk, 110 CLK_APB0, /* id */ 111 "apb0", apb0_parents, /* name, parents */ 112 0x0c, /* offset */ 113 0, 2, /* shift, width */ 114 0, NULL); /* flags, div table */ 115 116static const char *r_ccu_ir_parents[] = {"osc32k", "osc24M"}; 117NM_CLK(r_ccu_ir_clk, 118 CLK_IR, /* id */ 119 "ir", r_ccu_ir_parents, /* names, parents */ 120 0x54, /* offset */ 121 0, 4, 0, 0, /* N factor */ 122 16, 2, 0, 0, /* M factor */ 123 24, 2, /* mux */ 124 31, /* gate */ 125 AW_CLK_HAS_MUX | AW_CLK_REPARENT | AW_CLK_HAS_GATE);/* flags */ 126 127static const char *a83t_ir_parents[] = {"osc16M", "osc24M"}; 128static struct aw_clk_nm_def a83t_ir_clk = { 129 .clkdef = { 130 .id = CLK_IR, 131 .name = "ir", 132 .parent_names = a83t_ir_parents, 133 .parent_cnt = nitems(a83t_ir_parents), 134 }, 135 .offset = 0x54, 136 .n = {.shift = 0, .width = 4, .flags = AW_CLK_FACTOR_POWER_OF_TWO, }, 137 .m = {.shift = 16, .width = 2}, 138 .prediv = { 139 .cond_shift = 24, 140 .cond_width = 2, 141 .cond_value = 0, 142 .value = 16 143 }, 144 .mux_shift = 24, 145 .mux_width = 2, 146 .flags = AW_CLK_HAS_MUX | AW_CLK_HAS_PREDIV, 147}; 148 149static struct aw_ccung_clk clks[] = { 150 { .type = AW_CLK_PREDIV_MUX, .clk.prediv_mux = &ar100_clk}, 151 { .type = AW_CLK_DIV, .clk.div = &apb0_clk}, 152 { .type = AW_CLK_FIXED, .clk.fixed = &ahb0_clk}, 153 { .type = AW_CLK_NM, .clk.nm = &r_ccu_ir_clk}, 154}; 155 156static struct aw_ccung_clk a83t_clks[] = { 157 { .type = AW_CLK_PREDIV_MUX, .clk.prediv_mux = &a83t_ar100_clk}, 158 { .type = AW_CLK_DIV, .clk.div = &apb0_clk}, 159 { .type = AW_CLK_FIXED, .clk.fixed = &ahb0_clk}, 160 { .type = AW_CLK_NM, .clk.nm = &a83t_ir_clk}, 161}; 162 163static struct ofw_compat_data compat_data[] = { 164#if defined(SOC_ALLWINNER_H3) || defined(SOC_ALLWINNER_H5) 165 { "allwinner,sun8i-h3-r-ccu", 1 }, 166#endif 167#if defined(SOC_ALLWINNER_A64) 168 { "allwinner,sun50i-a64-r-ccu", 1 }, 169#endif 170 { NULL, 0}, 171}; 172 173static int 174ccu_sun8i_r_probe(device_t dev) 175{ 176 177 if (!ofw_bus_status_okay(dev)) 178 return (ENXIO); 179 180 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 181 return (ENXIO); 182 183 device_set_desc(dev, "Allwinner SUN8I_R Clock Control Unit NG"); 184 return (BUS_PROBE_DEFAULT); 185} 186 187static int 188ccu_sun8i_r_attach(device_t dev) 189{ 190 struct aw_ccung_softc *sc; 191 192 sc = device_get_softc(dev); 193 194 sc->resets = ccu_sun8i_r_resets; 195 sc->nresets = nitems(ccu_sun8i_r_resets); 196 sc->gates = ccu_sun8i_r_gates; 197 sc->ngates = nitems(ccu_sun8i_r_gates); 198 sc->clks = clks; 199 sc->nclks = nitems(clks); 200 201 return (aw_ccung_attach(dev)); 202} 203 204static device_method_t ccu_sun8i_r_methods[] = { 205 /* Device interface */ 206 DEVMETHOD(device_probe, ccu_sun8i_r_probe), 207 DEVMETHOD(device_attach, ccu_sun8i_r_attach), 208 209 DEVMETHOD_END 210}; 211 212static devclass_t ccu_sun8i_r_devclass; 213 214DEFINE_CLASS_1(ccu_sun8i_r, ccu_sun8i_r_driver, ccu_sun8i_r_methods, 215 sizeof(struct aw_ccung_softc), aw_ccung_driver); 216 217EARLY_DRIVER_MODULE(ccu_sun8i_r, simplebus, ccu_sun8i_r_driver, 218 ccu_sun8i_r_devclass, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); 219 220static int 221ccu_a83t_r_probe(device_t dev) 222{ 223 224 if (!ofw_bus_status_okay(dev)) 225 return (ENXIO); 226 227 if (!ofw_bus_is_compatible(dev, "allwinner,sun8i-a83t-r-ccu")) 228 return (ENXIO); 229 230 device_set_desc(dev, "Allwinner A83T_R Clock Control Unit NG"); 231 return (BUS_PROBE_DEFAULT); 232} 233 234static int 235ccu_a83t_r_attach(device_t dev) 236{ 237 struct aw_ccung_softc *sc; 238 239 sc = device_get_softc(dev); 240 241 sc->resets = ccu_sun8i_r_resets; 242 sc->nresets = nitems(ccu_sun8i_r_resets); 243 sc->gates = ccu_sun8i_r_gates; 244 sc->ngates = nitems(ccu_sun8i_r_gates); 245 sc->clks = a83t_clks; 246 sc->nclks = nitems(a83t_clks); 247 248 return (aw_ccung_attach(dev)); 249} 250 251static device_method_t ccu_a83t_r_methods[] = { 252 /* Device interface */ 253 DEVMETHOD(device_probe, ccu_a83t_r_probe), 254 DEVMETHOD(device_attach, ccu_a83t_r_attach), 255 256 DEVMETHOD_END 257}; 258 259static devclass_t ccu_a83t_r_devclass; 260 261DEFINE_CLASS_1(ccu_a83t_r, ccu_a83t_r_driver, ccu_a83t_r_methods, 262 sizeof(struct aw_ccung_softc), aw_ccung_driver); 263 264EARLY_DRIVER_MODULE(ccu_a83t_r, simplebus, ccu_a83t_r_driver, 265 ccu_a83t_r_devclass, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); 266