1*08f787a3SHao Wu /* 2*08f787a3SHao Wu * Nuvoton NPCM7xx/8xx GMAC Module 3*08f787a3SHao Wu * 4*08f787a3SHao Wu * Copyright 2024 Google LLC 5*08f787a3SHao Wu * Authors: 6*08f787a3SHao Wu * Hao Wu <wuhaotsh@google.com> 7*08f787a3SHao Wu * Nabih Estefan <nabihestefan@google.com> 8*08f787a3SHao Wu * 9*08f787a3SHao Wu * This program is free software; you can redistribute it and/or modify it 10*08f787a3SHao Wu * under the terms of the GNU General Public License as published by the 11*08f787a3SHao Wu * Free Software Foundation; either version 2 of the License, or 12*08f787a3SHao Wu * (at your option) any later version. 13*08f787a3SHao Wu * 14*08f787a3SHao Wu * This program is distributed in the hope that it will be useful, but WITHOUT 15*08f787a3SHao Wu * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16*08f787a3SHao Wu * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17*08f787a3SHao Wu * for more details. 18*08f787a3SHao Wu * 19*08f787a3SHao Wu * Unsupported/unimplemented features: 20*08f787a3SHao Wu * - MII is not implemented, MII_ADDR.BUSY and MII_DATA always return zero 21*08f787a3SHao Wu * - Precision timestamp (PTP) is not implemented. 22*08f787a3SHao Wu */ 23*08f787a3SHao Wu 24*08f787a3SHao Wu #include "qemu/osdep.h" 25*08f787a3SHao Wu 26*08f787a3SHao Wu #include "hw/registerfields.h" 27*08f787a3SHao Wu #include "hw/net/mii.h" 28*08f787a3SHao Wu #include "hw/net/npcm_gmac.h" 29*08f787a3SHao Wu #include "migration/vmstate.h" 30*08f787a3SHao Wu #include "qemu/log.h" 31*08f787a3SHao Wu #include "qemu/units.h" 32*08f787a3SHao Wu #include "sysemu/dma.h" 33*08f787a3SHao Wu #include "trace.h" 34*08f787a3SHao Wu 35*08f787a3SHao Wu REG32(NPCM_DMA_BUS_MODE, 0x1000) 36*08f787a3SHao Wu REG32(NPCM_DMA_XMT_POLL_DEMAND, 0x1004) 37*08f787a3SHao Wu REG32(NPCM_DMA_RCV_POLL_DEMAND, 0x1008) 38*08f787a3SHao Wu REG32(NPCM_DMA_RX_BASE_ADDR, 0x100c) 39*08f787a3SHao Wu REG32(NPCM_DMA_TX_BASE_ADDR, 0x1010) 40*08f787a3SHao Wu REG32(NPCM_DMA_STATUS, 0x1014) 41*08f787a3SHao Wu REG32(NPCM_DMA_CONTROL, 0x1018) 42*08f787a3SHao Wu REG32(NPCM_DMA_INTR_ENA, 0x101c) 43*08f787a3SHao Wu REG32(NPCM_DMA_MISSED_FRAME_CTR, 0x1020) 44*08f787a3SHao Wu REG32(NPCM_DMA_HOST_TX_DESC, 0x1048) 45*08f787a3SHao Wu REG32(NPCM_DMA_HOST_RX_DESC, 0x104c) 46*08f787a3SHao Wu REG32(NPCM_DMA_CUR_TX_BUF_ADDR, 0x1050) 47*08f787a3SHao Wu REG32(NPCM_DMA_CUR_RX_BUF_ADDR, 0x1054) 48*08f787a3SHao Wu REG32(NPCM_DMA_HW_FEATURE, 0x1058) 49*08f787a3SHao Wu 50*08f787a3SHao Wu REG32(NPCM_GMAC_MAC_CONFIG, 0x0) 51*08f787a3SHao Wu REG32(NPCM_GMAC_FRAME_FILTER, 0x4) 52*08f787a3SHao Wu REG32(NPCM_GMAC_HASH_HIGH, 0x8) 53*08f787a3SHao Wu REG32(NPCM_GMAC_HASH_LOW, 0xc) 54*08f787a3SHao Wu REG32(NPCM_GMAC_MII_ADDR, 0x10) 55*08f787a3SHao Wu REG32(NPCM_GMAC_MII_DATA, 0x14) 56*08f787a3SHao Wu REG32(NPCM_GMAC_FLOW_CTRL, 0x18) 57*08f787a3SHao Wu REG32(NPCM_GMAC_VLAN_FLAG, 0x1c) 58*08f787a3SHao Wu REG32(NPCM_GMAC_VERSION, 0x20) 59*08f787a3SHao Wu REG32(NPCM_GMAC_WAKEUP_FILTER, 0x28) 60*08f787a3SHao Wu REG32(NPCM_GMAC_PMT, 0x2c) 61*08f787a3SHao Wu REG32(NPCM_GMAC_LPI_CTRL, 0x30) 62*08f787a3SHao Wu REG32(NPCM_GMAC_TIMER_CTRL, 0x34) 63*08f787a3SHao Wu REG32(NPCM_GMAC_INT_STATUS, 0x38) 64*08f787a3SHao Wu REG32(NPCM_GMAC_INT_MASK, 0x3c) 65*08f787a3SHao Wu REG32(NPCM_GMAC_MAC0_ADDR_HI, 0x40) 66*08f787a3SHao Wu REG32(NPCM_GMAC_MAC0_ADDR_LO, 0x44) 67*08f787a3SHao Wu REG32(NPCM_GMAC_MAC1_ADDR_HI, 0x48) 68*08f787a3SHao Wu REG32(NPCM_GMAC_MAC1_ADDR_LO, 0x4c) 69*08f787a3SHao Wu REG32(NPCM_GMAC_MAC2_ADDR_HI, 0x50) 70*08f787a3SHao Wu REG32(NPCM_GMAC_MAC2_ADDR_LO, 0x54) 71*08f787a3SHao Wu REG32(NPCM_GMAC_MAC3_ADDR_HI, 0x58) 72*08f787a3SHao Wu REG32(NPCM_GMAC_MAC3_ADDR_LO, 0x5c) 73*08f787a3SHao Wu REG32(NPCM_GMAC_RGMII_STATUS, 0xd8) 74*08f787a3SHao Wu REG32(NPCM_GMAC_WATCHDOG, 0xdc) 75*08f787a3SHao Wu REG32(NPCM_GMAC_PTP_TCR, 0x700) 76*08f787a3SHao Wu REG32(NPCM_GMAC_PTP_SSIR, 0x704) 77*08f787a3SHao Wu REG32(NPCM_GMAC_PTP_STSR, 0x708) 78*08f787a3SHao Wu REG32(NPCM_GMAC_PTP_STNSR, 0x70c) 79*08f787a3SHao Wu REG32(NPCM_GMAC_PTP_STSUR, 0x710) 80*08f787a3SHao Wu REG32(NPCM_GMAC_PTP_STNSUR, 0x714) 81*08f787a3SHao Wu REG32(NPCM_GMAC_PTP_TAR, 0x718) 82*08f787a3SHao Wu REG32(NPCM_GMAC_PTP_TTSR, 0x71c) 83*08f787a3SHao Wu 84*08f787a3SHao Wu /* Register Fields */ 85*08f787a3SHao Wu #define NPCM_GMAC_MII_ADDR_BUSY BIT(0) 86*08f787a3SHao Wu #define NPCM_GMAC_MII_ADDR_WRITE BIT(1) 87*08f787a3SHao Wu #define NPCM_GMAC_MII_ADDR_GR(rv) extract16((rv), 6, 5) 88*08f787a3SHao Wu #define NPCM_GMAC_MII_ADDR_PA(rv) extract16((rv), 11, 5) 89*08f787a3SHao Wu 90*08f787a3SHao Wu #define NPCM_GMAC_INT_MASK_LPIIM BIT(10) 91*08f787a3SHao Wu #define NPCM_GMAC_INT_MASK_PMTM BIT(3) 92*08f787a3SHao Wu #define NPCM_GMAC_INT_MASK_RGIM BIT(0) 93*08f787a3SHao Wu 94*08f787a3SHao Wu #define NPCM_DMA_BUS_MODE_SWR BIT(0) 95*08f787a3SHao Wu 96*08f787a3SHao Wu static const uint32_t npcm_gmac_cold_reset_values[NPCM_GMAC_NR_REGS] = { 97*08f787a3SHao Wu /* Reduce version to 3.2 so that the kernel can enable interrupt. */ 98*08f787a3SHao Wu [R_NPCM_GMAC_VERSION] = 0x00001032, 99*08f787a3SHao Wu [R_NPCM_GMAC_TIMER_CTRL] = 0x03e80000, 100*08f787a3SHao Wu [R_NPCM_GMAC_MAC0_ADDR_HI] = 0x8000ffff, 101*08f787a3SHao Wu [R_NPCM_GMAC_MAC0_ADDR_LO] = 0xffffffff, 102*08f787a3SHao Wu [R_NPCM_GMAC_MAC1_ADDR_HI] = 0x0000ffff, 103*08f787a3SHao Wu [R_NPCM_GMAC_MAC1_ADDR_LO] = 0xffffffff, 104*08f787a3SHao Wu [R_NPCM_GMAC_MAC2_ADDR_HI] = 0x0000ffff, 105*08f787a3SHao Wu [R_NPCM_GMAC_MAC2_ADDR_LO] = 0xffffffff, 106*08f787a3SHao Wu [R_NPCM_GMAC_MAC3_ADDR_HI] = 0x0000ffff, 107*08f787a3SHao Wu [R_NPCM_GMAC_MAC3_ADDR_LO] = 0xffffffff, 108*08f787a3SHao Wu [R_NPCM_GMAC_PTP_TCR] = 0x00002000, 109*08f787a3SHao Wu [R_NPCM_DMA_BUS_MODE] = 0x00020101, 110*08f787a3SHao Wu [R_NPCM_DMA_HW_FEATURE] = 0x100d4f37, 111*08f787a3SHao Wu }; 112*08f787a3SHao Wu 113*08f787a3SHao Wu static const uint16_t phy_reg_init[] = { 114*08f787a3SHao Wu [MII_BMCR] = MII_BMCR_AUTOEN | MII_BMCR_FD | MII_BMCR_SPEED1000, 115*08f787a3SHao Wu [MII_BMSR] = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD | 116*08f787a3SHao Wu MII_BMSR_10T_HD | MII_BMSR_EXTSTAT | MII_BMSR_AUTONEG | 117*08f787a3SHao Wu MII_BMSR_LINK_ST | MII_BMSR_EXTCAP, 118*08f787a3SHao Wu [MII_PHYID1] = 0x0362, 119*08f787a3SHao Wu [MII_PHYID2] = 0x5e6a, 120*08f787a3SHao Wu [MII_ANAR] = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD | 121*08f787a3SHao Wu MII_ANAR_10 | MII_ANAR_CSMACD, 122*08f787a3SHao Wu [MII_ANLPAR] = MII_ANLPAR_ACK | MII_ANLPAR_PAUSE | 123*08f787a3SHao Wu MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD | 124*08f787a3SHao Wu MII_ANLPAR_10 | MII_ANLPAR_CSMACD, 125*08f787a3SHao Wu [MII_ANER] = 0x64 | MII_ANER_NWAY, 126*08f787a3SHao Wu [MII_ANNP] = 0x2001, 127*08f787a3SHao Wu [MII_CTRL1000] = MII_CTRL1000_FULL, 128*08f787a3SHao Wu [MII_STAT1000] = MII_STAT1000_FULL, 129*08f787a3SHao Wu [MII_EXTSTAT] = 0x3000, /* 1000BASTE_T full-duplex capable */ 130*08f787a3SHao Wu }; 131*08f787a3SHao Wu 132*08f787a3SHao Wu static void npcm_gmac_soft_reset(NPCMGMACState *gmac) 133*08f787a3SHao Wu { 134*08f787a3SHao Wu memcpy(gmac->regs, npcm_gmac_cold_reset_values, 135*08f787a3SHao Wu NPCM_GMAC_NR_REGS * sizeof(uint32_t)); 136*08f787a3SHao Wu /* Clear reset bits */ 137*08f787a3SHao Wu gmac->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR; 138*08f787a3SHao Wu } 139*08f787a3SHao Wu 140*08f787a3SHao Wu static void gmac_phy_set_link(NPCMGMACState *gmac, bool active) 141*08f787a3SHao Wu { 142*08f787a3SHao Wu /* Autonegotiation status mirrors link status. */ 143*08f787a3SHao Wu if (active) { 144*08f787a3SHao Wu gmac->phy_regs[0][MII_BMSR] |= (MII_BMSR_LINK_ST | MII_BMSR_AN_COMP); 145*08f787a3SHao Wu } else { 146*08f787a3SHao Wu gmac->phy_regs[0][MII_BMSR] &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP); 147*08f787a3SHao Wu } 148*08f787a3SHao Wu } 149*08f787a3SHao Wu 150*08f787a3SHao Wu static bool gmac_can_receive(NetClientState *nc) 151*08f787a3SHao Wu { 152*08f787a3SHao Wu return true; 153*08f787a3SHao Wu } 154*08f787a3SHao Wu 155*08f787a3SHao Wu /* 156*08f787a3SHao Wu * Function that updates the GMAC IRQ 157*08f787a3SHao Wu * It find the logical OR of the enabled bits for NIS (if enabled) 158*08f787a3SHao Wu * It find the logical OR of the enabled bits for AIS (if enabled) 159*08f787a3SHao Wu */ 160*08f787a3SHao Wu static void gmac_update_irq(NPCMGMACState *gmac) 161*08f787a3SHao Wu { 162*08f787a3SHao Wu /* 163*08f787a3SHao Wu * Check if the normal interrupts summary is enabled 164*08f787a3SHao Wu * if so, add the bits for the summary that are enabled 165*08f787a3SHao Wu */ 166*08f787a3SHao Wu if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] & 167*08f787a3SHao Wu (NPCM_DMA_INTR_ENAB_NIE_BITS)) { 168*08f787a3SHao Wu gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_NIS; 169*08f787a3SHao Wu } 170*08f787a3SHao Wu /* 171*08f787a3SHao Wu * Check if the abnormal interrupts summary is enabled 172*08f787a3SHao Wu * if so, add the bits for the summary that are enabled 173*08f787a3SHao Wu */ 174*08f787a3SHao Wu if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] & 175*08f787a3SHao Wu (NPCM_DMA_INTR_ENAB_AIE_BITS)) { 176*08f787a3SHao Wu gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_AIS; 177*08f787a3SHao Wu } 178*08f787a3SHao Wu 179*08f787a3SHao Wu /* Get the logical OR of both normal and abnormal interrupts */ 180*08f787a3SHao Wu int level = !!((gmac->regs[R_NPCM_DMA_STATUS] & 181*08f787a3SHao Wu gmac->regs[R_NPCM_DMA_INTR_ENA] & 182*08f787a3SHao Wu NPCM_DMA_STATUS_NIS) | 183*08f787a3SHao Wu (gmac->regs[R_NPCM_DMA_STATUS] & 184*08f787a3SHao Wu gmac->regs[R_NPCM_DMA_INTR_ENA] & 185*08f787a3SHao Wu NPCM_DMA_STATUS_AIS)); 186*08f787a3SHao Wu 187*08f787a3SHao Wu /* Set the IRQ */ 188*08f787a3SHao Wu trace_npcm_gmac_update_irq(DEVICE(gmac)->canonical_path, 189*08f787a3SHao Wu gmac->regs[R_NPCM_DMA_STATUS], 190*08f787a3SHao Wu gmac->regs[R_NPCM_DMA_INTR_ENA], 191*08f787a3SHao Wu level); 192*08f787a3SHao Wu qemu_set_irq(gmac->irq, level); 193*08f787a3SHao Wu } 194*08f787a3SHao Wu 195*08f787a3SHao Wu static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len) 196*08f787a3SHao Wu { 197*08f787a3SHao Wu /* Placeholder. Function will be filled in following patches */ 198*08f787a3SHao Wu return 0; 199*08f787a3SHao Wu } 200*08f787a3SHao Wu 201*08f787a3SHao Wu static void gmac_cleanup(NetClientState *nc) 202*08f787a3SHao Wu { 203*08f787a3SHao Wu /* Nothing to do yet. */ 204*08f787a3SHao Wu } 205*08f787a3SHao Wu 206*08f787a3SHao Wu static void gmac_set_link(NetClientState *nc) 207*08f787a3SHao Wu { 208*08f787a3SHao Wu NPCMGMACState *gmac = qemu_get_nic_opaque(nc); 209*08f787a3SHao Wu 210*08f787a3SHao Wu trace_npcm_gmac_set_link(!nc->link_down); 211*08f787a3SHao Wu gmac_phy_set_link(gmac, !nc->link_down); 212*08f787a3SHao Wu } 213*08f787a3SHao Wu 214*08f787a3SHao Wu static void npcm_gmac_mdio_access(NPCMGMACState *gmac, uint16_t v) 215*08f787a3SHao Wu { 216*08f787a3SHao Wu bool busy = v & NPCM_GMAC_MII_ADDR_BUSY; 217*08f787a3SHao Wu uint8_t is_write; 218*08f787a3SHao Wu uint8_t pa, gr; 219*08f787a3SHao Wu uint16_t data; 220*08f787a3SHao Wu 221*08f787a3SHao Wu if (busy) { 222*08f787a3SHao Wu is_write = v & NPCM_GMAC_MII_ADDR_WRITE; 223*08f787a3SHao Wu pa = NPCM_GMAC_MII_ADDR_PA(v); 224*08f787a3SHao Wu gr = NPCM_GMAC_MII_ADDR_GR(v); 225*08f787a3SHao Wu /* Both pa and gr are 5 bits, so they are less than 32. */ 226*08f787a3SHao Wu g_assert(pa < NPCM_GMAC_MAX_PHYS); 227*08f787a3SHao Wu g_assert(gr < NPCM_GMAC_MAX_PHY_REGS); 228*08f787a3SHao Wu 229*08f787a3SHao Wu 230*08f787a3SHao Wu if (v & NPCM_GMAC_MII_ADDR_WRITE) { 231*08f787a3SHao Wu data = gmac->regs[R_NPCM_GMAC_MII_DATA]; 232*08f787a3SHao Wu /* Clear reset bit for BMCR register */ 233*08f787a3SHao Wu switch (gr) { 234*08f787a3SHao Wu case MII_BMCR: 235*08f787a3SHao Wu data &= ~MII_BMCR_RESET; 236*08f787a3SHao Wu /* Autonegotiation is a W1C bit*/ 237*08f787a3SHao Wu if (data & MII_BMCR_ANRESTART) { 238*08f787a3SHao Wu /* Tells autonegotiation to not restart again */ 239*08f787a3SHao Wu data &= ~MII_BMCR_ANRESTART; 240*08f787a3SHao Wu } 241*08f787a3SHao Wu if ((data & MII_BMCR_AUTOEN) && 242*08f787a3SHao Wu !(gmac->phy_regs[pa][MII_BMSR] & MII_BMSR_AN_COMP)) { 243*08f787a3SHao Wu /* sets autonegotiation as complete */ 244*08f787a3SHao Wu gmac->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP; 245*08f787a3SHao Wu /* Resolve AN automatically->need to set this */ 246*08f787a3SHao Wu gmac->phy_regs[0][MII_ANLPAR] = 0x0000; 247*08f787a3SHao Wu } 248*08f787a3SHao Wu } 249*08f787a3SHao Wu gmac->phy_regs[pa][gr] = data; 250*08f787a3SHao Wu } else { 251*08f787a3SHao Wu data = gmac->phy_regs[pa][gr]; 252*08f787a3SHao Wu gmac->regs[R_NPCM_GMAC_MII_DATA] = data; 253*08f787a3SHao Wu } 254*08f787a3SHao Wu trace_npcm_gmac_mdio_access(DEVICE(gmac)->canonical_path, is_write, pa, 255*08f787a3SHao Wu gr, data); 256*08f787a3SHao Wu } 257*08f787a3SHao Wu gmac->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY; 258*08f787a3SHao Wu } 259*08f787a3SHao Wu 260*08f787a3SHao Wu static uint64_t npcm_gmac_read(void *opaque, hwaddr offset, unsigned size) 261*08f787a3SHao Wu { 262*08f787a3SHao Wu NPCMGMACState *gmac = opaque; 263*08f787a3SHao Wu uint32_t v = 0; 264*08f787a3SHao Wu 265*08f787a3SHao Wu switch (offset) { 266*08f787a3SHao Wu /* Write only registers */ 267*08f787a3SHao Wu case A_NPCM_DMA_XMT_POLL_DEMAND: 268*08f787a3SHao Wu case A_NPCM_DMA_RCV_POLL_DEMAND: 269*08f787a3SHao Wu qemu_log_mask(LOG_GUEST_ERROR, 270*08f787a3SHao Wu "%s: Read of write-only reg: offset: 0x%04" HWADDR_PRIx 271*08f787a3SHao Wu "\n", DEVICE(gmac)->canonical_path, offset); 272*08f787a3SHao Wu break; 273*08f787a3SHao Wu 274*08f787a3SHao Wu default: 275*08f787a3SHao Wu v = gmac->regs[offset / sizeof(uint32_t)]; 276*08f787a3SHao Wu } 277*08f787a3SHao Wu 278*08f787a3SHao Wu trace_npcm_gmac_reg_read(DEVICE(gmac)->canonical_path, offset, v); 279*08f787a3SHao Wu return v; 280*08f787a3SHao Wu } 281*08f787a3SHao Wu 282*08f787a3SHao Wu static void npcm_gmac_write(void *opaque, hwaddr offset, 283*08f787a3SHao Wu uint64_t v, unsigned size) 284*08f787a3SHao Wu { 285*08f787a3SHao Wu NPCMGMACState *gmac = opaque; 286*08f787a3SHao Wu 287*08f787a3SHao Wu trace_npcm_gmac_reg_write(DEVICE(gmac)->canonical_path, offset, v); 288*08f787a3SHao Wu 289*08f787a3SHao Wu switch (offset) { 290*08f787a3SHao Wu /* Read only registers */ 291*08f787a3SHao Wu case A_NPCM_GMAC_VERSION: 292*08f787a3SHao Wu case A_NPCM_GMAC_INT_STATUS: 293*08f787a3SHao Wu case A_NPCM_GMAC_RGMII_STATUS: 294*08f787a3SHao Wu case A_NPCM_GMAC_PTP_STSR: 295*08f787a3SHao Wu case A_NPCM_GMAC_PTP_STNSR: 296*08f787a3SHao Wu case A_NPCM_DMA_MISSED_FRAME_CTR: 297*08f787a3SHao Wu case A_NPCM_DMA_HOST_TX_DESC: 298*08f787a3SHao Wu case A_NPCM_DMA_HOST_RX_DESC: 299*08f787a3SHao Wu case A_NPCM_DMA_CUR_TX_BUF_ADDR: 300*08f787a3SHao Wu case A_NPCM_DMA_CUR_RX_BUF_ADDR: 301*08f787a3SHao Wu case A_NPCM_DMA_HW_FEATURE: 302*08f787a3SHao Wu qemu_log_mask(LOG_GUEST_ERROR, 303*08f787a3SHao Wu "%s: Write of read-only reg: offset: 0x%04" HWADDR_PRIx 304*08f787a3SHao Wu ", value: 0x%04" PRIx64 "\n", 305*08f787a3SHao Wu DEVICE(gmac)->canonical_path, offset, v); 306*08f787a3SHao Wu break; 307*08f787a3SHao Wu 308*08f787a3SHao Wu case A_NPCM_GMAC_MAC_CONFIG: 309*08f787a3SHao Wu break; 310*08f787a3SHao Wu 311*08f787a3SHao Wu case A_NPCM_GMAC_MII_ADDR: 312*08f787a3SHao Wu npcm_gmac_mdio_access(gmac, v); 313*08f787a3SHao Wu break; 314*08f787a3SHao Wu 315*08f787a3SHao Wu case A_NPCM_GMAC_MAC0_ADDR_HI: 316*08f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 317*08f787a3SHao Wu gmac->conf.macaddr.a[0] = v >> 8; 318*08f787a3SHao Wu gmac->conf.macaddr.a[1] = v >> 0; 319*08f787a3SHao Wu break; 320*08f787a3SHao Wu 321*08f787a3SHao Wu case A_NPCM_GMAC_MAC0_ADDR_LO: 322*08f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 323*08f787a3SHao Wu gmac->conf.macaddr.a[2] = v >> 24; 324*08f787a3SHao Wu gmac->conf.macaddr.a[3] = v >> 16; 325*08f787a3SHao Wu gmac->conf.macaddr.a[4] = v >> 8; 326*08f787a3SHao Wu gmac->conf.macaddr.a[5] = v >> 0; 327*08f787a3SHao Wu break; 328*08f787a3SHao Wu 329*08f787a3SHao Wu case A_NPCM_GMAC_MAC1_ADDR_HI: 330*08f787a3SHao Wu case A_NPCM_GMAC_MAC1_ADDR_LO: 331*08f787a3SHao Wu case A_NPCM_GMAC_MAC2_ADDR_HI: 332*08f787a3SHao Wu case A_NPCM_GMAC_MAC2_ADDR_LO: 333*08f787a3SHao Wu case A_NPCM_GMAC_MAC3_ADDR_HI: 334*08f787a3SHao Wu case A_NPCM_GMAC_MAC3_ADDR_LO: 335*08f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 336*08f787a3SHao Wu qemu_log_mask(LOG_UNIMP, 337*08f787a3SHao Wu "%s: Only MAC Address 0 is supported. This request " 338*08f787a3SHao Wu "is ignored.\n", DEVICE(gmac)->canonical_path); 339*08f787a3SHao Wu break; 340*08f787a3SHao Wu 341*08f787a3SHao Wu case A_NPCM_DMA_BUS_MODE: 342*08f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 343*08f787a3SHao Wu if (v & NPCM_DMA_BUS_MODE_SWR) { 344*08f787a3SHao Wu npcm_gmac_soft_reset(gmac); 345*08f787a3SHao Wu } 346*08f787a3SHao Wu break; 347*08f787a3SHao Wu 348*08f787a3SHao Wu case A_NPCM_DMA_RCV_POLL_DEMAND: 349*08f787a3SHao Wu /* We dont actually care about the value */ 350*08f787a3SHao Wu break; 351*08f787a3SHao Wu 352*08f787a3SHao Wu case A_NPCM_DMA_STATUS: 353*08f787a3SHao Wu /* Check that RO bits are not written to */ 354*08f787a3SHao Wu if (NPCM_DMA_STATUS_RO_MASK(v)) { 355*08f787a3SHao Wu qemu_log_mask(LOG_GUEST_ERROR, 356*08f787a3SHao Wu "%s: Write of read-only bits of reg: offset: 0x%04" 357*08f787a3SHao Wu HWADDR_PRIx ", value: 0x%04" PRIx64 "\n", 358*08f787a3SHao Wu DEVICE(gmac)->canonical_path, offset, v); 359*08f787a3SHao Wu } 360*08f787a3SHao Wu break; 361*08f787a3SHao Wu 362*08f787a3SHao Wu default: 363*08f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 364*08f787a3SHao Wu break; 365*08f787a3SHao Wu } 366*08f787a3SHao Wu 367*08f787a3SHao Wu gmac_update_irq(gmac); 368*08f787a3SHao Wu } 369*08f787a3SHao Wu 370*08f787a3SHao Wu static void npcm_gmac_reset(DeviceState *dev) 371*08f787a3SHao Wu { 372*08f787a3SHao Wu NPCMGMACState *gmac = NPCM_GMAC(dev); 373*08f787a3SHao Wu 374*08f787a3SHao Wu npcm_gmac_soft_reset(gmac); 375*08f787a3SHao Wu memcpy(gmac->phy_regs[0], phy_reg_init, sizeof(phy_reg_init)); 376*08f787a3SHao Wu 377*08f787a3SHao Wu trace_npcm_gmac_reset(DEVICE(gmac)->canonical_path, 378*08f787a3SHao Wu gmac->phy_regs[0][MII_BMSR]); 379*08f787a3SHao Wu } 380*08f787a3SHao Wu 381*08f787a3SHao Wu static NetClientInfo net_npcm_gmac_info = { 382*08f787a3SHao Wu .type = NET_CLIENT_DRIVER_NIC, 383*08f787a3SHao Wu .size = sizeof(NICState), 384*08f787a3SHao Wu .can_receive = gmac_can_receive, 385*08f787a3SHao Wu .receive = gmac_receive, 386*08f787a3SHao Wu .cleanup = gmac_cleanup, 387*08f787a3SHao Wu .link_status_changed = gmac_set_link, 388*08f787a3SHao Wu }; 389*08f787a3SHao Wu 390*08f787a3SHao Wu static const struct MemoryRegionOps npcm_gmac_ops = { 391*08f787a3SHao Wu .read = npcm_gmac_read, 392*08f787a3SHao Wu .write = npcm_gmac_write, 393*08f787a3SHao Wu .endianness = DEVICE_LITTLE_ENDIAN, 394*08f787a3SHao Wu .valid = { 395*08f787a3SHao Wu .min_access_size = 4, 396*08f787a3SHao Wu .max_access_size = 4, 397*08f787a3SHao Wu .unaligned = false, 398*08f787a3SHao Wu }, 399*08f787a3SHao Wu }; 400*08f787a3SHao Wu 401*08f787a3SHao Wu static void npcm_gmac_realize(DeviceState *dev, Error **errp) 402*08f787a3SHao Wu { 403*08f787a3SHao Wu NPCMGMACState *gmac = NPCM_GMAC(dev); 404*08f787a3SHao Wu SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 405*08f787a3SHao Wu 406*08f787a3SHao Wu memory_region_init_io(&gmac->iomem, OBJECT(gmac), &npcm_gmac_ops, gmac, 407*08f787a3SHao Wu TYPE_NPCM_GMAC, 8 * KiB); 408*08f787a3SHao Wu sysbus_init_mmio(sbd, &gmac->iomem); 409*08f787a3SHao Wu sysbus_init_irq(sbd, &gmac->irq); 410*08f787a3SHao Wu 411*08f787a3SHao Wu qemu_macaddr_default_if_unset(&gmac->conf.macaddr); 412*08f787a3SHao Wu 413*08f787a3SHao Wu gmac->nic = qemu_new_nic(&net_npcm_gmac_info, &gmac->conf, TYPE_NPCM_GMAC, 414*08f787a3SHao Wu dev->id, &dev->mem_reentrancy_guard, gmac); 415*08f787a3SHao Wu qemu_format_nic_info_str(qemu_get_queue(gmac->nic), gmac->conf.macaddr.a); 416*08f787a3SHao Wu gmac->regs[R_NPCM_GMAC_MAC0_ADDR_HI] = (gmac->conf.macaddr.a[0] << 8) + \ 417*08f787a3SHao Wu gmac->conf.macaddr.a[1]; 418*08f787a3SHao Wu gmac->regs[R_NPCM_GMAC_MAC0_ADDR_LO] = (gmac->conf.macaddr.a[2] << 24) + \ 419*08f787a3SHao Wu (gmac->conf.macaddr.a[3] << 16) + \ 420*08f787a3SHao Wu (gmac->conf.macaddr.a[4] << 8) + \ 421*08f787a3SHao Wu gmac->conf.macaddr.a[5]; 422*08f787a3SHao Wu } 423*08f787a3SHao Wu 424*08f787a3SHao Wu static void npcm_gmac_unrealize(DeviceState *dev) 425*08f787a3SHao Wu { 426*08f787a3SHao Wu NPCMGMACState *gmac = NPCM_GMAC(dev); 427*08f787a3SHao Wu 428*08f787a3SHao Wu qemu_del_nic(gmac->nic); 429*08f787a3SHao Wu } 430*08f787a3SHao Wu 431*08f787a3SHao Wu static const VMStateDescription vmstate_npcm_gmac = { 432*08f787a3SHao Wu .name = TYPE_NPCM_GMAC, 433*08f787a3SHao Wu .version_id = 0, 434*08f787a3SHao Wu .minimum_version_id = 0, 435*08f787a3SHao Wu .fields = (VMStateField[]) { 436*08f787a3SHao Wu VMSTATE_UINT32_ARRAY(regs, NPCMGMACState, NPCM_GMAC_NR_REGS), 437*08f787a3SHao Wu VMSTATE_END_OF_LIST(), 438*08f787a3SHao Wu }, 439*08f787a3SHao Wu }; 440*08f787a3SHao Wu 441*08f787a3SHao Wu static Property npcm_gmac_properties[] = { 442*08f787a3SHao Wu DEFINE_NIC_PROPERTIES(NPCMGMACState, conf), 443*08f787a3SHao Wu DEFINE_PROP_END_OF_LIST(), 444*08f787a3SHao Wu }; 445*08f787a3SHao Wu 446*08f787a3SHao Wu static void npcm_gmac_class_init(ObjectClass *klass, void *data) 447*08f787a3SHao Wu { 448*08f787a3SHao Wu DeviceClass *dc = DEVICE_CLASS(klass); 449*08f787a3SHao Wu 450*08f787a3SHao Wu set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 451*08f787a3SHao Wu dc->desc = "NPCM GMAC Controller"; 452*08f787a3SHao Wu dc->realize = npcm_gmac_realize; 453*08f787a3SHao Wu dc->unrealize = npcm_gmac_unrealize; 454*08f787a3SHao Wu dc->reset = npcm_gmac_reset; 455*08f787a3SHao Wu dc->vmsd = &vmstate_npcm_gmac; 456*08f787a3SHao Wu device_class_set_props(dc, npcm_gmac_properties); 457*08f787a3SHao Wu } 458*08f787a3SHao Wu 459*08f787a3SHao Wu static const TypeInfo npcm_gmac_types[] = { 460*08f787a3SHao Wu { 461*08f787a3SHao Wu .name = TYPE_NPCM_GMAC, 462*08f787a3SHao Wu .parent = TYPE_SYS_BUS_DEVICE, 463*08f787a3SHao Wu .instance_size = sizeof(NPCMGMACState), 464*08f787a3SHao Wu .class_init = npcm_gmac_class_init, 465*08f787a3SHao Wu }, 466*08f787a3SHao Wu }; 467*08f787a3SHao Wu DEFINE_TYPES(npcm_gmac_types) 468