hwreset.c revision 308324
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: stable/11/sys/dev/extres/hwreset/hwreset.c 308324 2016-11-05 04:17:32Z mmel $ 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, phandle_t cnode, int idx, 113 hwreset_t *rst) 114{ 115 phandle_t xnode; 116 pcell_t *cells; 117 device_t rstdev; 118 int ncells, rv; 119 intptr_t id; 120 121 if (cnode <= 0) 122 cnode = ofw_bus_get_node(consumer_dev); 123 if (cnode <= 0) { 124 device_printf(consumer_dev, 125 "%s called on not ofw based device\n", __func__); 126 return (ENXIO); 127 } 128 129 rv = ofw_bus_parse_xref_list_alloc(cnode, "resets", "#reset-cells", 130 idx, &xnode, &ncells, &cells); 131 if (rv != 0) 132 return (rv); 133 134 /* Tranlate provider to device */ 135 rstdev = OF_device_from_xref(xnode); 136 if (rstdev == NULL) { 137 OF_prop_free(cells); 138 return (ENODEV); 139 } 140 /* Map reset to number */ 141 rv = HWRESET_MAP(rstdev, xnode, ncells, cells, &id); 142 OF_prop_free(cells); 143 if (rv != 0) 144 return (rv); 145 146 return (hwreset_get_by_id(consumer_dev, rstdev, id, rst)); 147} 148 149int 150hwreset_get_by_ofw_name(device_t consumer_dev, phandle_t cnode, char *name, 151 hwreset_t *rst) 152{ 153 int rv, idx; 154 155 if (cnode <= 0) 156 cnode = ofw_bus_get_node(consumer_dev); 157 if (cnode <= 0) { 158 device_printf(consumer_dev, 159 "%s called on not ofw based device\n", __func__); 160 return (ENXIO); 161 } 162 rv = ofw_bus_find_string_index(cnode, "reset-names", name, &idx); 163 if (rv != 0) 164 return (rv); 165 return (hwreset_get_by_ofw_idx(consumer_dev, cnode, idx, rst)); 166} 167 168void 169hwreset_register_ofw_provider(device_t provider_dev) 170{ 171 phandle_t xref, node; 172 173 node = ofw_bus_get_node(provider_dev); 174 if (node <= 0) 175 panic("%s called on not ofw based device.\n", __func__); 176 177 xref = OF_xref_from_node(node); 178 OF_device_register_xref(xref, provider_dev); 179} 180 181void 182hwreset_unregister_ofw_provider(device_t provider_dev) 183{ 184 phandle_t xref; 185 186 xref = OF_xref_from_device(provider_dev); 187 OF_device_register_xref(xref, NULL); 188} 189#endif 190