11c664378SSubbaraya Sundeep /* 21c664378SSubbaraya Sundeep * QEMU model of the Smartfusion2 Ethernet MAC. 31c664378SSubbaraya Sundeep * 41c664378SSubbaraya Sundeep * Copyright (c) 2020 Subbaraya Sundeep <sundeep.lkml@gmail.com>. 51c664378SSubbaraya Sundeep * 61c664378SSubbaraya Sundeep * Permission is hereby granted, free of charge, to any person obtaining a copy 71c664378SSubbaraya Sundeep * of this software and associated documentation files (the "Software"), to deal 81c664378SSubbaraya Sundeep * in the Software without restriction, including without limitation the rights 91c664378SSubbaraya Sundeep * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 101c664378SSubbaraya Sundeep * copies of the Software, and to permit persons to whom the Software is 111c664378SSubbaraya Sundeep * furnished to do so, subject to the following conditions: 121c664378SSubbaraya Sundeep * 131c664378SSubbaraya Sundeep * The above copyright notice and this permission notice shall be included in 141c664378SSubbaraya Sundeep * all copies or substantial portions of the Software. 151c664378SSubbaraya Sundeep * 161c664378SSubbaraya Sundeep * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171c664378SSubbaraya Sundeep * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181c664378SSubbaraya Sundeep * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 191c664378SSubbaraya Sundeep * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201c664378SSubbaraya Sundeep * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 211c664378SSubbaraya Sundeep * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 221c664378SSubbaraya Sundeep * THE SOFTWARE. 231c664378SSubbaraya Sundeep * 241c664378SSubbaraya Sundeep * Refer to section Ethernet MAC in the document: 251c664378SSubbaraya Sundeep * UG0331: SmartFusion2 Microcontroller Subsystem User Guide 261c664378SSubbaraya Sundeep * Datasheet URL: 271c664378SSubbaraya Sundeep * https://www.microsemi.com/document-portal/cat_view/56661-internal-documents/ 281c664378SSubbaraya Sundeep * 56758-soc?lang=en&limit=20&limitstart=220 291c664378SSubbaraya Sundeep */ 301c664378SSubbaraya Sundeep 311c664378SSubbaraya Sundeep #include "qemu/osdep.h" 321c664378SSubbaraya Sundeep #include "qemu/log.h" 331c664378SSubbaraya Sundeep #include "qapi/error.h" 341c664378SSubbaraya Sundeep #include "hw/registerfields.h" 351c664378SSubbaraya Sundeep #include "hw/net/msf2-emac.h" 361c664378SSubbaraya Sundeep #include "hw/net/mii.h" 371c664378SSubbaraya Sundeep #include "hw/irq.h" 381c664378SSubbaraya Sundeep #include "hw/qdev-properties.h" 391c664378SSubbaraya Sundeep #include "migration/vmstate.h" 401c664378SSubbaraya Sundeep 411c664378SSubbaraya Sundeep REG32(CFG1, 0x0) 421c664378SSubbaraya Sundeep FIELD(CFG1, RESET, 31, 1) 431c664378SSubbaraya Sundeep FIELD(CFG1, RX_EN, 2, 1) 441c664378SSubbaraya Sundeep FIELD(CFG1, TX_EN, 0, 1) 451c664378SSubbaraya Sundeep FIELD(CFG1, LB_EN, 8, 1) 461c664378SSubbaraya Sundeep REG32(CFG2, 0x4) 471c664378SSubbaraya Sundeep REG32(IFG, 0x8) 481c664378SSubbaraya Sundeep REG32(HALF_DUPLEX, 0xc) 491c664378SSubbaraya Sundeep REG32(MAX_FRAME_LENGTH, 0x10) 501c664378SSubbaraya Sundeep REG32(MII_CMD, 0x24) 511c664378SSubbaraya Sundeep FIELD(MII_CMD, READ, 0, 1) 521c664378SSubbaraya Sundeep REG32(MII_ADDR, 0x28) 531c664378SSubbaraya Sundeep FIELD(MII_ADDR, REGADDR, 0, 5) 541c664378SSubbaraya Sundeep FIELD(MII_ADDR, PHYADDR, 8, 5) 551c664378SSubbaraya Sundeep REG32(MII_CTL, 0x2c) 561c664378SSubbaraya Sundeep REG32(MII_STS, 0x30) 571c664378SSubbaraya Sundeep REG32(STA1, 0x40) 581c664378SSubbaraya Sundeep REG32(STA2, 0x44) 591c664378SSubbaraya Sundeep REG32(FIFO_CFG0, 0x48) 601c664378SSubbaraya Sundeep REG32(FIFO_CFG4, 0x58) 611c664378SSubbaraya Sundeep FIELD(FIFO_CFG4, BCAST, 9, 1) 621c664378SSubbaraya Sundeep FIELD(FIFO_CFG4, MCAST, 8, 1) 631c664378SSubbaraya Sundeep REG32(FIFO_CFG5, 0x5C) 641c664378SSubbaraya Sundeep FIELD(FIFO_CFG5, BCAST, 9, 1) 651c664378SSubbaraya Sundeep FIELD(FIFO_CFG5, MCAST, 8, 1) 661c664378SSubbaraya Sundeep REG32(DMA_TX_CTL, 0x180) 671c664378SSubbaraya Sundeep FIELD(DMA_TX_CTL, EN, 0, 1) 681c664378SSubbaraya Sundeep REG32(DMA_TX_DESC, 0x184) 691c664378SSubbaraya Sundeep REG32(DMA_TX_STATUS, 0x188) 701c664378SSubbaraya Sundeep FIELD(DMA_TX_STATUS, PKTCNT, 16, 8) 711c664378SSubbaraya Sundeep FIELD(DMA_TX_STATUS, UNDERRUN, 1, 1) 721c664378SSubbaraya Sundeep FIELD(DMA_TX_STATUS, PKT_SENT, 0, 1) 731c664378SSubbaraya Sundeep REG32(DMA_RX_CTL, 0x18c) 741c664378SSubbaraya Sundeep FIELD(DMA_RX_CTL, EN, 0, 1) 751c664378SSubbaraya Sundeep REG32(DMA_RX_DESC, 0x190) 761c664378SSubbaraya Sundeep REG32(DMA_RX_STATUS, 0x194) 771c664378SSubbaraya Sundeep FIELD(DMA_RX_STATUS, PKTCNT, 16, 8) 781c664378SSubbaraya Sundeep FIELD(DMA_RX_STATUS, OVERFLOW, 2, 1) 791c664378SSubbaraya Sundeep FIELD(DMA_RX_STATUS, PKT_RCVD, 0, 1) 801c664378SSubbaraya Sundeep REG32(DMA_IRQ_MASK, 0x198) 811c664378SSubbaraya Sundeep REG32(DMA_IRQ, 0x19c) 821c664378SSubbaraya Sundeep 831c664378SSubbaraya Sundeep #define EMPTY_MASK (1 << 31) 841c664378SSubbaraya Sundeep #define PKT_SIZE 0x7FF 851c664378SSubbaraya Sundeep #define PHYADDR 0x1 861c664378SSubbaraya Sundeep #define MAX_PKT_SIZE 2048 871c664378SSubbaraya Sundeep 881c664378SSubbaraya Sundeep typedef struct { 891c664378SSubbaraya Sundeep uint32_t pktaddr; 901c664378SSubbaraya Sundeep uint32_t pktsize; 911c664378SSubbaraya Sundeep uint32_t next; 921c664378SSubbaraya Sundeep } EmacDesc; 931c664378SSubbaraya Sundeep 941c664378SSubbaraya Sundeep static uint32_t emac_get_isr(MSF2EmacState *s) 951c664378SSubbaraya Sundeep { 961c664378SSubbaraya Sundeep uint32_t ier = s->regs[R_DMA_IRQ_MASK]; 971c664378SSubbaraya Sundeep uint32_t tx = s->regs[R_DMA_TX_STATUS] & 0xF; 981c664378SSubbaraya Sundeep uint32_t rx = s->regs[R_DMA_RX_STATUS] & 0xF; 991c664378SSubbaraya Sundeep uint32_t isr = (rx << 4) | tx; 1001c664378SSubbaraya Sundeep 1011c664378SSubbaraya Sundeep s->regs[R_DMA_IRQ] = ier & isr; 1021c664378SSubbaraya Sundeep return s->regs[R_DMA_IRQ]; 1031c664378SSubbaraya Sundeep } 1041c664378SSubbaraya Sundeep 1051c664378SSubbaraya Sundeep static void emac_update_irq(MSF2EmacState *s) 1061c664378SSubbaraya Sundeep { 1071c664378SSubbaraya Sundeep bool intr = emac_get_isr(s); 1081c664378SSubbaraya Sundeep 1091c664378SSubbaraya Sundeep qemu_set_irq(s->irq, intr); 1101c664378SSubbaraya Sundeep } 1111c664378SSubbaraya Sundeep 1121c664378SSubbaraya Sundeep static void emac_load_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc) 1131c664378SSubbaraya Sundeep { 1141c664378SSubbaraya Sundeep address_space_read(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, d, sizeof *d); 1151c664378SSubbaraya Sundeep /* Convert from LE into host endianness. */ 1161c664378SSubbaraya Sundeep d->pktaddr = le32_to_cpu(d->pktaddr); 1171c664378SSubbaraya Sundeep d->pktsize = le32_to_cpu(d->pktsize); 1181c664378SSubbaraya Sundeep d->next = le32_to_cpu(d->next); 1191c664378SSubbaraya Sundeep } 1201c664378SSubbaraya Sundeep 121d565f58bSPeter Maydell static void emac_store_desc(MSF2EmacState *s, const EmacDesc *d, hwaddr desc) 1221c664378SSubbaraya Sundeep { 123d565f58bSPeter Maydell EmacDesc outd; 124d565f58bSPeter Maydell /* 125d565f58bSPeter Maydell * Convert from host endianness into LE. We use a local struct because 126d565f58bSPeter Maydell * calling code may still want to look at the fields afterwards. 127d565f58bSPeter Maydell */ 128d565f58bSPeter Maydell outd.pktaddr = cpu_to_le32(d->pktaddr); 129d565f58bSPeter Maydell outd.pktsize = cpu_to_le32(d->pktsize); 130d565f58bSPeter Maydell outd.next = cpu_to_le32(d->next); 1311c664378SSubbaraya Sundeep 132d565f58bSPeter Maydell address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, &outd, sizeof outd); 1331c664378SSubbaraya Sundeep } 1341c664378SSubbaraya Sundeep 1351c664378SSubbaraya Sundeep static void msf2_dma_tx(MSF2EmacState *s) 1361c664378SSubbaraya Sundeep { 1371c664378SSubbaraya Sundeep NetClientState *nc = qemu_get_queue(s->nic); 1381c664378SSubbaraya Sundeep hwaddr desc = s->regs[R_DMA_TX_DESC]; 1391c664378SSubbaraya Sundeep uint8_t buf[MAX_PKT_SIZE]; 1401c664378SSubbaraya Sundeep EmacDesc d; 1411c664378SSubbaraya Sundeep int size; 1421c664378SSubbaraya Sundeep uint8_t pktcnt; 1431c664378SSubbaraya Sundeep uint32_t status; 1441c664378SSubbaraya Sundeep 1451c664378SSubbaraya Sundeep if (!(s->regs[R_CFG1] & R_CFG1_TX_EN_MASK)) { 1461c664378SSubbaraya Sundeep return; 1471c664378SSubbaraya Sundeep } 1481c664378SSubbaraya Sundeep 1491c664378SSubbaraya Sundeep while (1) { 1501c664378SSubbaraya Sundeep emac_load_desc(s, &d, desc); 1511c664378SSubbaraya Sundeep if (d.pktsize & EMPTY_MASK) { 1521c664378SSubbaraya Sundeep break; 1531c664378SSubbaraya Sundeep } 1541c664378SSubbaraya Sundeep size = d.pktsize & PKT_SIZE; 1551c664378SSubbaraya Sundeep address_space_read(&s->dma_as, d.pktaddr, MEMTXATTRS_UNSPECIFIED, 1561c664378SSubbaraya Sundeep buf, size); 1571c664378SSubbaraya Sundeep /* 1581c664378SSubbaraya Sundeep * This is very basic way to send packets. Ideally there should be 1591c664378SSubbaraya Sundeep * a FIFO and packets should be sent out from FIFO only when 1601c664378SSubbaraya Sundeep * R_CFG1 bit 0 is set. 1611c664378SSubbaraya Sundeep */ 1621c664378SSubbaraya Sundeep if (s->regs[R_CFG1] & R_CFG1_LB_EN_MASK) { 16326194a58SJason Wang qemu_receive_packet(nc, buf, size); 1641c664378SSubbaraya Sundeep } else { 1651c664378SSubbaraya Sundeep qemu_send_packet(nc, buf, size); 1661c664378SSubbaraya Sundeep } 1671c664378SSubbaraya Sundeep d.pktsize |= EMPTY_MASK; 1681c664378SSubbaraya Sundeep emac_store_desc(s, &d, desc); 1691c664378SSubbaraya Sundeep /* update sent packets count */ 1701c664378SSubbaraya Sundeep status = s->regs[R_DMA_TX_STATUS]; 1711c664378SSubbaraya Sundeep pktcnt = FIELD_EX32(status, DMA_TX_STATUS, PKTCNT); 1721c664378SSubbaraya Sundeep pktcnt++; 1731c664378SSubbaraya Sundeep s->regs[R_DMA_TX_STATUS] = FIELD_DP32(status, DMA_TX_STATUS, 1741c664378SSubbaraya Sundeep PKTCNT, pktcnt); 1751c664378SSubbaraya Sundeep s->regs[R_DMA_TX_STATUS] |= R_DMA_TX_STATUS_PKT_SENT_MASK; 1761c664378SSubbaraya Sundeep desc = d.next; 1771c664378SSubbaraya Sundeep } 1781c664378SSubbaraya Sundeep s->regs[R_DMA_TX_STATUS] |= R_DMA_TX_STATUS_UNDERRUN_MASK; 1791c664378SSubbaraya Sundeep s->regs[R_DMA_TX_CTL] &= ~R_DMA_TX_CTL_EN_MASK; 1801c664378SSubbaraya Sundeep } 1811c664378SSubbaraya Sundeep 1821c664378SSubbaraya Sundeep static void msf2_phy_update_link(MSF2EmacState *s) 1831c664378SSubbaraya Sundeep { 1841c664378SSubbaraya Sundeep /* Autonegotiation status mirrors link status. */ 1851c664378SSubbaraya Sundeep if (qemu_get_queue(s->nic)->link_down) { 1861c664378SSubbaraya Sundeep s->phy_regs[MII_BMSR] &= ~(MII_BMSR_AN_COMP | 1871c664378SSubbaraya Sundeep MII_BMSR_LINK_ST); 1881c664378SSubbaraya Sundeep } else { 1891c664378SSubbaraya Sundeep s->phy_regs[MII_BMSR] |= (MII_BMSR_AN_COMP | 1901c664378SSubbaraya Sundeep MII_BMSR_LINK_ST); 1911c664378SSubbaraya Sundeep } 1921c664378SSubbaraya Sundeep } 1931c664378SSubbaraya Sundeep 1941c664378SSubbaraya Sundeep static void msf2_phy_reset(MSF2EmacState *s) 1951c664378SSubbaraya Sundeep { 1961c664378SSubbaraya Sundeep memset(&s->phy_regs[0], 0, sizeof(s->phy_regs)); 1971c664378SSubbaraya Sundeep s->phy_regs[MII_BMCR] = 0x1140; 1981c664378SSubbaraya Sundeep s->phy_regs[MII_BMSR] = 0x7968; 1991c664378SSubbaraya Sundeep s->phy_regs[MII_PHYID1] = 0x0022; 2001c664378SSubbaraya Sundeep s->phy_regs[MII_PHYID2] = 0x1550; 2011c664378SSubbaraya Sundeep s->phy_regs[MII_ANAR] = 0x01E1; 2021c664378SSubbaraya Sundeep s->phy_regs[MII_ANLPAR] = 0xCDE1; 2031c664378SSubbaraya Sundeep 2041c664378SSubbaraya Sundeep msf2_phy_update_link(s); 2051c664378SSubbaraya Sundeep } 2061c664378SSubbaraya Sundeep 2071c664378SSubbaraya Sundeep static void write_to_phy(MSF2EmacState *s) 2081c664378SSubbaraya Sundeep { 2091c664378SSubbaraya Sundeep uint8_t reg_addr = s->regs[R_MII_ADDR] & R_MII_ADDR_REGADDR_MASK; 2101c664378SSubbaraya Sundeep uint8_t phy_addr = (s->regs[R_MII_ADDR] >> R_MII_ADDR_PHYADDR_SHIFT) & 2111c664378SSubbaraya Sundeep R_MII_ADDR_REGADDR_MASK; 2121c664378SSubbaraya Sundeep uint16_t data = s->regs[R_MII_CTL] & 0xFFFF; 2131c664378SSubbaraya Sundeep 2141c664378SSubbaraya Sundeep if (phy_addr != PHYADDR) { 2151c664378SSubbaraya Sundeep return; 2161c664378SSubbaraya Sundeep } 2171c664378SSubbaraya Sundeep 2181c664378SSubbaraya Sundeep switch (reg_addr) { 2191c664378SSubbaraya Sundeep case MII_BMCR: 2201c664378SSubbaraya Sundeep if (data & MII_BMCR_RESET) { 2211c664378SSubbaraya Sundeep /* Phy reset */ 2221c664378SSubbaraya Sundeep msf2_phy_reset(s); 2231c664378SSubbaraya Sundeep data &= ~MII_BMCR_RESET; 2241c664378SSubbaraya Sundeep } 2251c664378SSubbaraya Sundeep if (data & MII_BMCR_AUTOEN) { 2261c664378SSubbaraya Sundeep /* Complete autonegotiation immediately */ 2271c664378SSubbaraya Sundeep data &= ~MII_BMCR_AUTOEN; 2281c664378SSubbaraya Sundeep s->phy_regs[MII_BMSR] |= MII_BMSR_AN_COMP; 2291c664378SSubbaraya Sundeep } 2301c664378SSubbaraya Sundeep break; 2311c664378SSubbaraya Sundeep } 2321c664378SSubbaraya Sundeep 2331c664378SSubbaraya Sundeep s->phy_regs[reg_addr] = data; 2341c664378SSubbaraya Sundeep } 2351c664378SSubbaraya Sundeep 2361c664378SSubbaraya Sundeep static uint16_t read_from_phy(MSF2EmacState *s) 2371c664378SSubbaraya Sundeep { 2381c664378SSubbaraya Sundeep uint8_t reg_addr = s->regs[R_MII_ADDR] & R_MII_ADDR_REGADDR_MASK; 2391c664378SSubbaraya Sundeep uint8_t phy_addr = (s->regs[R_MII_ADDR] >> R_MII_ADDR_PHYADDR_SHIFT) & 2401c664378SSubbaraya Sundeep R_MII_ADDR_REGADDR_MASK; 2411c664378SSubbaraya Sundeep 2421c664378SSubbaraya Sundeep if (phy_addr == PHYADDR) { 2431c664378SSubbaraya Sundeep return s->phy_regs[reg_addr]; 2441c664378SSubbaraya Sundeep } else { 2451c664378SSubbaraya Sundeep return 0xFFFF; 2461c664378SSubbaraya Sundeep } 2471c664378SSubbaraya Sundeep } 2481c664378SSubbaraya Sundeep 2491c664378SSubbaraya Sundeep static void msf2_emac_do_reset(MSF2EmacState *s) 2501c664378SSubbaraya Sundeep { 2511c664378SSubbaraya Sundeep memset(&s->regs[0], 0, sizeof(s->regs)); 2521c664378SSubbaraya Sundeep s->regs[R_CFG1] = 0x80000000; 2531c664378SSubbaraya Sundeep s->regs[R_CFG2] = 0x00007000; 2541c664378SSubbaraya Sundeep s->regs[R_IFG] = 0x40605060; 2551c664378SSubbaraya Sundeep s->regs[R_HALF_DUPLEX] = 0x00A1F037; 2561c664378SSubbaraya Sundeep s->regs[R_MAX_FRAME_LENGTH] = 0x00000600; 2571c664378SSubbaraya Sundeep s->regs[R_FIFO_CFG5] = 0X3FFFF; 2581c664378SSubbaraya Sundeep 2591c664378SSubbaraya Sundeep msf2_phy_reset(s); 2601c664378SSubbaraya Sundeep } 2611c664378SSubbaraya Sundeep 2621c664378SSubbaraya Sundeep static uint64_t emac_read(void *opaque, hwaddr addr, unsigned int size) 2631c664378SSubbaraya Sundeep { 2641c664378SSubbaraya Sundeep MSF2EmacState *s = opaque; 2651c664378SSubbaraya Sundeep uint32_t r = 0; 2661c664378SSubbaraya Sundeep 2671c664378SSubbaraya Sundeep addr >>= 2; 2681c664378SSubbaraya Sundeep 2691c664378SSubbaraya Sundeep switch (addr) { 2701c664378SSubbaraya Sundeep case R_DMA_IRQ: 2711c664378SSubbaraya Sundeep r = emac_get_isr(s); 2721c664378SSubbaraya Sundeep break; 2731c664378SSubbaraya Sundeep default: 2741c664378SSubbaraya Sundeep if (addr >= ARRAY_SIZE(s->regs)) { 2751c664378SSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, 2761c664378SSubbaraya Sundeep "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, 2771c664378SSubbaraya Sundeep addr * 4); 2781c664378SSubbaraya Sundeep return r; 2791c664378SSubbaraya Sundeep } 2801c664378SSubbaraya Sundeep r = s->regs[addr]; 2811c664378SSubbaraya Sundeep break; 2821c664378SSubbaraya Sundeep } 2831c664378SSubbaraya Sundeep return r; 2841c664378SSubbaraya Sundeep } 2851c664378SSubbaraya Sundeep 2861c664378SSubbaraya Sundeep static void emac_write(void *opaque, hwaddr addr, uint64_t val64, 2871c664378SSubbaraya Sundeep unsigned int size) 2881c664378SSubbaraya Sundeep { 2891c664378SSubbaraya Sundeep MSF2EmacState *s = opaque; 2901c664378SSubbaraya Sundeep uint32_t value = val64; 2911c664378SSubbaraya Sundeep uint32_t enreqbits; 2921c664378SSubbaraya Sundeep uint8_t pktcnt; 2931c664378SSubbaraya Sundeep 2941c664378SSubbaraya Sundeep addr >>= 2; 2951c664378SSubbaraya Sundeep switch (addr) { 2961c664378SSubbaraya Sundeep case R_DMA_TX_CTL: 2971c664378SSubbaraya Sundeep s->regs[addr] = value; 2981c664378SSubbaraya Sundeep if (value & R_DMA_TX_CTL_EN_MASK) { 2991c664378SSubbaraya Sundeep msf2_dma_tx(s); 3001c664378SSubbaraya Sundeep } 3011c664378SSubbaraya Sundeep break; 3021c664378SSubbaraya Sundeep case R_DMA_RX_CTL: 3031c664378SSubbaraya Sundeep s->regs[addr] = value; 3041c664378SSubbaraya Sundeep if (value & R_DMA_RX_CTL_EN_MASK) { 3051c664378SSubbaraya Sundeep s->rx_desc = s->regs[R_DMA_RX_DESC]; 3061c664378SSubbaraya Sundeep qemu_flush_queued_packets(qemu_get_queue(s->nic)); 3071c664378SSubbaraya Sundeep } 3081c664378SSubbaraya Sundeep break; 3091c664378SSubbaraya Sundeep case R_CFG1: 3101c664378SSubbaraya Sundeep s->regs[addr] = value; 3111c664378SSubbaraya Sundeep if (value & R_CFG1_RESET_MASK) { 3121c664378SSubbaraya Sundeep msf2_emac_do_reset(s); 3131c664378SSubbaraya Sundeep } 3141c664378SSubbaraya Sundeep break; 3151c664378SSubbaraya Sundeep case R_FIFO_CFG0: 3161c664378SSubbaraya Sundeep /* 3171c664378SSubbaraya Sundeep * For our implementation, turning on modules is instantaneous, 3181c664378SSubbaraya Sundeep * so the states requested via the *ENREQ bits appear in the 3191c664378SSubbaraya Sundeep * *ENRPLY bits immediately. Also the reset bits to reset PE-MCXMAC 3201c664378SSubbaraya Sundeep * module are not emulated here since it deals with start of frames, 3211c664378SSubbaraya Sundeep * inter-packet gap and control frames. 3221c664378SSubbaraya Sundeep */ 3231c664378SSubbaraya Sundeep enreqbits = extract32(value, 8, 5); 3241c664378SSubbaraya Sundeep s->regs[addr] = deposit32(value, 16, 5, enreqbits); 3251c664378SSubbaraya Sundeep break; 3261c664378SSubbaraya Sundeep case R_DMA_TX_DESC: 3271c664378SSubbaraya Sundeep if (value & 0x3) { 3281c664378SSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, "Tx Descriptor address should be" 3291c664378SSubbaraya Sundeep " 32 bit aligned\n"); 3301c664378SSubbaraya Sundeep } 3311c664378SSubbaraya Sundeep /* Ignore [1:0] bits */ 3321c664378SSubbaraya Sundeep s->regs[addr] = value & ~3; 3331c664378SSubbaraya Sundeep break; 3341c664378SSubbaraya Sundeep case R_DMA_RX_DESC: 3351c664378SSubbaraya Sundeep if (value & 0x3) { 3361c664378SSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, "Rx Descriptor address should be" 3371c664378SSubbaraya Sundeep " 32 bit aligned\n"); 3381c664378SSubbaraya Sundeep } 3391c664378SSubbaraya Sundeep /* Ignore [1:0] bits */ 3401c664378SSubbaraya Sundeep s->regs[addr] = value & ~3; 3411c664378SSubbaraya Sundeep break; 3421c664378SSubbaraya Sundeep case R_DMA_TX_STATUS: 3431c664378SSubbaraya Sundeep if (value & R_DMA_TX_STATUS_UNDERRUN_MASK) { 3441c664378SSubbaraya Sundeep s->regs[addr] &= ~R_DMA_TX_STATUS_UNDERRUN_MASK; 3451c664378SSubbaraya Sundeep } 3461c664378SSubbaraya Sundeep if (value & R_DMA_TX_STATUS_PKT_SENT_MASK) { 3471c664378SSubbaraya Sundeep pktcnt = FIELD_EX32(s->regs[addr], DMA_TX_STATUS, PKTCNT); 3481c664378SSubbaraya Sundeep pktcnt--; 3491c664378SSubbaraya Sundeep s->regs[addr] = FIELD_DP32(s->regs[addr], DMA_TX_STATUS, 3501c664378SSubbaraya Sundeep PKTCNT, pktcnt); 3511c664378SSubbaraya Sundeep if (pktcnt == 0) { 3521c664378SSubbaraya Sundeep s->regs[addr] &= ~R_DMA_TX_STATUS_PKT_SENT_MASK; 3531c664378SSubbaraya Sundeep } 3541c664378SSubbaraya Sundeep } 3551c664378SSubbaraya Sundeep break; 3561c664378SSubbaraya Sundeep case R_DMA_RX_STATUS: 3571c664378SSubbaraya Sundeep if (value & R_DMA_RX_STATUS_OVERFLOW_MASK) { 3581c664378SSubbaraya Sundeep s->regs[addr] &= ~R_DMA_RX_STATUS_OVERFLOW_MASK; 3591c664378SSubbaraya Sundeep } 3601c664378SSubbaraya Sundeep if (value & R_DMA_RX_STATUS_PKT_RCVD_MASK) { 3611c664378SSubbaraya Sundeep pktcnt = FIELD_EX32(s->regs[addr], DMA_RX_STATUS, PKTCNT); 3621c664378SSubbaraya Sundeep pktcnt--; 3631c664378SSubbaraya Sundeep s->regs[addr] = FIELD_DP32(s->regs[addr], DMA_RX_STATUS, 3641c664378SSubbaraya Sundeep PKTCNT, pktcnt); 3651c664378SSubbaraya Sundeep if (pktcnt == 0) { 3661c664378SSubbaraya Sundeep s->regs[addr] &= ~R_DMA_RX_STATUS_PKT_RCVD_MASK; 3671c664378SSubbaraya Sundeep } 3681c664378SSubbaraya Sundeep } 3691c664378SSubbaraya Sundeep break; 3701c664378SSubbaraya Sundeep case R_DMA_IRQ: 3711c664378SSubbaraya Sundeep break; 3721c664378SSubbaraya Sundeep case R_MII_CMD: 3731c664378SSubbaraya Sundeep if (value & R_MII_CMD_READ_MASK) { 3741c664378SSubbaraya Sundeep s->regs[R_MII_STS] = read_from_phy(s); 3751c664378SSubbaraya Sundeep } 3761c664378SSubbaraya Sundeep break; 3771c664378SSubbaraya Sundeep case R_MII_CTL: 3781c664378SSubbaraya Sundeep s->regs[addr] = value; 3791c664378SSubbaraya Sundeep write_to_phy(s); 3801c664378SSubbaraya Sundeep break; 3811c664378SSubbaraya Sundeep case R_STA1: 3821c664378SSubbaraya Sundeep s->regs[addr] = value; 3831c664378SSubbaraya Sundeep /* 3841c664378SSubbaraya Sundeep * R_STA1 [31:24] : octet 1 of mac address 3851c664378SSubbaraya Sundeep * R_STA1 [23:16] : octet 2 of mac address 3861c664378SSubbaraya Sundeep * R_STA1 [15:8] : octet 3 of mac address 3871c664378SSubbaraya Sundeep * R_STA1 [7:0] : octet 4 of mac address 3881c664378SSubbaraya Sundeep */ 3891c664378SSubbaraya Sundeep stl_be_p(s->mac_addr, value); 3901c664378SSubbaraya Sundeep break; 3911c664378SSubbaraya Sundeep case R_STA2: 3921c664378SSubbaraya Sundeep s->regs[addr] = value; 3931c664378SSubbaraya Sundeep /* 3941c664378SSubbaraya Sundeep * R_STA2 [31:24] : octet 5 of mac address 3951c664378SSubbaraya Sundeep * R_STA2 [23:16] : octet 6 of mac address 3961c664378SSubbaraya Sundeep */ 3971c664378SSubbaraya Sundeep stw_be_p(s->mac_addr + 4, value >> 16); 3981c664378SSubbaraya Sundeep break; 3991c664378SSubbaraya Sundeep default: 4001c664378SSubbaraya Sundeep if (addr >= ARRAY_SIZE(s->regs)) { 4011c664378SSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, 4021c664378SSubbaraya Sundeep "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, 4031c664378SSubbaraya Sundeep addr * 4); 4041c664378SSubbaraya Sundeep return; 4051c664378SSubbaraya Sundeep } 4061c664378SSubbaraya Sundeep s->regs[addr] = value; 4071c664378SSubbaraya Sundeep break; 4081c664378SSubbaraya Sundeep } 4091c664378SSubbaraya Sundeep emac_update_irq(s); 4101c664378SSubbaraya Sundeep } 4111c664378SSubbaraya Sundeep 4121c664378SSubbaraya Sundeep static const MemoryRegionOps emac_ops = { 4131c664378SSubbaraya Sundeep .read = emac_read, 4141c664378SSubbaraya Sundeep .write = emac_write, 4151c664378SSubbaraya Sundeep .endianness = DEVICE_NATIVE_ENDIAN, 4161c664378SSubbaraya Sundeep .impl = { 4171c664378SSubbaraya Sundeep .min_access_size = 4, 4181c664378SSubbaraya Sundeep .max_access_size = 4 4191c664378SSubbaraya Sundeep } 4201c664378SSubbaraya Sundeep }; 4211c664378SSubbaraya Sundeep 4221c664378SSubbaraya Sundeep static bool emac_can_rx(NetClientState *nc) 4231c664378SSubbaraya Sundeep { 4241c664378SSubbaraya Sundeep MSF2EmacState *s = qemu_get_nic_opaque(nc); 4251c664378SSubbaraya Sundeep 4261c664378SSubbaraya Sundeep return (s->regs[R_CFG1] & R_CFG1_RX_EN_MASK) && 4271c664378SSubbaraya Sundeep (s->regs[R_DMA_RX_CTL] & R_DMA_RX_CTL_EN_MASK); 4281c664378SSubbaraya Sundeep } 4291c664378SSubbaraya Sundeep 4301c664378SSubbaraya Sundeep static bool addr_filter_ok(MSF2EmacState *s, const uint8_t *buf) 4311c664378SSubbaraya Sundeep { 4321c664378SSubbaraya Sundeep /* The broadcast MAC address: FF:FF:FF:FF:FF:FF */ 4331c664378SSubbaraya Sundeep const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 4341c664378SSubbaraya Sundeep 0xFF, 0xFF }; 4351c664378SSubbaraya Sundeep bool bcast_en = true; 4361c664378SSubbaraya Sundeep bool mcast_en = true; 4371c664378SSubbaraya Sundeep 4381c664378SSubbaraya Sundeep if (s->regs[R_FIFO_CFG5] & R_FIFO_CFG5_BCAST_MASK) { 4391c664378SSubbaraya Sundeep bcast_en = true; /* Broadcast dont care for drop circuitry */ 4401c664378SSubbaraya Sundeep } else if (s->regs[R_FIFO_CFG4] & R_FIFO_CFG4_BCAST_MASK) { 4411c664378SSubbaraya Sundeep bcast_en = false; 4421c664378SSubbaraya Sundeep } 4431c664378SSubbaraya Sundeep 4441c664378SSubbaraya Sundeep if (s->regs[R_FIFO_CFG5] & R_FIFO_CFG5_MCAST_MASK) { 4451c664378SSubbaraya Sundeep mcast_en = true; /* Multicast dont care for drop circuitry */ 4461c664378SSubbaraya Sundeep } else if (s->regs[R_FIFO_CFG4] & R_FIFO_CFG4_MCAST_MASK) { 4471c664378SSubbaraya Sundeep mcast_en = false; 4481c664378SSubbaraya Sundeep } 4491c664378SSubbaraya Sundeep 4501c664378SSubbaraya Sundeep if (!memcmp(buf, broadcast_addr, sizeof(broadcast_addr))) { 4511c664378SSubbaraya Sundeep return bcast_en; 4521c664378SSubbaraya Sundeep } 4531c664378SSubbaraya Sundeep 4541c664378SSubbaraya Sundeep if (buf[0] & 1) { 4551c664378SSubbaraya Sundeep return mcast_en; 4561c664378SSubbaraya Sundeep } 4571c664378SSubbaraya Sundeep 4581c664378SSubbaraya Sundeep return !memcmp(buf, s->mac_addr, sizeof(s->mac_addr)); 4591c664378SSubbaraya Sundeep } 4601c664378SSubbaraya Sundeep 4611c664378SSubbaraya Sundeep static ssize_t emac_rx(NetClientState *nc, const uint8_t *buf, size_t size) 4621c664378SSubbaraya Sundeep { 4631c664378SSubbaraya Sundeep MSF2EmacState *s = qemu_get_nic_opaque(nc); 4641c664378SSubbaraya Sundeep EmacDesc d; 4651c664378SSubbaraya Sundeep uint8_t pktcnt; 4661c664378SSubbaraya Sundeep uint32_t status; 4671c664378SSubbaraya Sundeep 4681c664378SSubbaraya Sundeep if (size > (s->regs[R_MAX_FRAME_LENGTH] & 0xFFFF)) { 4691c664378SSubbaraya Sundeep return size; 4701c664378SSubbaraya Sundeep } 4711c664378SSubbaraya Sundeep if (!addr_filter_ok(s, buf)) { 4721c664378SSubbaraya Sundeep return size; 4731c664378SSubbaraya Sundeep } 4741c664378SSubbaraya Sundeep 4751c664378SSubbaraya Sundeep emac_load_desc(s, &d, s->rx_desc); 4761c664378SSubbaraya Sundeep 4771c664378SSubbaraya Sundeep if (d.pktsize & EMPTY_MASK) { 4781c664378SSubbaraya Sundeep address_space_write(&s->dma_as, d.pktaddr, MEMTXATTRS_UNSPECIFIED, 4791c664378SSubbaraya Sundeep buf, size & PKT_SIZE); 4801c664378SSubbaraya Sundeep d.pktsize = size & PKT_SIZE; 4811c664378SSubbaraya Sundeep emac_store_desc(s, &d, s->rx_desc); 4821c664378SSubbaraya Sundeep /* update received packets count */ 4831c664378SSubbaraya Sundeep status = s->regs[R_DMA_RX_STATUS]; 4841c664378SSubbaraya Sundeep pktcnt = FIELD_EX32(status, DMA_RX_STATUS, PKTCNT); 4851c664378SSubbaraya Sundeep pktcnt++; 4861c664378SSubbaraya Sundeep s->regs[R_DMA_RX_STATUS] = FIELD_DP32(status, DMA_RX_STATUS, 4871c664378SSubbaraya Sundeep PKTCNT, pktcnt); 4881c664378SSubbaraya Sundeep s->regs[R_DMA_RX_STATUS] |= R_DMA_RX_STATUS_PKT_RCVD_MASK; 4891c664378SSubbaraya Sundeep s->rx_desc = d.next; 4901c664378SSubbaraya Sundeep } else { 4911c664378SSubbaraya Sundeep s->regs[R_DMA_RX_CTL] &= ~R_DMA_RX_CTL_EN_MASK; 4921c664378SSubbaraya Sundeep s->regs[R_DMA_RX_STATUS] |= R_DMA_RX_STATUS_OVERFLOW_MASK; 4931c664378SSubbaraya Sundeep } 4941c664378SSubbaraya Sundeep emac_update_irq(s); 4951c664378SSubbaraya Sundeep return size; 4961c664378SSubbaraya Sundeep } 4971c664378SSubbaraya Sundeep 4981c664378SSubbaraya Sundeep static void msf2_emac_reset(DeviceState *dev) 4991c664378SSubbaraya Sundeep { 5001c664378SSubbaraya Sundeep MSF2EmacState *s = MSS_EMAC(dev); 5011c664378SSubbaraya Sundeep 5021c664378SSubbaraya Sundeep msf2_emac_do_reset(s); 5031c664378SSubbaraya Sundeep } 5041c664378SSubbaraya Sundeep 5051c664378SSubbaraya Sundeep static void emac_set_link(NetClientState *nc) 5061c664378SSubbaraya Sundeep { 5071c664378SSubbaraya Sundeep MSF2EmacState *s = qemu_get_nic_opaque(nc); 5081c664378SSubbaraya Sundeep 5091c664378SSubbaraya Sundeep msf2_phy_update_link(s); 5101c664378SSubbaraya Sundeep } 5111c664378SSubbaraya Sundeep 5121c664378SSubbaraya Sundeep static NetClientInfo net_msf2_emac_info = { 5131c664378SSubbaraya Sundeep .type = NET_CLIENT_DRIVER_NIC, 5141c664378SSubbaraya Sundeep .size = sizeof(NICState), 5151c664378SSubbaraya Sundeep .can_receive = emac_can_rx, 5161c664378SSubbaraya Sundeep .receive = emac_rx, 5171c664378SSubbaraya Sundeep .link_status_changed = emac_set_link, 5181c664378SSubbaraya Sundeep }; 5191c664378SSubbaraya Sundeep 5201c664378SSubbaraya Sundeep static void msf2_emac_realize(DeviceState *dev, Error **errp) 5211c664378SSubbaraya Sundeep { 5221c664378SSubbaraya Sundeep MSF2EmacState *s = MSS_EMAC(dev); 5231c664378SSubbaraya Sundeep 5241c664378SSubbaraya Sundeep if (!s->dma_mr) { 5251c664378SSubbaraya Sundeep error_setg(errp, "MSS_EMAC 'ahb-bus' link not set"); 5261c664378SSubbaraya Sundeep return; 5271c664378SSubbaraya Sundeep } 5281c664378SSubbaraya Sundeep 5291c664378SSubbaraya Sundeep address_space_init(&s->dma_as, s->dma_mr, "emac-ahb"); 5301c664378SSubbaraya Sundeep 5311c664378SSubbaraya Sundeep qemu_macaddr_default_if_unset(&s->conf.macaddr); 5321c664378SSubbaraya Sundeep s->nic = qemu_new_nic(&net_msf2_emac_info, &s->conf, 5331c664378SSubbaraya Sundeep object_get_typename(OBJECT(dev)), dev->id, s); 5341c664378SSubbaraya Sundeep qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 5351c664378SSubbaraya Sundeep } 5361c664378SSubbaraya Sundeep 5371c664378SSubbaraya Sundeep static void msf2_emac_init(Object *obj) 5381c664378SSubbaraya Sundeep { 5391c664378SSubbaraya Sundeep MSF2EmacState *s = MSS_EMAC(obj); 5401c664378SSubbaraya Sundeep 5411c664378SSubbaraya Sundeep sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 5421c664378SSubbaraya Sundeep 5431c664378SSubbaraya Sundeep memory_region_init_io(&s->mmio, obj, &emac_ops, s, 5441c664378SSubbaraya Sundeep "msf2-emac", R_MAX * 4); 5451c664378SSubbaraya Sundeep sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 5461c664378SSubbaraya Sundeep } 5471c664378SSubbaraya Sundeep 5481c664378SSubbaraya Sundeep static Property msf2_emac_properties[] = { 5491c664378SSubbaraya Sundeep DEFINE_PROP_LINK("ahb-bus", MSF2EmacState, dma_mr, 5501c664378SSubbaraya Sundeep TYPE_MEMORY_REGION, MemoryRegion *), 5511c664378SSubbaraya Sundeep DEFINE_NIC_PROPERTIES(MSF2EmacState, conf), 5521c664378SSubbaraya Sundeep DEFINE_PROP_END_OF_LIST(), 5531c664378SSubbaraya Sundeep }; 5541c664378SSubbaraya Sundeep 5551c664378SSubbaraya Sundeep static const VMStateDescription vmstate_msf2_emac = { 5561c664378SSubbaraya Sundeep .name = TYPE_MSS_EMAC, 5571c664378SSubbaraya Sundeep .version_id = 1, 5581c664378SSubbaraya Sundeep .minimum_version_id = 1, 5591c664378SSubbaraya Sundeep .fields = (VMStateField[]) { 5601c664378SSubbaraya Sundeep VMSTATE_UINT8_ARRAY(mac_addr, MSF2EmacState, ETH_ALEN), 5611c664378SSubbaraya Sundeep VMSTATE_UINT32(rx_desc, MSF2EmacState), 5621c664378SSubbaraya Sundeep VMSTATE_UINT16_ARRAY(phy_regs, MSF2EmacState, PHY_MAX_REGS), 5631c664378SSubbaraya Sundeep VMSTATE_UINT32_ARRAY(regs, MSF2EmacState, R_MAX), 5641c664378SSubbaraya Sundeep VMSTATE_END_OF_LIST() 5651c664378SSubbaraya Sundeep } 5661c664378SSubbaraya Sundeep }; 5671c664378SSubbaraya Sundeep 5681c664378SSubbaraya Sundeep static void msf2_emac_class_init(ObjectClass *klass, void *data) 5691c664378SSubbaraya Sundeep { 5701c664378SSubbaraya Sundeep DeviceClass *dc = DEVICE_CLASS(klass); 5711c664378SSubbaraya Sundeep 5721c664378SSubbaraya Sundeep dc->realize = msf2_emac_realize; 5731c664378SSubbaraya Sundeep dc->reset = msf2_emac_reset; 5741c664378SSubbaraya Sundeep dc->vmsd = &vmstate_msf2_emac; 5751c664378SSubbaraya Sundeep device_class_set_props(dc, msf2_emac_properties); 5761c664378SSubbaraya Sundeep } 5771c664378SSubbaraya Sundeep 5781c664378SSubbaraya Sundeep static const TypeInfo msf2_emac_info = { 5791c664378SSubbaraya Sundeep .name = TYPE_MSS_EMAC, 5801c664378SSubbaraya Sundeep .parent = TYPE_SYS_BUS_DEVICE, 5811c664378SSubbaraya Sundeep .instance_size = sizeof(MSF2EmacState), 5821c664378SSubbaraya Sundeep .instance_init = msf2_emac_init, 5831c664378SSubbaraya Sundeep .class_init = msf2_emac_class_init, 5841c664378SSubbaraya Sundeep }; 5851c664378SSubbaraya Sundeep 5861c664378SSubbaraya Sundeep static void msf2_emac_register_types(void) 5871c664378SSubbaraya Sundeep { 5881c664378SSubbaraya Sundeep type_register_static(&msf2_emac_info); 5891c664378SSubbaraya Sundeep } 5901c664378SSubbaraya Sundeep 5911c664378SSubbaraya Sundeep type_init(msf2_emac_register_types) 592