phy.c revision 299714
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 *
26296907Smmel * $FreeBSD: head/sys/dev/extres/phy/phy.c 299714 2016-05-14 04:59:36Z gonzo $
27296907Smmel */
28296907Smmel#include "opt_platform.h"
29296907Smmel#include <sys/cdefs.h>
30296907Smmel#include <sys/param.h>
31296907Smmel#include <sys/kernel.h>
32296907Smmel#include <sys/malloc.h>
33296907Smmel#include <sys/systm.h>
34296907Smmel
35296907Smmel#ifdef FDT
36296907Smmel#include <dev/ofw/ofw_bus.h>
37296907Smmel#include <dev/ofw/ofw_bus_subr.h>
38296907Smmel#endif
39296907Smmel
40296907Smmel#include  <dev/extres/phy/phy.h>
41296907Smmel
42296907Smmel#include "phy_if.h"
43296907Smmel
44296907Smmelstruct phy {
45296907Smmel	device_t	consumer_dev;	/* consumer device*/
46296907Smmel	device_t	provider_dev;	/* provider device*/
47296907Smmel	uintptr_t	phy_id;		/* phy id */
48296907Smmel};
49296907Smmel
50296907SmmelMALLOC_DEFINE(M_PHY, "phy", "Phy framework");
51296907Smmel
52296907Smmelint
53296907Smmelphy_init(device_t consumer, phy_t phy)
54296907Smmel{
55296907Smmel
56296907Smmel	return (PHY_INIT(phy->provider_dev, phy->phy_id, true));
57296907Smmel}
58296907Smmel
59296907Smmelint
60296907Smmelphy_deinit(device_t consumer, phy_t phy)
61296907Smmel{
62296907Smmel
63296907Smmel	return (PHY_INIT(phy->provider_dev, phy->phy_id, false));
64296907Smmel}
65296907Smmel
66296907Smmel
67296907Smmelint
68296907Smmelphy_enable(device_t consumer, phy_t phy)
69296907Smmel{
70296907Smmel
71296907Smmel	return (PHY_ENABLE(phy->provider_dev, phy->phy_id, true));
72296907Smmel}
73296907Smmel
74296907Smmelint
75296907Smmelphy_disable(device_t consumer, phy_t phy)
76296907Smmel{
77296907Smmel
78296907Smmel	return (PHY_ENABLE(phy->provider_dev, phy->phy_id, false));
79296907Smmel}
80296907Smmel
81296907Smmelint
82296907Smmelphy_status(device_t consumer, phy_t phy, int *value)
83296907Smmel{
84296907Smmel
85296907Smmel	return (PHY_STATUS(phy->provider_dev, phy->phy_id, value));
86296907Smmel}
87296907Smmel
88296907Smmelint
89296907Smmelphy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
90296907Smmel    phy_t *phy_out)
91296907Smmel{
92296907Smmel	phy_t phy;
93296907Smmel
94296907Smmel	/* Create handle */
95296907Smmel	phy = malloc(sizeof(struct phy), M_PHY,
96296907Smmel	    M_WAITOK | M_ZERO);
97296907Smmel	phy->consumer_dev = consumer_dev;
98296907Smmel	phy->provider_dev = provider_dev;
99296907Smmel	phy->phy_id = id;
100296907Smmel	*phy_out = phy;
101296907Smmel	return (0);
102296907Smmel}
103296907Smmel
104296907Smmelvoid
105296907Smmelphy_release(phy_t phy)
106296907Smmel{
107296907Smmel	free(phy, M_PHY);
108296907Smmel}
109296907Smmel
110296907Smmel
111296907Smmel#ifdef FDT
112296907Smmelint phy_default_map(device_t provider, phandle_t xref, int ncells,
113296907Smmel    pcell_t *cells, intptr_t *id)
114296907Smmel{
115296907Smmel
116296907Smmel	if (ncells == 0)
117296907Smmel		*id = 1;
118296907Smmel	else if (ncells == 1)
119296907Smmel		*id = cells[0];
120296907Smmel	else
121296907Smmel		return  (ERANGE);
122296907Smmel
123296907Smmel	return (0);
124296907Smmel}
125296907Smmel
126296907Smmelint
127296907Smmelphy_get_by_ofw_idx(device_t consumer_dev, int idx, phy_t *phy)
128296907Smmel{
129296907Smmel	phandle_t cnode, xnode;
130296907Smmel	pcell_t *cells;
131296907Smmel	device_t phydev;
132296907Smmel	int ncells, rv;
133296907Smmel	intptr_t id;
134296907Smmel
135296907Smmel	cnode = ofw_bus_get_node(consumer_dev);
136296907Smmel	if (cnode <= 0) {
137296907Smmel		device_printf(consumer_dev,
138296907Smmel		    "%s called on not ofw based device\n", __func__);
139296907Smmel		return (ENXIO);
140296907Smmel	}
141296907Smmel	rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx,
142296907Smmel	    &xnode, &ncells, &cells);
143296907Smmel	if (rv != 0)
144296907Smmel		return (rv);
145296907Smmel
146296907Smmel	/* Tranlate provider to device. */
147296907Smmel	phydev = OF_device_from_xref(xnode);
148296907Smmel	if (phydev == NULL) {
149299714Sgonzo		OF_prop_free(cells);
150296907Smmel		return (ENODEV);
151296907Smmel	}
152296907Smmel	/* Map phy to number. */
153296907Smmel	rv = PHY_MAP(phydev, xnode, ncells, cells, &id);
154299714Sgonzo	OF_prop_free(cells);
155296907Smmel	if (rv != 0)
156296907Smmel		return (rv);
157296907Smmel
158296907Smmel	return (phy_get_by_id(consumer_dev, phydev, id, phy));
159296907Smmel}
160296907Smmel
161296907Smmelint
162296907Smmelphy_get_by_ofw_name(device_t consumer_dev, char *name, phy_t *phy)
163296907Smmel{
164296907Smmel	int rv, idx;
165296907Smmel	phandle_t cnode;
166296907Smmel
167296907Smmel	cnode = ofw_bus_get_node(consumer_dev);
168296907Smmel	if (cnode <= 0) {
169296907Smmel		device_printf(consumer_dev,
170296907Smmel		    "%s called on not ofw based device\n",  __func__);
171296907Smmel		return (ENXIO);
172296907Smmel	}
173296907Smmel	rv = ofw_bus_find_string_index(cnode, "phy-names", name, &idx);
174296907Smmel	if (rv != 0)
175296907Smmel		return (rv);
176296907Smmel	return (phy_get_by_ofw_idx(consumer_dev, idx, phy));
177296907Smmel}
178296907Smmel
179296907Smmelint
180296907Smmelphy_get_by_ofw_property(device_t consumer_dev, char *name, phy_t *phy)
181296907Smmel{
182296907Smmel	phandle_t cnode;
183296907Smmel	pcell_t *cells;
184296907Smmel	device_t phydev;
185296907Smmel	int ncells, rv;
186296907Smmel	intptr_t id;
187296907Smmel
188296907Smmel	cnode = ofw_bus_get_node(consumer_dev);
189296907Smmel	if (cnode <= 0) {
190296907Smmel		device_printf(consumer_dev,
191296907Smmel		    "%s called on not ofw based device\n", __func__);
192296907Smmel		return (ENXIO);
193296907Smmel	}
194296907Smmel	ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t),
195296907Smmel	    (void **)&cells);
196296907Smmel	if (ncells < 1)
197296907Smmel		return (ENXIO);
198296907Smmel
199296907Smmel	/* Tranlate provider to device. */
200296907Smmel	phydev = OF_device_from_xref(cells[0]);
201296907Smmel	if (phydev == NULL) {
202299714Sgonzo		OF_prop_free(cells);
203296907Smmel		return (ENODEV);
204296907Smmel	}
205296907Smmel	/* Map phy to number. */
206296907Smmel	rv = PHY_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id);
207299714Sgonzo	OF_prop_free(cells);
208296907Smmel	if (rv != 0)
209296907Smmel		return (rv);
210296907Smmel
211296907Smmel	return (phy_get_by_id(consumer_dev, phydev, id, phy));
212296907Smmel}
213296907Smmel
214296907Smmelvoid
215296907Smmelphy_register_provider(device_t provider_dev)
216296907Smmel{
217296907Smmel	phandle_t xref, node;
218296907Smmel
219296907Smmel	node = ofw_bus_get_node(provider_dev);
220296907Smmel	if (node <= 0)
221296907Smmel		panic("%s called on not ofw based device.\n", __func__);
222296907Smmel
223296907Smmel	xref = OF_xref_from_node(node);
224296907Smmel	OF_device_register_xref(xref, provider_dev);
225296907Smmel}
226296907Smmel
227296907Smmelvoid
228296907Smmelphy_unregister_provider(device_t provider_dev)
229296907Smmel{
230296907Smmel	phandle_t xref;
231296907Smmel
232296907Smmel	xref = OF_xref_from_device(provider_dev);
233296907Smmel	OF_device_register_xref(xref, NULL);
234296907Smmel}
235296907Smmel#endif
236