2 * QEMU model of the Smartfusion2 Ethernet MAC.
4 * Copyright (c) 2020 Subbaraya Sundeep <sundeep.lkml@gmail.com>.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * Refer to section Ethernet MAC in the document:
25 * UG0331: SmartFusion2 Microcontroller Subsystem User Guide
27 * https://www.microsemi.com/document-portal/cat_view/56661-internal-documents/
28 * 56758-soc?lang=en&limit=20&limitstart=220
31 #include "qemu/osdep.h"
32 #include "qemu-common.h"
34 #include "qapi/error.h"
35 #include "exec/address-spaces.h"
36 #include "hw/registerfields.h"
37 #include "hw/net/msf2-emac.h"
38 #include "hw/net/mii.h"
40 #include "hw/qdev-properties.h"
41 #include "migration/vmstate.h"
44 FIELD(CFG1
, RESET
, 31, 1)
45 FIELD(CFG1
, RX_EN
, 2, 1)
46 FIELD(CFG1
, TX_EN
, 0, 1)
47 FIELD(CFG1
, LB_EN
, 8, 1)
50 REG32(HALF_DUPLEX
, 0xc)
51 REG32(MAX_FRAME_LENGTH
, 0x10)
53 FIELD(MII_CMD
, READ
, 0, 1)
55 FIELD(MII_ADDR
, REGADDR
, 0, 5)
56 FIELD(MII_ADDR
, PHYADDR
, 8, 5)
61 REG32(FIFO_CFG0
, 0x48)
62 REG32(FIFO_CFG4
, 0x58)
63 FIELD(FIFO_CFG4
, BCAST
, 9, 1)
64 FIELD(FIFO_CFG4
, MCAST
, 8, 1)
65 REG32(FIFO_CFG5
, 0x5C)
66 FIELD(FIFO_CFG5
, BCAST
, 9, 1)
67 FIELD(FIFO_CFG5
, MCAST
, 8, 1)
68 REG32(DMA_TX_CTL
, 0x180)
69 FIELD(DMA_TX_CTL
, EN
, 0, 1)
70 REG32(DMA_TX_DESC
, 0x184)
71 REG32(DMA_TX_STATUS
, 0x188)
72 FIELD(DMA_TX_STATUS
, PKTCNT
, 16, 8)
73 FIELD(DMA_TX_STATUS
, UNDERRUN
, 1, 1)
74 FIELD(DMA_TX_STATUS
, PKT_SENT
, 0, 1)
75 REG32(DMA_RX_CTL
, 0x18c)
76 FIELD(DMA_RX_CTL
, EN
, 0, 1)
77 REG32(DMA_RX_DESC
, 0x190)
78 REG32(DMA_RX_STATUS
, 0x194)
79 FIELD(DMA_RX_STATUS
, PKTCNT
, 16, 8)
80 FIELD(DMA_RX_STATUS
, OVERFLOW
, 2, 1)
81 FIELD(DMA_RX_STATUS
, PKT_RCVD
, 0, 1)
82 REG32(DMA_IRQ_MASK
, 0x198)
85 #define EMPTY_MASK (1 << 31)
86 #define PKT_SIZE 0x7FF
88 #define MAX_PKT_SIZE 2048
96 static uint32_t emac_get_isr(MSF2EmacState
*s
)
98 uint32_t ier
= s
->regs
[R_DMA_IRQ_MASK
];
99 uint32_t tx
= s
->regs
[R_DMA_TX_STATUS
] & 0xF;
100 uint32_t rx
= s
->regs
[R_DMA_RX_STATUS
] & 0xF;
101 uint32_t isr
= (rx
<< 4) | tx
;
103 s
->regs
[R_DMA_IRQ
] = ier
& isr
;
104 return s
->regs
[R_DMA_IRQ
];
107 static void emac_update_irq(MSF2EmacState
*s
)
109 bool intr
= emac_get_isr(s
);
111 qemu_set_irq(s
->irq
, intr
);
114 static void emac_load_desc(MSF2EmacState
*s
, EmacDesc
*d
, hwaddr desc
)
116 address_space_read(&s
->dma_as
, desc
, MEMTXATTRS_UNSPECIFIED
, d
, sizeof *d
);
117 /* Convert from LE into host endianness. */
118 d
->pktaddr
= le32_to_cpu(d
->pktaddr
);
119 d
->pktsize
= le32_to_cpu(d
->pktsize
);
120 d
->next
= le32_to_cpu(d
->next
);
123 static void emac_store_desc(MSF2EmacState
*s
, EmacDesc
*d
, hwaddr desc
)
125 /* Convert from host endianness into LE. */
126 d
->pktaddr
= cpu_to_le32(d
->pktaddr
);
127 d
->pktsize
= cpu_to_le32(d
->pktsize
);
128 d
->next
= cpu_to_le32(d
->next
);
130 address_space_write(&s
->dma_as
, desc
, MEMTXATTRS_UNSPECIFIED
, d
, sizeof *d
);
133 static void msf2_dma_tx(MSF2EmacState
*s
)
135 NetClientState
*nc
= qemu_get_queue(s
->nic
);
136 hwaddr desc
= s
->regs
[R_DMA_TX_DESC
];
137 uint8_t buf
[MAX_PKT_SIZE
];
143 if (!(s
->regs
[R_CFG1
] & R_CFG1_TX_EN_MASK
)) {
148 emac_load_desc(s
, &d
, desc
);
149 if (d
.pktsize
& EMPTY_MASK
) {
152 size
= d
.pktsize
& PKT_SIZE
;
153 address_space_read(&s
->dma_as
, d
.pktaddr
, MEMTXATTRS_UNSPECIFIED
,
156 * This is very basic way to send packets. Ideally there should be
157 * a FIFO and packets should be sent out from FIFO only when
158 * R_CFG1 bit 0 is set.
160 if (s
->regs
[R_CFG1
] & R_CFG1_LB_EN_MASK
) {
161 nc
->info
->receive(nc
, buf
, size
);
163 qemu_send_packet(nc
, buf
, size
);
165 d
.pktsize
|= EMPTY_MASK
;
166 emac_store_desc(s
, &d
, desc
);
167 /* update sent packets count */
168 status
= s
->regs
[R_DMA_TX_STATUS
];
169 pktcnt
= FIELD_EX32(status
, DMA_TX_STATUS
, PKTCNT
);
171 s
->regs
[R_DMA_TX_STATUS
] = FIELD_DP32(status
, DMA_TX_STATUS
,
173 s
->regs
[R_DMA_TX_STATUS
] |= R_DMA_TX_STATUS_PKT_SENT_MASK
;
176 s
->regs
[R_DMA_TX_STATUS
] |= R_DMA_TX_STATUS_UNDERRUN_MASK
;
177 s
->regs
[R_DMA_TX_CTL
] &= ~R_DMA_TX_CTL_EN_MASK
;
180 static void msf2_phy_update_link(MSF2EmacState
*s
)
182 /* Autonegotiation status mirrors link status. */
183 if (qemu_get_queue(s
->nic
)->link_down
) {
184 s
->phy_regs
[MII_BMSR
] &= ~(MII_BMSR_AN_COMP
|
187 s
->phy_regs
[MII_BMSR
] |= (MII_BMSR_AN_COMP
|
192 static void msf2_phy_reset(MSF2EmacState
*s
)
194 memset(&s
->phy_regs
[0], 0, sizeof(s
->phy_regs
));
195 s
->phy_regs
[MII_BMCR
] = 0x1140;
196 s
->phy_regs
[MII_BMSR
] = 0x7968;
197 s
->phy_regs
[MII_PHYID1
] = 0x0022;
198 s
->phy_regs
[MII_PHYID2
] = 0x1550;
199 s
->phy_regs
[MII_ANAR
] = 0x01E1;
200 s
->phy_regs
[MII_ANLPAR
] = 0xCDE1;
202 msf2_phy_update_link(s
);
205 static void write_to_phy(MSF2EmacState
*s
)
207 uint8_t reg_addr
= s
->regs
[R_MII_ADDR
] & R_MII_ADDR_REGADDR_MASK
;
208 uint8_t phy_addr
= (s
->regs
[R_MII_ADDR
] >> R_MII_ADDR_PHYADDR_SHIFT
) &
209 R_MII_ADDR_REGADDR_MASK
;
210 uint16_t data
= s
->regs
[R_MII_CTL
] & 0xFFFF;
212 if (phy_addr
!= PHYADDR
) {
218 if (data
& MII_BMCR_RESET
) {
221 data
&= ~MII_BMCR_RESET
;
223 if (data
& MII_BMCR_AUTOEN
) {
224 /* Complete autonegotiation immediately */
225 data
&= ~MII_BMCR_AUTOEN
;
226 s
->phy_regs
[MII_BMSR
] |= MII_BMSR_AN_COMP
;
231 s
->phy_regs
[reg_addr
] = data
;
234 static uint16_t read_from_phy(MSF2EmacState
*s
)
236 uint8_t reg_addr
= s
->regs
[R_MII_ADDR
] & R_MII_ADDR_REGADDR_MASK
;
237 uint8_t phy_addr
= (s
->regs
[R_MII_ADDR
] >> R_MII_ADDR_PHYADDR_SHIFT
) &
238 R_MII_ADDR_REGADDR_MASK
;
240 if (phy_addr
== PHYADDR
) {
241 return s
->phy_regs
[reg_addr
];
247 static void msf2_emac_do_reset(MSF2EmacState
*s
)
249 memset(&s
->regs
[0], 0, sizeof(s
->regs
));
250 s
->regs
[R_CFG1
] = 0x80000000;
251 s
->regs
[R_CFG2
] = 0x00007000;
252 s
->regs
[R_IFG
] = 0x40605060;
253 s
->regs
[R_HALF_DUPLEX
] = 0x00A1F037;
254 s
->regs
[R_MAX_FRAME_LENGTH
] = 0x00000600;
255 s
->regs
[R_FIFO_CFG5
] = 0X3FFFF;
260 static uint64_t emac_read(void *opaque
, hwaddr addr
, unsigned int size
)
262 MSF2EmacState
*s
= opaque
;
272 if (addr
>= ARRAY_SIZE(s
->regs
)) {
273 qemu_log_mask(LOG_GUEST_ERROR
,
274 "%s: Bad offset 0x%" HWADDR_PRIx
"\n", __func__
,
284 static void emac_write(void *opaque
, hwaddr addr
, uint64_t val64
,
287 MSF2EmacState
*s
= opaque
;
288 uint32_t value
= val64
;
295 s
->regs
[addr
] = value
;
296 if (value
& R_DMA_TX_CTL_EN_MASK
) {
301 s
->regs
[addr
] = value
;
302 if (value
& R_DMA_RX_CTL_EN_MASK
) {
303 s
->rx_desc
= s
->regs
[R_DMA_RX_DESC
];
304 qemu_flush_queued_packets(qemu_get_queue(s
->nic
));
308 s
->regs
[addr
] = value
;
309 if (value
& R_CFG1_RESET_MASK
) {
310 msf2_emac_do_reset(s
);
315 * For our implementation, turning on modules is instantaneous,
316 * so the states requested via the *ENREQ bits appear in the
317 * *ENRPLY bits immediately. Also the reset bits to reset PE-MCXMAC
318 * module are not emulated here since it deals with start of frames,
319 * inter-packet gap and control frames.
321 enreqbits
= extract32(value
, 8, 5);
322 s
->regs
[addr
] = deposit32(value
, 16, 5, enreqbits
);
326 qemu_log_mask(LOG_GUEST_ERROR
, "Tx Descriptor address should be"
327 " 32 bit aligned\n");
329 /* Ignore [1:0] bits */
330 s
->regs
[addr
] = value
& ~3;
334 qemu_log_mask(LOG_GUEST_ERROR
, "Rx Descriptor address should be"
335 " 32 bit aligned\n");
337 /* Ignore [1:0] bits */
338 s
->regs
[addr
] = value
& ~3;
340 case R_DMA_TX_STATUS
:
341 if (value
& R_DMA_TX_STATUS_UNDERRUN_MASK
) {
342 s
->regs
[addr
] &= ~R_DMA_TX_STATUS_UNDERRUN_MASK
;
344 if (value
& R_DMA_TX_STATUS_PKT_SENT_MASK
) {
345 pktcnt
= FIELD_EX32(s
->regs
[addr
], DMA_TX_STATUS
, PKTCNT
);
347 s
->regs
[addr
] = FIELD_DP32(s
->regs
[addr
], DMA_TX_STATUS
,
350 s
->regs
[addr
] &= ~R_DMA_TX_STATUS_PKT_SENT_MASK
;
354 case R_DMA_RX_STATUS
:
355 if (value
& R_DMA_RX_STATUS_OVERFLOW_MASK
) {
356 s
->regs
[addr
] &= ~R_DMA_RX_STATUS_OVERFLOW_MASK
;
358 if (value
& R_DMA_RX_STATUS_PKT_RCVD_MASK
) {
359 pktcnt
= FIELD_EX32(s
->regs
[addr
], DMA_RX_STATUS
, PKTCNT
);
361 s
->regs
[addr
] = FIELD_DP32(s
->regs
[addr
], DMA_RX_STATUS
,
364 s
->regs
[addr
] &= ~R_DMA_RX_STATUS_PKT_RCVD_MASK
;
371 if (value
& R_MII_CMD_READ_MASK
) {
372 s
->regs
[R_MII_STS
] = read_from_phy(s
);
376 s
->regs
[addr
] = value
;
380 s
->regs
[addr
] = value
;
382 * R_STA1 [31:24] : octet 1 of mac address
383 * R_STA1 [23:16] : octet 2 of mac address
384 * R_STA1 [15:8] : octet 3 of mac address
385 * R_STA1 [7:0] : octet 4 of mac address
387 stl_be_p(s
->mac_addr
, value
);
390 s
->regs
[addr
] = value
;
392 * R_STA2 [31:24] : octet 5 of mac address
393 * R_STA2 [23:16] : octet 6 of mac address
395 stw_be_p(s
->mac_addr
+ 4, value
>> 16);
398 if (addr
>= ARRAY_SIZE(s
->regs
)) {
399 qemu_log_mask(LOG_GUEST_ERROR
,
400 "%s: Bad offset 0x%" HWADDR_PRIx
"\n", __func__
,
404 s
->regs
[addr
] = value
;
410 static const MemoryRegionOps emac_ops
= {
413 .endianness
= DEVICE_NATIVE_ENDIAN
,
415 .min_access_size
= 4,
420 static bool emac_can_rx(NetClientState
*nc
)
422 MSF2EmacState
*s
= qemu_get_nic_opaque(nc
);
424 return (s
->regs
[R_CFG1
] & R_CFG1_RX_EN_MASK
) &&
425 (s
->regs
[R_DMA_RX_CTL
] & R_DMA_RX_CTL_EN_MASK
);
428 static bool addr_filter_ok(MSF2EmacState
*s
, const uint8_t *buf
)
430 /* The broadcast MAC address: FF:FF:FF:FF:FF:FF */
431 const uint8_t broadcast_addr
[] = { 0xFF, 0xFF, 0xFF, 0xFF,
433 bool bcast_en
= true;
434 bool mcast_en
= true;
436 if (s
->regs
[R_FIFO_CFG5
] & R_FIFO_CFG5_BCAST_MASK
) {
437 bcast_en
= true; /* Broadcast dont care for drop circuitry */
438 } else if (s
->regs
[R_FIFO_CFG4
] & R_FIFO_CFG4_BCAST_MASK
) {
442 if (s
->regs
[R_FIFO_CFG5
] & R_FIFO_CFG5_MCAST_MASK
) {
443 mcast_en
= true; /* Multicast dont care for drop circuitry */
444 } else if (s
->regs
[R_FIFO_CFG4
] & R_FIFO_CFG4_MCAST_MASK
) {
448 if (!memcmp(buf
, broadcast_addr
, sizeof(broadcast_addr
))) {
456 return !memcmp(buf
, s
->mac_addr
, sizeof(s
->mac_addr
));
459 static ssize_t
emac_rx(NetClientState
*nc
, const uint8_t *buf
, size_t size
)
461 MSF2EmacState
*s
= qemu_get_nic_opaque(nc
);
466 if (size
> (s
->regs
[R_MAX_FRAME_LENGTH
] & 0xFFFF)) {
469 if (!addr_filter_ok(s
, buf
)) {
473 emac_load_desc(s
, &d
, s
->rx_desc
);
475 if (d
.pktsize
& EMPTY_MASK
) {
476 address_space_write(&s
->dma_as
, d
.pktaddr
, MEMTXATTRS_UNSPECIFIED
,
477 buf
, size
& PKT_SIZE
);
478 d
.pktsize
= size
& PKT_SIZE
;
479 emac_store_desc(s
, &d
, s
->rx_desc
);
480 /* update received packets count */
481 status
= s
->regs
[R_DMA_RX_STATUS
];
482 pktcnt
= FIELD_EX32(status
, DMA_RX_STATUS
, PKTCNT
);
484 s
->regs
[R_DMA_RX_STATUS
] = FIELD_DP32(status
, DMA_RX_STATUS
,
486 s
->regs
[R_DMA_RX_STATUS
] |= R_DMA_RX_STATUS_PKT_RCVD_MASK
;
489 s
->regs
[R_DMA_RX_CTL
] &= ~R_DMA_RX_CTL_EN_MASK
;
490 s
->regs
[R_DMA_RX_STATUS
] |= R_DMA_RX_STATUS_OVERFLOW_MASK
;
496 static void msf2_emac_reset(DeviceState
*dev
)
498 MSF2EmacState
*s
= MSS_EMAC(dev
);
500 msf2_emac_do_reset(s
);
503 static void emac_set_link(NetClientState
*nc
)
505 MSF2EmacState
*s
= qemu_get_nic_opaque(nc
);
507 msf2_phy_update_link(s
);
510 static NetClientInfo net_msf2_emac_info
= {
511 .type
= NET_CLIENT_DRIVER_NIC
,
512 .size
= sizeof(NICState
),
513 .can_receive
= emac_can_rx
,
515 .link_status_changed
= emac_set_link
,
518 static void msf2_emac_realize(DeviceState
*dev
, Error
**errp
)
520 MSF2EmacState
*s
= MSS_EMAC(dev
);
523 error_setg(errp
, "MSS_EMAC 'ahb-bus' link not set");
527 address_space_init(&s
->dma_as
, s
->dma_mr
, "emac-ahb");
529 qemu_macaddr_default_if_unset(&s
->conf
.macaddr
);
530 s
->nic
= qemu_new_nic(&net_msf2_emac_info
, &s
->conf
,
531 object_get_typename(OBJECT(dev
)), dev
->id
, s
);
532 qemu_format_nic_info_str(qemu_get_queue(s
->nic
), s
->conf
.macaddr
.a
);
535 static void msf2_emac_init(Object
*obj
)
537 MSF2EmacState
*s
= MSS_EMAC(obj
);
539 sysbus_init_irq(SYS_BUS_DEVICE(obj
), &s
->irq
);
541 memory_region_init_io(&s
->mmio
, obj
, &emac_ops
, s
,
542 "msf2-emac", R_MAX
* 4);
543 sysbus_init_mmio(SYS_BUS_DEVICE(obj
), &s
->mmio
);
546 static Property msf2_emac_properties
[] = {
547 DEFINE_PROP_LINK("ahb-bus", MSF2EmacState
, dma_mr
,
548 TYPE_MEMORY_REGION
, MemoryRegion
*),
549 DEFINE_NIC_PROPERTIES(MSF2EmacState
, conf
),
550 DEFINE_PROP_END_OF_LIST(),
553 static const VMStateDescription vmstate_msf2_emac
= {
554 .name
= TYPE_MSS_EMAC
,
556 .minimum_version_id
= 1,
557 .fields
= (VMStateField
[]) {
558 VMSTATE_UINT8_ARRAY(mac_addr
, MSF2EmacState
, ETH_ALEN
),
559 VMSTATE_UINT32(rx_desc
, MSF2EmacState
),
560 VMSTATE_UINT16_ARRAY(phy_regs
, MSF2EmacState
, PHY_MAX_REGS
),
561 VMSTATE_UINT32_ARRAY(regs
, MSF2EmacState
, R_MAX
),
562 VMSTATE_END_OF_LIST()
566 static void msf2_emac_class_init(ObjectClass
*klass
, void *data
)
568 DeviceClass
*dc
= DEVICE_CLASS(klass
);
570 dc
->realize
= msf2_emac_realize
;
571 dc
->reset
= msf2_emac_reset
;
572 dc
->vmsd
= &vmstate_msf2_emac
;
573 device_class_set_props(dc
, msf2_emac_properties
);
576 static const TypeInfo msf2_emac_info
= {
577 .name
= TYPE_MSS_EMAC
,
578 .parent
= TYPE_SYS_BUS_DEVICE
,
579 .instance_size
= sizeof(MSF2EmacState
),
580 .instance_init
= msf2_emac_init
,
581 .class_init
= msf2_emac_class_init
,
584 static void msf2_emac_register_types(void)
586 type_register_static(&msf2_emac_info
);
589 type_init(msf2_emac_register_types
)