2 * Allwinner Sun8i Ethernet MAC emulation
4 * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qemu/units.h"
22 #include "hw/sysbus.h"
23 #include "migration/vmstate.h"
26 #include "hw/qdev-properties.h"
29 #include "net/checksum.h"
30 #include "qemu/module.h"
31 #include "exec/cpu-common.h"
32 #include "hw/net/allwinner-sun8i-emac.h"
34 /* EMAC register offsets */
36 REG_BASIC_CTL_0
= 0x0000, /* Basic Control 0 */
37 REG_BASIC_CTL_1
= 0x0004, /* Basic Control 1 */
38 REG_INT_STA
= 0x0008, /* Interrupt Status */
39 REG_INT_EN
= 0x000C, /* Interrupt Enable */
40 REG_TX_CTL_0
= 0x0010, /* Transmit Control 0 */
41 REG_TX_CTL_1
= 0x0014, /* Transmit Control 1 */
42 REG_TX_FLOW_CTL
= 0x001C, /* Transmit Flow Control */
43 REG_TX_DMA_DESC_LIST
= 0x0020, /* Transmit Descriptor List Address */
44 REG_RX_CTL_0
= 0x0024, /* Receive Control 0 */
45 REG_RX_CTL_1
= 0x0028, /* Receive Control 1 */
46 REG_RX_DMA_DESC_LIST
= 0x0034, /* Receive Descriptor List Address */
47 REG_FRM_FLT
= 0x0038, /* Receive Frame Filter */
48 REG_RX_HASH_0
= 0x0040, /* Receive Hash Table 0 */
49 REG_RX_HASH_1
= 0x0044, /* Receive Hash Table 1 */
50 REG_MII_CMD
= 0x0048, /* Management Interface Command */
51 REG_MII_DATA
= 0x004C, /* Management Interface Data */
52 REG_ADDR_HIGH
= 0x0050, /* MAC Address High */
53 REG_ADDR_LOW
= 0x0054, /* MAC Address Low */
54 REG_TX_DMA_STA
= 0x00B0, /* Transmit DMA Status */
55 REG_TX_CUR_DESC
= 0x00B4, /* Transmit Current Descriptor */
56 REG_TX_CUR_BUF
= 0x00B8, /* Transmit Current Buffer */
57 REG_RX_DMA_STA
= 0x00C0, /* Receive DMA Status */
58 REG_RX_CUR_DESC
= 0x00C4, /* Receive Current Descriptor */
59 REG_RX_CUR_BUF
= 0x00C8, /* Receive Current Buffer */
60 REG_RGMII_STA
= 0x00D0, /* RGMII Status */
63 /* EMAC register flags */
65 BASIC_CTL0_100Mbps
= (0b11 << 2),
66 BASIC_CTL0_FD
= (1 << 0),
67 BASIC_CTL1_SOFTRST
= (1 << 0),
71 INT_STA_RGMII_LINK
= (1 << 16),
72 INT_STA_RX_EARLY
= (1 << 13),
73 INT_STA_RX_OVERFLOW
= (1 << 12),
74 INT_STA_RX_TIMEOUT
= (1 << 11),
75 INT_STA_RX_DMA_STOP
= (1 << 10),
76 INT_STA_RX_BUF_UA
= (1 << 9),
77 INT_STA_RX
= (1 << 8),
78 INT_STA_TX_EARLY
= (1 << 5),
79 INT_STA_TX_UNDERFLOW
= (1 << 4),
80 INT_STA_TX_TIMEOUT
= (1 << 3),
81 INT_STA_TX_BUF_UA
= (1 << 2),
82 INT_STA_TX_DMA_STOP
= (1 << 1),
83 INT_STA_TX
= (1 << 0),
87 INT_EN_RX_EARLY
= (1 << 13),
88 INT_EN_RX_OVERFLOW
= (1 << 12),
89 INT_EN_RX_TIMEOUT
= (1 << 11),
90 INT_EN_RX_DMA_STOP
= (1 << 10),
91 INT_EN_RX_BUF_UA
= (1 << 9),
93 INT_EN_TX_EARLY
= (1 << 5),
94 INT_EN_TX_UNDERFLOW
= (1 << 4),
95 INT_EN_TX_TIMEOUT
= (1 << 3),
96 INT_EN_TX_BUF_UA
= (1 << 2),
97 INT_EN_TX_DMA_STOP
= (1 << 1),
102 TX_CTL0_TX_EN
= (1 << 31),
103 TX_CTL1_TX_DMA_START
= (1 << 31),
104 TX_CTL1_TX_DMA_EN
= (1 << 30),
105 TX_CTL1_TX_FLUSH
= (1 << 0),
109 RX_CTL0_RX_EN
= (1 << 31),
110 RX_CTL0_STRIP_FCS
= (1 << 28),
111 RX_CTL0_CRC_IPV4
= (1 << 27),
115 RX_CTL1_RX_DMA_START
= (1 << 31),
116 RX_CTL1_RX_DMA_EN
= (1 << 30),
117 RX_CTL1_RX_MD
= (1 << 1),
121 RX_FRM_FLT_DIS_ADDR
= (1 << 31),
125 MII_CMD_PHY_ADDR_SHIFT
= (12),
126 MII_CMD_PHY_ADDR_MASK
= (0xf000),
127 MII_CMD_PHY_REG_SHIFT
= (4),
128 MII_CMD_PHY_REG_MASK
= (0xf0),
129 MII_CMD_PHY_RW
= (1 << 1),
130 MII_CMD_PHY_BUSY
= (1 << 0),
134 TX_DMA_STA_STOP
= (0b000),
135 TX_DMA_STA_RUN_FETCH
= (0b001),
136 TX_DMA_STA_WAIT_STA
= (0b010),
140 RX_DMA_STA_STOP
= (0b000),
141 RX_DMA_STA_RUN_FETCH
= (0b001),
142 RX_DMA_STA_WAIT_FRM
= (0b011),
145 /* EMAC register reset values */
147 REG_BASIC_CTL_1_RST
= 0x08000000,
152 AW_SUN8I_EMAC_MIN_PKT_SZ
= 64
155 /* Transmit/receive frame descriptor */
156 typedef struct FrameDescriptor
{
163 /* Frame descriptor flags */
165 DESC_STATUS_CTL
= (1 << 31),
166 DESC_STATUS2_BUF_SIZE_MASK
= (0x7ff),
169 /* Transmit frame descriptor flags */
171 TX_DESC_STATUS_LENGTH_ERR
= (1 << 14),
172 TX_DESC_STATUS2_FIRST_DESC
= (1 << 29),
173 TX_DESC_STATUS2_LAST_DESC
= (1 << 30),
174 TX_DESC_STATUS2_CHECKSUM_MASK
= (0x3 << 27),
177 /* Receive frame descriptor flags */
179 RX_DESC_STATUS_FIRST_DESC
= (1 << 9),
180 RX_DESC_STATUS_LAST_DESC
= (1 << 8),
181 RX_DESC_STATUS_FRM_LEN_MASK
= (0x3fff0000),
182 RX_DESC_STATUS_FRM_LEN_SHIFT
= (16),
183 RX_DESC_STATUS_NO_BUF
= (1 << 14),
184 RX_DESC_STATUS_HEADER_ERR
= (1 << 7),
185 RX_DESC_STATUS_LENGTH_ERR
= (1 << 4),
186 RX_DESC_STATUS_CRC_ERR
= (1 << 1),
187 RX_DESC_STATUS_PAYLOAD_ERR
= (1 << 0),
188 RX_DESC_STATUS2_RX_INT_CTL
= (1 << 31),
191 /* MII register offsets */
193 MII_REG_CR
= (0x0), /* Control */
194 MII_REG_ST
= (0x1), /* Status */
195 MII_REG_ID_HIGH
= (0x2), /* Identifier High */
196 MII_REG_ID_LOW
= (0x3), /* Identifier Low */
197 MII_REG_ADV
= (0x4), /* Advertised abilities */
198 MII_REG_LPA
= (0x5), /* Link partner abilities */
201 /* MII register flags */
203 MII_REG_CR_RESET
= (1 << 15),
204 MII_REG_CR_POWERDOWN
= (1 << 11),
205 MII_REG_CR_10Mbit
= (0),
206 MII_REG_CR_100Mbit
= (1 << 13),
207 MII_REG_CR_1000Mbit
= (1 << 6),
208 MII_REG_CR_AUTO_NEG
= (1 << 12),
209 MII_REG_CR_AUTO_NEG_RESTART
= (1 << 9),
210 MII_REG_CR_FULLDUPLEX
= (1 << 8),
214 MII_REG_ST_100BASE_T4
= (1 << 15),
215 MII_REG_ST_100BASE_X_FD
= (1 << 14),
216 MII_REG_ST_100BASE_X_HD
= (1 << 13),
217 MII_REG_ST_10_FD
= (1 << 12),
218 MII_REG_ST_10_HD
= (1 << 11),
219 MII_REG_ST_100BASE_T2_FD
= (1 << 10),
220 MII_REG_ST_100BASE_T2_HD
= (1 << 9),
221 MII_REG_ST_AUTONEG_COMPLETE
= (1 << 5),
222 MII_REG_ST_AUTONEG_AVAIL
= (1 << 3),
223 MII_REG_ST_LINK_UP
= (1 << 2),
227 MII_REG_LPA_10_HD
= (1 << 5),
228 MII_REG_LPA_10_FD
= (1 << 6),
229 MII_REG_LPA_100_HD
= (1 << 7),
230 MII_REG_LPA_100_FD
= (1 << 8),
231 MII_REG_LPA_PAUSE
= (1 << 10),
232 MII_REG_LPA_ASYMPAUSE
= (1 << 11),
237 MII_PHY_ID_HIGH
= 0x0044,
238 MII_PHY_ID_LOW
= 0x1400,
241 static void allwinner_sun8i_emac_mii_set_link(AwSun8iEmacState
*s
,
245 s
->mii_st
|= MII_REG_ST_LINK_UP
;
247 s
->mii_st
&= ~MII_REG_ST_LINK_UP
;
251 static void allwinner_sun8i_emac_mii_reset(AwSun8iEmacState
*s
,
254 s
->mii_cr
= MII_REG_CR_100Mbit
| MII_REG_CR_AUTO_NEG
|
255 MII_REG_CR_FULLDUPLEX
;
256 s
->mii_st
= MII_REG_ST_100BASE_T4
| MII_REG_ST_100BASE_X_FD
|
257 MII_REG_ST_100BASE_X_HD
| MII_REG_ST_10_FD
| MII_REG_ST_10_HD
|
258 MII_REG_ST_100BASE_T2_FD
| MII_REG_ST_100BASE_T2_HD
|
259 MII_REG_ST_AUTONEG_COMPLETE
| MII_REG_ST_AUTONEG_AVAIL
;
262 allwinner_sun8i_emac_mii_set_link(s
, link_active
);
265 static void allwinner_sun8i_emac_mii_cmd(AwSun8iEmacState
*s
)
269 addr
= (s
->mii_cmd
& MII_CMD_PHY_ADDR_MASK
) >> MII_CMD_PHY_ADDR_SHIFT
;
270 reg
= (s
->mii_cmd
& MII_CMD_PHY_REG_MASK
) >> MII_CMD_PHY_REG_SHIFT
;
272 if (addr
!= s
->mii_phy_addr
) {
276 /* Read or write a PHY register? */
277 if (s
->mii_cmd
& MII_CMD_PHY_RW
) {
278 trace_allwinner_sun8i_emac_mii_write_reg(reg
, s
->mii_data
);
282 if (s
->mii_data
& MII_REG_CR_RESET
) {
283 allwinner_sun8i_emac_mii_reset(s
, s
->mii_st
&
286 s
->mii_cr
= s
->mii_data
& ~(MII_REG_CR_RESET
|
287 MII_REG_CR_AUTO_NEG_RESTART
);
291 s
->mii_adv
= s
->mii_data
;
293 case MII_REG_ID_HIGH
:
298 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: write access to "
299 "unknown MII register 0x%x\n", reg
);
305 s
->mii_data
= s
->mii_cr
;
308 s
->mii_data
= s
->mii_st
;
310 case MII_REG_ID_HIGH
:
311 s
->mii_data
= MII_PHY_ID_HIGH
;
314 s
->mii_data
= MII_PHY_ID_LOW
;
317 s
->mii_data
= s
->mii_adv
;
320 s
->mii_data
= MII_REG_LPA_10_HD
| MII_REG_LPA_10_FD
|
321 MII_REG_LPA_100_HD
| MII_REG_LPA_100_FD
|
322 MII_REG_LPA_PAUSE
| MII_REG_LPA_ASYMPAUSE
;
325 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: read access to "
326 "unknown MII register 0x%x\n", reg
);
331 trace_allwinner_sun8i_emac_mii_read_reg(reg
, s
->mii_data
);
335 static void allwinner_sun8i_emac_update_irq(AwSun8iEmacState
*s
)
337 qemu_set_irq(s
->irq
, (s
->int_sta
& s
->int_en
) != 0);
340 static uint32_t allwinner_sun8i_emac_next_desc(FrameDescriptor
*desc
,
343 uint32_t paddr
= desc
->next
;
345 cpu_physical_memory_read(paddr
, desc
, sizeof(*desc
));
347 if ((desc
->status
& DESC_STATUS_CTL
) &&
348 (desc
->status2
& DESC_STATUS2_BUF_SIZE_MASK
) >= min_size
) {
355 static uint32_t allwinner_sun8i_emac_get_desc(FrameDescriptor
*desc
,
359 uint32_t desc_addr
= start_addr
;
361 /* Note that the list is a cycle. Last entry points back to the head. */
362 while (desc_addr
!= 0) {
363 cpu_physical_memory_read(desc_addr
, desc
, sizeof(*desc
));
365 if ((desc
->status
& DESC_STATUS_CTL
) &&
366 (desc
->status2
& DESC_STATUS2_BUF_SIZE_MASK
) >= min_size
) {
368 } else if (desc
->next
== start_addr
) {
371 desc_addr
= desc
->next
;
378 static uint32_t allwinner_sun8i_emac_rx_desc(AwSun8iEmacState
*s
,
379 FrameDescriptor
*desc
,
382 return allwinner_sun8i_emac_get_desc(desc
, s
->rx_desc_curr
, min_size
);
385 static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState
*s
,
386 FrameDescriptor
*desc
,
389 return allwinner_sun8i_emac_get_desc(desc
, s
->tx_desc_head
, min_size
);
392 static void allwinner_sun8i_emac_flush_desc(FrameDescriptor
*desc
,
395 cpu_physical_memory_write(phys_addr
, desc
, sizeof(*desc
));
398 static bool allwinner_sun8i_emac_can_receive(NetClientState
*nc
)
400 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
401 FrameDescriptor desc
;
403 return (s
->rx_ctl0
& RX_CTL0_RX_EN
) &&
404 (allwinner_sun8i_emac_rx_desc(s
, &desc
, 0) != 0);
407 static ssize_t
allwinner_sun8i_emac_receive(NetClientState
*nc
,
411 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
412 FrameDescriptor desc
;
413 size_t bytes_left
= size
;
414 size_t desc_bytes
= 0;
415 size_t pad_fcs_size
= 4;
418 if (!(s
->rx_ctl0
& RX_CTL0_RX_EN
)) {
422 s
->rx_desc_curr
= allwinner_sun8i_emac_rx_desc(s
, &desc
,
423 AW_SUN8I_EMAC_MIN_PKT_SZ
);
424 if (!s
->rx_desc_curr
) {
425 s
->int_sta
|= INT_STA_RX_BUF_UA
;
428 /* Keep filling RX descriptors until the whole frame is written */
429 while (s
->rx_desc_curr
&& bytes_left
> 0) {
430 desc
.status
&= ~DESC_STATUS_CTL
;
431 desc
.status
&= ~RX_DESC_STATUS_FRM_LEN_MASK
;
433 if (bytes_left
== size
) {
434 desc
.status
|= RX_DESC_STATUS_FIRST_DESC
;
437 if ((desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
) <
438 (bytes_left
+ pad_fcs_size
)) {
439 desc_bytes
= desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
;
440 desc
.status
|= desc_bytes
<< RX_DESC_STATUS_FRM_LEN_SHIFT
;
442 padding
= pad_fcs_size
;
443 if (bytes_left
< AW_SUN8I_EMAC_MIN_PKT_SZ
) {
444 padding
+= (AW_SUN8I_EMAC_MIN_PKT_SZ
- bytes_left
);
447 desc_bytes
= (bytes_left
);
448 desc
.status
|= RX_DESC_STATUS_LAST_DESC
;
449 desc
.status
|= (bytes_left
+ padding
)
450 << RX_DESC_STATUS_FRM_LEN_SHIFT
;
453 cpu_physical_memory_write(desc
.addr
, buf
, desc_bytes
);
454 allwinner_sun8i_emac_flush_desc(&desc
, s
->rx_desc_curr
);
455 trace_allwinner_sun8i_emac_receive(s
->rx_desc_curr
, desc
.addr
,
458 /* Check if frame needs to raise the receive interrupt */
459 if (!(desc
.status2
& RX_DESC_STATUS2_RX_INT_CTL
)) {
460 s
->int_sta
|= INT_STA_RX
;
463 /* Increment variables */
465 bytes_left
-= desc_bytes
;
467 /* Move to the next descriptor */
468 s
->rx_desc_curr
= allwinner_sun8i_emac_next_desc(&desc
, 64);
469 if (!s
->rx_desc_curr
) {
470 /* Not enough buffer space available */
471 s
->int_sta
|= INT_STA_RX_BUF_UA
;
472 s
->rx_desc_curr
= s
->rx_desc_head
;
477 /* Report receive DMA is finished */
478 s
->rx_ctl1
&= ~RX_CTL1_RX_DMA_START
;
479 allwinner_sun8i_emac_update_irq(s
);
484 static void allwinner_sun8i_emac_transmit(AwSun8iEmacState
*s
)
486 NetClientState
*nc
= qemu_get_queue(s
->nic
);
487 FrameDescriptor desc
;
489 size_t packet_bytes
= 0;
490 size_t transmitted
= 0;
491 static uint8_t packet_buf
[2048];
493 s
->tx_desc_curr
= allwinner_sun8i_emac_tx_desc(s
, &desc
, 0);
495 /* Read all transmit descriptors */
496 while (s
->tx_desc_curr
!= 0) {
498 /* Read from physical memory into packet buffer */
499 bytes
= desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
;
500 if (bytes
+ packet_bytes
> sizeof(packet_buf
)) {
501 desc
.status
|= TX_DESC_STATUS_LENGTH_ERR
;
504 cpu_physical_memory_read(desc
.addr
, packet_buf
+ packet_bytes
, bytes
);
505 packet_bytes
+= bytes
;
506 desc
.status
&= ~DESC_STATUS_CTL
;
507 allwinner_sun8i_emac_flush_desc(&desc
, s
->tx_desc_curr
);
509 /* After the last descriptor, send the packet */
510 if (desc
.status2
& TX_DESC_STATUS2_LAST_DESC
) {
511 if (desc
.status2
& TX_DESC_STATUS2_CHECKSUM_MASK
) {
512 net_checksum_calculate(packet_buf
, packet_bytes
);
515 qemu_send_packet(nc
, packet_buf
, packet_bytes
);
516 trace_allwinner_sun8i_emac_transmit(s
->tx_desc_curr
, desc
.addr
,
522 s
->tx_desc_curr
= allwinner_sun8i_emac_next_desc(&desc
, 0);
525 /* Raise transmit completed interrupt */
526 if (transmitted
> 0) {
527 s
->int_sta
|= INT_STA_TX
;
528 s
->tx_ctl1
&= ~TX_CTL1_TX_DMA_START
;
529 allwinner_sun8i_emac_update_irq(s
);
533 static void allwinner_sun8i_emac_reset(DeviceState
*dev
)
535 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(dev
);
536 NetClientState
*nc
= qemu_get_queue(s
->nic
);
538 trace_allwinner_sun8i_emac_reset();
543 s
->basic_ctl1
= REG_BASIC_CTL_1_RST
;
548 s
->rx_ctl1
= RX_CTL1_RX_MD
;
557 allwinner_sun8i_emac_mii_reset(s
, !nc
->link_down
);
560 static uint64_t allwinner_sun8i_emac_read(void *opaque
, hwaddr offset
,
563 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(opaque
);
565 FrameDescriptor desc
;
568 case REG_BASIC_CTL_0
: /* Basic Control 0 */
569 value
= s
->basic_ctl0
;
571 case REG_BASIC_CTL_1
: /* Basic Control 1 */
572 value
= s
->basic_ctl1
;
574 case REG_INT_STA
: /* Interrupt Status */
577 case REG_INT_EN
: /* Interupt Enable */
580 case REG_TX_CTL_0
: /* Transmit Control 0 */
583 case REG_TX_CTL_1
: /* Transmit Control 1 */
586 case REG_TX_FLOW_CTL
: /* Transmit Flow Control */
587 value
= s
->tx_flowctl
;
589 case REG_TX_DMA_DESC_LIST
: /* Transmit Descriptor List Address */
590 value
= s
->tx_desc_head
;
592 case REG_RX_CTL_0
: /* Receive Control 0 */
595 case REG_RX_CTL_1
: /* Receive Control 1 */
598 case REG_RX_DMA_DESC_LIST
: /* Receive Descriptor List Address */
599 value
= s
->rx_desc_head
;
601 case REG_FRM_FLT
: /* Receive Frame Filter */
604 case REG_RX_HASH_0
: /* Receive Hash Table 0 */
605 case REG_RX_HASH_1
: /* Receive Hash Table 1 */
607 case REG_MII_CMD
: /* Management Interface Command */
610 case REG_MII_DATA
: /* Management Interface Data */
613 case REG_ADDR_HIGH
: /* MAC Address High */
614 value
= lduw_le_p(s
->conf
.macaddr
.a
+ 4);
616 case REG_ADDR_LOW
: /* MAC Address Low */
617 value
= ldl_le_p(s
->conf
.macaddr
.a
);
619 case REG_TX_DMA_STA
: /* Transmit DMA Status */
621 case REG_TX_CUR_DESC
: /* Transmit Current Descriptor */
622 value
= s
->tx_desc_curr
;
624 case REG_TX_CUR_BUF
: /* Transmit Current Buffer */
625 if (s
->tx_desc_curr
!= 0) {
626 cpu_physical_memory_read(s
->tx_desc_curr
, &desc
, sizeof(desc
));
632 case REG_RX_DMA_STA
: /* Receive DMA Status */
634 case REG_RX_CUR_DESC
: /* Receive Current Descriptor */
635 value
= s
->rx_desc_curr
;
637 case REG_RX_CUR_BUF
: /* Receive Current Buffer */
638 if (s
->rx_desc_curr
!= 0) {
639 cpu_physical_memory_read(s
->rx_desc_curr
, &desc
, sizeof(desc
));
645 case REG_RGMII_STA
: /* RGMII Status */
648 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: read access to unknown "
649 "EMAC register 0x" TARGET_FMT_plx
"\n",
653 trace_allwinner_sun8i_emac_read(offset
, value
);
657 static void allwinner_sun8i_emac_write(void *opaque
, hwaddr offset
,
658 uint64_t value
, unsigned size
)
660 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(opaque
);
661 NetClientState
*nc
= qemu_get_queue(s
->nic
);
663 trace_allwinner_sun8i_emac_write(offset
, value
);
666 case REG_BASIC_CTL_0
: /* Basic Control 0 */
667 s
->basic_ctl0
= value
;
669 case REG_BASIC_CTL_1
: /* Basic Control 1 */
670 if (value
& BASIC_CTL1_SOFTRST
) {
671 allwinner_sun8i_emac_reset(DEVICE(s
));
672 value
&= ~BASIC_CTL1_SOFTRST
;
674 s
->basic_ctl1
= value
;
675 if (allwinner_sun8i_emac_can_receive(nc
)) {
676 qemu_flush_queued_packets(nc
);
679 case REG_INT_STA
: /* Interrupt Status */
680 s
->int_sta
&= ~value
;
681 allwinner_sun8i_emac_update_irq(s
);
683 case REG_INT_EN
: /* Interrupt Enable */
685 allwinner_sun8i_emac_update_irq(s
);
687 case REG_TX_CTL_0
: /* Transmit Control 0 */
690 case REG_TX_CTL_1
: /* Transmit Control 1 */
692 if (value
& TX_CTL1_TX_DMA_EN
) {
693 allwinner_sun8i_emac_transmit(s
);
696 case REG_TX_FLOW_CTL
: /* Transmit Flow Control */
697 s
->tx_flowctl
= value
;
699 case REG_TX_DMA_DESC_LIST
: /* Transmit Descriptor List Address */
700 s
->tx_desc_head
= value
;
701 s
->tx_desc_curr
= value
;
703 case REG_RX_CTL_0
: /* Receive Control 0 */
706 case REG_RX_CTL_1
: /* Receive Control 1 */
707 s
->rx_ctl1
= value
| RX_CTL1_RX_MD
;
708 if ((value
& RX_CTL1_RX_DMA_EN
) &&
709 allwinner_sun8i_emac_can_receive(nc
)) {
710 qemu_flush_queued_packets(nc
);
713 case REG_RX_DMA_DESC_LIST
: /* Receive Descriptor List Address */
714 s
->rx_desc_head
= value
;
715 s
->rx_desc_curr
= value
;
717 case REG_FRM_FLT
: /* Receive Frame Filter */
720 case REG_RX_HASH_0
: /* Receive Hash Table 0 */
721 case REG_RX_HASH_1
: /* Receive Hash Table 1 */
723 case REG_MII_CMD
: /* Management Interface Command */
724 s
->mii_cmd
= value
& ~MII_CMD_PHY_BUSY
;
725 allwinner_sun8i_emac_mii_cmd(s
);
727 case REG_MII_DATA
: /* Management Interface Data */
730 case REG_ADDR_HIGH
: /* MAC Address High */
731 stw_le_p(s
->conf
.macaddr
.a
+ 4, value
);
733 case REG_ADDR_LOW
: /* MAC Address Low */
734 stl_le_p(s
->conf
.macaddr
.a
, value
);
736 case REG_TX_DMA_STA
: /* Transmit DMA Status */
737 case REG_TX_CUR_DESC
: /* Transmit Current Descriptor */
738 case REG_TX_CUR_BUF
: /* Transmit Current Buffer */
739 case REG_RX_DMA_STA
: /* Receive DMA Status */
740 case REG_RX_CUR_DESC
: /* Receive Current Descriptor */
741 case REG_RX_CUR_BUF
: /* Receive Current Buffer */
742 case REG_RGMII_STA
: /* RGMII Status */
745 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: write access to unknown "
746 "EMAC register 0x" TARGET_FMT_plx
"\n",
751 static void allwinner_sun8i_emac_set_link(NetClientState
*nc
)
753 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
755 trace_allwinner_sun8i_emac_set_link(!nc
->link_down
);
756 allwinner_sun8i_emac_mii_set_link(s
, !nc
->link_down
);
759 static const MemoryRegionOps allwinner_sun8i_emac_mem_ops
= {
760 .read
= allwinner_sun8i_emac_read
,
761 .write
= allwinner_sun8i_emac_write
,
762 .endianness
= DEVICE_NATIVE_ENDIAN
,
764 .min_access_size
= 4,
765 .max_access_size
= 4,
767 .impl
.min_access_size
= 4,
770 static NetClientInfo net_allwinner_sun8i_emac_info
= {
771 .type
= NET_CLIENT_DRIVER_NIC
,
772 .size
= sizeof(NICState
),
773 .can_receive
= allwinner_sun8i_emac_can_receive
,
774 .receive
= allwinner_sun8i_emac_receive
,
775 .link_status_changed
= allwinner_sun8i_emac_set_link
,
778 static void allwinner_sun8i_emac_init(Object
*obj
)
780 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
781 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(obj
);
783 memory_region_init_io(&s
->iomem
, OBJECT(s
), &allwinner_sun8i_emac_mem_ops
,
784 s
, TYPE_AW_SUN8I_EMAC
, 64 * KiB
);
785 sysbus_init_mmio(sbd
, &s
->iomem
);
786 sysbus_init_irq(sbd
, &s
->irq
);
789 static void allwinner_sun8i_emac_realize(DeviceState
*dev
, Error
**errp
)
791 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(dev
);
793 qemu_macaddr_default_if_unset(&s
->conf
.macaddr
);
794 s
->nic
= qemu_new_nic(&net_allwinner_sun8i_emac_info
, &s
->conf
,
795 object_get_typename(OBJECT(dev
)), dev
->id
, s
);
796 qemu_format_nic_info_str(qemu_get_queue(s
->nic
), s
->conf
.macaddr
.a
);
799 static Property allwinner_sun8i_emac_properties
[] = {
800 DEFINE_NIC_PROPERTIES(AwSun8iEmacState
, conf
),
801 DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState
, mii_phy_addr
, 0),
802 DEFINE_PROP_END_OF_LIST(),
805 static int allwinner_sun8i_emac_post_load(void *opaque
, int version_id
)
807 AwSun8iEmacState
*s
= opaque
;
809 allwinner_sun8i_emac_set_link(qemu_get_queue(s
->nic
));
814 static const VMStateDescription vmstate_aw_emac
= {
815 .name
= "allwinner-sun8i-emac",
817 .minimum_version_id
= 1,
818 .post_load
= allwinner_sun8i_emac_post_load
,
819 .fields
= (VMStateField
[]) {
820 VMSTATE_UINT8(mii_phy_addr
, AwSun8iEmacState
),
821 VMSTATE_UINT32(mii_cmd
, AwSun8iEmacState
),
822 VMSTATE_UINT32(mii_data
, AwSun8iEmacState
),
823 VMSTATE_UINT32(mii_cr
, AwSun8iEmacState
),
824 VMSTATE_UINT32(mii_st
, AwSun8iEmacState
),
825 VMSTATE_UINT32(mii_adv
, AwSun8iEmacState
),
826 VMSTATE_UINT32(basic_ctl0
, AwSun8iEmacState
),
827 VMSTATE_UINT32(basic_ctl1
, AwSun8iEmacState
),
828 VMSTATE_UINT32(int_en
, AwSun8iEmacState
),
829 VMSTATE_UINT32(int_sta
, AwSun8iEmacState
),
830 VMSTATE_UINT32(frm_flt
, AwSun8iEmacState
),
831 VMSTATE_UINT32(rx_ctl0
, AwSun8iEmacState
),
832 VMSTATE_UINT32(rx_ctl1
, AwSun8iEmacState
),
833 VMSTATE_UINT32(rx_desc_head
, AwSun8iEmacState
),
834 VMSTATE_UINT32(rx_desc_curr
, AwSun8iEmacState
),
835 VMSTATE_UINT32(tx_ctl0
, AwSun8iEmacState
),
836 VMSTATE_UINT32(tx_ctl1
, AwSun8iEmacState
),
837 VMSTATE_UINT32(tx_desc_head
, AwSun8iEmacState
),
838 VMSTATE_UINT32(tx_desc_curr
, AwSun8iEmacState
),
839 VMSTATE_UINT32(tx_flowctl
, AwSun8iEmacState
),
840 VMSTATE_END_OF_LIST()
844 static void allwinner_sun8i_emac_class_init(ObjectClass
*klass
, void *data
)
846 DeviceClass
*dc
= DEVICE_CLASS(klass
);
848 dc
->realize
= allwinner_sun8i_emac_realize
;
849 dc
->reset
= allwinner_sun8i_emac_reset
;
850 dc
->vmsd
= &vmstate_aw_emac
;
851 device_class_set_props(dc
, allwinner_sun8i_emac_properties
);
854 static const TypeInfo allwinner_sun8i_emac_info
= {
855 .name
= TYPE_AW_SUN8I_EMAC
,
856 .parent
= TYPE_SYS_BUS_DEVICE
,
857 .instance_size
= sizeof(AwSun8iEmacState
),
858 .instance_init
= allwinner_sun8i_emac_init
,
859 .class_init
= allwinner_sun8i_emac_class_init
,
862 static void allwinner_sun8i_emac_register_types(void)
864 type_register_static(&allwinner_sun8i_emac_info
);
867 type_init(allwinner_sun8i_emac_register_types
)