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
));
356 static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState
*s
,
357 FrameDescriptor
*desc
)
359 const uint32_t nxt
= desc
->next
;
360 allwinner_sun8i_emac_get_desc(s
, desc
, nxt
);
364 static uint32_t allwinner_sun8i_emac_find_desc(AwSun8iEmacState
*s
,
365 FrameDescriptor
*desc
,
369 uint32_t desc_addr
= start_addr
;
371 /* Note that the list is a cycle. Last entry points back to the head. */
372 while (desc_addr
!= 0) {
373 allwinner_sun8i_emac_get_desc(s
, desc
, desc_addr
);
375 if (allwinner_sun8i_emac_desc_owned(desc
, min_size
)) {
377 } else if (desc
->next
== start_addr
) {
380 desc_addr
= desc
->next
;
387 static uint32_t allwinner_sun8i_emac_rx_desc(AwSun8iEmacState
*s
,
388 FrameDescriptor
*desc
,
391 return allwinner_sun8i_emac_find_desc(s
, desc
, s
->rx_desc_curr
, min_size
);
394 static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState
*s
,
395 FrameDescriptor
*desc
)
397 allwinner_sun8i_emac_get_desc(s
, desc
, s
->tx_desc_curr
);
398 return s
->tx_desc_curr
;
401 static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState
*s
,
402 FrameDescriptor
*desc
,
405 dma_memory_write(&s
->dma_as
, phys_addr
, desc
, sizeof(*desc
));
408 static bool allwinner_sun8i_emac_can_receive(NetClientState
*nc
)
410 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
411 FrameDescriptor desc
;
413 return (s
->rx_ctl0
& RX_CTL0_RX_EN
) &&
414 (allwinner_sun8i_emac_rx_desc(s
, &desc
, 0) != 0);
417 static ssize_t
allwinner_sun8i_emac_receive(NetClientState
*nc
,
421 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
422 FrameDescriptor desc
;
423 size_t bytes_left
= size
;
424 size_t desc_bytes
= 0;
425 size_t pad_fcs_size
= 4;
428 if (!(s
->rx_ctl0
& RX_CTL0_RX_EN
)) {
432 s
->rx_desc_curr
= allwinner_sun8i_emac_rx_desc(s
, &desc
,
433 AW_SUN8I_EMAC_MIN_PKT_SZ
);
434 if (!s
->rx_desc_curr
) {
435 s
->int_sta
|= INT_STA_RX_BUF_UA
;
438 /* Keep filling RX descriptors until the whole frame is written */
439 while (s
->rx_desc_curr
&& bytes_left
> 0) {
440 desc
.status
&= ~DESC_STATUS_CTL
;
441 desc
.status
&= ~RX_DESC_STATUS_FRM_LEN_MASK
;
443 if (bytes_left
== size
) {
444 desc
.status
|= RX_DESC_STATUS_FIRST_DESC
;
447 if ((desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
) <
448 (bytes_left
+ pad_fcs_size
)) {
449 desc_bytes
= desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
;
450 desc
.status
|= desc_bytes
<< RX_DESC_STATUS_FRM_LEN_SHIFT
;
452 padding
= pad_fcs_size
;
453 if (bytes_left
< AW_SUN8I_EMAC_MIN_PKT_SZ
) {
454 padding
+= (AW_SUN8I_EMAC_MIN_PKT_SZ
- bytes_left
);
457 desc_bytes
= (bytes_left
);
458 desc
.status
|= RX_DESC_STATUS_LAST_DESC
;
459 desc
.status
|= (bytes_left
+ padding
)
460 << RX_DESC_STATUS_FRM_LEN_SHIFT
;
463 dma_memory_write(&s
->dma_as
, desc
.addr
, buf
, desc_bytes
);
464 allwinner_sun8i_emac_flush_desc(s
, &desc
, s
->rx_desc_curr
);
465 trace_allwinner_sun8i_emac_receive(s
->rx_desc_curr
, desc
.addr
,
468 /* Check if frame needs to raise the receive interrupt */
469 if (!(desc
.status2
& RX_DESC_STATUS2_RX_INT_CTL
)) {
470 s
->int_sta
|= INT_STA_RX
;
473 /* Increment variables */
475 bytes_left
-= desc_bytes
;
477 /* Move to the next descriptor */
478 s
->rx_desc_curr
= allwinner_sun8i_emac_find_desc(s
, &desc
, desc
.next
,
479 AW_SUN8I_EMAC_MIN_PKT_SZ
);
480 if (!s
->rx_desc_curr
) {
481 /* Not enough buffer space available */
482 s
->int_sta
|= INT_STA_RX_BUF_UA
;
483 s
->rx_desc_curr
= s
->rx_desc_head
;
488 /* Report receive DMA is finished */
489 s
->rx_ctl1
&= ~RX_CTL1_RX_DMA_START
;
490 allwinner_sun8i_emac_update_irq(s
);
495 static void allwinner_sun8i_emac_transmit(AwSun8iEmacState
*s
)
497 NetClientState
*nc
= qemu_get_queue(s
->nic
);
498 FrameDescriptor desc
;
500 size_t packet_bytes
= 0;
501 size_t transmitted
= 0;
502 static uint8_t packet_buf
[2048];
504 s
->tx_desc_curr
= allwinner_sun8i_emac_tx_desc(s
, &desc
);
506 /* Read all transmit descriptors */
507 while (allwinner_sun8i_emac_desc_owned(&desc
, 0)) {
509 /* Read from physical memory into packet buffer */
510 bytes
= desc
.status2
& DESC_STATUS2_BUF_SIZE_MASK
;
511 if (bytes
+ packet_bytes
> sizeof(packet_buf
)) {
512 desc
.status
|= TX_DESC_STATUS_LENGTH_ERR
;
515 dma_memory_read(&s
->dma_as
, desc
.addr
, packet_buf
+ packet_bytes
, bytes
);
516 packet_bytes
+= bytes
;
517 desc
.status
&= ~DESC_STATUS_CTL
;
518 allwinner_sun8i_emac_flush_desc(s
, &desc
, s
->tx_desc_curr
);
520 /* After the last descriptor, send the packet */
521 if (desc
.status2
& TX_DESC_STATUS2_LAST_DESC
) {
522 if (desc
.status2
& TX_DESC_STATUS2_CHECKSUM_MASK
) {
523 net_checksum_calculate(packet_buf
, packet_bytes
, CSUM_ALL
);
526 qemu_send_packet(nc
, packet_buf
, packet_bytes
);
527 trace_allwinner_sun8i_emac_transmit(s
->tx_desc_curr
, desc
.addr
,
533 s
->tx_desc_curr
= allwinner_sun8i_emac_next_desc(s
, &desc
);
536 /* Raise transmit completed interrupt */
537 if (transmitted
> 0) {
538 s
->int_sta
|= INT_STA_TX
;
539 s
->tx_ctl1
&= ~TX_CTL1_TX_DMA_START
;
540 allwinner_sun8i_emac_update_irq(s
);
544 static void allwinner_sun8i_emac_reset(DeviceState
*dev
)
546 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(dev
);
547 NetClientState
*nc
= qemu_get_queue(s
->nic
);
549 trace_allwinner_sun8i_emac_reset();
554 s
->basic_ctl1
= REG_BASIC_CTL_1_RST
;
559 s
->rx_ctl1
= RX_CTL1_RX_MD
;
568 allwinner_sun8i_emac_mii_reset(s
, !nc
->link_down
);
571 static uint64_t allwinner_sun8i_emac_read(void *opaque
, hwaddr offset
,
574 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(opaque
);
576 FrameDescriptor desc
;
579 case REG_BASIC_CTL_0
: /* Basic Control 0 */
580 value
= s
->basic_ctl0
;
582 case REG_BASIC_CTL_1
: /* Basic Control 1 */
583 value
= s
->basic_ctl1
;
585 case REG_INT_STA
: /* Interrupt Status */
588 case REG_INT_EN
: /* Interrupt Enable */
591 case REG_TX_CTL_0
: /* Transmit Control 0 */
594 case REG_TX_CTL_1
: /* Transmit Control 1 */
597 case REG_TX_FLOW_CTL
: /* Transmit Flow Control */
598 value
= s
->tx_flowctl
;
600 case REG_TX_DMA_DESC_LIST
: /* Transmit Descriptor List Address */
601 value
= s
->tx_desc_head
;
603 case REG_RX_CTL_0
: /* Receive Control 0 */
606 case REG_RX_CTL_1
: /* Receive Control 1 */
609 case REG_RX_DMA_DESC_LIST
: /* Receive Descriptor List Address */
610 value
= s
->rx_desc_head
;
612 case REG_FRM_FLT
: /* Receive Frame Filter */
615 case REG_RX_HASH_0
: /* Receive Hash Table 0 */
616 case REG_RX_HASH_1
: /* Receive Hash Table 1 */
618 case REG_MII_CMD
: /* Management Interface Command */
621 case REG_MII_DATA
: /* Management Interface Data */
624 case REG_ADDR_HIGH
: /* MAC Address High */
625 value
= lduw_le_p(s
->conf
.macaddr
.a
+ 4);
627 case REG_ADDR_LOW
: /* MAC Address Low */
628 value
= ldl_le_p(s
->conf
.macaddr
.a
);
630 case REG_TX_DMA_STA
: /* Transmit DMA Status */
632 case REG_TX_CUR_DESC
: /* Transmit Current Descriptor */
633 value
= s
->tx_desc_curr
;
635 case REG_TX_CUR_BUF
: /* Transmit Current Buffer */
636 if (s
->tx_desc_curr
!= 0) {
637 dma_memory_read(&s
->dma_as
, s
->tx_desc_curr
, &desc
, sizeof(desc
));
643 case REG_RX_DMA_STA
: /* Receive DMA Status */
645 case REG_RX_CUR_DESC
: /* Receive Current Descriptor */
646 value
= s
->rx_desc_curr
;
648 case REG_RX_CUR_BUF
: /* Receive Current Buffer */
649 if (s
->rx_desc_curr
!= 0) {
650 dma_memory_read(&s
->dma_as
, s
->rx_desc_curr
, &desc
, sizeof(desc
));
656 case REG_RGMII_STA
: /* RGMII Status */
659 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: read access to unknown "
660 "EMAC register 0x" TARGET_FMT_plx
"\n",
664 trace_allwinner_sun8i_emac_read(offset
, value
);
668 static void allwinner_sun8i_emac_write(void *opaque
, hwaddr offset
,
669 uint64_t value
, unsigned size
)
671 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(opaque
);
672 NetClientState
*nc
= qemu_get_queue(s
->nic
);
674 trace_allwinner_sun8i_emac_write(offset
, value
);
677 case REG_BASIC_CTL_0
: /* Basic Control 0 */
678 s
->basic_ctl0
= value
;
680 case REG_BASIC_CTL_1
: /* Basic Control 1 */
681 if (value
& BASIC_CTL1_SOFTRST
) {
682 allwinner_sun8i_emac_reset(DEVICE(s
));
683 value
&= ~BASIC_CTL1_SOFTRST
;
685 s
->basic_ctl1
= value
;
686 if (allwinner_sun8i_emac_can_receive(nc
)) {
687 qemu_flush_queued_packets(nc
);
690 case REG_INT_STA
: /* Interrupt Status */
691 s
->int_sta
&= ~value
;
692 allwinner_sun8i_emac_update_irq(s
);
694 case REG_INT_EN
: /* Interrupt Enable */
696 allwinner_sun8i_emac_update_irq(s
);
698 case REG_TX_CTL_0
: /* Transmit Control 0 */
701 case REG_TX_CTL_1
: /* Transmit Control 1 */
703 if (value
& TX_CTL1_TX_DMA_EN
) {
704 allwinner_sun8i_emac_transmit(s
);
707 case REG_TX_FLOW_CTL
: /* Transmit Flow Control */
708 s
->tx_flowctl
= value
;
710 case REG_TX_DMA_DESC_LIST
: /* Transmit Descriptor List Address */
711 s
->tx_desc_head
= value
;
712 s
->tx_desc_curr
= value
;
714 case REG_RX_CTL_0
: /* Receive Control 0 */
717 case REG_RX_CTL_1
: /* Receive Control 1 */
718 s
->rx_ctl1
= value
| RX_CTL1_RX_MD
;
719 if ((value
& RX_CTL1_RX_DMA_EN
) &&
720 allwinner_sun8i_emac_can_receive(nc
)) {
721 qemu_flush_queued_packets(nc
);
724 case REG_RX_DMA_DESC_LIST
: /* Receive Descriptor List Address */
725 s
->rx_desc_head
= value
;
726 s
->rx_desc_curr
= value
;
728 case REG_FRM_FLT
: /* Receive Frame Filter */
731 case REG_RX_HASH_0
: /* Receive Hash Table 0 */
732 case REG_RX_HASH_1
: /* Receive Hash Table 1 */
734 case REG_MII_CMD
: /* Management Interface Command */
735 s
->mii_cmd
= value
& ~MII_CMD_PHY_BUSY
;
736 allwinner_sun8i_emac_mii_cmd(s
);
738 case REG_MII_DATA
: /* Management Interface Data */
741 case REG_ADDR_HIGH
: /* MAC Address High */
742 stw_le_p(s
->conf
.macaddr
.a
+ 4, value
);
744 case REG_ADDR_LOW
: /* MAC Address Low */
745 stl_le_p(s
->conf
.macaddr
.a
, value
);
747 case REG_TX_DMA_STA
: /* Transmit DMA Status */
748 case REG_TX_CUR_DESC
: /* Transmit Current Descriptor */
749 case REG_TX_CUR_BUF
: /* Transmit Current Buffer */
750 case REG_RX_DMA_STA
: /* Receive DMA Status */
751 case REG_RX_CUR_DESC
: /* Receive Current Descriptor */
752 case REG_RX_CUR_BUF
: /* Receive Current Buffer */
753 case REG_RGMII_STA
: /* RGMII Status */
756 qemu_log_mask(LOG_UNIMP
, "allwinner-h3-emac: write access to unknown "
757 "EMAC register 0x" TARGET_FMT_plx
"\n",
762 static void allwinner_sun8i_emac_set_link(NetClientState
*nc
)
764 AwSun8iEmacState
*s
= qemu_get_nic_opaque(nc
);
766 trace_allwinner_sun8i_emac_set_link(!nc
->link_down
);
767 allwinner_sun8i_emac_mii_set_link(s
, !nc
->link_down
);
770 static const MemoryRegionOps allwinner_sun8i_emac_mem_ops
= {
771 .read
= allwinner_sun8i_emac_read
,
772 .write
= allwinner_sun8i_emac_write
,
773 .endianness
= DEVICE_NATIVE_ENDIAN
,
775 .min_access_size
= 4,
776 .max_access_size
= 4,
778 .impl
.min_access_size
= 4,
781 static NetClientInfo net_allwinner_sun8i_emac_info
= {
782 .type
= NET_CLIENT_DRIVER_NIC
,
783 .size
= sizeof(NICState
),
784 .can_receive
= allwinner_sun8i_emac_can_receive
,
785 .receive
= allwinner_sun8i_emac_receive
,
786 .link_status_changed
= allwinner_sun8i_emac_set_link
,
789 static void allwinner_sun8i_emac_init(Object
*obj
)
791 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
792 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(obj
);
794 memory_region_init_io(&s
->iomem
, OBJECT(s
), &allwinner_sun8i_emac_mem_ops
,
795 s
, TYPE_AW_SUN8I_EMAC
, 64 * KiB
);
796 sysbus_init_mmio(sbd
, &s
->iomem
);
797 sysbus_init_irq(sbd
, &s
->irq
);
800 static void allwinner_sun8i_emac_realize(DeviceState
*dev
, Error
**errp
)
802 AwSun8iEmacState
*s
= AW_SUN8I_EMAC(dev
);
805 error_setg(errp
, TYPE_AW_SUN8I_EMAC
" 'dma-memory' link not set");
809 address_space_init(&s
->dma_as
, s
->dma_mr
, "emac-dma");
811 qemu_macaddr_default_if_unset(&s
->conf
.macaddr
);
812 s
->nic
= qemu_new_nic(&net_allwinner_sun8i_emac_info
, &s
->conf
,
813 object_get_typename(OBJECT(dev
)), dev
->id
, s
);
814 qemu_format_nic_info_str(qemu_get_queue(s
->nic
), s
->conf
.macaddr
.a
);
817 static Property allwinner_sun8i_emac_properties
[] = {
818 DEFINE_NIC_PROPERTIES(AwSun8iEmacState
, conf
),
819 DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState
, mii_phy_addr
, 0),
820 DEFINE_PROP_LINK("dma-memory", AwSun8iEmacState
, dma_mr
,
821 TYPE_MEMORY_REGION
, MemoryRegion
*),
822 DEFINE_PROP_END_OF_LIST(),
825 static int allwinner_sun8i_emac_post_load(void *opaque
, int version_id
)
827 AwSun8iEmacState
*s
= opaque
;
829 allwinner_sun8i_emac_set_link(qemu_get_queue(s
->nic
));
834 static const VMStateDescription vmstate_aw_emac
= {
835 .name
= "allwinner-sun8i-emac",
837 .minimum_version_id
= 1,
838 .post_load
= allwinner_sun8i_emac_post_load
,
839 .fields
= (VMStateField
[]) {
840 VMSTATE_UINT8(mii_phy_addr
, AwSun8iEmacState
),
841 VMSTATE_UINT32(mii_cmd
, AwSun8iEmacState
),
842 VMSTATE_UINT32(mii_data
, AwSun8iEmacState
),
843 VMSTATE_UINT32(mii_cr
, AwSun8iEmacState
),
844 VMSTATE_UINT32(mii_st
, AwSun8iEmacState
),
845 VMSTATE_UINT32(mii_adv
, AwSun8iEmacState
),
846 VMSTATE_UINT32(basic_ctl0
, AwSun8iEmacState
),
847 VMSTATE_UINT32(basic_ctl1
, AwSun8iEmacState
),
848 VMSTATE_UINT32(int_en
, AwSun8iEmacState
),
849 VMSTATE_UINT32(int_sta
, AwSun8iEmacState
),
850 VMSTATE_UINT32(frm_flt
, AwSun8iEmacState
),
851 VMSTATE_UINT32(rx_ctl0
, AwSun8iEmacState
),
852 VMSTATE_UINT32(rx_ctl1
, AwSun8iEmacState
),
853 VMSTATE_UINT32(rx_desc_head
, AwSun8iEmacState
),
854 VMSTATE_UINT32(rx_desc_curr
, AwSun8iEmacState
),
855 VMSTATE_UINT32(tx_ctl0
, AwSun8iEmacState
),
856 VMSTATE_UINT32(tx_ctl1
, AwSun8iEmacState
),
857 VMSTATE_UINT32(tx_desc_head
, AwSun8iEmacState
),
858 VMSTATE_UINT32(tx_desc_curr
, AwSun8iEmacState
),
859 VMSTATE_UINT32(tx_flowctl
, AwSun8iEmacState
),
860 VMSTATE_END_OF_LIST()
864 static void allwinner_sun8i_emac_class_init(ObjectClass
*klass
, void *data
)
866 DeviceClass
*dc
= DEVICE_CLASS(klass
);
868 dc
->realize
= allwinner_sun8i_emac_realize
;
869 dc
->reset
= allwinner_sun8i_emac_reset
;
870 dc
->vmsd
= &vmstate_aw_emac
;
871 device_class_set_props(dc
, allwinner_sun8i_emac_properties
);
874 static const TypeInfo allwinner_sun8i_emac_info
= {
875 .name
= TYPE_AW_SUN8I_EMAC
,
876 .parent
= TYPE_SYS_BUS_DEVICE
,
877 .instance_size
= sizeof(AwSun8iEmacState
),
878 .instance_init
= allwinner_sun8i_emac_init
,
879 .class_init
= allwinner_sun8i_emac_class_init
,
882 static void allwinner_sun8i_emac_register_types(void)
884 type_register_static(&allwinner_sun8i_emac_info
);
887 type_init(allwinner_sun8i_emac_register_types
)