aw_gate.c revision 297627
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: head/sys/arm/allwinner/clk/aw_gate.c 297627 2016-04-06 23:11:03Z jmcneill $ 27297627Sjmcneill */ 28297627Sjmcneill 29297627Sjmcneill/* 30297627Sjmcneill * Allwinner clock gates 31297627Sjmcneill */ 32297627Sjmcneill 33297627Sjmcneill#include <sys/cdefs.h> 34297627Sjmcneill__FBSDID("$FreeBSD: head/sys/arm/allwinner/clk/aw_gate.c 297627 2016-04-06 23:11:03Z jmcneill $"); 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> 47297627Sjmcneill 48297627Sjmcneill#include <dev/extres/clk/clk_gate.h> 49297627Sjmcneill 50297627Sjmcneill#define GATE_OFFSET(index) ((index / 32) * 4) 51297627Sjmcneill#define GATE_SHIFT(index) (index % 32) 52297627Sjmcneill 53297627Sjmcneillstatic struct ofw_compat_data compat_data[] = { 54297627Sjmcneill { "allwinner,sun4i-a10-dram-gates-clk", 55297627Sjmcneill (uintptr_t)"Allwinner DRAM Clock Gates" }, 56297627Sjmcneill { "allwinner,sun4i-a10-ahb-gates-clk", 57297627Sjmcneill (uintptr_t)"Allwinner AHB Clock Gates" }, 58297627Sjmcneill { "allwinner,sun4i-a10-apb0-gates-clk", 59297627Sjmcneill (uintptr_t)"Allwinner APB0 Clock Gates" }, 60297627Sjmcneill { "allwinner,sun4i-a10-apb1-gates-clk", 61297627Sjmcneill (uintptr_t)"Allwinner APB1 Clock Gates" }, 62297627Sjmcneill 63297627Sjmcneill { "allwinner,sun7i-a20-ahb-gates-clk", 64297627Sjmcneill (uintptr_t)"Allwinner AHB Clock Gates" }, 65297627Sjmcneill { "allwinner,sun7i-a20-apb0-gates-clk", 66297627Sjmcneill (uintptr_t)"Allwinner APB0 Clock Gates" }, 67297627Sjmcneill { "allwinner,sun7i-a20-apb1-gates-clk", 68297627Sjmcneill (uintptr_t)"Allwinner APB1 Clock Gates" }, 69297627Sjmcneill 70297627Sjmcneill { "allwinner,sun6i-a31-ahb1-gates-clk", 71297627Sjmcneill (uintptr_t)"Allwinner AHB1 Clock Gates" }, 72297627Sjmcneill { "allwinner,sun6i-a31-apb0-gates-clk", 73297627Sjmcneill (uintptr_t)"Allwinner APB0 Clock Gates" }, 74297627Sjmcneill { "allwinner,sun6i-a31-apb1-gates-clk", 75297627Sjmcneill (uintptr_t)"Allwinner APB1 Clock Gates" }, 76297627Sjmcneill { "allwinner,sun6i-a31-apb2-gates-clk", 77297627Sjmcneill (uintptr_t)"Allwinner APB2 Clock Gates" }, 78297627Sjmcneill 79297627Sjmcneill { NULL, 0 } 80297627Sjmcneill}; 81297627Sjmcneill 82297627Sjmcneillstatic int 83297627Sjmcneillaw_gate_create(device_t dev, bus_addr_t paddr, struct clkdom *clkdom, 84297627Sjmcneill const char *pclkname, const char *clkname, int index) 85297627Sjmcneill{ 86297627Sjmcneill const char *parent_names[1] = { pclkname }; 87297627Sjmcneill struct clk_gate_def def; 88297627Sjmcneill 89297627Sjmcneill memset(&def, 0, sizeof(def)); 90297627Sjmcneill def.clkdef.id = index; 91297627Sjmcneill def.clkdef.name = clkname; 92297627Sjmcneill def.clkdef.parent_names = parent_names; 93297627Sjmcneill def.clkdef.parent_cnt = 1; 94297627Sjmcneill def.offset = paddr + GATE_OFFSET(index); 95297627Sjmcneill def.shift = GATE_SHIFT(index); 96297627Sjmcneill def.mask = 1; 97297627Sjmcneill def.on_value = 1; 98297627Sjmcneill def.off_value = 0; 99297627Sjmcneill 100297627Sjmcneill return (clknode_gate_register(clkdom, &def)); 101297627Sjmcneill} 102297627Sjmcneill 103297627Sjmcneillstatic int 104297627Sjmcneillaw_gate_probe(device_t dev) 105297627Sjmcneill{ 106297627Sjmcneill const char *d; 107297627Sjmcneill 108297627Sjmcneill if (!ofw_bus_status_okay(dev)) 109297627Sjmcneill return (ENXIO); 110297627Sjmcneill 111297627Sjmcneill d = (const char *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; 112297627Sjmcneill if (d == NULL) 113297627Sjmcneill return (ENXIO); 114297627Sjmcneill 115297627Sjmcneill device_set_desc(dev, d); 116297627Sjmcneill return (BUS_PROBE_DEFAULT); 117297627Sjmcneill} 118297627Sjmcneill 119297627Sjmcneillstatic int 120297627Sjmcneillaw_gate_attach(device_t dev) 121297627Sjmcneill{ 122297627Sjmcneill struct clkdom *clkdom; 123297627Sjmcneill const char **names; 124297627Sjmcneill int index, nout, error; 125297627Sjmcneill uint32_t *indices; 126297627Sjmcneill clk_t clk_parent; 127297627Sjmcneill bus_addr_t paddr; 128297627Sjmcneill bus_size_t psize; 129297627Sjmcneill phandle_t node; 130297627Sjmcneill 131297627Sjmcneill node = ofw_bus_get_node(dev); 132297627Sjmcneill indices = NULL; 133297627Sjmcneill 134297627Sjmcneill if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) { 135297627Sjmcneill device_printf(dev, "cannot parse 'reg' property\n"); 136297627Sjmcneill return (ENXIO); 137297627Sjmcneill } 138297627Sjmcneill 139297627Sjmcneill clkdom = clkdom_create(dev); 140297627Sjmcneill 141297627Sjmcneill nout = clk_parse_ofw_out_names(dev, node, &names, &indices); 142297627Sjmcneill if (nout == 0) { 143297627Sjmcneill device_printf(dev, "no clock outputs found\n"); 144297627Sjmcneill error = ENOENT; 145297627Sjmcneill goto fail; 146297627Sjmcneill } 147297627Sjmcneill if (indices == NULL) { 148297627Sjmcneill device_printf(dev, "no clock-indices property\n"); 149297627Sjmcneill error = ENXIO; 150297627Sjmcneill goto fail; 151297627Sjmcneill } 152297627Sjmcneill 153297627Sjmcneill error = clk_get_by_ofw_index(dev, 0, &clk_parent); 154297627Sjmcneill if (error != 0) { 155297627Sjmcneill device_printf(dev, "cannot parse clock parent\n"); 156297627Sjmcneill return (ENXIO); 157297627Sjmcneill } 158297627Sjmcneill 159297627Sjmcneill for (index = 0; index < nout; index++) { 160297627Sjmcneill error = aw_gate_create(dev, paddr, clkdom, 161297627Sjmcneill clk_get_name(clk_parent), names[index], indices[index]); 162297627Sjmcneill if (error) 163297627Sjmcneill goto fail; 164297627Sjmcneill } 165297627Sjmcneill 166297627Sjmcneill if (clkdom_finit(clkdom) != 0) { 167297627Sjmcneill device_printf(dev, "cannot finalize clkdom initialization\n"); 168297627Sjmcneill error = ENXIO; 169297627Sjmcneill goto fail; 170297627Sjmcneill } 171297627Sjmcneill 172297627Sjmcneill if (bootverbose) 173297627Sjmcneill clkdom_dump(clkdom); 174297627Sjmcneill 175297627Sjmcneill return (0); 176297627Sjmcneill 177297627Sjmcneillfail: 178297627Sjmcneill return (error); 179297627Sjmcneill} 180297627Sjmcneill 181297627Sjmcneillstatic device_method_t aw_gate_methods[] = { 182297627Sjmcneill /* Device interface */ 183297627Sjmcneill DEVMETHOD(device_probe, aw_gate_probe), 184297627Sjmcneill DEVMETHOD(device_attach, aw_gate_attach), 185297627Sjmcneill 186297627Sjmcneill DEVMETHOD_END 187297627Sjmcneill}; 188297627Sjmcneill 189297627Sjmcneillstatic driver_t aw_gate_driver = { 190297627Sjmcneill "aw_gate", 191297627Sjmcneill aw_gate_methods, 192297627Sjmcneill 0 193297627Sjmcneill}; 194297627Sjmcneill 195297627Sjmcneillstatic devclass_t aw_gate_devclass; 196297627Sjmcneill 197297627SjmcneillEARLY_DRIVER_MODULE(aw_gate, simplebus, aw_gate_driver, 198297627Sjmcneill aw_gate_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 199