1*e37e8677SEmmanuel Vadot /*- 2*e37e8677SEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause 3*e37e8677SEmmanuel Vadot * 4*e37e8677SEmmanuel Vadot * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org> 5*e37e8677SEmmanuel Vadot * 6*e37e8677SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 7*e37e8677SEmmanuel Vadot * modification, are permitted provided that the following conditions 8*e37e8677SEmmanuel Vadot * are met: 9*e37e8677SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 10*e37e8677SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 11*e37e8677SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 12*e37e8677SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 13*e37e8677SEmmanuel Vadot * documentation and/or other materials provided with the distribution. 14*e37e8677SEmmanuel Vadot * 15*e37e8677SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*e37e8677SEmmanuel Vadot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*e37e8677SEmmanuel Vadot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*e37e8677SEmmanuel Vadot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*e37e8677SEmmanuel Vadot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20*e37e8677SEmmanuel Vadot * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21*e37e8677SEmmanuel Vadot * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22*e37e8677SEmmanuel Vadot * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23*e37e8677SEmmanuel Vadot * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*e37e8677SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*e37e8677SEmmanuel Vadot * SUCH DAMAGE. 26*e37e8677SEmmanuel Vadot */ 27*e37e8677SEmmanuel Vadot 28*e37e8677SEmmanuel Vadot #include <sys/param.h> 29*e37e8677SEmmanuel Vadot #include <sys/systm.h> 30*e37e8677SEmmanuel Vadot #include <sys/bus.h> 31*e37e8677SEmmanuel Vadot #include <sys/rman.h> 32*e37e8677SEmmanuel Vadot #include <sys/kernel.h> 33*e37e8677SEmmanuel Vadot #include <sys/module.h> 34*e37e8677SEmmanuel Vadot #include <machine/bus.h> 35*e37e8677SEmmanuel Vadot 36*e37e8677SEmmanuel Vadot #include <dev/fdt/simplebus.h> 37*e37e8677SEmmanuel Vadot 38*e37e8677SEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 39*e37e8677SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 40*e37e8677SEmmanuel Vadot 41*e37e8677SEmmanuel Vadot #ifdef __aarch64__ 42*e37e8677SEmmanuel Vadot #include "opt_soc.h" 43*e37e8677SEmmanuel Vadot #endif 44*e37e8677SEmmanuel Vadot 45*e37e8677SEmmanuel Vadot #include <dev/extres/clk/clk_div.h> 46*e37e8677SEmmanuel Vadot #include <dev/extres/clk/clk_fixed.h> 47*e37e8677SEmmanuel Vadot #include <dev/extres/clk/clk_mux.h> 48*e37e8677SEmmanuel Vadot 49*e37e8677SEmmanuel Vadot #include <dev/extres/hwreset/hwreset.h> 50*e37e8677SEmmanuel Vadot 51*e37e8677SEmmanuel Vadot #include <dev/clk/allwinner/aw_ccung.h> 52*e37e8677SEmmanuel Vadot 53*e37e8677SEmmanuel Vadot #include <dt-bindings/clock/sun8i-de2.h> 54*e37e8677SEmmanuel Vadot #include <dt-bindings/reset/sun8i-de2.h> 55*e37e8677SEmmanuel Vadot 56*e37e8677SEmmanuel Vadot enum CCU_DE2 { 57*e37e8677SEmmanuel Vadot H3_CCU = 1, 58*e37e8677SEmmanuel Vadot A64_CCU, 59*e37e8677SEmmanuel Vadot }; 60*e37e8677SEmmanuel Vadot 61*e37e8677SEmmanuel Vadot /* Non exported clocks */ 62*e37e8677SEmmanuel Vadot #define CLK_MIXER0_DIV 3 63*e37e8677SEmmanuel Vadot #define CLK_MIXER1_DIV 4 64*e37e8677SEmmanuel Vadot #define CLK_WB_DIV 5 65*e37e8677SEmmanuel Vadot 66*e37e8677SEmmanuel Vadot static struct aw_ccung_reset h3_de2_ccu_resets[] = { 67*e37e8677SEmmanuel Vadot CCU_RESET(RST_MIXER0, 0x08, 0) 68*e37e8677SEmmanuel Vadot CCU_RESET(RST_WB, 0x08, 2) 69*e37e8677SEmmanuel Vadot }; 70*e37e8677SEmmanuel Vadot 71*e37e8677SEmmanuel Vadot static struct aw_ccung_reset a64_de2_ccu_resets[] = { 72*e37e8677SEmmanuel Vadot CCU_RESET(RST_MIXER0, 0x08, 0) 73*e37e8677SEmmanuel Vadot CCU_RESET(RST_MIXER1, 0x08, 1) 74*e37e8677SEmmanuel Vadot CCU_RESET(RST_WB, 0x08, 2) 75*e37e8677SEmmanuel Vadot }; 76*e37e8677SEmmanuel Vadot 77*e37e8677SEmmanuel Vadot static struct aw_ccung_gate h3_de2_ccu_gates[] = { 78*e37e8677SEmmanuel Vadot CCU_GATE(CLK_BUS_MIXER0, "mixer0", "mixer0-div", 0x00, 0) 79*e37e8677SEmmanuel Vadot CCU_GATE(CLK_BUS_WB, "wb", "wb-div", 0x00, 2) 80*e37e8677SEmmanuel Vadot 81*e37e8677SEmmanuel Vadot CCU_GATE(CLK_MIXER0, "bus-mixer0", "bus-de", 0x04, 0) 82*e37e8677SEmmanuel Vadot CCU_GATE(CLK_WB, "bus-wb", "bus-de", 0x04, 2) 83*e37e8677SEmmanuel Vadot }; 84*e37e8677SEmmanuel Vadot 85*e37e8677SEmmanuel Vadot static struct aw_ccung_gate a64_de2_ccu_gates[] = { 86*e37e8677SEmmanuel Vadot CCU_GATE(CLK_BUS_MIXER0, "mixer0", "mixer0-div", 0x00, 0) 87*e37e8677SEmmanuel Vadot CCU_GATE(CLK_BUS_MIXER1, "mixer1", "mixer1-div", 0x00, 1) 88*e37e8677SEmmanuel Vadot CCU_GATE(CLK_BUS_WB, "wb", "wb-div", 0x00, 2) 89*e37e8677SEmmanuel Vadot 90*e37e8677SEmmanuel Vadot CCU_GATE(CLK_MIXER0, "bus-mixer0", "bus-de", 0x04, 0) 91*e37e8677SEmmanuel Vadot CCU_GATE(CLK_MIXER1, "bus-mixer1", "bus-de", 0x04, 1) 92*e37e8677SEmmanuel Vadot CCU_GATE(CLK_WB, "bus-wb", "bus-de", 0x04, 2) 93*e37e8677SEmmanuel Vadot }; 94*e37e8677SEmmanuel Vadot 95*e37e8677SEmmanuel Vadot static const char *div_parents[] = {"de"}; 96*e37e8677SEmmanuel Vadot 97*e37e8677SEmmanuel Vadot NM_CLK(mixer0_div_clk, 98*e37e8677SEmmanuel Vadot CLK_MIXER0_DIV, /* id */ 99*e37e8677SEmmanuel Vadot "mixer0-div", div_parents, /* names, parents */ 100*e37e8677SEmmanuel Vadot 0x0C, /* offset */ 101*e37e8677SEmmanuel Vadot 0, 0, 1, AW_CLK_FACTOR_FIXED, /* N factor (fake)*/ 102*e37e8677SEmmanuel Vadot 0, 4, 0, 0, /* M flags */ 103*e37e8677SEmmanuel Vadot 0, 0, /* mux */ 104*e37e8677SEmmanuel Vadot 0, /* gate */ 105*e37e8677SEmmanuel Vadot AW_CLK_SCALE_CHANGE); /* flags */ 106*e37e8677SEmmanuel Vadot 107*e37e8677SEmmanuel Vadot NM_CLK(mixer1_div_clk, 108*e37e8677SEmmanuel Vadot CLK_MIXER1_DIV, /* id */ 109*e37e8677SEmmanuel Vadot "mixer1-div", div_parents, /* names, parents */ 110*e37e8677SEmmanuel Vadot 0x0C, /* offset */ 111*e37e8677SEmmanuel Vadot 0, 0, 1, AW_CLK_FACTOR_FIXED, /* N factor (fake)*/ 112*e37e8677SEmmanuel Vadot 4, 4, 0, 0, /* M flags */ 113*e37e8677SEmmanuel Vadot 0, 0, /* mux */ 114*e37e8677SEmmanuel Vadot 0, /* gate */ 115*e37e8677SEmmanuel Vadot AW_CLK_SCALE_CHANGE); /* flags */ 116*e37e8677SEmmanuel Vadot 117*e37e8677SEmmanuel Vadot NM_CLK(wb_div_clk, 118*e37e8677SEmmanuel Vadot CLK_WB_DIV, /* id */ 119*e37e8677SEmmanuel Vadot "wb-div", div_parents, /* names, parents */ 120*e37e8677SEmmanuel Vadot 0x0C, /* offset */ 121*e37e8677SEmmanuel Vadot 0, 0, 1, AW_CLK_FACTOR_FIXED, /* N factor (fake)*/ 122*e37e8677SEmmanuel Vadot 8, 4, 0, 0, /* M flags */ 123*e37e8677SEmmanuel Vadot 0, 0, /* mux */ 124*e37e8677SEmmanuel Vadot 0, /* gate */ 125*e37e8677SEmmanuel Vadot AW_CLK_SCALE_CHANGE); /* flags */ 126*e37e8677SEmmanuel Vadot 127*e37e8677SEmmanuel Vadot static struct aw_ccung_clk h3_de2_ccu_clks[] = { 128*e37e8677SEmmanuel Vadot { .type = AW_CLK_NM, .clk.nm = &mixer0_div_clk}, 129*e37e8677SEmmanuel Vadot { .type = AW_CLK_NM, .clk.nm = &wb_div_clk}, 130*e37e8677SEmmanuel Vadot }; 131*e37e8677SEmmanuel Vadot 132*e37e8677SEmmanuel Vadot static struct aw_ccung_clk a64_de2_ccu_clks[] = { 133*e37e8677SEmmanuel Vadot { .type = AW_CLK_NM, .clk.nm = &mixer0_div_clk}, 134*e37e8677SEmmanuel Vadot { .type = AW_CLK_NM, .clk.nm = &mixer1_div_clk}, 135*e37e8677SEmmanuel Vadot { .type = AW_CLK_NM, .clk.nm = &wb_div_clk}, 136*e37e8677SEmmanuel Vadot }; 137*e37e8677SEmmanuel Vadot 138*e37e8677SEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 139*e37e8677SEmmanuel Vadot {"allwinner,sun8i-h3-de2-clk", H3_CCU}, 140*e37e8677SEmmanuel Vadot {"allwinner,sun50i-a64-de2-clk", A64_CCU}, 141*e37e8677SEmmanuel Vadot {NULL, 0} 142*e37e8677SEmmanuel Vadot }; 143*e37e8677SEmmanuel Vadot 144*e37e8677SEmmanuel Vadot static int 145*e37e8677SEmmanuel Vadot ccu_de2_probe(device_t dev) 146*e37e8677SEmmanuel Vadot { 147*e37e8677SEmmanuel Vadot 148*e37e8677SEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 149*e37e8677SEmmanuel Vadot return (ENXIO); 150*e37e8677SEmmanuel Vadot 151*e37e8677SEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 152*e37e8677SEmmanuel Vadot return (ENXIO); 153*e37e8677SEmmanuel Vadot 154*e37e8677SEmmanuel Vadot device_set_desc(dev, "Allwinner DE2 Clock Control Unit"); 155*e37e8677SEmmanuel Vadot return (BUS_PROBE_DEFAULT); 156*e37e8677SEmmanuel Vadot } 157*e37e8677SEmmanuel Vadot 158*e37e8677SEmmanuel Vadot static int 159*e37e8677SEmmanuel Vadot ccu_de2_attach(device_t dev) 160*e37e8677SEmmanuel Vadot { 161*e37e8677SEmmanuel Vadot struct aw_ccung_softc *sc; 162*e37e8677SEmmanuel Vadot phandle_t node; 163*e37e8677SEmmanuel Vadot clk_t mod, bus; 164*e37e8677SEmmanuel Vadot hwreset_t rst_de; 165*e37e8677SEmmanuel Vadot enum CCU_DE2 type; 166*e37e8677SEmmanuel Vadot 167*e37e8677SEmmanuel Vadot sc = device_get_softc(dev); 168*e37e8677SEmmanuel Vadot node = ofw_bus_get_node(dev); 169*e37e8677SEmmanuel Vadot 170*e37e8677SEmmanuel Vadot type = (enum CCU_DE2)ofw_bus_search_compatible(dev, compat_data)->ocd_data; 171*e37e8677SEmmanuel Vadot 172*e37e8677SEmmanuel Vadot switch (type) { 173*e37e8677SEmmanuel Vadot case H3_CCU: 174*e37e8677SEmmanuel Vadot sc->resets = h3_de2_ccu_resets; 175*e37e8677SEmmanuel Vadot sc->nresets = nitems(h3_de2_ccu_resets); 176*e37e8677SEmmanuel Vadot sc->gates = h3_de2_ccu_gates; 177*e37e8677SEmmanuel Vadot sc->ngates = nitems(h3_de2_ccu_gates); 178*e37e8677SEmmanuel Vadot sc->clks = h3_de2_ccu_clks; 179*e37e8677SEmmanuel Vadot sc->nclks = nitems(h3_de2_ccu_clks); 180*e37e8677SEmmanuel Vadot break; 181*e37e8677SEmmanuel Vadot case A64_CCU: 182*e37e8677SEmmanuel Vadot sc->resets = a64_de2_ccu_resets; 183*e37e8677SEmmanuel Vadot sc->nresets = nitems(a64_de2_ccu_resets); 184*e37e8677SEmmanuel Vadot sc->gates = a64_de2_ccu_gates; 185*e37e8677SEmmanuel Vadot sc->ngates = nitems(a64_de2_ccu_gates); 186*e37e8677SEmmanuel Vadot sc->clks = a64_de2_ccu_clks; 187*e37e8677SEmmanuel Vadot sc->nclks = nitems(a64_de2_ccu_clks); 188*e37e8677SEmmanuel Vadot break; 189*e37e8677SEmmanuel Vadot } 190*e37e8677SEmmanuel Vadot 191*e37e8677SEmmanuel Vadot if (hwreset_get_by_ofw_idx(dev, node, 0, &rst_de) != 0) { 192*e37e8677SEmmanuel Vadot device_printf(dev, "Cannot get de reset\n"); 193*e37e8677SEmmanuel Vadot return (ENXIO); 194*e37e8677SEmmanuel Vadot } 195*e37e8677SEmmanuel Vadot if (hwreset_deassert(rst_de) != 0) { 196*e37e8677SEmmanuel Vadot device_printf(dev, "Cannot de-assert de reset\n"); 197*e37e8677SEmmanuel Vadot return (ENXIO); 198*e37e8677SEmmanuel Vadot } 199*e37e8677SEmmanuel Vadot 200*e37e8677SEmmanuel Vadot if (clk_get_by_ofw_name(dev, node, "mod", &mod) != 0) { 201*e37e8677SEmmanuel Vadot device_printf(dev, "Cannot get mod clock\n"); 202*e37e8677SEmmanuel Vadot return (ENXIO); 203*e37e8677SEmmanuel Vadot } 204*e37e8677SEmmanuel Vadot if (clk_enable(mod) != 0) { 205*e37e8677SEmmanuel Vadot device_printf(dev, "Cannot enable mod clock\n"); 206*e37e8677SEmmanuel Vadot return (ENXIO); 207*e37e8677SEmmanuel Vadot } 208*e37e8677SEmmanuel Vadot 209*e37e8677SEmmanuel Vadot if (clk_get_by_ofw_name(dev, node, "bus", &bus) != 0) { 210*e37e8677SEmmanuel Vadot device_printf(dev, "Cannot get bus clock\n"); 211*e37e8677SEmmanuel Vadot return (ENXIO); 212*e37e8677SEmmanuel Vadot } 213*e37e8677SEmmanuel Vadot if (clk_enable(bus) != 0) { 214*e37e8677SEmmanuel Vadot device_printf(dev, "Cannot enable bus clock\n"); 215*e37e8677SEmmanuel Vadot return (ENXIO); 216*e37e8677SEmmanuel Vadot } 217*e37e8677SEmmanuel Vadot 218*e37e8677SEmmanuel Vadot return (aw_ccung_attach(dev)); 219*e37e8677SEmmanuel Vadot } 220*e37e8677SEmmanuel Vadot 221*e37e8677SEmmanuel Vadot static device_method_t ccu_de2_methods[] = { 222*e37e8677SEmmanuel Vadot /* Device interface */ 223*e37e8677SEmmanuel Vadot DEVMETHOD(device_probe, ccu_de2_probe), 224*e37e8677SEmmanuel Vadot DEVMETHOD(device_attach, ccu_de2_attach), 225*e37e8677SEmmanuel Vadot 226*e37e8677SEmmanuel Vadot DEVMETHOD_END 227*e37e8677SEmmanuel Vadot }; 228*e37e8677SEmmanuel Vadot 229*e37e8677SEmmanuel Vadot DEFINE_CLASS_1(ccu_de2, ccu_de2_driver, ccu_de2_methods, 230*e37e8677SEmmanuel Vadot sizeof(struct aw_ccung_softc), aw_ccung_driver); 231*e37e8677SEmmanuel Vadot 232*e37e8677SEmmanuel Vadot EARLY_DRIVER_MODULE(ccu_de2, simplebus, ccu_de2_driver, 0, 0, 233*e37e8677SEmmanuel Vadot BUS_PASS_RESOURCE + BUS_PASS_ORDER_LAST); 234