xref: /freebsd/sys/dev/phy/phy.c (revision 950a6087)
1*950a6087SEmmanuel Vadot /*-
2*950a6087SEmmanuel Vadot  * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
3*950a6087SEmmanuel Vadot  *
4*950a6087SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
5*950a6087SEmmanuel Vadot  * modification, are permitted provided that the following conditions
6*950a6087SEmmanuel Vadot  * are met:
7*950a6087SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
8*950a6087SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
9*950a6087SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
10*950a6087SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
11*950a6087SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
12*950a6087SEmmanuel Vadot  *
13*950a6087SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*950a6087SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*950a6087SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*950a6087SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*950a6087SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*950a6087SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*950a6087SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*950a6087SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*950a6087SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*950a6087SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*950a6087SEmmanuel Vadot  * SUCH DAMAGE.
24*950a6087SEmmanuel Vadot  */
25*950a6087SEmmanuel Vadot 
26*950a6087SEmmanuel Vadot  #include <sys/cdefs.h>
27*950a6087SEmmanuel Vadot 
28*950a6087SEmmanuel Vadot #include "opt_platform.h"
29*950a6087SEmmanuel Vadot #include <sys/param.h>
30*950a6087SEmmanuel Vadot #include <sys/kernel.h>
31*950a6087SEmmanuel Vadot #include <sys/kobj.h>
32*950a6087SEmmanuel Vadot #include <sys/lock.h>
33*950a6087SEmmanuel Vadot #include <sys/malloc.h>
34*950a6087SEmmanuel Vadot #include <sys/queue.h>
35*950a6087SEmmanuel Vadot #include <sys/systm.h>
36*950a6087SEmmanuel Vadot #include <sys/sx.h>
37*950a6087SEmmanuel Vadot 
38*950a6087SEmmanuel Vadot #ifdef FDT
39*950a6087SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
40*950a6087SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
41*950a6087SEmmanuel Vadot #endif
42*950a6087SEmmanuel Vadot 
43*950a6087SEmmanuel Vadot #include  <dev/phy/phy.h>
44*950a6087SEmmanuel Vadot #include  <dev/phy/phy_internal.h>
45*950a6087SEmmanuel Vadot 
46*950a6087SEmmanuel Vadot #ifdef FDT
47*950a6087SEmmanuel Vadot #include "phydev_if.h"
48*950a6087SEmmanuel Vadot #endif
49*950a6087SEmmanuel Vadot 
50*950a6087SEmmanuel Vadot MALLOC_DEFINE(M_PHY, "phy", "Phy framework");
51*950a6087SEmmanuel Vadot 
52*950a6087SEmmanuel Vadot /* Default phy methods. */
53*950a6087SEmmanuel Vadot static int phynode_method_init(struct phynode *phynode);
54*950a6087SEmmanuel Vadot static int phynode_method_enable(struct phynode *phynode, bool disable);
55*950a6087SEmmanuel Vadot static int phynode_method_status(struct phynode *phynode, int *status);
56*950a6087SEmmanuel Vadot 
57*950a6087SEmmanuel Vadot 
58*950a6087SEmmanuel Vadot /*
59*950a6087SEmmanuel Vadot  * Phy controller methods.
60*950a6087SEmmanuel Vadot  */
61*950a6087SEmmanuel Vadot static phynode_method_t phynode_methods[] = {
62*950a6087SEmmanuel Vadot 	PHYNODEMETHOD(phynode_init,		phynode_method_init),
63*950a6087SEmmanuel Vadot 	PHYNODEMETHOD(phynode_enable,		phynode_method_enable),
64*950a6087SEmmanuel Vadot 	PHYNODEMETHOD(phynode_status,		phynode_method_status),
65*950a6087SEmmanuel Vadot 
66*950a6087SEmmanuel Vadot 	PHYNODEMETHOD_END
67*950a6087SEmmanuel Vadot };
68*950a6087SEmmanuel Vadot DEFINE_CLASS_0(phynode, phynode_class, phynode_methods, 0);
69*950a6087SEmmanuel Vadot 
70*950a6087SEmmanuel Vadot static phynode_list_t phynode_list = TAILQ_HEAD_INITIALIZER(phynode_list);
71*950a6087SEmmanuel Vadot struct sx phynode_topo_lock;
72*950a6087SEmmanuel Vadot SX_SYSINIT(phy_topology, &phynode_topo_lock, "Phy topology lock");
73*950a6087SEmmanuel Vadot 
74*950a6087SEmmanuel Vadot /* ----------------------------------------------------------------------------
75*950a6087SEmmanuel Vadot  *
76*950a6087SEmmanuel Vadot  * Default phy methods for base class.
77*950a6087SEmmanuel Vadot  *
78*950a6087SEmmanuel Vadot  */
79*950a6087SEmmanuel Vadot 
80*950a6087SEmmanuel Vadot static int
phynode_method_init(struct phynode * phynode)81*950a6087SEmmanuel Vadot phynode_method_init(struct phynode *phynode)
82*950a6087SEmmanuel Vadot {
83*950a6087SEmmanuel Vadot 
84*950a6087SEmmanuel Vadot 	return (0);
85*950a6087SEmmanuel Vadot }
86*950a6087SEmmanuel Vadot 
87*950a6087SEmmanuel Vadot static int
phynode_method_enable(struct phynode * phynode,bool enable)88*950a6087SEmmanuel Vadot phynode_method_enable(struct phynode *phynode, bool enable)
89*950a6087SEmmanuel Vadot {
90*950a6087SEmmanuel Vadot 
91*950a6087SEmmanuel Vadot 	if (!enable)
92*950a6087SEmmanuel Vadot 		return (ENXIO);
93*950a6087SEmmanuel Vadot 
94*950a6087SEmmanuel Vadot 	return (0);
95*950a6087SEmmanuel Vadot }
96*950a6087SEmmanuel Vadot 
97*950a6087SEmmanuel Vadot static int
phynode_method_status(struct phynode * phynode,int * status)98*950a6087SEmmanuel Vadot phynode_method_status(struct phynode *phynode, int *status)
99*950a6087SEmmanuel Vadot {
100*950a6087SEmmanuel Vadot 	*status = PHY_STATUS_ENABLED;
101*950a6087SEmmanuel Vadot 	return (0);
102*950a6087SEmmanuel Vadot }
103*950a6087SEmmanuel Vadot 
104*950a6087SEmmanuel Vadot /* ----------------------------------------------------------------------------
105*950a6087SEmmanuel Vadot  *
106*950a6087SEmmanuel Vadot  * Internal functions.
107*950a6087SEmmanuel Vadot  *
108*950a6087SEmmanuel Vadot  */
109*950a6087SEmmanuel Vadot /*
110*950a6087SEmmanuel Vadot  * Create and initialize phy object, but do not register it.
111*950a6087SEmmanuel Vadot  */
112*950a6087SEmmanuel Vadot struct phynode *
phynode_create(device_t pdev,phynode_class_t phynode_class,struct phynode_init_def * def)113*950a6087SEmmanuel Vadot phynode_create(device_t pdev, phynode_class_t phynode_class,
114*950a6087SEmmanuel Vadot     struct phynode_init_def *def)
115*950a6087SEmmanuel Vadot {
116*950a6087SEmmanuel Vadot 	struct phynode *phynode;
117*950a6087SEmmanuel Vadot 
118*950a6087SEmmanuel Vadot 
119*950a6087SEmmanuel Vadot 	/* Create object and initialize it. */
120*950a6087SEmmanuel Vadot 	phynode = malloc(sizeof(struct phynode), M_PHY, M_WAITOK | M_ZERO);
121*950a6087SEmmanuel Vadot 	kobj_init((kobj_t)phynode, (kobj_class_t)phynode_class);
122*950a6087SEmmanuel Vadot 	sx_init(&phynode->lock, "Phy node lock");
123*950a6087SEmmanuel Vadot 
124*950a6087SEmmanuel Vadot 	/* Allocate softc if required. */
125*950a6087SEmmanuel Vadot 	if (phynode_class->size > 0) {
126*950a6087SEmmanuel Vadot 		phynode->softc = malloc(phynode_class->size, M_PHY,
127*950a6087SEmmanuel Vadot 		    M_WAITOK | M_ZERO);
128*950a6087SEmmanuel Vadot 	}
129*950a6087SEmmanuel Vadot 
130*950a6087SEmmanuel Vadot 	/* Rest of init. */
131*950a6087SEmmanuel Vadot 	TAILQ_INIT(&phynode->consumers_list);
132*950a6087SEmmanuel Vadot 	phynode->id = def->id;
133*950a6087SEmmanuel Vadot 	phynode->pdev = pdev;
134*950a6087SEmmanuel Vadot #ifdef FDT
135*950a6087SEmmanuel Vadot 	phynode->ofw_node = def->ofw_node;
136*950a6087SEmmanuel Vadot #endif
137*950a6087SEmmanuel Vadot 
138*950a6087SEmmanuel Vadot 	return (phynode);
139*950a6087SEmmanuel Vadot }
140*950a6087SEmmanuel Vadot 
141*950a6087SEmmanuel Vadot /* Register phy object. */
142*950a6087SEmmanuel Vadot struct phynode *
phynode_register(struct phynode * phynode)143*950a6087SEmmanuel Vadot phynode_register(struct phynode *phynode)
144*950a6087SEmmanuel Vadot {
145*950a6087SEmmanuel Vadot 	int rv;
146*950a6087SEmmanuel Vadot 
147*950a6087SEmmanuel Vadot #ifdef FDT
148*950a6087SEmmanuel Vadot 	if (phynode->ofw_node <= 0)
149*950a6087SEmmanuel Vadot 		phynode->ofw_node = ofw_bus_get_node(phynode->pdev);
150*950a6087SEmmanuel Vadot 	if (phynode->ofw_node <= 0)
151*950a6087SEmmanuel Vadot 		return (NULL);
152*950a6087SEmmanuel Vadot #endif
153*950a6087SEmmanuel Vadot 
154*950a6087SEmmanuel Vadot 	rv = PHYNODE_INIT(phynode);
155*950a6087SEmmanuel Vadot 	if (rv != 0) {
156*950a6087SEmmanuel Vadot 		printf("PHYNODE_INIT failed: %d\n", rv);
157*950a6087SEmmanuel Vadot 		return (NULL);
158*950a6087SEmmanuel Vadot 	}
159*950a6087SEmmanuel Vadot 
160*950a6087SEmmanuel Vadot 	PHY_TOPO_XLOCK();
161*950a6087SEmmanuel Vadot 	TAILQ_INSERT_TAIL(&phynode_list, phynode, phylist_link);
162*950a6087SEmmanuel Vadot 	PHY_TOPO_UNLOCK();
163*950a6087SEmmanuel Vadot #ifdef FDT
164*950a6087SEmmanuel Vadot 	OF_device_register_xref(OF_xref_from_node(phynode->ofw_node),
165*950a6087SEmmanuel Vadot 	    phynode->pdev);
166*950a6087SEmmanuel Vadot #endif
167*950a6087SEmmanuel Vadot 	return (phynode);
168*950a6087SEmmanuel Vadot }
169*950a6087SEmmanuel Vadot 
170*950a6087SEmmanuel Vadot static struct phynode *
phynode_find_by_id(device_t dev,intptr_t id)171*950a6087SEmmanuel Vadot phynode_find_by_id(device_t dev, intptr_t id)
172*950a6087SEmmanuel Vadot {
173*950a6087SEmmanuel Vadot 	struct phynode *entry;
174*950a6087SEmmanuel Vadot 
175*950a6087SEmmanuel Vadot 	PHY_TOPO_ASSERT();
176*950a6087SEmmanuel Vadot 
177*950a6087SEmmanuel Vadot 	TAILQ_FOREACH(entry, &phynode_list, phylist_link) {
178*950a6087SEmmanuel Vadot 		if ((entry->pdev == dev) && (entry->id ==  id))
179*950a6087SEmmanuel Vadot 			return (entry);
180*950a6087SEmmanuel Vadot 	}
181*950a6087SEmmanuel Vadot 
182*950a6087SEmmanuel Vadot 	return (NULL);
183*950a6087SEmmanuel Vadot }
184*950a6087SEmmanuel Vadot 
185*950a6087SEmmanuel Vadot /* --------------------------------------------------------------------------
186*950a6087SEmmanuel Vadot  *
187*950a6087SEmmanuel Vadot  * Phy providers interface
188*950a6087SEmmanuel Vadot  *
189*950a6087SEmmanuel Vadot  */
190*950a6087SEmmanuel Vadot 
191*950a6087SEmmanuel Vadot void *
phynode_get_softc(struct phynode * phynode)192*950a6087SEmmanuel Vadot phynode_get_softc(struct phynode *phynode)
193*950a6087SEmmanuel Vadot {
194*950a6087SEmmanuel Vadot 
195*950a6087SEmmanuel Vadot 	return (phynode->softc);
196*950a6087SEmmanuel Vadot }
197*950a6087SEmmanuel Vadot 
198*950a6087SEmmanuel Vadot device_t
phynode_get_device(struct phynode * phynode)199*950a6087SEmmanuel Vadot phynode_get_device(struct phynode *phynode)
200*950a6087SEmmanuel Vadot {
201*950a6087SEmmanuel Vadot 
202*950a6087SEmmanuel Vadot 	return (phynode->pdev);
203*950a6087SEmmanuel Vadot }
204*950a6087SEmmanuel Vadot 
phynode_get_id(struct phynode * phynode)205*950a6087SEmmanuel Vadot intptr_t phynode_get_id(struct phynode *phynode)
206*950a6087SEmmanuel Vadot {
207*950a6087SEmmanuel Vadot 
208*950a6087SEmmanuel Vadot 	return (phynode->id);
209*950a6087SEmmanuel Vadot }
210*950a6087SEmmanuel Vadot 
211*950a6087SEmmanuel Vadot #ifdef FDT
212*950a6087SEmmanuel Vadot phandle_t
phynode_get_ofw_node(struct phynode * phynode)213*950a6087SEmmanuel Vadot phynode_get_ofw_node(struct phynode *phynode)
214*950a6087SEmmanuel Vadot {
215*950a6087SEmmanuel Vadot 
216*950a6087SEmmanuel Vadot 	return (phynode->ofw_node);
217*950a6087SEmmanuel Vadot }
218*950a6087SEmmanuel Vadot #endif
219*950a6087SEmmanuel Vadot 
220*950a6087SEmmanuel Vadot /* --------------------------------------------------------------------------
221*950a6087SEmmanuel Vadot  *
222*950a6087SEmmanuel Vadot  * Real consumers executive
223*950a6087SEmmanuel Vadot  *
224*950a6087SEmmanuel Vadot  */
225*950a6087SEmmanuel Vadot 
226*950a6087SEmmanuel Vadot /*
227*950a6087SEmmanuel Vadot  * Enable phy.
228*950a6087SEmmanuel Vadot  */
229*950a6087SEmmanuel Vadot int
phynode_enable(struct phynode * phynode)230*950a6087SEmmanuel Vadot phynode_enable(struct phynode *phynode)
231*950a6087SEmmanuel Vadot {
232*950a6087SEmmanuel Vadot 	int rv;
233*950a6087SEmmanuel Vadot 
234*950a6087SEmmanuel Vadot 	PHY_TOPO_ASSERT();
235*950a6087SEmmanuel Vadot 
236*950a6087SEmmanuel Vadot 	PHYNODE_XLOCK(phynode);
237*950a6087SEmmanuel Vadot 	if (phynode->enable_cnt == 0) {
238*950a6087SEmmanuel Vadot 		rv = PHYNODE_ENABLE(phynode, true);
239*950a6087SEmmanuel Vadot 		if (rv != 0) {
240*950a6087SEmmanuel Vadot 			PHYNODE_UNLOCK(phynode);
241*950a6087SEmmanuel Vadot 			return (rv);
242*950a6087SEmmanuel Vadot 		}
243*950a6087SEmmanuel Vadot 	}
244*950a6087SEmmanuel Vadot 	phynode->enable_cnt++;
245*950a6087SEmmanuel Vadot 	PHYNODE_UNLOCK(phynode);
246*950a6087SEmmanuel Vadot 	return (0);
247*950a6087SEmmanuel Vadot }
248*950a6087SEmmanuel Vadot 
249*950a6087SEmmanuel Vadot /*
250*950a6087SEmmanuel Vadot  * Disable phy.
251*950a6087SEmmanuel Vadot  */
252*950a6087SEmmanuel Vadot int
phynode_disable(struct phynode * phynode)253*950a6087SEmmanuel Vadot phynode_disable(struct phynode *phynode)
254*950a6087SEmmanuel Vadot {
255*950a6087SEmmanuel Vadot 	int rv;
256*950a6087SEmmanuel Vadot 
257*950a6087SEmmanuel Vadot 	PHY_TOPO_ASSERT();
258*950a6087SEmmanuel Vadot 
259*950a6087SEmmanuel Vadot 	PHYNODE_XLOCK(phynode);
260*950a6087SEmmanuel Vadot 	if (phynode->enable_cnt == 1) {
261*950a6087SEmmanuel Vadot 		rv = PHYNODE_ENABLE(phynode, false);
262*950a6087SEmmanuel Vadot 		if (rv != 0) {
263*950a6087SEmmanuel Vadot 			PHYNODE_UNLOCK(phynode);
264*950a6087SEmmanuel Vadot 			return (rv);
265*950a6087SEmmanuel Vadot 		}
266*950a6087SEmmanuel Vadot 	}
267*950a6087SEmmanuel Vadot 	phynode->enable_cnt--;
268*950a6087SEmmanuel Vadot 	PHYNODE_UNLOCK(phynode);
269*950a6087SEmmanuel Vadot 	return (0);
270*950a6087SEmmanuel Vadot }
271*950a6087SEmmanuel Vadot 
272*950a6087SEmmanuel Vadot /*
273*950a6087SEmmanuel Vadot  * Set phy mode (protocol and its variant).
274*950a6087SEmmanuel Vadot  */
275*950a6087SEmmanuel Vadot int
phynode_set_mode(struct phynode * phynode,phy_mode_t mode,phy_submode_t submode)276*950a6087SEmmanuel Vadot phynode_set_mode(struct phynode *phynode, phy_mode_t mode,
277*950a6087SEmmanuel Vadot     phy_submode_t submode)
278*950a6087SEmmanuel Vadot {
279*950a6087SEmmanuel Vadot 	int rv;
280*950a6087SEmmanuel Vadot 
281*950a6087SEmmanuel Vadot 	PHY_TOPO_ASSERT();
282*950a6087SEmmanuel Vadot 
283*950a6087SEmmanuel Vadot 	PHYNODE_XLOCK(phynode);
284*950a6087SEmmanuel Vadot 	rv = PHYNODE_SET_MODE(phynode, mode, submode);
285*950a6087SEmmanuel Vadot 	PHYNODE_UNLOCK(phynode);
286*950a6087SEmmanuel Vadot 	return (rv);
287*950a6087SEmmanuel Vadot }
288*950a6087SEmmanuel Vadot 
289*950a6087SEmmanuel Vadot /*
290*950a6087SEmmanuel Vadot  * Get phy status. (PHY_STATUS_*)
291*950a6087SEmmanuel Vadot  */
292*950a6087SEmmanuel Vadot int
phynode_status(struct phynode * phynode,int * status)293*950a6087SEmmanuel Vadot phynode_status(struct phynode *phynode, int *status)
294*950a6087SEmmanuel Vadot {
295*950a6087SEmmanuel Vadot 	int rv;
296*950a6087SEmmanuel Vadot 
297*950a6087SEmmanuel Vadot 	PHY_TOPO_ASSERT();
298*950a6087SEmmanuel Vadot 
299*950a6087SEmmanuel Vadot 	PHYNODE_XLOCK(phynode);
300*950a6087SEmmanuel Vadot 	rv = PHYNODE_STATUS(phynode, status);
301*950a6087SEmmanuel Vadot 	PHYNODE_UNLOCK(phynode);
302*950a6087SEmmanuel Vadot 	return (rv);
303*950a6087SEmmanuel Vadot }
304*950a6087SEmmanuel Vadot 
305*950a6087SEmmanuel Vadot  /* --------------------------------------------------------------------------
306*950a6087SEmmanuel Vadot  *
307*950a6087SEmmanuel Vadot  * Phy consumers interface.
308*950a6087SEmmanuel Vadot  *
309*950a6087SEmmanuel Vadot  */
310*950a6087SEmmanuel Vadot 
311*950a6087SEmmanuel Vadot /* Helper function for phy_get*() */
312*950a6087SEmmanuel Vadot static phy_t
phy_create(struct phynode * phynode,device_t cdev)313*950a6087SEmmanuel Vadot phy_create(struct phynode *phynode, device_t cdev)
314*950a6087SEmmanuel Vadot {
315*950a6087SEmmanuel Vadot 	struct phy *phy;
316*950a6087SEmmanuel Vadot 
317*950a6087SEmmanuel Vadot 	PHY_TOPO_ASSERT();
318*950a6087SEmmanuel Vadot 
319*950a6087SEmmanuel Vadot 	phy =  malloc(sizeof(struct phy), M_PHY, M_WAITOK | M_ZERO);
320*950a6087SEmmanuel Vadot 	phy->cdev = cdev;
321*950a6087SEmmanuel Vadot 	phy->phynode = phynode;
322*950a6087SEmmanuel Vadot 	phy->enable_cnt = 0;
323*950a6087SEmmanuel Vadot 
324*950a6087SEmmanuel Vadot 	PHYNODE_XLOCK(phynode);
325*950a6087SEmmanuel Vadot 	phynode->ref_cnt++;
326*950a6087SEmmanuel Vadot 	TAILQ_INSERT_TAIL(&phynode->consumers_list, phy, link);
327*950a6087SEmmanuel Vadot 	PHYNODE_UNLOCK(phynode);
328*950a6087SEmmanuel Vadot 
329*950a6087SEmmanuel Vadot 	return (phy);
330*950a6087SEmmanuel Vadot }
331*950a6087SEmmanuel Vadot 
332*950a6087SEmmanuel Vadot int
phy_enable(phy_t phy)333*950a6087SEmmanuel Vadot phy_enable(phy_t phy)
334*950a6087SEmmanuel Vadot {
335*950a6087SEmmanuel Vadot 	int rv;
336*950a6087SEmmanuel Vadot 	struct phynode *phynode;
337*950a6087SEmmanuel Vadot 
338*950a6087SEmmanuel Vadot 	phynode = phy->phynode;
339*950a6087SEmmanuel Vadot 	KASSERT(phynode->ref_cnt > 0,
340*950a6087SEmmanuel Vadot 	    ("Attempt to access unreferenced phy.\n"));
341*950a6087SEmmanuel Vadot 
342*950a6087SEmmanuel Vadot 	PHY_TOPO_SLOCK();
343*950a6087SEmmanuel Vadot 	rv = phynode_enable(phynode);
344*950a6087SEmmanuel Vadot 	if (rv == 0)
345*950a6087SEmmanuel Vadot 		phy->enable_cnt++;
346*950a6087SEmmanuel Vadot 	PHY_TOPO_UNLOCK();
347*950a6087SEmmanuel Vadot 	return (rv);
348*950a6087SEmmanuel Vadot }
349*950a6087SEmmanuel Vadot 
350*950a6087SEmmanuel Vadot int
phy_disable(phy_t phy)351*950a6087SEmmanuel Vadot phy_disable(phy_t phy)
352*950a6087SEmmanuel Vadot {
353*950a6087SEmmanuel Vadot 	int rv;
354*950a6087SEmmanuel Vadot 	struct phynode *phynode;
355*950a6087SEmmanuel Vadot 
356*950a6087SEmmanuel Vadot 	phynode = phy->phynode;
357*950a6087SEmmanuel Vadot 	KASSERT(phynode->ref_cnt > 0,
358*950a6087SEmmanuel Vadot 	   ("Attempt to access unreferenced phy.\n"));
359*950a6087SEmmanuel Vadot 	KASSERT(phy->enable_cnt > 0,
360*950a6087SEmmanuel Vadot 	   ("Attempt to disable already disabled phy.\n"));
361*950a6087SEmmanuel Vadot 
362*950a6087SEmmanuel Vadot 	PHY_TOPO_SLOCK();
363*950a6087SEmmanuel Vadot 	rv = phynode_disable(phynode);
364*950a6087SEmmanuel Vadot 	if (rv == 0)
365*950a6087SEmmanuel Vadot 		phy->enable_cnt--;
366*950a6087SEmmanuel Vadot 	PHY_TOPO_UNLOCK();
367*950a6087SEmmanuel Vadot 	return (rv);
368*950a6087SEmmanuel Vadot }
369*950a6087SEmmanuel Vadot 
370*950a6087SEmmanuel Vadot int
phy_set_mode(phy_t phy,phy_mode_t mode,phy_submode_t submode)371*950a6087SEmmanuel Vadot phy_set_mode(phy_t phy, phy_mode_t mode, phy_submode_t submode)
372*950a6087SEmmanuel Vadot {
373*950a6087SEmmanuel Vadot 	int rv;
374*950a6087SEmmanuel Vadot 	struct phynode *phynode;
375*950a6087SEmmanuel Vadot 
376*950a6087SEmmanuel Vadot 	phynode = phy->phynode;
377*950a6087SEmmanuel Vadot 	KASSERT(phynode->ref_cnt > 0,
378*950a6087SEmmanuel Vadot 	   ("Attempt to access unreferenced phy.\n"));
379*950a6087SEmmanuel Vadot 
380*950a6087SEmmanuel Vadot 	PHY_TOPO_SLOCK();
381*950a6087SEmmanuel Vadot 	rv = phynode_set_mode(phynode, mode, submode);
382*950a6087SEmmanuel Vadot 	PHY_TOPO_UNLOCK();
383*950a6087SEmmanuel Vadot 	return (rv);
384*950a6087SEmmanuel Vadot }
385*950a6087SEmmanuel Vadot 
386*950a6087SEmmanuel Vadot int
phy_status(phy_t phy,int * status)387*950a6087SEmmanuel Vadot phy_status(phy_t phy, int *status)
388*950a6087SEmmanuel Vadot {
389*950a6087SEmmanuel Vadot 	int rv;
390*950a6087SEmmanuel Vadot 	struct phynode *phynode;
391*950a6087SEmmanuel Vadot 
392*950a6087SEmmanuel Vadot 	phynode = phy->phynode;
393*950a6087SEmmanuel Vadot 	KASSERT(phynode->ref_cnt > 0,
394*950a6087SEmmanuel Vadot 	   ("Attempt to access unreferenced phy.\n"));
395*950a6087SEmmanuel Vadot 
396*950a6087SEmmanuel Vadot 	PHY_TOPO_SLOCK();
397*950a6087SEmmanuel Vadot 	rv = phynode_status(phynode, status);
398*950a6087SEmmanuel Vadot 	PHY_TOPO_UNLOCK();
399*950a6087SEmmanuel Vadot 	return (rv);
400*950a6087SEmmanuel Vadot }
401*950a6087SEmmanuel Vadot 
402*950a6087SEmmanuel Vadot int
phy_get_by_id(device_t consumer_dev,device_t provider_dev,intptr_t id,phy_t * phy)403*950a6087SEmmanuel Vadot phy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
404*950a6087SEmmanuel Vadot     phy_t *phy)
405*950a6087SEmmanuel Vadot {
406*950a6087SEmmanuel Vadot 	struct phynode *phynode;
407*950a6087SEmmanuel Vadot 
408*950a6087SEmmanuel Vadot 	PHY_TOPO_SLOCK();
409*950a6087SEmmanuel Vadot 
410*950a6087SEmmanuel Vadot 	phynode = phynode_find_by_id(provider_dev, id);
411*950a6087SEmmanuel Vadot 	if (phynode == NULL) {
412*950a6087SEmmanuel Vadot 		PHY_TOPO_UNLOCK();
413*950a6087SEmmanuel Vadot 		return (ENODEV);
414*950a6087SEmmanuel Vadot 	}
415*950a6087SEmmanuel Vadot 	*phy = phy_create(phynode, consumer_dev);
416*950a6087SEmmanuel Vadot 	PHY_TOPO_UNLOCK();
417*950a6087SEmmanuel Vadot 
418*950a6087SEmmanuel Vadot 	return (0);
419*950a6087SEmmanuel Vadot }
420*950a6087SEmmanuel Vadot 
421*950a6087SEmmanuel Vadot void
phy_release(phy_t phy)422*950a6087SEmmanuel Vadot phy_release(phy_t phy)
423*950a6087SEmmanuel Vadot {
424*950a6087SEmmanuel Vadot 	struct phynode *phynode;
425*950a6087SEmmanuel Vadot 
426*950a6087SEmmanuel Vadot 	phynode = phy->phynode;
427*950a6087SEmmanuel Vadot 	KASSERT(phynode->ref_cnt > 0,
428*950a6087SEmmanuel Vadot 	   ("Attempt to access unreferenced phy.\n"));
429*950a6087SEmmanuel Vadot 
430*950a6087SEmmanuel Vadot 	PHY_TOPO_SLOCK();
431*950a6087SEmmanuel Vadot 	while (phy->enable_cnt > 0) {
432*950a6087SEmmanuel Vadot 		phynode_disable(phynode);
433*950a6087SEmmanuel Vadot 		phy->enable_cnt--;
434*950a6087SEmmanuel Vadot 	}
435*950a6087SEmmanuel Vadot 	PHYNODE_XLOCK(phynode);
436*950a6087SEmmanuel Vadot 	TAILQ_REMOVE(&phynode->consumers_list, phy, link);
437*950a6087SEmmanuel Vadot 	phynode->ref_cnt--;
438*950a6087SEmmanuel Vadot 	PHYNODE_UNLOCK(phynode);
439*950a6087SEmmanuel Vadot 	PHY_TOPO_UNLOCK();
440*950a6087SEmmanuel Vadot 
441*950a6087SEmmanuel Vadot 	free(phy, M_PHY);
442*950a6087SEmmanuel Vadot }
443*950a6087SEmmanuel Vadot 
444*950a6087SEmmanuel Vadot #ifdef FDT
phydev_default_ofw_map(device_t provider,phandle_t xref,int ncells,pcell_t * cells,intptr_t * id)445*950a6087SEmmanuel Vadot int phydev_default_ofw_map(device_t provider, phandle_t xref, int ncells,
446*950a6087SEmmanuel Vadot     pcell_t *cells, intptr_t *id)
447*950a6087SEmmanuel Vadot {
448*950a6087SEmmanuel Vadot 	struct phynode *entry;
449*950a6087SEmmanuel Vadot 	phandle_t node;
450*950a6087SEmmanuel Vadot 
451*950a6087SEmmanuel Vadot 	/* Single device can register multiple subnodes. */
452*950a6087SEmmanuel Vadot 	if (ncells == 0) {
453*950a6087SEmmanuel Vadot 
454*950a6087SEmmanuel Vadot 		node = OF_node_from_xref(xref);
455*950a6087SEmmanuel Vadot 		PHY_TOPO_XLOCK();
456*950a6087SEmmanuel Vadot 		TAILQ_FOREACH(entry, &phynode_list, phylist_link) {
457*950a6087SEmmanuel Vadot 			if ((entry->pdev == provider) &&
458*950a6087SEmmanuel Vadot 			    (entry->ofw_node == node)) {
459*950a6087SEmmanuel Vadot 				*id = entry->id;
460*950a6087SEmmanuel Vadot 				PHY_TOPO_UNLOCK();
461*950a6087SEmmanuel Vadot 				return (0);
462*950a6087SEmmanuel Vadot 			}
463*950a6087SEmmanuel Vadot 		}
464*950a6087SEmmanuel Vadot 		PHY_TOPO_UNLOCK();
465*950a6087SEmmanuel Vadot 		return (ERANGE);
466*950a6087SEmmanuel Vadot 	}
467*950a6087SEmmanuel Vadot 
468*950a6087SEmmanuel Vadot 	/* First cell is ID. */
469*950a6087SEmmanuel Vadot 	if (ncells == 1) {
470*950a6087SEmmanuel Vadot 		*id = cells[0];
471*950a6087SEmmanuel Vadot 		return (0);
472*950a6087SEmmanuel Vadot 	}
473*950a6087SEmmanuel Vadot 
474*950a6087SEmmanuel Vadot 	/* No default way how to get ID, custom mapper is required. */
475*950a6087SEmmanuel Vadot 	return  (ERANGE);
476*950a6087SEmmanuel Vadot }
477*950a6087SEmmanuel Vadot 
478*950a6087SEmmanuel Vadot int
phy_get_by_ofw_idx(device_t consumer_dev,phandle_t cnode,int idx,phy_t * phy)479*950a6087SEmmanuel Vadot phy_get_by_ofw_idx(device_t consumer_dev, phandle_t cnode, int idx, phy_t *phy)
480*950a6087SEmmanuel Vadot {
481*950a6087SEmmanuel Vadot 	phandle_t xnode;
482*950a6087SEmmanuel Vadot 	pcell_t *cells;
483*950a6087SEmmanuel Vadot 	device_t phydev;
484*950a6087SEmmanuel Vadot 	int ncells, rv;
485*950a6087SEmmanuel Vadot 	intptr_t id;
486*950a6087SEmmanuel Vadot 
487*950a6087SEmmanuel Vadot 	if (cnode <= 0)
488*950a6087SEmmanuel Vadot 		cnode = ofw_bus_get_node(consumer_dev);
489*950a6087SEmmanuel Vadot 	if (cnode <= 0) {
490*950a6087SEmmanuel Vadot 		device_printf(consumer_dev,
491*950a6087SEmmanuel Vadot 		    "%s called on not ofw based device\n", __func__);
492*950a6087SEmmanuel Vadot 		return (ENXIO);
493*950a6087SEmmanuel Vadot 	}
494*950a6087SEmmanuel Vadot 	rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx,
495*950a6087SEmmanuel Vadot 	    &xnode, &ncells, &cells);
496*950a6087SEmmanuel Vadot 	if (rv != 0)
497*950a6087SEmmanuel Vadot 		return (rv);
498*950a6087SEmmanuel Vadot 
499*950a6087SEmmanuel Vadot 	/* Tranlate provider to device. */
500*950a6087SEmmanuel Vadot 	phydev = OF_device_from_xref(xnode);
501*950a6087SEmmanuel Vadot 	if (phydev == NULL) {
502*950a6087SEmmanuel Vadot 		OF_prop_free(cells);
503*950a6087SEmmanuel Vadot 		return (ENODEV);
504*950a6087SEmmanuel Vadot 	}
505*950a6087SEmmanuel Vadot 	/* Map phy to number. */
506*950a6087SEmmanuel Vadot 	rv = PHYDEV_MAP(phydev, xnode, ncells, cells, &id);
507*950a6087SEmmanuel Vadot 	OF_prop_free(cells);
508*950a6087SEmmanuel Vadot 	if (rv != 0)
509*950a6087SEmmanuel Vadot 		return (rv);
510*950a6087SEmmanuel Vadot 
511*950a6087SEmmanuel Vadot 	return (phy_get_by_id(consumer_dev, phydev, id, phy));
512*950a6087SEmmanuel Vadot }
513*950a6087SEmmanuel Vadot 
514*950a6087SEmmanuel Vadot int
phy_get_by_ofw_name(device_t consumer_dev,phandle_t cnode,char * name,phy_t * phy)515*950a6087SEmmanuel Vadot phy_get_by_ofw_name(device_t consumer_dev, phandle_t cnode, char *name,
516*950a6087SEmmanuel Vadot     phy_t *phy)
517*950a6087SEmmanuel Vadot {
518*950a6087SEmmanuel Vadot 	int rv, idx;
519*950a6087SEmmanuel Vadot 
520*950a6087SEmmanuel Vadot 	if (cnode <= 0)
521*950a6087SEmmanuel Vadot 		cnode = ofw_bus_get_node(consumer_dev);
522*950a6087SEmmanuel Vadot 	if (cnode <= 0) {
523*950a6087SEmmanuel Vadot 		device_printf(consumer_dev,
524*950a6087SEmmanuel Vadot 		    "%s called on not ofw based device\n",  __func__);
525*950a6087SEmmanuel Vadot 		return (ENXIO);
526*950a6087SEmmanuel Vadot 	}
527*950a6087SEmmanuel Vadot 	rv = ofw_bus_find_string_index(cnode, "phy-names", name, &idx);
528*950a6087SEmmanuel Vadot 	if (rv != 0)
529*950a6087SEmmanuel Vadot 		return (rv);
530*950a6087SEmmanuel Vadot 	return (phy_get_by_ofw_idx(consumer_dev, cnode, idx, phy));
531*950a6087SEmmanuel Vadot }
532*950a6087SEmmanuel Vadot 
533*950a6087SEmmanuel Vadot int
phy_get_by_ofw_property(device_t consumer_dev,phandle_t cnode,char * name,phy_t * phy)534*950a6087SEmmanuel Vadot phy_get_by_ofw_property(device_t consumer_dev, phandle_t cnode, char *name,
535*950a6087SEmmanuel Vadot     phy_t *phy)
536*950a6087SEmmanuel Vadot {
537*950a6087SEmmanuel Vadot 	pcell_t *cells;
538*950a6087SEmmanuel Vadot 	device_t phydev;
539*950a6087SEmmanuel Vadot 	int ncells, rv;
540*950a6087SEmmanuel Vadot 	intptr_t id;
541*950a6087SEmmanuel Vadot 
542*950a6087SEmmanuel Vadot 	if (cnode <= 0)
543*950a6087SEmmanuel Vadot 		cnode = ofw_bus_get_node(consumer_dev);
544*950a6087SEmmanuel Vadot 	if (cnode <= 0) {
545*950a6087SEmmanuel Vadot 		device_printf(consumer_dev,
546*950a6087SEmmanuel Vadot 		    "%s called on not ofw based device\n", __func__);
547*950a6087SEmmanuel Vadot 		return (ENXIO);
548*950a6087SEmmanuel Vadot 	}
549*950a6087SEmmanuel Vadot 	ncells = OF_getencprop_alloc_multi(cnode, name, sizeof(pcell_t),
550*950a6087SEmmanuel Vadot 	    (void **)&cells);
551*950a6087SEmmanuel Vadot 	if (ncells < 1)
552*950a6087SEmmanuel Vadot 		return (ENOENT);
553*950a6087SEmmanuel Vadot 
554*950a6087SEmmanuel Vadot 	/* Tranlate provider to device. */
555*950a6087SEmmanuel Vadot 	phydev = OF_device_from_xref(cells[0]);
556*950a6087SEmmanuel Vadot 	if (phydev == NULL) {
557*950a6087SEmmanuel Vadot 		OF_prop_free(cells);
558*950a6087SEmmanuel Vadot 		return (ENODEV);
559*950a6087SEmmanuel Vadot 	}
560*950a6087SEmmanuel Vadot 	/* Map phy to number. */
561*950a6087SEmmanuel Vadot 	rv = PHYDEV_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id);
562*950a6087SEmmanuel Vadot 	OF_prop_free(cells);
563*950a6087SEmmanuel Vadot 	if (rv != 0)
564*950a6087SEmmanuel Vadot 		return (rv);
565*950a6087SEmmanuel Vadot 
566*950a6087SEmmanuel Vadot 	return (phy_get_by_id(consumer_dev, phydev, id, phy));
567*950a6087SEmmanuel Vadot }
568*950a6087SEmmanuel Vadot #endif
569