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