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 "qapi/error.h"
  30#include "migration/vmstate.h"
  31#include "hw/qdev-properties.h"
  32#include "hw/mdio/mdio_slave.h"
  33#include "hw/fdt_generic_util.h"
  34
  35struct MDIOBus *mdio_init_bus(DeviceState *parent, const char *name)
  36{
  37    struct MDIOBus *bus;
  38
  39    bus = MDIO_BUS(qbus_new(TYPE_MDIO_BUS, parent, name));
  40    return bus;
  41}
  42
  43void mdio_set_slave_addr(MDIOSlave *s, uint8_t addr)
  44{
  45    s->addr = addr;
  46}
  47
  48static MDIOSlave *mdio_find_slave(struct MDIOBus *bus, uint8_t addr)
  49{
  50    MDIOSlave *slave = NULL;
  51    BusChild *kid;
  52
  53    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
  54        DeviceState *qdev = kid->child;
  55        MDIOSlave *candidate = MDIO_SLAVE(qdev);
  56        /* For slave having no address, assign the requested addr */
  57        if (candidate->addr == 0) {
  58            candidate->addr = addr;
  59        }
  60        if (addr == candidate->addr) {
  61            slave = candidate;
  62            break;
  63        }
  64    }
  65    return slave;
  66}
  67
  68int mdio_send(struct MDIOBus *bus, uint8_t addr, uint8_t reg, uint8_t data)
  69{
  70    MDIOSlave *slave = NULL;
  71    MDIOSlaveClass *sc;
  72
  73    if ((bus->cur_addr != addr) || !bus->cur_slave) {
  74        slave = mdio_find_slave(bus, addr);
  75        if (slave) {
  76            bus->cur_slave = slave;
  77            bus->cur_addr = addr;
  78        } else {
  79            return -1;
  80        }
  81    } else {
  82        slave = bus->cur_slave;
  83    }
  84
  85    sc = MDIO_SLAVE_GET_CLASS(slave);
  86    if (sc->send) {
  87        return sc->send(slave, reg, data);
  88    }
  89    return -1;
  90}
  91
  92int mdio_recv(struct MDIOBus *bus, uint8_t addr, uint8_t reg)
  93{
  94    MDIOSlave *slave = NULL;
  95    MDIOSlaveClass *sc;
  96
  97    if ((bus->cur_addr != addr) || !bus->cur_slave) {
  98        slave = mdio_find_slave(bus, addr);
  99        if (slave) {
 100            bus->cur_slave = slave;
 101            bus->cur_addr = addr;
 102        } else {
 103            return -1;
 104        }
 105    } else {
 106        slave = bus->cur_slave;
 107    }
 108
 109    sc = MDIO_SLAVE_GET_CLASS(slave);
 110    if (sc->recv) {
 111        return sc->recv(slave, reg);
 112    }
 113    return -1;
 114}
 115
 116static Property mdio_props[] = {
 117    DEFINE_PROP_UINT8("reg", MDIOSlave, addr, 0),
 118    DEFINE_PROP_END_OF_LIST(),
 119};
 120
 121static bool mdio_slave_parse_reg(FDTGenericMMap *obj, FDTGenericRegPropInfo reg,
 122                                Error **errp)
 123{
 124    DeviceState *parent;
 125
 126    parent = (DeviceState *)object_dynamic_cast(reg.parents[0], TYPE_DEVICE);
 127
 128    if (!parent) {
 129        return false;
 130    }
 131
 132    if (!parent->realized) {
 133        return true;
 134    }
 135
 136    qdev_set_parent_bus(DEVICE(obj), qdev_get_child_bus(parent, "mdio-bus"),
 137                        &error_abort);
 138
 139    return false;
 140}
 141
 142static void mdio_slave_class_init(ObjectClass *klass, void *data)
 143{
 144    DeviceClass *k = DEVICE_CLASS(klass);
 145    FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_CLASS(klass);
 146
 147    set_bit(DEVICE_CATEGORY_MISC, k->categories);
 148    k->bus_type = TYPE_MDIO_BUS;
 149    device_class_set_props(k, mdio_props);
 150    fmc->parse_reg = mdio_slave_parse_reg;
 151}
 152
 153static const TypeInfo mdio_slave_info = {
 154    .name = TYPE_MDIO_SLAVE,
 155    .parent = TYPE_DEVICE,
 156    .instance_size = sizeof(MDIOSlave),
 157    .class_size = sizeof(MDIOSlaveClass),
 158    .class_init = mdio_slave_class_init,
 159    .interfaces = (InterfaceInfo []) {
 160        {TYPE_FDT_GENERIC_MMAP},
 161        { },
 162    },
 163};
 164
 165static const TypeInfo mdio_bus_info = {
 166    .name = TYPE_MDIO_BUS,
 167    .parent = TYPE_BUS,
 168    .instance_size = sizeof(struct MDIOBus),
 169};
 170
 171static void mdio_slave_register_type(void)
 172{
 173    type_register_static(&mdio_bus_info);
 174    type_register_static(&mdio_slave_info);
 175}
 176
 177type_init(mdio_slave_register_type)
 178