xref: /qemu/hw/net/npcm_gmac.c (revision 08f787a3)
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