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 bool allwinner_sun8i_emac_desc_owned(FrameDescriptor
*desc
,
345 return (desc
->status
& DESC_STATUS_CTL
) && (min_buf_size
== 0 ||
346 (desc
->status2
& DESC_STATUS2_BUF_SIZE_MASK
) >= min_buf_size
);
349 static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState
*s
,
350 FrameDescriptor
*desc
,
353 dma_memory_read(&s
->dma_as
, phys_addr
, desc
, sizeof(*desc
),
354 MEMTXATTRS_UNSPECIFIED
);
357 static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState
*s
,
358 FrameDescriptor
*desc
)
360 const uint32_t nxt
= desc
->next
;
361 allwinner_sun8i_emac_get_desc(s
, desc
, nxt
);
365 static uint32_t allwinner_sun8i_emac_find_desc(AwSun8iEmacState
*s
,
366 FrameDescriptor
*desc
,
370 uint32_t desc_addr
= start_addr
;
372 /* Note that the list is a cycle. Last entry points back to the head. */
373 while (desc_addr
!= 0) {
374 allwinner_sun8i_emac_get_desc(s
, desc
, desc_addr
);
376 if (allwinner_sun8i_emac_desc_owned(desc
, min_size
)) {
378 } else if (desc
->next
== start_addr
) {
381 desc_addr
= desc
->next
;
388 static uint32_t allwinner_sun8i_emac_rx_desc(AwSun8iEmacState
*s
,
389 FrameDescriptor
*desc
,
392 return allwinner_sun8i_emac_find_desc(s
, desc
, s
->rx_desc_curr
, min_size
);
395 static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState
*s
,
396 FrameDescriptor
*desc
)
398 allwinner_sun8i_emac_get_desc(s
, desc
, s
->tx_desc_curr
);
399 return s
->tx_desc_curr
;
402 static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState
*s
,
403 FrameDescriptor
*desc
,
406 dma_memory_write(&s
->dma_as
, phys_addr
, desc
, sizeof(*desc
),
407 MEMTXATTRS_UNSPECIFIED
);
410 static bool allwinner_sun8i_emac_can_receive(NetClientState
*nc
)
412 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
413 FrameDescriptor desc
;
415 return (s
->rx_ctl0
& RX_CTL0_RX_EN
) &&
416 (allwinner_sun8i_emac_rx_desc(s
, &desc
, 0) != 0);
419 static ssize_t
allwinner_sun8i_emac_receive(NetClientState
*nc
,
423 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
424 FrameDescriptor desc
;
425 size_t bytes_left
= size
;
426 size_t desc_bytes
= 0;
427 size_t pad_fcs_size
= 4;
430 if (!(s
->rx_ctl0
& RX_CTL0_RX_EN
)) {
434 s
->rx_desc_curr
= allwinner_sun8i_emac_rx_desc(s
, &desc
,
435 AW_SUN8I_EMAC_MIN_PKT_SZ
);
436 if (!s
->rx_desc_curr
) {
437 s
->int_sta
|= INT_STA_RX_BUF_UA
;
440 /* Keep filling RX descriptors until the whole frame is written */
441 while (s
->rx_desc_curr
&& bytes_left
> 0) {
442 desc
.status
&= ~DESC_STATUS_CTL
;
443 desc
.status
&= ~RX_DESC_STATUS_FRM_LEN_MASK
;
445 if (bytes_left
== size
) {
446 desc
.status
|= RX_DESC_STATUS_FIRST_DESC
;
449 if ((desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
) <
450 (bytes_left
+ pad_fcs_size
)) {
451 desc_bytes
= desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
;
452 desc
.status
|= desc_bytes
<< RX_DESC_STATUS_FRM_LEN_SHIFT
;
454 padding
= pad_fcs_size
;
455 if (bytes_left
< AW_SUN8I_EMAC_MIN_PKT_SZ
) {
456 padding
+= (AW_SUN8I_EMAC_MIN_PKT_SZ
- bytes_left
);
459 desc_bytes
= (bytes_left
);
460 desc
.status
|= RX_DESC_STATUS_LAST_DESC
;
461 desc
.status
|= (bytes_left
+ padding
)
462 << RX_DESC_STATUS_FRM_LEN_SHIFT
;
465 dma_memory_write(&s
->dma_as
, desc
.addr
, buf
, desc_bytes
,
466 MEMTXATTRS_UNSPECIFIED
);
467 allwinner_sun8i_emac_flush_desc(s
, &desc
, s
->rx_desc_curr
);
468 trace_allwinner_sun8i_emac_receive(s
->rx_desc_curr
, desc
.addr
,
471 /* Check if frame needs to raise the receive interrupt */
472 if (!(desc
.status2
& RX_DESC_STATUS2_RX_INT_CTL
)) {
473 s
->int_sta
|= INT_STA_RX
;
476 /* Increment variables */
478 bytes_left
-= desc_bytes
;
480 /* Move to the next descriptor */
481 s
->rx_desc_curr
= allwinner_sun8i_emac_find_desc(s
, &desc
, desc
.next
,
482 AW_SUN8I_EMAC_MIN_PKT_SZ
);
483 if (!s
->rx_desc_curr
) {
484 /* Not enough buffer space available */
485 s
->int_sta
|= INT_STA_RX_BUF_UA
;
486 s
->rx_desc_curr
= s
->rx_desc_head
;
491 /* Report receive DMA is finished */
492 s
->rx_ctl1
&= ~RX_CTL1_RX_DMA_START
;
493 allwinner_sun8i_emac_update_irq(s
);
498 static void allwinner_sun8i_emac_transmit(AwSun8iEmacState
*s
)
500 NetClientState
*nc
= qemu_get_queue(s
->nic
);
501 FrameDescriptor desc
;
503 size_t packet_bytes
= 0;
504 size_t transmitted
= 0;
505 static uint8_t packet_buf
[2048];
507 s
->tx_desc_curr
= allwinner_sun8i_emac_tx_desc(s
, &desc
);
509 /* Read all transmit descriptors */
510 while (allwinner_sun8i_emac_desc_owned(&desc
, 0)) {
512 /* Read from physical memory into packet buffer */
513 bytes
= desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
;
514 if (bytes
+ packet_bytes
> sizeof(packet_buf
)) {
515 desc
.status
|= TX_DESC_STATUS_LENGTH_ERR
;
518 dma_memory_read(&s
->dma_as
, desc
.addr
, packet_buf
+ packet_bytes
,
519 bytes
, MEMTXATTRS_UNSPECIFIED
);
520 packet_bytes
+= bytes
;
521 desc
.status
&= ~DESC_STATUS_CTL
;
522 allwinner_sun8i_emac_flush_desc(s
, &desc
, s
->tx_desc_curr
);
524 /* After the last descriptor, send the packet */
525 if (desc
.status2
& TX_DESC_STATUS2_LAST_DESC
) {
526 if (desc
.status2
& TX_DESC_STATUS2_CHECKSUM_MASK
) {
527 net_checksum_calculate(packet_buf
, packet_bytes
, CSUM_ALL
);
530 qemu_send_packet(nc
, packet_buf
, packet_bytes
);
531 trace_allwinner_sun8i_emac_transmit(s
->tx_desc_curr
, desc
.addr
,
537 s
->tx_desc_curr
= allwinner_sun8i_emac_next_desc(s
, &desc
);
540 /* Raise transmit completed interrupt */
541 if (transmitted
> 0) {
542 s
->int_sta
|= INT_STA_TX
;
543 s
->tx_ctl1
&= ~TX_CTL1_TX_DMA_START
;
544 allwinner_sun8i_emac_update_irq(s
);
548 static void allwinner_sun8i_emac_reset(DeviceState
*dev
)
550 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(dev
);
551 NetClientState
*nc
= qemu_get_queue(s
->nic
);
553 trace_allwinner_sun8i_emac_reset();
558 s
->basic_ctl1
= REG_BASIC_CTL_1_RST
;
563 s
->rx_ctl1
= RX_CTL1_RX_MD
;
572 allwinner_sun8i_emac_mii_reset(s
, !nc
->link_down
);
575 static uint64_t allwinner_sun8i_emac_read(void *opaque
, hwaddr offset
,
578 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(opaque
);
580 FrameDescriptor desc
;
583 case REG_BASIC_CTL_0
: /* Basic Control 0 */
584 value
= s
->basic_ctl0
;
586 case REG_BASIC_CTL_1
: /* Basic Control 1 */
587 value
= s
->basic_ctl1
;
589 case REG_INT_STA
: /* Interrupt Status */
592 case REG_INT_EN
: /* Interrupt Enable */
595 case REG_TX_CTL_0
: /* Transmit Control 0 */
598 case REG_TX_CTL_1
: /* Transmit Control 1 */
601 case REG_TX_FLOW_CTL
: /* Transmit Flow Control */
602 value
= s
->tx_flowctl
;
604 case REG_TX_DMA_DESC_LIST
: /* Transmit Descriptor List Address */
605 value
= s
->tx_desc_head
;
607 case REG_RX_CTL_0
: /* Receive Control 0 */
610 case REG_RX_CTL_1
: /* Receive Control 1 */
613 case REG_RX_DMA_DESC_LIST
: /* Receive Descriptor List Address */
614 value
= s
->rx_desc_head
;
616 case REG_FRM_FLT
: /* Receive Frame Filter */
619 case REG_RX_HASH_0
: /* Receive Hash Table 0 */
620 case REG_RX_HASH_1
: /* Receive Hash Table 1 */
622 case REG_MII_CMD
: /* Management Interface Command */
625 case REG_MII_DATA
: /* Management Interface Data */
628 case REG_ADDR_HIGH
: /* MAC Address High */
629 value
= lduw_le_p(s
->conf
.macaddr
.a
+ 4);
631 case REG_ADDR_LOW
: /* MAC Address Low */
632 value
= ldl_le_p(s
->conf
.macaddr
.a
);
634 case REG_TX_DMA_STA
: /* Transmit DMA Status */
636 case REG_TX_CUR_DESC
: /* Transmit Current Descriptor */
637 value
= s
->tx_desc_curr
;
639 case REG_TX_CUR_BUF
: /* Transmit Current Buffer */
640 if (s
->tx_desc_curr
!= 0) {
641 dma_memory_read(&s
->dma_as
, s
->tx_desc_curr
, &desc
, sizeof(desc
),
642 MEMTXATTRS_UNSPECIFIED
);
648 case REG_RX_DMA_STA
: /* Receive DMA Status */
650 case REG_RX_CUR_DESC
: /* Receive Current Descriptor */
651 value
= s
->rx_desc_curr
;
653 case REG_RX_CUR_BUF
: /* Receive Current Buffer */
654 if (s
->rx_desc_curr
!= 0) {
655 dma_memory_read(&s
->dma_as
, s
->rx_desc_curr
, &desc
, sizeof(desc
),
656 MEMTXATTRS_UNSPECIFIED
);
662 case REG_RGMII_STA
: /* RGMII Status */
665 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: read access to unknown "
666 "EMAC register 0x" TARGET_FMT_plx
"\n",
670 trace_allwinner_sun8i_emac_read(offset
, value
);
674 static void allwinner_sun8i_emac_write(void *opaque
, hwaddr offset
,
675 uint64_t value
, unsigned size
)
677 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(opaque
);
678 NetClientState
*nc
= qemu_get_queue(s
->nic
);
680 trace_allwinner_sun8i_emac_write(offset
, value
);
683 case REG_BASIC_CTL_0
: /* Basic Control 0 */
684 s
->basic_ctl0
= value
;
686 case REG_BASIC_CTL_1
: /* Basic Control 1 */
687 if (value
& BASIC_CTL1_SOFTRST
) {
688 allwinner_sun8i_emac_reset(DEVICE(s
));
689 value
&= ~BASIC_CTL1_SOFTRST
;
691 s
->basic_ctl1
= value
;
692 if (allwinner_sun8i_emac_can_receive(nc
)) {
693 qemu_flush_queued_packets(nc
);
696 case REG_INT_STA
: /* Interrupt Status */
697 s
->int_sta
&= ~value
;
698 allwinner_sun8i_emac_update_irq(s
);
700 case REG_INT_EN
: /* Interrupt Enable */
702 allwinner_sun8i_emac_update_irq(s
);
704 case REG_TX_CTL_0
: /* Transmit Control 0 */
707 case REG_TX_CTL_1
: /* Transmit Control 1 */
709 if (value
& TX_CTL1_TX_DMA_EN
) {
710 allwinner_sun8i_emac_transmit(s
);
713 case REG_TX_FLOW_CTL
: /* Transmit Flow Control */
714 s
->tx_flowctl
= value
;
716 case REG_TX_DMA_DESC_LIST
: /* Transmit Descriptor List Address */
717 s
->tx_desc_head
= value
;
718 s
->tx_desc_curr
= value
;
720 case REG_RX_CTL_0
: /* Receive Control 0 */
723 case REG_RX_CTL_1
: /* Receive Control 1 */
724 s
->rx_ctl1
= value
| RX_CTL1_RX_MD
;
725 if ((value
& RX_CTL1_RX_DMA_EN
) &&
726 allwinner_sun8i_emac_can_receive(nc
)) {
727 qemu_flush_queued_packets(nc
);
730 case REG_RX_DMA_DESC_LIST
: /* Receive Descriptor List Address */
731 s
->rx_desc_head
= value
;
732 s
->rx_desc_curr
= value
;
734 case REG_FRM_FLT
: /* Receive Frame Filter */
737 case REG_RX_HASH_0
: /* Receive Hash Table 0 */
738 case REG_RX_HASH_1
: /* Receive Hash Table 1 */
740 case REG_MII_CMD
: /* Management Interface Command */
741 s
->mii_cmd
= value
& ~MII_CMD_PHY_BUSY
;
742 allwinner_sun8i_emac_mii_cmd(s
);
744 case REG_MII_DATA
: /* Management Interface Data */
747 case REG_ADDR_HIGH
: /* MAC Address High */
748 stw_le_p(s
->conf
.macaddr
.a
+ 4, value
);
750 case REG_ADDR_LOW
: /* MAC Address Low */
751 stl_le_p(s
->conf
.macaddr
.a
, value
);
753 case REG_TX_DMA_STA
: /* Transmit DMA Status */
754 case REG_TX_CUR_DESC
: /* Transmit Current Descriptor */
755 case REG_TX_CUR_BUF
: /* Transmit Current Buffer */
756 case REG_RX_DMA_STA
: /* Receive DMA Status */
757 case REG_RX_CUR_DESC
: /* Receive Current Descriptor */
758 case REG_RX_CUR_BUF
: /* Receive Current Buffer */
759 case REG_RGMII_STA
: /* RGMII Status */
762 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: write access to unknown "
763 "EMAC register 0x" TARGET_FMT_plx
"\n",
768 static void allwinner_sun8i_emac_set_link(NetClientState
*nc
)
770 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
772 trace_allwinner_sun8i_emac_set_link(!nc
->link_down
);
773 allwinner_sun8i_emac_mii_set_link(s
, !nc
->link_down
);
776 static const MemoryRegionOps allwinner_sun8i_emac_mem_ops
= {
777 .read
= allwinner_sun8i_emac_read
,
778 .write
= allwinner_sun8i_emac_write
,
779 .endianness
= DEVICE_NATIVE_ENDIAN
,
781 .min_access_size
= 4,
782 .max_access_size
= 4,
784 .impl
.min_access_size
= 4,
787 static NetClientInfo net_allwinner_sun8i_emac_info
= {
788 .type
= NET_CLIENT_DRIVER_NIC
,
789 .size
= sizeof(NICState
),
790 .can_receive
= allwinner_sun8i_emac_can_receive
,
791 .receive
= allwinner_sun8i_emac_receive
,
792 .link_status_changed
= allwinner_sun8i_emac_set_link
,
795 static void allwinner_sun8i_emac_init(Object
*obj
)
797 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
798 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(obj
);
800 memory_region_init_io(&s
->iomem
, OBJECT(s
), &allwinner_sun8i_emac_mem_ops
,
801 s
, TYPE_AW_SUN8I_EMAC
, 64 * KiB
);
802 sysbus_init_mmio(sbd
, &s
->iomem
);
803 sysbus_init_irq(sbd
, &s
->irq
);
806 static void allwinner_sun8i_emac_realize(DeviceState
*dev
, Error
**errp
)
808 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(dev
);
811 error_setg(errp
, TYPE_AW_SUN8I_EMAC
" 'dma-memory' link not set");
815 address_space_init(&s
->dma_as
, s
->dma_mr
, "emac-dma");
817 qemu_macaddr_default_if_unset(&s
->conf
.macaddr
);
818 s
->nic
= qemu_new_nic(&net_allwinner_sun8i_emac_info
, &s
->conf
,
819 object_get_typename(OBJECT(dev
)), dev
->id
, s
);
820 qemu_format_nic_info_str(qemu_get_queue(s
->nic
), s
->conf
.macaddr
.a
);
823 static Property allwinner_sun8i_emac_properties
[] = {
824 DEFINE_NIC_PROPERTIES(AwSun8iEmacState
, conf
),
825 DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState
, mii_phy_addr
, 0),
826 DEFINE_PROP_LINK("dma-memory", AwSun8iEmacState
, dma_mr
,
827 TYPE_MEMORY_REGION
, MemoryRegion
*),
828 DEFINE_PROP_END_OF_LIST(),
831 static int allwinner_sun8i_emac_post_load(void *opaque
, int version_id
)
833 AwSun8iEmacState
*s
= opaque
;
835 allwinner_sun8i_emac_set_link(qemu_get_queue(s
->nic
));
840 static const VMStateDescription vmstate_aw_emac
= {
841 .name
= "allwinner-sun8i-emac",
843 .minimum_version_id
= 1,
844 .post_load
= allwinner_sun8i_emac_post_load
,
845 .fields
= (VMStateField
[]) {
846 VMSTATE_UINT8(mii_phy_addr
, AwSun8iEmacState
),
847 VMSTATE_UINT32(mii_cmd
, AwSun8iEmacState
),
848 VMSTATE_UINT32(mii_data
, AwSun8iEmacState
),
849 VMSTATE_UINT32(mii_cr
, AwSun8iEmacState
),
850 VMSTATE_UINT32(mii_st
, AwSun8iEmacState
),
851 VMSTATE_UINT32(mii_adv
, AwSun8iEmacState
),
852 VMSTATE_UINT32(basic_ctl0
, AwSun8iEmacState
),
853 VMSTATE_UINT32(basic_ctl1
, AwSun8iEmacState
),
854 VMSTATE_UINT32(int_en
, AwSun8iEmacState
),
855 VMSTATE_UINT32(int_sta
, AwSun8iEmacState
),
856 VMSTATE_UINT32(frm_flt
, AwSun8iEmacState
),
857 VMSTATE_UINT32(rx_ctl0
, AwSun8iEmacState
),
858 VMSTATE_UINT32(rx_ctl1
, AwSun8iEmacState
),
859 VMSTATE_UINT32(rx_desc_head
, AwSun8iEmacState
),
860 VMSTATE_UINT32(rx_desc_curr
, AwSun8iEmacState
),
861 VMSTATE_UINT32(tx_ctl0
, AwSun8iEmacState
),
862 VMSTATE_UINT32(tx_ctl1
, AwSun8iEmacState
),
863 VMSTATE_UINT32(tx_desc_head
, AwSun8iEmacState
),
864 VMSTATE_UINT32(tx_desc_curr
, AwSun8iEmacState
),
865 VMSTATE_UINT32(tx_flowctl
, AwSun8iEmacState
),
866 VMSTATE_END_OF_LIST()
870 static void allwinner_sun8i_emac_class_init(ObjectClass
*klass
, void *data
)
872 DeviceClass
*dc
= DEVICE_CLASS(klass
);
874 dc
->realize
= allwinner_sun8i_emac_realize
;
875 dc
->reset
= allwinner_sun8i_emac_reset
;
876 dc
->vmsd
= &vmstate_aw_emac
;
877 device_class_set_props(dc
, allwinner_sun8i_emac_properties
);
880 static const TypeInfo allwinner_sun8i_emac_info
= {
881 .name
= TYPE_AW_SUN8I_EMAC
,
882 .parent
= TYPE_SYS_BUS_DEVICE
,
883 .instance_size
= sizeof(AwSun8iEmacState
),
884 .instance_init
= allwinner_sun8i_emac_init
,
885 .class_init
= allwinner_sun8i_emac_class_init
,
888 static void allwinner_sun8i_emac_register_types(void)
890 type_register_static(&allwinner_sun8i_emac_info
);
893 type_init(allwinner_sun8i_emac_register_types
)