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