]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/extres/phy/phy.c
Update to bmake-20171028
[FreeBSD/FreeBSD.git] / sys / dev / extres / phy / phy.c
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$
27  */
28 #include "opt_platform.h"
29 #include <sys/cdefs.h>
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/systm.h>
34
35 #ifdef FDT
36 #include <dev/ofw/ofw_bus.h>
37 #include <dev/ofw/ofw_bus_subr.h>
38 #endif
39
40 #include  <dev/extres/phy/phy.h>
41
42 #include "phy_if.h"
43
44 struct phy {
45         device_t        consumer_dev;   /* consumer device*/
46         device_t        provider_dev;   /* provider device*/
47         uintptr_t       phy_id;         /* phy id */
48 };
49
50 MALLOC_DEFINE(M_PHY, "phy", "Phy framework");
51
52 int
53 phy_init(device_t consumer, phy_t phy)
54 {
55
56         return (PHY_INIT(phy->provider_dev, phy->phy_id, true));
57 }
58
59 int
60 phy_deinit(device_t consumer, phy_t phy)
61 {
62
63         return (PHY_INIT(phy->provider_dev, phy->phy_id, false));
64 }
65
66
67 int
68 phy_enable(device_t consumer, phy_t phy)
69 {
70
71         return (PHY_ENABLE(phy->provider_dev, phy->phy_id, true));
72 }
73
74 int
75 phy_disable(device_t consumer, phy_t phy)
76 {
77
78         return (PHY_ENABLE(phy->provider_dev, phy->phy_id, false));
79 }
80
81 int
82 phy_status(device_t consumer, phy_t phy, int *value)
83 {
84
85         return (PHY_STATUS(phy->provider_dev, phy->phy_id, value));
86 }
87
88 int
89 phy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
90     phy_t *phy_out)
91 {
92         phy_t phy;
93
94         /* Create handle */
95         phy = malloc(sizeof(struct phy), M_PHY,
96             M_WAITOK | M_ZERO);
97         phy->consumer_dev = consumer_dev;
98         phy->provider_dev = provider_dev;
99         phy->phy_id = id;
100         *phy_out = phy;
101         return (0);
102 }
103
104 void
105 phy_release(phy_t phy)
106 {
107         free(phy, M_PHY);
108 }
109
110
111 #ifdef FDT
112 int phy_default_map(device_t provider, phandle_t xref, int ncells,
113     pcell_t *cells, intptr_t *id)
114 {
115
116         if (ncells == 0)
117                 *id = 1;
118         else if (ncells == 1)
119                 *id = cells[0];
120         else
121                 return  (ERANGE);
122
123         return (0);
124 }
125
126 int
127 phy_get_by_ofw_idx(device_t consumer_dev, phandle_t cnode, int idx, phy_t *phy)
128 {
129         phandle_t xnode;
130         pcell_t *cells;
131         device_t phydev;
132         int ncells, rv;
133         intptr_t id;
134
135         if (cnode <= 0)
136                 cnode = ofw_bus_get_node(consumer_dev);
137         if (cnode <= 0) {
138                 device_printf(consumer_dev,
139                     "%s called on not ofw based device\n", __func__);
140                 return (ENXIO);
141         }
142         rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx,
143             &xnode, &ncells, &cells);
144         if (rv != 0)
145                 return (rv);
146
147         /* Tranlate provider to device. */
148         phydev = OF_device_from_xref(xnode);
149         if (phydev == NULL) {
150                 OF_prop_free(cells);
151                 return (ENODEV);
152         }
153         /* Map phy to number. */
154         rv = PHY_MAP(phydev, xnode, ncells, cells, &id);
155         OF_prop_free(cells);
156         if (rv != 0)
157                 return (rv);
158
159         return (phy_get_by_id(consumer_dev, phydev, id, phy));
160 }
161
162 int
163 phy_get_by_ofw_name(device_t consumer_dev, phandle_t cnode, char *name,
164     phy_t *phy)
165 {
166         int rv, idx;
167
168         if (cnode <= 0)
169                 cnode = ofw_bus_get_node(consumer_dev);
170         if (cnode <= 0) {
171                 device_printf(consumer_dev,
172                     "%s called on not ofw based device\n",  __func__);
173                 return (ENXIO);
174         }
175         rv = ofw_bus_find_string_index(cnode, "phy-names", name, &idx);
176         if (rv != 0)
177                 return (rv);
178         return (phy_get_by_ofw_idx(consumer_dev, cnode, idx, phy));
179 }
180
181 int
182 phy_get_by_ofw_property(device_t consumer_dev, phandle_t cnode, char *name,
183     phy_t *phy)
184 {
185         pcell_t *cells;
186         device_t phydev;
187         int ncells, rv;
188         intptr_t id;
189
190         if (cnode <= 0)
191                 cnode = ofw_bus_get_node(consumer_dev);
192         if (cnode <= 0) {
193                 device_printf(consumer_dev,
194                     "%s called on not ofw based device\n", __func__);
195                 return (ENXIO);
196         }
197         ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t),
198             (void **)&cells);
199         if (ncells < 1)
200                 return (ENXIO);
201
202         /* Tranlate provider to device. */
203         phydev = OF_device_from_xref(cells[0]);
204         if (phydev == NULL) {
205                 OF_prop_free(cells);
206                 return (ENODEV);
207         }
208         /* Map phy to number. */
209         rv = PHY_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id);
210         OF_prop_free(cells);
211         if (rv != 0)
212                 return (rv);
213
214         return (phy_get_by_id(consumer_dev, phydev, id, phy));
215 }
216
217 void
218 phy_register_provider(device_t provider_dev)
219 {
220         phandle_t xref, node;
221
222         node = ofw_bus_get_node(provider_dev);
223         if (node <= 0)
224                 panic("%s called on not ofw based device.\n", __func__);
225
226         xref = OF_xref_from_node(node);
227         OF_device_register_xref(xref, provider_dev);
228 }
229
230 void
231 phy_unregister_provider(device_t provider_dev)
232 {
233         phandle_t xref;
234
235         xref = OF_xref_from_device(provider_dev);
236         OF_device_register_xref(xref, NULL);
237 }
238 #endif