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