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 "qapi/error.h"
23 #include "hw/sysbus.h"
24 #include "migration/vmstate.h"
27 #include "hw/qdev-properties.h"
30 #include "net/checksum.h"
31 #include "qemu/module.h"
32 #include "exec/cpu-common.h"
33 #include "sysemu/dma.h"
34 #include "hw/net/allwinner-sun8i-emac.h"
36 /* EMAC register offsets */
38 REG_BASIC_CTL_0
= 0x0000, /* Basic Control 0 */
39 REG_BASIC_CTL_1
= 0x0004, /* Basic Control 1 */
40 REG_INT_STA
= 0x0008, /* Interrupt Status */
41 REG_INT_EN
= 0x000C, /* Interrupt Enable */
42 REG_TX_CTL_0
= 0x0010, /* Transmit Control 0 */
43 REG_TX_CTL_1
= 0x0014, /* Transmit Control 1 */
44 REG_TX_FLOW_CTL
= 0x001C, /* Transmit Flow Control */
45 REG_TX_DMA_DESC_LIST
= 0x0020, /* Transmit Descriptor List Address */
46 REG_RX_CTL_0
= 0x0024, /* Receive Control 0 */
47 REG_RX_CTL_1
= 0x0028, /* Receive Control 1 */
48 REG_RX_DMA_DESC_LIST
= 0x0034, /* Receive Descriptor List Address */
49 REG_FRM_FLT
= 0x0038, /* Receive Frame Filter */
50 REG_RX_HASH_0
= 0x0040, /* Receive Hash Table 0 */
51 REG_RX_HASH_1
= 0x0044, /* Receive Hash Table 1 */
52 REG_MII_CMD
= 0x0048, /* Management Interface Command */
53 REG_MII_DATA
= 0x004C, /* Management Interface Data */
54 REG_ADDR_HIGH
= 0x0050, /* MAC Address High */
55 REG_ADDR_LOW
= 0x0054, /* MAC Address Low */
56 REG_TX_DMA_STA
= 0x00B0, /* Transmit DMA Status */
57 REG_TX_CUR_DESC
= 0x00B4, /* Transmit Current Descriptor */
58 REG_TX_CUR_BUF
= 0x00B8, /* Transmit Current Buffer */
59 REG_RX_DMA_STA
= 0x00C0, /* Receive DMA Status */
60 REG_RX_CUR_DESC
= 0x00C4, /* Receive Current Descriptor */
61 REG_RX_CUR_BUF
= 0x00C8, /* Receive Current Buffer */
62 REG_RGMII_STA
= 0x00D0, /* RGMII Status */
65 /* EMAC register flags */
67 BASIC_CTL0_100Mbps
= (0b11 << 2),
68 BASIC_CTL0_FD
= (1 << 0),
69 BASIC_CTL1_SOFTRST
= (1 << 0),
73 INT_STA_RGMII_LINK
= (1 << 16),
74 INT_STA_RX_EARLY
= (1 << 13),
75 INT_STA_RX_OVERFLOW
= (1 << 12),
76 INT_STA_RX_TIMEOUT
= (1 << 11),
77 INT_STA_RX_DMA_STOP
= (1 << 10),
78 INT_STA_RX_BUF_UA
= (1 << 9),
79 INT_STA_RX
= (1 << 8),
80 INT_STA_TX_EARLY
= (1 << 5),
81 INT_STA_TX_UNDERFLOW
= (1 << 4),
82 INT_STA_TX_TIMEOUT
= (1 << 3),
83 INT_STA_TX_BUF_UA
= (1 << 2),
84 INT_STA_TX_DMA_STOP
= (1 << 1),
85 INT_STA_TX
= (1 << 0),
89 INT_EN_RX_EARLY
= (1 << 13),
90 INT_EN_RX_OVERFLOW
= (1 << 12),
91 INT_EN_RX_TIMEOUT
= (1 << 11),
92 INT_EN_RX_DMA_STOP
= (1 << 10),
93 INT_EN_RX_BUF_UA
= (1 << 9),
95 INT_EN_TX_EARLY
= (1 << 5),
96 INT_EN_TX_UNDERFLOW
= (1 << 4),
97 INT_EN_TX_TIMEOUT
= (1 << 3),
98 INT_EN_TX_BUF_UA
= (1 << 2),
99 INT_EN_TX_DMA_STOP
= (1 << 1),
100 INT_EN_TX
= (1 << 0),
104 TX_CTL0_TX_EN
= (1 << 31),
105 TX_CTL1_TX_DMA_START
= (1 << 31),
106 TX_CTL1_TX_DMA_EN
= (1 << 30),
107 TX_CTL1_TX_FLUSH
= (1 << 0),
111 RX_CTL0_RX_EN
= (1 << 31),
112 RX_CTL0_STRIP_FCS
= (1 << 28),
113 RX_CTL0_CRC_IPV4
= (1 << 27),
117 RX_CTL1_RX_DMA_START
= (1 << 31),
118 RX_CTL1_RX_DMA_EN
= (1 << 30),
119 RX_CTL1_RX_MD
= (1 << 1),
123 RX_FRM_FLT_DIS_ADDR
= (1 << 31),
127 MII_CMD_PHY_ADDR_SHIFT
= (12),
128 MII_CMD_PHY_ADDR_MASK
= (0xf000),
129 MII_CMD_PHY_REG_SHIFT
= (4),
130 MII_CMD_PHY_REG_MASK
= (0xf0),
131 MII_CMD_PHY_RW
= (1 << 1),
132 MII_CMD_PHY_BUSY
= (1 << 0),
136 TX_DMA_STA_STOP
= (0b000),
137 TX_DMA_STA_RUN_FETCH
= (0b001),
138 TX_DMA_STA_WAIT_STA
= (0b010),
142 RX_DMA_STA_STOP
= (0b000),
143 RX_DMA_STA_RUN_FETCH
= (0b001),
144 RX_DMA_STA_WAIT_FRM
= (0b011),
147 /* EMAC register reset values */
149 REG_BASIC_CTL_1_RST
= 0x08000000,
154 AW_SUN8I_EMAC_MIN_PKT_SZ
= 64
157 /* Transmit/receive frame descriptor */
158 typedef struct FrameDescriptor
{
165 /* Frame descriptor flags */
167 DESC_STATUS_CTL
= (1 << 31),
168 DESC_STATUS2_BUF_SIZE_MASK
= (0x7ff),
171 /* Transmit frame descriptor flags */
173 TX_DESC_STATUS_LENGTH_ERR
= (1 << 14),
174 TX_DESC_STATUS2_FIRST_DESC
= (1 << 29),
175 TX_DESC_STATUS2_LAST_DESC
= (1 << 30),
176 TX_DESC_STATUS2_CHECKSUM_MASK
= (0x3 << 27),
179 /* Receive frame descriptor flags */
181 RX_DESC_STATUS_FIRST_DESC
= (1 << 9),
182 RX_DESC_STATUS_LAST_DESC
= (1 << 8),
183 RX_DESC_STATUS_FRM_LEN_MASK
= (0x3fff0000),
184 RX_DESC_STATUS_FRM_LEN_SHIFT
= (16),
185 RX_DESC_STATUS_NO_BUF
= (1 << 14),
186 RX_DESC_STATUS_HEADER_ERR
= (1 << 7),
187 RX_DESC_STATUS_LENGTH_ERR
= (1 << 4),
188 RX_DESC_STATUS_CRC_ERR
= (1 << 1),
189 RX_DESC_STATUS_PAYLOAD_ERR
= (1 << 0),
190 RX_DESC_STATUS2_RX_INT_CTL
= (1 << 31),
193 /* MII register offsets */
195 MII_REG_CR
= (0x0), /* Control */
196 MII_REG_ST
= (0x1), /* Status */
197 MII_REG_ID_HIGH
= (0x2), /* Identifier High */
198 MII_REG_ID_LOW
= (0x3), /* Identifier Low */
199 MII_REG_ADV
= (0x4), /* Advertised abilities */
200 MII_REG_LPA
= (0x5), /* Link partner abilities */
203 /* MII register flags */
205 MII_REG_CR_RESET
= (1 << 15),
206 MII_REG_CR_POWERDOWN
= (1 << 11),
207 MII_REG_CR_10Mbit
= (0),
208 MII_REG_CR_100Mbit
= (1 << 13),
209 MII_REG_CR_1000Mbit
= (1 << 6),
210 MII_REG_CR_AUTO_NEG
= (1 << 12),
211 MII_REG_CR_AUTO_NEG_RESTART
= (1 << 9),
212 MII_REG_CR_FULLDUPLEX
= (1 << 8),
216 MII_REG_ST_100BASE_T4
= (1 << 15),
217 MII_REG_ST_100BASE_X_FD
= (1 << 14),
218 MII_REG_ST_100BASE_X_HD
= (1 << 13),
219 MII_REG_ST_10_FD
= (1 << 12),
220 MII_REG_ST_10_HD
= (1 << 11),
221 MII_REG_ST_100BASE_T2_FD
= (1 << 10),
222 MII_REG_ST_100BASE_T2_HD
= (1 << 9),
223 MII_REG_ST_AUTONEG_COMPLETE
= (1 << 5),
224 MII_REG_ST_AUTONEG_AVAIL
= (1 << 3),
225 MII_REG_ST_LINK_UP
= (1 << 2),
229 MII_REG_LPA_10_HD
= (1 << 5),
230 MII_REG_LPA_10_FD
= (1 << 6),
231 MII_REG_LPA_100_HD
= (1 << 7),
232 MII_REG_LPA_100_FD
= (1 << 8),
233 MII_REG_LPA_PAUSE
= (1 << 10),
234 MII_REG_LPA_ASYMPAUSE
= (1 << 11),
239 MII_PHY_ID_HIGH
= 0x0044,
240 MII_PHY_ID_LOW
= 0x1400,
243 static void allwinner_sun8i_emac_mii_set_link(AwSun8iEmacState
*s
,
247 s
->mii_st
|= MII_REG_ST_LINK_UP
;
249 s
->mii_st
&= ~MII_REG_ST_LINK_UP
;
253 static void allwinner_sun8i_emac_mii_reset(AwSun8iEmacState
*s
,
256 s
->mii_cr
= MII_REG_CR_100Mbit
| MII_REG_CR_AUTO_NEG
|
257 MII_REG_CR_FULLDUPLEX
;
258 s
->mii_st
= MII_REG_ST_100BASE_T4
| MII_REG_ST_100BASE_X_FD
|
259 MII_REG_ST_100BASE_X_HD
| MII_REG_ST_10_FD
| MII_REG_ST_10_HD
|
260 MII_REG_ST_100BASE_T2_FD
| MII_REG_ST_100BASE_T2_HD
|
261 MII_REG_ST_AUTONEG_COMPLETE
| MII_REG_ST_AUTONEG_AVAIL
;
264 allwinner_sun8i_emac_mii_set_link(s
, link_active
);
267 static void allwinner_sun8i_emac_mii_cmd(AwSun8iEmacState
*s
)
271 addr
= (s
->mii_cmd
& MII_CMD_PHY_ADDR_MASK
) >> MII_CMD_PHY_ADDR_SHIFT
;
272 reg
= (s
->mii_cmd
& MII_CMD_PHY_REG_MASK
) >> MII_CMD_PHY_REG_SHIFT
;
274 if (addr
!= s
->mii_phy_addr
) {
278 /* Read or write a PHY register? */
279 if (s
->mii_cmd
& MII_CMD_PHY_RW
) {
280 trace_allwinner_sun8i_emac_mii_write_reg(reg
, s
->mii_data
);
284 if (s
->mii_data
& MII_REG_CR_RESET
) {
285 allwinner_sun8i_emac_mii_reset(s
, s
->mii_st
&
288 s
->mii_cr
= s
->mii_data
& ~(MII_REG_CR_RESET
|
289 MII_REG_CR_AUTO_NEG_RESTART
);
293 s
->mii_adv
= s
->mii_data
;
295 case MII_REG_ID_HIGH
:
300 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: write access to "
301 "unknown MII register 0x%x\n", reg
);
307 s
->mii_data
= s
->mii_cr
;
310 s
->mii_data
= s
->mii_st
;
312 case MII_REG_ID_HIGH
:
313 s
->mii_data
= MII_PHY_ID_HIGH
;
316 s
->mii_data
= MII_PHY_ID_LOW
;
319 s
->mii_data
= s
->mii_adv
;
322 s
->mii_data
= MII_REG_LPA_10_HD
| MII_REG_LPA_10_FD
|
323 MII_REG_LPA_100_HD
| MII_REG_LPA_100_FD
|
324 MII_REG_LPA_PAUSE
| MII_REG_LPA_ASYMPAUSE
;
327 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: read access to "
328 "unknown MII register 0x%x\n", reg
);
333 trace_allwinner_sun8i_emac_mii_read_reg(reg
, s
->mii_data
);
337 static void allwinner_sun8i_emac_update_irq(AwSun8iEmacState
*s
)
339 qemu_set_irq(s
->irq
, (s
->int_sta
& s
->int_en
) != 0);
342 static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState
*s
,
343 FrameDescriptor
*desc
,
346 uint32_t paddr
= desc
->next
;
348 dma_memory_read(&s
->dma_as
, paddr
, desc
, sizeof(*desc
));
350 if ((desc
->status
& DESC_STATUS_CTL
) &&
351 (desc
->status2
& DESC_STATUS2_BUF_SIZE_MASK
) >= min_size
) {
358 static uint32_t allwinner_sun8i_emac_get_desc(AwSun8iEmacState
*s
,
359 FrameDescriptor
*desc
,
363 uint32_t desc_addr
= start_addr
;
365 /* Note that the list is a cycle. Last entry points back to the head. */
366 while (desc_addr
!= 0) {
367 dma_memory_read(&s
->dma_as
, desc_addr
, desc
, sizeof(*desc
));
369 if ((desc
->status
& DESC_STATUS_CTL
) &&
370 (desc
->status2
& DESC_STATUS2_BUF_SIZE_MASK
) >= min_size
) {
372 } else if (desc
->next
== start_addr
) {
375 desc_addr
= desc
->next
;
382 static uint32_t allwinner_sun8i_emac_rx_desc(AwSun8iEmacState
*s
,
383 FrameDescriptor
*desc
,
386 return allwinner_sun8i_emac_get_desc(s
, desc
, s
->rx_desc_curr
, min_size
);
389 static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState
*s
,
390 FrameDescriptor
*desc
,
393 return allwinner_sun8i_emac_get_desc(s
, desc
, s
->tx_desc_head
, min_size
);
396 static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState
*s
,
397 FrameDescriptor
*desc
,
400 dma_memory_write(&s
->dma_as
, phys_addr
, desc
, sizeof(*desc
));
403 static bool allwinner_sun8i_emac_can_receive(NetClientState
*nc
)
405 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
406 FrameDescriptor desc
;
408 return (s
->rx_ctl0
& RX_CTL0_RX_EN
) &&
409 (allwinner_sun8i_emac_rx_desc(s
, &desc
, 0) != 0);
412 static ssize_t
allwinner_sun8i_emac_receive(NetClientState
*nc
,
416 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
417 FrameDescriptor desc
;
418 size_t bytes_left
= size
;
419 size_t desc_bytes
= 0;
420 size_t pad_fcs_size
= 4;
423 if (!(s
->rx_ctl0
& RX_CTL0_RX_EN
)) {
427 s
->rx_desc_curr
= allwinner_sun8i_emac_rx_desc(s
, &desc
,
428 AW_SUN8I_EMAC_MIN_PKT_SZ
);
429 if (!s
->rx_desc_curr
) {
430 s
->int_sta
|= INT_STA_RX_BUF_UA
;
433 /* Keep filling RX descriptors until the whole frame is written */
434 while (s
->rx_desc_curr
&& bytes_left
> 0) {
435 desc
.status
&= ~DESC_STATUS_CTL
;
436 desc
.status
&= ~RX_DESC_STATUS_FRM_LEN_MASK
;
438 if (bytes_left
== size
) {
439 desc
.status
|= RX_DESC_STATUS_FIRST_DESC
;
442 if ((desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
) <
443 (bytes_left
+ pad_fcs_size
)) {
444 desc_bytes
= desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
;
445 desc
.status
|= desc_bytes
<< RX_DESC_STATUS_FRM_LEN_SHIFT
;
447 padding
= pad_fcs_size
;
448 if (bytes_left
< AW_SUN8I_EMAC_MIN_PKT_SZ
) {
449 padding
+= (AW_SUN8I_EMAC_MIN_PKT_SZ
- bytes_left
);
452 desc_bytes
= (bytes_left
);
453 desc
.status
|= RX_DESC_STATUS_LAST_DESC
;
454 desc
.status
|= (bytes_left
+ padding
)
455 << RX_DESC_STATUS_FRM_LEN_SHIFT
;
458 dma_memory_write(&s
->dma_as
, desc
.addr
, buf
, desc_bytes
);
459 allwinner_sun8i_emac_flush_desc(s
, &desc
, s
->rx_desc_curr
);
460 trace_allwinner_sun8i_emac_receive(s
->rx_desc_curr
, desc
.addr
,
463 /* Check if frame needs to raise the receive interrupt */
464 if (!(desc
.status2
& RX_DESC_STATUS2_RX_INT_CTL
)) {
465 s
->int_sta
|= INT_STA_RX
;
468 /* Increment variables */
470 bytes_left
-= desc_bytes
;
472 /* Move to the next descriptor */
473 s
->rx_desc_curr
= allwinner_sun8i_emac_next_desc(s
, &desc
, 64);
474 if (!s
->rx_desc_curr
) {
475 /* Not enough buffer space available */
476 s
->int_sta
|= INT_STA_RX_BUF_UA
;
477 s
->rx_desc_curr
= s
->rx_desc_head
;
482 /* Report receive DMA is finished */
483 s
->rx_ctl1
&= ~RX_CTL1_RX_DMA_START
;
484 allwinner_sun8i_emac_update_irq(s
);
489 static void allwinner_sun8i_emac_transmit(AwSun8iEmacState
*s
)
491 NetClientState
*nc
= qemu_get_queue(s
->nic
);
492 FrameDescriptor desc
;
494 size_t packet_bytes
= 0;
495 size_t transmitted
= 0;
496 static uint8_t packet_buf
[2048];
498 s
->tx_desc_curr
= allwinner_sun8i_emac_tx_desc(s
, &desc
, 0);
500 /* Read all transmit descriptors */
501 while (s
->tx_desc_curr
!= 0) {
503 /* Read from physical memory into packet buffer */
504 bytes
= desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
;
505 if (bytes
+ packet_bytes
> sizeof(packet_buf
)) {
506 desc
.status
|= TX_DESC_STATUS_LENGTH_ERR
;
509 dma_memory_read(&s
->dma_as
, desc
.addr
, packet_buf
+ packet_bytes
, bytes
);
510 packet_bytes
+= bytes
;
511 desc
.status
&= ~DESC_STATUS_CTL
;
512 allwinner_sun8i_emac_flush_desc(s
, &desc
, s
->tx_desc_curr
);
514 /* After the last descriptor, send the packet */
515 if (desc
.status2
& TX_DESC_STATUS2_LAST_DESC
) {
516 if (desc
.status2
& TX_DESC_STATUS2_CHECKSUM_MASK
) {
517 net_checksum_calculate(packet_buf
, packet_bytes
);
520 qemu_send_packet(nc
, packet_buf
, packet_bytes
);
521 trace_allwinner_sun8i_emac_transmit(s
->tx_desc_curr
, desc
.addr
,
527 s
->tx_desc_curr
= allwinner_sun8i_emac_next_desc(s
, &desc
, 0);
530 /* Raise transmit completed interrupt */
531 if (transmitted
> 0) {
532 s
->int_sta
|= INT_STA_TX
;
533 s
->tx_ctl1
&= ~TX_CTL1_TX_DMA_START
;
534 allwinner_sun8i_emac_update_irq(s
);
538 static void allwinner_sun8i_emac_reset(DeviceState
*dev
)
540 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(dev
);
541 NetClientState
*nc
= qemu_get_queue(s
->nic
);
543 trace_allwinner_sun8i_emac_reset();
548 s
->basic_ctl1
= REG_BASIC_CTL_1_RST
;
553 s
->rx_ctl1
= RX_CTL1_RX_MD
;
562 allwinner_sun8i_emac_mii_reset(s
, !nc
->link_down
);
565 static uint64_t allwinner_sun8i_emac_read(void *opaque
, hwaddr offset
,
568 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(opaque
);
570 FrameDescriptor desc
;
573 case REG_BASIC_CTL_0
: /* Basic Control 0 */
574 value
= s
->basic_ctl0
;
576 case REG_BASIC_CTL_1
: /* Basic Control 1 */
577 value
= s
->basic_ctl1
;
579 case REG_INT_STA
: /* Interrupt Status */
582 case REG_INT_EN
: /* Interupt Enable */
585 case REG_TX_CTL_0
: /* Transmit Control 0 */
588 case REG_TX_CTL_1
: /* Transmit Control 1 */
591 case REG_TX_FLOW_CTL
: /* Transmit Flow Control */
592 value
= s
->tx_flowctl
;
594 case REG_TX_DMA_DESC_LIST
: /* Transmit Descriptor List Address */
595 value
= s
->tx_desc_head
;
597 case REG_RX_CTL_0
: /* Receive Control 0 */
600 case REG_RX_CTL_1
: /* Receive Control 1 */
603 case REG_RX_DMA_DESC_LIST
: /* Receive Descriptor List Address */
604 value
= s
->rx_desc_head
;
606 case REG_FRM_FLT
: /* Receive Frame Filter */
609 case REG_RX_HASH_0
: /* Receive Hash Table 0 */
610 case REG_RX_HASH_1
: /* Receive Hash Table 1 */
612 case REG_MII_CMD
: /* Management Interface Command */
615 case REG_MII_DATA
: /* Management Interface Data */
618 case REG_ADDR_HIGH
: /* MAC Address High */
619 value
= lduw_le_p(s
->conf
.macaddr
.a
+ 4);
621 case REG_ADDR_LOW
: /* MAC Address Low */
622 value
= ldl_le_p(s
->conf
.macaddr
.a
);
624 case REG_TX_DMA_STA
: /* Transmit DMA Status */
626 case REG_TX_CUR_DESC
: /* Transmit Current Descriptor */
627 value
= s
->tx_desc_curr
;
629 case REG_TX_CUR_BUF
: /* Transmit Current Buffer */
630 if (s
->tx_desc_curr
!= 0) {
631 dma_memory_read(&s
->dma_as
, s
->tx_desc_curr
, &desc
, sizeof(desc
));
637 case REG_RX_DMA_STA
: /* Receive DMA Status */
639 case REG_RX_CUR_DESC
: /* Receive Current Descriptor */
640 value
= s
->rx_desc_curr
;
642 case REG_RX_CUR_BUF
: /* Receive Current Buffer */
643 if (s
->rx_desc_curr
!= 0) {
644 dma_memory_read(&s
->dma_as
, s
->rx_desc_curr
, &desc
, sizeof(desc
));
650 case REG_RGMII_STA
: /* RGMII Status */
653 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: read access to unknown "
654 "EMAC register 0x" TARGET_FMT_plx
"\n",
658 trace_allwinner_sun8i_emac_read(offset
, value
);
662 static void allwinner_sun8i_emac_write(void *opaque
, hwaddr offset
,
663 uint64_t value
, unsigned size
)
665 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(opaque
);
666 NetClientState
*nc
= qemu_get_queue(s
->nic
);
668 trace_allwinner_sun8i_emac_write(offset
, value
);
671 case REG_BASIC_CTL_0
: /* Basic Control 0 */
672 s
->basic_ctl0
= value
;
674 case REG_BASIC_CTL_1
: /* Basic Control 1 */
675 if (value
& BASIC_CTL1_SOFTRST
) {
676 allwinner_sun8i_emac_reset(DEVICE(s
));
677 value
&= ~BASIC_CTL1_SOFTRST
;
679 s
->basic_ctl1
= value
;
680 if (allwinner_sun8i_emac_can_receive(nc
)) {
681 qemu_flush_queued_packets(nc
);
684 case REG_INT_STA
: /* Interrupt Status */
685 s
->int_sta
&= ~value
;
686 allwinner_sun8i_emac_update_irq(s
);
688 case REG_INT_EN
: /* Interrupt Enable */
690 allwinner_sun8i_emac_update_irq(s
);
692 case REG_TX_CTL_0
: /* Transmit Control 0 */
695 case REG_TX_CTL_1
: /* Transmit Control 1 */
697 if (value
& TX_CTL1_TX_DMA_EN
) {
698 allwinner_sun8i_emac_transmit(s
);
701 case REG_TX_FLOW_CTL
: /* Transmit Flow Control */
702 s
->tx_flowctl
= value
;
704 case REG_TX_DMA_DESC_LIST
: /* Transmit Descriptor List Address */
705 s
->tx_desc_head
= value
;
706 s
->tx_desc_curr
= value
;
708 case REG_RX_CTL_0
: /* Receive Control 0 */
711 case REG_RX_CTL_1
: /* Receive Control 1 */
712 s
->rx_ctl1
= value
| RX_CTL1_RX_MD
;
713 if ((value
& RX_CTL1_RX_DMA_EN
) &&
714 allwinner_sun8i_emac_can_receive(nc
)) {
715 qemu_flush_queued_packets(nc
);
718 case REG_RX_DMA_DESC_LIST
: /* Receive Descriptor List Address */
719 s
->rx_desc_head
= value
;
720 s
->rx_desc_curr
= value
;
722 case REG_FRM_FLT
: /* Receive Frame Filter */
725 case REG_RX_HASH_0
: /* Receive Hash Table 0 */
726 case REG_RX_HASH_1
: /* Receive Hash Table 1 */
728 case REG_MII_CMD
: /* Management Interface Command */
729 s
->mii_cmd
= value
& ~MII_CMD_PHY_BUSY
;
730 allwinner_sun8i_emac_mii_cmd(s
);
732 case REG_MII_DATA
: /* Management Interface Data */
735 case REG_ADDR_HIGH
: /* MAC Address High */
736 stw_le_p(s
->conf
.macaddr
.a
+ 4, value
);
738 case REG_ADDR_LOW
: /* MAC Address Low */
739 stl_le_p(s
->conf
.macaddr
.a
, value
);
741 case REG_TX_DMA_STA
: /* Transmit DMA Status */
742 case REG_TX_CUR_DESC
: /* Transmit Current Descriptor */
743 case REG_TX_CUR_BUF
: /* Transmit Current Buffer */
744 case REG_RX_DMA_STA
: /* Receive DMA Status */
745 case REG_RX_CUR_DESC
: /* Receive Current Descriptor */
746 case REG_RX_CUR_BUF
: /* Receive Current Buffer */
747 case REG_RGMII_STA
: /* RGMII Status */
750 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: write access to unknown "
751 "EMAC register 0x" TARGET_FMT_plx
"\n",
756 static void allwinner_sun8i_emac_set_link(NetClientState
*nc
)
758 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
760 trace_allwinner_sun8i_emac_set_link(!nc
->link_down
);
761 allwinner_sun8i_emac_mii_set_link(s
, !nc
->link_down
);
764 static const MemoryRegionOps allwinner_sun8i_emac_mem_ops
= {
765 .read
= allwinner_sun8i_emac_read
,
766 .write
= allwinner_sun8i_emac_write
,
767 .endianness
= DEVICE_NATIVE_ENDIAN
,
769 .min_access_size
= 4,
770 .max_access_size
= 4,
772 .impl
.min_access_size
= 4,
775 static NetClientInfo net_allwinner_sun8i_emac_info
= {
776 .type
= NET_CLIENT_DRIVER_NIC
,
777 .size
= sizeof(NICState
),
778 .can_receive
= allwinner_sun8i_emac_can_receive
,
779 .receive
= allwinner_sun8i_emac_receive
,
780 .link_status_changed
= allwinner_sun8i_emac_set_link
,
783 static void allwinner_sun8i_emac_init(Object
*obj
)
785 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
786 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(obj
);
788 memory_region_init_io(&s
->iomem
, OBJECT(s
), &allwinner_sun8i_emac_mem_ops
,
789 s
, TYPE_AW_SUN8I_EMAC
, 64 * KiB
);
790 sysbus_init_mmio(sbd
, &s
->iomem
);
791 sysbus_init_irq(sbd
, &s
->irq
);
794 static void allwinner_sun8i_emac_realize(DeviceState
*dev
, Error
**errp
)
796 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(dev
);
799 error_setg(errp
, TYPE_AW_SUN8I_EMAC
" 'dma-memory' link not set");
803 address_space_init(&s
->dma_as
, s
->dma_mr
, "emac-dma");
805 qemu_macaddr_default_if_unset(&s
->conf
.macaddr
);
806 s
->nic
= qemu_new_nic(&net_allwinner_sun8i_emac_info
, &s
->conf
,
807 object_get_typename(OBJECT(dev
)), dev
->id
, s
);
808 qemu_format_nic_info_str(qemu_get_queue(s
->nic
), s
->conf
.macaddr
.a
);
811 static Property allwinner_sun8i_emac_properties
[] = {
812 DEFINE_NIC_PROPERTIES(AwSun8iEmacState
, conf
),
813 DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState
, mii_phy_addr
, 0),
814 DEFINE_PROP_LINK("dma-memory", AwSun8iEmacState
, dma_mr
,
815 TYPE_MEMORY_REGION
, MemoryRegion
*),
816 DEFINE_PROP_END_OF_LIST(),
819 static int allwinner_sun8i_emac_post_load(void *opaque
, int version_id
)
821 AwSun8iEmacState
*s
= opaque
;
823 allwinner_sun8i_emac_set_link(qemu_get_queue(s
->nic
));
828 static const VMStateDescription vmstate_aw_emac
= {
829 .name
= "allwinner-sun8i-emac",
831 .minimum_version_id
= 1,
832 .post_load
= allwinner_sun8i_emac_post_load
,
833 .fields
= (VMStateField
[]) {
834 VMSTATE_UINT8(mii_phy_addr
, AwSun8iEmacState
),
835 VMSTATE_UINT32(mii_cmd
, AwSun8iEmacState
),
836 VMSTATE_UINT32(mii_data
, AwSun8iEmacState
),
837 VMSTATE_UINT32(mii_cr
, AwSun8iEmacState
),
838 VMSTATE_UINT32(mii_st
, AwSun8iEmacState
),
839 VMSTATE_UINT32(mii_adv
, AwSun8iEmacState
),
840 VMSTATE_UINT32(basic_ctl0
, AwSun8iEmacState
),
841 VMSTATE_UINT32(basic_ctl1
, AwSun8iEmacState
),
842 VMSTATE_UINT32(int_en
, AwSun8iEmacState
),
843 VMSTATE_UINT32(int_sta
, AwSun8iEmacState
),
844 VMSTATE_UINT32(frm_flt
, AwSun8iEmacState
),
845 VMSTATE_UINT32(rx_ctl0
, AwSun8iEmacState
),
846 VMSTATE_UINT32(rx_ctl1
, AwSun8iEmacState
),
847 VMSTATE_UINT32(rx_desc_head
, AwSun8iEmacState
),
848 VMSTATE_UINT32(rx_desc_curr
, AwSun8iEmacState
),
849 VMSTATE_UINT32(tx_ctl0
, AwSun8iEmacState
),
850 VMSTATE_UINT32(tx_ctl1
, AwSun8iEmacState
),
851 VMSTATE_UINT32(tx_desc_head
, AwSun8iEmacState
),
852 VMSTATE_UINT32(tx_desc_curr
, AwSun8iEmacState
),
853 VMSTATE_UINT32(tx_flowctl
, AwSun8iEmacState
),
854 VMSTATE_END_OF_LIST()
858 static void allwinner_sun8i_emac_class_init(ObjectClass
*klass
, void *data
)
860 DeviceClass
*dc
= DEVICE_CLASS(klass
);
862 dc
->realize
= allwinner_sun8i_emac_realize
;
863 dc
->reset
= allwinner_sun8i_emac_reset
;
864 dc
->vmsd
= &vmstate_aw_emac
;
865 device_class_set_props(dc
, allwinner_sun8i_emac_properties
);
868 static const TypeInfo allwinner_sun8i_emac_info
= {
869 .name
= TYPE_AW_SUN8I_EMAC
,
870 .parent
= TYPE_SYS_BUS_DEVICE
,
871 .instance_size
= sizeof(AwSun8iEmacState
),
872 .instance_init
= allwinner_sun8i_emac_init
,
873 .class_init
= allwinner_sun8i_emac_class_init
,
876 static void allwinner_sun8i_emac_register_types(void)
878 type_register_static(&allwinner_sun8i_emac_info
);
881 type_init(allwinner_sun8i_emac_register_types
)