qemu/hw/mdio/eth_phy.c
<<
>>
Prefs
   1/*
   2 * QEMU Ethernet MDIO bus & PHY models
   3 *
   4 * Copyright (c) 2008 Edgar E. Iglesias (edgari@xilinx.com),
   5 * Copyright (c) 2008 Grant Likely (grant.likely@secretlab.ca),
   6 * Copyright (c) 2016 Xilinx Inc.
   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/mdio/eth_phy.h"
  31#include "qemu/log.h"
  32
  33#ifndef ETH_PHY_DEBUG
  34#define ETH_PHY_DEBUG 0
  35#endif
  36
  37#define DPRINT(fmt, args...) \
  38    do { \
  39        if (ETH_PHY_DEBUG) { \
  40            qemu_log("%s: " fmt, __func__, ## args); \
  41        } \
  42    } while (0)
  43
  44static void eth_phy_reset(DeviceState *dev)
  45{
  46    EthPhy *s = ETHPHY(dev);
  47
  48    /* If AutoNegotiation is supported */
  49    if (s->part->autoneg) {
  50        /* Show as AutoNeg capable & show as its completed autoneg */
  51        s->regs[PHY_STATUS] |= M(PHY_STAT_AUTONEG_CAP) |
  52                               M(PHY_STAT_AUTONEG_COMP) |
  53                               M(PHY_STAT_EXT_CAP);
  54
  55        s->regs[PHY_CTRL] |= M(PHY_CTRLREG_AUTONEG_EN);
  56        /* Supports IEEE 802.3 std and 10BaseT and 10BaseTX Full and Half
  57         *  duplex
  58         */
  59        s->regs[PHY_AUTONEG_ADV] |= 0x01E1;
  60        s->regs[PHY_LP_ABILITY]  |= 0xCDE1;
  61
  62        s->regs[PHY_1000T_CTRL] |= 0x0300;
  63        s->regs[PHY_1000T_STATUS] |= 0x7C00;
  64
  65        /* Support all modes in gmii mode*/
  66        if (s->part->gmii) {
  67            s->regs[PHY_EXT_STATUS] |=  M(PHY_EXT_STAT_1000BT_HD) |
  68                                        M(PHY_EXT_STAT_1000BT_FD) |
  69                                        M(PHY_EXT_STAT_1000BX_HD) |
  70                                        M(PHY_EXT_STAT_1000BX_FD);
  71            s->regs[PHY_STATUS] |= M(PHY_STAT_100BX_FD) |
  72                                   M(PHY_STAT_100BX_HD) |
  73                                   M(PHY_STAT_100B_T2_FD) |
  74                                   M(PHY_STAT_100B_T2_HD) |
  75                                   M(PHY_STAT_10MBPS_HD) |
  76                                   M(PHY_STAT_10MBPS_FD);
  77            /* Show 1000Mb/s as default */
  78            s->regs[PHY_CTRL] |= M(PHY_CTRLREG_SPEED_SEL_MSB);
  79
  80            /* Supports Extended status */
  81            s->regs[PHY_STATUS] |= M(PHY_STAT_EXT_STAT_CAP);
  82            s->regs[PHY_SPEC_STATUS] |= 0xBC00;
  83        } else {
  84            s->regs[PHY_STATUS] |= M(PHY_STAT_100BX_FD) |
  85                                   M(PHY_STAT_100BX_HD) |
  86                                   M(PHY_STAT_100B_T2_FD) |
  87                                   M(PHY_STAT_100B_T2_HD) |
  88                                   M(PHY_STAT_10MBPS_HD) |
  89                                   M(PHY_STAT_10MBPS_FD);
  90            /* Show 100Mb/s as default */
  91            s->regs[PHY_CTRL] |= M(PHY_CTRLREG_SPEED_SEL_LSB);
  92            s->regs[PHY_SPEC_STATUS] |= 0x7C00;
  93        }
  94
  95    }
  96    s->link = true;
  97    s->regs[PHY_STATUS] |= M(PHY_STAT_LINK_STAT);
  98}
  99
 100static int eth_phy_read(MDIOSlave *slave, uint8_t req)
 101{
 102    EthPhy *phy = ETHPHY(slave);
 103    int regnum;
 104    unsigned r = 0;
 105
 106    regnum = req & 0x1f;
 107
 108    switch (regnum) {
 109    case PHY_STATUS:
 110        if (!phy->link) {
 111            break;
 112        }
 113        r = phy->regs[PHY_STATUS];
 114        break;
 115    default:
 116        r = phy->regs[regnum];
 117        break;
 118    }
 119    DPRINT("%s %x = reg[%d]\r\n", __func__, r, regnum);
 120    return r;
 121}
 122
 123static int eth_phy_write(MDIOSlave *slave, uint8_t req, uint8_t data)
 124{
 125    EthPhy *phy = ETHPHY(slave);
 126    int regnum = req & 0x1f;
 127    uint16_t mask = phy->regs_readonly_mask[regnum];
 128
 129    DPRINT("%s reg[%d] = %x; mask=%x\n", __func__, regnum, data, mask);
 130    switch (regnum) {
 131    case PHY_CTRL:
 132        /* Update Registers on Fall through */
 133        if (data & PHY_CTRL_RST) {
 134            eth_phy_reset(DEVICE(phy));
 135        }
 136    default:
 137        phy->regs[regnum] = (phy->regs[regnum] & mask) | (data & ~mask);
 138        break;
 139    }
 140    return 0;
 141}
 142
 143static void eth_phy_init(Object *Obj)
 144{
 145    EthPhy *s = ETHPHY(Obj);
 146    EthPhyClass *k = ETHPHY_GET_CLASS(Obj);
 147
 148    s->part = k->part;
 149    /* PHY Id. */
 150    s->regs[PHY_ID1] = s->part->phy_id1;
 151    s->regs[PHY_ID2] = s->part->phy_id2;
 152
 153    s->regs_readonly_mask = default_readonly_mask;
 154}
 155
 156static void eth_phy_class_init(ObjectClass *klass, void *data)
 157{
 158    MDIOSlaveClass *sc = MDIO_SLAVE_CLASS(klass);
 159
 160    sc->send = eth_phy_write;
 161    sc->recv = eth_phy_read;
 162}
 163
 164static void phy_class_init(ObjectClass *klass, void *data)
 165{
 166    DeviceClass *dc = DEVICE_CLASS(klass);
 167    EthPhyClass *k = ETHPHY_CLASS(klass);
 168
 169    k->part = data;
 170    dc->reset = eth_phy_reset;
 171}
 172
 173static const TypeInfo eth_phy_info = {
 174    .name = TYPE_ETH_PHY,
 175    .parent = TYPE_MDIO_SLAVE,
 176    .instance_size = sizeof(EthPhy),
 177    .class_size = sizeof(EthPhyClass),
 178    .instance_init = eth_phy_init,
 179    .class_init = eth_phy_class_init,
 180};
 181
 182static void eth_phy_register_types(void)
 183{
 184    int i;
 185
 186    type_register_static(&eth_phy_info);
 187
 188    for (i = 0; i < ARRAY_SIZE(devices); i++) {
 189        TypeInfo ti = {
 190            .name       = devices[i].partname,
 191            .parent     = TYPE_ETH_PHY,
 192            .class_init = phy_class_init,
 193            .class_data = (void *)&devices[i],
 194        };
 195        type_register(&ti);
 196    }
 197}
 198
 199type_init(eth_phy_register_types)
 200