1*c0cf6b41SBernhard Beschow /* 2*c0cf6b41SBernhard Beschow * SMSC LAN9118 PHY emulation 3*c0cf6b41SBernhard Beschow * 4*c0cf6b41SBernhard Beschow * Copyright (c) 2009 CodeSourcery, LLC. 5*c0cf6b41SBernhard Beschow * Written by Paul Brook 6*c0cf6b41SBernhard Beschow * 7*c0cf6b41SBernhard Beschow * This code is licensed under the GNU GPL v2 8*c0cf6b41SBernhard Beschow * 9*c0cf6b41SBernhard Beschow * Contributions after 2012-01-13 are licensed under the terms of the 10*c0cf6b41SBernhard Beschow * GNU GPL, version 2 or (at your option) any later version. 11*c0cf6b41SBernhard Beschow */ 12*c0cf6b41SBernhard Beschow 13*c0cf6b41SBernhard Beschow #include "qemu/osdep.h" 14*c0cf6b41SBernhard Beschow #include "hw/net/lan9118_phy.h" 15*c0cf6b41SBernhard Beschow #include "hw/irq.h" 16*c0cf6b41SBernhard Beschow #include "hw/resettable.h" 17*c0cf6b41SBernhard Beschow #include "migration/vmstate.h" 18*c0cf6b41SBernhard Beschow #include "qemu/log.h" 19*c0cf6b41SBernhard Beschow 20*c0cf6b41SBernhard Beschow #define PHY_INT_ENERGYON (1 << 7) 21*c0cf6b41SBernhard Beschow #define PHY_INT_AUTONEG_COMPLETE (1 << 6) 22*c0cf6b41SBernhard Beschow #define PHY_INT_FAULT (1 << 5) 23*c0cf6b41SBernhard Beschow #define PHY_INT_DOWN (1 << 4) 24*c0cf6b41SBernhard Beschow #define PHY_INT_AUTONEG_LP (1 << 3) 25*c0cf6b41SBernhard Beschow #define PHY_INT_PARFAULT (1 << 2) 26*c0cf6b41SBernhard Beschow #define PHY_INT_AUTONEG_PAGE (1 << 1) 27*c0cf6b41SBernhard Beschow 28*c0cf6b41SBernhard Beschow static void lan9118_phy_update_irq(Lan9118PhyState *s) 29*c0cf6b41SBernhard Beschow { 30*c0cf6b41SBernhard Beschow qemu_set_irq(s->irq, !!(s->ints & s->int_mask)); 31*c0cf6b41SBernhard Beschow } 32*c0cf6b41SBernhard Beschow 33*c0cf6b41SBernhard Beschow uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg) 34*c0cf6b41SBernhard Beschow { 35*c0cf6b41SBernhard Beschow uint16_t val; 36*c0cf6b41SBernhard Beschow 37*c0cf6b41SBernhard Beschow switch (reg) { 38*c0cf6b41SBernhard Beschow case 0: /* Basic Control */ 39*c0cf6b41SBernhard Beschow return s->control; 40*c0cf6b41SBernhard Beschow case 1: /* Basic Status */ 41*c0cf6b41SBernhard Beschow return s->status; 42*c0cf6b41SBernhard Beschow case 2: /* ID1 */ 43*c0cf6b41SBernhard Beschow return 0x0007; 44*c0cf6b41SBernhard Beschow case 3: /* ID2 */ 45*c0cf6b41SBernhard Beschow return 0xc0d1; 46*c0cf6b41SBernhard Beschow case 4: /* Auto-neg advertisement */ 47*c0cf6b41SBernhard Beschow return s->advertise; 48*c0cf6b41SBernhard Beschow case 5: /* Auto-neg Link Partner Ability */ 49*c0cf6b41SBernhard Beschow return 0x0f71; 50*c0cf6b41SBernhard Beschow case 6: /* Auto-neg Expansion */ 51*c0cf6b41SBernhard Beschow return 1; 52*c0cf6b41SBernhard Beschow /* TODO 17, 18, 27, 29, 30, 31 */ 53*c0cf6b41SBernhard Beschow case 29: /* Interrupt source. */ 54*c0cf6b41SBernhard Beschow val = s->ints; 55*c0cf6b41SBernhard Beschow s->ints = 0; 56*c0cf6b41SBernhard Beschow lan9118_phy_update_irq(s); 57*c0cf6b41SBernhard Beschow return val; 58*c0cf6b41SBernhard Beschow case 30: /* Interrupt mask */ 59*c0cf6b41SBernhard Beschow return s->int_mask; 60*c0cf6b41SBernhard Beschow default: 61*c0cf6b41SBernhard Beschow qemu_log_mask(LOG_GUEST_ERROR, 62*c0cf6b41SBernhard Beschow "lan9118_phy_read: PHY read reg %d\n", reg); 63*c0cf6b41SBernhard Beschow return 0; 64*c0cf6b41SBernhard Beschow } 65*c0cf6b41SBernhard Beschow } 66*c0cf6b41SBernhard Beschow 67*c0cf6b41SBernhard Beschow void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val) 68*c0cf6b41SBernhard Beschow { 69*c0cf6b41SBernhard Beschow switch (reg) { 70*c0cf6b41SBernhard Beschow case 0: /* Basic Control */ 71*c0cf6b41SBernhard Beschow if (val & 0x8000) { 72*c0cf6b41SBernhard Beschow lan9118_phy_reset(s); 73*c0cf6b41SBernhard Beschow break; 74*c0cf6b41SBernhard Beschow } 75*c0cf6b41SBernhard Beschow s->control = val & 0x7980; 76*c0cf6b41SBernhard Beschow /* Complete autonegotiation immediately. */ 77*c0cf6b41SBernhard Beschow if (val & 0x1000) { 78*c0cf6b41SBernhard Beschow s->status |= 0x0020; 79*c0cf6b41SBernhard Beschow } 80*c0cf6b41SBernhard Beschow break; 81*c0cf6b41SBernhard Beschow case 4: /* Auto-neg advertisement */ 82*c0cf6b41SBernhard Beschow s->advertise = (val & 0x2d7f) | 0x80; 83*c0cf6b41SBernhard Beschow break; 84*c0cf6b41SBernhard Beschow /* TODO 17, 18, 27, 31 */ 85*c0cf6b41SBernhard Beschow case 30: /* Interrupt mask */ 86*c0cf6b41SBernhard Beschow s->int_mask = val & 0xff; 87*c0cf6b41SBernhard Beschow lan9118_phy_update_irq(s); 88*c0cf6b41SBernhard Beschow break; 89*c0cf6b41SBernhard Beschow default: 90*c0cf6b41SBernhard Beschow qemu_log_mask(LOG_GUEST_ERROR, 91*c0cf6b41SBernhard Beschow "lan9118_phy_write: PHY write reg %d = 0x%04x\n", reg, val); 92*c0cf6b41SBernhard Beschow } 93*c0cf6b41SBernhard Beschow } 94*c0cf6b41SBernhard Beschow 95*c0cf6b41SBernhard Beschow void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down) 96*c0cf6b41SBernhard Beschow { 97*c0cf6b41SBernhard Beschow s->link_down = link_down; 98*c0cf6b41SBernhard Beschow 99*c0cf6b41SBernhard Beschow /* Autonegotiation status mirrors link status. */ 100*c0cf6b41SBernhard Beschow if (link_down) { 101*c0cf6b41SBernhard Beschow s->status &= ~0x0024; 102*c0cf6b41SBernhard Beschow s->ints |= PHY_INT_DOWN; 103*c0cf6b41SBernhard Beschow } else { 104*c0cf6b41SBernhard Beschow s->status |= 0x0024; 105*c0cf6b41SBernhard Beschow s->ints |= PHY_INT_ENERGYON; 106*c0cf6b41SBernhard Beschow s->ints |= PHY_INT_AUTONEG_COMPLETE; 107*c0cf6b41SBernhard Beschow } 108*c0cf6b41SBernhard Beschow lan9118_phy_update_irq(s); 109*c0cf6b41SBernhard Beschow } 110*c0cf6b41SBernhard Beschow 111*c0cf6b41SBernhard Beschow void lan9118_phy_reset(Lan9118PhyState *s) 112*c0cf6b41SBernhard Beschow { 113*c0cf6b41SBernhard Beschow s->control = 0x3000; 114*c0cf6b41SBernhard Beschow s->status = 0x7809; 115*c0cf6b41SBernhard Beschow s->advertise = 0x01e1; 116*c0cf6b41SBernhard Beschow s->int_mask = 0; 117*c0cf6b41SBernhard Beschow s->ints = 0; 118*c0cf6b41SBernhard Beschow lan9118_phy_update_link(s, s->link_down); 119*c0cf6b41SBernhard Beschow } 120*c0cf6b41SBernhard Beschow 121*c0cf6b41SBernhard Beschow static void lan9118_phy_reset_hold(Object *obj, ResetType type) 122*c0cf6b41SBernhard Beschow { 123*c0cf6b41SBernhard Beschow Lan9118PhyState *s = LAN9118_PHY(obj); 124*c0cf6b41SBernhard Beschow 125*c0cf6b41SBernhard Beschow lan9118_phy_reset(s); 126*c0cf6b41SBernhard Beschow } 127*c0cf6b41SBernhard Beschow 128*c0cf6b41SBernhard Beschow static void lan9118_phy_init(Object *obj) 129*c0cf6b41SBernhard Beschow { 130*c0cf6b41SBernhard Beschow Lan9118PhyState *s = LAN9118_PHY(obj); 131*c0cf6b41SBernhard Beschow 132*c0cf6b41SBernhard Beschow qdev_init_gpio_out(DEVICE(s), &s->irq, 1); 133*c0cf6b41SBernhard Beschow } 134*c0cf6b41SBernhard Beschow 135*c0cf6b41SBernhard Beschow static const VMStateDescription vmstate_lan9118_phy = { 136*c0cf6b41SBernhard Beschow .name = "lan9118-phy", 137*c0cf6b41SBernhard Beschow .version_id = 1, 138*c0cf6b41SBernhard Beschow .minimum_version_id = 1, 139*c0cf6b41SBernhard Beschow .fields = (const VMStateField[]) { 140*c0cf6b41SBernhard Beschow VMSTATE_UINT16(control, Lan9118PhyState), 141*c0cf6b41SBernhard Beschow VMSTATE_UINT16(status, Lan9118PhyState), 142*c0cf6b41SBernhard Beschow VMSTATE_UINT16(advertise, Lan9118PhyState), 143*c0cf6b41SBernhard Beschow VMSTATE_UINT16(ints, Lan9118PhyState), 144*c0cf6b41SBernhard Beschow VMSTATE_UINT16(int_mask, Lan9118PhyState), 145*c0cf6b41SBernhard Beschow VMSTATE_BOOL(link_down, Lan9118PhyState), 146*c0cf6b41SBernhard Beschow VMSTATE_END_OF_LIST() 147*c0cf6b41SBernhard Beschow } 148*c0cf6b41SBernhard Beschow }; 149*c0cf6b41SBernhard Beschow 150*c0cf6b41SBernhard Beschow static void lan9118_phy_class_init(ObjectClass *klass, void *data) 151*c0cf6b41SBernhard Beschow { 152*c0cf6b41SBernhard Beschow ResettableClass *rc = RESETTABLE_CLASS(klass); 153*c0cf6b41SBernhard Beschow DeviceClass *dc = DEVICE_CLASS(klass); 154*c0cf6b41SBernhard Beschow 155*c0cf6b41SBernhard Beschow rc->phases.hold = lan9118_phy_reset_hold; 156*c0cf6b41SBernhard Beschow dc->vmsd = &vmstate_lan9118_phy; 157*c0cf6b41SBernhard Beschow } 158*c0cf6b41SBernhard Beschow 159*c0cf6b41SBernhard Beschow static const TypeInfo types[] = { 160*c0cf6b41SBernhard Beschow { 161*c0cf6b41SBernhard Beschow .name = TYPE_LAN9118_PHY, 162*c0cf6b41SBernhard Beschow .parent = TYPE_SYS_BUS_DEVICE, 163*c0cf6b41SBernhard Beschow .instance_size = sizeof(Lan9118PhyState), 164*c0cf6b41SBernhard Beschow .instance_init = lan9118_phy_init, 165*c0cf6b41SBernhard Beschow .class_init = lan9118_phy_class_init, 166*c0cf6b41SBernhard Beschow } 167*c0cf6b41SBernhard Beschow }; 168*c0cf6b41SBernhard Beschow 169*c0cf6b41SBernhard Beschow DEFINE_TYPES(types) 170