phy.c revision 308324
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: stable/11/sys/dev/extres/phy/phy.c 308324 2016-11-05 04:17:32Z mmel $ 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 127308324Smmelphy_get_by_ofw_idx(device_t consumer_dev, phandle_t cnode, int idx, phy_t *phy) 128296907Smmel{ 129308324Smmel phandle_t xnode; 130296907Smmel pcell_t *cells; 131296907Smmel device_t phydev; 132296907Smmel int ncells, rv; 133296907Smmel intptr_t id; 134296907Smmel 135308324Smmel if (cnode <= 0) 136308324Smmel cnode = ofw_bus_get_node(consumer_dev); 137296907Smmel if (cnode <= 0) { 138296907Smmel device_printf(consumer_dev, 139296907Smmel "%s called on not ofw based device\n", __func__); 140296907Smmel return (ENXIO); 141296907Smmel } 142296907Smmel rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx, 143296907Smmel &xnode, &ncells, &cells); 144296907Smmel if (rv != 0) 145296907Smmel return (rv); 146296907Smmel 147296907Smmel /* Tranlate provider to device. */ 148296907Smmel phydev = OF_device_from_xref(xnode); 149296907Smmel if (phydev == NULL) { 150299714Sgonzo OF_prop_free(cells); 151296907Smmel return (ENODEV); 152296907Smmel } 153296907Smmel /* Map phy to number. */ 154296907Smmel rv = PHY_MAP(phydev, xnode, ncells, cells, &id); 155299714Sgonzo OF_prop_free(cells); 156296907Smmel if (rv != 0) 157296907Smmel return (rv); 158296907Smmel 159296907Smmel return (phy_get_by_id(consumer_dev, phydev, id, phy)); 160296907Smmel} 161296907Smmel 162296907Smmelint 163308324Smmelphy_get_by_ofw_name(device_t consumer_dev, phandle_t cnode, char *name, 164308324Smmel phy_t *phy) 165296907Smmel{ 166296907Smmel int rv, idx; 167296907Smmel 168308324Smmel if (cnode <= 0) 169308324Smmel cnode = ofw_bus_get_node(consumer_dev); 170296907Smmel if (cnode <= 0) { 171296907Smmel device_printf(consumer_dev, 172296907Smmel "%s called on not ofw based device\n", __func__); 173296907Smmel return (ENXIO); 174296907Smmel } 175296907Smmel rv = ofw_bus_find_string_index(cnode, "phy-names", name, &idx); 176296907Smmel if (rv != 0) 177296907Smmel return (rv); 178308324Smmel return (phy_get_by_ofw_idx(consumer_dev, cnode, idx, phy)); 179296907Smmel} 180296907Smmel 181296907Smmelint 182308324Smmelphy_get_by_ofw_property(device_t consumer_dev, phandle_t cnode, char *name, 183308324Smmel phy_t *phy) 184296907Smmel{ 185296907Smmel pcell_t *cells; 186296907Smmel device_t phydev; 187296907Smmel int ncells, rv; 188296907Smmel intptr_t id; 189296907Smmel 190308324Smmel if (cnode <= 0) 191308324Smmel cnode = ofw_bus_get_node(consumer_dev); 192296907Smmel if (cnode <= 0) { 193296907Smmel device_printf(consumer_dev, 194296907Smmel "%s called on not ofw based device\n", __func__); 195296907Smmel return (ENXIO); 196296907Smmel } 197296907Smmel ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t), 198296907Smmel (void **)&cells); 199296907Smmel if (ncells < 1) 200296907Smmel return (ENXIO); 201296907Smmel 202296907Smmel /* Tranlate provider to device. */ 203296907Smmel phydev = OF_device_from_xref(cells[0]); 204296907Smmel if (phydev == NULL) { 205299714Sgonzo OF_prop_free(cells); 206296907Smmel return (ENODEV); 207296907Smmel } 208296907Smmel /* Map phy to number. */ 209296907Smmel rv = PHY_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id); 210299714Sgonzo OF_prop_free(cells); 211296907Smmel if (rv != 0) 212296907Smmel return (rv); 213296907Smmel 214296907Smmel return (phy_get_by_id(consumer_dev, phydev, id, phy)); 215296907Smmel} 216296907Smmel 217296907Smmelvoid 218296907Smmelphy_register_provider(device_t provider_dev) 219296907Smmel{ 220296907Smmel phandle_t xref, node; 221296907Smmel 222296907Smmel node = ofw_bus_get_node(provider_dev); 223296907Smmel if (node <= 0) 224296907Smmel panic("%s called on not ofw based device.\n", __func__); 225296907Smmel 226296907Smmel xref = OF_xref_from_node(node); 227296907Smmel OF_device_register_xref(xref, provider_dev); 228296907Smmel} 229296907Smmel 230296907Smmelvoid 231296907Smmelphy_unregister_provider(device_t provider_dev) 232296907Smmel{ 233296907Smmel phandle_t xref; 234296907Smmel 235296907Smmel xref = OF_xref_from_device(provider_dev); 236296907Smmel OF_device_register_xref(xref, NULL); 237296907Smmel} 238296907Smmel#endif 239