1/*- 2 * Copyright 2016 Michal Meloun <mmel@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: releng/11.0/sys/dev/extres/hwreset/hwreset.c 299714 2016-05-14 04:59:36Z gonzo $ 27 */ 28#include "opt_platform.h" 29#include <sys/cdefs.h> 30#include <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/kobj.h> 33#include <sys/malloc.h> 34#include <sys/systm.h> 35 36#ifdef FDT 37#include <dev/ofw/ofw_bus.h> 38#include <dev/ofw/ofw_bus_subr.h> 39#endif 40 41#include <dev/extres/hwreset/hwreset.h> 42 43#include "hwreset_if.h" 44 45struct hwreset { 46 device_t consumer_dev; /* consumer device*/ 47 device_t provider_dev; /* provider device*/ 48 int rst_id; /* reset id */ 49}; 50 51MALLOC_DEFINE(M_HWRESET, "hwreset", "Reset framework"); 52 53int 54hwreset_assert(hwreset_t rst) 55{ 56 57 return (HWRESET_ASSERT(rst->provider_dev, rst->rst_id, true)); 58} 59 60int 61hwreset_deassert(hwreset_t rst) 62{ 63 64 return (HWRESET_ASSERT(rst->provider_dev, rst->rst_id, false)); 65} 66 67int 68hwreset_is_asserted(hwreset_t rst, bool *value) 69{ 70 71 return (HWRESET_IS_ASSERTED(rst->provider_dev, rst->rst_id, value)); 72} 73 74void 75hwreset_release(hwreset_t rst) 76{ 77 free(rst, M_HWRESET); 78} 79 80int 81hwreset_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id, 82 hwreset_t *rst_out) 83{ 84 hwreset_t rst; 85 86 /* Create handle */ 87 rst = malloc(sizeof(struct hwreset), M_HWRESET, 88 M_WAITOK | M_ZERO); 89 rst->consumer_dev = consumer_dev; 90 rst->provider_dev = provider_dev; 91 rst->rst_id = id; 92 *rst_out = rst; 93 return (0); 94} 95 96#ifdef FDT 97int 98hwreset_default_ofw_map(device_t provider_dev, phandle_t xref, int ncells, 99 pcell_t *cells, intptr_t *id) 100{ 101 if (ncells == 0) 102 *id = 1; 103 else if (ncells == 1) 104 *id = cells[0]; 105 else 106 return (ERANGE); 107 108 return (0); 109} 110 111int 112hwreset_get_by_ofw_idx(device_t consumer_dev, int idx, hwreset_t *rst) 113{ 114 phandle_t cnode, xnode; 115 pcell_t *cells; 116 device_t rstdev; 117 int ncells, rv; 118 intptr_t id; 119 120 cnode = ofw_bus_get_node(consumer_dev); 121 if (cnode <= 0) { 122 device_printf(consumer_dev, 123 "%s called on not ofw based device\n", __func__); 124 return (ENXIO); 125 } 126 127 rv = ofw_bus_parse_xref_list_alloc(cnode, "resets", "#reset-cells", 128 idx, &xnode, &ncells, &cells); 129 if (rv != 0) 130 return (rv); 131 132 /* Tranlate provider to device */ 133 rstdev = OF_device_from_xref(xnode); 134 if (rstdev == NULL) { 135 OF_prop_free(cells); 136 return (ENODEV); 137 } 138 /* Map reset to number */ 139 rv = HWRESET_MAP(rstdev, xnode, ncells, cells, &id); 140 OF_prop_free(cells); 141 if (rv != 0) 142 return (rv); 143 144 return (hwreset_get_by_id(consumer_dev, rstdev, id, rst)); 145} 146 147int 148hwreset_get_by_ofw_name(device_t consumer_dev, char *name, hwreset_t *rst) 149{ 150 int rv, idx; 151 phandle_t cnode; 152 153 cnode = ofw_bus_get_node(consumer_dev); 154 if (cnode <= 0) { 155 device_printf(consumer_dev, 156 "%s called on not ofw based device\n", __func__); 157 return (ENXIO); 158 } 159 rv = ofw_bus_find_string_index(cnode, "reset-names", name, &idx); 160 if (rv != 0) 161 return (rv); 162 return (hwreset_get_by_ofw_idx(consumer_dev, idx, rst)); 163} 164 165void 166hwreset_register_ofw_provider(device_t provider_dev) 167{ 168 phandle_t xref, node; 169 170 node = ofw_bus_get_node(provider_dev); 171 if (node <= 0) 172 panic("%s called on not ofw based device.\n", __func__); 173 174 xref = OF_xref_from_node(node); 175 OF_device_register_xref(xref, provider_dev); 176} 177 178void 179hwreset_unregister_ofw_provider(device_t provider_dev) 180{ 181 phandle_t xref; 182 183 xref = OF_xref_from_device(provider_dev); 184 OF_device_register_xref(xref, NULL); 185} 186#endif 187