qemu/hw/mdio/core.c
<<
>>
Prefs
   1/*
   2 * QEMU MDIO bus & slave models
   3 *
   4 * Copyright (c) 2016 Xilinx Inc.
   5 *
   6 * Written by sai pavan boddu <saipava@xilinx.com>
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 * copies of the Software, and to permit persons to whom the Software is
  13 * furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 * THE SOFTWARE.
  25 *
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "hw/mdio/mdio_slave.h"
  30#include "hw/fdt_generic_util.h"
  31
  32struct MDIOBus *mdio_init_bus(DeviceState *parent, const char *name)
  33{
  34    struct MDIOBus *bus;
  35
  36    bus = MDIO_BUS(qbus_create(TYPE_MDIO_BUS, parent, name));
  37    return bus;
  38}
  39
  40void mdio_set_slave_addr(MDIOSlave *s, uint8_t addr)
  41{
  42    s->addr = addr;
  43}
  44
  45static MDIOSlave *mdio_find_slave(struct MDIOBus *bus, uint8_t addr)
  46{
  47    MDIOSlave *slave = NULL;
  48    BusChild *kid;
  49
  50    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
  51        DeviceState *qdev = kid->child;
  52        MDIOSlave *candidate = MDIO_SLAVE(qdev);
  53        if (addr == candidate->addr) {
  54            slave = candidate;
  55            break;
  56        }
  57    }
  58    return slave;
  59}
  60
  61int mdio_send(struct MDIOBus *bus, uint8_t addr, uint8_t reg, uint8_t data)
  62{
  63    MDIOSlave *slave = NULL;
  64    MDIOSlaveClass *sc;
  65
  66    if ((bus->cur_addr != addr) || !bus->cur_slave) {
  67        slave = mdio_find_slave(bus, addr);
  68        if (slave) {
  69            bus->cur_slave = slave;
  70            bus->cur_addr = addr;
  71        } else {
  72            return -1;
  73        }
  74    } else {
  75        slave = bus->cur_slave;
  76    }
  77
  78    sc = MDIO_SLAVE_GET_CLASS(slave);
  79    if (sc->send) {
  80        return sc->send(slave, reg, data);
  81    }
  82    return -1;
  83}
  84
  85int mdio_recv(struct MDIOBus *bus, uint8_t addr, uint8_t reg)
  86{
  87    MDIOSlave *slave = NULL;
  88    MDIOSlaveClass *sc;
  89
  90    if ((bus->cur_addr != addr) || !bus->cur_slave) {
  91        slave = mdio_find_slave(bus, addr);
  92        if (slave) {
  93            bus->cur_slave = slave;
  94            bus->cur_addr = addr;
  95        } else {
  96            return -1;
  97        }
  98    } else {
  99        slave = bus->cur_slave;
 100    }
 101
 102    sc = MDIO_SLAVE_GET_CLASS(slave);
 103    if (sc->recv) {
 104        return sc->recv(slave, reg);
 105    }
 106    return -1;
 107}
 108
 109static Property mdio_props[] = {
 110    DEFINE_PROP_UINT8("reg", MDIOSlave, addr, 0),
 111    DEFINE_PROP_END_OF_LIST(),
 112};
 113
 114static bool mdio_slave_parse_reg(FDTGenericMMap *obj, FDTGenericRegPropInfo reg,
 115                                Error **errp)
 116{
 117    DeviceState *parent;
 118
 119    parent = (DeviceState *)object_dynamic_cast(reg.parents[0], TYPE_DEVICE);
 120
 121    if (!parent) {
 122        return false;
 123    }
 124
 125    if (!parent->realized) {
 126        return true;
 127    }
 128
 129    qdev_set_parent_bus(DEVICE(obj), qdev_get_child_bus(parent, "mdio-bus"));
 130
 131    return false;
 132}
 133
 134static void mdio_slave_class_init(ObjectClass *klass, void *data)
 135{
 136    DeviceClass *k = DEVICE_CLASS(klass);
 137    FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_CLASS(klass);
 138
 139    set_bit(DEVICE_CATEGORY_MISC, k->categories);
 140    k->bus_type = TYPE_MDIO_BUS;
 141    k->props = mdio_props;
 142    fmc->parse_reg = mdio_slave_parse_reg;
 143}
 144
 145static const TypeInfo mdio_slave_info = {
 146    .name = TYPE_MDIO_SLAVE,
 147    .parent = TYPE_DEVICE,
 148    .instance_size = sizeof(MDIOSlave),
 149    .class_size = sizeof(MDIOSlaveClass),
 150    .class_init = mdio_slave_class_init,
 151    .interfaces = (InterfaceInfo []) {
 152        {TYPE_FDT_GENERIC_MMAP},
 153    },
 154};
 155
 156static const TypeInfo mdio_bus_info = {
 157    .name = TYPE_MDIO_BUS,
 158    .parent = TYPE_BUS,
 159    .instance_size = sizeof(struct MDIOBus),
 160};
 161
 162static void mdio_slave_register_type(void)
 163{
 164    type_register_static(&mdio_bus_info);
 165    type_register_static(&mdio_slave_info);
 166}
 167
 168type_init(mdio_slave_register_type)
 169