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 #include "opt_platform.h" 27 28 #include <sys/param.h> 29 #include <sys/kernel.h> 30 #include <sys/kobj.h> 31 #include <sys/malloc.h> 32 #include <sys/systm.h> 33 34 #ifdef FDT 35 #include <dev/ofw/ofw_bus.h> 36 #include <dev/ofw/ofw_bus_subr.h> 37 #endif 38 39 #include <dev/hwreset/hwreset.h> 40 41 #include "hwreset_if.h" 42 43 struct hwreset { 44 device_t consumer_dev; /* consumer device*/ 45 device_t provider_dev; /* provider device*/ 46 int rst_id; /* reset id */ 47 }; 48 49 MALLOC_DEFINE(M_HWRESET, "hwreset", "Reset framework"); 50 51 int 52 hwreset_assert(hwreset_t rst) 53 { 54 55 return (HWRESET_ASSERT(rst->provider_dev, rst->rst_id, true)); 56 } 57 58 int 59 hwreset_deassert(hwreset_t rst) 60 { 61 62 return (HWRESET_ASSERT(rst->provider_dev, rst->rst_id, false)); 63 } 64 65 int 66 hwreset_is_asserted(hwreset_t rst, bool *value) 67 { 68 69 return (HWRESET_IS_ASSERTED(rst->provider_dev, rst->rst_id, value)); 70 } 71 72 void 73 hwreset_release(hwreset_t rst) 74 { 75 free(rst, M_HWRESET); 76 } 77 78 int 79 hwreset_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id, 80 hwreset_t *rst_out) 81 { 82 hwreset_t rst; 83 84 /* Create handle */ 85 rst = malloc(sizeof(struct hwreset), M_HWRESET, 86 M_WAITOK | M_ZERO); 87 rst->consumer_dev = consumer_dev; 88 rst->provider_dev = provider_dev; 89 rst->rst_id = id; 90 *rst_out = rst; 91 return (0); 92 } 93 94 #ifdef FDT 95 int 96 hwreset_default_ofw_map(device_t provider_dev, phandle_t xref, int ncells, 97 pcell_t *cells, intptr_t *id) 98 { 99 if (ncells == 0) 100 *id = 1; 101 else if (ncells == 1) 102 *id = cells[0]; 103 else 104 return (ERANGE); 105 106 return (0); 107 } 108 109 int 110 hwreset_get_by_ofw_idx(device_t consumer_dev, phandle_t cnode, int idx, 111 hwreset_t *rst) 112 { 113 phandle_t xnode; 114 pcell_t *cells; 115 device_t rstdev; 116 int ncells, rv; 117 intptr_t id; 118 119 if (cnode <= 0) 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 147 int 148 hwreset_get_by_ofw_name(device_t consumer_dev, phandle_t cnode, char *name, 149 hwreset_t *rst) 150 { 151 int rv, idx; 152 153 if (cnode <= 0) 154 cnode = ofw_bus_get_node(consumer_dev); 155 if (cnode <= 0) { 156 device_printf(consumer_dev, 157 "%s called on not ofw based device\n", __func__); 158 return (ENXIO); 159 } 160 rv = ofw_bus_find_string_index(cnode, "reset-names", name, &idx); 161 if (rv != 0) 162 return (rv); 163 return (hwreset_get_by_ofw_idx(consumer_dev, cnode, idx, rst)); 164 } 165 166 void 167 hwreset_register_ofw_provider(device_t provider_dev) 168 { 169 phandle_t xref, node; 170 171 node = ofw_bus_get_node(provider_dev); 172 if (node <= 0) 173 panic("%s called on not ofw based device.\n", __func__); 174 175 xref = OF_xref_from_node(node); 176 OF_device_register_xref(xref, provider_dev); 177 } 178 179 void 180 hwreset_unregister_ofw_provider(device_t provider_dev) 181 { 182 phandle_t xref; 183 184 xref = OF_xref_from_device(provider_dev); 185 OF_device_register_xref(xref, NULL); 186 } 187 #endif 188