1296907Smmel/*-
2296907Smmel * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
3296907Smmel * All rights reserved.
4296907Smmel *
5296907Smmel * Redistribution and use in source and binary forms, with or without
6296907Smmel * modification, are permitted provided that the following conditions
7296907Smmel * are met:
8296907Smmel * 1. Redistributions of source code must retain the above copyright
9296907Smmel *    notice, this list of conditions and the following disclaimer.
10296907Smmel * 2. Redistributions in binary form must reproduce the above copyright
11296907Smmel *    notice, this list of conditions and the following disclaimer in the
12296907Smmel *    documentation and/or other materials provided with the distribution.
13296907Smmel *
14296907Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15296907Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16296907Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17296907Smmel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18296907Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19296907Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20296907Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21296907Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22296907Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23296907Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24296907Smmel * SUCH DAMAGE.
25296907Smmel */
26332025Smmel
27332025Smmel #include <sys/cdefs.h>
28332025Smmel__FBSDID("$FreeBSD: stable/11/sys/dev/extres/phy/phy.c 332025 2018-04-04 13:23:06Z mmel $");
29332025Smmel
30296907Smmel#include "opt_platform.h"
31296907Smmel#include <sys/param.h>
32296907Smmel#include <sys/kernel.h>
33332025Smmel#include <sys/kobj.h>
34332025Smmel#include <sys/lock.h>
35296907Smmel#include <sys/malloc.h>
36332025Smmel#include <sys/queue.h>
37296907Smmel#include <sys/systm.h>
38332025Smmel#include <sys/sx.h>
39296907Smmel
40296907Smmel#ifdef FDT
41296907Smmel#include <dev/ofw/ofw_bus.h>
42296907Smmel#include <dev/ofw/ofw_bus_subr.h>
43296907Smmel#endif
44296907Smmel
45296907Smmel#include  <dev/extres/phy/phy.h>
46296907Smmel
47332025Smmel#include "phydev_if.h"
48296907Smmel
49332025SmmelMALLOC_DEFINE(M_PHY, "phy", "Phy framework");
50332025Smmel
51332025Smmel/* Forward declarations. */
52332025Smmelstruct phy;
53332025Smmelstruct phynode;
54332025Smmel
55332025Smmeltypedef TAILQ_HEAD(phynode_list, phynode) phynode_list_t;
56332025Smmeltypedef TAILQ_HEAD(phy_list, phy) phy_list_t;
57332025Smmel
58332025Smmel/* Default phy methods. */
59332025Smmelstatic int phynode_method_init(struct phynode *phynode);
60332025Smmelstatic int phynode_method_enable(struct phynode *phynode, bool disable);
61332025Smmelstatic int phynode_method_status(struct phynode *phynode, int *status);
62332025Smmel
63332025Smmel
64332025Smmel/*
65332025Smmel * Phy controller methods.
66332025Smmel */
67332025Smmelstatic phynode_method_t phynode_methods[] = {
68332025Smmel	PHYNODEMETHOD(phynode_init,		phynode_method_init),
69332025Smmel	PHYNODEMETHOD(phynode_enable,		phynode_method_enable),
70332025Smmel	PHYNODEMETHOD(phynode_status,		phynode_method_status),
71332025Smmel
72332025Smmel	PHYNODEMETHOD_END
73332025Smmel};
74332025SmmelDEFINE_CLASS_0(phynode, phynode_class, phynode_methods, 0);
75332025Smmel
76332025Smmel/*
77332025Smmel * Phy node
78332025Smmel */
79332025Smmelstruct phynode {
80332025Smmel	KOBJ_FIELDS;
81332025Smmel
82332025Smmel	TAILQ_ENTRY(phynode)	phylist_link;	/* Global list entry */
83332025Smmel	phy_list_t		consumers_list;	/* Consumers list */
84332025Smmel
85332025Smmel
86332025Smmel	/* Details of this device. */
87332025Smmel	const char		*name;		/* Globally unique name */
88332025Smmel
89332025Smmel	device_t		pdev;		/* Producer device_t */
90332025Smmel	void			*softc;		/* Producer softc */
91332025Smmel	intptr_t		id;		/* Per producer unique id */
92332025Smmel#ifdef FDT
93332025Smmel	 phandle_t		ofw_node;	/* OFW node of phy */
94332025Smmel#endif
95332025Smmel	struct sx		lock;		/* Lock for this phy */
96332025Smmel	int			ref_cnt;	/* Reference counter */
97332025Smmel	int			enable_cnt;	/* Enabled counter */
98332025Smmel};
99332025Smmel
100296907Smmelstruct phy {
101332025Smmel	device_t		cdev;		/* consumer device*/
102332025Smmel	struct phynode		*phynode;
103332025Smmel	TAILQ_ENTRY(phy)	link;		/* Consumers list entry */
104332025Smmel
105332025Smmel	int			enable_cnt;
106296907Smmel};
107296907Smmel
108332025Smmelstatic phynode_list_t phynode_list = TAILQ_HEAD_INITIALIZER(phynode_list);
109296907Smmel
110332025Smmelstatic struct sx		phynode_topo_lock;
111332025SmmelSX_SYSINIT(phy_topology, &phynode_topo_lock, "Phy topology lock");
112332025Smmel
113332025Smmel#define PHY_TOPO_SLOCK()	sx_slock(&phynode_topo_lock)
114332025Smmel#define PHY_TOPO_XLOCK()	sx_xlock(&phynode_topo_lock)
115332025Smmel#define PHY_TOPO_UNLOCK()	sx_unlock(&phynode_topo_lock)
116332025Smmel#define PHY_TOPO_ASSERT()	sx_assert(&phynode_topo_lock, SA_LOCKED)
117332025Smmel#define PHY_TOPO_XASSERT() 	sx_assert(&phynode_topo_lock, SA_XLOCKED)
118332025Smmel
119332025Smmel#define PHYNODE_SLOCK(_sc)	sx_slock(&((_sc)->lock))
120332025Smmel#define PHYNODE_XLOCK(_sc)	sx_xlock(&((_sc)->lock))
121332025Smmel#define PHYNODE_UNLOCK(_sc)	sx_unlock(&((_sc)->lock))
122332025Smmel
123332025Smmel/* ----------------------------------------------------------------------------
124332025Smmel *
125332025Smmel * Default phy methods for base class.
126332025Smmel *
127332025Smmel */
128332025Smmel
129332025Smmelstatic int
130332025Smmelphynode_method_init(struct phynode *phynode)
131332025Smmel{
132332025Smmel
133332025Smmel	return (0);
134332025Smmel}
135332025Smmel
136332025Smmelstatic int
137332025Smmelphynode_method_enable(struct phynode *phynode, bool enable)
138332025Smmel{
139332025Smmel
140332025Smmel	if (!enable)
141332025Smmel		return (ENXIO);
142332025Smmel
143332025Smmel	return (0);
144332025Smmel}
145332025Smmel
146332025Smmelstatic int
147332025Smmelphynode_method_status(struct phynode *phynode, int *status)
148332025Smmel{
149332025Smmel	*status = PHY_STATUS_ENABLED;
150332025Smmel	return (0);
151332025Smmel}
152332025Smmel
153332025Smmel/* ----------------------------------------------------------------------------
154332025Smmel *
155332025Smmel * Internal functions.
156332025Smmel *
157332025Smmel */
158332025Smmel/*
159332025Smmel * Create and initialize phy object, but do not register it.
160332025Smmel */
161332025Smmelstruct phynode *
162332025Smmelphynode_create(device_t pdev, phynode_class_t phynode_class,
163332025Smmel    struct phynode_init_def *def)
164332025Smmel{
165332025Smmel	struct phynode *phynode;
166332025Smmel
167332025Smmel
168332025Smmel	/* Create object and initialize it. */
169332025Smmel	phynode = malloc(sizeof(struct phynode), M_PHY, M_WAITOK | M_ZERO);
170332025Smmel	kobj_init((kobj_t)phynode, (kobj_class_t)phynode_class);
171332025Smmel	sx_init(&phynode->lock, "Phy node lock");
172332025Smmel
173332025Smmel	/* Allocate softc if required. */
174332025Smmel	if (phynode_class->size > 0) {
175332025Smmel		phynode->softc = malloc(phynode_class->size, M_PHY,
176332025Smmel		    M_WAITOK | M_ZERO);
177332025Smmel	}
178332025Smmel
179332025Smmel	/* Rest of init. */
180332025Smmel	TAILQ_INIT(&phynode->consumers_list);
181332025Smmel	phynode->id = def->id;
182332025Smmel	phynode->pdev = pdev;
183332025Smmel#ifdef FDT
184332025Smmel	phynode->ofw_node = def->ofw_node;
185332025Smmel#endif
186332025Smmel
187332025Smmel	return (phynode);
188332025Smmel}
189332025Smmel
190332025Smmel/* Register phy object. */
191332025Smmelstruct phynode *
192332025Smmelphynode_register(struct phynode *phynode)
193332025Smmel{
194332025Smmel	int rv;
195332025Smmel
196332025Smmel#ifdef FDT
197332025Smmel	if (phynode->ofw_node <= 0)
198332025Smmel		phynode->ofw_node = ofw_bus_get_node(phynode->pdev);
199332025Smmel	if (phynode->ofw_node <= 0)
200332025Smmel		return (NULL);
201332025Smmel#endif
202332025Smmel
203332025Smmel	rv = PHYNODE_INIT(phynode);
204332025Smmel	if (rv != 0) {
205332025Smmel		printf("PHYNODE_INIT failed: %d\n", rv);
206332025Smmel		return (NULL);
207332025Smmel	}
208332025Smmel
209332025Smmel	PHY_TOPO_XLOCK();
210332025Smmel	TAILQ_INSERT_TAIL(&phynode_list, phynode, phylist_link);
211332025Smmel	PHY_TOPO_UNLOCK();
212332025Smmel#ifdef FDT
213332025Smmel	OF_device_register_xref(OF_xref_from_node(phynode->ofw_node),
214332025Smmel	    phynode->pdev);
215332025Smmel#endif
216332025Smmel	return (phynode);
217332025Smmel}
218332025Smmel
219332025Smmelstatic struct phynode *
220332025Smmelphynode_find_by_id(device_t dev, intptr_t id)
221332025Smmel{
222332025Smmel	struct phynode *entry;
223332025Smmel
224332025Smmel	PHY_TOPO_ASSERT();
225332025Smmel
226332025Smmel	TAILQ_FOREACH(entry, &phynode_list, phylist_link) {
227332025Smmel		if ((entry->pdev == dev) && (entry->id ==  id))
228332025Smmel			return (entry);
229332025Smmel	}
230332025Smmel
231332025Smmel	return (NULL);
232332025Smmel}
233332025Smmel
234332025Smmel/* --------------------------------------------------------------------------
235332025Smmel *
236332025Smmel * Phy providers interface
237332025Smmel *
238332025Smmel */
239332025Smmel
240332025Smmelvoid *
241332025Smmelphynode_get_softc(struct phynode *phynode)
242332025Smmel{
243332025Smmel
244332025Smmel	return (phynode->softc);
245332025Smmel}
246332025Smmel
247332025Smmeldevice_t
248332025Smmelphynode_get_device(struct phynode *phynode)
249332025Smmel{
250332025Smmel
251332025Smmel	return (phynode->pdev);
252332025Smmel}
253332025Smmel
254332025Smmelintptr_t phynode_get_id(struct phynode *phynode)
255332025Smmel{
256332025Smmel
257332025Smmel	return (phynode->id);
258332025Smmel}
259332025Smmel
260332025Smmel#ifdef FDT
261332025Smmelphandle_t
262332025Smmelphynode_get_ofw_node(struct phynode *phynode)
263332025Smmel{
264332025Smmel
265332025Smmel	return (phynode->ofw_node);
266332025Smmel}
267332025Smmel#endif
268332025Smmel
269332025Smmel/* --------------------------------------------------------------------------
270332025Smmel *
271332025Smmel * Real consumers executive
272332025Smmel *
273332025Smmel */
274332025Smmel
275332025Smmel/*
276332025Smmel * Enable phy.
277332025Smmel */
278296907Smmelint
279332025Smmelphynode_enable(struct phynode *phynode)
280296907Smmel{
281332025Smmel	int rv;
282296907Smmel
283332025Smmel	PHY_TOPO_ASSERT();
284332025Smmel
285332025Smmel	PHYNODE_XLOCK(phynode);
286332025Smmel	if (phynode->enable_cnt == 0) {
287332025Smmel		rv = PHYNODE_ENABLE(phynode, true);
288332025Smmel		if (rv != 0) {
289332025Smmel			PHYNODE_UNLOCK(phynode);
290332025Smmel			return (rv);
291332025Smmel		}
292332025Smmel	}
293332025Smmel	phynode->enable_cnt++;
294332025Smmel	PHYNODE_UNLOCK(phynode);
295332025Smmel	return (0);
296296907Smmel}
297296907Smmel
298332025Smmel/*
299332025Smmel * Disable phy.
300332025Smmel */
301296907Smmelint
302332025Smmelphynode_disable(struct phynode *phynode)
303296907Smmel{
304332025Smmel	int rv;
305296907Smmel
306332025Smmel	PHY_TOPO_ASSERT();
307332025Smmel
308332025Smmel	PHYNODE_XLOCK(phynode);
309332025Smmel	if (phynode->enable_cnt == 1) {
310332025Smmel		rv = PHYNODE_ENABLE(phynode, false);
311332025Smmel		if (rv != 0) {
312332025Smmel			PHYNODE_UNLOCK(phynode);
313332025Smmel			return (rv);
314332025Smmel		}
315332025Smmel	}
316332025Smmel	phynode->enable_cnt--;
317332025Smmel	PHYNODE_UNLOCK(phynode);
318332025Smmel	return (0);
319296907Smmel}
320296907Smmel
321296907Smmel
322332025Smmel/*
323332025Smmel * Get phy status. (PHY_STATUS_*)
324332025Smmel */
325296907Smmelint
326332025Smmelphynode_status(struct phynode *phynode, int *status)
327296907Smmel{
328332025Smmel	int rv;
329296907Smmel
330332025Smmel	PHY_TOPO_ASSERT();
331332025Smmel
332332025Smmel	PHYNODE_XLOCK(phynode);
333332025Smmel	rv = PHYNODE_STATUS(phynode, status);
334332025Smmel	PHYNODE_UNLOCK(phynode);
335332025Smmel	return (rv);
336296907Smmel}
337296907Smmel
338332025Smmel /* --------------------------------------------------------------------------
339332025Smmel *
340332025Smmel * Phy consumers interface.
341332025Smmel *
342332025Smmel */
343332025Smmel
344332025Smmel/* Helper function for phy_get*() */
345332025Smmelstatic phy_t
346332025Smmelphy_create(struct phynode *phynode, device_t cdev)
347332025Smmel{
348332025Smmel	struct phy *phy;
349332025Smmel
350332025Smmel	PHY_TOPO_ASSERT();
351332025Smmel
352332025Smmel	phy =  malloc(sizeof(struct phy), M_PHY, M_WAITOK | M_ZERO);
353332025Smmel	phy->cdev = cdev;
354332025Smmel	phy->phynode = phynode;
355332025Smmel	phy->enable_cnt = 0;
356332025Smmel
357332025Smmel	PHYNODE_XLOCK(phynode);
358332025Smmel	phynode->ref_cnt++;
359332025Smmel	TAILQ_INSERT_TAIL(&phynode->consumers_list, phy, link);
360332025Smmel	PHYNODE_UNLOCK(phynode);
361332025Smmel
362332025Smmel	return (phy);
363332025Smmel}
364332025Smmel
365296907Smmelint
366332025Smmelphy_enable(phy_t phy)
367296907Smmel{
368332025Smmel	int rv;
369332025Smmel	struct phynode *phynode;
370296907Smmel
371332025Smmel	phynode = phy->phynode;
372332025Smmel	KASSERT(phynode->ref_cnt > 0,
373332025Smmel	    ("Attempt to access unreferenced phy.\n"));
374332025Smmel
375332025Smmel	PHY_TOPO_SLOCK();
376332025Smmel	rv = phynode_enable(phynode);
377332025Smmel	if (rv == 0)
378332025Smmel		phy->enable_cnt++;
379332025Smmel	PHY_TOPO_UNLOCK();
380332025Smmel	return (rv);
381296907Smmel}
382296907Smmel
383296907Smmelint
384332025Smmelphy_disable(phy_t phy)
385296907Smmel{
386332025Smmel	int rv;
387332025Smmel	struct phynode *phynode;
388296907Smmel
389332025Smmel	phynode = phy->phynode;
390332025Smmel	KASSERT(phynode->ref_cnt > 0,
391332025Smmel	   ("Attempt to access unreferenced phy.\n"));
392332025Smmel	KASSERT(phy->enable_cnt > 0,
393332025Smmel	   ("Attempt to disable already disabled phy.\n"));
394332025Smmel
395332025Smmel	PHY_TOPO_SLOCK();
396332025Smmel	rv = phynode_disable(phynode);
397332025Smmel	if (rv == 0)
398332025Smmel		phy->enable_cnt--;
399332025Smmel	PHY_TOPO_UNLOCK();
400332025Smmel	return (rv);
401296907Smmel}
402296907Smmel
403296907Smmelint
404332025Smmelphy_status(phy_t phy, int *status)
405332025Smmel{
406332025Smmel	int rv;
407332025Smmel	struct phynode *phynode;
408332025Smmel
409332025Smmel	phynode = phy->phynode;
410332025Smmel	KASSERT(phynode->ref_cnt > 0,
411332025Smmel	   ("Attempt to access unreferenced phy.\n"));
412332025Smmel
413332025Smmel	PHY_TOPO_SLOCK();
414332025Smmel	rv = phynode_status(phynode, status);
415332025Smmel	PHY_TOPO_UNLOCK();
416332025Smmel	return (rv);
417332025Smmel}
418332025Smmel
419332025Smmelint
420296907Smmelphy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
421332025Smmel    phy_t *phy)
422296907Smmel{
423332025Smmel	struct phynode *phynode;
424296907Smmel
425332025Smmel	PHY_TOPO_SLOCK();
426332025Smmel
427332025Smmel	phynode = phynode_find_by_id(provider_dev, id);
428332025Smmel	if (phynode == NULL) {
429332025Smmel		PHY_TOPO_UNLOCK();
430332025Smmel		return (ENODEV);
431332025Smmel	}
432332025Smmel	*phy = phy_create(phynode, consumer_dev);
433332025Smmel	PHY_TOPO_UNLOCK();
434332025Smmel
435296907Smmel	return (0);
436296907Smmel}
437296907Smmel
438296907Smmelvoid
439296907Smmelphy_release(phy_t phy)
440296907Smmel{
441332025Smmel	struct phynode *phynode;
442332025Smmel
443332025Smmel	phynode = phy->phynode;
444332025Smmel	KASSERT(phynode->ref_cnt > 0,
445332025Smmel	   ("Attempt to access unreferenced phy.\n"));
446332025Smmel
447332025Smmel	PHY_TOPO_SLOCK();
448332025Smmel	while (phy->enable_cnt > 0) {
449332025Smmel		phynode_disable(phynode);
450332025Smmel		phy->enable_cnt--;
451332025Smmel	}
452332025Smmel	PHYNODE_XLOCK(phynode);
453332025Smmel	TAILQ_REMOVE(&phynode->consumers_list, phy, link);
454332025Smmel	phynode->ref_cnt--;
455332025Smmel	PHYNODE_UNLOCK(phynode);
456332025Smmel	PHY_TOPO_UNLOCK();
457332025Smmel
458296907Smmel	free(phy, M_PHY);
459296907Smmel}
460296907Smmel
461296907Smmel#ifdef FDT
462332025Smmelint phydev_default_ofw_map(device_t provider, phandle_t xref, int ncells,
463296907Smmel    pcell_t *cells, intptr_t *id)
464296907Smmel{
465332025Smmel	struct phynode *entry;
466332025Smmel	phandle_t node;
467296907Smmel
468332025Smmel	/* Single device can register multiple subnodes. */
469332025Smmel	if (ncells == 0) {
470332025Smmel
471332025Smmel		node = OF_node_from_xref(xref);
472332025Smmel		PHY_TOPO_XLOCK();
473332025Smmel		TAILQ_FOREACH(entry, &phynode_list, phylist_link) {
474332025Smmel			if ((entry->pdev == provider) &&
475332025Smmel			    (entry->ofw_node == node)) {
476332025Smmel				*id = entry->id;
477332025Smmel				PHY_TOPO_UNLOCK();
478332025Smmel				return (0);
479332025Smmel			}
480332025Smmel		}
481332025Smmel		PHY_TOPO_UNLOCK();
482332025Smmel		return (ERANGE);
483332025Smmel	}
484332025Smmel
485332025Smmel	/* First cell is ID. */
486332025Smmel	if (ncells == 1) {
487296907Smmel		*id = cells[0];
488332025Smmel		return (0);
489332025Smmel	}
490296907Smmel
491332025Smmel	/* No default way how to get ID, custom mapper is required. */
492332025Smmel	return  (ERANGE);
493296907Smmel}
494296907Smmel
495296907Smmelint
496308324Smmelphy_get_by_ofw_idx(device_t consumer_dev, phandle_t cnode, int idx, phy_t *phy)
497296907Smmel{
498308324Smmel	phandle_t xnode;
499296907Smmel	pcell_t *cells;
500296907Smmel	device_t phydev;
501296907Smmel	int ncells, rv;
502296907Smmel	intptr_t id;
503296907Smmel
504308324Smmel	if (cnode <= 0)
505308324Smmel		cnode = ofw_bus_get_node(consumer_dev);
506296907Smmel	if (cnode <= 0) {
507296907Smmel		device_printf(consumer_dev,
508296907Smmel		    "%s called on not ofw based device\n", __func__);
509296907Smmel		return (ENXIO);
510296907Smmel	}
511296907Smmel	rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx,
512296907Smmel	    &xnode, &ncells, &cells);
513296907Smmel	if (rv != 0)
514296907Smmel		return (rv);
515296907Smmel
516296907Smmel	/* Tranlate provider to device. */
517296907Smmel	phydev = OF_device_from_xref(xnode);
518296907Smmel	if (phydev == NULL) {
519299714Sgonzo		OF_prop_free(cells);
520296907Smmel		return (ENODEV);
521296907Smmel	}
522296907Smmel	/* Map phy to number. */
523332025Smmel	rv = PHYDEV_MAP(phydev, xnode, ncells, cells, &id);
524299714Sgonzo	OF_prop_free(cells);
525296907Smmel	if (rv != 0)
526296907Smmel		return (rv);
527296907Smmel
528296907Smmel	return (phy_get_by_id(consumer_dev, phydev, id, phy));
529296907Smmel}
530296907Smmel
531296907Smmelint
532308324Smmelphy_get_by_ofw_name(device_t consumer_dev, phandle_t cnode, char *name,
533308324Smmel    phy_t *phy)
534296907Smmel{
535296907Smmel	int rv, idx;
536296907Smmel
537308324Smmel	if (cnode <= 0)
538308324Smmel		cnode = ofw_bus_get_node(consumer_dev);
539296907Smmel	if (cnode <= 0) {
540296907Smmel		device_printf(consumer_dev,
541296907Smmel		    "%s called on not ofw based device\n",  __func__);
542296907Smmel		return (ENXIO);
543296907Smmel	}
544296907Smmel	rv = ofw_bus_find_string_index(cnode, "phy-names", name, &idx);
545296907Smmel	if (rv != 0)
546296907Smmel		return (rv);
547308324Smmel	return (phy_get_by_ofw_idx(consumer_dev, cnode, idx, phy));
548296907Smmel}
549296907Smmel
550296907Smmelint
551308324Smmelphy_get_by_ofw_property(device_t consumer_dev, phandle_t cnode, char *name,
552308324Smmel    phy_t *phy)
553296907Smmel{
554296907Smmel	pcell_t *cells;
555296907Smmel	device_t phydev;
556296907Smmel	int ncells, rv;
557296907Smmel	intptr_t id;
558296907Smmel
559308324Smmel	if (cnode <= 0)
560308324Smmel		cnode = ofw_bus_get_node(consumer_dev);
561296907Smmel	if (cnode <= 0) {
562296907Smmel		device_printf(consumer_dev,
563296907Smmel		    "%s called on not ofw based device\n", __func__);
564296907Smmel		return (ENXIO);
565296907Smmel	}
566296907Smmel	ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t),
567296907Smmel	    (void **)&cells);
568296907Smmel	if (ncells < 1)
569296907Smmel		return (ENXIO);
570296907Smmel
571296907Smmel	/* Tranlate provider to device. */
572296907Smmel	phydev = OF_device_from_xref(cells[0]);
573296907Smmel	if (phydev == NULL) {
574299714Sgonzo		OF_prop_free(cells);
575296907Smmel		return (ENODEV);
576296907Smmel	}
577296907Smmel	/* Map phy to number. */
578332025Smmel	rv = PHYDEV_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id);
579299714Sgonzo	OF_prop_free(cells);
580296907Smmel	if (rv != 0)
581296907Smmel		return (rv);
582296907Smmel
583296907Smmel	return (phy_get_by_id(consumer_dev, phydev, id, phy));
584296907Smmel}
585296907Smmel#endif
586