1 /* 2 * QEMU Freescale eTSEC Emulator 3 * 4 * Copyright (c) 2011-2013 AdaCore 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "hw/net/mii.h" 27 #include "etsec.h" 28 #include "registers.h" 29 30 /* #define DEBUG_MIIM */ 31 32 static void miim_read_cycle(eTSEC *etsec) 33 { 34 uint8_t phy; 35 uint8_t addr; 36 uint16_t value; 37 38 phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F; 39 (void)phy; /* Unreferenced */ 40 addr = etsec->regs[MIIMADD].value & 0x1F; 41 42 switch (addr) { 43 case MII_BMCR: 44 value = etsec->phy_control; 45 break; 46 case MII_BMSR: 47 value = etsec->phy_status; 48 break; 49 case MII_STAT1000: 50 value = MII_STAT1000_LOK | MII_STAT1000_ROK; 51 break; 52 default: 53 value = 0x0; 54 break; 55 }; 56 57 #ifdef DEBUG_MIIM 58 qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value); 59 #endif 60 61 etsec->regs[MIIMSTAT].value = value; 62 } 63 64 static void miim_write_cycle(eTSEC *etsec) 65 { 66 uint8_t phy; 67 uint8_t addr; 68 uint16_t value; 69 70 phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F; 71 (void)phy; /* Unreferenced */ 72 addr = etsec->regs[MIIMADD].value & 0x1F; 73 value = etsec->regs[MIIMCON].value & 0xffff; 74 75 #ifdef DEBUG_MIIM 76 qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value); 77 #endif 78 79 switch (addr) { 80 case MII_BMCR: 81 etsec->phy_control = value & ~(MII_BMCR_RESET | MII_BMCR_FD); 82 break; 83 default: 84 break; 85 }; 86 } 87 88 void etsec_write_miim(eTSEC *etsec, 89 eTSEC_Register *reg, 90 uint32_t reg_index, 91 uint32_t value) 92 { 93 94 switch (reg_index) { 95 96 case MIIMCOM: 97 /* Read and scan cycle */ 98 99 if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) { 100 /* Read */ 101 miim_read_cycle(etsec); 102 } 103 reg->value = value; 104 break; 105 106 case MIIMCON: 107 reg->value = value & 0xffff; 108 miim_write_cycle(etsec); 109 break; 110 111 default: 112 /* Default handling */ 113 switch (reg->access) { 114 115 case ACC_RW: 116 case ACC_WO: 117 reg->value = value; 118 break; 119 120 case ACC_W1C: 121 reg->value &= ~value; 122 break; 123 124 case ACC_RO: 125 default: 126 /* Read Only or Unknown register */ 127 break; 128 } 129 } 130 131 } 132 133 void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc) 134 { 135 /* Set link status */ 136 if (nc->link_down) { 137 etsec->phy_status &= ~MII_BMSR_LINK_ST; 138 } else { 139 etsec->phy_status |= MII_BMSR_LINK_ST; 140 } 141 } 142