1297627Sjmcneill/*- 2297627Sjmcneill * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 3297627Sjmcneill * All rights reserved. 4297627Sjmcneill * 5297627Sjmcneill * Redistribution and use in source and binary forms, with or without 6297627Sjmcneill * modification, are permitted provided that the following conditions 7297627Sjmcneill * are met: 8297627Sjmcneill * 1. Redistributions of source code must retain the above copyright 9297627Sjmcneill * notice, this list of conditions and the following disclaimer. 10297627Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 11297627Sjmcneill * notice, this list of conditions and the following disclaimer in the 12297627Sjmcneill * documentation and/or other materials provided with the distribution. 13297627Sjmcneill * 14297627Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15297627Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16297627Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17297627Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18297627Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19297627Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20297627Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21297627Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22297627Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23297627Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24297627Sjmcneill * SUCH DAMAGE. 25297627Sjmcneill * 26297627Sjmcneill * $FreeBSD: stable/11/sys/arm/allwinner/clk/aw_gate.c 309762 2016-12-09 20:35:01Z manu $ 27297627Sjmcneill */ 28297627Sjmcneill 29297627Sjmcneill/* 30297627Sjmcneill * Allwinner clock gates 31297627Sjmcneill */ 32297627Sjmcneill 33297627Sjmcneill#include <sys/cdefs.h> 34297627Sjmcneill__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_gate.c 309762 2016-12-09 20:35:01Z manu $"); 35297627Sjmcneill 36297627Sjmcneill#include <sys/param.h> 37297627Sjmcneill#include <sys/systm.h> 38297627Sjmcneill#include <sys/bus.h> 39297627Sjmcneill#include <sys/rman.h> 40297627Sjmcneill#include <sys/kernel.h> 41297627Sjmcneill#include <sys/module.h> 42297627Sjmcneill#include <machine/bus.h> 43297627Sjmcneill 44297627Sjmcneill#include <dev/ofw/ofw_bus.h> 45297627Sjmcneill#include <dev/ofw/ofw_bus_subr.h> 46297627Sjmcneill#include <dev/ofw/ofw_subr.h> 47309762Smanu#include <dev/fdt/fdt_common.h> 48297627Sjmcneill 49297627Sjmcneill#include <dev/extres/clk/clk_gate.h> 50297627Sjmcneill 51297627Sjmcneill#define GATE_OFFSET(index) ((index / 32) * 4) 52297627Sjmcneill#define GATE_SHIFT(index) (index % 32) 53297627Sjmcneill 54297627Sjmcneillstatic struct ofw_compat_data compat_data[] = { 55297627Sjmcneill { "allwinner,sun4i-a10-dram-gates-clk", 56297627Sjmcneill (uintptr_t)"Allwinner DRAM Clock Gates" }, 57297627Sjmcneill { "allwinner,sun4i-a10-ahb-gates-clk", 58297627Sjmcneill (uintptr_t)"Allwinner AHB Clock Gates" }, 59297627Sjmcneill { "allwinner,sun4i-a10-apb0-gates-clk", 60297627Sjmcneill (uintptr_t)"Allwinner APB0 Clock Gates" }, 61297627Sjmcneill { "allwinner,sun4i-a10-apb1-gates-clk", 62297627Sjmcneill (uintptr_t)"Allwinner APB1 Clock Gates" }, 63297627Sjmcneill 64305436Smanu { "allwinner,sun5i-a13-ahb-gates-clk", 65305436Smanu (uintptr_t)"Allwinner AHB Clock Gates" }, 66305436Smanu { "allwinner,sun5i-a13-apb0-gates-clk", 67305436Smanu (uintptr_t)"Allwinner APB0 Clock Gates" }, 68305436Smanu { "allwinner,sun5i-a13-apb1-gates-clk", 69305436Smanu (uintptr_t)"Allwinner APB1 Clock Gates" }, 70305436Smanu 71297627Sjmcneill { "allwinner,sun7i-a20-ahb-gates-clk", 72297627Sjmcneill (uintptr_t)"Allwinner AHB Clock Gates" }, 73297627Sjmcneill { "allwinner,sun7i-a20-apb0-gates-clk", 74297627Sjmcneill (uintptr_t)"Allwinner APB0 Clock Gates" }, 75297627Sjmcneill { "allwinner,sun7i-a20-apb1-gates-clk", 76297627Sjmcneill (uintptr_t)"Allwinner APB1 Clock Gates" }, 77297627Sjmcneill 78297627Sjmcneill { "allwinner,sun6i-a31-ahb1-gates-clk", 79297627Sjmcneill (uintptr_t)"Allwinner AHB1 Clock Gates" }, 80297627Sjmcneill { "allwinner,sun6i-a31-apb0-gates-clk", 81297627Sjmcneill (uintptr_t)"Allwinner APB0 Clock Gates" }, 82297627Sjmcneill { "allwinner,sun6i-a31-apb1-gates-clk", 83297627Sjmcneill (uintptr_t)"Allwinner APB1 Clock Gates" }, 84297627Sjmcneill { "allwinner,sun6i-a31-apb2-gates-clk", 85297627Sjmcneill (uintptr_t)"Allwinner APB2 Clock Gates" }, 86297627Sjmcneill 87299113Sjmcneill { "allwinner,sun8i-a83t-bus-gates-clk", 88299113Sjmcneill (uintptr_t)"Allwinner Bus Clock Gates" }, 89299113Sjmcneill { "allwinner,sun8i-a83t-apb0-gates-clk", 90299113Sjmcneill (uintptr_t)"Allwinner APB0 Clock Gates" }, 91299113Sjmcneill 92299688Smanu { "allwinner,sun8i-h3-bus-gates-clk", 93309762Smanu (uintptr_t)"Allwinner Bus Clock Gates" }, 94309762Smanu { "allwinner,sun8i-h3-apb0-gates-clk", 95309762Smanu (uintptr_t)"Allwinner APB0 Clock Gates" }, 96299688Smanu 97299113Sjmcneill { "allwinner,sun9i-a80-apbs-gates-clk", 98299113Sjmcneill (uintptr_t)"Allwinner APBS Clock Gates" }, 99299113Sjmcneill 100309762Smanu { "allwinner,sunxi-multi-bus-gates-clk", 101309762Smanu (uintptr_t)"Allwinner Multi Bus Clock Gates" }, 102309762Smanu 103297627Sjmcneill { NULL, 0 } 104297627Sjmcneill}; 105297627Sjmcneill 106297627Sjmcneillstatic int 107297627Sjmcneillaw_gate_create(device_t dev, bus_addr_t paddr, struct clkdom *clkdom, 108297627Sjmcneill const char *pclkname, const char *clkname, int index) 109297627Sjmcneill{ 110297627Sjmcneill const char *parent_names[1] = { pclkname }; 111297627Sjmcneill struct clk_gate_def def; 112297627Sjmcneill 113297627Sjmcneill memset(&def, 0, sizeof(def)); 114297627Sjmcneill def.clkdef.id = index; 115297627Sjmcneill def.clkdef.name = clkname; 116297627Sjmcneill def.clkdef.parent_names = parent_names; 117297627Sjmcneill def.clkdef.parent_cnt = 1; 118297627Sjmcneill def.offset = paddr + GATE_OFFSET(index); 119297627Sjmcneill def.shift = GATE_SHIFT(index); 120297627Sjmcneill def.mask = 1; 121297627Sjmcneill def.on_value = 1; 122297627Sjmcneill def.off_value = 0; 123297627Sjmcneill 124297627Sjmcneill return (clknode_gate_register(clkdom, &def)); 125297627Sjmcneill} 126297627Sjmcneill 127297627Sjmcneillstatic int 128309762Smanuaw_gate_add(device_t dev, struct clkdom *clkdom, phandle_t node, 129309762Smanu bus_addr_t paddr) 130309762Smanu{ 131309762Smanu const char **names; 132309762Smanu uint32_t *indices; 133309762Smanu clk_t clk_parent; 134309762Smanu int index, nout, error; 135309762Smanu 136309762Smanu indices = NULL; 137309762Smanu 138309762Smanu nout = clk_parse_ofw_out_names(dev, node, &names, &indices); 139309762Smanu if (nout == 0) { 140309762Smanu device_printf(dev, "no clock outputs found\n"); 141309762Smanu return (ENOENT); 142309762Smanu } 143309762Smanu if (indices == NULL) { 144309762Smanu device_printf(dev, "no clock-indices property\n"); 145309762Smanu return (ENXIO); 146309762Smanu } 147309762Smanu 148309762Smanu error = clk_get_by_ofw_index(dev, node, 0, &clk_parent); 149309762Smanu if (error != 0) { 150309762Smanu device_printf(dev, "cannot parse clock parent\n"); 151309762Smanu return (ENXIO); 152309762Smanu } 153309762Smanu 154309762Smanu for (index = 0; index < nout; index++) { 155309762Smanu error = aw_gate_create(dev, paddr, clkdom, 156309762Smanu clk_get_name(clk_parent), names[index], indices[index]); 157309762Smanu if (error) 158309762Smanu return (error); 159309762Smanu } 160309762Smanu 161309762Smanu return (0); 162309762Smanu} 163309762Smanu 164309762Smanustatic int 165297627Sjmcneillaw_gate_probe(device_t dev) 166297627Sjmcneill{ 167297627Sjmcneill const char *d; 168297627Sjmcneill 169297627Sjmcneill if (!ofw_bus_status_okay(dev)) 170297627Sjmcneill return (ENXIO); 171297627Sjmcneill 172297627Sjmcneill d = (const char *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; 173297627Sjmcneill if (d == NULL) 174297627Sjmcneill return (ENXIO); 175297627Sjmcneill 176297627Sjmcneill device_set_desc(dev, d); 177297627Sjmcneill return (BUS_PROBE_DEFAULT); 178297627Sjmcneill} 179297627Sjmcneill 180297627Sjmcneillstatic int 181297627Sjmcneillaw_gate_attach(device_t dev) 182297627Sjmcneill{ 183297627Sjmcneill struct clkdom *clkdom; 184297627Sjmcneill bus_addr_t paddr; 185297627Sjmcneill bus_size_t psize; 186309762Smanu phandle_t node, child; 187297627Sjmcneill 188297627Sjmcneill node = ofw_bus_get_node(dev); 189297627Sjmcneill 190297627Sjmcneill if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) { 191297627Sjmcneill device_printf(dev, "cannot parse 'reg' property\n"); 192297627Sjmcneill return (ENXIO); 193297627Sjmcneill } 194297627Sjmcneill 195297627Sjmcneill clkdom = clkdom_create(dev); 196297627Sjmcneill 197309762Smanu if (ofw_bus_is_compatible(dev, "allwinner,sunxi-multi-bus-gates-clk")) { 198309762Smanu for (child = OF_child(node); child > 0; child = OF_peer(child)) 199309762Smanu aw_gate_add(dev, clkdom, child, paddr); 200309762Smanu } else 201309762Smanu aw_gate_add(dev, clkdom, node, paddr); 202297627Sjmcneill 203297627Sjmcneill if (clkdom_finit(clkdom) != 0) { 204297627Sjmcneill device_printf(dev, "cannot finalize clkdom initialization\n"); 205309762Smanu return (ENXIO); 206297627Sjmcneill } 207297627Sjmcneill 208297627Sjmcneill if (bootverbose) 209297627Sjmcneill clkdom_dump(clkdom); 210297627Sjmcneill 211297627Sjmcneill return (0); 212297627Sjmcneill} 213297627Sjmcneill 214297627Sjmcneillstatic device_method_t aw_gate_methods[] = { 215297627Sjmcneill /* Device interface */ 216297627Sjmcneill DEVMETHOD(device_probe, aw_gate_probe), 217297627Sjmcneill DEVMETHOD(device_attach, aw_gate_attach), 218297627Sjmcneill 219297627Sjmcneill DEVMETHOD_END 220297627Sjmcneill}; 221297627Sjmcneill 222297627Sjmcneillstatic driver_t aw_gate_driver = { 223297627Sjmcneill "aw_gate", 224297627Sjmcneill aw_gate_methods, 225297627Sjmcneill 0 226297627Sjmcneill}; 227297627Sjmcneill 228297627Sjmcneillstatic devclass_t aw_gate_devclass; 229297627Sjmcneill 230297627SjmcneillEARLY_DRIVER_MODULE(aw_gate, simplebus, aw_gate_driver, 231297627Sjmcneill aw_gate_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 232