summaryrefslogtreecommitdiffstats
path: root/qemu/roms/u-boot/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/u-boot/drivers/net')
-rw-r--r--qemu/roms/u-boot/drivers/net/4xx_enet.c2059
-rw-r--r--qemu/roms/u-boot/drivers/net/8390.h124
-rw-r--r--qemu/roms/u-boot/drivers/net/Makefile66
-rw-r--r--qemu/roms/u-boot/drivers/net/altera_tse.c971
-rw-r--r--qemu/roms/u-boot/drivers/net/altera_tse.h492
-rw-r--r--qemu/roms/u-boot/drivers/net/armada100_fec.c726
-rw-r--r--qemu/roms/u-boot/drivers/net/armada100_fec.h209
-rw-r--r--qemu/roms/u-boot/drivers/net/at91_emac.c508
-rw-r--r--qemu/roms/u-boot/drivers/net/ax88180.c757
-rw-r--r--qemu/roms/u-boot/drivers/net/ax88180.h396
-rw-r--r--qemu/roms/u-boot/drivers/net/ax88796.c144
-rw-r--r--qemu/roms/u-boot/drivers/net/ax88796.h67
-rw-r--r--qemu/roms/u-boot/drivers/net/bfin_mac.c498
-rw-r--r--qemu/roms/u-boot/drivers/net/bfin_mac.h65
-rw-r--r--qemu/roms/u-boot/drivers/net/calxedaxgmac.c544
-rw-r--r--qemu/roms/u-boot/drivers/net/cpsw.c1020
-rw-r--r--qemu/roms/u-boot/drivers/net/cs8900.c320
-rw-r--r--qemu/roms/u-boot/drivers/net/cs8900.h249
-rw-r--r--qemu/roms/u-boot/drivers/net/davinci_emac.c894
-rw-r--r--qemu/roms/u-boot/drivers/net/davinci_emac.h303
-rw-r--r--qemu/roms/u-boot/drivers/net/dc2114x.c760
-rw-r--r--qemu/roms/u-boot/drivers/net/designware.c449
-rw-r--r--qemu/roms/u-boot/drivers/net/designware.h236
-rw-r--r--qemu/roms/u-boot/drivers/net/dm9000x.c643
-rw-r--r--qemu/roms/u-boot/drivers/net/dm9000x.h140
-rw-r--r--qemu/roms/u-boot/drivers/net/dnet.c392
-rw-r--r--qemu/roms/u-boot/drivers/net/dnet.h166
-rw-r--r--qemu/roms/u-boot/drivers/net/e1000.c5307
-rw-r--r--qemu/roms/u-boot/drivers/net/e1000.h2601
-rw-r--r--qemu/roms/u-boot/drivers/net/e1000_spi.c577
-rw-r--r--qemu/roms/u-boot/drivers/net/eepro100.c931
-rw-r--r--qemu/roms/u-boot/drivers/net/enc28j60.c963
-rw-r--r--qemu/roms/u-boot/drivers/net/enc28j60.h238
-rw-r--r--qemu/roms/u-boot/drivers/net/ep93xx_eth.c639
-rw-r--r--qemu/roms/u-boot/drivers/net/ep93xx_eth.h127
-rw-r--r--qemu/roms/u-boot/drivers/net/ethoc.c511
-rw-r--r--qemu/roms/u-boot/drivers/net/fec_mxc.c1102
-rw-r--r--qemu/roms/u-boot/drivers/net/fec_mxc.h323
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/Makefile37
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/b4860.c75
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/dtsec.c168
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/eth.c712
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/fm.c420
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/fm.h148
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/init.c338
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/memac.c137
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/memac_phy.c145
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/p1023.c73
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/p4080.c99
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/p5020.c90
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/p5040.c107
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/t1040.c72
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/t2080.c93
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/t4240.c166
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/tgec.c106
-rw-r--r--qemu/roms/u-boot/drivers/net/fm/tgec_phy.c126
-rw-r--r--qemu/roms/u-boot/drivers/net/fsl_mcdmafec.c571
-rw-r--r--qemu/roms/u-boot/drivers/net/fsl_mdio.c110
-rw-r--r--qemu/roms/u-boot/drivers/net/ftgmac100.c583
-rw-r--r--qemu/roms/u-boot/drivers/net/ftgmac100.h243
-rw-r--r--qemu/roms/u-boot/drivers/net/ftmac100.c265
-rw-r--r--qemu/roms/u-boot/drivers/net/ftmac100.h142
-rw-r--r--qemu/roms/u-boot/drivers/net/ftmac110.c480
-rw-r--r--qemu/roms/u-boot/drivers/net/ftmac110.h176
-rw-r--r--qemu/roms/u-boot/drivers/net/greth.c670
-rw-r--r--qemu/roms/u-boot/drivers/net/greth.h81
-rw-r--r--qemu/roms/u-boot/drivers/net/keystone_net.c716
-rw-r--r--qemu/roms/u-boot/drivers/net/ks8695eth.c229
-rw-r--r--qemu/roms/u-boot/drivers/net/ks8851_mll.c633
-rw-r--r--qemu/roms/u-boot/drivers/net/ks8851_mll.h357
-rw-r--r--qemu/roms/u-boot/drivers/net/lan91c96.c804
-rw-r--r--qemu/roms/u-boot/drivers/net/lan91c96.h617
-rw-r--r--qemu/roms/u-boot/drivers/net/macb.c702
-rw-r--r--qemu/roms/u-boot/drivers/net/macb.h313
-rw-r--r--qemu/roms/u-boot/drivers/net/mcffec.c609
-rw-r--r--qemu/roms/u-boot/drivers/net/mcfmii.c315
-rw-r--r--qemu/roms/u-boot/drivers/net/mpc512x_fec.c754
-rw-r--r--qemu/roms/u-boot/drivers/net/mpc512x_fec.h98
-rw-r--r--qemu/roms/u-boot/drivers/net/mpc5xxx_fec.c1027
-rw-r--r--qemu/roms/u-boot/drivers/net/mpc5xxx_fec.h282
-rw-r--r--qemu/roms/u-boot/drivers/net/mvgbe.c788
-rw-r--r--qemu/roms/u-boot/drivers/net/mvgbe.h498
-rw-r--r--qemu/roms/u-boot/drivers/net/natsemi.c882
-rw-r--r--qemu/roms/u-boot/drivers/net/ne2000.c259
-rw-r--r--qemu/roms/u-boot/drivers/net/ne2000.h94
-rw-r--r--qemu/roms/u-boot/drivers/net/ne2000_base.c800
-rw-r--r--qemu/roms/u-boot/drivers/net/ne2000_base.h304
-rw-r--r--qemu/roms/u-boot/drivers/net/netconsole.c331
-rw-r--r--qemu/roms/u-boot/drivers/net/ns8382x.c851
-rw-r--r--qemu/roms/u-boot/drivers/net/pcnet.c542
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/Makefile26
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/atheros.c76
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/broadcom.c274
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/davicom.c84
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/et1011c.c101
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/generic_10g.c94
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/icplus.c80
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/lxt.c73
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/marvell.c524
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/micrel.c226
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/miiphybb.c364
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/mv88e61xx.c537
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/mv88e61xx.h61
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/mv88e6352.c302
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/natsemi.c119
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/phy.c817
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/realtek.c141
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/smsc.c79
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/teranetics.c112
-rw-r--r--qemu/roms/u-boot/drivers/net/phy/vitesse.c373
-rw-r--r--qemu/roms/u-boot/drivers/net/plb2800_eth.c373
-rw-r--r--qemu/roms/u-boot/drivers/net/rtl8139.c539
-rw-r--r--qemu/roms/u-boot/drivers/net/rtl8169.c967
-rw-r--r--qemu/roms/u-boot/drivers/net/sh_eth.c655
-rw-r--r--qemu/roms/u-boot/drivers/net/sh_eth.h624
-rw-r--r--qemu/roms/u-boot/drivers/net/smc91111.c1355
-rw-r--r--qemu/roms/u-boot/drivers/net/smc91111.h789
-rw-r--r--qemu/roms/u-boot/drivers/net/smc911x.c282
-rw-r--r--qemu/roms/u-boot/drivers/net/smc911x.h500
-rw-r--r--qemu/roms/u-boot/drivers/net/sunxi_wemac.c525
-rw-r--r--qemu/roms/u-boot/drivers/net/tsec.c688
-rw-r--r--qemu/roms/u-boot/drivers/net/tsi108_eth.c1016
-rw-r--r--qemu/roms/u-boot/drivers/net/uli526x.c996
-rw-r--r--qemu/roms/u-boot/drivers/net/vsc7385.c97
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_axi_emac.c656
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_emaclite.c392
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_ll_temac.c402
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_ll_temac.h307
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_ll_temac_fifo.c139
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_ll_temac_fifo.h118
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_ll_temac_mdio.c177
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_ll_temac_mdio.h50
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_ll_temac_sdma.c366
-rw-r--r--qemu/roms/u-boot/drivers/net/xilinx_ll_temac_sdma.h277
-rw-r--r--qemu/roms/u-boot/drivers/net/zynq_gem.c580
135 files changed, 63088 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/drivers/net/4xx_enet.c b/qemu/roms/u-boot/drivers/net/4xx_enet.c
new file mode 100644
index 000000000..381ec4286
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/4xx_enet.c
@@ -0,0 +1,2059 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0 IBM-pibs
+ */
+/*-----------------------------------------------------------------------------+
+ *
+ * File Name: enetemac.c
+ *
+ * Function: Device driver for the ethernet EMAC3 macro on the 405GP.
+ *
+ * Author: Mark Wisner
+ *
+ * Change Activity-
+ *
+ * Date Description of Change BY
+ * --------- --------------------- ---
+ * 05-May-99 Created MKW
+ * 27-Jun-99 Clean up JWB
+ * 16-Jul-99 Added MAL error recovery and better IP packet handling MKW
+ * 29-Jul-99 Added Full duplex support MKW
+ * 06-Aug-99 Changed names for Mal CR reg MKW
+ * 23-Aug-99 Turned off SYE when running at 10Mbs MKW
+ * 24-Aug-99 Marked descriptor empty after call_xlc MKW
+ * 07-Sep-99 Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16 MCG
+ * to avoid chaining maximum sized packets. Push starting
+ * RX descriptor address up to the next cache line boundary.
+ * 16-Jan-00 Added support for booting with IP of 0x0 MKW
+ * 15-Mar-00 Updated enetInit() to enable broadcast addresses in the
+ * EMAC0_RXM register. JWB
+ * 12-Mar-01 anne-sophie.harnois@nextream.fr
+ * - Variables are compatible with those already defined in
+ * include/net.h
+ * - Receive buffer descriptor ring is used to send buffers
+ * to the user
+ * - Info print about send/received/handled packet number if
+ * INFO_405_ENET is set
+ * 17-Apr-01 stefan.roese@esd-electronics.com
+ * - MAL reset in "eth_halt" included
+ * - Enet speed and duplex output now in one line
+ * 08-May-01 stefan.roese@esd-electronics.com
+ * - MAL error handling added (eth_init called again)
+ * 13-Nov-01 stefan.roese@esd-electronics.com
+ * - Set IST bit in EMAC0_MR1 reg upon 100MBit or full duplex
+ * 04-Jan-02 stefan.roese@esd-electronics.com
+ * - Wait for PHY auto negotiation to complete added
+ * 06-Feb-02 stefan.roese@esd-electronics.com
+ * - Bug fixed in waiting for auto negotiation to complete
+ * 26-Feb-02 stefan.roese@esd-electronics.com
+ * - rx and tx buffer descriptors now allocated (no fixed address
+ * used anymore)
+ * 17-Jun-02 stefan.roese@esd-electronics.com
+ * - MAL error debug printf 'M' removed (rx de interrupt may
+ * occur upon many incoming packets with only 4 rx buffers).
+ *-----------------------------------------------------------------------------*
+ * 17-Nov-03 travis.sawyer@sandburst.com
+ * - ported from 405gp_enet.c to utilized upto 4 EMAC ports
+ * in the 440GX. This port should work with the 440GP
+ * (2 EMACs) also
+ * 15-Aug-05 sr@denx.de
+ * - merged 405gp_enet.c and 440gx_enet.c to generic 4xx_enet.c
+ now handling all 4xx cpu's.
+ *-----------------------------------------------------------------------------*/
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <commproc.h>
+#include <asm/ppc4xx.h>
+#include <asm/ppc4xx-emac.h>
+#include <asm/ppc4xx-mal.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <linux/compiler.h>
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */
+#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* 5000 ms autonegotiate timeout */
+
+/* Ethernet Transmit and Receive Buffers */
+/* AS.HARNOIS
+ * In the same way ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from
+ * PKTSIZE and PKTSIZE_ALIGN (include/net.h)
+ */
+#define ENET_MAX_MTU PKTSIZE
+#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN
+
+/*-----------------------------------------------------------------------------+
+ * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
+ * Interrupt Controller).
+ *-----------------------------------------------------------------------------*/
+#define ETH_IRQ_NUM(dev) (VECNUM_ETH0 + ((dev) * VECNUM_ETH1_OFFS))
+
+#if defined(CONFIG_HAS_ETH3)
+#if !defined(CONFIG_440GX)
+#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)) || \
+ UIC_MASK(ETH_IRQ_NUM(2)) || UIC_MASK(ETH_IRQ_NUM(3)))
+#else
+/* Unfortunately 440GX spreads EMAC interrupts on multiple UIC's */
+#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)))
+#define UIC_ETHxB (UIC_MASK(ETH_IRQ_NUM(2)) || UIC_MASK(ETH_IRQ_NUM(3)))
+#endif /* !defined(CONFIG_440GX) */
+#elif defined(CONFIG_HAS_ETH2)
+#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)) || \
+ UIC_MASK(ETH_IRQ_NUM(2)))
+#elif defined(CONFIG_HAS_ETH1)
+#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)))
+#else
+#define UIC_ETHx UIC_MASK(ETH_IRQ_NUM(0))
+#endif
+
+/*
+ * Define a default version for UIC_ETHxB for non 440GX so that we can
+ * use common code for all 4xx variants
+ */
+#if !defined(UIC_ETHxB)
+#define UIC_ETHxB 0
+#endif
+
+#define UIC_MAL_SERR UIC_MASK(VECNUM_MAL_SERR)
+#define UIC_MAL_TXDE UIC_MASK(VECNUM_MAL_TXDE)
+#define UIC_MAL_RXDE UIC_MASK(VECNUM_MAL_RXDE)
+#define UIC_MAL_TXEOB UIC_MASK(VECNUM_MAL_TXEOB)
+#define UIC_MAL_RXEOB UIC_MASK(VECNUM_MAL_RXEOB)
+
+#define MAL_UIC_ERR (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)
+#define MAL_UIC_DEF (UIC_MAL_RXEOB | MAL_UIC_ERR)
+
+/*
+ * We have 3 different interrupt types:
+ * - MAL interrupts indicating successful transfer
+ * - MAL error interrupts indicating MAL related errors
+ * - EMAC interrupts indicating EMAC related errors
+ *
+ * All those interrupts can be on different UIC's, but since
+ * now at least all interrupts from one type are on the same
+ * UIC. Only exception is 440GX where the EMAC interrupts are
+ * spread over two UIC's!
+ */
+#if defined(CONFIG_440GX)
+#define UIC_BASE_MAL UIC1_DCR_BASE
+#define UIC_BASE_MAL_ERR UIC2_DCR_BASE
+#define UIC_BASE_EMAC UIC2_DCR_BASE
+#define UIC_BASE_EMAC_B UIC3_DCR_BASE
+#else
+#define UIC_BASE_MAL (UIC0_DCR_BASE + (UIC_NR(VECNUM_MAL_TXEOB) * 0x10))
+#define UIC_BASE_MAL_ERR (UIC0_DCR_BASE + (UIC_NR(VECNUM_MAL_SERR) * 0x10))
+#define UIC_BASE_EMAC (UIC0_DCR_BASE + (UIC_NR(ETH_IRQ_NUM(0)) * 0x10))
+#define UIC_BASE_EMAC_B (UIC0_DCR_BASE + (UIC_NR(ETH_IRQ_NUM(0)) * 0x10))
+#endif
+
+#undef INFO_4XX_ENET
+
+#define BI_PHYMODE_NONE 0
+#define BI_PHYMODE_ZMII 1
+#define BI_PHYMODE_RGMII 2
+#define BI_PHYMODE_GMII 3
+#define BI_PHYMODE_RTBI 4
+#define BI_PHYMODE_TBI 5
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+#define BI_PHYMODE_SMII 6
+#define BI_PHYMODE_MII 7
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define BI_PHYMODE_RMII 8
+#endif
+#endif
+#define BI_PHYMODE_SGMII 9
+
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+#define SDR0_MFR_ETH_CLK_SEL_V(n) ((0x01<<27) / (n+1))
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define SDR0_ETH_CFG_CLK_SEL_V(n) (0x01 << (8 + n))
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define MAL_RX_CHAN_MUL 8 /* 460EX/GT uses MAL channel 8 for EMAC1 */
+#else
+#define MAL_RX_CHAN_MUL 1
+#endif
+
+/*--------------------------------------------------------------------+
+ * Fixed PHY (PHY-less) support for Ethernet Ports.
+ *--------------------------------------------------------------------*/
+
+/*
+ * Some boards do not have a PHY for each ethernet port. These ports
+ * are known as Fixed PHY (or PHY-less) ports. For such ports, set
+ * the appropriate CONFIG_PHY_ADDR equal to CONFIG_FIXED_PHY and
+ * then define CONFIG_SYS_FIXED_PHY_PORTS to define what the speed and
+ * duplex should be for these ports in the board configuration
+ * file.
+ *
+ * For Example:
+ * #define CONFIG_FIXED_PHY 0xFFFFFFFF
+ *
+ * #define CONFIG_PHY_ADDR CONFIG_FIXED_PHY
+ * #define CONFIG_PHY1_ADDR 1
+ * #define CONFIG_PHY2_ADDR CONFIG_FIXED_PHY
+ * #define CONFIG_PHY3_ADDR 3
+ *
+ * #define CONFIG_SYS_FIXED_PHY_PORT(devnum,speed,duplex) \
+ * {devnum, speed, duplex},
+ *
+ * #define CONFIG_SYS_FIXED_PHY_PORTS \
+ * CONFIG_SYS_FIXED_PHY_PORT(0,1000,FULL) \
+ * CONFIG_SYS_FIXED_PHY_PORT(2,100,HALF)
+ */
+
+#ifndef CONFIG_FIXED_PHY
+#define CONFIG_FIXED_PHY 0xFFFFFFFF /* Fixed PHY (PHY-less) */
+#endif
+
+#ifndef CONFIG_SYS_FIXED_PHY_PORTS
+#define CONFIG_SYS_FIXED_PHY_PORTS /* default is an empty array */
+#endif
+
+struct fixed_phy_port {
+ unsigned int devnum; /* ethernet port */
+ unsigned int speed; /* specified speed 10,100 or 1000 */
+ unsigned int duplex; /* specified duplex FULL or HALF */
+};
+
+static const struct fixed_phy_port fixed_phy_port[] = {
+ CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */
+};
+
+/*-----------------------------------------------------------------------------+
+ * Global variables. TX and RX descriptors and buffers.
+ *-----------------------------------------------------------------------------*/
+
+/*
+ * Get count of EMAC devices (doesn't have to be the max. possible number
+ * supported by the cpu)
+ *
+ * CONFIG_BOARD_EMAC_COUNT added so now a "dynamic" way to configure the
+ * EMAC count is possible. As it is needed for the Kilauea/Haleakala
+ * 405EX/405EXr eval board, using the same binary.
+ */
+#if defined(CONFIG_BOARD_EMAC_COUNT)
+#define LAST_EMAC_NUM board_emac_count()
+#else /* CONFIG_BOARD_EMAC_COUNT */
+#if defined(CONFIG_HAS_ETH3)
+#define LAST_EMAC_NUM 4
+#elif defined(CONFIG_HAS_ETH2)
+#define LAST_EMAC_NUM 3
+#elif defined(CONFIG_HAS_ETH1)
+#define LAST_EMAC_NUM 2
+#else
+#define LAST_EMAC_NUM 1
+#endif
+#endif /* CONFIG_BOARD_EMAC_COUNT */
+
+/* normal boards start with EMAC0 */
+#if !defined(CONFIG_EMAC_NR_START)
+#define CONFIG_EMAC_NR_START 0
+#endif
+
+#define MAL_RX_DESC_SIZE 2048
+#define MAL_TX_DESC_SIZE 2048
+#define MAL_ALLOC_SIZE (MAL_TX_DESC_SIZE + MAL_RX_DESC_SIZE)
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes and externals.
+ *-----------------------------------------------------------------------------*/
+static void enet_rcv (struct eth_device *dev, unsigned long malisr);
+
+int enetInt (struct eth_device *dev);
+static void mal_err (struct eth_device *dev, unsigned long isr,
+ unsigned long uic, unsigned long maldef,
+ unsigned long mal_errr);
+static void emac_err (struct eth_device *dev, unsigned long isr);
+
+extern int phy_setup_aneg (char *devname, unsigned char addr);
+extern int emac4xx_miiphy_read (const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value);
+extern int emac4xx_miiphy_write (const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value);
+
+int board_emac_count(void);
+
+static void emac_loopback_enable(EMAC_4XX_HW_PST hw_p)
+{
+#if defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_405EX)
+ u32 val;
+
+ mfsdr(SDR0_MFR, val);
+ val |= SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
+ mtsdr(SDR0_MFR, val);
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ u32 val;
+
+ mfsdr(SDR0_ETH_CFG, val);
+ val |= SDR0_ETH_CFG_CLK_SEL_V(hw_p->devnum);
+ mtsdr(SDR0_ETH_CFG, val);
+#endif
+}
+
+static void emac_loopback_disable(EMAC_4XX_HW_PST hw_p)
+{
+#if defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_405EX)
+ u32 val;
+
+ mfsdr(SDR0_MFR, val);
+ val &= ~SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
+ mtsdr(SDR0_MFR, val);
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ u32 val;
+
+ mfsdr(SDR0_ETH_CFG, val);
+ val &= ~SDR0_ETH_CFG_CLK_SEL_V(hw_p->devnum);
+ mtsdr(SDR0_ETH_CFG, val);
+#endif
+}
+
+/*-----------------------------------------------------------------------------+
+| ppc_4xx_eth_halt
+| Disable MAL channel, and EMACn
++-----------------------------------------------------------------------------*/
+static void ppc_4xx_eth_halt (struct eth_device *dev)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+ u32 val = 10000;
+
+ out_be32((void *)EMAC0_IER + hw_p->hw_addr, 0x00000000); /* disable emac interrupts */
+
+ /* 1st reset MAL channel */
+ /* Note: writing a 0 to a channel has no effect */
+#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mtdcr (MAL0_TXCARR, (MAL_CR_MMSR >> (hw_p->devnum * 2)));
+#else
+ mtdcr (MAL0_TXCARR, (MAL_CR_MMSR >> hw_p->devnum));
+#endif
+ mtdcr (MAL0_RXCARR, (MAL_CR_MMSR >> hw_p->devnum));
+
+ /* wait for reset */
+ while (mfdcr (MAL0_RXCASR) & (MAL_CR_MMSR >> hw_p->devnum)) {
+ udelay (1000); /* Delay 1 MS so as not to hammer the register */
+ val--;
+ if (val == 0)
+ break;
+ }
+
+ /* provide clocks for EMAC internal loopback */
+ emac_loopback_enable(hw_p);
+
+ /* EMAC RESET */
+ out_be32((void *)EMAC0_MR0 + hw_p->hw_addr, EMAC_MR0_SRST);
+
+ /* remove clocks for EMAC internal loopback */
+ emac_loopback_disable(hw_p);
+
+#ifndef CONFIG_NETCONSOLE
+ hw_p->print_speed = 1; /* print speed message again next time */
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ /* don't bypass the TAHOE0/TAHOE1 cores for Linux */
+ mfsdr(SDR0_ETH_CFG, val);
+ val &= ~(SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS);
+ mtsdr(SDR0_ETH_CFG, val);
+#endif
+
+ return;
+}
+
+#if defined (CONFIG_440GX)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ unsigned long pfc1;
+ unsigned long zmiifer;
+ unsigned long rmiifer;
+
+ mfsdr(SDR0_PFC1, pfc1);
+ pfc1 = SDR0_PFC1_EPS_DECODE(pfc1);
+
+ zmiifer = 0;
+ rmiifer = 0;
+
+ switch (pfc1) {
+ case 1:
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ case 2:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ case 3:
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 4:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RGMII;
+ break;
+ case 5:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RGMII;
+ break;
+ case 6:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ break;
+ case 0:
+ default:
+ zmiifer = ZMII_FER_MII << ZMII_FER_V(devnum);
+ rmiifer = 0x0;
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ }
+
+ /* Ensure we setup mdio for this devnum and ONLY this devnum */
+ zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
+
+ out_be32((void *)ZMII0_FER, zmiifer);
+ out_be32((void *)RGMII_FER, rmiifer);
+
+ return ((int)pfc1);
+}
+#endif /* CONFIG_440_GX */
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ unsigned long zmiifer=0x0;
+ unsigned long pfc1;
+
+ mfsdr(SDR0_PFC1, pfc1);
+ pfc1 &= SDR0_PFC1_SELECT_MASK;
+
+ switch (pfc1) {
+ case SDR0_PFC1_SELECT_CONFIG_2:
+ /* 1 x GMII port */
+ out_be32((void *)ZMII0_FER, 0x00);
+ out_be32((void *)RGMII_FER, 0x00000037);
+ bis->bi_phymode[0] = BI_PHYMODE_GMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case SDR0_PFC1_SELECT_CONFIG_4:
+ /* 2 x RGMII ports */
+ out_be32((void *)ZMII0_FER, 0x00);
+ out_be32((void *)RGMII_FER, 0x00000055);
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ break;
+ case SDR0_PFC1_SELECT_CONFIG_6:
+ /* 2 x SMII ports */
+ out_be32((void *)ZMII0_FER,
+ ((ZMII_FER_SMII) << ZMII_FER_V(0)) |
+ ((ZMII_FER_SMII) << ZMII_FER_V(1)));
+ out_be32((void *)RGMII_FER, 0x00000000);
+ bis->bi_phymode[0] = BI_PHYMODE_SMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SMII;
+ break;
+ case SDR0_PFC1_SELECT_CONFIG_1_2:
+ /* only 1 x MII supported */
+ out_be32((void *)ZMII0_FER, (ZMII_FER_MII) << ZMII_FER_V(0));
+ out_be32((void *)RGMII_FER, 0x00000000);
+ bis->bi_phymode[0] = BI_PHYMODE_MII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ default:
+ break;
+ }
+
+ /* Ensure we setup mdio for this devnum and ONLY this devnum */
+ zmiifer = in_be32((void *)ZMII0_FER);
+ zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
+ out_be32((void *)ZMII0_FER, zmiifer);
+
+ return ((int)0x0);
+}
+#endif /* CONFIG_440EPX */
+
+#if defined(CONFIG_405EX)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ u32 rgmiifer = 0;
+
+ /*
+ * The 405EX(r)'s RGMII bridge can operate in one of several
+ * modes, only one of which (2 x RGMII) allows the
+ * simultaneous use of both EMACs on the 405EX.
+ */
+
+ switch (CONFIG_EMAC_PHY_MODE) {
+
+ case EMAC_PHY_MODE_NONE:
+ /* No ports */
+ rgmiifer |= RGMII_FER_DIS << 0;
+ rgmiifer |= RGMII_FER_DIS << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case EMAC_PHY_MODE_NONE_RGMII:
+ /* 1 x RGMII port on channel 0 */
+ rgmiifer |= RGMII_FER_RGMII << 0;
+ rgmiifer |= RGMII_FER_DIS << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case EMAC_PHY_MODE_RGMII_NONE:
+ /* 1 x RGMII port on channel 1 */
+ rgmiifer |= RGMII_FER_DIS << 0;
+ rgmiifer |= RGMII_FER_RGMII << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ break;
+ case EMAC_PHY_MODE_RGMII_RGMII:
+ /* 2 x RGMII ports */
+ rgmiifer |= RGMII_FER_RGMII << 0;
+ rgmiifer |= RGMII_FER_RGMII << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ break;
+ case EMAC_PHY_MODE_NONE_GMII:
+ /* 1 x GMII port on channel 0 */
+ rgmiifer |= RGMII_FER_GMII << 0;
+ rgmiifer |= RGMII_FER_DIS << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_GMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case EMAC_PHY_MODE_NONE_MII:
+ /* 1 x MII port on channel 0 */
+ rgmiifer |= RGMII_FER_MII << 0;
+ rgmiifer |= RGMII_FER_DIS << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_MII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case EMAC_PHY_MODE_GMII_NONE:
+ /* 1 x GMII port on channel 1 */
+ rgmiifer |= RGMII_FER_DIS << 0;
+ rgmiifer |= RGMII_FER_GMII << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_GMII;
+ break;
+ case EMAC_PHY_MODE_MII_NONE:
+ /* 1 x MII port on channel 1 */
+ rgmiifer |= RGMII_FER_DIS << 0;
+ rgmiifer |= RGMII_FER_MII << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_MII;
+ break;
+ default:
+ break;
+ }
+
+ /* Ensure we setup mdio for this devnum and ONLY this devnum */
+ rgmiifer = in_be32((void *)RGMII_FER);
+ rgmiifer |= (1 << (19-devnum));
+ out_be32((void *)RGMII_FER, rgmiifer);
+
+ return ((int)0x0);
+}
+#endif /* CONFIG_405EX */
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ u32 eth_cfg;
+ u32 zmiifer; /* ZMII0_FER reg. */
+ u32 rmiifer; /* RGMII0_FER reg. Bridge 0 */
+ u32 rmiifer1; /* RGMII0_FER reg. Bridge 1 */
+ int mode;
+
+ zmiifer = 0;
+ rmiifer = 0;
+ rmiifer1 = 0;
+
+#if defined(CONFIG_460EX)
+ mode = 9;
+ mfsdr(SDR0_ETH_CFG, eth_cfg);
+ if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
+ ((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0))
+ mode = 11; /* config SGMII */
+#else
+ mode = 10;
+ mfsdr(SDR0_ETH_CFG, eth_cfg);
+ if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
+ ((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0) &&
+ ((eth_cfg & SDR0_ETH_CFG_SGMII2_ENABLE) > 0))
+ mode = 12; /* config SGMII */
+#endif
+
+ /* TODO:
+ * NOTE: 460GT has 2 RGMII bridge cores:
+ * emac0 ------ RGMII0_BASE
+ * |
+ * emac1 -----+
+ *
+ * emac2 ------ RGMII1_BASE
+ * |
+ * emac3 -----+
+ *
+ * 460EX has 1 RGMII bridge core:
+ * and RGMII1_BASE is disabled
+ * emac0 ------ RGMII0_BASE
+ * |
+ * emac1 -----+
+ */
+
+ /*
+ * Right now only 2*RGMII is supported. Please extend when needed.
+ * sr - 2008-02-19
+ * Add SGMII support.
+ * vg - 2008-07-28
+ */
+ switch (mode) {
+ case 1:
+ /* 1 MII - 460EX */
+ /* GMC0 EMAC4_0, ZMII Bridge */
+ zmiifer |= ZMII_FER_MII << ZMII_FER_V(0);
+ bis->bi_phymode[0] = BI_PHYMODE_MII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 2:
+ /* 2 MII - 460GT */
+ /* GMC0 EMAC4_0, GMC1 EMAC4_2, ZMII Bridge */
+ zmiifer |= ZMII_FER_MII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_MII << ZMII_FER_V(2);
+ bis->bi_phymode[0] = BI_PHYMODE_MII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_MII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 3:
+ /* 2 RMII - 460EX */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, ZMII Bridge */
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
+ bis->bi_phymode[0] = BI_PHYMODE_RMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 4:
+ /* 4 RMII - 460GT */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, GMC1 EMAC4_2, GMC1, EMAC4_3 */
+ /* ZMII Bridge */
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_RMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RMII;
+ break;
+ case 5:
+ /* 2 SMII - 460EX */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, ZMII Bridge */
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ bis->bi_phymode[0] = BI_PHYMODE_SMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 6:
+ /* 4 SMII - 460GT */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, GMC0 EMAC4_3, GMC0 EMAC4_3 */
+ /* ZMII Bridge */
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_SMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SMII;
+ bis->bi_phymode[2] = BI_PHYMODE_SMII;
+ bis->bi_phymode[3] = BI_PHYMODE_SMII;
+ break;
+ case 7:
+ /* This is the default mode that we want for board bringup - Maple */
+ /* 1 GMII - 460EX */
+ /* GMC0 EMAC4_0, RGMII Bridge 0 */
+ rmiifer |= RGMII_FER_MDIO(0);
+
+ if (devnum == 0) {
+ rmiifer |= RGMII_FER_GMII << RGMII_FER_V(2); /* CH0CFG - EMAC0 */
+ bis->bi_phymode[0] = BI_PHYMODE_GMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ } else {
+ rmiifer |= RGMII_FER_GMII << RGMII_FER_V(3); /* CH1CFG - EMAC1 */
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_GMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ }
+ break;
+ case 8:
+ /* 2 GMII - 460GT */
+ /* GMC0 EMAC4_0, RGMII Bridge 0 */
+ /* GMC1 EMAC4_2, RGMII Bridge 1 */
+ rmiifer |= RGMII_FER_GMII << RGMII_FER_V(2); /* CH0CFG - EMAC0 */
+ rmiifer1 |= RGMII_FER_GMII << RGMII_FER_V(2); /* CH0CFG - EMAC2 */
+ rmiifer |= RGMII_FER_MDIO(0); /* enable MDIO - EMAC0 */
+ rmiifer1 |= RGMII_FER_MDIO(0); /* enable MDIO - EMAC2 */
+
+ bis->bi_phymode[0] = BI_PHYMODE_GMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_GMII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 9:
+ /* 2 RGMII - 460EX */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ rmiifer |= RGMII_FER_MDIO(0); /* enable MDIO - EMAC0 */
+
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 10:
+ /* 4 RGMII - 460GT */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */
+ /* GMC1 EMAC4_2, GMC1 EMAC4_3, RGMII Bridge 1 */
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ rmiifer1 |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ rmiifer1 |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RGMII;
+ break;
+ case 11:
+ /* 2 SGMII - 460EX */
+ bis->bi_phymode[0] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 12:
+ /* 3 SGMII - 460GT */
+ bis->bi_phymode[0] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[2] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ default:
+ break;
+ }
+
+ /* Set EMAC for MDIO */
+ mfsdr(SDR0_ETH_CFG, eth_cfg);
+ eth_cfg |= SDR0_ETH_CFG_MDIO_SEL_EMAC0;
+ mtsdr(SDR0_ETH_CFG, eth_cfg);
+
+ out_be32((void *)RGMII_FER, rmiifer);
+#if defined(CONFIG_460GT)
+ out_be32((void *)RGMII_FER + RGMII1_BASE_OFFSET, rmiifer1);
+#endif
+
+ /* bypass the TAHOE0/TAHOE1 cores for U-Boot */
+ mfsdr(SDR0_ETH_CFG, eth_cfg);
+ eth_cfg |= (SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS);
+ mtsdr(SDR0_ETH_CFG, eth_cfg);
+
+ return 0;
+}
+#endif /* CONFIG_460EX || CONFIG_460GT */
+
+static inline void *malloc_aligned(u32 size, u32 align)
+{
+ return (void *)(((u32)malloc(size + align) + align - 1) &
+ ~(align - 1));
+}
+
+static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
+{
+ int i;
+ unsigned long reg = 0;
+ unsigned long msr;
+ unsigned long speed;
+ unsigned long duplex;
+ unsigned long failsafe;
+ unsigned mode_reg;
+ unsigned short devnum;
+ unsigned short reg_short;
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ u32 opbfreq;
+ sys_info_t sysinfo;
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ __maybe_unused int ethgroup = -1;
+#endif
+#endif
+ u32 bd_cached;
+ u32 bd_uncached = 0;
+#ifdef CONFIG_4xx_DCACHE
+ static u32 last_used_ea = 0;
+#endif
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ int rgmii_channel;
+#endif
+
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ /* before doing anything, figure out if we have a MAC address */
+ /* if not, bail */
+ if (memcmp (dev->enetaddr, "\0\0\0\0\0\0", 6) == 0) {
+ printf("ERROR: ethaddr not set!\n");
+ return -1;
+ }
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ /* Need to get the OPB frequency so we can access the PHY */
+ get_sys_info (&sysinfo);
+#endif
+
+ msr = mfmsr ();
+ mtmsr (msr & ~(MSR_EE)); /* disable interrupts */
+
+ devnum = hw_p->devnum;
+
+#ifdef INFO_4XX_ENET
+ /* AS.HARNOIS
+ * We should have :
+ * hw_p->stats.pkts_handled <= hw_p->stats.pkts_rx <= hw_p->stats.pkts_handled+PKTBUFSRX
+ * In the most cases hw_p->stats.pkts_handled = hw_p->stats.pkts_rx, but it
+ * is possible that new packets (without relationship with
+ * current transfer) have got the time to arrived before
+ * netloop calls eth_halt
+ */
+ printf ("About preceeding transfer (eth%d):\n"
+ "- Sent packet number %d\n"
+ "- Received packet number %d\n"
+ "- Handled packet number %d\n",
+ hw_p->devnum,
+ hw_p->stats.pkts_tx,
+ hw_p->stats.pkts_rx, hw_p->stats.pkts_handled);
+
+ hw_p->stats.pkts_tx = 0;
+ hw_p->stats.pkts_rx = 0;
+ hw_p->stats.pkts_handled = 0;
+ hw_p->print_speed = 1; /* print speed message again next time */
+#endif
+
+ hw_p->tx_err_index = 0; /* Transmit Error Index for tx_err_log */
+ hw_p->rx_err_index = 0; /* Receive Error Index for rx_err_log */
+
+ hw_p->rx_slot = 0; /* MAL Receive Slot */
+ hw_p->rx_i_index = 0; /* Receive Interrupt Queue Index */
+ hw_p->rx_u_index = 0; /* Receive User Queue Index */
+
+ hw_p->tx_slot = 0; /* MAL Transmit Slot */
+ hw_p->tx_i_index = 0; /* Transmit Interrupt Queue Index */
+ hw_p->tx_u_index = 0; /* Transmit User Queue Index */
+
+#if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
+ /* set RMII mode */
+ /* NOTE: 440GX spec states that mode is mutually exclusive */
+ /* NOTE: Therefore, disable all other EMACS, since we handle */
+ /* NOTE: only one emac at a time */
+ reg = 0;
+ out_be32((void *)ZMII0_FER, 0);
+ udelay (100);
+
+#if defined(CONFIG_440GP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ out_be32((void *)ZMII0_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
+#elif defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
+#endif
+
+ out_be32((void *)ZMII0_SSR, ZMII0_SSR_SP << ZMII0_SSR_V(devnum));
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
+#if defined(CONFIG_405EX)
+ ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
+#endif
+
+ sync();
+
+ /* provide clocks for EMAC internal loopback */
+ emac_loopback_enable(hw_p);
+
+ /* EMAC RESET */
+ out_be32((void *)EMAC0_MR0 + hw_p->hw_addr, EMAC_MR0_SRST);
+
+ /* remove clocks for EMAC internal loopback */
+ emac_loopback_disable(hw_p);
+
+ failsafe = 1000;
+ while ((in_be32((void *)EMAC0_MR0 + hw_p->hw_addr) & (EMAC_MR0_SRST)) && failsafe) {
+ udelay (1000);
+ failsafe--;
+ }
+ if (failsafe <= 0)
+ printf("\nProblem resetting EMAC!\n");
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ /* Whack the M1 register */
+ mode_reg = 0x0;
+ mode_reg &= ~0x00000038;
+ opbfreq = sysinfo.freqOPB / 1000000;
+ if (opbfreq <= 50);
+ else if (opbfreq <= 66)
+ mode_reg |= EMAC_MR1_OBCI_66;
+ else if (opbfreq <= 83)
+ mode_reg |= EMAC_MR1_OBCI_83;
+ else if (opbfreq <= 100)
+ mode_reg |= EMAC_MR1_OBCI_100;
+ else
+ mode_reg |= EMAC_MR1_OBCI_GT100;
+
+ out_be32((void *)EMAC0_MR1 + hw_p->hw_addr, mode_reg);
+#endif /* defined(CONFIG_440GX) || defined(CONFIG_440SP) */
+
+#if defined(CONFIG_GPCS_PHY_ADDR) || defined(CONFIG_GPCS_PHY1_ADDR) || \
+ defined(CONFIG_GPCS_PHY2_ADDR) || defined(CONFIG_GPCS_PHY3_ADDR)
+ if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) {
+ /*
+ * In SGMII mode, GPCS access is needed for
+ * communication with the internal SGMII SerDes.
+ */
+ switch (devnum) {
+#if defined(CONFIG_GPCS_PHY_ADDR)
+ case 0:
+ reg = CONFIG_GPCS_PHY_ADDR;
+ break;
+#endif
+#if defined(CONFIG_GPCS_PHY1_ADDR)
+ case 1:
+ reg = CONFIG_GPCS_PHY1_ADDR;
+ break;
+#endif
+#if defined(CONFIG_GPCS_PHY2_ADDR)
+ case 2:
+ reg = CONFIG_GPCS_PHY2_ADDR;
+ break;
+#endif
+#if defined(CONFIG_GPCS_PHY3_ADDR)
+ case 3:
+ reg = CONFIG_GPCS_PHY3_ADDR;
+ break;
+#endif
+ }
+
+ mode_reg = in_be32((void *)EMAC0_MR1 + hw_p->hw_addr);
+ mode_reg |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_IPPA_SET(reg);
+ out_be32((void *)EMAC0_MR1 + hw_p->hw_addr, mode_reg);
+
+ /* Configure GPCS interface to recommended setting for SGMII */
+ miiphy_reset(dev->name, reg);
+ miiphy_write(dev->name, reg, 0x04, 0x8120); /* AsymPause, FDX */
+ miiphy_write(dev->name, reg, 0x07, 0x2801); /* msg_pg, toggle */
+ miiphy_write(dev->name, reg, 0x00, 0x0140); /* 1Gbps, FDX */
+ }
+#endif /* defined(CONFIG_GPCS_PHY_ADDR) */
+
+ /* wait for PHY to complete auto negotiation */
+ reg_short = 0;
+ switch (devnum) {
+ case 0:
+ reg = CONFIG_PHY_ADDR;
+ break;
+#if defined (CONFIG_PHY1_ADDR)
+ case 1:
+ reg = CONFIG_PHY1_ADDR;
+ break;
+#endif
+#if defined (CONFIG_PHY2_ADDR)
+ case 2:
+ reg = CONFIG_PHY2_ADDR;
+ break;
+#endif
+#if defined (CONFIG_PHY3_ADDR)
+ case 3:
+ reg = CONFIG_PHY3_ADDR;
+ break;
+#endif
+ default:
+ reg = CONFIG_PHY_ADDR;
+ break;
+ }
+
+ bis->bi_phynum[devnum] = reg;
+
+ if (reg == CONFIG_FIXED_PHY)
+ goto get_speed;
+
+#if defined(CONFIG_PHY_RESET)
+ /*
+ * Reset the phy, only if its the first time through
+ * otherwise, just check the speeds & feeds
+ */
+ if (hw_p->first_init == 0) {
+#if defined(CONFIG_M88E1111_PHY)
+ miiphy_write (dev->name, reg, 0x14, 0x0ce3);
+ miiphy_write (dev->name, reg, 0x18, 0x4101);
+ miiphy_write (dev->name, reg, 0x09, 0x0e00);
+ miiphy_write (dev->name, reg, 0x04, 0x01e1);
+#if defined(CONFIG_M88E1111_DISABLE_FIBER)
+ miiphy_read(dev->name, reg, 0x1b, &reg_short);
+ reg_short |= 0x8000;
+ miiphy_write(dev->name, reg, 0x1b, reg_short);
+#endif
+#endif
+#if defined(CONFIG_M88E1112_PHY)
+ if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) {
+ /*
+ * Marvell 88E1112 PHY needs to have the SGMII MAC
+ * interace (page 2) properly configured to
+ * communicate with the 460EX/GT GPCS interface.
+ */
+
+ /* Set access to Page 2 */
+ miiphy_write(dev->name, reg, 0x16, 0x0002);
+
+ miiphy_write(dev->name, reg, 0x00, 0x0040); /* 1Gbps */
+ miiphy_read(dev->name, reg, 0x1a, &reg_short);
+ reg_short |= 0x8000; /* bypass Auto-Negotiation */
+ miiphy_write(dev->name, reg, 0x1a, reg_short);
+ miiphy_reset(dev->name, reg); /* reset MAC interface */
+
+ /* Reset access to Page 0 */
+ miiphy_write(dev->name, reg, 0x16, 0x0000);
+ }
+#endif /* defined(CONFIG_M88E1112_PHY) */
+ miiphy_reset (dev->name, reg);
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+
+#if defined(CONFIG_CIS8201_PHY)
+ /*
+ * Cicada 8201 PHY needs to have an extended register whacked
+ * for RGMII mode.
+ */
+ if (((devnum == 2) || (devnum == 3)) && (4 == ethgroup)) {
+#if defined(CONFIG_CIS8201_SHORT_ETCH)
+ miiphy_write (dev->name, reg, 23, 0x1300);
+#else
+ miiphy_write (dev->name, reg, 23, 0x1000);
+#endif
+ /*
+ * Vitesse VSC8201/Cicada CIS8201 errata:
+ * Interoperability problem with Intel 82547EI phys
+ * This work around (provided by Vitesse) changes
+ * the default timer convergence from 8ms to 12ms
+ */
+ miiphy_write (dev->name, reg, 0x1f, 0x2a30);
+ miiphy_write (dev->name, reg, 0x08, 0x0200);
+ miiphy_write (dev->name, reg, 0x1f, 0x52b5);
+ miiphy_write (dev->name, reg, 0x02, 0x0004);
+ miiphy_write (dev->name, reg, 0x01, 0x0671);
+ miiphy_write (dev->name, reg, 0x00, 0x8fae);
+ miiphy_write (dev->name, reg, 0x1f, 0x2a30);
+ miiphy_write (dev->name, reg, 0x08, 0x0000);
+ miiphy_write (dev->name, reg, 0x1f, 0x0000);
+ /* end Vitesse/Cicada errata */
+ }
+#endif /* defined(CONFIG_CIS8201_PHY) */
+
+#if defined(CONFIG_ET1011C_PHY)
+ /*
+ * Agere ET1011c PHY needs to have an extended register whacked
+ * for RGMII mode.
+ */
+ if (((devnum == 2) || (devnum ==3)) && (4 == ethgroup)) {
+ miiphy_read (dev->name, reg, 0x16, &reg_short);
+ reg_short &= ~(0x7);
+ reg_short |= 0x6; /* RGMII DLL Delay*/
+ miiphy_write (dev->name, reg, 0x16, reg_short);
+
+ miiphy_read (dev->name, reg, 0x17, &reg_short);
+ reg_short &= ~(0x40);
+ miiphy_write (dev->name, reg, 0x17, reg_short);
+
+ miiphy_write(dev->name, reg, 0x1c, 0x74f0);
+ }
+#endif /* defined(CONFIG_ET1011C_PHY) */
+
+#endif /* defined(CONFIG_440GX) ... */
+ /* Start/Restart autonegotiation */
+ phy_setup_aneg (dev->name, reg);
+ udelay (1000);
+ }
+#endif /* defined(CONFIG_PHY_RESET) */
+
+ miiphy_read (dev->name, reg, MII_BMSR, &reg_short);
+
+ /*
+ * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
+ */
+ if ((reg_short & BMSR_ANEGCAPABLE)
+ && !(reg_short & BMSR_ANEGCOMPLETE)) {
+ puts ("Waiting for PHY auto negotiation to complete");
+ i = 0;
+ while (!(reg_short & BMSR_ANEGCOMPLETE)) {
+ /*
+ * Timeout reached ?
+ */
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts (" TIMEOUT !\n");
+ break;
+ }
+
+ if ((i++ % 1000) == 0) {
+ putc ('.');
+ }
+ udelay (1000); /* 1 ms */
+ miiphy_read (dev->name, reg, MII_BMSR, &reg_short);
+ }
+ puts (" done\n");
+ udelay (500000); /* another 500 ms (results in faster booting) */
+ }
+
+get_speed:
+ if (reg == CONFIG_FIXED_PHY) {
+ for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
+ if (devnum == fixed_phy_port[i].devnum) {
+ speed = fixed_phy_port[i].speed;
+ duplex = fixed_phy_port[i].duplex;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(fixed_phy_port)) {
+ printf("ERROR: PHY (%s) not configured correctly!\n",
+ dev->name);
+ return -1;
+ }
+ } else {
+ speed = miiphy_speed(dev->name, reg);
+ duplex = miiphy_duplex(dev->name, reg);
+ }
+
+ if (hw_p->print_speed) {
+ hw_p->print_speed = 0;
+ printf ("ENET Speed is %d Mbps - %s duplex connection (EMAC%d)\n",
+ (int) speed, (duplex == HALF) ? "HALF" : "FULL",
+ hw_p->devnum);
+ }
+
+#if defined(CONFIG_440) && \
+ !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
+ !defined(CONFIG_440EPX) && !defined(CONFIG_440GRX) && \
+ !defined(CONFIG_460EX) && !defined(CONFIG_460GT)
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mfsdr(SDR0_MFR, reg);
+ if (speed == 100) {
+ reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M;
+ } else {
+ reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M;
+ }
+ mtsdr(SDR0_MFR, reg);
+#endif
+
+ /* Set ZMII/RGMII speed according to the phy link speed */
+ reg = in_be32((void *)ZMII0_SSR);
+ if ( (speed == 100) || (speed == 1000) )
+ out_be32((void *)ZMII0_SSR, reg | (ZMII0_SSR_SP << ZMII0_SSR_V (devnum)));
+ else
+ out_be32((void *)ZMII0_SSR, reg & (~(ZMII0_SSR_SP << ZMII0_SSR_V (devnum))));
+
+ if ((devnum == 2) || (devnum == 3)) {
+ if (speed == 1000)
+ reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V (devnum));
+ else if (speed == 100)
+ reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V (devnum));
+ else if (speed == 10)
+ reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V (devnum));
+ else {
+ printf("Error in RGMII Speed\n");
+ return -1;
+ }
+ out_be32((void *)RGMII_SSR, reg);
+ }
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ if (devnum >= 2)
+ rgmii_channel = devnum - 2;
+ else
+ rgmii_channel = devnum;
+
+ if (speed == 1000)
+ reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V(rgmii_channel));
+ else if (speed == 100)
+ reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V(rgmii_channel));
+ else if (speed == 10)
+ reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V(rgmii_channel));
+ else {
+ printf("Error in RGMII Speed\n");
+ return -1;
+ }
+ out_be32((void *)RGMII_SSR, reg);
+#if defined(CONFIG_460GT)
+ if ((devnum == 2) || (devnum == 3))
+ out_be32((void *)RGMII_SSR + RGMII1_BASE_OFFSET, reg);
+#endif
+#endif
+
+ /* set the Mal configuration reg */
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ mtdcr (MAL0_CFG, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA |
+ MAL_CR_PLBLT_DEFAULT | MAL_CR_EOPIE | 0x00330000);
+#else
+ mtdcr (MAL0_CFG, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
+ /* Errata 1.12: MAL_1 -- Disable MAL bursting */
+ if (get_pvr() == PVR_440GP_RB) {
+ mtdcr (MAL0_CFG, mfdcr(MAL0_CFG) & ~MAL_CR_PLBB);
+ }
+#endif
+
+ /*
+ * Malloc MAL buffer desciptors, make sure they are
+ * aligned on cache line boundary size
+ * (401/403/IOP480 = 16, 405 = 32)
+ * and doesn't cross cache block boundaries.
+ */
+ if (hw_p->first_init == 0) {
+ debug("*** Allocating descriptor memory ***\n");
+
+ bd_cached = (u32)malloc_aligned(MAL_ALLOC_SIZE, 4096);
+ if (!bd_cached) {
+ printf("%s: Error allocating MAL descriptor buffers!\n", __func__);
+ return -1;
+ }
+
+#ifdef CONFIG_4xx_DCACHE
+ flush_dcache_range(bd_cached, bd_cached + MAL_ALLOC_SIZE);
+ if (!last_used_ea)
+#if defined(CONFIG_SYS_MEM_TOP_HIDE)
+ bd_uncached = bis->bi_memsize + CONFIG_SYS_MEM_TOP_HIDE;
+#else
+ bd_uncached = bis->bi_memsize;
+#endif
+ else
+ bd_uncached = last_used_ea + MAL_ALLOC_SIZE;
+
+ last_used_ea = bd_uncached;
+ program_tlb(bd_cached, bd_uncached, MAL_ALLOC_SIZE,
+ TLB_WORD2_I_ENABLE);
+#else
+ bd_uncached = bd_cached;
+#endif
+ hw_p->tx_phys = bd_cached;
+ hw_p->rx_phys = bd_cached + MAL_TX_DESC_SIZE;
+ hw_p->tx = (mal_desc_t *)(bd_uncached);
+ hw_p->rx = (mal_desc_t *)(bd_uncached + MAL_TX_DESC_SIZE);
+ debug("hw_p->tx=%p, hw_p->rx=%p\n", hw_p->tx, hw_p->rx);
+ }
+
+ for (i = 0; i < NUM_TX_BUFF; i++) {
+ hw_p->tx[i].ctrl = 0;
+ hw_p->tx[i].data_len = 0;
+ if (hw_p->first_init == 0)
+ hw_p->txbuf_ptr = malloc_aligned(MAL_ALLOC_SIZE,
+ L1_CACHE_BYTES);
+ hw_p->tx[i].data_ptr = hw_p->txbuf_ptr;
+ if ((NUM_TX_BUFF - 1) == i)
+ hw_p->tx[i].ctrl |= MAL_TX_CTRL_WRAP;
+ hw_p->tx_run[i] = -1;
+ debug("TX_BUFF %d @ 0x%08x\n", i, (u32)hw_p->tx[i].data_ptr);
+ }
+
+ for (i = 0; i < NUM_RX_BUFF; i++) {
+ hw_p->rx[i].ctrl = 0;
+ hw_p->rx[i].data_len = 0;
+ hw_p->rx[i].data_ptr = (char *)NetRxPackets[i];
+ if ((NUM_RX_BUFF - 1) == i)
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_WRAP;
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
+ hw_p->rx_ready[i] = -1;
+ debug("RX_BUFF %d @ 0x%08x\n", i, (u32)hw_p->rx[i].data_ptr);
+ }
+
+ reg = 0x00000000;
+
+ reg |= dev->enetaddr[0]; /* set high address */
+ reg = reg << 8;
+ reg |= dev->enetaddr[1];
+
+ out_be32((void *)EMAC0_IAH + hw_p->hw_addr, reg);
+
+ reg = 0x00000000;
+ reg |= dev->enetaddr[2]; /* set low address */
+ reg = reg << 8;
+ reg |= dev->enetaddr[3];
+ reg = reg << 8;
+ reg |= dev->enetaddr[4];
+ reg = reg << 8;
+ reg |= dev->enetaddr[5];
+
+ out_be32((void *)EMAC0_IAL + hw_p->hw_addr, reg);
+
+ switch (devnum) {
+ case 1:
+ /* setup MAL tx & rx channel pointers */
+#if defined (CONFIG_405EP) || defined (CONFIG_440EP) || defined (CONFIG_440GR)
+ mtdcr (MAL0_TXCTP2R, hw_p->tx_phys);
+#else
+ mtdcr (MAL0_TXCTP1R, hw_p->tx_phys);
+#endif
+#if defined(CONFIG_440)
+ mtdcr (MAL0_TXBADDR, 0x0);
+ mtdcr (MAL0_RXBADDR, 0x0);
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ mtdcr (MAL0_RXCTP8R, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (MAL0_RCBS8, ENET_MAX_MTU_ALIGNED / 16);
+#else
+ mtdcr (MAL0_RXCTP1R, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (MAL0_RCBS1, ENET_MAX_MTU_ALIGNED / 16);
+#endif
+ break;
+#if defined (CONFIG_440GX)
+ case 2:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (MAL0_TXBADDR, 0x0);
+ mtdcr (MAL0_RXBADDR, 0x0);
+ mtdcr (MAL0_TXCTP2R, hw_p->tx_phys);
+ mtdcr (MAL0_RXCTP2R, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (MAL0_RCBS2, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+ case 3:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (MAL0_TXBADDR, 0x0);
+ mtdcr (MAL0_TXCTP3R, hw_p->tx_phys);
+ mtdcr (MAL0_RXBADDR, 0x0);
+ mtdcr (MAL0_RXCTP3R, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (MAL0_RCBS3, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+#endif /* CONFIG_440GX */
+#if defined (CONFIG_460GT)
+ case 2:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (MAL0_TXBADDR, 0x0);
+ mtdcr (MAL0_RXBADDR, 0x0);
+ mtdcr (MAL0_TXCTP2R, hw_p->tx_phys);
+ mtdcr (MAL0_RXCTP16R, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (MAL0_RCBS16, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+ case 3:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (MAL0_TXBADDR, 0x0);
+ mtdcr (MAL0_RXBADDR, 0x0);
+ mtdcr (MAL0_TXCTP3R, hw_p->tx_phys);
+ mtdcr (MAL0_RXCTP24R, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (MAL0_RCBS24, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+#endif /* CONFIG_460GT */
+ case 0:
+ default:
+ /* setup MAL tx & rx channel pointers */
+#if defined(CONFIG_440)
+ mtdcr (MAL0_TXBADDR, 0x0);
+ mtdcr (MAL0_RXBADDR, 0x0);
+#endif
+ mtdcr (MAL0_TXCTP0R, hw_p->tx_phys);
+ mtdcr (MAL0_RXCTP0R, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (MAL0_RCBS0, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+ }
+
+ /* Enable MAL transmit and receive channels */
+#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mtdcr (MAL0_TXCASR, (MAL_TXRX_CASR >> (hw_p->devnum*2)));
+#else
+ mtdcr (MAL0_TXCASR, (MAL_TXRX_CASR >> hw_p->devnum));
+#endif
+ mtdcr (MAL0_RXCASR, (MAL_TXRX_CASR >> hw_p->devnum));
+
+ /* set transmit enable & receive enable */
+ out_be32((void *)EMAC0_MR0 + hw_p->hw_addr, EMAC_MR0_TXE | EMAC_MR0_RXE);
+
+ mode_reg = in_be32((void *)EMAC0_MR1 + hw_p->hw_addr);
+
+ /* set rx-/tx-fifo size */
+ mode_reg = (mode_reg & ~EMAC_MR1_FIFO_MASK) | EMAC_MR1_FIFO_SIZE;
+
+ /* set speed */
+ if (speed == _1000BASET) {
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ unsigned long pfc1;
+
+ mfsdr (SDR0_PFC1, pfc1);
+ pfc1 |= SDR0_PFC1_EM_1000;
+ mtsdr (SDR0_PFC1, pfc1);
+#endif
+ mode_reg = mode_reg | EMAC_MR1_MF_1000MBPS | EMAC_MR1_IST;
+ } else if (speed == _100BASET)
+ mode_reg = mode_reg | EMAC_MR1_MF_100MBPS | EMAC_MR1_IST;
+ else
+ mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */
+ if (duplex == FULL)
+ mode_reg = mode_reg | 0x80000000 | EMAC_MR1_IST;
+
+ out_be32((void *)EMAC0_MR1 + hw_p->hw_addr, mode_reg);
+
+ /* Enable broadcast and indvidual address */
+ /* TBS: enabling runts as some misbehaved nics will send runts */
+ out_be32((void *)EMAC0_RXM + hw_p->hw_addr, EMAC_RMR_BAE | EMAC_RMR_IAE);
+
+ /* we probably need to set the tx mode1 reg? maybe at tx time */
+
+ /* set transmit request threshold register */
+ out_be32((void *)EMAC0_TRTR + hw_p->hw_addr, 0x18000000); /* 256 byte threshold */
+
+ /* set receive low/high water mark register */
+#if defined(CONFIG_440)
+ /* 440s has a 64 byte burst length */
+ out_be32((void *)EMAC0_RX_HI_LO_WMARK + hw_p->hw_addr, 0x80009000);
+#else
+ /* 405s have a 16 byte burst length */
+ out_be32((void *)EMAC0_RX_HI_LO_WMARK + hw_p->hw_addr, 0x0f002000);
+#endif /* defined(CONFIG_440) */
+ out_be32((void *)EMAC0_TMR1 + hw_p->hw_addr, 0xf8640000);
+
+ /* Set fifo limit entry in tx mode 0 */
+ out_be32((void *)EMAC0_TMR0 + hw_p->hw_addr, 0x00000003);
+ /* Frame gap set */
+ out_be32((void *)EMAC0_I_FRAME_GAP_REG + hw_p->hw_addr, 0x00000008);
+
+ /* Set EMAC IER */
+ hw_p->emac_ier = EMAC_ISR_PTLE | EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE;
+ if (speed == _100BASET)
+ hw_p->emac_ier = hw_p->emac_ier | EMAC_ISR_SYE;
+
+ out_be32((void *)EMAC0_ISR + hw_p->hw_addr, 0xffffffff); /* clear pending interrupts */
+ out_be32((void *)EMAC0_IER + hw_p->hw_addr, hw_p->emac_ier);
+
+ if (hw_p->first_init == 0) {
+ /*
+ * Connect interrupt service routines
+ */
+ irq_install_handler(ETH_IRQ_NUM(hw_p->devnum),
+ (interrupt_handler_t *) enetInt, dev);
+ }
+
+ mtmsr (msr); /* enable interrupts again */
+
+ hw_p->bis = bis;
+ hw_p->first_init = 1;
+
+ return 0;
+}
+
+
+static int ppc_4xx_eth_send(struct eth_device *dev, void *ptr, int len)
+{
+ struct enet_frame *ef_ptr;
+ ulong time_start, time_now;
+ unsigned long temp_txm0;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ ef_ptr = (struct enet_frame *) ptr;
+
+ /*-----------------------------------------------------------------------+
+ * Copy in our address into the frame.
+ *-----------------------------------------------------------------------*/
+ (void) memcpy (ef_ptr->source_addr, dev->enetaddr, ENET_ADDR_LENGTH);
+
+ /*-----------------------------------------------------------------------+
+ * If frame is too long or too short, modify length.
+ *-----------------------------------------------------------------------*/
+ /* TBS: where does the fragment go???? */
+ if (len > ENET_MAX_MTU)
+ len = ENET_MAX_MTU;
+
+ /* memcpy ((void *) &tx_buff[tx_slot], (const void *) ptr, len); */
+ memcpy ((void *) hw_p->txbuf_ptr, (const void *) ptr, len);
+ flush_dcache_range((u32)hw_p->txbuf_ptr, (u32)hw_p->txbuf_ptr + len);
+
+ /*-----------------------------------------------------------------------+
+ * set TX Buffer busy, and send it
+ *-----------------------------------------------------------------------*/
+ hw_p->tx[hw_p->tx_slot].ctrl = (MAL_TX_CTRL_LAST |
+ EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP) &
+ ~(EMAC_TX_CTRL_ISA | EMAC_TX_CTRL_RSA);
+ if ((NUM_TX_BUFF - 1) == hw_p->tx_slot)
+ hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_WRAP;
+
+ hw_p->tx[hw_p->tx_slot].data_len = (short) len;
+ hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_READY;
+
+ sync();
+
+ out_be32((void *)EMAC0_TMR0 + hw_p->hw_addr,
+ in_be32((void *)EMAC0_TMR0 + hw_p->hw_addr) | EMAC_TMR0_GNP0);
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_tx++;
+#endif
+
+ /*-----------------------------------------------------------------------+
+ * poll unitl the packet is sent and then make sure it is OK
+ *-----------------------------------------------------------------------*/
+ time_start = get_timer (0);
+ while (1) {
+ temp_txm0 = in_be32((void *)EMAC0_TMR0 + hw_p->hw_addr);
+ /* loop until either TINT turns on or 3 seconds elapse */
+ if ((temp_txm0 & EMAC_TMR0_GNP0) != 0) {
+ /* transmit is done, so now check for errors
+ * If there is an error, an interrupt should
+ * happen when we return
+ */
+ time_now = get_timer (0);
+ if ((time_now - time_start) > 3000) {
+ return (-1);
+ }
+ } else {
+ return (len);
+ }
+ }
+}
+
+int enetInt (struct eth_device *dev)
+{
+ int serviced;
+ int rc = -1; /* default to not us */
+ u32 mal_isr;
+ u32 emac_isr = 0;
+ u32 mal_eob;
+ u32 uic_mal;
+ u32 uic_mal_err;
+ u32 uic_emac;
+ u32 uic_emac_b;
+ EMAC_4XX_HW_PST hw_p;
+
+ /*
+ * Because the mal is generic, we need to get the current
+ * eth device
+ */
+ dev = eth_get_dev();
+
+ hw_p = dev->priv;
+
+ /* enter loop that stays in interrupt code until nothing to service */
+ do {
+ serviced = 0;
+
+ uic_mal = mfdcr(UIC_BASE_MAL + UIC_MSR);
+ uic_mal_err = mfdcr(UIC_BASE_MAL_ERR + UIC_MSR);
+ uic_emac = mfdcr(UIC_BASE_EMAC + UIC_MSR);
+ uic_emac_b = mfdcr(UIC_BASE_EMAC_B + UIC_MSR);
+
+ if (!(uic_mal & (UIC_MAL_RXEOB | UIC_MAL_TXEOB))
+ && !(uic_mal_err & (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE))
+ && !(uic_emac & UIC_ETHx) && !(uic_emac_b & UIC_ETHxB)) {
+ /* not for us */
+ return (rc);
+ }
+
+ /* get and clear controller status interrupts */
+ /* look at MAL and EMAC error interrupts */
+ if (uic_mal_err & (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)) {
+ /* we have a MAL error interrupt */
+ mal_isr = mfdcr(MAL0_ESR);
+ mal_err(dev, mal_isr, uic_mal_err,
+ MAL_UIC_DEF, MAL_UIC_ERR);
+
+ /* clear MAL error interrupt status bits */
+ mtdcr(UIC_BASE_MAL_ERR + UIC_SR,
+ UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE);
+
+ return -1;
+ }
+
+ /* look for EMAC errors */
+ if ((uic_emac & UIC_ETHx) || (uic_emac_b & UIC_ETHxB)) {
+ emac_isr = in_be32((void *)EMAC0_ISR + hw_p->hw_addr);
+ emac_err(dev, emac_isr);
+
+ /* clear EMAC error interrupt status bits */
+ mtdcr(UIC_BASE_EMAC + UIC_SR, UIC_ETHx);
+ mtdcr(UIC_BASE_EMAC_B + UIC_SR, UIC_ETHxB);
+
+ return -1;
+ }
+
+ /* handle MAX TX EOB interrupt from a tx */
+ if (uic_mal & UIC_MAL_TXEOB) {
+ /* clear MAL interrupt status bits */
+ mal_eob = mfdcr(MAL0_TXEOBISR);
+ mtdcr(MAL0_TXEOBISR, mal_eob);
+ mtdcr(UIC_BASE_MAL + UIC_SR, UIC_MAL_TXEOB);
+
+ /* indicate that we serviced an interrupt */
+ serviced = 1;
+ rc = 0;
+ }
+
+ /* handle MAL RX EOB interrupt from a receive */
+ /* check for EOB on valid channels */
+ if (uic_mal & UIC_MAL_RXEOB) {
+ mal_eob = mfdcr(MAL0_RXEOBISR);
+ if (mal_eob &
+ (0x80000000 >> (hw_p->devnum * MAL_RX_CHAN_MUL))) {
+ /* push packet to upper layer */
+ enet_rcv(dev, emac_isr);
+
+ /* clear MAL interrupt status bits */
+ mtdcr(UIC_BASE_MAL + UIC_SR, UIC_MAL_RXEOB);
+
+ /* indicate that we serviced an interrupt */
+ serviced = 1;
+ rc = 0;
+ }
+ }
+#if defined(CONFIG_405EZ)
+ /*
+ * On 405EZ the RX-/TX-interrupts are coalesced into
+ * one IRQ bit in the UIC. We need to acknowledge the
+ * RX-/TX-interrupts in the SDR0_ICINTSTAT reg as well.
+ */
+ mtsdr(SDR0_ICINTSTAT,
+ SDR_ICRX_STAT | SDR_ICTX0_STAT | SDR_ICTX1_STAT);
+#endif /* defined(CONFIG_405EZ) */
+ } while (serviced);
+
+ return (rc);
+}
+
+/*-----------------------------------------------------------------------------+
+ * MAL Error Routine
+ *-----------------------------------------------------------------------------*/
+static void mal_err (struct eth_device *dev, unsigned long isr,
+ unsigned long uic, unsigned long maldef,
+ unsigned long mal_errr)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ mtdcr (MAL0_ESR, isr); /* clear interrupt */
+
+ /* clear DE interrupt */
+ mtdcr (MAL0_TXDEIR, 0xC0000000);
+ mtdcr (MAL0_RXDEIR, 0x80000000);
+
+#ifdef INFO_4XX_ENET
+ printf ("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx \n", isr, uic, maldef, mal_errr);
+#endif
+
+ eth_init (hw_p->bis); /* start again... */
+}
+
+/*-----------------------------------------------------------------------------+
+ * EMAC Error Routine
+ *-----------------------------------------------------------------------------*/
+static void emac_err (struct eth_device *dev, unsigned long isr)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ printf ("EMAC%d error occured.... ISR = %lx\n", hw_p->devnum, isr);
+ out_be32((void *)EMAC0_ISR + hw_p->hw_addr, isr);
+}
+
+/*-----------------------------------------------------------------------------+
+ * enet_rcv() handles the ethernet receive data
+ *-----------------------------------------------------------------------------*/
+static void enet_rcv (struct eth_device *dev, unsigned long malisr)
+{
+ unsigned long data_len;
+ unsigned long rx_eob_isr;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ int handled = 0;
+ int i;
+ int loop_count = 0;
+
+ rx_eob_isr = mfdcr (MAL0_RXEOBISR);
+ if ((0x80000000 >> (hw_p->devnum * MAL_RX_CHAN_MUL)) & rx_eob_isr) {
+ /* clear EOB */
+ mtdcr (MAL0_RXEOBISR, rx_eob_isr);
+
+ /* EMAC RX done */
+ while (1) { /* do all */
+ i = hw_p->rx_slot;
+
+ if ((MAL_RX_CTRL_EMPTY & hw_p->rx[i].ctrl)
+ || (loop_count >= NUM_RX_BUFF))
+ break;
+
+ loop_count++;
+ handled++;
+ data_len = (unsigned long) hw_p->rx[i].data_len & 0x0fff; /* Get len */
+ if (data_len) {
+ if (data_len > ENET_MAX_MTU) /* Check len */
+ data_len = 0;
+ else {
+ if (EMAC_RX_ERRORS & hw_p->rx[i].ctrl) { /* Check Errors */
+ data_len = 0;
+ hw_p->stats.rx_err_log[hw_p->
+ rx_err_index]
+ = hw_p->rx[i].ctrl;
+ hw_p->rx_err_index++;
+ if (hw_p->rx_err_index ==
+ MAX_ERR_LOG)
+ hw_p->rx_err_index =
+ 0;
+ } /* emac_erros */
+ } /* data_len < max mtu */
+ } /* if data_len */
+ if (!data_len) { /* no data */
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY; /* Free Recv Buffer */
+
+ hw_p->stats.data_len_err++; /* Error at Rx */
+ }
+
+ /* !data_len */
+ /* AS.HARNOIS */
+ /* Check if user has already eaten buffer */
+ /* if not => ERROR */
+ else if (hw_p->rx_ready[hw_p->rx_i_index] != -1) {
+ if (hw_p->is_receiving)
+ printf ("ERROR : Receive buffers are full!\n");
+ break;
+ } else {
+ hw_p->stats.rx_frames++;
+ hw_p->stats.rx += data_len;
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_rx++;
+#endif
+ /* AS.HARNOIS
+ * use ring buffer
+ */
+ hw_p->rx_ready[hw_p->rx_i_index] = i;
+ hw_p->rx_i_index++;
+ if (NUM_RX_BUFF == hw_p->rx_i_index)
+ hw_p->rx_i_index = 0;
+
+ hw_p->rx_slot++;
+ if (NUM_RX_BUFF == hw_p->rx_slot)
+ hw_p->rx_slot = 0;
+
+ /* AS.HARNOIS
+ * free receive buffer only when
+ * buffer has been handled (eth_rx)
+ rx[i].ctrl |= MAL_RX_CTRL_EMPTY;
+ */
+ } /* if data_len */
+ } /* while */
+ } /* if EMACK_RXCHL */
+}
+
+
+static int ppc_4xx_eth_rx (struct eth_device *dev)
+{
+ int length;
+ int user_index;
+ unsigned long msr;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ hw_p->is_receiving = 1; /* tell driver */
+
+ for (;;) {
+ /* AS.HARNOIS
+ * use ring buffer and
+ * get index from rx buffer desciptor queue
+ */
+ user_index = hw_p->rx_ready[hw_p->rx_u_index];
+ if (user_index == -1) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ msr = mfmsr ();
+ mtmsr (msr & ~(MSR_EE));
+
+ length = hw_p->rx[user_index].data_len & 0x0fff;
+
+ /* Pass the packet up to the protocol layers. */
+ /* NetReceive(NetRxPackets[rxIdx], length - 4); */
+ /* NetReceive(NetRxPackets[i], length); */
+ invalidate_dcache_range((u32)hw_p->rx[user_index].data_ptr,
+ (u32)hw_p->rx[user_index].data_ptr +
+ length - 4);
+ NetReceive (NetRxPackets[user_index], length - 4);
+ /* Free Recv Buffer */
+ hw_p->rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY;
+ /* Free rx buffer descriptor queue */
+ hw_p->rx_ready[hw_p->rx_u_index] = -1;
+ hw_p->rx_u_index++;
+ if (NUM_RX_BUFF == hw_p->rx_u_index)
+ hw_p->rx_u_index = 0;
+
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_handled++;
+#endif
+
+ mtmsr (msr); /* Enable IRQ's */
+ }
+
+ hw_p->is_receiving = 0; /* tell driver */
+
+ return length;
+}
+
+int ppc_4xx_eth_initialize (bd_t * bis)
+{
+ static int virgin = 0;
+ struct eth_device *dev;
+ int eth_num = 0;
+ EMAC_4XX_HW_PST hw = NULL;
+ u8 ethaddr[4 + CONFIG_EMAC_NR_START][6];
+ u32 hw_addr[4];
+ u32 mal_ier;
+
+#if defined(CONFIG_440GX)
+ unsigned long pfc1;
+
+ mfsdr (SDR0_PFC1, pfc1);
+ pfc1 &= ~(0x01e00000);
+ pfc1 |= 0x01200000;
+ mtsdr (SDR0_PFC1, pfc1);
+#endif
+
+ /* first clear all mac-addresses */
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++)
+ memcpy(ethaddr[eth_num], "\0\0\0\0\0\0", 6);
+
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+ int ethaddr_idx = eth_num + CONFIG_EMAC_NR_START;
+ switch (eth_num) {
+ default: /* fall through */
+ case 0:
+ eth_getenv_enetaddr("ethaddr", ethaddr[ethaddr_idx]);
+ hw_addr[eth_num] = 0x0;
+ break;
+#ifdef CONFIG_HAS_ETH1
+ case 1:
+ eth_getenv_enetaddr("eth1addr", ethaddr[ethaddr_idx]);
+ hw_addr[eth_num] = 0x100;
+ break;
+#endif
+#ifdef CONFIG_HAS_ETH2
+ case 2:
+ eth_getenv_enetaddr("eth2addr", ethaddr[ethaddr_idx]);
+#if defined(CONFIG_460GT)
+ hw_addr[eth_num] = 0x300;
+#else
+ hw_addr[eth_num] = 0x400;
+#endif
+ break;
+#endif
+#ifdef CONFIG_HAS_ETH3
+ case 3:
+ eth_getenv_enetaddr("eth3addr", ethaddr[ethaddr_idx]);
+#if defined(CONFIG_460GT)
+ hw_addr[eth_num] = 0x400;
+#else
+ hw_addr[eth_num] = 0x600;
+#endif
+ break;
+#endif
+ }
+ }
+
+ /* set phy num and mode */
+ bis->bi_phynum[0] = CONFIG_PHY_ADDR;
+ bis->bi_phymode[0] = 0;
+
+#if defined(CONFIG_PHY1_ADDR)
+ bis->bi_phynum[1] = CONFIG_PHY1_ADDR;
+ bis->bi_phymode[1] = 0;
+#endif
+#if defined(CONFIG_440GX)
+ bis->bi_phynum[2] = CONFIG_PHY2_ADDR;
+ bis->bi_phynum[3] = CONFIG_PHY3_ADDR;
+ bis->bi_phymode[2] = 2;
+ bis->bi_phymode[3] = 2;
+#endif
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_405EX)
+ ppc_4xx_eth_setup_bridge(0, bis);
+#endif
+
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+ /*
+ * See if we can actually bring up the interface,
+ * otherwise, skip it
+ */
+ if (memcmp (ethaddr[eth_num], "\0\0\0\0\0\0", 6) == 0) {
+ bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
+ continue;
+ }
+
+ /* Allocate device structure */
+ dev = (struct eth_device *) malloc (sizeof (*dev));
+ if (dev == NULL) {
+ printf ("ppc_4xx_eth_initialize: "
+ "Cannot allocate eth_device %d\n", eth_num);
+ return (-1);
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ /* Allocate our private use data */
+ hw = (EMAC_4XX_HW_PST) malloc (sizeof (*hw));
+ if (hw == NULL) {
+ printf ("ppc_4xx_eth_initialize: "
+ "Cannot allocate private hw data for eth_device %d",
+ eth_num);
+ free (dev);
+ return (-1);
+ }
+ memset(hw, 0, sizeof(*hw));
+
+ hw->hw_addr = hw_addr[eth_num];
+ memcpy (dev->enetaddr, ethaddr[eth_num], 6);
+ hw->devnum = eth_num;
+ hw->print_speed = 1;
+
+ sprintf (dev->name, "ppc_4xx_eth%d", eth_num - CONFIG_EMAC_NR_START);
+ dev->priv = (void *) hw;
+ dev->init = ppc_4xx_eth_init;
+ dev->halt = ppc_4xx_eth_halt;
+ dev->send = ppc_4xx_eth_send;
+ dev->recv = ppc_4xx_eth_rx;
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name,
+ emac4xx_miiphy_read, emac4xx_miiphy_write);
+#endif
+
+ if (0 == virgin) {
+ /* set the MAL IER ??? names may change with new spec ??? */
+#if defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ mal_ier =
+ MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE |
+ MAL_IER_DE | MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE ;
+#else
+ mal_ier =
+ MAL_IER_DE | MAL_IER_NE | MAL_IER_TE |
+ MAL_IER_OPBE | MAL_IER_PLBE;
+#endif
+ mtdcr (MAL0_ESR, 0xffffffff); /* clear pending interrupts */
+ mtdcr (MAL0_TXDEIR, 0xffffffff); /* clear pending interrupts */
+ mtdcr (MAL0_RXDEIR, 0xffffffff); /* clear pending interrupts */
+ mtdcr (MAL0_IER, mal_ier);
+
+ /* install MAL interrupt handler */
+ irq_install_handler (VECNUM_MAL_SERR,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MAL_TXEOB,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MAL_RXEOB,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MAL_TXDE,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MAL_RXDE,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ virgin = 1;
+ }
+ } /* end for each supported device */
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/8390.h b/qemu/roms/u-boot/drivers/net/8390.h
new file mode 100644
index 000000000..f087217ed
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/8390.h
@@ -0,0 +1,124 @@
+/*
+
+Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+*/
+
+/* Generic NS8390 register definitions. */
+/* This file is part of Donald Becker's 8390 drivers, and is distributed
+ under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
+ Some of these names and comments originated from the Crynwr
+ packet drivers, which are distributed under the GPL. */
+
+#ifndef _8390_h
+#define _8390_h
+
+/* Some generic ethernet register configurations. */
+#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
+#define E8390_RX_IRQ_MASK 0x5
+#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
+#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
+#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
+#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
+
+/* Register accessed at EN_CMD, the 8390 base addr. */
+#define E8390_STOP 0x01 /* Stop and reset the chip */
+#define E8390_START 0x02 /* Start the chip, clear reset */
+#define E8390_TRANS 0x04 /* Transmit a frame */
+#define E8390_RREAD 0x08 /* Remote read */
+#define E8390_RWRITE 0x10 /* Remote write */
+#define E8390_NODMA 0x20 /* Remote DMA */
+#define E8390_PAGE0 0x00 /* Select page chip registers */
+#define E8390_PAGE1 0x40 /* using the two high-order bits */
+#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
+
+/*
+ * Only generate indirect loads given a machine that needs them.
+ * - removed AMIGA_PCMCIA from this list, handled as ISA io now
+ */
+
+#define n2k_inb(port) (*((volatile unsigned char *)(port+CONFIG_DRIVER_NE2000_BASE)))
+#define n2k_outb(val,port) (*((volatile unsigned char *)(port+CONFIG_DRIVER_NE2000_BASE)) = val)
+
+#define EI_SHIFT(x) (x)
+
+#define E8390_CMD EI_SHIFT(0x00) /* The command register (for all pages) */
+/* Page 0 register offsets. */
+#define EN0_CLDALO EI_SHIFT(0x01) /* Low byte of current local dma addr RD */
+#define EN0_STARTPG EI_SHIFT(0x01) /* Starting page of ring bfr WR */
+#define EN0_CLDAHI EI_SHIFT(0x02) /* High byte of current local dma addr RD */
+#define EN0_STOPPG EI_SHIFT(0x02) /* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY EI_SHIFT(0x03) /* Boundary page of ring bfr RD WR */
+#define EN0_TSR EI_SHIFT(0x04) /* Transmit status reg RD */
+#define EN0_TPSR EI_SHIFT(0x04) /* Transmit starting page WR */
+#define EN0_NCR EI_SHIFT(0x05) /* Number of collision reg RD */
+#define EN0_TCNTLO EI_SHIFT(0x05) /* Low byte of tx byte count WR */
+#define EN0_FIFO EI_SHIFT(0x06) /* FIFO RD */
+#define EN0_TCNTHI EI_SHIFT(0x06) /* High byte of tx byte count WR */
+#define EN0_ISR EI_SHIFT(0x07) /* Interrupt status reg RD WR */
+#define EN0_CRDALO EI_SHIFT(0x08) /* low byte of current remote dma address RD */
+#define EN0_RSARLO EI_SHIFT(0x08) /* Remote start address reg 0 */
+#define EN0_CRDAHI EI_SHIFT(0x09) /* high byte, current remote dma address RD */
+#define EN0_RSARHI EI_SHIFT(0x09) /* Remote start address reg 1 */
+#define EN0_RCNTLO EI_SHIFT(0x0a) /* Remote byte count reg WR */
+#define EN0_RCNTHI EI_SHIFT(0x0b) /* Remote byte count reg WR */
+#define EN0_RSR EI_SHIFT(0x0c) /* rx status reg RD */
+#define EN0_RXCR EI_SHIFT(0x0c) /* RX configuration reg WR */
+#define EN0_TXCR EI_SHIFT(0x0d) /* TX configuration reg WR */
+#define EN0_COUNTER0 EI_SHIFT(0x0d) /* Rcv alignment error counter RD */
+#define EN0_DCFG EI_SHIFT(0x0e) /* Data configuration reg WR */
+#define EN0_COUNTER1 EI_SHIFT(0x0e) /* Rcv CRC error counter RD */
+#define EN0_IMR EI_SHIFT(0x0f) /* Interrupt mask reg WR */
+#define EN0_COUNTER2 EI_SHIFT(0x0f) /* Rcv missed frame error counter RD */
+
+/* Bits in EN0_ISR - Interrupt status register */
+#define ENISR_RX 0x01 /* Receiver, no error */
+#define ENISR_TX 0x02 /* Transmitter, no error */
+#define ENISR_RX_ERR 0x04 /* Receiver, with error */
+#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
+#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
+#define ENISR_COUNTERS 0x20 /* Counters need emptying */
+#define ENISR_RDC 0x40 /* remote dma complete */
+#define ENISR_RESET 0x80 /* Reset completed */
+#define ENISR_ALL 0x3f /* Interrupts we will enable */
+
+/* Bits in EN0_DCFG - Data config register */
+#define ENDCFG_WTS 0x01 /* word transfer mode selection */
+#define ENDCFG_BOS 0x02 /* byte order selection */
+#define ENDCFG_AUTO_INIT 0x10 /* Auto-init to remove packets from ring */
+#define ENDCFG_FIFO 0x40 /* 8 bytes */
+
+/* Page 1 register offsets. */
+#define EN1_PHYS EI_SHIFT(0x01) /* This board's physical enet addr RD WR */
+#define EN1_PHYS_SHIFT(i) EI_SHIFT(i+1) /* Get and set mac address */
+#define EN1_CURPAG EI_SHIFT(0x07) /* Current memory page RD WR */
+#define EN1_MULT EI_SHIFT(0x08) /* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_MULT_SHIFT(i) EI_SHIFT(8+i) /* Get and set multicast filter */
+
+/* Bits in received packet status byte and EN0_RSR*/
+#define ENRSR_RXOK 0x01 /* Received a good packet */
+#define ENRSR_CRC 0x02 /* CRC error */
+#define ENRSR_FAE 0x04 /* frame alignment error */
+#define ENRSR_FO 0x08 /* FIFO overrun */
+#define ENRSR_MPA 0x10 /* missed pkt */
+#define ENRSR_PHY 0x20 /* physical/multicast address */
+#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
+#define ENRSR_DEF 0x80 /* deferring */
+
+/* Transmitted packet status, EN0_TSR. */
+#define ENTSR_PTX 0x01 /* Packet transmitted without error */
+#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
+#define ENTSR_COL 0x04 /* The transmit collided at least once. */
+#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
+#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
+#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
+#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
+#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
+
+#define NIC_RECEIVE_MONITOR_MODE 0x20
+
+#endif /* _8390_h */
diff --git a/qemu/roms/u-boot/drivers/net/Makefile b/qemu/roms/u-boot/drivers/net/Makefile
new file mode 100644
index 000000000..6005f7e41
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/Makefile
@@ -0,0 +1,66 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
+obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
+obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
+obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
+obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
+obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
+obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
+obj-$(CONFIG_CS8900) += cs8900.o
+obj-$(CONFIG_TULIP) += dc2114x.o
+obj-$(CONFIG_DESIGNWARE_ETH) += designware.o
+obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
+obj-$(CONFIG_DNET) += dnet.o
+obj-$(CONFIG_E1000) += e1000.o
+obj-$(CONFIG_E1000_SPI) += e1000_spi.o
+obj-$(CONFIG_EEPRO100) += eepro100.o
+obj-$(CONFIG_ENC28J60) += enc28j60.o
+obj-$(CONFIG_EP93XX) += ep93xx_eth.o
+obj-$(CONFIG_ETHOC) += ethoc.o
+obj-$(CONFIG_FEC_MXC) += fec_mxc.o
+obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
+obj-$(CONFIG_FTGMAC100) += ftgmac100.o
+obj-$(CONFIG_FTMAC110) += ftmac110.o
+obj-$(CONFIG_FTMAC100) += ftmac100.o
+obj-$(CONFIG_GRETH) += greth.o
+obj-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
+obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
+obj-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
+obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
+obj-$(CONFIG_LAN91C96) += lan91c96.o
+obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
+obj-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
+obj-$(CONFIG_MPC512x_FEC) += mpc512x_fec.o
+obj-$(CONFIG_MVGBE) += mvgbe.o
+obj-$(CONFIG_NATSEMI) += natsemi.o
+obj-$(CONFIG_DRIVER_NE2000) += ne2000.o ne2000_base.o
+obj-$(CONFIG_DRIVER_AX88796L) += ax88796.o ne2000_base.o
+obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_NS8382X) += ns8382x.o
+obj-$(CONFIG_PCNET) += pcnet.o
+obj-$(CONFIG_PLB2800_ETHER) += plb2800_eth.o
+obj-$(CONFIG_RTL8139) += rtl8139.o
+obj-$(CONFIG_RTL8169) += rtl8169.o
+obj-$(CONFIG_SH_ETHER) += sh_eth.o
+obj-$(CONFIG_SMC91111) += smc91111.o
+obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o
+obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
+obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
+obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o
+obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
+obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
+obj-$(CONFIG_ULI526X) += uli526x.o
+obj-$(CONFIG_VSC7385_ENET) += vsc7385.o
+obj-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o
+obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
+obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \
+ xilinx_ll_temac_fifo.o xilinx_ll_temac_sdma.o
+obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o
diff --git a/qemu/roms/u-boot/drivers/net/altera_tse.c b/qemu/roms/u-boot/drivers/net/altera_tse.c
new file mode 100644
index 000000000..de517f8da
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/altera_tse.c
@@ -0,0 +1,971 @@
+/*
+ * Altera 10/100/1000 triple speed ethernet mac driver
+ *
+ * Copyright (C) 2008 Altera Corporation.
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <asm/dma-mapping.h>
+#include <miiphy.h>
+#include "altera_tse.h"
+
+/* sgdma debug - print descriptor */
+static void alt_sgdma_print_desc(volatile struct alt_sgdma_descriptor *desc)
+{
+ debug("SGDMA DEBUG :\n");
+ debug("desc->source : 0x%x \n", (unsigned int)desc->source);
+ debug("desc->destination : 0x%x \n", (unsigned int)desc->destination);
+ debug("desc->next : 0x%x \n", (unsigned int)desc->next);
+ debug("desc->source_pad : 0x%x \n", (unsigned int)desc->source_pad);
+ debug("desc->destination_pad : 0x%x \n",
+ (unsigned int)desc->destination_pad);
+ debug("desc->next_pad : 0x%x \n", (unsigned int)desc->next_pad);
+ debug("desc->bytes_to_transfer : 0x%x \n",
+ (unsigned int)desc->bytes_to_transfer);
+ debug("desc->actual_bytes_transferred : 0x%x \n",
+ (unsigned int)desc->actual_bytes_transferred);
+ debug("desc->descriptor_status : 0x%x \n",
+ (unsigned int)desc->descriptor_status);
+ debug("desc->descriptor_control : 0x%x \n",
+ (unsigned int)desc->descriptor_control);
+}
+
+/* This is a generic routine that the SGDMA mode-specific routines
+ * call to populate a descriptor.
+ * arg1 :pointer to first SGDMA descriptor.
+ * arg2 :pointer to next SGDMA descriptor.
+ * arg3 :Address to where data to be written.
+ * arg4 :Address from where data to be read.
+ * arg5 :no of byte to transaction.
+ * arg6 :variable indicating to generate start of packet or not
+ * arg7 :read fixed
+ * arg8 :write fixed
+ * arg9 :read burst
+ * arg10 :write burst
+ * arg11 :atlantic_channel number
+ */
+static void alt_sgdma_construct_descriptor_burst(
+ volatile struct alt_sgdma_descriptor *desc,
+ volatile struct alt_sgdma_descriptor *next,
+ unsigned int *read_addr,
+ unsigned int *write_addr,
+ unsigned short length_or_eop,
+ int generate_eop,
+ int read_fixed,
+ int write_fixed_or_sop,
+ int read_burst,
+ int write_burst,
+ unsigned char atlantic_channel)
+{
+ /*
+ * Mark the "next" descriptor as "not" owned by hardware. This prevents
+ * The SGDMA controller from continuing to process the chain. This is
+ * done as a single IO write to bypass cache, without flushing
+ * the entire descriptor, since only the 8-bit descriptor status must
+ * be flushed.
+ */
+ if (!next)
+ debug("Next descriptor not defined!!\n");
+
+ next->descriptor_control = (next->descriptor_control &
+ ~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK);
+
+ desc->source = (unsigned int *)((unsigned int)read_addr & 0x1FFFFFFF);
+ desc->destination =
+ (unsigned int *)((unsigned int)write_addr & 0x1FFFFFFF);
+ desc->next = (unsigned int *)((unsigned int)next & 0x1FFFFFFF);
+ desc->source_pad = 0x0;
+ desc->destination_pad = 0x0;
+ desc->next_pad = 0x0;
+ desc->bytes_to_transfer = length_or_eop;
+ desc->actual_bytes_transferred = 0;
+ desc->descriptor_status = 0x0;
+
+ /* SGDMA burst not currently supported */
+ desc->read_burst = 0;
+ desc->write_burst = 0;
+
+ /*
+ * Set the descriptor control block as follows:
+ * - Set "owned by hardware" bit
+ * - Optionally set "generate EOP" bit
+ * - Optionally set the "read from fixed address" bit
+ * - Optionally set the "write to fixed address bit (which serves
+ * serves as a "generate SOP" control bit in memory-to-stream mode).
+ * - Set the 4-bit atlantic channel, if specified
+ *
+ * Note this step is performed after all other descriptor information
+ * has been filled out so that, if the controller already happens to be
+ * pointing at this descriptor, it will not run (via the "owned by
+ * hardware" bit) until all other descriptor has been set up.
+ */
+
+ desc->descriptor_control =
+ ((ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) |
+ (generate_eop ?
+ ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK : 0x0) |
+ (read_fixed ?
+ ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK : 0x0) |
+ (write_fixed_or_sop ?
+ ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK : 0x0) |
+ (atlantic_channel ? ((atlantic_channel & 0x0F) << 3) : 0)
+ );
+}
+
+static int alt_sgdma_do_sync_transfer(volatile struct alt_sgdma_registers *dev,
+ volatile struct alt_sgdma_descriptor *desc)
+{
+ unsigned int status;
+ int counter = 0;
+
+ /* Wait for any pending transfers to complete */
+ alt_sgdma_print_desc(desc);
+ status = dev->status;
+
+ counter = 0;
+ while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
+ break;
+ }
+
+ if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
+ debug("Timeout waiting sgdma in do sync!\n");
+
+ /*
+ * Clear any (previous) status register information
+ * that might occlude our error checking later.
+ */
+ dev->status = 0xFF;
+
+ /* Point the controller at the descriptor */
+ dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF;
+ debug("next desc in sgdma 0x%x\n",
+ (unsigned int)dev->next_descriptor_pointer);
+
+ /*
+ * Set up SGDMA controller to:
+ * - Disable interrupt generation
+ * - Run once a valid descriptor is written to controller
+ * - Stop on an error with any particular descriptor
+ */
+ dev->control = (ALT_SGDMA_CONTROL_RUN_MSK |
+ ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK);
+
+ /* Wait for the descriptor (chain) to complete */
+ status = dev->status;
+ debug("wait for sgdma....");
+ while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK)
+ ;
+ debug("done\n");
+
+ /* Clear Run */
+ dev->control = (dev->control & (~ALT_SGDMA_CONTROL_RUN_MSK));
+
+ /* Get & clear status register contents */
+ status = dev->status;
+ dev->status = 0xFF;
+
+ /* we really should check if the transfer completes properly */
+ debug("tx sgdma status = 0x%x", status);
+ return 0;
+}
+
+static int alt_sgdma_do_async_transfer(volatile struct alt_sgdma_registers *dev,
+ volatile struct alt_sgdma_descriptor *desc)
+{
+ unsigned int status;
+ int counter = 0;
+
+ /* Wait for any pending transfers to complete */
+ alt_sgdma_print_desc(desc);
+ status = dev->status;
+
+ counter = 0;
+ while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
+ break;
+ }
+
+ if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
+ debug("Timeout waiting sgdma in do async!\n");
+
+ /*
+ * Clear the RUN bit in the control register. This is needed
+ * to restart the SGDMA engine later on.
+ */
+ dev->control = 0;
+
+ /*
+ * Clear any (previous) status register information
+ * that might occlude our error checking later.
+ */
+ dev->status = 0xFF;
+
+ /* Point the controller at the descriptor */
+ dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF;
+
+ /*
+ * Set up SGDMA controller to:
+ * - Disable interrupt generation
+ * - Run once a valid descriptor is written to controller
+ * - Stop on an error with any particular descriptor
+ */
+ dev->control = (ALT_SGDMA_CONTROL_RUN_MSK |
+ ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK);
+
+ /* we really should check if the transfer completes properly */
+ return 0;
+}
+
+/* u-boot interface */
+static int tse_adjust_link(struct altera_tse_priv *priv)
+{
+ unsigned int refvar;
+
+ refvar = priv->mac_dev->command_config.image;
+
+ if (!(priv->duplexity))
+ refvar |= ALTERA_TSE_CMD_HD_ENA_MSK;
+ else
+ refvar &= ~ALTERA_TSE_CMD_HD_ENA_MSK;
+
+ switch (priv->speed) {
+ case 1000:
+ refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK;
+ refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK;
+ break;
+ case 100:
+ refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK;
+ refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK;
+ break;
+ case 10:
+ refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK;
+ refvar |= ALTERA_TSE_CMD_ENA_10_MSK;
+ break;
+ }
+ priv->mac_dev->command_config.image = refvar;
+
+ return 0;
+}
+
+static int tse_eth_send(struct eth_device *dev, void *packet, int length)
+{
+ struct altera_tse_priv *priv = dev->priv;
+ volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
+ volatile struct alt_sgdma_descriptor *tx_desc =
+ (volatile struct alt_sgdma_descriptor *)priv->tx_desc;
+
+ volatile struct alt_sgdma_descriptor *tx_desc_cur =
+ (volatile struct alt_sgdma_descriptor *)&tx_desc[0];
+
+ flush_dcache_range((unsigned long)packet,
+ (unsigned long)packet + length);
+ alt_sgdma_construct_descriptor_burst(
+ (volatile struct alt_sgdma_descriptor *)&tx_desc[0],
+ (volatile struct alt_sgdma_descriptor *)&tx_desc[1],
+ (unsigned int *)packet, /* read addr */
+ (unsigned int *)0,
+ length, /* length or EOP ,will change for each tx */
+ 0x1, /* gen eop */
+ 0x0, /* read fixed */
+ 0x1, /* write fixed or sop */
+ 0x0, /* read burst */
+ 0x0, /* write burst */
+ 0x0 /* channel */
+ );
+ debug("TX Packet @ 0x%x,0x%x bytes", (unsigned int)packet, length);
+
+ /* send the packet */
+ debug("sending packet\n");
+ alt_sgdma_do_sync_transfer(tx_sgdma, tx_desc_cur);
+ debug("sent %d bytes\n", tx_desc_cur->actual_bytes_transferred);
+ return tx_desc_cur->actual_bytes_transferred;
+}
+
+static int tse_eth_rx(struct eth_device *dev)
+{
+ int packet_length = 0;
+ struct altera_tse_priv *priv = dev->priv;
+ volatile struct alt_sgdma_descriptor *rx_desc =
+ (volatile struct alt_sgdma_descriptor *)priv->rx_desc;
+ volatile struct alt_sgdma_descriptor *rx_desc_cur = &rx_desc[0];
+
+ if (rx_desc_cur->descriptor_status &
+ ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) {
+ debug("got packet\n");
+ packet_length = rx_desc->actual_bytes_transferred;
+ NetReceive(NetRxPackets[0], packet_length);
+
+ /* start descriptor again */
+ flush_dcache_range((unsigned long)(NetRxPackets[0]),
+ (unsigned long)(NetRxPackets[0]) + PKTSIZE_ALIGN);
+ alt_sgdma_construct_descriptor_burst(
+ (volatile struct alt_sgdma_descriptor *)&rx_desc[0],
+ (volatile struct alt_sgdma_descriptor *)&rx_desc[1],
+ (unsigned int)0x0, /* read addr */
+ (unsigned int *)NetRxPackets[0],
+ 0x0, /* length or EOP */
+ 0x0, /* gen eop */
+ 0x0, /* read fixed */
+ 0x0, /* write fixed or sop */
+ 0x0, /* read burst */
+ 0x0, /* write burst */
+ 0x0 /* channel */
+ );
+
+ /* setup the sgdma */
+ alt_sgdma_do_async_transfer(priv->sgdma_rx, &rx_desc[0]);
+
+ return packet_length;
+ }
+
+ return -1;
+}
+
+static void tse_eth_halt(struct eth_device *dev)
+{
+ /* don't do anything! */
+ /* this gets called after each uboot */
+ /* network command. don't need to reset the thing all of the time */
+}
+
+static void tse_eth_reset(struct eth_device *dev)
+{
+ /* stop sgdmas, disable tse receive */
+ struct altera_tse_priv *priv = dev->priv;
+ volatile struct alt_tse_mac *mac_dev = priv->mac_dev;
+ volatile struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;
+ volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
+ int counter;
+ volatile struct alt_sgdma_descriptor *rx_desc =
+ (volatile struct alt_sgdma_descriptor *)&priv->rx_desc[0];
+
+ /* clear rx desc & wait for sgdma to complete */
+ rx_desc->descriptor_control = 0;
+ rx_sgdma->control = 0;
+ counter = 0;
+ while (rx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
+ break;
+ }
+
+ if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) {
+ debug("Timeout waiting for rx sgdma!\n");
+ rx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK;
+ rx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK;
+ }
+
+ counter = 0;
+ tx_sgdma->control = 0;
+ while (tx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
+ break;
+ }
+
+ if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) {
+ debug("Timeout waiting for tx sgdma!\n");
+ tx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK;
+ tx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK;
+ }
+ /* reset the mac */
+ mac_dev->command_config.bits.transmit_enable = 1;
+ mac_dev->command_config.bits.receive_enable = 1;
+ mac_dev->command_config.bits.software_reset = 1;
+
+ counter = 0;
+ while (mac_dev->command_config.bits.software_reset) {
+ if (counter++ > ALT_TSE_SW_RESET_WATCHDOG_CNTR)
+ break;
+ }
+
+ if (counter >= ALT_TSE_SW_RESET_WATCHDOG_CNTR)
+ debug("TSEMAC SW reset bit never cleared!\n");
+}
+
+static int tse_mdio_read(struct altera_tse_priv *priv, unsigned int regnum)
+{
+ volatile struct alt_tse_mac *mac_dev;
+ unsigned int *mdio_regs;
+ unsigned int data;
+ u16 value;
+
+ mac_dev = priv->mac_dev;
+
+ /* set mdio address */
+ mac_dev->mdio_phy1_addr = priv->phyaddr;
+ mdio_regs = (unsigned int *)&mac_dev->mdio_phy1;
+
+ /* get the data */
+ data = mdio_regs[regnum];
+
+ value = data & 0xffff;
+
+ return value;
+}
+
+static int tse_mdio_write(struct altera_tse_priv *priv, unsigned int regnum,
+ unsigned int value)
+{
+ volatile struct alt_tse_mac *mac_dev;
+ unsigned int *mdio_regs;
+ unsigned int data;
+
+ mac_dev = priv->mac_dev;
+
+ /* set mdio address */
+ mac_dev->mdio_phy1_addr = priv->phyaddr;
+ mdio_regs = (unsigned int *)&mac_dev->mdio_phy1;
+
+ /* get the data */
+ data = (unsigned int)value;
+
+ mdio_regs[regnum] = data;
+
+ return 0;
+}
+
+/* MDIO access to phy */
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII)
+static int altera_tse_miiphy_write(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ struct eth_device *dev;
+ struct altera_tse_priv *priv;
+ dev = eth_get_dev_by_name(devname);
+ priv = dev->priv;
+
+ tse_mdio_write(priv, (uint) reg, (uint) value);
+
+ return 0;
+}
+
+static int altera_tse_miiphy_read(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ struct eth_device *dev;
+ struct altera_tse_priv *priv;
+ volatile struct alt_tse_mac *mac_dev;
+ unsigned int *mdio_regs;
+
+ dev = eth_get_dev_by_name(devname);
+ priv = dev->priv;
+
+ mac_dev = priv->mac_dev;
+ mac_dev->mdio_phy1_addr = (int)addr;
+ mdio_regs = (unsigned int *)&mac_dev->mdio_phy1;
+
+ *value = 0xffff & mdio_regs[reg];
+
+ return 0;
+
+}
+#endif
+
+/*
+ * Also copied from tsec.c
+ */
+/* Parse the status register for link, and then do
+ * auto-negotiation
+ */
+static uint mii_parse_sr(uint mii_reg, struct altera_tse_priv *priv)
+{
+ /*
+ * Wait if the link is up, and autonegotiation is in progress
+ * (ie - we're capable and it's not done)
+ */
+ mii_reg = tse_mdio_read(priv, MIIM_STATUS);
+
+ if (!(mii_reg & MIIM_STATUS_LINK) && (mii_reg & BMSR_ANEGCAPABLE)
+ && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+ int i = 0;
+
+ puts("Waiting for PHY auto negotiation to complete");
+ while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
+ /*
+ * Timeout reached ?
+ */
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts(" TIMEOUT !\n");
+ priv->link = 0;
+ return 0;
+ }
+
+ if ((i++ % 1000) == 0)
+ putc('.');
+ udelay(1000); /* 1 ms */
+ mii_reg = tse_mdio_read(priv, MIIM_STATUS);
+ }
+ puts(" done\n");
+ priv->link = 1;
+ udelay(500000); /* another 500 ms (results in faster booting) */
+ } else {
+ if (mii_reg & MIIM_STATUS_LINK) {
+ debug("Link is up\n");
+ priv->link = 1;
+ } else {
+ debug("Link is down\n");
+ priv->link = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Parse the 88E1011's status register for speed and duplex
+ * information
+ */
+static uint mii_parse_88E1011_psr(uint mii_reg, struct altera_tse_priv *priv)
+{
+ uint speed;
+
+ mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS);
+
+ if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
+ !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
+ int i = 0;
+
+ puts("Waiting for PHY realtime link");
+ while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
+ /* Timeout reached ? */
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts(" TIMEOUT !\n");
+ priv->link = 0;
+ break;
+ }
+
+ if ((i++ == 1000) == 0) {
+ i = 0;
+ puts(".");
+ }
+ udelay(1000); /* 1 ms */
+ mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS);
+ }
+ puts(" done\n");
+ udelay(500000); /* another 500 ms (results in faster booting) */
+ } else {
+ if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
+ priv->link = 1;
+ else
+ priv->link = 0;
+ }
+
+ if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
+ priv->duplexity = 1;
+ else
+ priv->duplexity = 0;
+
+ speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED);
+
+ switch (speed) {
+ case MIIM_88E1011_PHYSTAT_GBIT:
+ priv->speed = 1000;
+ debug("PHY Speed is 1000Mbit\n");
+ break;
+ case MIIM_88E1011_PHYSTAT_100:
+ debug("PHY Speed is 100Mbit\n");
+ priv->speed = 100;
+ break;
+ default:
+ debug("PHY Speed is 10Mbit\n");
+ priv->speed = 10;
+ }
+
+ return 0;
+}
+
+static uint mii_m88e1111s_setmode_sr(uint mii_reg, struct altera_tse_priv *priv)
+{
+ uint mii_data = tse_mdio_read(priv, mii_reg);
+ mii_data &= 0xfff0;
+ if ((priv->flags >= 1) && (priv->flags <= 4))
+ mii_data |= 0xb;
+ else if (priv->flags == 5)
+ mii_data |= 0x4;
+
+ return mii_data;
+}
+
+static uint mii_m88e1111s_setmode_cr(uint mii_reg, struct altera_tse_priv *priv)
+{
+ uint mii_data = tse_mdio_read(priv, mii_reg);
+ mii_data &= ~0x82;
+ if ((priv->flags >= 1) && (priv->flags <= 4))
+ mii_data |= 0x82;
+
+ return mii_data;
+}
+
+/*
+ * Returns which value to write to the control register.
+ * For 10/100, the value is slightly different
+ */
+static uint mii_cr_init(uint mii_reg, struct altera_tse_priv *priv)
+{
+ return MIIM_CONTROL_INIT;
+}
+
+/*
+ * PHY & MDIO code
+ * Need to add SGMII stuff
+ *
+ */
+
+static struct phy_info phy_info_M88E1111S = {
+ 0x01410cc,
+ "Marvell 88E1111S",
+ 4,
+ (struct phy_cmd[]){ /* config */
+ /* Reset and configure the PHY */
+ {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+ {MIIM_88E1111_PHY_EXT_SR, 0x848f,
+ &mii_m88e1111s_setmode_sr},
+ /* Delay RGMII TX and RX */
+ {MIIM_88E1111_PHY_EXT_CR, 0x0cd2,
+ &mii_m88e1111s_setmode_cr},
+ {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+ {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+ {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+ {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+ {miim_end,}
+ },
+ (struct phy_cmd[]){ /* startup */
+ /* Status is read once to clear old link state */
+ {MIIM_STATUS, miim_read, NULL},
+ /* Auto-negotiate */
+ {MIIM_STATUS, miim_read, &mii_parse_sr},
+ /* Read the status */
+ {MIIM_88E1011_PHY_STATUS, miim_read,
+ &mii_parse_88E1011_psr},
+ {miim_end,}
+ },
+ (struct phy_cmd[]){ /* shutdown */
+ {miim_end,}
+ },
+};
+
+/* a generic flavor. */
+static struct phy_info phy_info_generic = {
+ 0,
+ "Unknown/Generic PHY",
+ 32,
+ (struct phy_cmd[]){ /* config */
+ {MII_BMCR, BMCR_RESET, NULL},
+ {MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART, NULL},
+ {miim_end,}
+ },
+ (struct phy_cmd[]){ /* startup */
+ {MII_BMSR, miim_read, NULL},
+ {MII_BMSR, miim_read, &mii_parse_sr},
+ {miim_end,}
+ },
+ (struct phy_cmd[]){ /* shutdown */
+ {miim_end,}
+ }
+};
+
+static struct phy_info *phy_info[] = {
+ &phy_info_M88E1111S,
+ NULL
+};
+
+ /* Grab the identifier of the device's PHY, and search through
+ * all of the known PHYs to see if one matches. If so, return
+ * it, if not, return NULL
+ */
+static struct phy_info *get_phy_info(struct eth_device *dev)
+{
+ struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv;
+ uint phy_reg, phy_ID;
+ int i;
+ struct phy_info *theInfo = NULL;
+
+ /* Grab the bits from PHYIR1, and put them in the upper half */
+ phy_reg = tse_mdio_read(priv, MIIM_PHYIR1);
+ phy_ID = (phy_reg & 0xffff) << 16;
+
+ /* Grab the bits from PHYIR2, and put them in the lower half */
+ phy_reg = tse_mdio_read(priv, MIIM_PHYIR2);
+ phy_ID |= (phy_reg & 0xffff);
+
+ /* loop through all the known PHY types, and find one that */
+ /* matches the ID we read from the PHY. */
+ for (i = 0; phy_info[i]; i++) {
+ if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) {
+ theInfo = phy_info[i];
+ break;
+ }
+ }
+
+ if (theInfo == NULL) {
+ theInfo = &phy_info_generic;
+ debug("%s: No support for PHY id %x; assuming generic\n",
+ dev->name, phy_ID);
+ } else
+ debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
+
+ return theInfo;
+}
+
+/* Execute the given series of commands on the given device's
+ * PHY, running functions as necessary
+ */
+static void phy_run_commands(struct altera_tse_priv *priv, struct phy_cmd *cmd)
+{
+ int i;
+ uint result;
+
+ for (i = 0; cmd->mii_reg != miim_end; i++) {
+ if (cmd->mii_data == miim_read) {
+ result = tse_mdio_read(priv, cmd->mii_reg);
+
+ if (cmd->funct != NULL)
+ (*(cmd->funct)) (result, priv);
+
+ } else {
+ if (cmd->funct != NULL)
+ result = (*(cmd->funct)) (cmd->mii_reg, priv);
+ else
+ result = cmd->mii_data;
+
+ tse_mdio_write(priv, cmd->mii_reg, result);
+
+ }
+ cmd++;
+ }
+}
+
+/* Phy init code */
+static int init_phy(struct eth_device *dev)
+{
+ struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv;
+ struct phy_info *curphy;
+
+ /* Get the cmd structure corresponding to the attached
+ * PHY */
+ curphy = get_phy_info(dev);
+
+ if (curphy == NULL) {
+ priv->phyinfo = NULL;
+ debug("%s: No PHY found\n", dev->name);
+
+ return 0;
+ } else
+ debug("%s found\n", curphy->name);
+ priv->phyinfo = curphy;
+
+ phy_run_commands(priv, priv->phyinfo->config);
+
+ return 1;
+}
+
+static int tse_set_mac_address(struct eth_device *dev)
+{
+ struct altera_tse_priv *priv = dev->priv;
+ volatile struct alt_tse_mac *mac_dev = priv->mac_dev;
+
+ debug("Setting MAC address to 0x%02x%02x%02x%02x%02x%02x\n",
+ dev->enetaddr[5], dev->enetaddr[4],
+ dev->enetaddr[3], dev->enetaddr[2],
+ dev->enetaddr[1], dev->enetaddr[0]);
+ mac_dev->mac_addr_0 = ((dev->enetaddr[3]) << 24 |
+ (dev->enetaddr[2]) << 16 |
+ (dev->enetaddr[1]) << 8 | (dev->enetaddr[0]));
+
+ mac_dev->mac_addr_1 = ((dev->enetaddr[5] << 8 |
+ (dev->enetaddr[4])) & 0xFFFF);
+
+ /* Set the MAC address */
+ mac_dev->supp_mac_addr_0_0 = mac_dev->mac_addr_0;
+ mac_dev->supp_mac_addr_0_1 = mac_dev->mac_addr_1;
+
+ /* Set the MAC address */
+ mac_dev->supp_mac_addr_1_0 = mac_dev->mac_addr_0;
+ mac_dev->supp_mac_addr_1_1 = mac_dev->mac_addr_1;
+
+ /* Set the MAC address */
+ mac_dev->supp_mac_addr_2_0 = mac_dev->mac_addr_0;
+ mac_dev->supp_mac_addr_2_1 = mac_dev->mac_addr_1;
+
+ /* Set the MAC address */
+ mac_dev->supp_mac_addr_3_0 = mac_dev->mac_addr_0;
+ mac_dev->supp_mac_addr_3_1 = mac_dev->mac_addr_1;
+ return 0;
+}
+
+static int tse_eth_init(struct eth_device *dev, bd_t * bd)
+{
+ int dat;
+ struct altera_tse_priv *priv = dev->priv;
+ volatile struct alt_tse_mac *mac_dev = priv->mac_dev;
+ volatile struct alt_sgdma_descriptor *tx_desc = priv->tx_desc;
+ volatile struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
+ volatile struct alt_sgdma_descriptor *rx_desc_cur =
+ (volatile struct alt_sgdma_descriptor *)&rx_desc[0];
+
+ /* stop controller */
+ debug("Reseting TSE & SGDMAs\n");
+ tse_eth_reset(dev);
+
+ /* start the phy */
+ debug("Configuring PHY\n");
+ phy_run_commands(priv, priv->phyinfo->startup);
+
+ /* need to create sgdma */
+ debug("Configuring tx desc\n");
+ alt_sgdma_construct_descriptor_burst(
+ (volatile struct alt_sgdma_descriptor *)&tx_desc[0],
+ (volatile struct alt_sgdma_descriptor *)&tx_desc[1],
+ (unsigned int *)NULL, /* read addr */
+ (unsigned int *)0,
+ 0, /* length or EOP ,will change for each tx */
+ 0x1, /* gen eop */
+ 0x0, /* read fixed */
+ 0x1, /* write fixed or sop */
+ 0x0, /* read burst */
+ 0x0, /* write burst */
+ 0x0 /* channel */
+ );
+ debug("Configuring rx desc\n");
+ flush_dcache_range((unsigned long)(NetRxPackets[0]),
+ (unsigned long)(NetRxPackets[0]) + PKTSIZE_ALIGN);
+ alt_sgdma_construct_descriptor_burst(
+ (volatile struct alt_sgdma_descriptor *)&rx_desc[0],
+ (volatile struct alt_sgdma_descriptor *)&rx_desc[1],
+ (unsigned int)0x0, /* read addr */
+ (unsigned int *)NetRxPackets[0],
+ 0x0, /* length or EOP */
+ 0x0, /* gen eop */
+ 0x0, /* read fixed */
+ 0x0, /* write fixed or sop */
+ 0x0, /* read burst */
+ 0x0, /* write burst */
+ 0x0 /* channel */
+ );
+ /* start rx async transfer */
+ debug("Starting rx sgdma\n");
+ alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur);
+
+ /* start TSE */
+ debug("Configuring TSE Mac\n");
+ /* Initialize MAC registers */
+ mac_dev->max_frame_length = PKTSIZE_ALIGN;
+ mac_dev->rx_almost_empty_threshold = 8;
+ mac_dev->rx_almost_full_threshold = 8;
+ mac_dev->tx_almost_empty_threshold = 8;
+ mac_dev->tx_almost_full_threshold = 3;
+ mac_dev->tx_sel_empty_threshold =
+ CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16;
+ mac_dev->tx_sel_full_threshold = 0;
+ mac_dev->rx_sel_empty_threshold =
+ CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16;
+ mac_dev->rx_sel_full_threshold = 0;
+
+ /* NO Shift */
+ mac_dev->rx_cmd_stat.bits.rx_shift16 = 0;
+ mac_dev->tx_cmd_stat.bits.tx_shift16 = 0;
+
+ /* enable MAC */
+ dat = 0;
+ dat = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK;
+
+ mac_dev->command_config.image = dat;
+
+ /* configure the TSE core */
+ /* -- output clocks, */
+ /* -- and later config stuff for SGMII */
+ if (priv->link) {
+ debug("Adjusting TSE to link speed\n");
+ tse_adjust_link(priv);
+ }
+
+ return priv->link ? 0 : -1;
+}
+
+/* TSE init code */
+int altera_tse_initialize(u8 dev_num, int mac_base,
+ int sgdma_rx_base, int sgdma_tx_base,
+ u32 sgdma_desc_base, u32 sgdma_desc_size)
+{
+ struct altera_tse_priv *priv;
+ struct eth_device *dev;
+ struct alt_sgdma_descriptor *rx_desc;
+ struct alt_sgdma_descriptor *tx_desc;
+ unsigned long dma_handle;
+
+ dev = (struct eth_device *)malloc(sizeof *dev);
+
+ if (NULL == dev)
+ return 0;
+
+ memset(dev, 0, sizeof *dev);
+
+ priv = malloc(sizeof(*priv));
+
+ if (!priv) {
+ free(dev);
+ return 0;
+ }
+ if (sgdma_desc_size) {
+ if (sgdma_desc_size < (sizeof(*tx_desc) * (3 + PKTBUFSRX))) {
+ printf("ALTERA_TSE-%hu: "
+ "descriptor memory is too small\n", dev_num);
+ free(priv);
+ free(dev);
+ return 0;
+ }
+ tx_desc = (struct alt_sgdma_descriptor *)sgdma_desc_base;
+ } else {
+ tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX),
+ &dma_handle);
+ }
+
+ rx_desc = tx_desc + 2;
+ debug("tx desc: address = 0x%x\n", (unsigned int)tx_desc);
+ debug("rx desc: address = 0x%x\n", (unsigned int)rx_desc);
+
+ if (!tx_desc) {
+ free(priv);
+ free(dev);
+ return 0;
+ }
+ memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1));
+ memset(tx_desc, 0, (sizeof *tx_desc) * 2);
+
+ /* initialize tse priv */
+ priv->mac_dev = (volatile struct alt_tse_mac *)mac_base;
+ priv->sgdma_rx = (volatile struct alt_sgdma_registers *)sgdma_rx_base;
+ priv->sgdma_tx = (volatile struct alt_sgdma_registers *)sgdma_tx_base;
+ priv->phyaddr = CONFIG_SYS_ALTERA_TSE_PHY_ADDR;
+ priv->flags = CONFIG_SYS_ALTERA_TSE_FLAGS;
+ priv->rx_desc = rx_desc;
+ priv->tx_desc = tx_desc;
+
+ /* init eth structure */
+ dev->priv = priv;
+ dev->init = tse_eth_init;
+ dev->halt = tse_eth_halt;
+ dev->send = tse_eth_send;
+ dev->recv = tse_eth_rx;
+ dev->write_hwaddr = tse_set_mac_address;
+ sprintf(dev->name, "%s-%hu", "ALTERA_TSE", dev_num);
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII)
+ miiphy_register(dev->name, altera_tse_miiphy_read,
+ altera_tse_miiphy_write);
+#endif
+
+ init_phy(dev);
+
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/altera_tse.h b/qemu/roms/u-boot/drivers/net/altera_tse.h
new file mode 100644
index 000000000..8880bfc0f
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/altera_tse.h
@@ -0,0 +1,492 @@
+/*
+ * Altera 10/100/1000 triple speed ethernet mac
+ *
+ * Copyright (C) 2008 Altera Corporation.
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ALTERA_TSE_H_
+#define _ALTERA_TSE_H_
+
+#define __packed_1_ __attribute__ ((packed, aligned(1)))
+
+/* PHY Stuff */
+#define miim_end -2
+#define miim_read -1
+
+#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* in ms */
+
+#ifndef CONFIG_SYS_TBIPA_VALUE
+#define CONFIG_SYS_TBIPA_VALUE 0x1f
+#endif
+#define MIIMCFG_INIT_VALUE 0x00000003
+#define MIIMCFG_RESET 0x80000000
+
+#define MIIMIND_BUSY 0x00000001
+#define MIIMIND_NOTVALID 0x00000004
+
+#define MIIM_CONTROL 0x00
+#define MIIM_CONTROL_RESET 0x00009140
+#define MIIM_CONTROL_INIT 0x00001140
+#define MIIM_CONTROL_RESTART 0x00001340
+#define MIIM_ANEN 0x00001000
+
+#define MIIM_CR 0x00
+#define MIIM_CR_RST 0x00008000
+#define MIIM_CR_INIT 0x00001000
+
+#define MIIM_STATUS 0x1
+#define MIIM_STATUS_AN_DONE 0x00000020
+#define MIIM_STATUS_LINK 0x0004
+
+#define MIIM_PHYIR1 0x2
+#define MIIM_PHYIR2 0x3
+
+#define MIIM_ANAR 0x4
+#define MIIM_ANAR_INIT 0x1e1
+
+#define MIIM_TBI_ANLPBPA 0x5
+#define MIIM_TBI_ANLPBPA_HALF 0x00000040
+#define MIIM_TBI_ANLPBPA_FULL 0x00000020
+
+#define MIIM_TBI_ANEX 0x6
+#define MIIM_TBI_ANEX_NP 0x00000004
+#define MIIM_TBI_ANEX_PRX 0x00000002
+
+#define MIIM_GBIT_CONTROL 0x9
+#define MIIM_GBIT_CONTROL_INIT 0xe00
+
+#define MIIM_EXT_PAGE_ACCESS 0x1f
+
+/* 88E1011 PHY Status Register */
+#define MIIM_88E1011_PHY_STATUS 0x11
+#define MIIM_88E1011_PHYSTAT_SPEED 0xc000
+#define MIIM_88E1011_PHYSTAT_GBIT 0x8000
+#define MIIM_88E1011_PHYSTAT_100 0x4000
+#define MIIM_88E1011_PHYSTAT_DUPLEX 0x2000
+#define MIIM_88E1011_PHYSTAT_SPDDONE 0x0800
+#define MIIM_88E1011_PHYSTAT_LINK 0x0400
+
+#define MIIM_88E1011_PHY_SCR 0x10
+#define MIIM_88E1011_PHY_MDI_X_AUTO 0x0060
+
+#define MIIM_88E1111_PHY_EXT_CR 0x14
+#define MIIM_88E1111_PHY_EXT_SR 0x1b
+
+/* 88E1111 PHY LED Control Register */
+#define MIIM_88E1111_PHY_LED_CONTROL 24
+#define MIIM_88E1111_PHY_LED_DIRECT 0x4100
+#define MIIM_88E1111_PHY_LED_COMBINE 0x411C
+
+#define MIIM_READ_COMMAND 0x00000001
+
+/* struct phy_info: a structure which defines attributes for a PHY
+ * id will contain a number which represents the PHY. During
+ * startup, the driver will poll the PHY to find out what its
+ * UID--as defined by registers 2 and 3--is. The 32-bit result
+ * gotten from the PHY will be shifted right by "shift" bits to
+ * discard any bits which may change based on revision numbers
+ * unimportant to functionality
+ *
+ * The struct phy_cmd entries represent pointers to an arrays of
+ * commands which tell the driver what to do to the PHY.
+ */
+struct phy_info {
+ uint id;
+ char *name;
+ uint shift;
+ /* Called to configure the PHY, and modify the controller
+ * based on the results */
+ struct phy_cmd *config;
+
+ /* Called when starting up the controller */
+ struct phy_cmd *startup;
+
+ /* Called when bringing down the controller */
+ struct phy_cmd *shutdown;
+};
+
+/* SGDMA Stuff */
+#define ALT_SGDMA_STATUS_ERROR_MSK (0x00000001)
+#define ALT_SGDMA_STATUS_EOP_ENCOUNTERED_MSK (0x00000002)
+#define ALT_SGDMA_STATUS_DESC_COMPLETED_MSK (0x00000004)
+#define ALT_SGDMA_STATUS_CHAIN_COMPLETED_MSK (0x00000008)
+#define ALT_SGDMA_STATUS_BUSY_MSK (0x00000010)
+
+#define ALT_SGDMA_CONTROL_IE_ERROR_MSK (0x00000001)
+#define ALT_SGDMA_CONTROL_IE_EOP_ENCOUNTERED_MSK (0x00000002)
+#define ALT_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK (0x00000004)
+#define ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK (0x00000008)
+#define ALT_SGDMA_CONTROL_IE_GLOBAL_MSK (0x00000010)
+#define ALT_SGDMA_CONTROL_RUN_MSK (0x00000020)
+#define ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK (0x00000040)
+#define ALT_SGDMA_CONTROL_IE_MAX_DESC_PROCESSED_MSK (0x00000080)
+#define ALT_SGDMA_CONTROL_MAX_DESC_PROCESSED_MSK (0x0000FF00)
+#define ALT_SGDMA_CONTROL_SOFTWARERESET_MSK (0x00010000)
+#define ALT_SGDMA_CONTROL_PARK_MSK (0x00020000)
+#define ALT_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK (0x80000000)
+
+#define ALTERA_TSE_SGDMA_INTR_MASK (ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK \
+ | ALT_SGDMA_STATUS_DESC_COMPLETED_MSK \
+ | ALT_SGDMA_CONTROL_IE_GLOBAL_MSK)
+
+/*
+ * Descriptor control bit masks & offsets
+ *
+ * Note: The control byte physically occupies bits [31:24] in memory.
+ * The following bit-offsets are expressed relative to the LSB of
+ * the control register bitfield.
+ */
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK (0x00000001)
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK (0x00000002)
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK (0x00000004)
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_ATLANTIC_CHANNEL_MSK (0x00000008)
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK (0x00000080)
+
+/*
+ * Descriptor status bit masks & offsets
+ *
+ * Note: The status byte physically occupies bits [23:16] in memory.
+ * The following bit-offsets are expressed relative to the LSB of
+ * the status register bitfield.
+ */
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK (0x00000001)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK (0x00000002)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK (0x00000004)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK (0x00000008)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK (0x00000010)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK (0x00000020)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK (0x00000040)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK (0x00000080)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_ERROR_MSK (0x0000007F)
+
+/*
+ * The SGDMA controller buffer descriptor allocates
+ * 64 bits for each address. To support ANSI C, the
+ * struct implementing a descriptor places 32-bits
+ * of padding directly above each address; each pad must
+ * be cleared when initializing a descriptor.
+ */
+
+/*
+ * Buffer Descriptor data structure
+ *
+ */
+struct alt_sgdma_descriptor {
+ unsigned int *source; /* the address of data to be read. */
+ unsigned int source_pad;
+
+ unsigned int *destination; /* the address to write data */
+ unsigned int destination_pad;
+
+ unsigned int *next; /* the next descriptor in the list. */
+ unsigned int next_pad;
+
+ unsigned short bytes_to_transfer; /* the number of bytes to transfer */
+ unsigned char read_burst;
+ unsigned char write_burst;
+
+ unsigned short actual_bytes_transferred;/* bytes transferred by DMA */
+ unsigned char descriptor_status;
+ unsigned char descriptor_control;
+
+} __packed_1_;
+
+/* SG-DMA Control/Status Slave registers map */
+
+struct alt_sgdma_registers {
+ unsigned int status;
+ unsigned int status_pad[3];
+ unsigned int control;
+ unsigned int control_pad[3];
+ unsigned int next_descriptor_pointer;
+ unsigned int descriptor_pad[3];
+};
+
+/* TSE Stuff */
+#define ALTERA_TSE_CMD_TX_ENA_MSK (0x00000001)
+#define ALTERA_TSE_CMD_RX_ENA_MSK (0x00000002)
+#define ALTERA_TSE_CMD_XON_GEN_MSK (0x00000004)
+#define ALTERA_TSE_CMD_ETH_SPEED_MSK (0x00000008)
+#define ALTERA_TSE_CMD_PROMIS_EN_MSK (0x00000010)
+#define ALTERA_TSE_CMD_PAD_EN_MSK (0x00000020)
+#define ALTERA_TSE_CMD_CRC_FWD_MSK (0x00000040)
+#define ALTERA_TSE_CMD_PAUSE_FWD_MSK (0x00000080)
+#define ALTERA_TSE_CMD_PAUSE_IGNORE_MSK (0x00000100)
+#define ALTERA_TSE_CMD_TX_ADDR_INS_MSK (0x00000200)
+#define ALTERA_TSE_CMD_HD_ENA_MSK (0x00000400)
+#define ALTERA_TSE_CMD_EXCESS_COL_MSK (0x00000800)
+#define ALTERA_TSE_CMD_LATE_COL_MSK (0x00001000)
+#define ALTERA_TSE_CMD_SW_RESET_MSK (0x00002000)
+#define ALTERA_TSE_CMD_MHASH_SEL_MSK (0x00004000)
+#define ALTERA_TSE_CMD_LOOPBACK_MSK (0x00008000)
+/* Bits (18:16) = address select */
+#define ALTERA_TSE_CMD_TX_ADDR_SEL_MSK (0x00070000)
+#define ALTERA_TSE_CMD_MAGIC_ENA_MSK (0x00080000)
+#define ALTERA_TSE_CMD_SLEEP_MSK (0x00100000)
+#define ALTERA_TSE_CMD_WAKEUP_MSK (0x00200000)
+#define ALTERA_TSE_CMD_XOFF_GEN_MSK (0x00400000)
+#define ALTERA_TSE_CMD_CNTL_FRM_ENA_MSK (0x00800000)
+#define ALTERA_TSE_CMD_NO_LENGTH_CHECK_MSK (0x01000000)
+#define ALTERA_TSE_CMD_ENA_10_MSK (0x02000000)
+#define ALTERA_TSE_CMD_RX_ERR_DISC_MSK (0x04000000)
+/* Bits (30..27) reserved */
+#define ALTERA_TSE_CMD_CNT_RESET_MSK (0x80000000)
+
+#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 (0x00040000)
+#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC (0x00020000)
+
+#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16 (0x02000000)
+
+#define ALT_TSE_SW_RESET_WATCHDOG_CNTR 10000
+#define ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR 90000000
+
+/* Command_Config Register Bit Definitions */
+
+typedef volatile union __alt_tse_command_config {
+ unsigned int image;
+ struct {
+ unsigned int
+ transmit_enable:1, /* bit 0 */
+ receive_enable:1, /* bit 1 */
+ pause_frame_xon_gen:1, /* bit 2 */
+ ethernet_speed:1, /* bit 3 */
+ promiscuous_enable:1, /* bit 4 */
+ pad_enable:1, /* bit 5 */
+ crc_forward:1, /* bit 6 */
+ pause_frame_forward:1, /* bit 7 */
+ pause_frame_ignore:1, /* bit 8 */
+ set_mac_address_on_tx:1, /* bit 9 */
+ halfduplex_enable:1, /* bit 10 */
+ excessive_collision:1, /* bit 11 */
+ late_collision:1, /* bit 12 */
+ software_reset:1, /* bit 13 */
+ multicast_hash_mode_sel:1, /* bit 14 */
+ loopback_enable:1, /* bit 15 */
+ src_mac_addr_sel_on_tx:3, /* bit 18:16 */
+ magic_packet_detect:1, /* bit 19 */
+ sleep_mode_enable:1, /* bit 20 */
+ wake_up_request:1, /* bit 21 */
+ pause_frame_xoff_gen:1, /* bit 22 */
+ control_frame_enable:1, /* bit 23 */
+ payload_len_chk_disable:1, /* bit 24 */
+ enable_10mbps_intf:1, /* bit 25 */
+ rx_error_discard_enable:1, /* bit 26 */
+ reserved_bits:4, /* bit 30:27 */
+ self_clear_counter_reset:1; /* bit 31 */
+ } __packed_1_ bits;
+} __packed_1_ alt_tse_command_config;
+
+/* Tx_Cmd_Stat Register Bit Definitions */
+
+typedef volatile union __alt_tse_tx_cmd_stat {
+ unsigned int image;
+ struct {
+ unsigned int reserved_lsbs:17, /* bit 16:0 */
+ omit_crc:1, /* bit 17 */
+ tx_shift16:1, /* bit 18 */
+ reserved_msbs:13; /* bit 31:19 */
+
+ } __packed_1_ bits;
+} alt_tse_tx_cmd_stat;
+
+/* Rx_Cmd_Stat Register Bit Definitions */
+
+typedef volatile union __alt_tse_rx_cmd_stat {
+ unsigned int image;
+ struct {
+ unsigned int reserved_lsbs:25, /* bit 24:0 */
+ rx_shift16:1, /* bit 25 */
+ reserved_msbs:6; /* bit 31:26 */
+
+ } __packed_1_ bits;
+} alt_tse_rx_cmd_stat;
+
+struct alt_tse_mdio {
+ unsigned int control; /*PHY device operation control register */
+ unsigned int status; /*PHY device operation status register */
+ unsigned int phy_id1; /*Bits 31:16 of PHY identifier. */
+ unsigned int phy_id2; /*Bits 15:0 of PHY identifier. */
+ unsigned int auto_negotiation_advertisement;
+ unsigned int remote_partner_base_page_ability;
+
+ unsigned int reg6;
+ unsigned int reg7;
+ unsigned int reg8;
+ unsigned int reg9;
+ unsigned int rega;
+ unsigned int regb;
+ unsigned int regc;
+ unsigned int regd;
+ unsigned int rege;
+ unsigned int regf;
+ unsigned int reg10;
+ unsigned int reg11;
+ unsigned int reg12;
+ unsigned int reg13;
+ unsigned int reg14;
+ unsigned int reg15;
+ unsigned int reg16;
+ unsigned int reg17;
+ unsigned int reg18;
+ unsigned int reg19;
+ unsigned int reg1a;
+ unsigned int reg1b;
+ unsigned int reg1c;
+ unsigned int reg1d;
+ unsigned int reg1e;
+ unsigned int reg1f;
+};
+
+/* MAC register Space */
+
+struct alt_tse_mac {
+ unsigned int megacore_revision;
+ unsigned int scratch_pad;
+ alt_tse_command_config command_config;
+ unsigned int mac_addr_0;
+ unsigned int mac_addr_1;
+ unsigned int max_frame_length;
+ unsigned int pause_quanta;
+ unsigned int rx_sel_empty_threshold;
+ unsigned int rx_sel_full_threshold;
+ unsigned int tx_sel_empty_threshold;
+ unsigned int tx_sel_full_threshold;
+ unsigned int rx_almost_empty_threshold;
+ unsigned int rx_almost_full_threshold;
+ unsigned int tx_almost_empty_threshold;
+ unsigned int tx_almost_full_threshold;
+ unsigned int mdio_phy0_addr;
+ unsigned int mdio_phy1_addr;
+
+ /* only if 100/1000 BaseX PCS, reserved otherwise */
+ unsigned int reservedx44[5];
+
+ unsigned int reg_read_access_status;
+ unsigned int min_tx_ipg_length;
+
+ /* IEEE 802.3 oEntity Managed Object Support */
+ unsigned int aMACID_1; /*The MAC addresses */
+ unsigned int aMACID_2;
+ unsigned int aFramesTransmittedOK;
+ unsigned int aFramesReceivedOK;
+ unsigned int aFramesCheckSequenceErrors;
+ unsigned int aAlignmentErrors;
+ unsigned int aOctetsTransmittedOK;
+ unsigned int aOctetsReceivedOK;
+
+ /* IEEE 802.3 oPausedEntity Managed Object Support */
+ unsigned int aTxPAUSEMACCtrlFrames;
+ unsigned int aRxPAUSEMACCtrlFrames;
+
+ /* IETF MIB (MIB-II) Object Support */
+ unsigned int ifInErrors;
+ unsigned int ifOutErrors;
+ unsigned int ifInUcastPkts;
+ unsigned int ifInMulticastPkts;
+ unsigned int ifInBroadcastPkts;
+ unsigned int ifOutDiscards;
+ unsigned int ifOutUcastPkts;
+ unsigned int ifOutMulticastPkts;
+ unsigned int ifOutBroadcastPkts;
+
+ /* IETF RMON MIB Object Support */
+ unsigned int etherStatsDropEvent;
+ unsigned int etherStatsOctets;
+ unsigned int etherStatsPkts;
+ unsigned int etherStatsUndersizePkts;
+ unsigned int etherStatsOversizePkts;
+ unsigned int etherStatsPkts64Octets;
+ unsigned int etherStatsPkts65to127Octets;
+ unsigned int etherStatsPkts128to255Octets;
+ unsigned int etherStatsPkts256to511Octets;
+ unsigned int etherStatsPkts512to1023Octets;
+ unsigned int etherStatsPkts1024to1518Octets;
+
+ unsigned int etherStatsPkts1519toXOctets;
+ unsigned int etherStatsJabbers;
+ unsigned int etherStatsFragments;
+
+ unsigned int reservedxE4;
+
+ /*FIFO control register. */
+ alt_tse_tx_cmd_stat tx_cmd_stat;
+ alt_tse_rx_cmd_stat rx_cmd_stat;
+
+ unsigned int ipaccTxConf;
+ unsigned int ipaccRxConf;
+ unsigned int ipaccRxStat;
+ unsigned int ipaccRxStatSum;
+
+ /*Multicast address resolution table */
+ unsigned int hash_table[64];
+
+ /*Registers 0 to 31 within PHY device 0/1 */
+ struct alt_tse_mdio mdio_phy0;
+ struct alt_tse_mdio mdio_phy1;
+
+ /*4 Supplemental MAC Addresses */
+ unsigned int supp_mac_addr_0_0;
+ unsigned int supp_mac_addr_0_1;
+ unsigned int supp_mac_addr_1_0;
+ unsigned int supp_mac_addr_1_1;
+ unsigned int supp_mac_addr_2_0;
+ unsigned int supp_mac_addr_2_1;
+ unsigned int supp_mac_addr_3_0;
+ unsigned int supp_mac_addr_3_1;
+
+ unsigned int reservedx320[56];
+};
+
+/* flags: TSE MII modes */
+/* GMII/MII = 0 */
+/* RGMII = 1 */
+/* RGMII_ID = 2 */
+/* RGMII_TXID = 3 */
+/* RGMII_RXID = 4 */
+/* SGMII = 5 */
+struct altera_tse_priv {
+ char devname[16];
+ volatile struct alt_tse_mac *mac_dev;
+ volatile struct alt_sgdma_registers *sgdma_rx;
+ volatile struct alt_sgdma_registers *sgdma_tx;
+ unsigned int rx_sgdma_irq;
+ unsigned int tx_sgdma_irq;
+ unsigned int has_descriptor_mem;
+ unsigned int descriptor_mem_base;
+ unsigned int descriptor_mem_size;
+ volatile struct alt_sgdma_descriptor *rx_desc;
+ volatile struct alt_sgdma_descriptor *tx_desc;
+ volatile unsigned char *rx_buf;
+ struct phy_info *phyinfo;
+ unsigned int phyaddr;
+ unsigned int flags;
+ unsigned int link;
+ unsigned int duplexity;
+ unsigned int speed;
+};
+
+/* Phy stuff continued */
+/*
+ * struct phy_cmd: A command for reading or writing a PHY register
+ *
+ * mii_reg: The register to read or write
+ *
+ * mii_data: For writes, the value to put in the register.
+ * A value of -1 indicates this is a read.
+ *
+ * funct: A function pointer which is invoked for each command.
+ * For reads, this function will be passed the value read
+ * from the PHY, and process it.
+ * For writes, the result of this function will be written
+ * to the PHY register
+ */
+struct phy_cmd {
+ uint mii_reg;
+ uint mii_data;
+ uint(*funct) (uint mii_reg, struct altera_tse_priv *priv);
+};
+#endif /* _ALTERA_TSE_H_ */
diff --git a/qemu/roms/u-boot/drivers/net/armada100_fec.c b/qemu/roms/u-boot/drivers/net/armada100_fec.c
new file mode 100644
index 000000000..a8da6b17d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/armada100_fec.c
@@ -0,0 +1,726 @@
+/*
+ * (C) Copyright 2011
+ * eInfochips Ltd. <www.einfochips.com>
+ * Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
+ *
+ * (C) Copyright 2010
+ * Marvell Semiconductor <www.marvell.com>
+ * Contributor: Mahavir Jain <mjain@marvell.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <netdev.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#include <linux/err.h>
+#include <linux/mii.h>
+#include <asm/io.h>
+#include <asm/arch/armada100.h>
+#include "armada100_fec.h"
+
+#define PHY_ADR_REQ 0xFF /* Magic number to read/write PHY address */
+
+#ifdef DEBUG
+static int eth_dump_regs(struct eth_device *dev)
+{
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct armdfec_reg *regs = darmdfec->regs;
+ unsigned int i = 0;
+
+ printf("\noffset: phy_adr, value: 0x%x\n", readl(&regs->phyadr));
+ printf("offset: smi, value: 0x%x\n", readl(&regs->smi));
+ for (i = 0x400; i <= 0x4e4; i += 4)
+ printf("offset: 0x%x, value: 0x%x\n",
+ i, readl(ARMD1_FEC_BASE + i));
+ return 0;
+}
+#endif
+
+static int armdfec_phy_timeout(u32 *reg, u32 flag, int cond)
+{
+ u32 timeout = PHY_WAIT_ITERATIONS;
+ u32 reg_val;
+
+ while (--timeout) {
+ reg_val = readl(reg);
+ if (cond && (reg_val & flag))
+ break;
+ else if (!cond && !(reg_val & flag))
+ break;
+ udelay(PHY_WAIT_MICRO_SECONDS);
+ }
+ return !timeout;
+}
+
+static int smi_reg_read(const char *devname, u8 phy_addr, u8 phy_reg,
+ u16 *value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct armdfec_reg *regs = darmdfec->regs;
+ u32 val;
+
+ if (phy_addr == PHY_ADR_REQ && phy_reg == PHY_ADR_REQ) {
+ val = readl(&regs->phyadr);
+ *value = val & 0x1f;
+ return 0;
+ }
+
+ /* check parameters */
+ if (phy_addr > PHY_MASK) {
+ printf("ARMD100 FEC: (%s) Invalid phy address: 0x%X\n",
+ __func__, phy_addr);
+ return -EINVAL;
+ }
+ if (phy_reg > PHY_MASK) {
+ printf("ARMD100 FEC: (%s) Invalid register offset: 0x%X\n",
+ __func__, phy_reg);
+ return -EINVAL;
+ }
+
+ /* wait for the SMI register to become available */
+ if (armdfec_phy_timeout(&regs->smi, SMI_BUSY, false)) {
+ printf("ARMD100 FEC: (%s) PHY busy timeout\n", __func__);
+ return -1;
+ }
+
+ writel((phy_addr << 16) | (phy_reg << 21) | SMI_OP_R, &regs->smi);
+
+ /* now wait for the data to be valid */
+ if (armdfec_phy_timeout(&regs->smi, SMI_R_VALID, true)) {
+ val = readl(&regs->smi);
+ printf("ARMD100 FEC: (%s) PHY Read timeout, val=0x%x\n",
+ __func__, val);
+ return -1;
+ }
+ val = readl(&regs->smi);
+ *value = val & 0xffff;
+
+ return 0;
+}
+
+static int smi_reg_write(const char *devname,
+ u8 phy_addr, u8 phy_reg, u16 value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct armdfec_reg *regs = darmdfec->regs;
+
+ if (phy_addr == PHY_ADR_REQ && phy_reg == PHY_ADR_REQ) {
+ clrsetbits_le32(&regs->phyadr, 0x1f, value & 0x1f);
+ return 0;
+ }
+
+ /* check parameters */
+ if (phy_addr > PHY_MASK) {
+ printf("ARMD100 FEC: (%s) Invalid phy address\n", __func__);
+ return -EINVAL;
+ }
+ if (phy_reg > PHY_MASK) {
+ printf("ARMD100 FEC: (%s) Invalid register offset\n", __func__);
+ return -EINVAL;
+ }
+
+ /* wait for the SMI register to become available */
+ if (armdfec_phy_timeout(&regs->smi, SMI_BUSY, false)) {
+ printf("ARMD100 FEC: (%s) PHY busy timeout\n", __func__);
+ return -1;
+ }
+
+ writel((phy_addr << 16) | (phy_reg << 21) | SMI_OP_W | (value & 0xffff),
+ &regs->smi);
+ return 0;
+}
+
+/*
+ * Abort any transmit and receive operations and put DMA
+ * in idle state. AT and AR bits are cleared upon entering
+ * in IDLE state. So poll those bits to verify operation.
+ */
+static void abortdma(struct eth_device *dev)
+{
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct armdfec_reg *regs = darmdfec->regs;
+ int delay;
+ int maxretries = 40;
+ u32 tmp;
+
+ while (--maxretries) {
+ writel(SDMA_CMD_AR | SDMA_CMD_AT, &regs->sdma_cmd);
+ udelay(100);
+
+ delay = 10;
+ while (--delay) {
+ tmp = readl(&regs->sdma_cmd);
+ if (!(tmp & (SDMA_CMD_AR | SDMA_CMD_AT)))
+ break;
+ udelay(10);
+ }
+ if (delay)
+ break;
+ }
+
+ if (!maxretries)
+ printf("ARMD100 FEC: (%s) DMA Stuck\n", __func__);
+}
+
+static inline u32 nibble_swapping_32_bit(u32 x)
+{
+ return ((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4);
+}
+
+static inline u32 nibble_swapping_16_bit(u32 x)
+{
+ return ((x & 0x0000f0f0) >> 4) | ((x & 0x00000f0f) << 4);
+}
+
+static inline u32 flip_4_bits(u32 x)
+{
+ return ((x & 0x01) << 3) | ((x & 0x002) << 1)
+ | ((x & 0x04) >> 1) | ((x & 0x008) >> 3);
+}
+
+/*
+ * This function will calculate the hash function of the address.
+ * depends on the hash mode and hash size.
+ * Inputs
+ * mach - the 2 most significant bytes of the MAC address.
+ * macl - the 4 least significant bytes of the MAC address.
+ * Outputs
+ * return the calculated entry.
+ */
+static u32 hash_function(u32 mach, u32 macl)
+{
+ u32 hashresult;
+ u32 addrh;
+ u32 addrl;
+ u32 addr0;
+ u32 addr1;
+ u32 addr2;
+ u32 addr3;
+ u32 addrhswapped;
+ u32 addrlswapped;
+
+ addrh = nibble_swapping_16_bit(mach);
+ addrl = nibble_swapping_32_bit(macl);
+
+ addrhswapped = flip_4_bits(addrh & 0xf)
+ + ((flip_4_bits((addrh >> 4) & 0xf)) << 4)
+ + ((flip_4_bits((addrh >> 8) & 0xf)) << 8)
+ + ((flip_4_bits((addrh >> 12) & 0xf)) << 12);
+
+ addrlswapped = flip_4_bits(addrl & 0xf)
+ + ((flip_4_bits((addrl >> 4) & 0xf)) << 4)
+ + ((flip_4_bits((addrl >> 8) & 0xf)) << 8)
+ + ((flip_4_bits((addrl >> 12) & 0xf)) << 12)
+ + ((flip_4_bits((addrl >> 16) & 0xf)) << 16)
+ + ((flip_4_bits((addrl >> 20) & 0xf)) << 20)
+ + ((flip_4_bits((addrl >> 24) & 0xf)) << 24)
+ + ((flip_4_bits((addrl >> 28) & 0xf)) << 28);
+
+ addrh = addrhswapped;
+ addrl = addrlswapped;
+
+ addr0 = (addrl >> 2) & 0x03f;
+ addr1 = (addrl & 0x003) | (((addrl >> 8) & 0x7f) << 2);
+ addr2 = (addrl >> 15) & 0x1ff;
+ addr3 = ((addrl >> 24) & 0x0ff) | ((addrh & 1) << 8);
+
+ hashresult = (addr0 << 9) | (addr1 ^ addr2 ^ addr3);
+ hashresult = hashresult & 0x07ff;
+ return hashresult;
+}
+
+/*
+ * This function will add an entry to the address table.
+ * depends on the hash mode and hash size that was initialized.
+ * Inputs
+ * mach - the 2 most significant bytes of the MAC address.
+ * macl - the 4 least significant bytes of the MAC address.
+ * skip - if 1, skip this address.
+ * rd - the RD field in the address table.
+ * Outputs
+ * address table entry is added.
+ * 0 if success.
+ * -ENOSPC if table full
+ */
+static int add_del_hash_entry(struct armdfec_device *darmdfec, u32 mach,
+ u32 macl, u32 rd, u32 skip, int del)
+{
+ struct addr_table_entry_t *entry, *start;
+ u32 newhi;
+ u32 newlo;
+ u32 i;
+
+ newlo = (((mach >> 4) & 0xf) << 15)
+ | (((mach >> 0) & 0xf) << 11)
+ | (((mach >> 12) & 0xf) << 7)
+ | (((mach >> 8) & 0xf) << 3)
+ | (((macl >> 20) & 0x1) << 31)
+ | (((macl >> 16) & 0xf) << 27)
+ | (((macl >> 28) & 0xf) << 23)
+ | (((macl >> 24) & 0xf) << 19)
+ | (skip << HTESKIP) | (rd << HTERDBIT)
+ | HTEVALID;
+
+ newhi = (((macl >> 4) & 0xf) << 15)
+ | (((macl >> 0) & 0xf) << 11)
+ | (((macl >> 12) & 0xf) << 7)
+ | (((macl >> 8) & 0xf) << 3)
+ | (((macl >> 21) & 0x7) << 0);
+
+ /*
+ * Pick the appropriate table, start scanning for free/reusable
+ * entries at the index obtained by hashing the specified MAC address
+ */
+ start = (struct addr_table_entry_t *)(darmdfec->htpr);
+ entry = start + hash_function(mach, macl);
+ for (i = 0; i < HOP_NUMBER; i++) {
+ if (!(entry->lo & HTEVALID)) {
+ break;
+ } else {
+ /* if same address put in same position */
+ if (((entry->lo & 0xfffffff8) == (newlo & 0xfffffff8))
+ && (entry->hi == newhi))
+ break;
+ }
+ if (entry == start + 0x7ff)
+ entry = start;
+ else
+ entry++;
+ }
+
+ if (((entry->lo & 0xfffffff8) != (newlo & 0xfffffff8)) &&
+ (entry->hi != newhi) && del)
+ return 0;
+
+ if (i == HOP_NUMBER) {
+ if (!del) {
+ printf("ARMD100 FEC: (%s) table section is full\n",
+ __func__);
+ return -ENOSPC;
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * Update the selected entry
+ */
+ if (del) {
+ entry->hi = 0;
+ entry->lo = 0;
+ } else {
+ entry->hi = newhi;
+ entry->lo = newlo;
+ }
+
+ return 0;
+}
+
+/*
+ * Create an addressTable entry from MAC address info
+ * found in the specifed net_device struct
+ *
+ * Input : pointer to ethernet interface network device structure
+ * Output : N/A
+ */
+static void update_hash_table_mac_address(struct armdfec_device *darmdfec,
+ u8 *oaddr, u8 *addr)
+{
+ u32 mach;
+ u32 macl;
+
+ /* Delete old entry */
+ if (oaddr) {
+ mach = (oaddr[0] << 8) | oaddr[1];
+ macl = (oaddr[2] << 24) | (oaddr[3] << 16) |
+ (oaddr[4] << 8) | oaddr[5];
+ add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_DELETE);
+ }
+
+ /* Add new entry */
+ mach = (addr[0] << 8) | addr[1];
+ macl = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+ add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_ADD);
+}
+
+/* Address Table Initialization */
+static void init_hashtable(struct eth_device *dev)
+{
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct armdfec_reg *regs = darmdfec->regs;
+ memset(darmdfec->htpr, 0, HASH_ADDR_TABLE_SIZE);
+ writel((u32)darmdfec->htpr, &regs->htpr);
+}
+
+/*
+ * This detects PHY chip from address 0-31 by reading PHY status
+ * registers. PHY chip can be connected at any of this address.
+ */
+static int ethernet_phy_detect(struct eth_device *dev)
+{
+ u32 val;
+ u16 tmp, mii_status;
+ u8 addr;
+
+ for (addr = 0; addr < 32; addr++) {
+ if (miiphy_read(dev->name, addr, MII_BMSR, &mii_status) != 0)
+ /* try next phy */
+ continue;
+
+ /* invalid MII status. More validation required here... */
+ if (mii_status == 0 || mii_status == 0xffff)
+ /* try next phy */
+ continue;
+
+ if (miiphy_read(dev->name, addr, MII_PHYSID1, &tmp) != 0)
+ /* try next phy */
+ continue;
+
+ val = tmp << 16;
+ if (miiphy_read(dev->name, addr, MII_PHYSID2, &tmp) != 0)
+ /* try next phy */
+ continue;
+
+ val |= tmp;
+
+ if ((val & 0xfffffff0) != 0)
+ return addr;
+ }
+ return -1;
+}
+
+static void armdfec_init_rx_desc_ring(struct armdfec_device *darmdfec)
+{
+ struct rx_desc *p_rx_desc;
+ int i;
+
+ /* initialize the Rx descriptors ring */
+ p_rx_desc = darmdfec->p_rxdesc;
+ for (i = 0; i < RINGSZ; i++) {
+ p_rx_desc->cmd_sts = BUF_OWNED_BY_DMA | RX_EN_INT;
+ p_rx_desc->buf_size = PKTSIZE_ALIGN;
+ p_rx_desc->byte_cnt = 0;
+ p_rx_desc->buf_ptr = darmdfec->p_rxbuf + i * PKTSIZE_ALIGN;
+ if (i == (RINGSZ - 1)) {
+ p_rx_desc->nxtdesc_p = darmdfec->p_rxdesc;
+ } else {
+ p_rx_desc->nxtdesc_p = (struct rx_desc *)
+ ((u32)p_rx_desc + ARMDFEC_RXQ_DESC_ALIGNED_SIZE);
+ p_rx_desc = p_rx_desc->nxtdesc_p;
+ }
+ }
+ darmdfec->p_rxdesc_curr = darmdfec->p_rxdesc;
+}
+
+static int armdfec_init(struct eth_device *dev, bd_t *bd)
+{
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct armdfec_reg *regs = darmdfec->regs;
+ int phy_adr;
+ u32 temp;
+
+ armdfec_init_rx_desc_ring(darmdfec);
+
+ /* Disable interrupts */
+ writel(0, &regs->im);
+ writel(0, &regs->ic);
+ /* Write to ICR to clear interrupts. */
+ writel(0, &regs->iwc);
+
+ /*
+ * Abort any transmit and receive operations and put DMA
+ * in idle state.
+ */
+ abortdma(dev);
+
+ /* Initialize address hash table */
+ init_hashtable(dev);
+
+ /* SDMA configuration */
+ writel(SDCR_BSZ8 | /* Burst size = 32 bytes */
+ SDCR_RIFB | /* Rx interrupt on frame */
+ SDCR_BLMT | /* Little endian transmit */
+ SDCR_BLMR | /* Little endian receive */
+ SDCR_RC_MAX_RETRANS, /* Max retransmit count */
+ &regs->sdma_conf);
+ /* Port Configuration */
+ writel(PCR_HS, &regs->pconf); /* Hash size is 1/2kb */
+
+ /* Set extended port configuration */
+ writel(PCXR_2BSM | /* Two byte suffix aligns IP hdr */
+ PCXR_DSCP_EN | /* Enable DSCP in IP */
+ PCXR_MFL_1536 | /* Set MTU = 1536 */
+ PCXR_FLP | /* do not force link pass */
+ PCXR_TX_HIGH_PRI, /* Transmit - high priority queue */
+ &regs->pconf_ext);
+
+ update_hash_table_mac_address(darmdfec, NULL, dev->enetaddr);
+
+ /* Update TX and RX queue descriptor register */
+ temp = (u32)&regs->txcdp[TXQ];
+ writel((u32)darmdfec->p_txdesc, temp);
+ temp = (u32)&regs->rxfdp[RXQ];
+ writel((u32)darmdfec->p_rxdesc, temp);
+ temp = (u32)&regs->rxcdp[RXQ];
+ writel((u32)darmdfec->p_rxdesc_curr, temp);
+
+ /* Enable Interrupts */
+ writel(ALL_INTS, &regs->im);
+
+ /* Enable Ethernet Port */
+ setbits_le32(&regs->pconf, PCR_EN);
+
+ /* Enable RX DMA engine */
+ setbits_le32(&regs->sdma_cmd, SDMA_CMD_ERD);
+
+#ifdef DEBUG
+ eth_dump_regs(dev);
+#endif
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+
+#if defined(CONFIG_PHY_BASE_ADR)
+ miiphy_write(dev->name, PHY_ADR_REQ, PHY_ADR_REQ, CONFIG_PHY_BASE_ADR);
+#else
+ /* Search phy address from range 0-31 */
+ phy_adr = ethernet_phy_detect(dev);
+ if (phy_adr < 0) {
+ printf("ARMD100 FEC: PHY not detected at address range 0-31\n");
+ return -1;
+ } else {
+ debug("ARMD100 FEC: PHY detected at addr %d\n", phy_adr);
+ miiphy_write(dev->name, PHY_ADR_REQ, PHY_ADR_REQ, phy_adr);
+ }
+#endif
+
+#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
+ /* Wait up to 5s for the link status */
+ for (i = 0; i < 5; i++) {
+ u16 phy_adr;
+
+ miiphy_read(dev->name, 0xFF, 0xFF, &phy_adr);
+ /* Return if we get link up */
+ if (miiphy_link(dev->name, phy_adr))
+ return 0;
+ udelay(1000000);
+ }
+
+ printf("ARMD100 FEC: No link on %s\n", dev->name);
+ return -1;
+#endif
+#endif
+ return 0;
+}
+
+static void armdfec_halt(struct eth_device *dev)
+{
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct armdfec_reg *regs = darmdfec->regs;
+
+ /* Stop RX DMA */
+ clrbits_le32(&regs->sdma_cmd, SDMA_CMD_ERD);
+
+ /*
+ * Abort any transmit and receive operations and put DMA
+ * in idle state.
+ */
+ abortdma(dev);
+
+ /* Disable interrupts */
+ writel(0, &regs->im);
+ writel(0, &regs->ic);
+ writel(0, &regs->iwc);
+
+ /* Disable Port */
+ clrbits_le32(&regs->pconf, PCR_EN);
+}
+
+static int armdfec_send(struct eth_device *dev, void *dataptr, int datasize)
+{
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct armdfec_reg *regs = darmdfec->regs;
+ struct tx_desc *p_txdesc = darmdfec->p_txdesc;
+ void *p = (void *)dataptr;
+ int retry = PHY_WAIT_ITERATIONS * PHY_WAIT_MICRO_SECONDS;
+ u32 cmd_sts, temp;
+
+ /* Copy buffer if it's misaligned */
+ if ((u32)dataptr & 0x07) {
+ if (datasize > PKTSIZE_ALIGN) {
+ printf("ARMD100 FEC: Non-aligned data too large (%d)\n",
+ datasize);
+ return -1;
+ }
+ memcpy(darmdfec->p_aligned_txbuf, p, datasize);
+ p = darmdfec->p_aligned_txbuf;
+ }
+
+ p_txdesc->cmd_sts = TX_ZERO_PADDING | TX_GEN_CRC;
+ p_txdesc->cmd_sts |= TX_FIRST_DESC | TX_LAST_DESC;
+ p_txdesc->cmd_sts |= BUF_OWNED_BY_DMA;
+ p_txdesc->cmd_sts |= TX_EN_INT;
+ p_txdesc->buf_ptr = p;
+ p_txdesc->byte_cnt = datasize;
+
+ /* Apply send command using high priority TX queue */
+ temp = (u32)&regs->txcdp[TXQ];
+ writel((u32)p_txdesc, temp);
+ writel(SDMA_CMD_TXDL | SDMA_CMD_TXDH | SDMA_CMD_ERD, &regs->sdma_cmd);
+
+ /*
+ * wait for packet xmit completion
+ */
+ cmd_sts = readl(&p_txdesc->cmd_sts);
+ while (cmd_sts & BUF_OWNED_BY_DMA) {
+ /* return fail if error is detected */
+ if ((cmd_sts & (TX_ERROR | TX_LAST_DESC)) ==
+ (TX_ERROR | TX_LAST_DESC)) {
+ printf("ARMD100 FEC: (%s) in xmit packet\n", __func__);
+ return -1;
+ }
+ cmd_sts = readl(&p_txdesc->cmd_sts);
+ if (!(retry--)) {
+ printf("ARMD100 FEC: (%s) xmit packet timeout!\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int armdfec_recv(struct eth_device *dev)
+{
+ struct armdfec_device *darmdfec = to_darmdfec(dev);
+ struct rx_desc *p_rxdesc_curr = darmdfec->p_rxdesc_curr;
+ u32 cmd_sts;
+ u32 timeout = 0;
+ u32 temp;
+
+ /* wait untill rx packet available or timeout */
+ do {
+ if (timeout < PHY_WAIT_ITERATIONS * PHY_WAIT_MICRO_SECONDS) {
+ timeout++;
+ } else {
+ debug("ARMD100 FEC: %s time out...\n", __func__);
+ return -1;
+ }
+ } while (readl(&p_rxdesc_curr->cmd_sts) & BUF_OWNED_BY_DMA);
+
+ if (p_rxdesc_curr->byte_cnt != 0) {
+ debug("ARMD100 FEC: %s: Received %d byte Packet @ 0x%x"
+ "(cmd_sts= %08x)\n", __func__,
+ (u32)p_rxdesc_curr->byte_cnt,
+ (u32)p_rxdesc_curr->buf_ptr,
+ (u32)p_rxdesc_curr->cmd_sts);
+ }
+
+ /*
+ * In case received a packet without first/last bits on
+ * OR the error summary bit is on,
+ * the packets needs to be dropeed.
+ */
+ cmd_sts = readl(&p_rxdesc_curr->cmd_sts);
+
+ if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
+ (RX_FIRST_DESC | RX_LAST_DESC)) {
+ printf("ARMD100 FEC: (%s) Dropping packet spread on"
+ " multiple descriptors\n", __func__);
+ } else if (cmd_sts & RX_ERROR) {
+ printf("ARMD100 FEC: (%s) Dropping packet with errors\n",
+ __func__);
+ } else {
+ /* !!! call higher layer processing */
+ debug("ARMD100 FEC: (%s) Sending Received packet to"
+ " upper layer (NetReceive)\n", __func__);
+
+ /*
+ * let the upper layer handle the packet, subtract offset
+ * as two dummy bytes are added in received buffer see
+ * PORT_CONFIG_EXT register bit TWO_Byte_Stuff_Mode bit.
+ */
+ NetReceive((p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET),
+ (int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET));
+ }
+ /*
+ * free these descriptors and point next in the ring
+ */
+ p_rxdesc_curr->cmd_sts = BUF_OWNED_BY_DMA | RX_EN_INT;
+ p_rxdesc_curr->buf_size = PKTSIZE_ALIGN;
+ p_rxdesc_curr->byte_cnt = 0;
+
+ temp = (u32)&darmdfec->p_rxdesc_curr;
+ writel((u32)p_rxdesc_curr->nxtdesc_p, temp);
+
+ return 0;
+}
+
+int armada100_fec_register(unsigned long base_addr)
+{
+ struct armdfec_device *darmdfec;
+ struct eth_device *dev;
+
+ darmdfec = malloc(sizeof(struct armdfec_device));
+ if (!darmdfec)
+ goto error;
+
+ memset(darmdfec, 0, sizeof(struct armdfec_device));
+
+ darmdfec->htpr = memalign(8, HASH_ADDR_TABLE_SIZE);
+ if (!darmdfec->htpr)
+ goto error1;
+
+ darmdfec->p_rxdesc = memalign(PKTALIGN,
+ ARMDFEC_RXQ_DESC_ALIGNED_SIZE * RINGSZ + 1);
+
+ if (!darmdfec->p_rxdesc)
+ goto error1;
+
+ darmdfec->p_rxbuf = memalign(PKTALIGN, RINGSZ * PKTSIZE_ALIGN + 1);
+ if (!darmdfec->p_rxbuf)
+ goto error1;
+
+ darmdfec->p_aligned_txbuf = memalign(8, PKTSIZE_ALIGN);
+ if (!darmdfec->p_aligned_txbuf)
+ goto error1;
+
+ darmdfec->p_txdesc = memalign(PKTALIGN, sizeof(struct tx_desc) + 1);
+ if (!darmdfec->p_txdesc)
+ goto error1;
+
+ dev = &darmdfec->dev;
+ /* Assign ARMADA100 Fast Ethernet Controller Base Address */
+ darmdfec->regs = (void *)base_addr;
+
+ /* must be less than sizeof(dev->name) */
+ strcpy(dev->name, "armd-fec0");
+
+ dev->init = armdfec_init;
+ dev->halt = armdfec_halt;
+ dev->send = armdfec_send;
+ dev->recv = armdfec_recv;
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, smi_reg_read, smi_reg_write);
+#endif
+ return 0;
+
+error1:
+ free(darmdfec->p_aligned_txbuf);
+ free(darmdfec->p_rxbuf);
+ free(darmdfec->p_rxdesc);
+ free(darmdfec->htpr);
+error:
+ free(darmdfec);
+ printf("AMD100 FEC: (%s) Failed to allocate memory\n", __func__);
+ return -1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/armada100_fec.h b/qemu/roms/u-boot/drivers/net/armada100_fec.h
new file mode 100644
index 000000000..5a0a3d982
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/armada100_fec.h
@@ -0,0 +1,209 @@
+/*
+ * (C) Copyright 2011
+ * eInfochips Ltd. <www.einfochips.com>
+ * Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
+ *
+ * (C) Copyright 2010
+ * Marvell Semiconductor <www.marvell.com>
+ * Contributor: Mahavir Jain <mjain@marvell.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ARMADA100_FEC_H__
+#define __ARMADA100_FEC_H__
+
+#define PORT_NUM 0x0
+
+/* RX & TX descriptor command */
+#define BUF_OWNED_BY_DMA (1<<31)
+
+/* RX descriptor status */
+#define RX_EN_INT (1<<23)
+#define RX_FIRST_DESC (1<<17)
+#define RX_LAST_DESC (1<<16)
+#define RX_ERROR (1<<15)
+
+/* TX descriptor command */
+#define TX_EN_INT (1<<23)
+#define TX_GEN_CRC (1<<22)
+#define TX_ZERO_PADDING (1<<18)
+#define TX_FIRST_DESC (1<<17)
+#define TX_LAST_DESC (1<<16)
+#define TX_ERROR (1<<15)
+
+/* smi register */
+#define SMI_BUSY (1<<28) /* 0 - Write, 1 - Read */
+#define SMI_R_VALID (1<<27) /* 0 - Write, 1 - Read */
+#define SMI_OP_W (0<<26) /* Write operation */
+#define SMI_OP_R (1<<26) /* Read operation */
+
+#define HASH_ADD 0
+#define HASH_DELETE 1
+#define HASH_ADDR_TABLE_SIZE 0x4000 /* 16K (1/2K address - PCR_HS == 1) */
+#define HOP_NUMBER 12
+
+#define PHY_WAIT_ITERATIONS 1000 /* 1000 iterations * 10uS = 10mS max */
+#define PHY_WAIT_MICRO_SECONDS 10
+
+#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */
+#define ETH_EXTRA_HEADER (6+6+2+4)
+ /* dest+src addr+protocol id+crc */
+#define MAX_PKT_SIZE 1536
+
+
+/* Bit definitions of the SDMA Config Reg */
+#define SDCR_BSZ_OFF 12
+#define SDCR_BSZ8 (3<<SDCR_BSZ_OFF)
+#define SDCR_BSZ4 (2<<SDCR_BSZ_OFF)
+#define SDCR_BSZ2 (1<<SDCR_BSZ_OFF)
+#define SDCR_BSZ1 (0<<SDCR_BSZ_OFF)
+#define SDCR_BLMR (1<<6)
+#define SDCR_BLMT (1<<7)
+#define SDCR_RIFB (1<<9)
+#define SDCR_RC_OFF 2
+#define SDCR_RC_MAX_RETRANS (0xf << SDCR_RC_OFF)
+
+/* SDMA_CMD */
+#define SDMA_CMD_AT (1<<31)
+#define SDMA_CMD_TXDL (1<<24)
+#define SDMA_CMD_TXDH (1<<23)
+#define SDMA_CMD_AR (1<<15)
+#define SDMA_CMD_ERD (1<<7)
+
+
+/* Bit definitions of the Port Config Reg */
+#define PCR_HS (1<<12)
+#define PCR_EN (1<<7)
+#define PCR_PM (1<<0)
+
+/* Bit definitions of the Port Config Extend Reg */
+#define PCXR_2BSM (1<<28)
+#define PCXR_DSCP_EN (1<<21)
+#define PCXR_MFL_1518 (0<<14)
+#define PCXR_MFL_1536 (1<<14)
+#define PCXR_MFL_2048 (2<<14)
+#define PCXR_MFL_64K (3<<14)
+#define PCXR_FLP (1<<11)
+#define PCXR_PRIO_TX_OFF 3
+#define PCXR_TX_HIGH_PRI (7<<PCXR_PRIO_TX_OFF)
+
+/*
+ * * Bit definitions of the Interrupt Cause Reg
+ * * and Interrupt MASK Reg is the same
+ * */
+#define ICR_RXBUF (1<<0)
+#define ICR_TXBUF_H (1<<2)
+#define ICR_TXBUF_L (1<<3)
+#define ICR_TXEND_H (1<<6)
+#define ICR_TXEND_L (1<<7)
+#define ICR_RXERR (1<<8)
+#define ICR_TXERR_H (1<<10)
+#define ICR_TXERR_L (1<<11)
+#define ICR_TX_UDR (1<<13)
+#define ICR_MII_CH (1<<28)
+
+#define ALL_INTS (ICR_TXBUF_H | ICR_TXBUF_L | ICR_TX_UDR |\
+ ICR_TXERR_H | ICR_TXERR_L |\
+ ICR_TXEND_H | ICR_TXEND_L |\
+ ICR_RXBUF | ICR_RXERR | ICR_MII_CH)
+
+#define PHY_MASK 0x0000001f
+
+#define to_darmdfec(_kd) container_of(_kd, struct armdfec_device, dev)
+/* Size of a Tx/Rx descriptor used in chain list data structure */
+#define ARMDFEC_RXQ_DESC_ALIGNED_SIZE \
+ (((sizeof(struct rx_desc) / PKTALIGN) + 1) * PKTALIGN)
+
+#define RX_BUF_OFFSET 0x2
+#define RXQ 0x0 /* RX Queue 0 */
+#define TXQ 0x1 /* TX Queue 1 */
+
+struct addr_table_entry_t {
+ u32 lo;
+ u32 hi;
+};
+
+/* Bit fields of a Hash Table Entry */
+enum hash_table_entry {
+ HTEVALID = 1,
+ HTESKIP = 2,
+ HTERD = 4,
+ HTERDBIT = 2
+};
+
+struct tx_desc {
+ u32 cmd_sts; /* Command/status field */
+ u16 reserved;
+ u16 byte_cnt; /* buffer byte count */
+ u8 *buf_ptr; /* pointer to buffer for this descriptor */
+ struct tx_desc *nextdesc_p; /* Pointer to next descriptor */
+};
+
+struct rx_desc {
+ u32 cmd_sts; /* Descriptor command status */
+ u16 byte_cnt; /* Descriptor buffer byte count */
+ u16 buf_size; /* Buffer size */
+ u8 *buf_ptr; /* Descriptor buffer pointer */
+ struct rx_desc *nxtdesc_p; /* Next descriptor pointer */
+};
+
+/*
+ * Armada100 Fast Ethernet controller Registers
+ * Refer Datasheet Appendix A.22
+ */
+struct armdfec_reg {
+ u32 phyadr; /* PHY Address */
+ u32 pad1[3];
+ u32 smi; /* SMI */
+ u32 pad2[0xFB];
+ u32 pconf; /* Port configuration */
+ u32 pad3;
+ u32 pconf_ext; /* Port configuration extend */
+ u32 pad4;
+ u32 pcmd; /* Port Command */
+ u32 pad5;
+ u32 pstatus; /* Port Status */
+ u32 pad6;
+ u32 spar; /* Serial Parameters */
+ u32 pad7;
+ u32 htpr; /* Hash table pointer */
+ u32 pad8;
+ u32 fcsal; /* Flow control source address low */
+ u32 pad9;
+ u32 fcsah; /* Flow control source address high */
+ u32 pad10;
+ u32 sdma_conf; /* SDMA configuration */
+ u32 pad11;
+ u32 sdma_cmd; /* SDMA command */
+ u32 pad12;
+ u32 ic; /* Interrupt cause */
+ u32 iwc; /* Interrupt write to clear */
+ u32 im; /* Interrupt mask */
+ u32 pad13;
+ u32 *eth_idscpp[4]; /* Eth0 IP Differentiated Services Code
+ Point to Priority 0 Low */
+ u32 eth_vlan_p; /* Eth0 VLAN Priority Tag to Priority */
+ u32 pad14[3];
+ struct rx_desc *rxfdp[4]; /* Ethernet First Rx Descriptor
+ Pointer */
+ u32 pad15[4];
+ struct rx_desc *rxcdp[4]; /* Ethernet Current Rx Descriptor
+ Pointer */
+ u32 pad16[0x0C];
+ struct tx_desc *txcdp[2]; /* Ethernet Current Tx Descriptor
+ Pointer */
+};
+
+struct armdfec_device {
+ struct eth_device dev;
+ struct armdfec_reg *regs;
+ struct tx_desc *p_txdesc;
+ struct rx_desc *p_rxdesc;
+ struct rx_desc *p_rxdesc_curr;
+ u8 *p_rxbuf;
+ u8 *p_aligned_txbuf;
+ u8 *htpr; /* hash pointer */
+};
+
+#endif /* __ARMADA100_FEC_H__ */
diff --git a/qemu/roms/u-boot/drivers/net/at91_emac.c b/qemu/roms/u-boot/drivers/net/at91_emac.c
new file mode 100644
index 000000000..64d4c56ac
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/at91_emac.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2009 BuS Elektronik GmbH & Co. KG
+ * Jens Scharsig (esw@bus-elektronik.de)
+ *
+ * (C) Copyright 2003
+ * Author : Hamid Ikdoumi (Atmel)
+
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_emac.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_pio.h>
+#include <net.h>
+#include <netdev.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <linux/mii.h>
+
+#undef MII_DEBUG
+#undef ET_DEBUG
+
+#if (CONFIG_SYS_RX_ETH_BUFFER > 1024)
+#error AT91 EMAC supports max 1024 RX buffers. \
+ Please decrease the CONFIG_SYS_RX_ETH_BUFFER value
+#endif
+
+#ifndef CONFIG_DRIVER_AT91EMAC_PHYADDR
+#define CONFIG_DRIVER_AT91EMAC_PHYADDR 0
+#endif
+
+/* MDIO clock must not exceed 2.5 MHz, so enable MCK divider */
+#if (AT91C_MASTER_CLOCK > 80000000)
+ #define HCLK_DIV AT91_EMAC_CFG_MCLK_64
+#elif (AT91C_MASTER_CLOCK > 40000000)
+ #define HCLK_DIV AT91_EMAC_CFG_MCLK_32
+#elif (AT91C_MASTER_CLOCK > 20000000)
+ #define HCLK_DIV AT91_EMAC_CFG_MCLK_16
+#else
+ #define HCLK_DIV AT91_EMAC_CFG_MCLK_8
+#endif
+
+#ifdef ET_DEBUG
+#define DEBUG_AT91EMAC 1
+#else
+#define DEBUG_AT91EMAC 0
+#endif
+
+#ifdef MII_DEBUG
+#define DEBUG_AT91PHY 1
+#else
+#define DEBUG_AT91PHY 0
+#endif
+
+#ifndef CONFIG_DRIVER_AT91EMAC_QUIET
+#define VERBOSEP 1
+#else
+#define VERBOSEP 0
+#endif
+
+#define RBF_ADDR 0xfffffffc
+#define RBF_OWNER (1<<0)
+#define RBF_WRAP (1<<1)
+#define RBF_BROADCAST (1<<31)
+#define RBF_MULTICAST (1<<30)
+#define RBF_UNICAST (1<<29)
+#define RBF_EXTERNAL (1<<28)
+#define RBF_UNKNOWN (1<<27)
+#define RBF_SIZE 0x07ff
+#define RBF_LOCAL4 (1<<26)
+#define RBF_LOCAL3 (1<<25)
+#define RBF_LOCAL2 (1<<24)
+#define RBF_LOCAL1 (1<<23)
+
+#define RBF_FRAMEMAX CONFIG_SYS_RX_ETH_BUFFER
+#define RBF_FRAMELEN 0x600
+
+typedef struct {
+ unsigned long addr, size;
+} rbf_t;
+
+typedef struct {
+ rbf_t rbfdt[RBF_FRAMEMAX];
+ unsigned long rbindex;
+} emac_device;
+
+void at91emac_EnableMDIO(at91_emac_t *at91mac)
+{
+ /* Mac CTRL reg set for MDIO enable */
+ writel(readl(&at91mac->ctl) | AT91_EMAC_CTL_MPE, &at91mac->ctl);
+}
+
+void at91emac_DisableMDIO(at91_emac_t *at91mac)
+{
+ /* Mac CTRL reg set for MDIO disable */
+ writel(readl(&at91mac->ctl) & ~AT91_EMAC_CTL_MPE, &at91mac->ctl);
+}
+
+int at91emac_read(at91_emac_t *at91mac, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ unsigned long netstat;
+ at91emac_EnableMDIO(at91mac);
+
+ writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_R |
+ AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 |
+ AT91_EMAC_MAN_PHYA(addr),
+ &at91mac->man);
+
+ do {
+ netstat = readl(&at91mac->sr);
+ debug_cond(DEBUG_AT91PHY, "poll SR %08lx\n", netstat);
+ } while (!(netstat & AT91_EMAC_SR_IDLE));
+
+ *value = readl(&at91mac->man) & AT91_EMAC_MAN_DATA_MASK;
+
+ at91emac_DisableMDIO(at91mac);
+
+ debug_cond(DEBUG_AT91PHY,
+ "AT91PHY read %p REG(%d)=%x\n", at91mac, reg, *value);
+
+ return 0;
+}
+
+int at91emac_write(at91_emac_t *at91mac, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ unsigned long netstat;
+ debug_cond(DEBUG_AT91PHY,
+ "AT91PHY write %p REG(%d)=%p\n", at91mac, reg, &value);
+
+ at91emac_EnableMDIO(at91mac);
+
+ writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_W |
+ AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 |
+ AT91_EMAC_MAN_PHYA(addr) | (value & AT91_EMAC_MAN_DATA_MASK),
+ &at91mac->man);
+
+ do {
+ netstat = readl(&at91mac->sr);
+ debug_cond(DEBUG_AT91PHY, "poll SR %08lx\n", netstat);
+ } while (!(netstat & AT91_EMAC_SR_IDLE));
+
+ at91emac_DisableMDIO(at91mac);
+
+ return 0;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+at91_emac_t *get_emacbase_by_name(const char *devname)
+{
+ struct eth_device *netdev;
+
+ netdev = eth_get_dev_by_name(devname);
+ return (at91_emac_t *) netdev->iobase;
+}
+
+int at91emac_mii_read(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ at91_emac_t *emac;
+
+ emac = get_emacbase_by_name(devname);
+ at91emac_read(emac , addr, reg, value);
+ return 0;
+}
+
+
+int at91emac_mii_write(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ at91_emac_t *emac;
+
+ emac = get_emacbase_by_name(devname);
+ at91emac_write(emac, addr, reg, value);
+ return 0;
+}
+
+#endif
+
+static int at91emac_phy_reset(struct eth_device *netdev)
+{
+ int i;
+ u16 status, adv;
+ at91_emac_t *emac;
+
+ emac = (at91_emac_t *) netdev->iobase;
+
+ adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+ at91emac_write(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
+ MII_ADVERTISE, adv);
+ debug_cond(VERBOSEP, "%s: Starting autonegotiation...\n", netdev->name);
+ at91emac_write(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_BMCR,
+ (BMCR_ANENABLE | BMCR_ANRESTART));
+
+ for (i = 0; i < 30000; i++) {
+ at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
+ MII_BMSR, &status);
+ if (status & BMSR_ANEGCOMPLETE)
+ break;
+ udelay(100);
+ }
+
+ if (status & BMSR_ANEGCOMPLETE) {
+ debug_cond(VERBOSEP,
+ "%s: Autonegotiation complete\n", netdev->name);
+ } else {
+ printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+ netdev->name, status);
+ return -1;
+ }
+ return 0;
+}
+
+static int at91emac_phy_init(struct eth_device *netdev)
+{
+ u16 phy_id, status, adv, lpa;
+ int media, speed, duplex;
+ int i;
+ at91_emac_t *emac;
+
+ emac = (at91_emac_t *) netdev->iobase;
+
+ /* Check if the PHY is up to snuff... */
+ at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
+ MII_PHYSID1, &phy_id);
+ if (phy_id == 0xffff) {
+ printf("%s: No PHY present\n", netdev->name);
+ return -1;
+ }
+
+ at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
+ MII_BMSR, &status);
+
+ if (!(status & BMSR_LSTATUS)) {
+ /* Try to re-negotiate if we don't have link already. */
+ if (at91emac_phy_reset(netdev))
+ return -2;
+
+ for (i = 0; i < 100000 / 100; i++) {
+ at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
+ MII_BMSR, &status);
+ if (status & BMSR_LSTATUS)
+ break;
+ udelay(100);
+ }
+ }
+ if (!(status & BMSR_LSTATUS)) {
+ debug_cond(VERBOSEP, "%s: link down\n", netdev->name);
+ return -3;
+ } else {
+ at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
+ MII_ADVERTISE, &adv);
+ at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
+ MII_LPA, &lpa);
+ media = mii_nway_result(lpa & adv);
+ speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+ ? 1 : 0);
+ duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+ debug_cond(VERBOSEP, "%s: link up, %sMbps %s-duplex\n",
+ netdev->name,
+ speed ? "100" : "10",
+ duplex ? "full" : "half");
+ }
+ return 0;
+}
+
+int at91emac_UpdateLinkSpeed(at91_emac_t *emac)
+{
+ unsigned short stat1;
+
+ at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_BMSR, &stat1);
+
+ if (!(stat1 & BMSR_LSTATUS)) /* link status up? */
+ return -1;
+
+ if (stat1 & BMSR_100FULL) {
+ /*set Emac for 100BaseTX and Full Duplex */
+ writel(readl(&emac->cfg) |
+ AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD,
+ &emac->cfg);
+ return 0;
+ }
+
+ if (stat1 & BMSR_10FULL) {
+ /*set MII for 10BaseT and Full Duplex */
+ writel((readl(&emac->cfg) &
+ ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)
+ ) | AT91_EMAC_CFG_FD,
+ &emac->cfg);
+ return 0;
+ }
+
+ if (stat1 & BMSR_100HALF) {
+ /*set MII for 100BaseTX and Half Duplex */
+ writel((readl(&emac->cfg) &
+ ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)
+ ) | AT91_EMAC_CFG_SPD,
+ &emac->cfg);
+ return 0;
+ }
+
+ if (stat1 & BMSR_10HALF) {
+ /*set MII for 10BaseT and Half Duplex */
+ writel((readl(&emac->cfg) &
+ ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)),
+ &emac->cfg);
+ return 0;
+ }
+ return 0;
+}
+
+static int at91emac_init(struct eth_device *netdev, bd_t *bd)
+{
+ int i;
+ u32 value;
+ emac_device *dev;
+ at91_emac_t *emac;
+ at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIO;
+ at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC;
+
+ emac = (at91_emac_t *) netdev->iobase;
+ dev = (emac_device *) netdev->priv;
+
+ /* PIO Disable Register */
+ value = ATMEL_PMX_AA_EMDIO | ATMEL_PMX_AA_EMDC |
+ ATMEL_PMX_AA_ERXER | ATMEL_PMX_AA_ERX1 |
+ ATMEL_PMX_AA_ERX0 | ATMEL_PMX_AA_ECRS |
+ ATMEL_PMX_AA_ETX1 | ATMEL_PMX_AA_ETX0 |
+ ATMEL_PMX_AA_ETXEN | ATMEL_PMX_AA_EREFCK;
+
+ writel(value, &pio->pioa.pdr);
+ writel(value, &pio->pioa.asr);
+
+#ifdef CONFIG_RMII
+ value = ATMEL_PMX_BA_ERXCK;
+#else
+ value = ATMEL_PMX_BA_ERXCK | ATMEL_PMX_BA_ECOL |
+ ATMEL_PMX_BA_ERXDV | ATMEL_PMX_BA_ERX3 |
+ ATMEL_PMX_BA_ERX2 | ATMEL_PMX_BA_ETXER |
+ ATMEL_PMX_BA_ETX3 | ATMEL_PMX_BA_ETX2;
+#endif
+ writel(value, &pio->piob.pdr);
+ writel(value, &pio->piob.bsr);
+
+ writel(1 << ATMEL_ID_EMAC, &pmc->pcer);
+ writel(readl(&emac->ctl) | AT91_EMAC_CTL_CSR, &emac->ctl);
+
+ /* Init Ethernet buffers */
+ for (i = 0; i < RBF_FRAMEMAX; i++) {
+ dev->rbfdt[i].addr = (unsigned long) NetRxPackets[i];
+ dev->rbfdt[i].size = 0;
+ }
+ dev->rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP;
+ dev->rbindex = 0;
+ writel((u32) &(dev->rbfdt[0]), &emac->rbqp);
+
+ writel(readl(&emac->rsr) &
+ ~(AT91_EMAC_RSR_OVR | AT91_EMAC_RSR_REC | AT91_EMAC_RSR_BNA),
+ &emac->rsr);
+
+ value = AT91_EMAC_CFG_CAF | AT91_EMAC_CFG_NBC |
+ HCLK_DIV;
+#ifdef CONFIG_RMII
+ value |= AT91_EMAC_CFG_RMII;
+#endif
+ writel(value, &emac->cfg);
+
+ writel(readl(&emac->ctl) | AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE,
+ &emac->ctl);
+
+ if (!at91emac_phy_init(netdev)) {
+ at91emac_UpdateLinkSpeed(emac);
+ return 0;
+ }
+ return -1;
+}
+
+static void at91emac_halt(struct eth_device *netdev)
+{
+ at91_emac_t *emac;
+
+ emac = (at91_emac_t *) netdev->iobase;
+ writel(readl(&emac->ctl) & ~(AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE),
+ &emac->ctl);
+ debug_cond(DEBUG_AT91EMAC, "halt MAC\n");
+}
+
+static int at91emac_send(struct eth_device *netdev, void *packet, int length)
+{
+ at91_emac_t *emac;
+
+ emac = (at91_emac_t *) netdev->iobase;
+
+ while (!(readl(&emac->tsr) & AT91_EMAC_TSR_BNQ))
+ ;
+ writel((u32) packet, &emac->tar);
+ writel(AT91_EMAC_TCR_LEN(length), &emac->tcr);
+ while (AT91_EMAC_TCR_LEN(readl(&emac->tcr)))
+ ;
+ debug_cond(DEBUG_AT91EMAC, "Send %d\n", length);
+ writel(readl(&emac->tsr) | AT91_EMAC_TSR_COMP, &emac->tsr);
+ return 0;
+}
+
+static int at91emac_recv(struct eth_device *netdev)
+{
+ emac_device *dev;
+ at91_emac_t *emac;
+ rbf_t *rbfp;
+ int size;
+
+ emac = (at91_emac_t *) netdev->iobase;
+ dev = (emac_device *) netdev->priv;
+
+ rbfp = &dev->rbfdt[dev->rbindex];
+ while (rbfp->addr & RBF_OWNER) {
+ size = rbfp->size & RBF_SIZE;
+ NetReceive(NetRxPackets[dev->rbindex], size);
+
+ debug_cond(DEBUG_AT91EMAC, "Recv[%ld]: %d bytes @ %lx\n",
+ dev->rbindex, size, rbfp->addr);
+
+ rbfp->addr &= ~RBF_OWNER;
+ rbfp->size = 0;
+ if (dev->rbindex < (RBF_FRAMEMAX-1))
+ dev->rbindex++;
+ else
+ dev->rbindex = 0;
+
+ rbfp = &(dev->rbfdt[dev->rbindex]);
+ if (!(rbfp->addr & RBF_OWNER))
+ writel(readl(&emac->rsr) | AT91_EMAC_RSR_REC,
+ &emac->rsr);
+ }
+
+ if (readl(&emac->isr) & AT91_EMAC_IxR_RBNA) {
+ /* EMAC silicon bug 41.3.1 workaround 1 */
+ writel(readl(&emac->ctl) & ~AT91_EMAC_CTL_RE, &emac->ctl);
+ writel(readl(&emac->ctl) | AT91_EMAC_CTL_RE, &emac->ctl);
+ dev->rbindex = 0;
+ printf("%s: reset receiver (EMAC dead lock bug)\n",
+ netdev->name);
+ }
+ return 0;
+}
+
+static int at91emac_write_hwaddr(struct eth_device *netdev)
+{
+ at91_emac_t *emac;
+ at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC;
+ emac = (at91_emac_t *) netdev->iobase;
+
+ writel(1 << ATMEL_ID_EMAC, &pmc->pcer);
+ debug_cond(DEBUG_AT91EMAC,
+ "init MAC-ADDR %02x:%02x:%02x:%02x:%02x:%02x\n",
+ netdev->enetaddr[5], netdev->enetaddr[4], netdev->enetaddr[3],
+ netdev->enetaddr[2], netdev->enetaddr[1], netdev->enetaddr[0]);
+ writel( (netdev->enetaddr[0] | netdev->enetaddr[1] << 8 |
+ netdev->enetaddr[2] << 16 | netdev->enetaddr[3] << 24),
+ &emac->sa2l);
+ writel((netdev->enetaddr[4] | netdev->enetaddr[5] << 8), &emac->sa2h);
+ debug_cond(DEBUG_AT91EMAC, "init MAC-ADDR %x%x\n",
+ readl(&emac->sa2h), readl(&emac->sa2l));
+ return 0;
+}
+
+int at91emac_register(bd_t *bis, unsigned long iobase)
+{
+ emac_device *emac;
+ emac_device *emacfix;
+ struct eth_device *dev;
+
+ if (iobase == 0)
+ iobase = ATMEL_BASE_EMAC;
+ emac = malloc(sizeof(*emac)+512);
+ if (emac == NULL)
+ return -1;
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL) {
+ free(emac);
+ return -1;
+ }
+ /* alignment as per Errata (64 bytes) is insufficient! */
+ emacfix = (emac_device *) (((unsigned long) emac + 0x1ff) & 0xFFFFFE00);
+ memset(emacfix, 0, sizeof(emac_device));
+
+ memset(dev, 0, sizeof(*dev));
+ sprintf(dev->name, "emac");
+ dev->iobase = iobase;
+ dev->priv = emacfix;
+ dev->init = at91emac_init;
+ dev->halt = at91emac_halt;
+ dev->send = at91emac_send;
+ dev->recv = at91emac_recv;
+ dev->write_hwaddr = at91emac_write_hwaddr;
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, at91emac_mii_read, at91emac_mii_write);
+#endif
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ax88180.c b/qemu/roms/u-boot/drivers/net/ax88180.c
new file mode 100644
index 000000000..7f0cfe594
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ax88180.c
@@ -0,0 +1,757 @@
+/*
+ * ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver
+ *
+ * This program is free software; you can distribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ * This program is distributed in the hope it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+/*
+ * ========================================================================
+ * ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver
+ *
+ * The AX88180 Ethernet controller is a high performance and highly
+ * integrated local CPU bus Ethernet controller with embedded 40K bytes
+ * SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any
+ * embedded systems.
+ * The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet
+ * controller that supports both MII and RGMII interfaces and is
+ * compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards.
+ *
+ * Please visit ASIX's web site (http://www.asix.com.tw) for more
+ * details.
+ *
+ * Module Name : ax88180.c
+ * Date : 2008-07-07
+ * History
+ * 09/06/2006 : New release for AX88180 US2 chip.
+ * 07/07/2008 : Fix up the coding style and using inline functions
+ * instead of macros
+ * ========================================================================
+ */
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <malloc.h>
+#include <linux/mii.h>
+#include "ax88180.h"
+
+/*
+ * ===========================================================================
+ * Local SubProgram Declaration
+ * ===========================================================================
+ */
+static void ax88180_rx_handler (struct eth_device *dev);
+static int ax88180_phy_initial (struct eth_device *dev);
+static void ax88180_media_config (struct eth_device *dev);
+static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev);
+static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev);
+static unsigned short ax88180_mdio_read (struct eth_device *dev,
+ unsigned long regaddr);
+static void ax88180_mdio_write (struct eth_device *dev,
+ unsigned long regaddr, unsigned short regdata);
+
+/*
+ * ===========================================================================
+ * Local SubProgram Bodies
+ * ===========================================================================
+ */
+static int ax88180_mdio_check_complete (struct eth_device *dev)
+{
+ int us_cnt = 10000;
+ unsigned short tmpval;
+
+ /* MDIO read/write should not take more than 10 ms */
+ while (--us_cnt) {
+ tmpval = INW (dev, MDIOCTRL);
+ if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0))
+ break;
+ }
+
+ return us_cnt;
+}
+
+static unsigned short
+ax88180_mdio_read (struct eth_device *dev, unsigned long regaddr)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long tmpval = 0;
+
+ OUTW (dev, (READ_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
+
+ if (ax88180_mdio_check_complete (dev))
+ tmpval = INW (dev, MDIODP);
+ else
+ printf ("Failed to read PHY register!\n");
+
+ return (unsigned short)(tmpval & 0xFFFF);
+}
+
+static void
+ax88180_mdio_write (struct eth_device *dev, unsigned long regaddr,
+ unsigned short regdata)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+
+ OUTW (dev, regdata, MDIODP);
+
+ OUTW (dev, (WRITE_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
+
+ if (!ax88180_mdio_check_complete (dev))
+ printf ("Failed to write PHY register!\n");
+}
+
+static int ax88180_phy_reset (struct eth_device *dev)
+{
+ unsigned short delay_cnt = 500;
+
+ ax88180_mdio_write (dev, MII_BMCR, (BMCR_RESET | BMCR_ANENABLE));
+
+ /* Wait for the reset to complete, or time out (500 ms) */
+ while (ax88180_mdio_read (dev, MII_BMCR) & BMCR_RESET) {
+ udelay (1000);
+ if (--delay_cnt == 0) {
+ printf ("Failed to reset PHY!\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void ax88180_mac_reset (struct eth_device *dev)
+{
+ unsigned long tmpval;
+ unsigned char i;
+
+ struct {
+ unsigned short offset, value;
+ } program_seq[] = {
+ {
+ MISC, MISC_NORMAL}, {
+ RXINDICATOR, DEFAULT_RXINDICATOR}, {
+ TXCMD, DEFAULT_TXCMD}, {
+ TXBS, DEFAULT_TXBS}, {
+ TXDES0, DEFAULT_TXDES0}, {
+ TXDES1, DEFAULT_TXDES1}, {
+ TXDES2, DEFAULT_TXDES2}, {
+ TXDES3, DEFAULT_TXDES3}, {
+ TXCFG, DEFAULT_TXCFG}, {
+ MACCFG2, DEFAULT_MACCFG2}, {
+ MACCFG3, DEFAULT_MACCFG3}, {
+ TXLEN, DEFAULT_TXLEN}, {
+ RXBTHD0, DEFAULT_RXBTHD0}, {
+ RXBTHD1, DEFAULT_RXBTHD1}, {
+ RXFULTHD, DEFAULT_RXFULTHD}, {
+ DOGTHD0, DEFAULT_DOGTHD0}, {
+ DOGTHD1, DEFAULT_DOGTHD1},};
+
+ OUTW (dev, MISC_RESET_MAC, MISC);
+ tmpval = INW (dev, MISC);
+
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
+ OUTW (dev, program_seq[i].value, program_seq[i].offset);
+}
+
+static int ax88180_poll_tx_complete (struct eth_device *dev)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long tmpval, txbs_txdp;
+ int TimeOutCnt = 10000;
+
+ txbs_txdp = 1 << priv->NextTxDesc;
+
+ while (TimeOutCnt--) {
+
+ tmpval = INW (dev, TXBS);
+
+ if ((tmpval & txbs_txdp) == 0)
+ break;
+
+ udelay (100);
+ }
+
+ if (TimeOutCnt)
+ return 0;
+ else
+ return -TimeOutCnt;
+}
+
+static void ax88180_rx_handler (struct eth_device *dev)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long data_size;
+ unsigned short rxcurt_ptr, rxbound_ptr, next_ptr;
+ int i;
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+ unsigned short *rxdata = (unsigned short *)NetRxPackets[0];
+#else
+ unsigned long *rxdata = (unsigned long *)NetRxPackets[0];
+#endif
+ unsigned short count;
+
+ rxcurt_ptr = INW (dev, RXCURT);
+ rxbound_ptr = INW (dev, RXBOUND);
+ next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
+
+ debug ("ax88180: RX original RXBOUND=0x%04x,"
+ " RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
+
+ while (next_ptr != rxcurt_ptr) {
+
+ OUTW (dev, RX_START_READ, RXINDICATOR);
+
+ data_size = READ_RXBUF (dev) & 0xFFFF;
+
+ if ((data_size == 0) || (data_size > MAX_RX_SIZE)) {
+
+ OUTW (dev, RX_STOP_READ, RXINDICATOR);
+
+ ax88180_mac_reset (dev);
+ printf ("ax88180: Invalid Rx packet length!"
+ " (len=0x%04lx)\n", data_size);
+
+ debug ("ax88180: RX RXBOUND=0x%04x,"
+ "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
+ return;
+ }
+
+ rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1;
+ rxbound_ptr &= RX_PAGE_NUM_MASK;
+
+ /* Comput access times */
+ count = (data_size + priv->PadSize) >> priv->BusWidth;
+
+ for (i = 0; i < count; i++) {
+ *(rxdata + i) = READ_RXBUF (dev);
+ }
+
+ OUTW (dev, RX_STOP_READ, RXINDICATOR);
+
+ /* Pass the packet up to the protocol layers. */
+ NetReceive (NetRxPackets[0], data_size);
+
+ OUTW (dev, rxbound_ptr, RXBOUND);
+
+ rxcurt_ptr = INW (dev, RXCURT);
+ rxbound_ptr = INW (dev, RXBOUND);
+ next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
+
+ debug ("ax88180: RX updated RXBOUND=0x%04x,"
+ "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
+ }
+
+ return;
+}
+
+static int ax88180_phy_initial (struct eth_device *dev)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long tmp_regval;
+ unsigned short phyaddr;
+
+ /* Search for first avaliable PHY chipset */
+#ifdef CONFIG_PHY_ADDR
+ phyaddr = CONFIG_PHY_ADDR;
+#else
+ for (phyaddr = 0; phyaddr < 32; ++phyaddr)
+#endif
+ {
+ priv->PhyAddr = phyaddr;
+ priv->PhyID0 = ax88180_mdio_read(dev, MII_PHYSID1);
+ priv->PhyID1 = ax88180_mdio_read(dev, MII_PHYSID2);
+
+ switch (priv->PhyID0) {
+ case MARVELL_ALASKA_PHYSID0:
+ debug("ax88180: Found Marvell Alaska PHY family."
+ " (PHY Addr=0x%x)\n", priv->PhyAddr);
+
+ switch (priv->PhyID1) {
+ case MARVELL_88E1118_PHYSID1:
+ ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 2);
+ ax88180_mdio_write(dev, M88E1118_CR,
+ M88E1118_CR_DEFAULT);
+ ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 3);
+ ax88180_mdio_write(dev, M88E1118_LEDCTL,
+ M88E1118_LEDCTL_DEFAULT);
+ ax88180_mdio_write(dev, M88E1118_LEDMIX,
+ M88E1118_LEDMIX_LED050 | M88E1118_LEDMIX_LED150 | 0x15);
+ ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 0);
+ default: /* Default to 88E1111 Phy */
+ tmp_regval = ax88180_mdio_read(dev, M88E1111_EXT_SSR);
+ if ((tmp_regval & HWCFG_MODE_MASK) != RGMII_COPPER_MODE)
+ ax88180_mdio_write(dev, M88E1111_EXT_SCR,
+ DEFAULT_EXT_SCR);
+ }
+
+ if (ax88180_phy_reset(dev) < 0)
+ return 0;
+ ax88180_mdio_write(dev, M88_IER, LINK_CHANGE_INT);
+
+ return 1;
+
+ case CICADA_CIS8201_PHYSID0:
+ debug("ax88180: Found CICADA CIS8201 PHY"
+ " chipset. (PHY Addr=0x%x)\n", priv->PhyAddr);
+
+ ax88180_mdio_write(dev, CIS_IMR,
+ (CIS_INT_ENABLE | LINK_CHANGE_INT));
+
+ /* Set CIS_SMI_PRIORITY bit before force the media mode */
+ tmp_regval = ax88180_mdio_read(dev, CIS_AUX_CTRL_STATUS);
+ tmp_regval &= ~CIS_SMI_PRIORITY;
+ ax88180_mdio_write(dev, CIS_AUX_CTRL_STATUS, tmp_regval);
+
+ return 1;
+
+ case 0xffff:
+ /* No PHY at this addr */
+ break;
+
+ default:
+ printf("ax88180: Unknown PHY chipset %#x at addr %#x\n",
+ priv->PhyID0, priv->PhyAddr);
+ break;
+ }
+ }
+
+ printf("ax88180: Unknown PHY chipset!!\n");
+ return 0;
+}
+
+static void ax88180_media_config (struct eth_device *dev)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long bmcr_val, bmsr_val;
+ unsigned long rxcfg_val, maccfg0_val, maccfg1_val;
+ unsigned long RealMediaMode;
+ int i;
+
+ /* Waiting 2 seconds for PHY link stable */
+ for (i = 0; i < 20000; i++) {
+ bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
+ if (bmsr_val & BMSR_LSTATUS) {
+ break;
+ }
+ udelay (100);
+ }
+
+ bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
+ debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val);
+
+ if (bmsr_val & BMSR_LSTATUS) {
+ bmcr_val = ax88180_mdio_read (dev, MII_BMCR);
+
+ if (bmcr_val & BMCR_ANENABLE) {
+
+ /*
+ * Waiting for Auto-negotiation completion, this may
+ * take up to 5 seconds.
+ */
+ debug ("ax88180: Auto-negotiation is "
+ "enabled. Waiting for NWay completion..\n");
+ for (i = 0; i < 50000; i++) {
+ bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
+ if (bmsr_val & BMSR_ANEGCOMPLETE) {
+ break;
+ }
+ udelay (100);
+ }
+ } else
+ debug ("ax88180: Auto-negotiation is disabled.\n");
+
+ debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n",
+ (unsigned int)bmcr_val, (unsigned int)bmsr_val);
+
+ /* Get real media mode here */
+ switch (priv->PhyID0) {
+ case MARVELL_ALASKA_PHYSID0:
+ RealMediaMode = get_MarvellPHY_media_mode(dev);
+ break;
+ case CICADA_CIS8201_PHYSID0:
+ RealMediaMode = get_CicadaPHY_media_mode(dev);
+ break;
+ default:
+ RealMediaMode = MEDIA_1000FULL;
+ break;
+ }
+
+ priv->LinkState = INS_LINK_UP;
+
+ switch (RealMediaMode) {
+ case MEDIA_1000FULL:
+ debug ("ax88180: 1000Mbps Full-duplex mode.\n");
+ rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
+ maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
+ maccfg1_val = GIGA_MODE_EN | RXFLOW_EN |
+ FULLDUPLEX | DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_1000HALF:
+ debug ("ax88180: 1000Mbps Half-duplex mode.\n");
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = DEFAULT_MACCFG0;
+ maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_100FULL:
+ debug ("ax88180: 100Mbps Full-duplex mode.\n");
+ rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
+ maccfg0_val = SPEED100 | TXFLOW_ENABLE
+ | DEFAULT_MACCFG0;
+ maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_100HALF:
+ debug ("ax88180: 100Mbps Half-duplex mode.\n");
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = SPEED100 | DEFAULT_MACCFG0;
+ maccfg1_val = DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_10FULL:
+ debug ("ax88180: 10Mbps Full-duplex mode.\n");
+ rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
+ maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
+ maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_10HALF:
+ debug ("ax88180: 10Mbps Half-duplex mode.\n");
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = DEFAULT_MACCFG0;
+ maccfg1_val = DEFAULT_MACCFG1;
+ break;
+ default:
+ debug ("ax88180: Unknow media mode.\n");
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = DEFAULT_MACCFG0;
+ maccfg1_val = DEFAULT_MACCFG1;
+
+ priv->LinkState = INS_LINK_DOWN;
+ break;
+ }
+
+ } else {
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = DEFAULT_MACCFG0;
+ maccfg1_val = DEFAULT_MACCFG1;
+
+ priv->LinkState = INS_LINK_DOWN;
+ }
+
+ OUTW (dev, rxcfg_val, RXCFG);
+ OUTW (dev, maccfg0_val, MACCFG0);
+ OUTW (dev, maccfg1_val, MACCFG1);
+
+ return;
+}
+
+static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev)
+{
+ unsigned long m88_ssr;
+ unsigned long MediaMode;
+
+ m88_ssr = ax88180_mdio_read (dev, M88_SSR);
+ switch (m88_ssr & SSR_MEDIA_MASK) {
+ case SSR_1000FULL:
+ MediaMode = MEDIA_1000FULL;
+ break;
+ case SSR_1000HALF:
+ MediaMode = MEDIA_1000HALF;
+ break;
+ case SSR_100FULL:
+ MediaMode = MEDIA_100FULL;
+ break;
+ case SSR_100HALF:
+ MediaMode = MEDIA_100HALF;
+ break;
+ case SSR_10FULL:
+ MediaMode = MEDIA_10FULL;
+ break;
+ case SSR_10HALF:
+ MediaMode = MEDIA_10HALF;
+ break;
+ default:
+ MediaMode = MEDIA_UNKNOWN;
+ break;
+ }
+
+ return MediaMode;
+}
+
+static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev)
+{
+ unsigned long tmp_regval;
+ unsigned long MediaMode;
+
+ tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS);
+ switch (tmp_regval & CIS_MEDIA_MASK) {
+ case CIS_1000FULL:
+ MediaMode = MEDIA_1000FULL;
+ break;
+ case CIS_1000HALF:
+ MediaMode = MEDIA_1000HALF;
+ break;
+ case CIS_100FULL:
+ MediaMode = MEDIA_100FULL;
+ break;
+ case CIS_100HALF:
+ MediaMode = MEDIA_100HALF;
+ break;
+ case CIS_10FULL:
+ MediaMode = MEDIA_10FULL;
+ break;
+ case CIS_10HALF:
+ MediaMode = MEDIA_10HALF;
+ break;
+ default:
+ MediaMode = MEDIA_UNKNOWN;
+ break;
+ }
+
+ return MediaMode;
+}
+
+static void ax88180_halt (struct eth_device *dev)
+{
+ /* Disable AX88180 TX/RX functions */
+ OUTW (dev, WAKEMOD, CMD);
+}
+
+static int ax88180_init (struct eth_device *dev, bd_t * bd)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned short tmp_regval;
+
+ ax88180_mac_reset (dev);
+
+ /* Disable interrupt */
+ OUTW (dev, CLEAR_IMR, IMR);
+
+ /* Disable AX88180 TX/RX functions */
+ OUTW (dev, WAKEMOD, CMD);
+
+ /* Fill the MAC address */
+ tmp_regval =
+ dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8);
+ OUTW (dev, tmp_regval, MACID0);
+
+ tmp_regval =
+ dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8);
+ OUTW (dev, tmp_regval, MACID1);
+
+ tmp_regval =
+ dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8);
+ OUTW (dev, tmp_regval, MACID2);
+
+ ax88180_media_config (dev);
+
+ OUTW (dev, DEFAULT_RXFILTER, RXFILTER);
+
+ /* Initial variables here */
+ priv->FirstTxDesc = TXDP0;
+ priv->NextTxDesc = TXDP0;
+
+ /* Check if there is any invalid interrupt status and clear it. */
+ OUTW (dev, INW (dev, ISR), ISR);
+
+ /* Start AX88180 TX/RX functions */
+ OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD);
+
+ return 0;
+}
+
+/* Get a data block via Ethernet */
+static int ax88180_recv (struct eth_device *dev)
+{
+ unsigned short ISR_Status;
+ unsigned short tmp_regval;
+
+ /* Read and check interrupt status here. */
+ ISR_Status = INW (dev, ISR);
+
+ while (ISR_Status) {
+ /* Clear the interrupt status */
+ OUTW (dev, ISR_Status, ISR);
+
+ debug ("\nax88180: The interrupt status = 0x%04x\n",
+ ISR_Status);
+
+ if (ISR_Status & ISR_PHY) {
+ /* Read ISR register once to clear PHY interrupt bit */
+ tmp_regval = ax88180_mdio_read (dev, M88_ISR);
+ ax88180_media_config (dev);
+ }
+
+ if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) {
+ ax88180_rx_handler (dev);
+ }
+
+ /* Read and check interrupt status again */
+ ISR_Status = INW (dev, ISR);
+ }
+
+ return 0;
+}
+
+/* Send a data block via Ethernet. */
+static int ax88180_send(struct eth_device *dev, void *packet, int length)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned short TXDES_addr;
+ unsigned short txcmd_txdp, txbs_txdp;
+ unsigned short tmp_data;
+ int i;
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+ volatile unsigned short *txdata = (volatile unsigned short *)packet;
+#else
+ volatile unsigned long *txdata = (volatile unsigned long *)packet;
+#endif
+ unsigned short count;
+
+ if (priv->LinkState != INS_LINK_UP) {
+ return 0;
+ }
+
+ priv->FirstTxDesc = priv->NextTxDesc;
+ txbs_txdp = 1 << priv->FirstTxDesc;
+
+ debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc);
+
+ txcmd_txdp = priv->FirstTxDesc << 13;
+ TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2);
+
+ OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD);
+
+ /* Comput access times */
+ count = (length + priv->PadSize) >> priv->BusWidth;
+
+ for (i = 0; i < count; i++) {
+ WRITE_TXBUF (dev, *(txdata + i));
+ }
+
+ OUTW (dev, txcmd_txdp | length, TXCMD);
+ OUTW (dev, txbs_txdp, TXBS);
+ OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr);
+
+ priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK;
+
+ /*
+ * Check the available transmit descriptor, if we had exhausted all
+ * transmit descriptor ,then we have to wait for at least one free
+ * descriptor
+ */
+ txbs_txdp = 1 << priv->NextTxDesc;
+ tmp_data = INW (dev, TXBS);
+
+ if (tmp_data & txbs_txdp) {
+ if (ax88180_poll_tx_complete (dev) < 0) {
+ ax88180_mac_reset (dev);
+ priv->FirstTxDesc = TXDP0;
+ priv->NextTxDesc = TXDP0;
+ printf ("ax88180: Transmit time out occurred!\n");
+ }
+ }
+
+ return 0;
+}
+
+static void ax88180_read_mac_addr (struct eth_device *dev)
+{
+ unsigned short macid0_val, macid1_val, macid2_val;
+ unsigned short tmp_regval;
+ unsigned short i;
+
+ /* Reload MAC address from EEPROM */
+ OUTW (dev, RELOAD_EEPROM, PROMCTRL);
+
+ /* Waiting for reload eeprom completion */
+ for (i = 0; i < 500; i++) {
+ tmp_regval = INW (dev, PROMCTRL);
+ if ((tmp_regval & RELOAD_EEPROM) == 0)
+ break;
+ udelay (1000);
+ }
+
+ /* Get MAC addresses */
+ macid0_val = INW (dev, MACID0);
+ macid1_val = INW (dev, MACID1);
+ macid2_val = INW (dev, MACID2);
+
+ if (((macid0_val | macid1_val | macid2_val) != 0) &&
+ ((macid0_val & 0x01) == 0)) {
+ dev->enetaddr[0] = (unsigned char)macid0_val;
+ dev->enetaddr[1] = (unsigned char)(macid0_val >> 8);
+ dev->enetaddr[2] = (unsigned char)macid1_val;
+ dev->enetaddr[3] = (unsigned char)(macid1_val >> 8);
+ dev->enetaddr[4] = (unsigned char)macid2_val;
+ dev->enetaddr[5] = (unsigned char)(macid2_val >> 8);
+ }
+}
+
+/*
+===========================================================================
+<<<<<< Exported SubProgram Bodies >>>>>>
+===========================================================================
+*/
+int ax88180_initialize (bd_t * bis)
+{
+ struct eth_device *dev;
+ struct ax88180_private *priv;
+
+ dev = (struct eth_device *)malloc (sizeof *dev);
+
+ if (NULL == dev)
+ return 0;
+
+ memset (dev, 0, sizeof *dev);
+
+ priv = (struct ax88180_private *)malloc (sizeof (*priv));
+
+ if (NULL == priv)
+ return 0;
+
+ memset (priv, 0, sizeof *priv);
+
+ sprintf (dev->name, "ax88180");
+ dev->iobase = AX88180_BASE;
+ dev->priv = priv;
+ dev->init = ax88180_init;
+ dev->halt = ax88180_halt;
+ dev->send = ax88180_send;
+ dev->recv = ax88180_recv;
+
+ priv->BusWidth = BUS_WIDTH_32;
+ priv->PadSize = 3;
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+ OUTW (dev, (START_BASE >> 8), BASE);
+ OUTW (dev, DECODE_EN, DECODE);
+
+ priv->BusWidth = BUS_WIDTH_16;
+ priv->PadSize = 1;
+#endif
+
+ ax88180_mac_reset (dev);
+
+ /* Disable interrupt */
+ OUTW (dev, CLEAR_IMR, IMR);
+
+ /* Disable AX88180 TX/RX functions */
+ OUTW (dev, WAKEMOD, CMD);
+
+ ax88180_read_mac_addr (dev);
+
+ eth_register (dev);
+
+ return ax88180_phy_initial (dev);
+
+}
diff --git a/qemu/roms/u-boot/drivers/net/ax88180.h b/qemu/roms/u-boot/drivers/net/ax88180.h
new file mode 100644
index 000000000..daf18e015
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ax88180.h
@@ -0,0 +1,396 @@
+/* ax88180.h: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */
+/*
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _AX88180_H_
+#define _AX88180_H_
+
+#include <asm/io.h>
+#include <asm/types.h>
+#include <config.h>
+
+typedef enum _ax88180_link_state {
+ INS_LINK_DOWN,
+ INS_LINK_UP,
+ INS_LINK_UNKNOWN
+} ax88180_link_state;
+
+struct ax88180_private {
+ unsigned char BusWidth;
+ unsigned char PadSize;
+ unsigned short PhyAddr;
+ unsigned short PhyID0;
+ unsigned short PhyID1;
+ unsigned short FirstTxDesc;
+ unsigned short NextTxDesc;
+ ax88180_link_state LinkState;
+};
+
+#define BUS_WIDTH_16 1
+#define BUS_WIDTH_32 2
+
+#define ENABLE_JUMBO 1
+#define DISABLE_JUMBO 0
+
+#define ENABLE_BURST 1
+#define DISABLE_BURST 0
+
+#define NORMAL_RX_MODE 0
+#define RX_LOOPBACK_MODE 1
+#define RX_INIFINIT_LOOP_MODE 2
+#define TX_INIFINIT_LOOP_MODE 3
+
+#define DEFAULT_ETH_MTU 1500
+
+/* Jumbo packet size 4086 bytes included 4 bytes CRC*/
+#define MAX_JUMBO_MTU 4072
+
+/* Max Tx Jumbo size 4086 bytes included 4 bytes CRC */
+#define MAX_TX_JUMBO_SIZE 4086
+
+/* Max Rx Jumbo size is 15K Bytes */
+#define MAX_RX_SIZE 0x3C00
+
+#define MARVELL_ALASKA_PHYSID0 0x141
+#define MARVELL_88E1118_PHYSID1 0xE40
+
+#define CICADA_CIS8201_PHYSID0 0x000F
+
+#define MEDIA_AUTO 0
+#define MEDIA_1000FULL 1
+#define MEDIA_1000HALF 2
+#define MEDIA_100FULL 3
+#define MEDIA_100HALF 4
+#define MEDIA_10FULL 5
+#define MEDIA_10HALF 6
+#define MEDIA_UNKNOWN 7
+
+#define AUTO_MEDIA 0
+#define FORCE_MEDIA 1
+
+#define TXDP_MASK 3
+#define TXDP0 0
+#define TXDP1 1
+#define TXDP2 2
+#define TXDP3 3
+
+#define CMD_MAP_SIZE 0x100
+
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+ #define AX88180_MEMORY_SIZE 0x00004000
+ #define START_BASE 0x1000
+
+ #define RX_BUF_SIZE 0x1000
+ #define TX_BUF_SIZE 0x0F00
+
+ #define TX_BASE START_BASE
+ #define CMD_BASE (TX_BASE + TX_BUF_SIZE)
+ #define RX_BASE (CMD_BASE + CMD_MAP_SIZE)
+#else
+ #define AX88180_MEMORY_SIZE 0x00010000
+
+ #define RX_BUF_SIZE 0x8000
+ #define TX_BUF_SIZE 0x7C00
+
+ #define RX_BASE 0x0000
+ #define TX_BASE (RX_BASE + RX_BUF_SIZE)
+ #define CMD_BASE (TX_BASE + TX_BUF_SIZE)
+#endif
+
+/* AX88180 Memory Mapping Definition */
+#define RXBUFFER_START RX_BASE
+ #define RX_PACKET_LEN_OFFSET 0
+ #define RX_PAGE_NUM_MASK 0x7FF /* RX pages 0~7FFh */
+#define TXBUFFER_START TX_BASE
+
+/* AX88180 MAC Register Definition */
+#define DECODE (0)
+ #define DECODE_EN 0x00000001
+#define BASE (6)
+#define CMD (CMD_BASE + 0x0000)
+ #define WAKEMOD 0x00000001
+ #define TXEN 0x00000100
+ #define RXEN 0x00000200
+ #define DEFAULT_CMD WAKEMOD
+#define IMR (CMD_BASE + 0x0004)
+ #define IMR_RXBUFFOVR 0x00000001
+ #define IMR_WATCHDOG 0x00000002
+ #define IMR_TX 0x00000008
+ #define IMR_RX 0x00000010
+ #define IMR_PHY 0x00000020
+ #define CLEAR_IMR 0x00000000
+ #define DEFAULT_IMR (IMR_PHY | IMR_RX | IMR_TX |\
+ IMR_RXBUFFOVR | IMR_WATCHDOG)
+#define ISR (CMD_BASE + 0x0008)
+ #define ISR_RXBUFFOVR 0x00000001
+ #define ISR_WATCHDOG 0x00000002
+ #define ISR_TX 0x00000008
+ #define ISR_RX 0x00000010
+ #define ISR_PHY 0x00000020
+#define TXCFG (CMD_BASE + 0x0010)
+ #define AUTOPAD_CRC 0x00000050
+ #define DEFAULT_TXCFG AUTOPAD_CRC
+#define TXCMD (CMD_BASE + 0x0014)
+ #define TXCMD_TXDP_MASK 0x00006000
+ #define TXCMD_TXDP0 0x00000000
+ #define TXCMD_TXDP1 0x00002000
+ #define TXCMD_TXDP2 0x00004000
+ #define TXCMD_TXDP3 0x00006000
+ #define TX_START_WRITE 0x00008000
+ #define TX_STOP_WRITE 0x00000000
+ #define DEFAULT_TXCMD 0x00000000
+#define TXBS (CMD_BASE + 0x0018)
+ #define TXDP0_USED 0x00000001
+ #define TXDP1_USED 0x00000002
+ #define TXDP2_USED 0x00000004
+ #define TXDP3_USED 0x00000008
+ #define DEFAULT_TXBS 0x00000000
+#define TXDES0 (CMD_BASE + 0x0020)
+ #define TXDPx_ENABLE 0x00008000
+ #define TXDPx_LEN_MASK 0x00001FFF
+ #define DEFAULT_TXDES0 0x00000000
+#define TXDES1 (CMD_BASE + 0x0024)
+ #define TXDPx_ENABLE 0x00008000
+ #define TXDPx_LEN_MASK 0x00001FFF
+ #define DEFAULT_TXDES1 0x00000000
+#define TXDES2 (CMD_BASE + 0x0028)
+ #define TXDPx_ENABLE 0x00008000
+ #define TXDPx_LEN_MASK 0x00001FFF
+ #define DEFAULT_TXDES2 0x00000000
+#define TXDES3 (CMD_BASE + 0x002C)
+ #define TXDPx_ENABLE 0x00008000
+ #define TXDPx_LEN_MASK 0x00001FFF
+ #define DEFAULT_TXDES3 0x00000000
+#define RXCFG (CMD_BASE + 0x0030)
+ #define RXBUFF_PROTECT 0x00000001
+ #define RXTCPCRC_CHECK 0x00000010
+ #define RXFLOW_ENABLE 0x00000100
+ #define DEFAULT_RXCFG RXBUFF_PROTECT
+#define RXCURT (CMD_BASE + 0x0034)
+ #define DEFAULT_RXCURT 0x00000000
+#define RXBOUND (CMD_BASE + 0x0038)
+ #define DEFAULT_RXBOUND 0x7FF /* RX pages 0~7FFh */
+#define MACCFG0 (CMD_BASE + 0x0040)
+ #define MACCFG0_BIT3_0 0x00000007
+ #define IPGT_VAL 0x00000150
+ #define TXFLOW_ENABLE 0x00001000
+ #define SPEED100 0x00008000
+ #define DEFAULT_MACCFG0 (IPGT_VAL | MACCFG0_BIT3_0)
+#define MACCFG1 (CMD_BASE + 0x0044)
+ #define RGMII_EN 0x00000002
+ #define RXFLOW_EN 0x00000020
+ #define FULLDUPLEX 0x00000040
+ #define MAX_JUMBO_LEN 0x00000780
+ #define RXJUMBO_EN 0x00000800
+ #define GIGA_MODE_EN 0x00001000
+ #define RXCRC_CHECK 0x00002000
+ #define RXPAUSE_DA_CHECK 0x00004000
+
+ #define JUMBO_LEN_4K 0x00000200
+ #define JUMBO_LEN_15K 0x00000780
+ #define DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK | \
+ RGMII_EN)
+ #define CICADA_DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK)
+#define MACCFG2 (CMD_BASE + 0x0048)
+ #define MACCFG2_BIT15_8 0x00000100
+ #define JAM_LIMIT_MASK 0x000000FC
+ #define DEFAULT_JAM_LIMIT 0x00000064
+ #define DEFAULT_MACCFG2 MACCFG2_BIT15_8
+#define MACCFG3 (CMD_BASE + 0x004C)
+ #define IPGR2_VAL 0x0000000E
+ #define IPGR1_VAL 0x00000600
+ #define NOABORT 0x00008000
+ #define DEFAULT_MACCFG3 (IPGR1_VAL | IPGR2_VAL)
+#define TXPAUT (CMD_BASE + 0x0054)
+ #define DEFAULT_TXPAUT 0x001FE000
+#define RXBTHD0 (CMD_BASE + 0x0058)
+ #define DEFAULT_RXBTHD0 0x00000300
+#define RXBTHD1 (CMD_BASE + 0x005C)
+ #define DEFAULT_RXBTHD1 0x00000600
+#define RXFULTHD (CMD_BASE + 0x0060)
+ #define DEFAULT_RXFULTHD 0x00000100
+#define MISC (CMD_BASE + 0x0068)
+ /* Normal operation mode */
+ #define MISC_NORMAL 0x00000003
+ /* Clear bit 0 to reset MAC */
+ #define MISC_RESET_MAC 0x00000002
+ /* Clear bit 1 to reset PHY */
+ #define MISC_RESET_PHY 0x00000001
+ /* Clear bit 0 and 1 to reset MAC and PHY */
+ #define MISC_RESET_MAC_PHY 0x00000000
+ #define DEFAULT_MISC MISC_NORMAL
+#define MACID0 (CMD_BASE + 0x0070)
+#define MACID1 (CMD_BASE + 0x0074)
+#define MACID2 (CMD_BASE + 0x0078)
+#define TXLEN (CMD_BASE + 0x007C)
+ #define DEFAULT_TXLEN 0x000005FC
+#define RXFILTER (CMD_BASE + 0x0080)
+ #define RX_RXANY 0x00000001
+ #define RX_MULTICAST 0x00000002
+ #define RX_UNICAST 0x00000004
+ #define RX_BROADCAST 0x00000008
+ #define RX_MULTI_HASH 0x00000010
+ #define DISABLE_RXFILTER 0x00000000
+ #define DEFAULT_RXFILTER (RX_BROADCAST + RX_UNICAST)
+#define MDIOCTRL (CMD_BASE + 0x0084)
+ #define PHY_ADDR_MASK 0x0000001F
+ #define REG_ADDR_MASK 0x00001F00
+ #define READ_PHY 0x00004000
+ #define WRITE_PHY 0x00008000
+#define MDIODP (CMD_BASE + 0x0088)
+#define GPIOCTRL (CMD_BASE + 0x008C)
+#define RXINDICATOR (CMD_BASE + 0x0090)
+ #define RX_START_READ 0x00000001
+ #define RX_STOP_READ 0x00000000
+ #define DEFAULT_RXINDICATOR RX_STOP_READ
+#define TXST (CMD_BASE + 0x0094)
+#define MDCCLKPAT (CMD_BASE + 0x00A0)
+#define RXIPCRCCNT (CMD_BASE + 0x00A4)
+#define RXCRCCNT (CMD_BASE + 0x00A8)
+#define TXFAILCNT (CMD_BASE + 0x00AC)
+#define PROMDP (CMD_BASE + 0x00B0)
+#define PROMCTRL (CMD_BASE + 0x00B4)
+ #define RELOAD_EEPROM 0x00000200
+#define MAXRXLEN (CMD_BASE + 0x00B8)
+#define HASHTAB0 (CMD_BASE + 0x00C0)
+#define HASHTAB1 (CMD_BASE + 0x00C4)
+#define HASHTAB2 (CMD_BASE + 0x00C8)
+#define HASHTAB3 (CMD_BASE + 0x00CC)
+#define DOGTHD0 (CMD_BASE + 0x00E0)
+ #define DEFAULT_DOGTHD0 0x0000FFFF
+#define DOGTHD1 (CMD_BASE + 0x00E4)
+ #define START_WATCHDOG_TIMER 0x00008000
+ #define DEFAULT_DOGTHD1 0x00000FFF
+#define SOFTRST (CMD_BASE + 0x00EC)
+ #define SOFTRST_NORMAL 0x00000003
+ #define SOFTRST_RESET_MAC 0x00000002
+
+/* Marvell 88E1111 Gigabit PHY Register Definition */
+#define M88_SSR 0x0011
+ #define SSR_SPEED_MASK 0xC000
+ #define SSR_SPEED_1000 0x8000
+ #define SSR_SPEED_100 0x4000
+ #define SSR_SPEED_10 0x0000
+ #define SSR_DUPLEX 0x2000
+ #define SSR_MEDIA_RESOLVED_OK 0x0800
+
+ #define SSR_MEDIA_MASK (SSR_SPEED_MASK | SSR_DUPLEX)
+ #define SSR_1000FULL (SSR_SPEED_1000 | SSR_DUPLEX)
+ #define SSR_1000HALF SSR_SPEED_1000
+ #define SSR_100FULL (SSR_SPEED_100 | SSR_DUPLEX)
+ #define SSR_100HALF SSR_SPEED_100
+ #define SSR_10FULL (SSR_SPEED_10 | SSR_DUPLEX)
+ #define SSR_10HALF SSR_SPEED_10
+#define M88_IER 0x0012
+ #define LINK_CHANGE_INT 0x0400
+#define M88_ISR 0x0013
+ #define LINK_CHANGE_STATUS 0x0400
+#define M88E1111_EXT_SCR 0x0014
+ #define RGMII_RXCLK_DELAY 0x0080
+ #define RGMII_TXCLK_DELAY 0x0002
+ #define DEFAULT_EXT_SCR (RGMII_TXCLK_DELAY | RGMII_RXCLK_DELAY)
+#define M88E1111_EXT_SSR 0x001B
+ #define HWCFG_MODE_MASK 0x000F
+ #define RGMII_COPPER_MODE 0x000B
+
+/* Marvell 88E1118 Gigabit PHY Register Definition */
+#define M88E1118_CR 0x14
+ #define M88E1118_CR_RGMII_RXCLK_DELAY 0x0020
+ #define M88E1118_CR_RGMII_TXCLK_DELAY 0x0010
+ #define M88E1118_CR_DEFAULT (M88E1118_CR_RGMII_TXCLK_DELAY | \
+ M88E1118_CR_RGMII_RXCLK_DELAY)
+#define M88E1118_LEDCTL 0x10 /* Reg 16 on page 3 */
+ #define M88E1118_LEDCTL_LED2INT 0x200
+ #define M88E1118_LEDCTL_LED2BLNK 0x400
+ #define M88E1118_LEDCTL_LED0DUALMODE1 0xc
+ #define M88E1118_LEDCTL_LED0DUALMODE2 0xd
+ #define M88E1118_LEDCTL_LED0DUALMODE3 0xe
+ #define M88E1118_LEDCTL_LED0DUALMODE4 0xf
+ #define M88E1118_LEDCTL_DEFAULT (M88E1118_LEDCTL_LED2BLNK | \
+ M88E1118_LEDCTL_LED0DUALMODE4)
+
+#define M88E1118_LEDMIX 0x11 /* Reg 17 on page 3 */
+ #define M88E1118_LEDMIX_LED050 0x4
+ #define M88E1118_LEDMIX_LED150 0x8
+
+#define M88E1118_PAGE_SEL 0x16 /* Reg page select */
+
+/* CICADA CIS8201 Gigabit PHY Register Definition */
+#define CIS_IMR 0x0019
+ #define CIS_INT_ENABLE 0x8000
+ #define CIS_LINK_CHANGE_INT 0x2000
+#define CIS_ISR 0x001A
+ #define CIS_INT_PENDING 0x8000
+ #define CIS_LINK_CHANGE_STATUS 0x2000
+#define CIS_AUX_CTRL_STATUS 0x001C
+ #define CIS_AUTONEG_COMPLETE 0x8000
+ #define CIS_SPEED_MASK 0x0018
+ #define CIS_SPEED_1000 0x0010
+ #define CIS_SPEED_100 0x0008
+ #define CIS_SPEED_10 0x0000
+ #define CIS_DUPLEX 0x0020
+
+ #define CIS_MEDIA_MASK (CIS_SPEED_MASK | CIS_DUPLEX)
+ #define CIS_1000FULL (CIS_SPEED_1000 | CIS_DUPLEX)
+ #define CIS_1000HALF CIS_SPEED_1000
+ #define CIS_100FULL (CIS_SPEED_100 | CIS_DUPLEX)
+ #define CIS_100HALF CIS_SPEED_100
+ #define CIS_10FULL (CIS_SPEED_10 | CIS_DUPLEX)
+ #define CIS_10HALF CIS_SPEED_10
+ #define CIS_SMI_PRIORITY 0x0004
+
+static inline unsigned short INW (struct eth_device *dev, unsigned long addr)
+{
+ return le16_to_cpu(readw(addr + (void *)dev->iobase));
+}
+
+/*
+ Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer
+*/
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+static inline void OUTW (struct eth_device *dev, unsigned short command, unsigned long addr)
+{
+ writew(cpu_to_le16(command), addr + (void *)dev->iobase);
+}
+
+static inline unsigned short READ_RXBUF (struct eth_device *dev)
+{
+ return le16_to_cpu(readw(RXBUFFER_START + (void *)dev->iobase));
+}
+
+static inline void WRITE_TXBUF (struct eth_device *dev, unsigned short data)
+{
+ writew(cpu_to_le16(data), TXBUFFER_START + (void *)dev->iobase);
+}
+#else
+static inline void OUTW (struct eth_device *dev, unsigned short command, unsigned long addr)
+{
+ writel(cpu_to_le32(command), addr + (void *)dev->iobase);
+}
+
+static inline unsigned long READ_RXBUF (struct eth_device *dev)
+{
+ return le32_to_cpu(readl(RXBUFFER_START + (void *)dev->iobase));
+}
+
+static inline void WRITE_TXBUF (struct eth_device *dev, unsigned long data)
+{
+ writel(cpu_to_le32(data), TXBUFFER_START + (void *)dev->iobase);
+}
+#endif
+
+#endif /* _AX88180_H_ */
diff --git a/qemu/roms/u-boot/drivers/net/ax88796.c b/qemu/roms/u-boot/drivers/net/ax88796.c
new file mode 100644
index 000000000..c45f64618
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ax88796.c
@@ -0,0 +1,144 @@
+/*
+ * (c) 2007 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include "ax88796.h"
+
+/*
+ * Set 1 bit data
+ */
+static void ax88796_bitset(u32 bit)
+{
+ /* DATA1 */
+ if( bit )
+ EEDI_HIGH;
+ else
+ EEDI_LOW;
+
+ EECLK_LOW;
+ udelay(1000);
+ EECLK_HIGH;
+ udelay(1000);
+ EEDI_LOW;
+}
+
+/*
+ * Get 1 bit data
+ */
+static u8 ax88796_bitget(void)
+{
+ u8 bit;
+
+ EECLK_LOW;
+ udelay(1000);
+ /* DATA */
+ bit = EEDO;
+ EECLK_HIGH;
+ udelay(1000);
+
+ return bit;
+}
+
+/*
+ * Send COMMAND to EEPROM
+ */
+static void ax88796_eep_cmd(u8 cmd)
+{
+ ax88796_bitset(BIT_DUMMY);
+ switch(cmd){
+ case MAC_EEP_READ:
+ ax88796_bitset(1);
+ ax88796_bitset(1);
+ ax88796_bitset(0);
+ break;
+
+ case MAC_EEP_WRITE:
+ ax88796_bitset(1);
+ ax88796_bitset(0);
+ ax88796_bitset(1);
+ break;
+
+ case MAC_EEP_ERACE:
+ ax88796_bitset(1);
+ ax88796_bitset(1);
+ ax88796_bitset(1);
+ break;
+
+ case MAC_EEP_EWEN:
+ ax88796_bitset(1);
+ ax88796_bitset(0);
+ ax88796_bitset(0);
+ break;
+
+ case MAC_EEP_EWDS:
+ ax88796_bitset(1);
+ ax88796_bitset(0);
+ ax88796_bitset(0);
+ break;
+ default:
+ break;
+ }
+}
+
+static void ax88796_eep_setaddr(u16 addr)
+{
+ int i ;
+
+ for( i = 7 ; i >= 0 ; i-- )
+ ax88796_bitset(addr & (1 << i));
+}
+
+/*
+ * Get data from EEPROM
+ */
+static u16 ax88796_eep_getdata(void)
+{
+ ushort data = 0;
+ int i;
+
+ ax88796_bitget(); /* DUMMY */
+ for( i = 0 ; i < 16 ; i++ ){
+ data <<= 1;
+ data |= ax88796_bitget();
+ }
+ return data;
+}
+
+static void ax88796_mac_read(u8 *buff)
+{
+ int i ;
+ u16 data;
+ u16 addr = 0;
+
+ for( i = 0 ; i < 3; i++ )
+ {
+ EECS_HIGH;
+ EEDI_LOW;
+ udelay(1000);
+ /* READ COMMAND */
+ ax88796_eep_cmd(MAC_EEP_READ);
+ /* ADDRESS */
+ ax88796_eep_setaddr(addr++);
+ /* GET DATA */
+ data = ax88796_eep_getdata();
+ *buff++ = (uchar)(data & 0xff);
+ *buff++ = (uchar)((data >> 8) & 0xff);
+ EECLK_LOW;
+ EEDI_LOW;
+ EECS_LOW;
+ }
+}
+
+int get_prom(u8* mac_addr, u8* base_addr)
+{
+ u8 prom[32];
+ int i;
+
+ ax88796_mac_read(prom);
+ for (i = 0; i < 6; i++){
+ mac_addr[i] = prom[i];
+ }
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ax88796.h b/qemu/roms/u-boot/drivers/net/ax88796.h
new file mode 100644
index 000000000..2b4e05af3
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ax88796.h
@@ -0,0 +1,67 @@
+/*
+ * AX88796L(NE2000) support
+ *
+ * (c) 2007 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __DRIVERS_AX88796L_H__
+#define __DRIVERS_AX88796L_H__
+
+#define DP_DATA (0x10 << 1)
+#define START_PG 0x40 /* First page of TX buffer */
+#define START_PG2 0x48
+#define STOP_PG 0x80 /* Last page +1 of RX ring */
+#define TX_PAGES 12
+#define RX_START (START_PG+TX_PAGES)
+#define RX_END STOP_PG
+
+#define AX88796L_BASE_ADDRESS CONFIG_DRIVER_NE2000_BASE
+#define AX88796L_BYTE_ACCESS 0x00001000
+#define AX88796L_OFFSET 0x00000400
+#define AX88796L_ADDRESS_BYTE AX88796L_BASE_ADDRESS + \
+ AX88796L_BYTE_ACCESS + AX88796L_OFFSET
+#define AX88796L_REG_MEMR AX88796L_ADDRESS_BYTE + (0x14<<1)
+#define AX88796L_REG_CR AX88796L_ADDRESS_BYTE + (0x00<<1)
+
+#define AX88796L_CR (*(vu_short *)(AX88796L_REG_CR))
+#define AX88796L_MEMR (*(vu_short *)(AX88796L_REG_MEMR))
+
+#define EECS_HIGH (AX88796L_MEMR |= 0x10)
+#define EECS_LOW (AX88796L_MEMR &= 0xef)
+#define EECLK_HIGH (AX88796L_MEMR |= 0x80)
+#define EECLK_LOW (AX88796L_MEMR &= 0x7f)
+#define EEDI_HIGH (AX88796L_MEMR |= 0x20)
+#define EEDI_LOW (AX88796L_MEMR &= 0xdf)
+#define EEDO ((AX88796L_MEMR & 0x40)>>6)
+
+#define PAGE0_SET (AX88796L_CR &= 0x3f)
+#define PAGE1_SET (AX88796L_CR = (AX88796L_CR & 0x3f) | 0x40)
+
+#define BIT_DUMMY 0
+#define MAC_EEP_READ 1
+#define MAC_EEP_WRITE 2
+#define MAC_EEP_ERACE 3
+#define MAC_EEP_EWEN 4
+#define MAC_EEP_EWDS 5
+
+/* R7780MP Specific code */
+#if defined(CONFIG_R7780MP)
+#define ISA_OFFSET 0x1400
+#define DP_IN(_b_, _o_, _d_) (_d_) = \
+ *( (vu_short *) ((_b_) + ((_o_) * 2) + ISA_OFFSET))
+#define DP_OUT(_b_, _o_, _d_) \
+ *((vu_short *)((_b_) + ((_o_) * 2) + ISA_OFFSET)) = (_d_)
+#define DP_IN_DATA(_b_, _d_) (_d_) = *( (vu_short *) ((_b_) + ISA_OFFSET))
+#define DP_OUT_DATA(_b_, _d_) *( (vu_short *) ((_b_)+ISA_OFFSET)) = (_d_)
+#else
+/* Please change for your target boards */
+#define ISA_OFFSET 0x0000
+#define DP_IN(_b_, _o_, _d_) (_d_) = *( (vu_short *)((_b_)+(_o_ )+ISA_OFFSET))
+#define DP_OUT(_b_, _o_, _d_) *((vu_short *)((_b_)+(_o_)+ISA_OFFSET)) = (_d_)
+#define DP_IN_DATA(_b_, _d_) (_d_) = *( (vu_short *) ((_b_)+ISA_OFFSET))
+#define DP_OUT_DATA(_b_, _d_) *( (vu_short *) ((_b_)+ISA_OFFSET)) = (_d_)
+#endif
+
+#endif /* __DRIVERS_AX88796L_H__ */
diff --git a/qemu/roms/u-boot/drivers/net/bfin_mac.c b/qemu/roms/u-boot/drivers/net/bfin_mac.c
new file mode 100644
index 000000000..0c2d2ef1a
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/bfin_mac.c
@@ -0,0 +1,498 @@
+/*
+ * Driver for Blackfin On-Chip MAC device
+ *
+ * Copyright (c) 2005-2008 Analog Device, Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <config.h>
+#include <net.h>
+#include <netdev.h>
+#include <command.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <linux/mii.h>
+
+#include <asm/blackfin.h>
+#include <asm/clock.h>
+#include <asm/portmux.h>
+#include <asm/mach-common/bits/dma.h>
+#include <asm/mach-common/bits/emac.h>
+#include <asm/mach-common/bits/pll.h>
+
+#include "bfin_mac.h"
+
+#ifndef CONFIG_PHY_ADDR
+# define CONFIG_PHY_ADDR 1
+#endif
+#ifndef CONFIG_PHY_CLOCK_FREQ
+# define CONFIG_PHY_CLOCK_FREQ 2500000
+#endif
+
+#ifdef CONFIG_POST
+#include <post.h>
+#endif
+
+#define RXBUF_BASE_ADDR 0xFF900000
+#define TXBUF_BASE_ADDR 0xFF800000
+#define TX_BUF_CNT 1
+
+#define TOUT_LOOP 1000000
+
+static ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT];
+static ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX];
+static u16 txIdx; /* index of the current RX buffer */
+static u16 rxIdx; /* index of the current TX buffer */
+
+/* DMAx_CONFIG values at DMA Restart */
+static const union {
+ u16 data;
+ ADI_DMA_CONFIG_REG reg;
+} txdmacfg = {
+ .reg = {
+ .b_DMA_EN = 1, /* enabled */
+ .b_WNR = 0, /* read from memory */
+ .b_WDSIZE = 2, /* wordsize is 32 bits */
+ .b_DMA2D = 0,
+ .b_RESTART = 0,
+ .b_DI_SEL = 0,
+ .b_DI_EN = 0, /* no interrupt */
+ .b_NDSIZE = 5, /* 5 half words is desc size */
+ .b_FLOW = 7 /* large desc flow */
+ },
+};
+
+static int bfin_miiphy_wait(void)
+{
+ /* poll the STABUSY bit */
+ while (bfin_read_EMAC_STAADD() & STABUSY)
+ continue;
+ return 0;
+}
+
+static int bfin_miiphy_read(const char *devname, uchar addr, uchar reg, ushort *val)
+{
+ if (bfin_miiphy_wait())
+ return 1;
+ bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STABUSY);
+ if (bfin_miiphy_wait())
+ return 1;
+ *val = bfin_read_EMAC_STADAT();
+ return 0;
+}
+
+static int bfin_miiphy_write(const char *devname, uchar addr, uchar reg, ushort val)
+{
+ if (bfin_miiphy_wait())
+ return 1;
+ bfin_write_EMAC_STADAT(val);
+ bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STAOP | STABUSY);
+ return 0;
+}
+
+int bfin_EMAC_initialize(bd_t *bis)
+{
+ struct eth_device *dev;
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL)
+ hang();
+
+ memset(dev, 0, sizeof(*dev));
+ strcpy(dev->name, "bfin_mac");
+
+ dev->iobase = 0;
+ dev->priv = 0;
+ dev->init = bfin_EMAC_init;
+ dev->halt = bfin_EMAC_halt;
+ dev->send = bfin_EMAC_send;
+ dev->recv = bfin_EMAC_recv;
+ dev->write_hwaddr = bfin_EMAC_setup_addr;
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, bfin_miiphy_read, bfin_miiphy_write);
+#endif
+
+ return 0;
+}
+
+static int bfin_EMAC_send(struct eth_device *dev, void *packet, int length)
+{
+ int i;
+ int result = 0;
+
+ if (length <= 0) {
+ printf("Ethernet: bad packet size: %d\n", length);
+ goto out;
+ }
+
+ if (bfin_read_DMA2_IRQ_STATUS() & DMA_ERR) {
+ printf("Ethernet: tx DMA error\n");
+ goto out;
+ }
+
+ for (i = 0; (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN); ++i) {
+ if (i > TOUT_LOOP) {
+ puts("Ethernet: tx time out\n");
+ goto out;
+ }
+ }
+ txbuf[txIdx]->FrmData->NoBytes = length;
+ memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length);
+ txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData;
+ bfin_write_DMA2_NEXT_DESC_PTR(txbuf[txIdx]->Dma);
+ bfin_write_DMA2_CONFIG(txdmacfg.data);
+ bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
+
+ for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) {
+ if (i > TOUT_LOOP) {
+ puts("Ethernet: tx error\n");
+ goto out;
+ }
+ }
+ result = txbuf[txIdx]->StatusWord;
+ txbuf[txIdx]->StatusWord = 0;
+ if ((txIdx + 1) >= TX_BUF_CNT)
+ txIdx = 0;
+ else
+ txIdx++;
+ out:
+ debug("BFIN EMAC send: length = %d\n", length);
+ return result;
+}
+
+static int bfin_EMAC_recv(struct eth_device *dev)
+{
+ int length = 0;
+
+ for (;;) {
+ if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) {
+ length = -1;
+ break;
+ }
+ if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) {
+ printf("Ethernet: rx dma overrun\n");
+ break;
+ }
+ if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) {
+ printf("Ethernet: rx error\n");
+ break;
+ }
+ length = rxbuf[rxIdx]->StatusWord & 0x000007FF;
+ if (length <= 4) {
+ printf("Ethernet: bad frame\n");
+ break;
+ }
+
+ debug("%s: len = %d\n", __func__, length - 4);
+
+ NetRxPackets[rxIdx] = rxbuf[rxIdx]->FrmData->Dest;
+ NetReceive(NetRxPackets[rxIdx], length - 4);
+ bfin_write_DMA1_IRQ_STATUS(DMA_DONE | DMA_ERR);
+ rxbuf[rxIdx]->StatusWord = 0x00000000;
+ if ((rxIdx + 1) >= PKTBUFSRX)
+ rxIdx = 0;
+ else
+ rxIdx++;
+ }
+
+ return length;
+}
+
+/**************************************************************
+ *
+ * Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+/* MDC = SCLK / MDC_freq / 2 - 1 */
+#define MDC_FREQ_TO_DIV(mdc_freq) (get_sclk() / (mdc_freq) / 2 - 1)
+
+#ifndef CONFIG_BFIN_MAC_PINS
+# ifdef CONFIG_RMII
+# define CONFIG_BFIN_MAC_PINS P_RMII0
+# else
+# define CONFIG_BFIN_MAC_PINS P_MII0
+# endif
+#endif
+
+static int bfin_miiphy_init(struct eth_device *dev, int *opmode)
+{
+ const unsigned short pins[] = CONFIG_BFIN_MAC_PINS;
+ u16 phydat;
+ size_t count;
+
+ /* Enable PHY output */
+ bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE);
+
+ /* Set all the pins to peripheral mode */
+ peripheral_request_list(pins, "bfin_mac");
+
+ /* Odd word alignment for Receive Frame DMA word */
+ /* Configure checksum support and rcve frame word alignment */
+ bfin_write_EMAC_SYSCTL(RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(CONFIG_PHY_CLOCK_FREQ)));
+
+ /* turn on auto-negotiation and wait for link to come up */
+ bfin_miiphy_write(dev->name, CONFIG_PHY_ADDR, MII_BMCR, BMCR_ANENABLE);
+ count = 0;
+ while (1) {
+ ++count;
+ if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_BMSR, &phydat))
+ return -1;
+ if (phydat & BMSR_LSTATUS)
+ break;
+ if (count > 30000) {
+ printf("%s: link down, check cable\n", dev->name);
+ return -1;
+ }
+ udelay(100);
+ }
+
+ /* see what kind of link we have */
+ if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_LPA, &phydat))
+ return -1;
+ if (phydat & LPA_DUPLEX)
+ *opmode = FDMODE;
+ else
+ *opmode = 0;
+
+ bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
+ bfin_write_EMAC_VLAN1(EMAC_VLANX_DEF_VAL);
+ bfin_write_EMAC_VLAN2(EMAC_VLANX_DEF_VAL);
+
+ /* Initialize the TX DMA channel registers */
+ bfin_write_DMA2_X_COUNT(0);
+ bfin_write_DMA2_X_MODIFY(4);
+ bfin_write_DMA2_Y_COUNT(0);
+ bfin_write_DMA2_Y_MODIFY(0);
+
+ /* Initialize the RX DMA channel registers */
+ bfin_write_DMA1_X_COUNT(0);
+ bfin_write_DMA1_X_MODIFY(4);
+ bfin_write_DMA1_Y_COUNT(0);
+ bfin_write_DMA1_Y_MODIFY(0);
+
+ return 0;
+}
+
+static int bfin_EMAC_setup_addr(struct eth_device *dev)
+{
+ bfin_write_EMAC_ADDRLO(
+ dev->enetaddr[0] |
+ dev->enetaddr[1] << 8 |
+ dev->enetaddr[2] << 16 |
+ dev->enetaddr[3] << 24
+ );
+ bfin_write_EMAC_ADDRHI(
+ dev->enetaddr[4] |
+ dev->enetaddr[5] << 8
+ );
+ return 0;
+}
+
+static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd)
+{
+ u32 opmode;
+ int dat;
+ int i;
+ debug("Eth_init: ......\n");
+
+ txIdx = 0;
+ rxIdx = 0;
+
+ /* Initialize System Register */
+ if (bfin_miiphy_init(dev, &dat) < 0)
+ return -1;
+
+ /* Initialize EMAC address */
+ bfin_EMAC_setup_addr(dev);
+
+ /* Initialize TX and RX buffer */
+ for (i = 0; i < PKTBUFSRX; i++) {
+ rxbuf[i] = SetupRxBuffer(i);
+ if (i > 0) {
+ rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = rxbuf[i]->Dma;
+ if (i == (PKTBUFSRX - 1))
+ rxbuf[i]->Dma[1].NEXT_DESC_PTR = rxbuf[0]->Dma;
+ }
+ }
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ txbuf[i] = SetupTxBuffer(i);
+ if (i > 0) {
+ txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = txbuf[i]->Dma;
+ if (i == (TX_BUF_CNT - 1))
+ txbuf[i]->Dma[1].NEXT_DESC_PTR = txbuf[0]->Dma;
+ }
+ }
+
+ /* Set RX DMA */
+ bfin_write_DMA1_NEXT_DESC_PTR(rxbuf[0]->Dma);
+ bfin_write_DMA1_CONFIG(rxbuf[0]->Dma[0].CONFIG_DATA);
+
+ /* Wait MII done */
+ bfin_miiphy_wait();
+
+ /* We enable only RX here */
+ /* ASTP : Enable Automatic Pad Stripping
+ PR : Promiscuous Mode for test
+ PSF : Receive frames with total length less than 64 bytes.
+ FDMODE : Full Duplex Mode
+ LB : Internal Loopback for test
+ RE : Receiver Enable */
+ if (dat == FDMODE)
+ opmode = ASTP | FDMODE | PSF;
+ else
+ opmode = ASTP | PSF;
+ opmode |= RE;
+#ifdef CONFIG_RMII
+ opmode |= TE | RMII;
+#endif
+ /* Turn on the EMAC */
+ bfin_write_EMAC_OPMODE(opmode);
+ return 0;
+}
+
+static void bfin_EMAC_halt(struct eth_device *dev)
+{
+ debug("Eth_halt: ......\n");
+ /* Turn off the EMAC */
+ bfin_write_EMAC_OPMODE(0);
+ /* Turn off the EMAC RX DMA */
+ bfin_write_DMA1_CONFIG(0);
+ bfin_write_DMA2_CONFIG(0);
+}
+
+ADI_ETHER_BUFFER *SetupRxBuffer(int no)
+{
+ ADI_ETHER_FRAME_BUFFER *frmbuf;
+ ADI_ETHER_BUFFER *buf;
+ int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */
+ int total_size = nobytes_buffer + RECV_BUFSIZE;
+
+ buf = (void *) (RXBUF_BASE_ADDR + no * total_size);
+ frmbuf = (void *) (RXBUF_BASE_ADDR + no * total_size + nobytes_buffer);
+
+ memset(buf, 0x00, nobytes_buffer);
+ buf->FrmData = frmbuf;
+ memset(frmbuf, 0xfe, RECV_BUFSIZE);
+
+ /* set up first desc to point to receive frame buffer */
+ buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
+ buf->Dma[0].START_ADDR = (u32) buf->FrmData;
+ buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */
+ buf->Dma[0].CONFIG.b_WNR = 1; /* Write to memory */
+ buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
+ buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */
+ buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */
+
+ /* set up second desc to point to status word */
+ buf->Dma[1].NEXT_DESC_PTR = buf->Dma;
+ buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum;
+ buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */
+ buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */
+ buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
+ buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
+ buf->Dma[1].CONFIG.b_NDSIZE = 5; /* must be 0 when FLOW is 0 */
+ buf->Dma[1].CONFIG.b_FLOW = 7; /* stop */
+
+ return buf;
+}
+
+ADI_ETHER_BUFFER *SetupTxBuffer(int no)
+{
+ ADI_ETHER_FRAME_BUFFER *frmbuf;
+ ADI_ETHER_BUFFER *buf;
+ int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */
+ int total_size = nobytes_buffer + RECV_BUFSIZE;
+
+ buf = (void *) (TXBUF_BASE_ADDR + no * total_size);
+ frmbuf = (void *) (TXBUF_BASE_ADDR + no * total_size + nobytes_buffer);
+
+ memset(buf, 0x00, nobytes_buffer);
+ buf->FrmData = frmbuf;
+ memset(frmbuf, 0x00, RECV_BUFSIZE);
+
+ /* set up first desc to point to receive frame buffer */
+ buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
+ buf->Dma[0].START_ADDR = (u32) buf->FrmData;
+ buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */
+ buf->Dma[0].CONFIG.b_WNR = 0; /* Read to memory */
+ buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
+ buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */
+ buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */
+
+ /* set up second desc to point to status word */
+ buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]);
+ buf->Dma[1].START_ADDR = (u32) & buf->StatusWord;
+ buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */
+ buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */
+ buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
+ buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
+ buf->Dma[1].CONFIG.b_NDSIZE = 0; /* must be 0 when FLOW is 0 */
+ buf->Dma[1].CONFIG.b_FLOW = 0; /* stop */
+
+ return buf;
+}
+
+#if defined(CONFIG_POST) && defined(CONFIG_SYS_POST_ETHER)
+int ether_post_test(int flags)
+{
+ uchar buf[64];
+ int i, value = 0;
+ int length;
+ uint addr;
+
+ printf("\n--------");
+ bfin_EMAC_init(NULL, NULL);
+ /* construct the package */
+ addr = bfin_read_EMAC_ADDRLO();
+ buf[0] = buf[6] = addr;
+ buf[1] = buf[7] = addr >> 8;
+ buf[2] = buf[8] = addr >> 16;
+ buf[3] = buf[9] = addr >> 24;
+ addr = bfin_read_EMAC_ADDRHI();
+ buf[4] = buf[10] = addr;
+ buf[5] = buf[11] = addr >> 8;
+ buf[12] = 0x08; /* Type: ARP */
+ buf[13] = 0x06;
+ buf[14] = 0x00; /* Hardware type: Ethernet */
+ buf[15] = 0x01;
+ buf[16] = 0x08; /* Protocal type: IP */
+ buf[17] = 0x00;
+ buf[18] = 0x06; /* Hardware size */
+ buf[19] = 0x04; /* Protocol size */
+ buf[20] = 0x00; /* Opcode: request */
+ buf[21] = 0x01;
+
+ for (i = 0; i < 42; i++)
+ buf[i + 22] = i;
+ printf("--------Send 64 bytes......\n");
+ bfin_EMAC_send(NULL, buf, 64);
+ for (i = 0; i < 100; i++) {
+ udelay(10000);
+ if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) {
+ value = 1;
+ break;
+ }
+ }
+ if (value == 0) {
+ printf("--------EMAC can't receive any data\n");
+ eth_halt();
+ return -1;
+ }
+ length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4;
+ for (i = 0; i < length; i++) {
+ if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) {
+ printf("--------EMAC receive error data!\n");
+ eth_halt();
+ return -1;
+ }
+ }
+ printf("--------receive %d bytes, matched\n", length);
+ bfin_EMAC_halt(NULL);
+ return 0;
+}
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/bfin_mac.h b/qemu/roms/u-boot/drivers/net/bfin_mac.h
new file mode 100644
index 000000000..54ffb3830
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/bfin_mac.h
@@ -0,0 +1,65 @@
+/*
+ * bfin_mac.h - some defines/structures for the Blackfin on-chip MAC.
+ *
+ * Copyright (c) 2005-2008 Analog Device, Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __BFIN_MAC_H__
+#define __BFIN_MAC_H__
+
+#define RECV_BUFSIZE (0x614)
+
+typedef struct ADI_DMA_CONFIG_REG {
+ u16 b_DMA_EN:1; /* 0 Enabled */
+ u16 b_WNR:1; /* 1 Direction */
+ u16 b_WDSIZE:2; /* 2:3 Transfer word size */
+ u16 b_DMA2D:1; /* 4 DMA mode */
+ u16 b_RESTART:1; /* 5 Retain FIFO */
+ u16 b_DI_SEL:1; /* 6 Data interrupt timing select */
+ u16 b_DI_EN:1; /* 7 Data interrupt enabled */
+ u16 b_NDSIZE:4; /* 8:11 Flex descriptor size */
+ u16 b_FLOW:3; /* 12:14Flow */
+} ADI_DMA_CONFIG_REG;
+
+typedef struct adi_ether_frame_buffer {
+ u16 NoBytes; /* the no. of following bytes */
+ u8 Dest[6]; /* destination MAC address */
+ u8 Srce[6]; /* source MAC address */
+ u16 LTfield; /* length/type field */
+ u8 Data[0]; /* payload bytes */
+} ADI_ETHER_FRAME_BUFFER;
+/* 16 bytes/struct */
+
+typedef struct dma_descriptor {
+ struct dma_descriptor *NEXT_DESC_PTR;
+ u32 START_ADDR;
+ union {
+ u16 CONFIG_DATA;
+ ADI_DMA_CONFIG_REG CONFIG;
+ };
+} DMA_DESCRIPTOR;
+/* 10 bytes/struct in 12 bytes */
+
+typedef struct adi_ether_buffer {
+ DMA_DESCRIPTOR Dma[2]; /* first for the frame, second for the status */
+ ADI_ETHER_FRAME_BUFFER *FrmData;/* pointer to data */
+ struct adi_ether_buffer *pNext; /* next buffer */
+ struct adi_ether_buffer *pPrev; /* prev buffer */
+ u16 IPHdrChksum; /* the IP header checksum */
+ u16 IPPayloadChksum; /* the IP header and payload checksum */
+ volatile u32 StatusWord; /* the frame status word */
+} ADI_ETHER_BUFFER;
+/* 40 bytes/struct in 44 bytes */
+
+static ADI_ETHER_BUFFER *SetupRxBuffer(int no);
+static ADI_ETHER_BUFFER *SetupTxBuffer(int no);
+
+static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd);
+static void bfin_EMAC_halt(struct eth_device *dev);
+static int bfin_EMAC_send(struct eth_device *dev, void *packet, int length);
+static int bfin_EMAC_recv(struct eth_device *dev);
+static int bfin_EMAC_setup_addr(struct eth_device *dev);
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/calxedaxgmac.c b/qemu/roms/u-boot/drivers/net/calxedaxgmac.c
new file mode 100644
index 000000000..ff94865c5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/calxedaxgmac.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <asm/io.h>
+
+#define TX_NUM_DESC 1
+#define RX_NUM_DESC 32
+
+#define MAC_TIMEOUT (5*CONFIG_SYS_HZ)
+
+#define ETH_BUF_SZ 2048
+#define TX_BUF_SZ (ETH_BUF_SZ * TX_NUM_DESC)
+#define RX_BUF_SZ (ETH_BUF_SZ * RX_NUM_DESC)
+
+#define RXSTART 0x00000002
+#define TXSTART 0x00002000
+
+#define RXENABLE 0x00000004
+#define TXENABLE 0x00000008
+
+#define XGMAC_CONTROL_SPD 0x40000000
+#define XGMAC_CONTROL_SPD_MASK 0x60000000
+#define XGMAC_CONTROL_SARC 0x10000000
+#define XGMAC_CONTROL_SARK_MASK 0x18000000
+#define XGMAC_CONTROL_CAR 0x04000000
+#define XGMAC_CONTROL_CAR_MASK 0x06000000
+#define XGMAC_CONTROL_CAR_SHIFT 25
+#define XGMAC_CONTROL_DP 0x01000000
+#define XGMAC_CONTROL_WD 0x00800000
+#define XGMAC_CONTROL_JD 0x00400000
+#define XGMAC_CONTROL_JE 0x00100000
+#define XGMAC_CONTROL_LM 0x00001000
+#define XGMAC_CONTROL_IPC 0x00000400
+#define XGMAC_CONTROL_ACS 0x00000080
+#define XGMAC_CONTROL_DDIC 0x00000010
+#define XGMAC_CONTROL_TE 0x00000008
+#define XGMAC_CONTROL_RE 0x00000004
+
+#define XGMAC_DMA_BUSMODE_RESET 0x00000001
+#define XGMAC_DMA_BUSMODE_DSL 0x00000004
+#define XGMAC_DMA_BUSMODE_DSL_MASK 0x0000007c
+#define XGMAC_DMA_BUSMODE_DSL_SHIFT 2
+#define XGMAC_DMA_BUSMODE_ATDS 0x00000080
+#define XGMAC_DMA_BUSMODE_PBL_MASK 0x00003f00
+#define XGMAC_DMA_BUSMODE_PBL_SHIFT 8
+#define XGMAC_DMA_BUSMODE_FB 0x00010000
+#define XGMAC_DMA_BUSMODE_USP 0x00800000
+#define XGMAC_DMA_BUSMODE_8PBL 0x01000000
+#define XGMAC_DMA_BUSMODE_AAL 0x02000000
+
+#define XGMAC_DMA_AXIMODE_ENLPI 0x80000000
+#define XGMAC_DMA_AXIMODE_MGK 0x40000000
+#define XGMAC_DMA_AXIMODE_WROSR 0x00100000
+#define XGMAC_DMA_AXIMODE_WROSR_MASK 0x00F00000
+#define XGMAC_DMA_AXIMODE_WROSR_SHIFT 20
+#define XGMAC_DMA_AXIMODE_RDOSR 0x00010000
+#define XGMAC_DMA_AXIMODE_RDOSR_MASK 0x000F0000
+#define XGMAC_DMA_AXIMODE_RDOSR_SHIFT 16
+#define XGMAC_DMA_AXIMODE_AAL 0x00001000
+#define XGMAC_DMA_AXIMODE_BLEN256 0x00000080
+#define XGMAC_DMA_AXIMODE_BLEN128 0x00000040
+#define XGMAC_DMA_AXIMODE_BLEN64 0x00000020
+#define XGMAC_DMA_AXIMODE_BLEN32 0x00000010
+#define XGMAC_DMA_AXIMODE_BLEN16 0x00000008
+#define XGMAC_DMA_AXIMODE_BLEN8 0x00000004
+#define XGMAC_DMA_AXIMODE_BLEN4 0x00000002
+#define XGMAC_DMA_AXIMODE_UNDEF 0x00000001
+
+#define XGMAC_CORE_OMR_RTC_SHIFT 3
+#define XGMAC_CORE_OMR_RTC_MASK 0x00000018
+#define XGMAC_CORE_OMR_RTC 0x00000010
+#define XGMAC_CORE_OMR_RSF 0x00000020
+#define XGMAC_CORE_OMR_DT 0x00000040
+#define XGMAC_CORE_OMR_FEF 0x00000080
+#define XGMAC_CORE_OMR_EFC 0x00000100
+#define XGMAC_CORE_OMR_RFA_SHIFT 9
+#define XGMAC_CORE_OMR_RFA_MASK 0x00000E00
+#define XGMAC_CORE_OMR_RFD_SHIFT 12
+#define XGMAC_CORE_OMR_RFD_MASK 0x00007000
+#define XGMAC_CORE_OMR_TTC_SHIFT 16
+#define XGMAC_CORE_OMR_TTC_MASK 0x00030000
+#define XGMAC_CORE_OMR_TTC 0x00020000
+#define XGMAC_CORE_OMR_FTF 0x00100000
+#define XGMAC_CORE_OMR_TSF 0x00200000
+
+#define FIFO_MINUS_1K 0x0
+#define FIFO_MINUS_2K 0x1
+#define FIFO_MINUS_3K 0x2
+#define FIFO_MINUS_4K 0x3
+#define FIFO_MINUS_6K 0x4
+#define FIFO_MINUS_8K 0x5
+#define FIFO_MINUS_12K 0x6
+#define FIFO_MINUS_16K 0x7
+
+#define XGMAC_CORE_FLOW_PT_SHIFT 16
+#define XGMAC_CORE_FLOW_PT_MASK 0xFFFF0000
+#define XGMAC_CORE_FLOW_PT 0x00010000
+#define XGMAC_CORE_FLOW_DZQP 0x00000080
+#define XGMAC_CORE_FLOW_PLT_SHIFT 4
+#define XGMAC_CORE_FLOW_PLT_MASK 0x00000030
+#define XGMAC_CORE_FLOW_PLT 0x00000010
+#define XGMAC_CORE_FLOW_UP 0x00000008
+#define XGMAC_CORE_FLOW_RFE 0x00000004
+#define XGMAC_CORE_FLOW_TFE 0x00000002
+#define XGMAC_CORE_FLOW_FCB 0x00000001
+
+/* XGMAC Descriptor Defines */
+#define MAX_DESC_BUF_SZ (0x2000 - 8)
+
+#define RXDESC_EXT_STATUS 0x00000001
+#define RXDESC_CRC_ERR 0x00000002
+#define RXDESC_RX_ERR 0x00000008
+#define RXDESC_RX_WDOG 0x00000010
+#define RXDESC_FRAME_TYPE 0x00000020
+#define RXDESC_GIANT_FRAME 0x00000080
+#define RXDESC_LAST_SEG 0x00000100
+#define RXDESC_FIRST_SEG 0x00000200
+#define RXDESC_VLAN_FRAME 0x00000400
+#define RXDESC_OVERFLOW_ERR 0x00000800
+#define RXDESC_LENGTH_ERR 0x00001000
+#define RXDESC_SA_FILTER_FAIL 0x00002000
+#define RXDESC_DESCRIPTOR_ERR 0x00004000
+#define RXDESC_ERROR_SUMMARY 0x00008000
+#define RXDESC_FRAME_LEN_OFFSET 16
+#define RXDESC_FRAME_LEN_MASK 0x3fff0000
+#define RXDESC_DA_FILTER_FAIL 0x40000000
+
+#define RXDESC1_END_RING 0x00008000
+
+#define RXDESC_IP_PAYLOAD_MASK 0x00000003
+#define RXDESC_IP_PAYLOAD_UDP 0x00000001
+#define RXDESC_IP_PAYLOAD_TCP 0x00000002
+#define RXDESC_IP_PAYLOAD_ICMP 0x00000003
+#define RXDESC_IP_HEADER_ERR 0x00000008
+#define RXDESC_IP_PAYLOAD_ERR 0x00000010
+#define RXDESC_IPV4_PACKET 0x00000040
+#define RXDESC_IPV6_PACKET 0x00000080
+#define TXDESC_UNDERFLOW_ERR 0x00000001
+#define TXDESC_JABBER_TIMEOUT 0x00000002
+#define TXDESC_LOCAL_FAULT 0x00000004
+#define TXDESC_REMOTE_FAULT 0x00000008
+#define TXDESC_VLAN_FRAME 0x00000010
+#define TXDESC_FRAME_FLUSHED 0x00000020
+#define TXDESC_IP_HEADER_ERR 0x00000040
+#define TXDESC_PAYLOAD_CSUM_ERR 0x00000080
+#define TXDESC_ERROR_SUMMARY 0x00008000
+#define TXDESC_SA_CTRL_INSERT 0x00040000
+#define TXDESC_SA_CTRL_REPLACE 0x00080000
+#define TXDESC_2ND_ADDR_CHAINED 0x00100000
+#define TXDESC_END_RING 0x00200000
+#define TXDESC_CSUM_IP 0x00400000
+#define TXDESC_CSUM_IP_PAYLD 0x00800000
+#define TXDESC_CSUM_ALL 0x00C00000
+#define TXDESC_CRC_EN_REPLACE 0x01000000
+#define TXDESC_CRC_EN_APPEND 0x02000000
+#define TXDESC_DISABLE_PAD 0x04000000
+#define TXDESC_FIRST_SEG 0x10000000
+#define TXDESC_LAST_SEG 0x20000000
+#define TXDESC_INTERRUPT 0x40000000
+
+#define DESC_OWN 0x80000000
+#define DESC_BUFFER1_SZ_MASK 0x00001fff
+#define DESC_BUFFER2_SZ_MASK 0x1fff0000
+#define DESC_BUFFER2_SZ_OFFSET 16
+
+struct xgmac_regs {
+ u32 config;
+ u32 framefilter;
+ u32 resv_1[4];
+ u32 flow_control;
+ u32 vlantag;
+ u32 version;
+ u32 vlaninclude;
+ u32 resv_2[2];
+ u32 pacestretch;
+ u32 vlanhash;
+ u32 resv_3;
+ u32 intreg;
+ struct {
+ u32 hi; /* 0x40 */
+ u32 lo; /* 0x44 */
+ } macaddr[16];
+ u32 resv_4[0xd0];
+ u32 core_opmode; /* 0x400 */
+ u32 resv_5[0x2bf];
+ u32 busmode; /* 0xf00 */
+ u32 txpoll;
+ u32 rxpoll;
+ u32 rxdesclist;
+ u32 txdesclist;
+ u32 dma_status;
+ u32 dma_opmode;
+ u32 intenable;
+ u32 resv_6[2];
+ u32 axi_mode; /* 0xf28 */
+};
+
+struct xgmac_dma_desc {
+ __le32 flags;
+ __le32 buf_size;
+ __le32 buf1_addr; /* Buffer 1 Address Pointer */
+ __le32 buf2_addr; /* Buffer 2 Address Pointer */
+ __le32 ext_status;
+ __le32 res[3];
+};
+
+/* XGMAC Descriptor Access Helpers */
+static inline void desc_set_buf_len(struct xgmac_dma_desc *p, u32 buf_sz)
+{
+ if (buf_sz > MAX_DESC_BUF_SZ)
+ p->buf_size = cpu_to_le32(MAX_DESC_BUF_SZ |
+ (buf_sz - MAX_DESC_BUF_SZ) << DESC_BUFFER2_SZ_OFFSET);
+ else
+ p->buf_size = cpu_to_le32(buf_sz);
+}
+
+static inline int desc_get_buf_len(struct xgmac_dma_desc *p)
+{
+ u32 len = le32_to_cpu(p->buf_size);
+ return (len & DESC_BUFFER1_SZ_MASK) +
+ ((len & DESC_BUFFER2_SZ_MASK) >> DESC_BUFFER2_SZ_OFFSET);
+}
+
+static inline void desc_init_rx_desc(struct xgmac_dma_desc *p, int ring_size,
+ int buf_sz)
+{
+ struct xgmac_dma_desc *end = p + ring_size - 1;
+
+ memset(p, 0, sizeof(*p) * ring_size);
+
+ for (; p <= end; p++)
+ desc_set_buf_len(p, buf_sz);
+
+ end->buf_size |= cpu_to_le32(RXDESC1_END_RING);
+}
+
+static inline void desc_init_tx_desc(struct xgmac_dma_desc *p, u32 ring_size)
+{
+ memset(p, 0, sizeof(*p) * ring_size);
+ p[ring_size - 1].flags = cpu_to_le32(TXDESC_END_RING);
+}
+
+static inline int desc_get_owner(struct xgmac_dma_desc *p)
+{
+ return le32_to_cpu(p->flags) & DESC_OWN;
+}
+
+static inline void desc_set_rx_owner(struct xgmac_dma_desc *p)
+{
+ /* Clear all fields and set the owner */
+ p->flags = cpu_to_le32(DESC_OWN);
+}
+
+static inline void desc_set_tx_owner(struct xgmac_dma_desc *p, u32 flags)
+{
+ u32 tmpflags = le32_to_cpu(p->flags);
+ tmpflags &= TXDESC_END_RING;
+ tmpflags |= flags | DESC_OWN;
+ p->flags = cpu_to_le32(tmpflags);
+}
+
+static inline void *desc_get_buf_addr(struct xgmac_dma_desc *p)
+{
+ return (void *)le32_to_cpu(p->buf1_addr);
+}
+
+static inline void desc_set_buf_addr(struct xgmac_dma_desc *p,
+ void *paddr, int len)
+{
+ p->buf1_addr = cpu_to_le32(paddr);
+ if (len > MAX_DESC_BUF_SZ)
+ p->buf2_addr = cpu_to_le32(paddr + MAX_DESC_BUF_SZ);
+}
+
+static inline void desc_set_buf_addr_and_size(struct xgmac_dma_desc *p,
+ void *paddr, int len)
+{
+ desc_set_buf_len(p, len);
+ desc_set_buf_addr(p, paddr, len);
+}
+
+static inline int desc_get_rx_frame_len(struct xgmac_dma_desc *p)
+{
+ u32 data = le32_to_cpu(p->flags);
+ u32 len = (data & RXDESC_FRAME_LEN_MASK) >> RXDESC_FRAME_LEN_OFFSET;
+ if (data & RXDESC_FRAME_TYPE)
+ len -= 4;
+
+ return len;
+}
+
+struct calxeda_eth_dev {
+ struct xgmac_dma_desc rx_chain[RX_NUM_DESC];
+ struct xgmac_dma_desc tx_chain[TX_NUM_DESC];
+ char rxbuffer[RX_BUF_SZ];
+
+ u32 tx_currdesc;
+ u32 rx_currdesc;
+
+ struct eth_device *dev;
+} __aligned(32);
+
+/*
+ * Initialize a descriptor ring. Calxeda XGMAC is configured to use
+ * advanced descriptors.
+ */
+
+static void init_rx_desc(struct calxeda_eth_dev *priv)
+{
+ struct xgmac_dma_desc *rxdesc = priv->rx_chain;
+ struct xgmac_regs *regs = (struct xgmac_regs *)priv->dev->iobase;
+ void *rxbuffer = priv->rxbuffer;
+ int i;
+
+ desc_init_rx_desc(rxdesc, RX_NUM_DESC, ETH_BUF_SZ);
+ writel((ulong)rxdesc, &regs->rxdesclist);
+
+ for (i = 0; i < RX_NUM_DESC; i++) {
+ desc_set_buf_addr(rxdesc + i, rxbuffer + (i * ETH_BUF_SZ),
+ ETH_BUF_SZ);
+ desc_set_rx_owner(rxdesc + i);
+ }
+}
+
+static void init_tx_desc(struct calxeda_eth_dev *priv)
+{
+ struct xgmac_regs *regs = (struct xgmac_regs *)priv->dev->iobase;
+
+ desc_init_tx_desc(priv->tx_chain, TX_NUM_DESC);
+ writel((ulong)priv->tx_chain, &regs->txdesclist);
+}
+
+static int xgmac_reset(struct eth_device *dev)
+{
+ struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
+ int timeout = MAC_TIMEOUT;
+ u32 value;
+
+ value = readl(&regs->config) & XGMAC_CONTROL_SPD_MASK;
+
+ writel(XGMAC_DMA_BUSMODE_RESET, &regs->busmode);
+ while ((timeout-- >= 0) &&
+ (readl(&regs->busmode) & XGMAC_DMA_BUSMODE_RESET))
+ udelay(1);
+
+ writel(value, &regs->config);
+
+ return timeout;
+}
+
+static void xgmac_hwmacaddr(struct eth_device *dev)
+{
+ struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
+ u32 macaddr[2];
+
+ memcpy(macaddr, dev->enetaddr, 6);
+ writel(macaddr[1], &regs->macaddr[0].hi);
+ writel(macaddr[0], &regs->macaddr[0].lo);
+}
+
+static int xgmac_init(struct eth_device *dev, bd_t * bis)
+{
+ struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
+ struct calxeda_eth_dev *priv = dev->priv;
+ int value;
+
+ if (xgmac_reset(dev) < 0)
+ return -1;
+
+ /* set the hardware MAC address */
+ xgmac_hwmacaddr(dev);
+
+ /* set the AXI bus modes */
+ value = XGMAC_DMA_BUSMODE_ATDS |
+ (16 << XGMAC_DMA_BUSMODE_PBL_SHIFT) |
+ XGMAC_DMA_BUSMODE_FB | XGMAC_DMA_BUSMODE_AAL;
+ writel(value, &regs->busmode);
+
+ value = XGMAC_DMA_AXIMODE_AAL | XGMAC_DMA_AXIMODE_BLEN16 |
+ XGMAC_DMA_AXIMODE_BLEN8 | XGMAC_DMA_AXIMODE_BLEN4;
+ writel(value, &regs->axi_mode);
+
+ /* set flow control parameters and store and forward mode */
+ value = (FIFO_MINUS_12K << XGMAC_CORE_OMR_RFD_SHIFT) |
+ (FIFO_MINUS_4K << XGMAC_CORE_OMR_RFA_SHIFT) |
+ XGMAC_CORE_OMR_EFC | XGMAC_CORE_OMR_TSF;
+ writel(value, &regs->core_opmode);
+
+ /* enable pause frames */
+ value = (1024 << XGMAC_CORE_FLOW_PT_SHIFT) |
+ (1 << XGMAC_CORE_FLOW_PLT_SHIFT) |
+ XGMAC_CORE_FLOW_UP | XGMAC_CORE_FLOW_RFE | XGMAC_CORE_FLOW_TFE;
+ writel(value, &regs->flow_control);
+
+ /* Initialize the descriptor chains */
+ init_rx_desc(priv);
+ init_tx_desc(priv);
+
+ /* must set to 0, or when started up will cause issues */
+ priv->tx_currdesc = 0;
+ priv->rx_currdesc = 0;
+
+ /* set default core values */
+ value = readl(&regs->config);
+ value &= XGMAC_CONTROL_SPD_MASK;
+ value |= XGMAC_CONTROL_DDIC | XGMAC_CONTROL_ACS |
+ XGMAC_CONTROL_IPC | XGMAC_CONTROL_CAR;
+
+ /* Everything is ready enable both mac and DMA */
+ value |= RXENABLE | TXENABLE;
+ writel(value, &regs->config);
+
+ value = readl(&regs->dma_opmode);
+ value |= RXSTART | TXSTART;
+ writel(value, &regs->dma_opmode);
+
+ return 0;
+}
+
+static int xgmac_tx(struct eth_device *dev, void *packet, int length)
+{
+ struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
+ struct calxeda_eth_dev *priv = dev->priv;
+ u32 currdesc = priv->tx_currdesc;
+ struct xgmac_dma_desc *txdesc = &priv->tx_chain[currdesc];
+ int timeout;
+
+ desc_set_buf_addr_and_size(txdesc, packet, length);
+ desc_set_tx_owner(txdesc, TXDESC_FIRST_SEG |
+ TXDESC_LAST_SEG | TXDESC_CRC_EN_APPEND);
+
+ /* write poll demand */
+ writel(1, &regs->txpoll);
+
+ timeout = 1000000;
+ while (desc_get_owner(txdesc)) {
+ if (timeout-- < 0) {
+ printf("xgmac: TX timeout\n");
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ priv->tx_currdesc = (currdesc + 1) & (TX_NUM_DESC - 1);
+ return 0;
+}
+
+static int xgmac_rx(struct eth_device *dev)
+{
+ struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
+ struct calxeda_eth_dev *priv = dev->priv;
+ u32 currdesc = priv->rx_currdesc;
+ struct xgmac_dma_desc *rxdesc = &priv->rx_chain[currdesc];
+ int length = 0;
+
+ /* check if the host has the desc */
+ if (desc_get_owner(rxdesc))
+ return -1; /* something bad happened */
+
+ length = desc_get_rx_frame_len(rxdesc);
+
+ NetReceive(desc_get_buf_addr(rxdesc), length);
+
+ /* set descriptor back to owned by XGMAC */
+ desc_set_rx_owner(rxdesc);
+ writel(1, &regs->rxpoll);
+
+ priv->rx_currdesc = (currdesc + 1) & (RX_NUM_DESC - 1);
+
+ return length;
+}
+
+static void xgmac_halt(struct eth_device *dev)
+{
+ struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
+ struct calxeda_eth_dev *priv = dev->priv;
+ int value;
+
+ /* Disable TX/RX */
+ value = readl(&regs->config);
+ value &= ~(RXENABLE | TXENABLE);
+ writel(value, &regs->config);
+
+ /* Disable DMA */
+ value = readl(&regs->dma_opmode);
+ value &= ~(RXSTART | TXSTART);
+ writel(value, &regs->dma_opmode);
+
+ /* must set to 0, or when started up will cause issues */
+ priv->tx_currdesc = 0;
+ priv->rx_currdesc = 0;
+}
+
+int calxedaxgmac_initialize(u32 id, ulong base_addr)
+{
+ struct eth_device *dev;
+ struct calxeda_eth_dev *priv;
+ struct xgmac_regs *regs;
+ u32 macaddr[2];
+
+ regs = (struct xgmac_regs *)base_addr;
+
+ /* check hardware version */
+ if (readl(&regs->version) != 0x1012)
+ return -1;
+
+ dev = malloc(sizeof(*dev));
+ if (!dev)
+ return 0;
+ memset(dev, 0, sizeof(*dev));
+
+ /* Structure must be aligned, because it contains the descriptors */
+ priv = memalign(32, sizeof(*priv));
+ if (!priv) {
+ free(dev);
+ return 0;
+ }
+
+ dev->iobase = (int)base_addr;
+ dev->priv = priv;
+ priv->dev = dev;
+ sprintf(dev->name, "xgmac%d", id);
+
+ /* The MAC address is already configured, so read it from registers. */
+ macaddr[1] = readl(&regs->macaddr[0].hi);
+ macaddr[0] = readl(&regs->macaddr[0].lo);
+ memcpy(dev->enetaddr, macaddr, 6);
+
+ dev->init = xgmac_init;
+ dev->send = xgmac_tx;
+ dev->recv = xgmac_rx;
+ dev->halt = xgmac_halt;
+
+ eth_register(dev);
+
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/cpsw.c b/qemu/roms/u-boot/drivers/net/cpsw.c
new file mode 100644
index 000000000..bd5fba21c
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/cpsw.c
@@ -0,0 +1,1020 @@
+/*
+ * CPSW Ethernet Switch Driver
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <cpsw.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <phy.h>
+#include <asm/arch/cpu.h>
+
+#define BITMASK(bits) (BIT(bits) - 1)
+#define PHY_REG_MASK 0x1f
+#define PHY_ID_MASK 0x1f
+#define NUM_DESCS (PKTBUFSRX * 2)
+#define PKT_MIN 60
+#define PKT_MAX (1500 + 14 + 4 + 4)
+#define CLEAR_BIT 1
+#define GIGABITEN BIT(7)
+#define FULLDUPLEXEN BIT(0)
+#define MIIEN BIT(15)
+
+/* DMA Registers */
+#define CPDMA_TXCONTROL 0x004
+#define CPDMA_RXCONTROL 0x014
+#define CPDMA_SOFTRESET 0x01c
+#define CPDMA_RXFREE 0x0e0
+#define CPDMA_TXHDP_VER1 0x100
+#define CPDMA_TXHDP_VER2 0x200
+#define CPDMA_RXHDP_VER1 0x120
+#define CPDMA_RXHDP_VER2 0x220
+#define CPDMA_TXCP_VER1 0x140
+#define CPDMA_TXCP_VER2 0x240
+#define CPDMA_RXCP_VER1 0x160
+#define CPDMA_RXCP_VER2 0x260
+
+/* Descriptor mode bits */
+#define CPDMA_DESC_SOP BIT(31)
+#define CPDMA_DESC_EOP BIT(30)
+#define CPDMA_DESC_OWNER BIT(29)
+#define CPDMA_DESC_EOQ BIT(28)
+
+/*
+ * This timeout definition is a worst-case ultra defensive measure against
+ * unexpected controller lock ups. Ideally, we should never ever hit this
+ * scenario in practice.
+ */
+#define MDIO_TIMEOUT 100 /* msecs */
+#define CPDMA_TIMEOUT 100 /* msecs */
+
+struct cpsw_mdio_regs {
+ u32 version;
+ u32 control;
+#define CONTROL_IDLE BIT(31)
+#define CONTROL_ENABLE BIT(30)
+
+ u32 alive;
+ u32 link;
+ u32 linkintraw;
+ u32 linkintmasked;
+ u32 __reserved_0[2];
+ u32 userintraw;
+ u32 userintmasked;
+ u32 userintmaskset;
+ u32 userintmaskclr;
+ u32 __reserved_1[20];
+
+ struct {
+ u32 access;
+ u32 physel;
+#define USERACCESS_GO BIT(31)
+#define USERACCESS_WRITE BIT(30)
+#define USERACCESS_ACK BIT(29)
+#define USERACCESS_READ (0)
+#define USERACCESS_DATA (0xffff)
+ } user[0];
+};
+
+struct cpsw_regs {
+ u32 id_ver;
+ u32 control;
+ u32 soft_reset;
+ u32 stat_port_en;
+ u32 ptype;
+};
+
+struct cpsw_slave_regs {
+ u32 max_blks;
+ u32 blk_cnt;
+ u32 flow_thresh;
+ u32 port_vlan;
+ u32 tx_pri_map;
+#ifdef CONFIG_AM33XX
+ u32 gap_thresh;
+#elif defined(CONFIG_TI814X)
+ u32 ts_ctl;
+ u32 ts_seq_ltype;
+ u32 ts_vlan;
+#endif
+ u32 sa_lo;
+ u32 sa_hi;
+};
+
+struct cpsw_host_regs {
+ u32 max_blks;
+ u32 blk_cnt;
+ u32 flow_thresh;
+ u32 port_vlan;
+ u32 tx_pri_map;
+ u32 cpdma_tx_pri_map;
+ u32 cpdma_rx_chan_map;
+};
+
+struct cpsw_sliver_regs {
+ u32 id_ver;
+ u32 mac_control;
+ u32 mac_status;
+ u32 soft_reset;
+ u32 rx_maxlen;
+ u32 __reserved_0;
+ u32 rx_pause;
+ u32 tx_pause;
+ u32 __reserved_1;
+ u32 rx_pri_map;
+};
+
+#define ALE_ENTRY_BITS 68
+#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32)
+
+/* ALE Registers */
+#define ALE_CONTROL 0x08
+#define ALE_UNKNOWNVLAN 0x18
+#define ALE_TABLE_CONTROL 0x20
+#define ALE_TABLE 0x34
+#define ALE_PORTCTL 0x40
+
+#define ALE_TABLE_WRITE BIT(31)
+
+#define ALE_TYPE_FREE 0
+#define ALE_TYPE_ADDR 1
+#define ALE_TYPE_VLAN 2
+#define ALE_TYPE_VLAN_ADDR 3
+
+#define ALE_UCAST_PERSISTANT 0
+#define ALE_UCAST_UNTOUCHED 1
+#define ALE_UCAST_OUI 2
+#define ALE_UCAST_TOUCHED 3
+
+#define ALE_MCAST_FWD 0
+#define ALE_MCAST_BLOCK_LEARN_FWD 1
+#define ALE_MCAST_FWD_LEARN 2
+#define ALE_MCAST_FWD_2 3
+
+enum cpsw_ale_port_state {
+ ALE_PORT_STATE_DISABLE = 0x00,
+ ALE_PORT_STATE_BLOCK = 0x01,
+ ALE_PORT_STATE_LEARN = 0x02,
+ ALE_PORT_STATE_FORWARD = 0x03,
+};
+
+/* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
+#define ALE_SECURE 1
+#define ALE_BLOCKED 2
+
+struct cpsw_slave {
+ struct cpsw_slave_regs *regs;
+ struct cpsw_sliver_regs *sliver;
+ int slave_num;
+ u32 mac_control;
+ struct cpsw_slave_data *data;
+};
+
+struct cpdma_desc {
+ /* hardware fields */
+ u32 hw_next;
+ u32 hw_buffer;
+ u32 hw_len;
+ u32 hw_mode;
+ /* software fields */
+ u32 sw_buffer;
+ u32 sw_len;
+};
+
+struct cpdma_chan {
+ struct cpdma_desc *head, *tail;
+ void *hdp, *cp, *rxfree;
+};
+
+#define desc_write(desc, fld, val) __raw_writel((u32)(val), &(desc)->fld)
+#define desc_read(desc, fld) __raw_readl(&(desc)->fld)
+#define desc_read_ptr(desc, fld) ((void *)__raw_readl(&(desc)->fld))
+
+#define chan_write(chan, fld, val) __raw_writel((u32)(val), (chan)->fld)
+#define chan_read(chan, fld) __raw_readl((chan)->fld)
+#define chan_read_ptr(chan, fld) ((void *)__raw_readl((chan)->fld))
+
+#define for_each_slave(slave, priv) \
+ for (slave = (priv)->slaves; slave != (priv)->slaves + \
+ (priv)->data.slaves; slave++)
+
+struct cpsw_priv {
+ struct eth_device *dev;
+ struct cpsw_platform_data data;
+ int host_port;
+
+ struct cpsw_regs *regs;
+ void *dma_regs;
+ struct cpsw_host_regs *host_port_regs;
+ void *ale_regs;
+
+ struct cpdma_desc *descs;
+ struct cpdma_desc *desc_free;
+ struct cpdma_chan rx_chan, tx_chan;
+
+ struct cpsw_slave *slaves;
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+
+ u32 mdio_link;
+ u32 phy_mask;
+};
+
+static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
+{
+ int idx;
+
+ idx = start / 32;
+ start -= idx * 32;
+ idx = 2 - idx; /* flip */
+ return (ale_entry[idx] >> start) & BITMASK(bits);
+}
+
+static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
+ u32 value)
+{
+ int idx;
+
+ value &= BITMASK(bits);
+ idx = start / 32;
+ start -= idx * 32;
+ idx = 2 - idx; /* flip */
+ ale_entry[idx] &= ~(BITMASK(bits) << start);
+ ale_entry[idx] |= (value << start);
+}
+
+#define DEFINE_ALE_FIELD(name, start, bits) \
+static inline int cpsw_ale_get_##name(u32 *ale_entry) \
+{ \
+ return cpsw_ale_get_field(ale_entry, start, bits); \
+} \
+static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \
+{ \
+ cpsw_ale_set_field(ale_entry, start, bits, value); \
+}
+
+DEFINE_ALE_FIELD(entry_type, 60, 2)
+DEFINE_ALE_FIELD(mcast_state, 62, 2)
+DEFINE_ALE_FIELD(port_mask, 66, 3)
+DEFINE_ALE_FIELD(ucast_type, 62, 2)
+DEFINE_ALE_FIELD(port_num, 66, 2)
+DEFINE_ALE_FIELD(blocked, 65, 1)
+DEFINE_ALE_FIELD(secure, 64, 1)
+DEFINE_ALE_FIELD(mcast, 40, 1)
+
+/* The MAC address field in the ALE entry cannot be macroized as above */
+static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
+}
+
+static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ cpsw_ale_set_field(ale_entry, 40 - 8*i, 8, addr[i]);
+}
+
+static int cpsw_ale_read(struct cpsw_priv *priv, int idx, u32 *ale_entry)
+{
+ int i;
+
+ __raw_writel(idx, priv->ale_regs + ALE_TABLE_CONTROL);
+
+ for (i = 0; i < ALE_ENTRY_WORDS; i++)
+ ale_entry[i] = __raw_readl(priv->ale_regs + ALE_TABLE + 4 * i);
+
+ return idx;
+}
+
+static int cpsw_ale_write(struct cpsw_priv *priv, int idx, u32 *ale_entry)
+{
+ int i;
+
+ for (i = 0; i < ALE_ENTRY_WORDS; i++)
+ __raw_writel(ale_entry[i], priv->ale_regs + ALE_TABLE + 4 * i);
+
+ __raw_writel(idx | ALE_TABLE_WRITE, priv->ale_regs + ALE_TABLE_CONTROL);
+
+ return idx;
+}
+
+static int cpsw_ale_match_addr(struct cpsw_priv *priv, u8* addr)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS];
+ int type, idx;
+
+ for (idx = 0; idx < priv->data.ale_entries; idx++) {
+ u8 entry_addr[6];
+
+ cpsw_ale_read(priv, idx, ale_entry);
+ type = cpsw_ale_get_entry_type(ale_entry);
+ if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
+ continue;
+ cpsw_ale_get_addr(ale_entry, entry_addr);
+ if (memcmp(entry_addr, addr, 6) == 0)
+ return idx;
+ }
+ return -ENOENT;
+}
+
+static int cpsw_ale_match_free(struct cpsw_priv *priv)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS];
+ int type, idx;
+
+ for (idx = 0; idx < priv->data.ale_entries; idx++) {
+ cpsw_ale_read(priv, idx, ale_entry);
+ type = cpsw_ale_get_entry_type(ale_entry);
+ if (type == ALE_TYPE_FREE)
+ return idx;
+ }
+ return -ENOENT;
+}
+
+static int cpsw_ale_find_ageable(struct cpsw_priv *priv)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS];
+ int type, idx;
+
+ for (idx = 0; idx < priv->data.ale_entries; idx++) {
+ cpsw_ale_read(priv, idx, ale_entry);
+ type = cpsw_ale_get_entry_type(ale_entry);
+ if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
+ continue;
+ if (cpsw_ale_get_mcast(ale_entry))
+ continue;
+ type = cpsw_ale_get_ucast_type(ale_entry);
+ if (type != ALE_UCAST_PERSISTANT &&
+ type != ALE_UCAST_OUI)
+ return idx;
+ }
+ return -ENOENT;
+}
+
+static int cpsw_ale_add_ucast(struct cpsw_priv *priv, u8 *addr,
+ int port, int flags)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+ int idx;
+
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ cpsw_ale_set_addr(ale_entry, addr);
+ cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
+ cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
+ cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
+ cpsw_ale_set_port_num(ale_entry, port);
+
+ idx = cpsw_ale_match_addr(priv, addr);
+ if (idx < 0)
+ idx = cpsw_ale_match_free(priv);
+ if (idx < 0)
+ idx = cpsw_ale_find_ageable(priv);
+ if (idx < 0)
+ return -ENOMEM;
+
+ cpsw_ale_write(priv, idx, ale_entry);
+ return 0;
+}
+
+static int cpsw_ale_add_mcast(struct cpsw_priv *priv, u8 *addr, int port_mask)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+ int idx, mask;
+
+ idx = cpsw_ale_match_addr(priv, addr);
+ if (idx >= 0)
+ cpsw_ale_read(priv, idx, ale_entry);
+
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ cpsw_ale_set_addr(ale_entry, addr);
+ cpsw_ale_set_mcast_state(ale_entry, ALE_MCAST_FWD_2);
+
+ mask = cpsw_ale_get_port_mask(ale_entry);
+ port_mask |= mask;
+ cpsw_ale_set_port_mask(ale_entry, port_mask);
+
+ if (idx < 0)
+ idx = cpsw_ale_match_free(priv);
+ if (idx < 0)
+ idx = cpsw_ale_find_ageable(priv);
+ if (idx < 0)
+ return -ENOMEM;
+
+ cpsw_ale_write(priv, idx, ale_entry);
+ return 0;
+}
+
+static inline void cpsw_ale_control(struct cpsw_priv *priv, int bit, int val)
+{
+ u32 tmp, mask = BIT(bit);
+
+ tmp = __raw_readl(priv->ale_regs + ALE_CONTROL);
+ tmp &= ~mask;
+ tmp |= val ? mask : 0;
+ __raw_writel(tmp, priv->ale_regs + ALE_CONTROL);
+}
+
+#define cpsw_ale_enable(priv, val) cpsw_ale_control(priv, 31, val)
+#define cpsw_ale_clear(priv, val) cpsw_ale_control(priv, 30, val)
+#define cpsw_ale_vlan_aware(priv, val) cpsw_ale_control(priv, 2, val)
+
+static inline void cpsw_ale_port_state(struct cpsw_priv *priv, int port,
+ int val)
+{
+ int offset = ALE_PORTCTL + 4 * port;
+ u32 tmp, mask = 0x3;
+
+ tmp = __raw_readl(priv->ale_regs + offset);
+ tmp &= ~mask;
+ tmp |= val & mask;
+ __raw_writel(tmp, priv->ale_regs + offset);
+}
+
+static struct cpsw_mdio_regs *mdio_regs;
+
+/* wait until hardware is ready for another user access */
+static inline u32 wait_for_user_access(void)
+{
+ u32 reg = 0;
+ int timeout = MDIO_TIMEOUT;
+
+ while (timeout-- &&
+ ((reg = __raw_readl(&mdio_regs->user[0].access)) & USERACCESS_GO))
+ udelay(10);
+
+ if (timeout == -1) {
+ printf("wait_for_user_access Timeout\n");
+ return -ETIMEDOUT;
+ }
+ return reg;
+}
+
+/* wait until hardware state machine is idle */
+static inline void wait_for_idle(void)
+{
+ int timeout = MDIO_TIMEOUT;
+
+ while (timeout-- &&
+ ((__raw_readl(&mdio_regs->control) & CONTROL_IDLE) == 0))
+ udelay(10);
+
+ if (timeout == -1)
+ printf("wait_for_idle Timeout\n");
+}
+
+static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
+ int dev_addr, int phy_reg)
+{
+ int data;
+ u32 reg;
+
+ if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
+ return -EINVAL;
+
+ wait_for_user_access();
+ reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
+ (phy_id << 16));
+ __raw_writel(reg, &mdio_regs->user[0].access);
+ reg = wait_for_user_access();
+
+ data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1;
+ return data;
+}
+
+static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr,
+ int phy_reg, u16 data)
+{
+ u32 reg;
+
+ if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
+ return -EINVAL;
+
+ wait_for_user_access();
+ reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
+ (phy_id << 16) | (data & USERACCESS_DATA));
+ __raw_writel(reg, &mdio_regs->user[0].access);
+ wait_for_user_access();
+
+ return 0;
+}
+
+static void cpsw_mdio_init(char *name, u32 mdio_base, u32 div)
+{
+ struct mii_dev *bus = mdio_alloc();
+
+ mdio_regs = (struct cpsw_mdio_regs *)mdio_base;
+
+ /* set enable and clock divider */
+ __raw_writel(div | CONTROL_ENABLE, &mdio_regs->control);
+
+ /*
+ * wait for scan logic to settle:
+ * the scan time consists of (a) a large fixed component, and (b) a
+ * small component that varies with the mii bus frequency. These
+ * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x
+ * silicon. Since the effect of (b) was found to be largely
+ * negligible, we keep things simple here.
+ */
+ udelay(1000);
+
+ bus->read = cpsw_mdio_read;
+ bus->write = cpsw_mdio_write;
+ sprintf(bus->name, name);
+
+ mdio_register(bus);
+}
+
+/* Set a self-clearing bit in a register, and wait for it to clear */
+static inline void setbit_and_wait_for_clear32(void *addr)
+{
+ __raw_writel(CLEAR_BIT, addr);
+ while (__raw_readl(addr) & CLEAR_BIT)
+ ;
+}
+
+#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \
+ ((mac)[2] << 16) | ((mac)[3] << 24))
+#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8))
+
+static void cpsw_set_slave_mac(struct cpsw_slave *slave,
+ struct cpsw_priv *priv)
+{
+ __raw_writel(mac_hi(priv->dev->enetaddr), &slave->regs->sa_hi);
+ __raw_writel(mac_lo(priv->dev->enetaddr), &slave->regs->sa_lo);
+}
+
+static void cpsw_slave_update_link(struct cpsw_slave *slave,
+ struct cpsw_priv *priv, int *link)
+{
+ struct phy_device *phy;
+ u32 mac_control = 0;
+
+ phy = priv->phydev;
+
+ if (!phy)
+ return;
+
+ phy_startup(phy);
+ *link = phy->link;
+
+ if (*link) { /* link up */
+ mac_control = priv->data.mac_control;
+ if (phy->speed == 1000)
+ mac_control |= GIGABITEN;
+ if (phy->duplex == DUPLEX_FULL)
+ mac_control |= FULLDUPLEXEN;
+ if (phy->speed == 100)
+ mac_control |= MIIEN;
+ }
+
+ if (mac_control == slave->mac_control)
+ return;
+
+ if (mac_control) {
+ printf("link up on port %d, speed %d, %s duplex\n",
+ slave->slave_num, phy->speed,
+ (phy->duplex == DUPLEX_FULL) ? "full" : "half");
+ } else {
+ printf("link down on port %d\n", slave->slave_num);
+ }
+
+ __raw_writel(mac_control, &slave->sliver->mac_control);
+ slave->mac_control = mac_control;
+}
+
+static int cpsw_update_link(struct cpsw_priv *priv)
+{
+ int link = 0;
+ struct cpsw_slave *slave;
+
+ for_each_slave(slave, priv)
+ cpsw_slave_update_link(slave, priv, &link);
+ priv->mdio_link = readl(&mdio_regs->link);
+ return link;
+}
+
+static int cpsw_check_link(struct cpsw_priv *priv)
+{
+ u32 link = 0;
+
+ link = __raw_readl(&mdio_regs->link) & priv->phy_mask;
+ if ((link) && (link == priv->mdio_link))
+ return 1;
+
+ return cpsw_update_link(priv);
+}
+
+static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
+{
+ if (priv->host_port == 0)
+ return slave_num + 1;
+ else
+ return slave_num;
+}
+
+static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
+{
+ u32 slave_port;
+
+ setbit_and_wait_for_clear32(&slave->sliver->soft_reset);
+
+ /* setup priority mapping */
+ __raw_writel(0x76543210, &slave->sliver->rx_pri_map);
+ __raw_writel(0x33221100, &slave->regs->tx_pri_map);
+
+ /* setup max packet size, and mac address */
+ __raw_writel(PKT_MAX, &slave->sliver->rx_maxlen);
+ cpsw_set_slave_mac(slave, priv);
+
+ slave->mac_control = 0; /* no link yet */
+
+ /* enable forwarding */
+ slave_port = cpsw_get_slave_port(priv, slave->slave_num);
+ cpsw_ale_port_state(priv, slave_port, ALE_PORT_STATE_FORWARD);
+
+ cpsw_ale_add_mcast(priv, NetBcastAddr, 1 << slave_port);
+
+ priv->phy_mask |= 1 << slave->data->phy_addr;
+}
+
+static struct cpdma_desc *cpdma_desc_alloc(struct cpsw_priv *priv)
+{
+ struct cpdma_desc *desc = priv->desc_free;
+
+ if (desc)
+ priv->desc_free = desc_read_ptr(desc, hw_next);
+ return desc;
+}
+
+static void cpdma_desc_free(struct cpsw_priv *priv, struct cpdma_desc *desc)
+{
+ if (desc) {
+ desc_write(desc, hw_next, priv->desc_free);
+ priv->desc_free = desc;
+ }
+}
+
+static int cpdma_submit(struct cpsw_priv *priv, struct cpdma_chan *chan,
+ void *buffer, int len)
+{
+ struct cpdma_desc *desc, *prev;
+ u32 mode;
+
+ desc = cpdma_desc_alloc(priv);
+ if (!desc)
+ return -ENOMEM;
+
+ if (len < PKT_MIN)
+ len = PKT_MIN;
+
+ mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
+
+ desc_write(desc, hw_next, 0);
+ desc_write(desc, hw_buffer, buffer);
+ desc_write(desc, hw_len, len);
+ desc_write(desc, hw_mode, mode | len);
+ desc_write(desc, sw_buffer, buffer);
+ desc_write(desc, sw_len, len);
+
+ if (!chan->head) {
+ /* simple case - first packet enqueued */
+ chan->head = desc;
+ chan->tail = desc;
+ chan_write(chan, hdp, desc);
+ goto done;
+ }
+
+ /* not the first packet - enqueue at the tail */
+ prev = chan->tail;
+ desc_write(prev, hw_next, desc);
+ chan->tail = desc;
+
+ /* next check if EOQ has been triggered already */
+ if (desc_read(prev, hw_mode) & CPDMA_DESC_EOQ)
+ chan_write(chan, hdp, desc);
+
+done:
+ if (chan->rxfree)
+ chan_write(chan, rxfree, 1);
+ return 0;
+}
+
+static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan,
+ void **buffer, int *len)
+{
+ struct cpdma_desc *desc = chan->head;
+ u32 status;
+
+ if (!desc)
+ return -ENOENT;
+
+ status = desc_read(desc, hw_mode);
+
+ if (len)
+ *len = status & 0x7ff;
+
+ if (buffer)
+ *buffer = desc_read_ptr(desc, sw_buffer);
+
+ if (status & CPDMA_DESC_OWNER) {
+ if (chan_read(chan, hdp) == 0) {
+ if (desc_read(desc, hw_mode) & CPDMA_DESC_OWNER)
+ chan_write(chan, hdp, desc);
+ }
+
+ return -EBUSY;
+ }
+
+ chan->head = desc_read_ptr(desc, hw_next);
+ chan_write(chan, cp, desc);
+
+ cpdma_desc_free(priv, desc);
+ return 0;
+}
+
+static int cpsw_init(struct eth_device *dev, bd_t *bis)
+{
+ struct cpsw_priv *priv = dev->priv;
+ struct cpsw_slave *slave;
+ int i, ret;
+
+ /* soft reset the controller and initialize priv */
+ setbit_and_wait_for_clear32(&priv->regs->soft_reset);
+
+ /* initialize and reset the address lookup engine */
+ cpsw_ale_enable(priv, 1);
+ cpsw_ale_clear(priv, 1);
+ cpsw_ale_vlan_aware(priv, 0); /* vlan unaware mode */
+
+ /* setup host port priority mapping */
+ __raw_writel(0x76543210, &priv->host_port_regs->cpdma_tx_pri_map);
+ __raw_writel(0, &priv->host_port_regs->cpdma_rx_chan_map);
+
+ /* disable priority elevation and enable statistics on all ports */
+ __raw_writel(0, &priv->regs->ptype);
+
+ /* enable statistics collection only on the host port */
+ __raw_writel(BIT(priv->host_port), &priv->regs->stat_port_en);
+ __raw_writel(0x7, &priv->regs->stat_port_en);
+
+ cpsw_ale_port_state(priv, priv->host_port, ALE_PORT_STATE_FORWARD);
+
+ cpsw_ale_add_ucast(priv, priv->dev->enetaddr, priv->host_port,
+ ALE_SECURE);
+ cpsw_ale_add_mcast(priv, NetBcastAddr, 1 << priv->host_port);
+
+ for_each_slave(slave, priv)
+ cpsw_slave_init(slave, priv);
+
+ cpsw_update_link(priv);
+
+ /* init descriptor pool */
+ for (i = 0; i < NUM_DESCS; i++) {
+ desc_write(&priv->descs[i], hw_next,
+ (i == (NUM_DESCS - 1)) ? 0 : &priv->descs[i+1]);
+ }
+ priv->desc_free = &priv->descs[0];
+
+ /* initialize channels */
+ if (priv->data.version == CPSW_CTRL_VERSION_2) {
+ memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan));
+ priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER2;
+ priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER2;
+ priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE;
+
+ memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan));
+ priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER2;
+ priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER2;
+ } else {
+ memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan));
+ priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER1;
+ priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER1;
+ priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE;
+
+ memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan));
+ priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER1;
+ priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER1;
+ }
+
+ /* clear dma state */
+ setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET);
+
+ if (priv->data.version == CPSW_CTRL_VERSION_2) {
+ for (i = 0; i < priv->data.channels; i++) {
+ __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER2 + 4
+ * i);
+ __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4
+ * i);
+ __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER2 + 4
+ * i);
+ __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER2 + 4
+ * i);
+ __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER2 + 4
+ * i);
+ }
+ } else {
+ for (i = 0; i < priv->data.channels; i++) {
+ __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER1 + 4
+ * i);
+ __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4
+ * i);
+ __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER1 + 4
+ * i);
+ __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER1 + 4
+ * i);
+ __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER1 + 4
+ * i);
+
+ }
+ }
+
+ __raw_writel(1, priv->dma_regs + CPDMA_TXCONTROL);
+ __raw_writel(1, priv->dma_regs + CPDMA_RXCONTROL);
+
+ /* submit rx descs */
+ for (i = 0; i < PKTBUFSRX; i++) {
+ ret = cpdma_submit(priv, &priv->rx_chan, NetRxPackets[i],
+ PKTSIZE);
+ if (ret < 0) {
+ printf("error %d submitting rx desc\n", ret);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void cpsw_halt(struct eth_device *dev)
+{
+ struct cpsw_priv *priv = dev->priv;
+
+ writel(0, priv->dma_regs + CPDMA_TXCONTROL);
+ writel(0, priv->dma_regs + CPDMA_RXCONTROL);
+
+ /* soft reset the controller and initialize priv */
+ setbit_and_wait_for_clear32(&priv->regs->soft_reset);
+
+ /* clear dma state */
+ setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET);
+
+ priv->data.control(0);
+}
+
+static int cpsw_send(struct eth_device *dev, void *packet, int length)
+{
+ struct cpsw_priv *priv = dev->priv;
+ void *buffer;
+ int len;
+ int timeout = CPDMA_TIMEOUT;
+
+ if (!cpsw_check_link(priv))
+ return -EIO;
+
+ flush_dcache_range((unsigned long)packet,
+ (unsigned long)packet + length);
+
+ /* first reap completed packets */
+ while (timeout-- &&
+ (cpdma_process(priv, &priv->tx_chan, &buffer, &len) >= 0))
+ ;
+
+ if (timeout == -1) {
+ printf("cpdma_process timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return cpdma_submit(priv, &priv->tx_chan, packet, length);
+}
+
+static int cpsw_recv(struct eth_device *dev)
+{
+ struct cpsw_priv *priv = dev->priv;
+ void *buffer;
+ int len;
+
+ cpsw_check_link(priv);
+
+ while (cpdma_process(priv, &priv->rx_chan, &buffer, &len) >= 0) {
+ invalidate_dcache_range((unsigned long)buffer,
+ (unsigned long)buffer + PKTSIZE_ALIGN);
+ NetReceive(buffer, len);
+ cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE);
+ }
+
+ return 0;
+}
+
+static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num,
+ struct cpsw_priv *priv)
+{
+ void *regs = priv->regs;
+ struct cpsw_slave_data *data = priv->data.slave_data + slave_num;
+ slave->slave_num = slave_num;
+ slave->data = data;
+ slave->regs = regs + data->slave_reg_ofs;
+ slave->sliver = regs + data->sliver_reg_ofs;
+}
+
+static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave)
+{
+ struct cpsw_priv *priv = (struct cpsw_priv *)dev->priv;
+ struct phy_device *phydev;
+ u32 supported = PHY_GBIT_FEATURES;
+
+ phydev = phy_connect(priv->bus,
+ slave->data->phy_addr,
+ dev,
+ slave->data->phy_if);
+
+ if (!phydev)
+ return -1;
+
+ phydev->supported &= supported;
+ phydev->advertising = phydev->supported;
+
+ priv->phydev = phydev;
+ phy_config(phydev);
+
+ return 1;
+}
+
+int cpsw_register(struct cpsw_platform_data *data)
+{
+ struct cpsw_priv *priv;
+ struct cpsw_slave *slave;
+ void *regs = (void *)data->cpsw_base;
+ struct eth_device *dev;
+
+ dev = calloc(sizeof(*dev), 1);
+ if (!dev)
+ return -ENOMEM;
+
+ priv = calloc(sizeof(*priv), 1);
+ if (!priv) {
+ free(dev);
+ return -ENOMEM;
+ }
+
+ priv->data = *data;
+ priv->dev = dev;
+
+ priv->slaves = malloc(sizeof(struct cpsw_slave) * data->slaves);
+ if (!priv->slaves) {
+ free(dev);
+ free(priv);
+ return -ENOMEM;
+ }
+
+ priv->host_port = data->host_port_num;
+ priv->regs = regs;
+ priv->host_port_regs = regs + data->host_port_reg_ofs;
+ priv->dma_regs = regs + data->cpdma_reg_ofs;
+ priv->ale_regs = regs + data->ale_reg_ofs;
+ priv->descs = (void *)regs + data->bd_ram_ofs;
+
+ int idx = 0;
+
+ for_each_slave(slave, priv) {
+ cpsw_slave_setup(slave, idx, priv);
+ idx = idx + 1;
+ }
+
+ strcpy(dev->name, "cpsw");
+ dev->iobase = 0;
+ dev->init = cpsw_init;
+ dev->halt = cpsw_halt;
+ dev->send = cpsw_send;
+ dev->recv = cpsw_recv;
+ dev->priv = priv;
+
+ eth_register(dev);
+
+ cpsw_mdio_init(dev->name, data->mdio_base, data->mdio_div);
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+ for_each_slave(slave, priv)
+ cpsw_phy_init(dev, slave);
+
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/cs8900.c b/qemu/roms/u-boot/drivers/net/cs8900.c
new file mode 100644
index 000000000..84963c1f2
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/cs8900.c
@@ -0,0 +1,320 @@
+/*
+ * Cirrus Logic CS8900A Ethernet
+ *
+ * (C) 2009 Ben Warren , biggerbadderben@gmail.com
+ * Converted to use CONFIG_NET_MULTI API
+ *
+ * (C) 2003 Wolfgang Denk, wd@denx.de
+ * Extension to synchronize ethaddr environment variable
+ * against value in EEPROM
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 1999 Ben Williamson <benw@pobox.com>
+ *
+ * This program is loaded into SRAM in bootstrap mode, where it waits
+ * for commands on UART1 to read and write memory, jump to code etc.
+ * A design goal for this program is to be entirely independent of the
+ * target board. Anything with a CL-PS7111 or EP7211 should be able to run
+ * this code in bootstrap mode. All the board specifics can be handled on
+ * the host.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <net.h>
+#include <malloc.h>
+#include "cs8900.h"
+
+#undef DEBUG
+
+/* packet page register access functions */
+
+#ifdef CONFIG_CS8900_BUS32
+
+#define REG_WRITE(v, a) writel((v),(a))
+#define REG_READ(a) readl((a))
+
+/* we don't need 16 bit initialisation on 32 bit bus */
+#define get_reg_init_bus(r,d) get_reg((r),(d))
+
+#else
+
+#define REG_WRITE(v, a) writew((v),(a))
+#define REG_READ(a) readw((a))
+
+static u16 get_reg_init_bus(struct eth_device *dev, int regno)
+{
+ /* force 16 bit busmode */
+ struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
+ uint8_t volatile * const iob = (uint8_t volatile * const)dev->iobase;
+
+ readb(iob);
+ readb(iob + 1);
+ readb(iob);
+ readb(iob + 1);
+ readb(iob);
+
+ REG_WRITE(regno, &priv->regs->pptr);
+ return REG_READ(&priv->regs->pdata);
+}
+#endif
+
+static u16 get_reg(struct eth_device *dev, int regno)
+{
+ struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
+ REG_WRITE(regno, &priv->regs->pptr);
+ return REG_READ(&priv->regs->pdata);
+}
+
+
+static void put_reg(struct eth_device *dev, int regno, u16 val)
+{
+ struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
+ REG_WRITE(regno, &priv->regs->pptr);
+ REG_WRITE(val, &priv->regs->pdata);
+}
+
+static void cs8900_reset(struct eth_device *dev)
+{
+ int tmo;
+ u16 us;
+
+ /* reset NIC */
+ put_reg(dev, PP_SelfCTL, get_reg(dev, PP_SelfCTL) | PP_SelfCTL_Reset);
+
+ /* wait for 200ms */
+ udelay(200000);
+ /* Wait until the chip is reset */
+
+ tmo = get_timer(0) + 1 * CONFIG_SYS_HZ;
+ while ((((us = get_reg_init_bus(dev, PP_SelfSTAT)) &
+ PP_SelfSTAT_InitD) == 0) && tmo < get_timer(0))
+ /*NOP*/;
+}
+
+static void cs8900_reginit(struct eth_device *dev)
+{
+ /* receive only error free packets addressed to this card */
+ put_reg(dev, PP_RxCTL,
+ PP_RxCTL_IA | PP_RxCTL_Broadcast | PP_RxCTL_RxOK);
+ /* do not generate any interrupts on receive operations */
+ put_reg(dev, PP_RxCFG, 0);
+ /* do not generate any interrupts on transmit operations */
+ put_reg(dev, PP_TxCFG, 0);
+ /* do not generate any interrupts on buffer operations */
+ put_reg(dev, PP_BufCFG, 0);
+ /* enable transmitter/receiver mode */
+ put_reg(dev, PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);
+}
+
+void cs8900_get_enetaddr(struct eth_device *dev)
+{
+ int i;
+
+ /* verify chip id */
+ if (get_reg_init_bus(dev, PP_ChipID) != 0x630e)
+ return;
+ cs8900_reset(dev);
+ if ((get_reg(dev, PP_SelfSTAT) &
+ (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) ==
+ (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) {
+
+ /* Load the MAC from EEPROM */
+ for (i = 0; i < 3; i++) {
+ u32 Addr;
+
+ Addr = get_reg(dev, PP_IA + i * 2);
+ dev->enetaddr[i * 2] = Addr & 0xFF;
+ dev->enetaddr[i * 2 + 1] = Addr >> 8;
+ }
+ }
+}
+
+void cs8900_halt(struct eth_device *dev)
+{
+ /* disable transmitter/receiver mode */
+ put_reg(dev, PP_LineCTL, 0);
+
+ /* "shutdown" to show ChipID or kernel wouldn't find he cs8900 ... */
+ get_reg_init_bus(dev, PP_ChipID);
+}
+
+static int cs8900_init(struct eth_device *dev, bd_t * bd)
+{
+ uchar *enetaddr = dev->enetaddr;
+ u16 id;
+
+ /* verify chip id */
+ id = get_reg_init_bus(dev, PP_ChipID);
+ if (id != 0x630e) {
+ printf ("CS8900 Ethernet chip not found: "
+ "ID=0x%04x instead 0x%04x\n", id, 0x630e);
+ return 1;
+ }
+
+ cs8900_reset (dev);
+ /* set the ethernet address */
+ put_reg(dev, PP_IA + 0, enetaddr[0] | (enetaddr[1] << 8));
+ put_reg(dev, PP_IA + 2, enetaddr[2] | (enetaddr[3] << 8));
+ put_reg(dev, PP_IA + 4, enetaddr[4] | (enetaddr[5] << 8));
+
+ cs8900_reginit(dev);
+ return 0;
+}
+
+/* Get a data block via Ethernet */
+static int cs8900_recv(struct eth_device *dev)
+{
+ int i;
+ u16 rxlen;
+ u16 *addr;
+ u16 status;
+
+ struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
+
+ status = get_reg(dev, PP_RER);
+
+ if ((status & PP_RER_RxOK) == 0)
+ return 0;
+
+ status = REG_READ(&priv->regs->rtdata);
+ rxlen = REG_READ(&priv->regs->rtdata);
+
+ if (rxlen > PKTSIZE_ALIGN + PKTALIGN)
+ debug("packet too big!\n");
+ for (addr = (u16 *) NetRxPackets[0], i = rxlen >> 1; i > 0;
+ i--)
+ *addr++ = REG_READ(&priv->regs->rtdata);
+ if (rxlen & 1)
+ *addr++ = REG_READ(&priv->regs->rtdata);
+
+ /* Pass the packet up to the protocol layers. */
+ NetReceive (NetRxPackets[0], rxlen);
+ return rxlen;
+}
+
+/* Send a data block via Ethernet. */
+static int cs8900_send(struct eth_device *dev, void *packet, int length)
+{
+ volatile u16 *addr;
+ int tmo;
+ u16 s;
+ struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
+
+retry:
+ /* initiate a transmit sequence */
+ REG_WRITE(PP_TxCmd_TxStart_Full, &priv->regs->txcmd);
+ REG_WRITE(length, &priv->regs->txlen);
+
+ /* Test to see if the chip has allocated memory for the packet */
+ if ((get_reg(dev, PP_BusSTAT) & PP_BusSTAT_TxRDY) == 0) {
+ /* Oops... this should not happen! */
+ debug("cs: unable to send packet; retrying...\n");
+ for (tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
+ get_timer(0) < tmo;)
+ /*NOP*/;
+ cs8900_reset(dev);
+ cs8900_reginit(dev);
+ goto retry;
+ }
+
+ /* Write the contents of the packet */
+ /* assume even number of bytes */
+ for (addr = packet; length > 0; length -= 2)
+ REG_WRITE(*addr++, &priv->regs->rtdata);
+
+ /* wait for transfer to succeed */
+ tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
+ while ((s = get_reg(dev, PP_TER) & ~0x1F) == 0) {
+ if (get_timer(0) >= tmo)
+ break;
+ }
+
+ /* nothing */ ;
+ if((s & (PP_TER_CRS | PP_TER_TxOK)) != PP_TER_TxOK) {
+ debug("\ntransmission error %#x\n", s);
+ }
+
+ return 0;
+}
+
+static void cs8900_e2prom_ready(struct eth_device *dev)
+{
+ while (get_reg(dev, PP_SelfSTAT) & SI_BUSY)
+ ;
+}
+
+/***********************************************************/
+/* read a 16-bit word out of the EEPROM */
+/***********************************************************/
+
+int cs8900_e2prom_read(struct eth_device *dev,
+ u8 addr, u16 *value)
+{
+ cs8900_e2prom_ready(dev);
+ put_reg(dev, PP_EECMD, EEPROM_READ_CMD | addr);
+ cs8900_e2prom_ready(dev);
+ *value = get_reg(dev, PP_EEData);
+
+ return 0;
+}
+
+
+/***********************************************************/
+/* write a 16-bit word into the EEPROM */
+/***********************************************************/
+
+int cs8900_e2prom_write(struct eth_device *dev, u8 addr, u16 value)
+{
+ cs8900_e2prom_ready(dev);
+ put_reg(dev, PP_EECMD, EEPROM_WRITE_EN);
+ cs8900_e2prom_ready(dev);
+ put_reg(dev, PP_EEData, value);
+ put_reg(dev, PP_EECMD, EEPROM_WRITE_CMD | addr);
+ cs8900_e2prom_ready(dev);
+ put_reg(dev, PP_EECMD, EEPROM_WRITE_DIS);
+ cs8900_e2prom_ready(dev);
+
+ return 0;
+}
+
+int cs8900_initialize(u8 dev_num, int base_addr)
+{
+ struct eth_device *dev;
+ struct cs8900_priv *priv;
+
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ return 0;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ priv = malloc(sizeof(*priv));
+ if (!priv) {
+ free(dev);
+ return 0;
+ }
+ memset(priv, 0, sizeof(*priv));
+ priv->regs = (struct cs8900_regs *)base_addr;
+
+ dev->iobase = base_addr;
+ dev->priv = priv;
+ dev->init = cs8900_init;
+ dev->halt = cs8900_halt;
+ dev->send = cs8900_send;
+ dev->recv = cs8900_recv;
+
+ /* Load MAC address from EEPROM */
+ cs8900_get_enetaddr(dev);
+
+ sprintf(dev->name, "%s-%hu", CS8900_DRIVERNAME, dev_num);
+
+ eth_register(dev);
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/cs8900.h b/qemu/roms/u-boot/drivers/net/cs8900.h
new file mode 100644
index 000000000..79877dd57
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/cs8900.h
@@ -0,0 +1,249 @@
+#ifndef CS8900_H
+#define CS8900_H
+/*
+ * Cirrus Logic CS8900A Ethernet
+ *
+ * (C) 2009 Ben Warren , biggerbadderben@gmail.com
+ * Converted to use CONFIG_NET_MULTI API
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 1999 Ben Williamson <benw@pobox.com>
+ *
+ * This program is loaded into SRAM in bootstrap mode, where it waits
+ * for commands on UART1 to read and write memory, jump to code etc.
+ * A design goal for this program is to be entirely independent of the
+ * target board. Anything with a CL-PS7111 or EP7211 should be able to run
+ * this code in bootstrap mode. All the board specifics can be handled on
+ * the host.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/types.h>
+#include <config.h>
+
+#define CS8900_DRIVERNAME "CS8900"
+/* although the registers are 16 bit, they are 32-bit aligned on the
+ EDB7111. so we have to read them as 32-bit registers and ignore the
+ upper 16-bits. i'm not sure if this holds for the EDB7211. */
+
+#ifdef CONFIG_CS8900_BUS16
+ /* 16 bit aligned registers, 16 bit wide */
+ #define CS8900_REG u16
+#elif defined(CONFIG_CS8900_BUS32)
+ /* 32 bit aligned registers, 16 bit wide (we ignore upper 16 bits) */
+ #define CS8900_REG u32
+#else
+ #error unknown bussize ...
+#endif
+
+struct cs8900_regs {
+ CS8900_REG rtdata;
+ CS8900_REG pad0;
+ CS8900_REG txcmd;
+ CS8900_REG txlen;
+ CS8900_REG isq;
+ CS8900_REG pptr;
+ CS8900_REG pdata;
+};
+
+struct cs8900_priv {
+ struct cs8900_regs *regs;
+};
+
+#define ISQ_RxEvent 0x04
+#define ISQ_TxEvent 0x08
+#define ISQ_BufEvent 0x0C
+#define ISQ_RxMissEvent 0x10
+#define ISQ_TxColEvent 0x12
+#define ISQ_EventMask 0x3F
+
+/* packet page register offsets */
+
+/* bus interface registers */
+#define PP_ChipID 0x0000 /* Chip identifier - must be 0x630E */
+#define PP_ChipRev 0x0002 /* Chip revision, model codes */
+
+#define PP_IntReg 0x0022 /* Interrupt configuration */
+#define PP_IntReg_IRQ0 0x0000 /* Use INTR0 pin */
+#define PP_IntReg_IRQ1 0x0001 /* Use INTR1 pin */
+#define PP_IntReg_IRQ2 0x0002 /* Use INTR2 pin */
+#define PP_IntReg_IRQ3 0x0003 /* Use INTR3 pin */
+
+/* status and control registers */
+
+#define PP_RxCFG 0x0102 /* Receiver configuration */
+#define PP_RxCFG_Skip1 0x0040 /* Skip (i.e. discard) current frame */
+#define PP_RxCFG_Stream 0x0080 /* Enable streaming mode */
+#define PP_RxCFG_RxOK 0x0100 /* RxOK interrupt enable */
+#define PP_RxCFG_RxDMAonly 0x0200 /* Use RxDMA for all frames */
+#define PP_RxCFG_AutoRxDMA 0x0400 /* Select RxDMA automatically */
+#define PP_RxCFG_BufferCRC 0x0800 /* Include CRC characters in frame */
+#define PP_RxCFG_CRC 0x1000 /* Enable interrupt on CRC error */
+#define PP_RxCFG_RUNT 0x2000 /* Enable interrupt on RUNT frames */
+#define PP_RxCFG_EXTRA 0x4000 /* Enable interrupt on frames with extra data */
+
+#define PP_RxCTL 0x0104 /* Receiver control */
+#define PP_RxCTL_IAHash 0x0040 /* Accept frames that match hash */
+#define PP_RxCTL_Promiscuous 0x0080 /* Accept any frame */
+#define PP_RxCTL_RxOK 0x0100 /* Accept well formed frames */
+#define PP_RxCTL_Multicast 0x0200 /* Accept multicast frames */
+#define PP_RxCTL_IA 0x0400 /* Accept frame that matches IA */
+#define PP_RxCTL_Broadcast 0x0800 /* Accept broadcast frames */
+#define PP_RxCTL_CRC 0x1000 /* Accept frames with bad CRC */
+#define PP_RxCTL_RUNT 0x2000 /* Accept runt frames */
+#define PP_RxCTL_EXTRA 0x4000 /* Accept frames that are too long */
+
+#define PP_TxCFG 0x0106 /* Transmit configuration */
+#define PP_TxCFG_CRS 0x0040 /* Enable interrupt on loss of carrier */
+#define PP_TxCFG_SQE 0x0080 /* Enable interrupt on Signal Quality Error */
+#define PP_TxCFG_TxOK 0x0100 /* Enable interrupt on successful xmits */
+#define PP_TxCFG_Late 0x0200 /* Enable interrupt on "out of window" */
+#define PP_TxCFG_Jabber 0x0400 /* Enable interrupt on jabber detect */
+#define PP_TxCFG_Collision 0x0800 /* Enable interrupt if collision */
+#define PP_TxCFG_16Collisions 0x8000 /* Enable interrupt if > 16 collisions */
+
+#define PP_TxCmd 0x0108 /* Transmit command status */
+#define PP_TxCmd_TxStart_5 0x0000 /* Start after 5 bytes in buffer */
+#define PP_TxCmd_TxStart_381 0x0040 /* Start after 381 bytes in buffer */
+#define PP_TxCmd_TxStart_1021 0x0080 /* Start after 1021 bytes in buffer */
+#define PP_TxCmd_TxStart_Full 0x00C0 /* Start after all bytes loaded */
+#define PP_TxCmd_Force 0x0100 /* Discard any pending packets */
+#define PP_TxCmd_OneCollision 0x0200 /* Abort after a single collision */
+#define PP_TxCmd_NoCRC 0x1000 /* Do not add CRC */
+#define PP_TxCmd_NoPad 0x2000 /* Do not pad short packets */
+
+#define PP_BufCFG 0x010A /* Buffer configuration */
+#define PP_BufCFG_SWI 0x0040 /* Force interrupt via software */
+#define PP_BufCFG_RxDMA 0x0080 /* Enable interrupt on Rx DMA */
+#define PP_BufCFG_TxRDY 0x0100 /* Enable interrupt when ready for Tx */
+#define PP_BufCFG_TxUE 0x0200 /* Enable interrupt in Tx underrun */
+#define PP_BufCFG_RxMiss 0x0400 /* Enable interrupt on missed Rx packets */
+#define PP_BufCFG_Rx128 0x0800 /* Enable Rx interrupt after 128 bytes */
+#define PP_BufCFG_TxCol 0x1000 /* Enable int on Tx collision ctr overflow */
+#define PP_BufCFG_Miss 0x2000 /* Enable int on Rx miss ctr overflow */
+#define PP_BufCFG_RxDest 0x8000 /* Enable int on Rx dest addr match */
+
+#define PP_LineCTL 0x0112 /* Line control */
+#define PP_LineCTL_Rx 0x0040 /* Enable receiver */
+#define PP_LineCTL_Tx 0x0080 /* Enable transmitter */
+#define PP_LineCTL_AUIonly 0x0100 /* AUI interface only */
+#define PP_LineCTL_AutoAUI10BT 0x0200 /* Autodetect AUI or 10BaseT interface */
+#define PP_LineCTL_ModBackoffE 0x0800 /* Enable modified backoff algorithm */
+#define PP_LineCTL_PolarityDis 0x1000 /* Disable Rx polarity autodetect */
+#define PP_LineCTL_2partDefDis 0x2000 /* Disable two-part defferal */
+#define PP_LineCTL_LoRxSquelch 0x4000 /* Reduce receiver squelch threshold */
+
+#define PP_SelfCTL 0x0114 /* Chip self control */
+#define PP_SelfCTL_Reset 0x0040 /* Self-clearing reset */
+#define PP_SelfCTL_SWSuspend 0x0100 /* Initiate suspend mode */
+#define PP_SelfCTL_HWSleepE 0x0200 /* Enable SLEEP input */
+#define PP_SelfCTL_HWStandbyE 0x0400 /* Enable standby mode */
+#define PP_SelfCTL_HC0E 0x1000 /* use HCB0 for LINK LED */
+#define PP_SelfCTL_HC1E 0x2000 /* use HCB1 for BSTATUS LED */
+#define PP_SelfCTL_HCB0 0x4000 /* control LINK LED if HC0E set */
+#define PP_SelfCTL_HCB1 0x8000 /* control BSTATUS LED if HC1E set */
+
+#define PP_BusCTL 0x0116 /* Bus control */
+#define PP_BusCTL_ResetRxDMA 0x0040 /* Reset RxDMA pointer */
+#define PP_BusCTL_DMAextend 0x0100 /* Extend DMA cycle */
+#define PP_BusCTL_UseSA 0x0200 /* Assert MEMCS16 on address decode */
+#define PP_BusCTL_MemoryE 0x0400 /* Enable memory mode */
+#define PP_BusCTL_DMAburst 0x0800 /* Limit DMA access burst */
+#define PP_BusCTL_IOCHRDYE 0x1000 /* Set IOCHRDY high impedence */
+#define PP_BusCTL_RxDMAsize 0x2000 /* Set DMA buffer size 64KB */
+#define PP_BusCTL_EnableIRQ 0x8000 /* Generate interrupt on interrupt event */
+
+#define PP_TestCTL 0x0118 /* Test control */
+#define PP_TestCTL_DisableLT 0x0080 /* Disable link status */
+#define PP_TestCTL_ENDECloop 0x0200 /* Internal loopback */
+#define PP_TestCTL_AUIloop 0x0400 /* AUI loopback */
+#define PP_TestCTL_DisBackoff 0x0800 /* Disable backoff algorithm */
+#define PP_TestCTL_FDX 0x4000 /* Enable full duplex mode */
+
+#define PP_ISQ 0x0120 /* Interrupt Status Queue */
+
+#define PP_RER 0x0124 /* Receive event */
+#define PP_RER_IAHash 0x0040 /* Frame hash match */
+#define PP_RER_Dribble 0x0080 /* Frame had 1-7 extra bits after last byte */
+#define PP_RER_RxOK 0x0100 /* Frame received with no errors */
+#define PP_RER_Hashed 0x0200 /* Frame address hashed OK */
+#define PP_RER_IA 0x0400 /* Frame address matched IA */
+#define PP_RER_Broadcast 0x0800 /* Broadcast frame */
+#define PP_RER_CRC 0x1000 /* Frame had CRC error */
+#define PP_RER_RUNT 0x2000 /* Runt frame */
+#define PP_RER_EXTRA 0x4000 /* Frame was too long */
+
+#define PP_TER 0x0128 /* Transmit event */
+#define PP_TER_CRS 0x0040 /* Carrier lost */
+#define PP_TER_SQE 0x0080 /* Signal Quality Error */
+#define PP_TER_TxOK 0x0100 /* Packet sent without error */
+#define PP_TER_Late 0x0200 /* Out of window */
+#define PP_TER_Jabber 0x0400 /* Stuck transmit? */
+#define PP_TER_NumCollisions 0x7800 /* Number of collisions */
+#define PP_TER_16Collisions 0x8000 /* > 16 collisions */
+
+#define PP_BER 0x012C /* Buffer event */
+#define PP_BER_SWint 0x0040 /* Software interrupt */
+#define PP_BER_RxDMAFrame 0x0080 /* Received framed DMAed */
+#define PP_BER_Rdy4Tx 0x0100 /* Ready for transmission */
+#define PP_BER_TxUnderrun 0x0200 /* Transmit underrun */
+#define PP_BER_RxMiss 0x0400 /* Received frame missed */
+#define PP_BER_Rx128 0x0800 /* 128 bytes received */
+#define PP_BER_RxDest 0x8000 /* Received framed passed address filter */
+
+#define PP_RxMiss 0x0130 /* Receiver miss counter */
+
+#define PP_TxCol 0x0132 /* Transmit collision counter */
+
+#define PP_LineSTAT 0x0134 /* Line status */
+#define PP_LineSTAT_LinkOK 0x0080 /* Line is connected and working */
+#define PP_LineSTAT_AUI 0x0100 /* Connected via AUI */
+#define PP_LineSTAT_10BT 0x0200 /* Connected via twisted pair */
+#define PP_LineSTAT_Polarity 0x1000 /* Line polarity OK (10BT only) */
+#define PP_LineSTAT_CRS 0x4000 /* Frame being received */
+
+#define PP_SelfSTAT 0x0136 /* Chip self status */
+#define PP_SelfSTAT_33VActive 0x0040 /* supply voltage is 3.3V */
+#define PP_SelfSTAT_InitD 0x0080 /* Chip initialization complete */
+#define PP_SelfSTAT_SIBSY 0x0100 /* EEPROM is busy */
+#define PP_SelfSTAT_EEPROM 0x0200 /* EEPROM present */
+#define PP_SelfSTAT_EEPROM_OK 0x0400 /* EEPROM checks out */
+#define PP_SelfSTAT_ELPresent 0x0800 /* External address latch logic available */
+#define PP_SelfSTAT_EEsize 0x1000 /* Size of EEPROM */
+
+#define PP_BusSTAT 0x0138 /* Bus status */
+#define PP_BusSTAT_TxBid 0x0080 /* Tx error */
+#define PP_BusSTAT_TxRDY 0x0100 /* Ready for Tx data */
+
+#define PP_TDR 0x013C /* AUI Time Domain Reflectometer */
+
+/* initiate transmit registers */
+
+#define PP_TxCommand 0x0144 /* Tx Command */
+#define PP_TxLength 0x0146 /* Tx Length */
+
+
+/* address filter registers */
+
+#define PP_LAF 0x0150 /* Logical address filter (6 bytes) */
+#define PP_IA 0x0158 /* Individual address (MAC) */
+
+/* EEPROM Kram */
+#define SI_BUSY 0x0100
+#define PP_EECMD 0x0040 /* NVR Interface Command register */
+#define PP_EEData 0x0042 /* NVR Interface Data Register */
+#define EEPROM_WRITE_EN 0x00F0
+#define EEPROM_WRITE_DIS 0x0000
+#define EEPROM_WRITE_CMD 0x0100
+#define EEPROM_READ_CMD 0x0200
+#define EEPROM_ERASE_CMD 0x0300
+
+/* Exported functions */
+int cs8900_e2prom_read(struct eth_device *dev, uchar, ushort *);
+int cs8900_e2prom_write(struct eth_device *dev, uchar, ushort);
+
+#endif /* CS8900_H */
diff --git a/qemu/roms/u-boot/drivers/net/davinci_emac.c b/qemu/roms/u-boot/drivers/net/davinci_emac.c
new file mode 100644
index 000000000..439f8ae99
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/davinci_emac.c
@@ -0,0 +1,894 @@
+/*
+ * Ethernet driver for TI TMS320DM644x (DaVinci) chips.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
+ * follows:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.c
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Modifications:
+ * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot.
+ * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors
+ */
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <linux/compiler.h>
+#include <asm/arch/emac_defs.h>
+#include <asm/io.h>
+#include "davinci_emac.h"
+
+unsigned int emac_dbg = 0;
+#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args)
+
+#ifdef EMAC_HW_RAM_ADDR
+static inline unsigned long BD_TO_HW(unsigned long x)
+{
+ if (x == 0)
+ return 0;
+
+ return x - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR;
+}
+
+static inline unsigned long HW_TO_BD(unsigned long x)
+{
+ if (x == 0)
+ return 0;
+
+ return x - EMAC_HW_RAM_ADDR + EMAC_WRAPPER_RAM_ADDR;
+}
+#else
+#define BD_TO_HW(x) (x)
+#define HW_TO_BD(x) (x)
+#endif
+
+#ifdef DAVINCI_EMAC_GIG_ENABLE
+#define emac_gigabit_enable(phy_addr) davinci_eth_gigabit_enable(phy_addr)
+#else
+#define emac_gigabit_enable(phy_addr) /* no gigabit to enable */
+#endif
+
+#if !defined(CONFIG_SYS_EMAC_TI_CLKDIV)
+#define CONFIG_SYS_EMAC_TI_CLKDIV ((EMAC_MDIO_BUS_FREQ / \
+ EMAC_MDIO_CLOCK_FREQ) - 1)
+#endif
+
+static void davinci_eth_mdio_enable(void);
+
+static int gen_init_phy(int phy_addr);
+static int gen_is_phy_connected(int phy_addr);
+static int gen_get_link_speed(int phy_addr);
+static int gen_auto_negotiate(int phy_addr);
+
+void eth_mdio_enable(void)
+{
+ davinci_eth_mdio_enable();
+}
+
+/* EMAC Addresses */
+static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR;
+static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR;
+static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
+
+/* EMAC descriptors */
+static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
+static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
+static volatile emac_desc *emac_rx_active_head = 0;
+static volatile emac_desc *emac_rx_active_tail = 0;
+static int emac_rx_queue_active = 0;
+
+/* Receive packet buffers */
+static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * EMAC_RXBUF_SIZE]
+ __aligned(ARCH_DMA_MINALIGN);
+
+#ifndef CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT
+#define CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT 3
+#endif
+
+/* PHY address for a discovered PHY (0xff - not found) */
+static u_int8_t active_phy_addr[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT];
+
+/* number of PHY found active */
+static u_int8_t num_phy;
+
+phy_t phy[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT];
+
+static inline void davinci_flush_rx_descs(void)
+{
+ /* flush the whole RX descs area */
+ flush_dcache_range(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE,
+ EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
+}
+
+static inline void davinci_invalidate_rx_descs(void)
+{
+ /* invalidate the whole RX descs area */
+ invalidate_dcache_range(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE,
+ EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
+}
+
+static inline void davinci_flush_desc(emac_desc *desc)
+{
+ flush_dcache_range((unsigned long)desc,
+ (unsigned long)desc + sizeof(*desc));
+}
+
+static int davinci_eth_set_mac_addr(struct eth_device *dev)
+{
+ unsigned long mac_hi;
+ unsigned long mac_lo;
+
+ /*
+ * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast
+ * receive)
+ * Using channel 0 only - other channels are disabled
+ * */
+ writel(0, &adap_emac->MACINDEX);
+ mac_hi = (dev->enetaddr[3] << 24) |
+ (dev->enetaddr[2] << 16) |
+ (dev->enetaddr[1] << 8) |
+ (dev->enetaddr[0]);
+ mac_lo = (dev->enetaddr[5] << 8) |
+ (dev->enetaddr[4]);
+
+ writel(mac_hi, &adap_emac->MACADDRHI);
+#if defined(DAVINCI_EMAC_VERSION2)
+ writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH,
+ &adap_emac->MACADDRLO);
+#else
+ writel(mac_lo, &adap_emac->MACADDRLO);
+#endif
+
+ writel(0, &adap_emac->MACHASH1);
+ writel(0, &adap_emac->MACHASH2);
+
+ /* Set source MAC address - REQUIRED */
+ writel(mac_hi, &adap_emac->MACSRCADDRHI);
+ writel(mac_lo, &adap_emac->MACSRCADDRLO);
+
+
+ return 0;
+}
+
+static void davinci_eth_mdio_enable(void)
+{
+ u_int32_t clkdiv;
+
+ clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV;
+
+ writel((clkdiv & 0xff) |
+ MDIO_CONTROL_ENABLE |
+ MDIO_CONTROL_FAULT |
+ MDIO_CONTROL_FAULT_ENABLE,
+ &adap_mdio->CONTROL);
+
+ while (readl(&adap_mdio->CONTROL) & MDIO_CONTROL_IDLE)
+ ;
+}
+
+/*
+ * Tries to find an active connected PHY. Returns 1 if address if found.
+ * If no active PHY (or more than one PHY) found returns 0.
+ * Sets active_phy_addr variable.
+ */
+static int davinci_eth_phy_detect(void)
+{
+ u_int32_t phy_act_state;
+ int i;
+ int j;
+ unsigned int count = 0;
+
+ for (i = 0; i < CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT; i++)
+ active_phy_addr[i] = 0xff;
+
+ udelay(1000);
+ phy_act_state = readl(&adap_mdio->ALIVE);
+
+ if (phy_act_state == 0)
+ return 0; /* No active PHYs */
+
+ debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state);
+
+ for (i = 0, j = 0; i < 32; i++)
+ if (phy_act_state & (1 << i)) {
+ count++;
+ if (count <= CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT) {
+ active_phy_addr[j++] = i;
+ } else {
+ printf("%s: to many PHYs detected.\n",
+ __func__);
+ count = 0;
+ break;
+ }
+ }
+
+ num_phy = count;
+
+ return count;
+}
+
+
+/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
+int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
+{
+ int tmp;
+
+ while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO)
+ ;
+
+ writel(MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_READ |
+ ((reg_num & 0x1f) << 21) |
+ ((phy_addr & 0x1f) << 16),
+ &adap_mdio->USERACCESS0);
+
+ /* Wait for command to complete */
+ while ((tmp = readl(&adap_mdio->USERACCESS0)) & MDIO_USERACCESS0_GO)
+ ;
+
+ if (tmp & MDIO_USERACCESS0_ACK) {
+ *data = tmp & 0xffff;
+ return(1);
+ }
+
+ *data = -1;
+ return(0);
+}
+
+/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
+int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
+{
+
+ while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO)
+ ;
+
+ writel(MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_WRITE |
+ ((reg_num & 0x1f) << 21) |
+ ((phy_addr & 0x1f) << 16) |
+ (data & 0xffff),
+ &adap_mdio->USERACCESS0);
+
+ /* Wait for command to complete */
+ while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO)
+ ;
+
+ return(1);
+}
+
+/* PHY functions for a generic PHY */
+static int gen_init_phy(int phy_addr)
+{
+ int ret = 1;
+
+ if (gen_get_link_speed(phy_addr)) {
+ /* Try another time */
+ ret = gen_get_link_speed(phy_addr);
+ }
+
+ return(ret);
+}
+
+static int gen_is_phy_connected(int phy_addr)
+{
+ u_int16_t dummy;
+
+ return davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy);
+}
+
+static int get_active_phy(void)
+{
+ int i;
+
+ for (i = 0; i < num_phy; i++)
+ if (phy[i].get_link_speed(active_phy_addr[i]))
+ return i;
+
+ return -1; /* Return error if no link */
+}
+
+static int gen_get_link_speed(int phy_addr)
+{
+ u_int16_t tmp;
+
+ if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) &&
+ (tmp & 0x04)) {
+#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
+ defined(CONFIG_MACH_DAVINCI_DA850_EVM)
+ davinci_eth_phy_read(phy_addr, MII_LPA, &tmp);
+
+ /* Speed doesn't matter, there is no setting for it in EMAC. */
+ if (tmp & (LPA_100FULL | LPA_10FULL)) {
+ /* set EMAC for Full Duplex */
+ writel(EMAC_MACCONTROL_MIIEN_ENABLE |
+ EMAC_MACCONTROL_FULLDUPLEX_ENABLE,
+ &adap_emac->MACCONTROL);
+ } else {
+ /*set EMAC for Half Duplex */
+ writel(EMAC_MACCONTROL_MIIEN_ENABLE,
+ &adap_emac->MACCONTROL);
+ }
+
+ if (tmp & (LPA_100FULL | LPA_100HALF))
+ writel(readl(&adap_emac->MACCONTROL) |
+ EMAC_MACCONTROL_RMIISPEED_100,
+ &adap_emac->MACCONTROL);
+ else
+ writel(readl(&adap_emac->MACCONTROL) &
+ ~EMAC_MACCONTROL_RMIISPEED_100,
+ &adap_emac->MACCONTROL);
+#endif
+ return(1);
+ }
+
+ return(0);
+}
+
+static int gen_auto_negotiate(int phy_addr)
+{
+ u_int16_t tmp;
+ u_int16_t val;
+ unsigned long cntr = 0;
+
+ if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp))
+ return 0;
+
+ val = tmp | BMCR_FULLDPLX | BMCR_ANENABLE |
+ BMCR_SPEED100;
+ davinci_eth_phy_write(phy_addr, MII_BMCR, val);
+
+ if (!davinci_eth_phy_read(phy_addr, MII_ADVERTISE, &val))
+ return 0;
+
+ val |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL |
+ ADVERTISE_10HALF);
+ davinci_eth_phy_write(phy_addr, MII_ADVERTISE, val);
+
+ if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp))
+ return(0);
+
+ /* Restart Auto_negotiation */
+ tmp |= BMCR_ANRESTART;
+ davinci_eth_phy_write(phy_addr, MII_BMCR, tmp);
+
+ /*check AutoNegotiate complete */
+ do {
+ udelay(40000);
+ if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp))
+ return 0;
+
+ if (tmp & BMSR_ANEGCOMPLETE)
+ break;
+
+ cntr++;
+ } while (cntr < 200);
+
+ if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp))
+ return(0);
+
+ if (!(tmp & BMSR_ANEGCOMPLETE))
+ return(0);
+
+ return(gen_get_link_speed(phy_addr));
+}
+/* End of generic PHY functions */
+
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static int davinci_mii_phy_read(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value)
+{
+ return(davinci_eth_phy_read(addr, reg, value) ? 0 : 1);
+}
+
+static int davinci_mii_phy_write(const char *devname, unsigned char addr, unsigned char reg, unsigned short value)
+{
+ return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1);
+}
+#endif
+
+static void __attribute__((unused)) davinci_eth_gigabit_enable(int phy_addr)
+{
+ u_int16_t data;
+
+ if (davinci_eth_phy_read(phy_addr, 0, &data)) {
+ if (data & (1 << 6)) { /* speed selection MSB */
+ /*
+ * Check if link detected is giga-bit
+ * If Gigabit mode detected, enable gigbit in MAC
+ */
+ writel(readl(&adap_emac->MACCONTROL) |
+ EMAC_MACCONTROL_GIGFORCE |
+ EMAC_MACCONTROL_GIGABIT_ENABLE,
+ &adap_emac->MACCONTROL);
+ }
+ }
+}
+
+/* Eth device open */
+static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
+{
+ dv_reg_p addr;
+ u_int32_t clkdiv, cnt;
+ volatile emac_desc *rx_desc;
+ int index;
+
+ debug_emac("+ emac_open\n");
+
+ /* Reset EMAC module and disable interrupts in wrapper */
+ writel(1, &adap_emac->SOFTRESET);
+ while (readl(&adap_emac->SOFTRESET) != 0)
+ ;
+#if defined(DAVINCI_EMAC_VERSION2)
+ writel(1, &adap_ewrap->softrst);
+ while (readl(&adap_ewrap->softrst) != 0)
+ ;
+#else
+ writel(0, &adap_ewrap->EWCTL);
+ for (cnt = 0; cnt < 5; cnt++) {
+ clkdiv = readl(&adap_ewrap->EWCTL);
+ }
+#endif
+
+#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
+ defined(CONFIG_MACH_DAVINCI_DA850_EVM)
+ adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0;
+ adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0;
+ adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0;
+#endif
+ rx_desc = emac_rx_desc;
+
+ writel(1, &adap_emac->TXCONTROL);
+ writel(1, &adap_emac->RXCONTROL);
+
+ davinci_eth_set_mac_addr(dev);
+
+ /* Set DMA 8 TX / 8 RX Head pointers to 0 */
+ addr = &adap_emac->TX0HDP;
+ for(cnt = 0; cnt < 16; cnt++)
+ writel(0, addr++);
+
+ addr = &adap_emac->RX0HDP;
+ for(cnt = 0; cnt < 16; cnt++)
+ writel(0, addr++);
+
+ /* Clear Statistics (do this before setting MacControl register) */
+ addr = &adap_emac->RXGOODFRAMES;
+ for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
+ writel(0, addr++);
+
+ /* No multicast addressing */
+ writel(0, &adap_emac->MACHASH1);
+ writel(0, &adap_emac->MACHASH2);
+
+ /* Create RX queue and set receive process in place */
+ emac_rx_active_head = emac_rx_desc;
+ for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
+ rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1));
+ rx_desc->buffer = &emac_rx_buffers[cnt * EMAC_RXBUF_SIZE];
+ rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
+ rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
+ rx_desc++;
+ }
+
+ /* Finalize the rx desc list */
+ rx_desc--;
+ rx_desc->next = 0;
+ emac_rx_active_tail = rx_desc;
+ emac_rx_queue_active = 1;
+
+ davinci_flush_rx_descs();
+
+ /* Enable TX/RX */
+ writel(EMAC_MAX_ETHERNET_PKT_SIZE, &adap_emac->RXMAXLEN);
+ writel(0, &adap_emac->RXBUFFEROFFSET);
+
+ /*
+ * No fancy configs - Use this for promiscous debug
+ * - EMAC_RXMBPENABLE_RXCAFEN_ENABLE
+ */
+ writel(EMAC_RXMBPENABLE_RXBROADEN, &adap_emac->RXMBPENABLE);
+
+ /* Enable ch 0 only */
+ writel(1, &adap_emac->RXUNICASTSET);
+
+ /* Enable MII interface and Full duplex mode */
+#if defined(CONFIG_SOC_DA8XX) || \
+ (defined(CONFIG_OMAP34XX) && defined(CONFIG_DRIVER_TI_EMAC_USE_RMII))
+ writel((EMAC_MACCONTROL_MIIEN_ENABLE |
+ EMAC_MACCONTROL_FULLDUPLEX_ENABLE |
+ EMAC_MACCONTROL_RMIISPEED_100),
+ &adap_emac->MACCONTROL);
+#else
+ writel((EMAC_MACCONTROL_MIIEN_ENABLE |
+ EMAC_MACCONTROL_FULLDUPLEX_ENABLE),
+ &adap_emac->MACCONTROL);
+#endif
+
+ /* Init MDIO & get link state */
+ clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV;
+ writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
+ &adap_mdio->CONTROL);
+
+ /* We need to wait for MDIO to start */
+ udelay(1000);
+
+ index = get_active_phy();
+ if (index == -1)
+ return(0);
+
+ emac_gigabit_enable(active_phy_addr[index]);
+
+ /* Start receive process */
+ writel(BD_TO_HW((u_int32_t)emac_rx_desc), &adap_emac->RX0HDP);
+
+ debug_emac("- emac_open\n");
+
+ return(1);
+}
+
+/* EMAC Channel Teardown */
+static void davinci_eth_ch_teardown(int ch)
+{
+ dv_reg dly = 0xff;
+ dv_reg cnt;
+
+ debug_emac("+ emac_ch_teardown\n");
+
+ if (ch == EMAC_CH_TX) {
+ /* Init TX channel teardown */
+ writel(0, &adap_emac->TXTEARDOWN);
+ do {
+ /*
+ * Wait here for Tx teardown completion interrupt to
+ * occur. Note: A task delay can be called here to pend
+ * rather than occupying CPU cycles - anyway it has
+ * been found that teardown takes very few cpu cycles
+ * and does not affect functionality
+ */
+ dly--;
+ udelay(1);
+ if (dly == 0)
+ break;
+ cnt = readl(&adap_emac->TX0CP);
+ } while (cnt != 0xfffffffc);
+ writel(cnt, &adap_emac->TX0CP);
+ writel(0, &adap_emac->TX0HDP);
+ } else {
+ /* Init RX channel teardown */
+ writel(0, &adap_emac->RXTEARDOWN);
+ do {
+ /*
+ * Wait here for Rx teardown completion interrupt to
+ * occur. Note: A task delay can be called here to pend
+ * rather than occupying CPU cycles - anyway it has
+ * been found that teardown takes very few cpu cycles
+ * and does not affect functionality
+ */
+ dly--;
+ udelay(1);
+ if (dly == 0)
+ break;
+ cnt = readl(&adap_emac->RX0CP);
+ } while (cnt != 0xfffffffc);
+ writel(cnt, &adap_emac->RX0CP);
+ writel(0, &adap_emac->RX0HDP);
+ }
+
+ debug_emac("- emac_ch_teardown\n");
+}
+
+/* Eth device close */
+static void davinci_eth_close(struct eth_device *dev)
+{
+ debug_emac("+ emac_close\n");
+
+ davinci_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */
+ davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */
+
+ /* Reset EMAC module and disable interrupts in wrapper */
+ writel(1, &adap_emac->SOFTRESET);
+#if defined(DAVINCI_EMAC_VERSION2)
+ writel(1, &adap_ewrap->softrst);
+#else
+ writel(0, &adap_ewrap->EWCTL);
+#endif
+
+#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
+ defined(CONFIG_MACH_DAVINCI_DA850_EVM)
+ adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0;
+ adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0;
+ adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0;
+#endif
+ debug_emac("- emac_close\n");
+}
+
+static int tx_send_loop = 0;
+
+/*
+ * This function sends a single packet on the network and returns
+ * positive number (number of bytes transmitted) or negative for error
+ */
+static int davinci_eth_send_packet (struct eth_device *dev,
+ void *packet, int length)
+{
+ int ret_status = -1;
+ int index;
+ tx_send_loop = 0;
+
+ index = get_active_phy();
+ if (index == -1) {
+ printf(" WARN: emac_send_packet: No link\n");
+ return (ret_status);
+ }
+
+ emac_gigabit_enable(active_phy_addr[index]);
+
+ /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
+ if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
+ length = EMAC_MIN_ETHERNET_PKT_SIZE;
+ }
+
+ /* Populate the TX descriptor */
+ emac_tx_desc->next = 0;
+ emac_tx_desc->buffer = (u_int8_t *) packet;
+ emac_tx_desc->buff_off_len = (length & 0xffff);
+ emac_tx_desc->pkt_flag_len = ((length & 0xffff) |
+ EMAC_CPPI_SOP_BIT |
+ EMAC_CPPI_OWNERSHIP_BIT |
+ EMAC_CPPI_EOP_BIT);
+
+ flush_dcache_range((unsigned long)packet,
+ (unsigned long)packet + length);
+ davinci_flush_desc(emac_tx_desc);
+
+ /* Send the packet */
+ writel(BD_TO_HW((unsigned long)emac_tx_desc), &adap_emac->TX0HDP);
+
+ /* Wait for packet to complete or link down */
+ while (1) {
+ if (!phy[index].get_link_speed(active_phy_addr[index])) {
+ davinci_eth_ch_teardown (EMAC_CH_TX);
+ return (ret_status);
+ }
+
+ emac_gigabit_enable(active_phy_addr[index]);
+
+ if (readl(&adap_emac->TXINTSTATRAW) & 0x01) {
+ ret_status = length;
+ break;
+ }
+ tx_send_loop++;
+ }
+
+ return (ret_status);
+}
+
+/*
+ * This function handles receipt of a packet from the network
+ */
+static int davinci_eth_rcv_packet (struct eth_device *dev)
+{
+ volatile emac_desc *rx_curr_desc;
+ volatile emac_desc *curr_desc;
+ volatile emac_desc *tail_desc;
+ int status, ret = -1;
+
+ davinci_invalidate_rx_descs();
+
+ rx_curr_desc = emac_rx_active_head;
+ status = rx_curr_desc->pkt_flag_len;
+ if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
+ if (status & EMAC_CPPI_RX_ERROR_FRAME) {
+ /* Error in packet - discard it and requeue desc */
+ printf ("WARN: emac_rcv_pkt: Error in packet\n");
+ } else {
+ unsigned long tmp = (unsigned long)rx_curr_desc->buffer;
+
+ invalidate_dcache_range(tmp, tmp + EMAC_RXBUF_SIZE);
+ NetReceive (rx_curr_desc->buffer,
+ (rx_curr_desc->buff_off_len & 0xffff));
+ ret = rx_curr_desc->buff_off_len & 0xffff;
+ }
+
+ /* Ack received packet descriptor */
+ writel(BD_TO_HW((ulong)rx_curr_desc), &adap_emac->RX0CP);
+ curr_desc = rx_curr_desc;
+ emac_rx_active_head =
+ (volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next));
+
+ if (status & EMAC_CPPI_EOQ_BIT) {
+ if (emac_rx_active_head) {
+ writel(BD_TO_HW((ulong)emac_rx_active_head),
+ &adap_emac->RX0HDP);
+ } else {
+ emac_rx_queue_active = 0;
+ printf ("INFO:emac_rcv_packet: RX Queue not active\n");
+ }
+ }
+
+ /* Recycle RX descriptor */
+ rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
+ rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
+ rx_curr_desc->next = 0;
+ davinci_flush_desc(rx_curr_desc);
+
+ if (emac_rx_active_head == 0) {
+ printf ("INFO: emac_rcv_pkt: active queue head = 0\n");
+ emac_rx_active_head = curr_desc;
+ emac_rx_active_tail = curr_desc;
+ if (emac_rx_queue_active != 0) {
+ writel(BD_TO_HW((ulong)emac_rx_active_head),
+ &adap_emac->RX0HDP);
+ printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
+ emac_rx_queue_active = 1;
+ }
+ } else {
+ tail_desc = emac_rx_active_tail;
+ emac_rx_active_tail = curr_desc;
+ tail_desc->next = BD_TO_HW((ulong) curr_desc);
+ status = tail_desc->pkt_flag_len;
+ if (status & EMAC_CPPI_EOQ_BIT) {
+ davinci_flush_desc(tail_desc);
+ writel(BD_TO_HW((ulong)curr_desc),
+ &adap_emac->RX0HDP);
+ status &= ~EMAC_CPPI_EOQ_BIT;
+ tail_desc->pkt_flag_len = status;
+ }
+ davinci_flush_desc(tail_desc);
+ }
+ return (ret);
+ }
+ return (0);
+}
+
+/*
+ * This function initializes the emac hardware. It does NOT initialize
+ * EMAC modules power or pin multiplexors, that is done by board_init()
+ * much earlier in bootup process. Returns 1 on success, 0 otherwise.
+ */
+int davinci_emac_initialize(void)
+{
+ u_int32_t phy_id;
+ u_int16_t tmp;
+ int i;
+ int ret;
+ struct eth_device *dev;
+
+ dev = malloc(sizeof *dev);
+
+ if (dev == NULL)
+ return -1;
+
+ memset(dev, 0, sizeof *dev);
+ sprintf(dev->name, "DaVinci-EMAC");
+
+ dev->iobase = 0;
+ dev->init = davinci_eth_open;
+ dev->halt = davinci_eth_close;
+ dev->send = davinci_eth_send_packet;
+ dev->recv = davinci_eth_rcv_packet;
+ dev->write_hwaddr = davinci_eth_set_mac_addr;
+
+ eth_register(dev);
+
+ davinci_eth_mdio_enable();
+
+ /* let the EMAC detect the PHYs */
+ udelay(5000);
+
+ for (i = 0; i < 256; i++) {
+ if (readl(&adap_mdio->ALIVE))
+ break;
+ udelay(1000);
+ }
+
+ if (i >= 256) {
+ printf("No ETH PHY detected!!!\n");
+ return(0);
+ }
+
+ /* Find if PHY(s) is/are connected */
+ ret = davinci_eth_phy_detect();
+ if (!ret)
+ return(0);
+ else
+ debug_emac(" %d ETH PHY detected\n", ret);
+
+ /* Get PHY ID and initialize phy_ops for a detected PHY */
+ for (i = 0; i < num_phy; i++) {
+ if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID1,
+ &tmp)) {
+ active_phy_addr[i] = 0xff;
+ continue;
+ }
+
+ phy_id = (tmp << 16) & 0xffff0000;
+
+ if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID2,
+ &tmp)) {
+ active_phy_addr[i] = 0xff;
+ continue;
+ }
+
+ phy_id |= tmp & 0x0000ffff;
+
+ switch (phy_id) {
+#ifdef PHY_KSZ8873
+ case PHY_KSZ8873:
+ sprintf(phy[i].name, "KSZ8873 @ 0x%02x",
+ active_phy_addr[i]);
+ phy[i].init = ksz8873_init_phy;
+ phy[i].is_phy_connected = ksz8873_is_phy_connected;
+ phy[i].get_link_speed = ksz8873_get_link_speed;
+ phy[i].auto_negotiate = ksz8873_auto_negotiate;
+ break;
+#endif
+#ifdef PHY_LXT972
+ case PHY_LXT972:
+ sprintf(phy[i].name, "LXT972 @ 0x%02x",
+ active_phy_addr[i]);
+ phy[i].init = lxt972_init_phy;
+ phy[i].is_phy_connected = lxt972_is_phy_connected;
+ phy[i].get_link_speed = lxt972_get_link_speed;
+ phy[i].auto_negotiate = lxt972_auto_negotiate;
+ break;
+#endif
+#ifdef PHY_DP83848
+ case PHY_DP83848:
+ sprintf(phy[i].name, "DP83848 @ 0x%02x",
+ active_phy_addr[i]);
+ phy[i].init = dp83848_init_phy;
+ phy[i].is_phy_connected = dp83848_is_phy_connected;
+ phy[i].get_link_speed = dp83848_get_link_speed;
+ phy[i].auto_negotiate = dp83848_auto_negotiate;
+ break;
+#endif
+#ifdef PHY_ET1011C
+ case PHY_ET1011C:
+ sprintf(phy[i].name, "ET1011C @ 0x%02x",
+ active_phy_addr[i]);
+ phy[i].init = gen_init_phy;
+ phy[i].is_phy_connected = gen_is_phy_connected;
+ phy[i].get_link_speed = et1011c_get_link_speed;
+ phy[i].auto_negotiate = gen_auto_negotiate;
+ break;
+#endif
+ default:
+ sprintf(phy[i].name, "GENERIC @ 0x%02x",
+ active_phy_addr[i]);
+ phy[i].init = gen_init_phy;
+ phy[i].is_phy_connected = gen_is_phy_connected;
+ phy[i].get_link_speed = gen_get_link_speed;
+ phy[i].auto_negotiate = gen_auto_negotiate;
+ }
+
+ debug("Ethernet PHY: %s\n", phy[i].name);
+
+ miiphy_register(phy[i].name, davinci_mii_phy_read,
+ davinci_mii_phy_write);
+ }
+
+#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
+ defined(CONFIG_MACH_DAVINCI_DA850_EVM) && \
+ !defined(CONFIG_DRIVER_TI_EMAC_RMII_NO_NEGOTIATE)
+ for (i = 0; i < num_phy; i++) {
+ if (phy[i].is_phy_connected(i))
+ phy[i].auto_negotiate(i);
+ }
+#endif
+ return(1);
+}
diff --git a/qemu/roms/u-boot/drivers/net/davinci_emac.h b/qemu/roms/u-boot/drivers/net/davinci_emac.h
new file mode 100644
index 000000000..13cd68f04
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/davinci_emac.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2011 Ilya Yanok, Emcraft Systems
+ *
+ * Based on: mach-davinci/emac_defs.h
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DAVINCI_EMAC_H_
+#define _DAVINCI_EMAC_H_
+/* Ethernet Min/Max packet size */
+#define EMAC_MIN_ETHERNET_PKT_SIZE 60
+#define EMAC_MAX_ETHERNET_PKT_SIZE 1518
+/* Buffer size (should be aligned on 32 byte and cache line) */
+#define EMAC_RXBUF_SIZE ALIGN(ALIGN(EMAC_MAX_ETHERNET_PKT_SIZE, 32),\
+ ARCH_DMA_MINALIGN)
+
+/* Number of RX packet buffers
+ * NOTE: Only 1 buffer supported as of now
+ */
+#define EMAC_MAX_RX_BUFFERS 10
+
+
+/***********************************************
+ ******** Internally used macros ***************
+ ***********************************************/
+
+#define EMAC_CH_TX 1
+#define EMAC_CH_RX 0
+
+/* Each descriptor occupies 4 words, lets start RX desc's at 0 and
+ * reserve space for 64 descriptors max
+ */
+#define EMAC_RX_DESC_BASE 0x0
+#define EMAC_TX_DESC_BASE 0x1000
+
+/* EMAC Teardown value */
+#define EMAC_TEARDOWN_VALUE 0xfffffffc
+
+/* MII Status Register */
+#define MII_STATUS_REG 1
+
+/* Number of statistics registers */
+#define EMAC_NUM_STATS 36
+
+
+/* EMAC Descriptor */
+typedef volatile struct _emac_desc
+{
+ u_int32_t next; /* Pointer to next descriptor
+ in chain */
+ u_int8_t *buffer; /* Pointer to data buffer */
+ u_int32_t buff_off_len; /* Buffer Offset(MSW) and Length(LSW) */
+ u_int32_t pkt_flag_len; /* Packet Flags(MSW) and Length(LSW) */
+} emac_desc;
+
+/* CPPI bit positions */
+#define EMAC_CPPI_SOP_BIT (0x80000000)
+#define EMAC_CPPI_EOP_BIT (0x40000000)
+#define EMAC_CPPI_OWNERSHIP_BIT (0x20000000)
+#define EMAC_CPPI_EOQ_BIT (0x10000000)
+#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (0x08000000)
+#define EMAC_CPPI_PASS_CRC_BIT (0x04000000)
+
+#define EMAC_CPPI_RX_ERROR_FRAME (0x03fc0000)
+
+#define EMAC_MACCONTROL_MIIEN_ENABLE (0x20)
+#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1)
+#define EMAC_MACCONTROL_GIGABIT_ENABLE (1 << 7)
+#define EMAC_MACCONTROL_GIGFORCE (1 << 17)
+#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15)
+
+#define EMAC_MAC_ADDR_MATCH (1 << 19)
+#define EMAC_MAC_ADDR_IS_VALID (1 << 20)
+
+#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000)
+#define EMAC_RXMBPENABLE_RXBROADEN (0x2000)
+
+
+#define MDIO_CONTROL_IDLE (0x80000000)
+#define MDIO_CONTROL_ENABLE (0x40000000)
+#define MDIO_CONTROL_FAULT_ENABLE (0x40000)
+#define MDIO_CONTROL_FAULT (0x80000)
+#define MDIO_USERACCESS0_GO (0x80000000)
+#define MDIO_USERACCESS0_WRITE_READ (0x0)
+#define MDIO_USERACCESS0_WRITE_WRITE (0x40000000)
+#define MDIO_USERACCESS0_ACK (0x20000000)
+
+/* Ethernet MAC Registers Structure */
+typedef struct {
+ dv_reg TXIDVER;
+ dv_reg TXCONTROL;
+ dv_reg TXTEARDOWN;
+ u_int8_t RSVD0[4];
+ dv_reg RXIDVER;
+ dv_reg RXCONTROL;
+ dv_reg RXTEARDOWN;
+ u_int8_t RSVD1[100];
+ dv_reg TXINTSTATRAW;
+ dv_reg TXINTSTATMASKED;
+ dv_reg TXINTMASKSET;
+ dv_reg TXINTMASKCLEAR;
+ dv_reg MACINVECTOR;
+ u_int8_t RSVD2[12];
+ dv_reg RXINTSTATRAW;
+ dv_reg RXINTSTATMASKED;
+ dv_reg RXINTMASKSET;
+ dv_reg RXINTMASKCLEAR;
+ dv_reg MACINTSTATRAW;
+ dv_reg MACINTSTATMASKED;
+ dv_reg MACINTMASKSET;
+ dv_reg MACINTMASKCLEAR;
+ u_int8_t RSVD3[64];
+ dv_reg RXMBPENABLE;
+ dv_reg RXUNICASTSET;
+ dv_reg RXUNICASTCLEAR;
+ dv_reg RXMAXLEN;
+ dv_reg RXBUFFEROFFSET;
+ dv_reg RXFILTERLOWTHRESH;
+ u_int8_t RSVD4[8];
+ dv_reg RX0FLOWTHRESH;
+ dv_reg RX1FLOWTHRESH;
+ dv_reg RX2FLOWTHRESH;
+ dv_reg RX3FLOWTHRESH;
+ dv_reg RX4FLOWTHRESH;
+ dv_reg RX5FLOWTHRESH;
+ dv_reg RX6FLOWTHRESH;
+ dv_reg RX7FLOWTHRESH;
+ dv_reg RX0FREEBUFFER;
+ dv_reg RX1FREEBUFFER;
+ dv_reg RX2FREEBUFFER;
+ dv_reg RX3FREEBUFFER;
+ dv_reg RX4FREEBUFFER;
+ dv_reg RX5FREEBUFFER;
+ dv_reg RX6FREEBUFFER;
+ dv_reg RX7FREEBUFFER;
+ dv_reg MACCONTROL;
+ dv_reg MACSTATUS;
+ dv_reg EMCONTROL;
+ dv_reg FIFOCONTROL;
+ dv_reg MACCONFIG;
+ dv_reg SOFTRESET;
+ u_int8_t RSVD5[88];
+ dv_reg MACSRCADDRLO;
+ dv_reg MACSRCADDRHI;
+ dv_reg MACHASH1;
+ dv_reg MACHASH2;
+ dv_reg BOFFTEST;
+ dv_reg TPACETEST;
+ dv_reg RXPAUSE;
+ dv_reg TXPAUSE;
+ u_int8_t RSVD6[16];
+ dv_reg RXGOODFRAMES;
+ dv_reg RXBCASTFRAMES;
+ dv_reg RXMCASTFRAMES;
+ dv_reg RXPAUSEFRAMES;
+ dv_reg RXCRCERRORS;
+ dv_reg RXALIGNCODEERRORS;
+ dv_reg RXOVERSIZED;
+ dv_reg RXJABBER;
+ dv_reg RXUNDERSIZED;
+ dv_reg RXFRAGMENTS;
+ dv_reg RXFILTERED;
+ dv_reg RXQOSFILTERED;
+ dv_reg RXOCTETS;
+ dv_reg TXGOODFRAMES;
+ dv_reg TXBCASTFRAMES;
+ dv_reg TXMCASTFRAMES;
+ dv_reg TXPAUSEFRAMES;
+ dv_reg TXDEFERRED;
+ dv_reg TXCOLLISION;
+ dv_reg TXSINGLECOLL;
+ dv_reg TXMULTICOLL;
+ dv_reg TXEXCESSIVECOLL;
+ dv_reg TXLATECOLL;
+ dv_reg TXUNDERRUN;
+ dv_reg TXCARRIERSENSE;
+ dv_reg TXOCTETS;
+ dv_reg FRAME64;
+ dv_reg FRAME65T127;
+ dv_reg FRAME128T255;
+ dv_reg FRAME256T511;
+ dv_reg FRAME512T1023;
+ dv_reg FRAME1024TUP;
+ dv_reg NETOCTETS;
+ dv_reg RXSOFOVERRUNS;
+ dv_reg RXMOFOVERRUNS;
+ dv_reg RXDMAOVERRUNS;
+ u_int8_t RSVD7[624];
+ dv_reg MACADDRLO;
+ dv_reg MACADDRHI;
+ dv_reg MACINDEX;
+ u_int8_t RSVD8[244];
+ dv_reg TX0HDP;
+ dv_reg TX1HDP;
+ dv_reg TX2HDP;
+ dv_reg TX3HDP;
+ dv_reg TX4HDP;
+ dv_reg TX5HDP;
+ dv_reg TX6HDP;
+ dv_reg TX7HDP;
+ dv_reg RX0HDP;
+ dv_reg RX1HDP;
+ dv_reg RX2HDP;
+ dv_reg RX3HDP;
+ dv_reg RX4HDP;
+ dv_reg RX5HDP;
+ dv_reg RX6HDP;
+ dv_reg RX7HDP;
+ dv_reg TX0CP;
+ dv_reg TX1CP;
+ dv_reg TX2CP;
+ dv_reg TX3CP;
+ dv_reg TX4CP;
+ dv_reg TX5CP;
+ dv_reg TX6CP;
+ dv_reg TX7CP;
+ dv_reg RX0CP;
+ dv_reg RX1CP;
+ dv_reg RX2CP;
+ dv_reg RX3CP;
+ dv_reg RX4CP;
+ dv_reg RX5CP;
+ dv_reg RX6CP;
+ dv_reg RX7CP;
+} emac_regs;
+
+/* EMAC Wrapper Registers Structure */
+typedef struct {
+#ifdef DAVINCI_EMAC_VERSION2
+ dv_reg idver;
+ dv_reg softrst;
+ dv_reg emctrl;
+ dv_reg c0rxthreshen;
+ dv_reg c0rxen;
+ dv_reg c0txen;
+ dv_reg c0miscen;
+ dv_reg c1rxthreshen;
+ dv_reg c1rxen;
+ dv_reg c1txen;
+ dv_reg c1miscen;
+ dv_reg c2rxthreshen;
+ dv_reg c2rxen;
+ dv_reg c2txen;
+ dv_reg c2miscen;
+ dv_reg c0rxthreshstat;
+ dv_reg c0rxstat;
+ dv_reg c0txstat;
+ dv_reg c0miscstat;
+ dv_reg c1rxthreshstat;
+ dv_reg c1rxstat;
+ dv_reg c1txstat;
+ dv_reg c1miscstat;
+ dv_reg c2rxthreshstat;
+ dv_reg c2rxstat;
+ dv_reg c2txstat;
+ dv_reg c2miscstat;
+ dv_reg c0rximax;
+ dv_reg c0tximax;
+ dv_reg c1rximax;
+ dv_reg c1tximax;
+ dv_reg c2rximax;
+ dv_reg c2tximax;
+#else
+ u_int8_t RSVD0[4100];
+ dv_reg EWCTL;
+ dv_reg EWINTTCNT;
+#endif
+} ewrap_regs;
+
+/* EMAC MDIO Registers Structure */
+typedef struct {
+ dv_reg VERSION;
+ dv_reg CONTROL;
+ dv_reg ALIVE;
+ dv_reg LINK;
+ dv_reg LINKINTRAW;
+ dv_reg LINKINTMASKED;
+ u_int8_t RSVD0[8];
+ dv_reg USERINTRAW;
+ dv_reg USERINTMASKED;
+ dv_reg USERINTMASKSET;
+ dv_reg USERINTMASKCLEAR;
+ u_int8_t RSVD1[80];
+ dv_reg USERACCESS0;
+ dv_reg USERPHYSEL0;
+ dv_reg USERACCESS1;
+ dv_reg USERPHYSEL1;
+} mdio_regs;
+
+int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data);
+int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data);
+
+typedef struct {
+ char name[64];
+ int (*init)(int phy_addr);
+ int (*is_phy_connected)(int phy_addr);
+ int (*get_link_speed)(int phy_addr);
+ int (*auto_negotiate)(int phy_addr);
+} phy_t;
+
+#endif /* _DAVINCI_EMAC_H_ */
diff --git a/qemu/roms/u-boot/drivers/net/dc2114x.c b/qemu/roms/u-boot/drivers/net/dc2114x.c
new file mode 100644
index 000000000..799839c4f
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/dc2114x.c
@@ -0,0 +1,760 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <pci.h>
+
+#undef DEBUG_SROM
+#undef DEBUG_SROM2
+
+#undef UPDATE_SROM
+
+/* PCI Registers.
+ */
+#define PCI_CFDA_PSM 0x43
+
+#define CFRV_RN 0x000000f0 /* Revision Number */
+
+#define WAKEUP 0x00 /* Power Saving Wakeup */
+#define SLEEP 0x80 /* Power Saving Sleep Mode */
+
+#define DC2114x_BRK 0x0020 /* CFRV break between DC21142 & DC21143 */
+
+/* Ethernet chip registers.
+ */
+#define DE4X5_BMR 0x000 /* Bus Mode Register */
+#define DE4X5_TPD 0x008 /* Transmit Poll Demand Reg */
+#define DE4X5_RRBA 0x018 /* RX Ring Base Address Reg */
+#define DE4X5_TRBA 0x020 /* TX Ring Base Address Reg */
+#define DE4X5_STS 0x028 /* Status Register */
+#define DE4X5_OMR 0x030 /* Operation Mode Register */
+#define DE4X5_SICR 0x068 /* SIA Connectivity Register */
+#define DE4X5_APROM 0x048 /* Ethernet Address PROM */
+
+/* Register bits.
+ */
+#define BMR_SWR 0x00000001 /* Software Reset */
+#define STS_TS 0x00700000 /* Transmit Process State */
+#define STS_RS 0x000e0000 /* Receive Process State */
+#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */
+#define OMR_SR 0x00000002 /* Start/Stop Receive */
+#define OMR_PS 0x00040000 /* Port Select */
+#define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */
+#define OMR_PM 0x00000080 /* Pass All Multicast */
+
+/* Descriptor bits.
+ */
+#define R_OWN 0x80000000 /* Own Bit */
+#define RD_RER 0x02000000 /* Receive End Of Ring */
+#define RD_LS 0x00000100 /* Last Descriptor */
+#define RD_ES 0x00008000 /* Error Summary */
+#define TD_TER 0x02000000 /* Transmit End Of Ring */
+#define T_OWN 0x80000000 /* Own Bit */
+#define TD_LS 0x40000000 /* Last Segment */
+#define TD_FS 0x20000000 /* First Segment */
+#define TD_ES 0x00008000 /* Error Summary */
+#define TD_SET 0x08000000 /* Setup Packet */
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define SROM_WRITE_CMD 5
+#define SROM_READ_CMD 6
+#define SROM_ERASE_CMD 7
+
+#define SROM_HWADD 0x0014 /* Hardware Address offset in SROM */
+#define SROM_RD 0x00004000 /* Read from Boot ROM */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x4801
+#define EE_WRITE_1 0x4805
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define SROM_SR 0x00000800 /* Select Serial ROM when set */
+
+#define DT_IN 0x00000004 /* Serial Data In */
+#define DT_CLK 0x00000002 /* Serial ROM Clock */
+#define DT_CS 0x00000001 /* Serial ROM Chip Select */
+
+#define POLL_DEMAND 1
+
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+#define RESET_DM9102(dev) {\
+ unsigned long i;\
+ i=INL(dev, 0x0);\
+ udelay(1000);\
+ OUTL(dev, i | BMR_SWR, DE4X5_BMR);\
+ udelay(1000);\
+}
+#else
+#define RESET_DE4X5(dev) {\
+ int i;\
+ i=INL(dev, DE4X5_BMR);\
+ udelay(1000);\
+ OUTL(dev, i | BMR_SWR, DE4X5_BMR);\
+ udelay(1000);\
+ OUTL(dev, i, DE4X5_BMR);\
+ udelay(1000);\
+ for (i=0;i<5;i++) {INL(dev, DE4X5_BMR); udelay(10000);}\
+ udelay(1000);\
+}
+#endif
+
+#define START_DE4X5(dev) {\
+ s32 omr; \
+ omr = INL(dev, DE4X5_OMR);\
+ omr |= OMR_ST | OMR_SR;\
+ OUTL(dev, omr, DE4X5_OMR); /* Enable the TX and/or RX */\
+}
+
+#define STOP_DE4X5(dev) {\
+ s32 omr; \
+ omr = INL(dev, DE4X5_OMR);\
+ omr &= ~(OMR_ST|OMR_SR);\
+ OUTL(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */ \
+}
+
+#define NUM_RX_DESC PKTBUFSRX
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+ #define NUM_TX_DESC 1 /* Number of TX descriptors */
+#else
+ #define NUM_TX_DESC 4
+#endif
+#define RX_BUFF_SZ PKTSIZE_ALIGN
+
+#define TOUT_LOOP 1000000
+
+#define SETUP_FRAME_LEN 192
+#define ETH_ALEN 6
+
+struct de4x5_desc {
+ volatile s32 status;
+ u32 des1;
+ u32 buf;
+ u32 next;
+};
+
+static struct de4x5_desc rx_ring[NUM_RX_DESC] __attribute__ ((aligned(32))); /* RX descriptor ring */
+static struct de4x5_desc tx_ring[NUM_TX_DESC] __attribute__ ((aligned(32))); /* TX descriptor ring */
+static int rx_new; /* RX descriptor ring pointer */
+static int tx_new; /* TX descriptor ring pointer */
+
+static char rxRingSize;
+static char txRingSize;
+
+#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
+static void sendto_srom(struct eth_device* dev, u_int command, u_long addr);
+static int getfrom_srom(struct eth_device* dev, u_long addr);
+static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr,int cmd,int cmd_len);
+static int do_read_eeprom(struct eth_device *dev,u_long ioaddr,int location,int addr_len);
+#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
+#ifdef UPDATE_SROM
+static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_value);
+static void update_srom(struct eth_device *dev, bd_t *bis);
+#endif
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+static int read_srom(struct eth_device *dev, u_long ioaddr, int index);
+static void read_hw_addr(struct eth_device* dev, bd_t * bis);
+#endif /* CONFIG_TULIP_FIX_DAVICOM */
+static void send_setup_frame(struct eth_device* dev, bd_t * bis);
+
+static int dc21x4x_init(struct eth_device* dev, bd_t* bis);
+static int dc21x4x_send(struct eth_device *dev, void *packet, int length);
+static int dc21x4x_recv(struct eth_device* dev);
+static void dc21x4x_halt(struct eth_device* dev);
+#ifdef CONFIG_TULIP_SELECT_MEDIA
+extern void dc21x4x_select_media(struct eth_device* dev);
+#endif
+
+#if defined(CONFIG_E500)
+#define phys_to_bus(a) (a)
+#else
+#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
+#endif
+
+static int INL(struct eth_device* dev, u_long addr)
+{
+ return le32_to_cpu(*(volatile u_long *)(addr + dev->iobase));
+}
+
+static void OUTL(struct eth_device* dev, int command, u_long addr)
+{
+ *(volatile u_long *)(addr + dev->iobase) = cpu_to_le32(command);
+}
+
+static struct pci_device_id supported[] = {
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST },
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142 },
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+ { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DAVICOM_DM9102A },
+#endif
+ { }
+};
+
+int dc21x4x_initialize(bd_t *bis)
+{
+ int idx=0;
+ int card_number = 0;
+ unsigned int cfrv;
+ unsigned char timer;
+ pci_dev_t devbusfn;
+ unsigned int iobase;
+ unsigned short status;
+ struct eth_device* dev;
+
+ while(1) {
+ devbusfn = pci_find_devices(supported, idx++);
+ if (devbusfn == -1) {
+ break;
+ }
+
+ /* Get the chip configuration revision register. */
+ pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv);
+
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+ if ((cfrv & CFRV_RN) < DC2114x_BRK ) {
+ printf("Error: The chip is not DC21143.\n");
+ continue;
+ }
+#endif
+
+ pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+ status |=
+#ifdef CONFIG_TULIP_USE_IO
+ PCI_COMMAND_IO |
+#else
+ PCI_COMMAND_MEMORY |
+#endif
+ PCI_COMMAND_MASTER;
+ pci_write_config_word(devbusfn, PCI_COMMAND, status);
+
+ pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+#ifdef CONFIG_TULIP_USE_IO
+ if (!(status & PCI_COMMAND_IO)) {
+ printf("Error: Can not enable I/O access.\n");
+ continue;
+ }
+#else
+ if (!(status & PCI_COMMAND_MEMORY)) {
+ printf("Error: Can not enable MEMORY access.\n");
+ continue;
+ }
+#endif
+
+ if (!(status & PCI_COMMAND_MASTER)) {
+ printf("Error: Can not enable Bus Mastering.\n");
+ continue;
+ }
+
+ /* Check the latency timer for values >= 0x60. */
+ pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer);
+
+ if (timer < 0x60) {
+ pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, 0x60);
+ }
+
+#ifdef CONFIG_TULIP_USE_IO
+ /* read BAR for memory space access */
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &iobase);
+ iobase &= PCI_BASE_ADDRESS_IO_MASK;
+#else
+ /* read BAR for memory space access */
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, &iobase);
+ iobase &= PCI_BASE_ADDRESS_MEM_MASK;
+#endif
+ debug ("dc21x4x: DEC 21142 PCI Device @0x%x\n", iobase);
+
+ dev = (struct eth_device*) malloc(sizeof *dev);
+
+ if (!dev) {
+ printf("Can not allocalte memory of dc21x4x\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+ sprintf(dev->name, "Davicom#%d", card_number);
+#else
+ sprintf(dev->name, "dc21x4x#%d", card_number);
+#endif
+
+#ifdef CONFIG_TULIP_USE_IO
+ dev->iobase = pci_io_to_phys(devbusfn, iobase);
+#else
+ dev->iobase = pci_mem_to_phys(devbusfn, iobase);
+#endif
+ dev->priv = (void*) devbusfn;
+ dev->init = dc21x4x_init;
+ dev->halt = dc21x4x_halt;
+ dev->send = dc21x4x_send;
+ dev->recv = dc21x4x_recv;
+
+ /* Ensure we're not sleeping. */
+ pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
+
+ udelay(10 * 1000);
+
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+ read_hw_addr(dev, bis);
+#endif
+ eth_register(dev);
+
+ card_number++;
+ }
+
+ return card_number;
+}
+
+static int dc21x4x_init(struct eth_device* dev, bd_t* bis)
+{
+ int i;
+ int devbusfn = (int) dev->priv;
+
+ /* Ensure we're not sleeping. */
+ pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
+
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+ RESET_DM9102(dev);
+#else
+ RESET_DE4X5(dev);
+#endif
+
+ if ((INL(dev, DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
+ printf("Error: Cannot reset ethernet controller.\n");
+ return -1;
+ }
+
+#ifdef CONFIG_TULIP_SELECT_MEDIA
+ dc21x4x_select_media(dev);
+#else
+ OUTL(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR);
+#endif
+
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ rx_ring[i].status = cpu_to_le32(R_OWN);
+ rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
+ rx_ring[i].buf = cpu_to_le32(phys_to_bus((u32) NetRxPackets[i]));
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+ rx_ring[i].next = cpu_to_le32(phys_to_bus((u32) &rx_ring[(i+1) % NUM_RX_DESC]));
+#else
+ rx_ring[i].next = 0;
+#endif
+ }
+
+ for (i=0; i < NUM_TX_DESC; i++) {
+ tx_ring[i].status = 0;
+ tx_ring[i].des1 = 0;
+ tx_ring[i].buf = 0;
+
+#ifdef CONFIG_TULIP_FIX_DAVICOM
+ tx_ring[i].next = cpu_to_le32(phys_to_bus((u32) &tx_ring[(i+1) % NUM_TX_DESC]));
+#else
+ tx_ring[i].next = 0;
+#endif
+ }
+
+ rxRingSize = NUM_RX_DESC;
+ txRingSize = NUM_TX_DESC;
+
+ /* Write the end of list marker to the descriptor lists. */
+ rx_ring[rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
+ tx_ring[txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
+
+ /* Tell the adapter where the TX/RX rings are located. */
+ OUTL(dev, phys_to_bus((u32) &rx_ring), DE4X5_RRBA);
+ OUTL(dev, phys_to_bus((u32) &tx_ring), DE4X5_TRBA);
+
+ START_DE4X5(dev);
+
+ tx_new = 0;
+ rx_new = 0;
+
+ send_setup_frame(dev, bis);
+
+ return 0;
+}
+
+static int dc21x4x_send(struct eth_device *dev, void *packet, int length)
+{
+ int status = -1;
+ int i;
+
+ if (length <= 0) {
+ printf("%s: bad packet size: %d\n", dev->name, length);
+ goto Done;
+ }
+
+ for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+ if (i >= TOUT_LOOP) {
+ printf("%s: tx error buffer not ready\n", dev->name);
+ goto Done;
+ }
+ }
+
+ tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32) packet));
+ tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length);
+ tx_ring[tx_new].status = cpu_to_le32(T_OWN);
+
+ OUTL(dev, POLL_DEMAND, DE4X5_TPD);
+
+ for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+ if (i >= TOUT_LOOP) {
+ printf(".%s: tx buffer not ready\n", dev->name);
+ goto Done;
+ }
+ }
+
+ if (le32_to_cpu(tx_ring[tx_new].status) & TD_ES) {
+#if 0 /* test-only */
+ printf("TX error status = 0x%08X\n",
+ le32_to_cpu(tx_ring[tx_new].status));
+#endif
+ tx_ring[tx_new].status = 0x0;
+ goto Done;
+ }
+
+ status = length;
+
+ Done:
+ tx_new = (tx_new+1) % NUM_TX_DESC;
+ return status;
+}
+
+static int dc21x4x_recv(struct eth_device* dev)
+{
+ s32 status;
+ int length = 0;
+
+ for ( ; ; ) {
+ status = (s32)le32_to_cpu(rx_ring[rx_new].status);
+
+ if (status & R_OWN) {
+ break;
+ }
+
+ if (status & RD_LS) {
+ /* Valid frame status.
+ */
+ if (status & RD_ES) {
+
+ /* There was an error.
+ */
+ printf("RX error status = 0x%08X\n", status);
+ } else {
+ /* A valid frame received.
+ */
+ length = (le32_to_cpu(rx_ring[rx_new].status) >> 16);
+
+ /* Pass the packet up to the protocol
+ * layers.
+ */
+ NetReceive(NetRxPackets[rx_new], length - 4);
+ }
+
+ /* Change buffer ownership for this frame, back
+ * to the adapter.
+ */
+ rx_ring[rx_new].status = cpu_to_le32(R_OWN);
+ }
+
+ /* Update entry information.
+ */
+ rx_new = (rx_new + 1) % rxRingSize;
+ }
+
+ return length;
+}
+
+static void dc21x4x_halt(struct eth_device* dev)
+{
+ int devbusfn = (int) dev->priv;
+
+ STOP_DE4X5(dev);
+ OUTL(dev, 0, DE4X5_SICR);
+
+ pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP);
+}
+
+static void send_setup_frame(struct eth_device* dev, bd_t *bis)
+{
+ int i;
+ char setup_frame[SETUP_FRAME_LEN];
+ char *pa = &setup_frame[0];
+
+ memset(pa, 0xff, SETUP_FRAME_LEN);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ *(pa + (i & 1)) = dev->enetaddr[i];
+ if (i & 0x01) {
+ pa += 4;
+ }
+ }
+
+ for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+ if (i >= TOUT_LOOP) {
+ printf("%s: tx error buffer not ready\n", dev->name);
+ goto Done;
+ }
+ }
+
+ tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32) &setup_frame[0]));
+ tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET| SETUP_FRAME_LEN);
+ tx_ring[tx_new].status = cpu_to_le32(T_OWN);
+
+ OUTL(dev, POLL_DEMAND, DE4X5_TPD);
+
+ for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+ if (i >= TOUT_LOOP) {
+ printf("%s: tx buffer not ready\n", dev->name);
+ goto Done;
+ }
+ }
+
+ if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) {
+ printf("TX error status2 = 0x%08X\n", le32_to_cpu(tx_ring[tx_new].status));
+ }
+ tx_new = (tx_new+1) % NUM_TX_DESC;
+
+Done:
+ return;
+}
+
+#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
+/* SROM Read and write routines.
+ */
+static void
+sendto_srom(struct eth_device* dev, u_int command, u_long addr)
+{
+ OUTL(dev, command, addr);
+ udelay(1);
+}
+
+static int
+getfrom_srom(struct eth_device* dev, u_long addr)
+{
+ s32 tmp;
+
+ tmp = INL(dev, addr);
+ udelay(1);
+
+ return tmp;
+}
+
+/* Note: this routine returns extra data bits for size detection. */
+static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned retval = 0;
+ int read_cmd = location | (SROM_READ_CMD << addr_len);
+
+ sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+
+#ifdef DEBUG_SROM
+ printf(" EEPROM read at %d ", location);
+#endif
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval, ioaddr);
+ udelay(10);
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK, ioaddr);
+ udelay(10);
+#ifdef DEBUG_SROM2
+ printf("%X", getfrom_srom(dev, ioaddr) & 15);
+#endif
+ retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0);
+ }
+
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+
+#ifdef DEBUG_SROM2
+ printf(" :%X:", getfrom_srom(dev, ioaddr) & 15);
+#endif
+
+ for (i = 16; i > 0; i--) {
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
+ udelay(10);
+#ifdef DEBUG_SROM2
+ printf("%X", getfrom_srom(dev, ioaddr) & 15);
+#endif
+ retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0);
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+ udelay(10);
+ }
+
+ /* Terminate the EEPROM access. */
+ sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
+
+#ifdef DEBUG_SROM2
+ printf(" EEPROM value at %d is %5.5x.\n", location, retval);
+#endif
+
+ return retval;
+}
+#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
+
+/* This executes a generic EEPROM command, typically a write or write
+ * enable. It returns the data output from the EEPROM, and thus may
+ * also be used for reads.
+ */
+#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
+static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, int cmd_len)
+{
+ unsigned retval = 0;
+
+#ifdef DEBUG_SROM
+ printf(" EEPROM op 0x%x: ", cmd);
+#endif
+
+ sendto_srom(dev,SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
+
+ /* Shift the command bits out. */
+ do {
+ short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
+ sendto_srom(dev,dataval, ioaddr);
+ udelay(10);
+
+#ifdef DEBUG_SROM2
+ printf("%X", getfrom_srom(dev,ioaddr) & 15);
+#endif
+
+ sendto_srom(dev,dataval | DT_CLK, ioaddr);
+ udelay(10);
+ retval = (retval << 1) | ((getfrom_srom(dev,ioaddr) & EE_DATA_READ) ? 1 : 0);
+ } while (--cmd_len >= 0);
+ sendto_srom(dev,SROM_RD | SROM_SR | DT_CS, ioaddr);
+
+ /* Terminate the EEPROM access. */
+ sendto_srom(dev,SROM_RD | SROM_SR, ioaddr);
+
+#ifdef DEBUG_SROM
+ printf(" EEPROM result is 0x%5.5x.\n", retval);
+#endif
+
+ return retval;
+}
+#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
+
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+static int read_srom(struct eth_device *dev, u_long ioaddr, int index)
+{
+ int ee_addr_size = do_read_eeprom(dev, ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+
+ return do_eeprom_cmd(dev, ioaddr,
+ (((SROM_READ_CMD << ee_addr_size) | index) << 16)
+ | 0xffff, 3 + ee_addr_size + 16);
+}
+#endif /* CONFIG_TULIP_FIX_DAVICOM */
+
+#ifdef UPDATE_SROM
+static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_value)
+{
+ int ee_addr_size = do_read_eeprom(dev, ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+ int i;
+ unsigned short newval;
+
+ udelay(10*1000); /* test-only */
+
+#ifdef DEBUG_SROM
+ printf("ee_addr_size=%d.\n", ee_addr_size);
+ printf("Writing new entry 0x%4.4x to offset %d.\n", new_value, index);
+#endif
+
+ /* Enable programming modes. */
+ do_eeprom_cmd(dev, ioaddr, (0x4f << (ee_addr_size-4)), 3+ee_addr_size);
+
+ /* Do the actual write. */
+ do_eeprom_cmd(dev, ioaddr,
+ (((SROM_WRITE_CMD<<ee_addr_size)|index) << 16) | new_value,
+ 3 + ee_addr_size + 16);
+
+ /* Poll for write finished. */
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+ for (i = 0; i < 10000; i++) /* Typical 2000 ticks */
+ if (getfrom_srom(dev, ioaddr) & EE_DATA_READ)
+ break;
+
+#ifdef DEBUG_SROM
+ printf(" Write finished after %d ticks.\n", i);
+#endif
+
+ /* Disable programming. */
+ do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size-4)), 3 + ee_addr_size);
+
+ /* And read the result. */
+ newval = do_eeprom_cmd(dev, ioaddr,
+ (((SROM_READ_CMD<<ee_addr_size)|index) << 16)
+ | 0xffff, 3 + ee_addr_size + 16);
+#ifdef DEBUG_SROM
+ printf(" New value at offset %d is %4.4x.\n", index, newval);
+#endif
+ return 1;
+}
+#endif
+
+#ifndef CONFIG_TULIP_FIX_DAVICOM
+static void read_hw_addr(struct eth_device *dev, bd_t *bis)
+{
+ u_short tmp, *p = (u_short *)(&dev->enetaddr[0]);
+ int i, j = 0;
+
+ for (i = 0; i < (ETH_ALEN >> 1); i++) {
+ tmp = read_srom(dev, DE4X5_APROM, ((SROM_HWADD >> 1) + i));
+ *p = le16_to_cpu(tmp);
+ j += *p++;
+ }
+
+ if ((j == 0) || (j == 0x2fffd)) {
+ memset (dev->enetaddr, 0, ETH_ALEN);
+ debug ("Warning: can't read HW address from SROM.\n");
+ goto Done;
+ }
+
+ return;
+
+Done:
+#ifdef UPDATE_SROM
+ update_srom(dev, bis);
+#endif
+ return;
+}
+#endif /* CONFIG_TULIP_FIX_DAVICOM */
+
+#ifdef UPDATE_SROM
+static void update_srom(struct eth_device *dev, bd_t *bis)
+{
+ int i;
+ static unsigned short eeprom[0x40] = {
+ 0x140b, 0x6610, 0x0000, 0x0000, /* 00 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 04 */
+ 0x00a3, 0x0103, 0x0000, 0x0000, /* 08 */
+ 0x0000, 0x1f00, 0x0000, 0x0000, /* 0c */
+ 0x0108, 0x038d, 0x0000, 0x0000, /* 10 */
+ 0xe078, 0x0001, 0x0040, 0x0018, /* 14 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 18 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 1c */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 20 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 2c */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 34 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 38 */
+ 0x0000, 0x0000, 0x0000, 0x4e07, /* 3c */
+ };
+ uchar enetaddr[6];
+
+ /* Ethernet Addr... */
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr))
+ return;
+ eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0];
+ eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2];
+ eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4];
+
+ for (i=0; i<0x40; i++) {
+ write_srom(dev, DE4X5_APROM, i, eeprom[i]);
+ }
+}
+#endif /* UPDATE_SROM */
diff --git a/qemu/roms/u-boot/drivers/net/designware.c b/qemu/roms/u-boot/drivers/net/designware.c
new file mode 100644
index 000000000..78751b260
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/designware.c
@@ -0,0 +1,449 @@
+/*
+ * (C) Copyright 2010
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Designware ethernet IP driver for u-boot
+ */
+
+#include <common.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include "designware.h"
+
+#if !defined(CONFIG_PHYLIB)
+# error "DesignWare Ether MAC requires PHYLIB - missing CONFIG_PHYLIB"
+#endif
+
+static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct eth_mac_regs *mac_p = bus->priv;
+ ulong start;
+ u16 miiaddr;
+ int timeout = CONFIG_MDIO_TIMEOUT;
+
+ miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
+ ((reg << MIIREGSHIFT) & MII_REGMSK);
+
+ writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
+
+ start = get_timer(0);
+ while (get_timer(start) < timeout) {
+ if (!(readl(&mac_p->miiaddr) & MII_BUSY))
+ return readl(&mac_p->miidata);
+ udelay(10);
+ };
+
+ return -1;
+}
+
+static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct eth_mac_regs *mac_p = bus->priv;
+ ulong start;
+ u16 miiaddr;
+ int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
+
+ writel(val, &mac_p->miidata);
+ miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
+ ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE;
+
+ writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
+
+ start = get_timer(0);
+ while (get_timer(start) < timeout) {
+ if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
+ ret = 0;
+ break;
+ }
+ udelay(10);
+ };
+
+ return ret;
+}
+
+static int dw_mdio_init(char *name, struct eth_mac_regs *mac_regs_p)
+{
+ struct mii_dev *bus = mdio_alloc();
+
+ if (!bus) {
+ printf("Failed to allocate MDIO bus\n");
+ return -1;
+ }
+
+ bus->read = dw_mdio_read;
+ bus->write = dw_mdio_write;
+ sprintf(bus->name, name);
+
+ bus->priv = (void *)mac_regs_p;
+
+ return mdio_register(bus);
+}
+
+static void tx_descs_init(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
+ char *txbuffs = &priv->txbuffs[0];
+ struct dmamacdescr *desc_p;
+ u32 idx;
+
+ for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
+ desc_p = &desc_table_p[idx];
+ desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
+ desc_p->dmamac_next = &desc_table_p[idx + 1];
+
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+ desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
+ DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \
+ DESC_TXSTS_TXCHECKINSCTRL | \
+ DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
+
+ desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
+ desc_p->dmamac_cntl = 0;
+ desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
+#else
+ desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
+ desc_p->txrx_status = 0;
+#endif
+ }
+
+ /* Correcting the last pointer of the chain */
+ desc_p->dmamac_next = &desc_table_p[0];
+
+ /* Flush all Tx buffer descriptors at once */
+ flush_dcache_range((unsigned int)priv->tx_mac_descrtable,
+ (unsigned int)priv->tx_mac_descrtable +
+ sizeof(priv->tx_mac_descrtable));
+
+ writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
+ priv->tx_currdescnum = 0;
+}
+
+static void rx_descs_init(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
+ char *rxbuffs = &priv->rxbuffs[0];
+ struct dmamacdescr *desc_p;
+ u32 idx;
+
+ /* Before passing buffers to GMAC we need to make sure zeros
+ * written there right after "priv" structure allocation were
+ * flushed into RAM.
+ * Otherwise there's a chance to get some of them flushed in RAM when
+ * GMAC is already pushing data to RAM via DMA. This way incoming from
+ * GMAC data will be corrupted. */
+ flush_dcache_range((unsigned int)rxbuffs, (unsigned int)rxbuffs +
+ RX_TOTAL_BUFSIZE);
+
+ for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
+ desc_p = &desc_table_p[idx];
+ desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
+ desc_p->dmamac_next = &desc_table_p[idx + 1];
+
+ desc_p->dmamac_cntl =
+ (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \
+ DESC_RXCTRL_RXCHAIN;
+
+ desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
+ }
+
+ /* Correcting the last pointer of the chain */
+ desc_p->dmamac_next = &desc_table_p[0];
+
+ /* Flush all Rx buffer descriptors at once */
+ flush_dcache_range((unsigned int)priv->rx_mac_descrtable,
+ (unsigned int)priv->rx_mac_descrtable +
+ sizeof(priv->rx_mac_descrtable));
+
+ writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
+ priv->rx_currdescnum = 0;
+}
+
+static int dw_write_hwaddr(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ u32 macid_lo, macid_hi;
+ u8 *mac_id = &dev->enetaddr[0];
+
+ macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
+ (mac_id[3] << 24);
+ macid_hi = mac_id[4] + (mac_id[5] << 8);
+
+ writel(macid_hi, &mac_p->macaddr0hi);
+ writel(macid_lo, &mac_p->macaddr0lo);
+
+ return 0;
+}
+
+static void dw_adjust_link(struct eth_mac_regs *mac_p,
+ struct phy_device *phydev)
+{
+ u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN;
+
+ if (!phydev->link) {
+ printf("%s: No link.\n", phydev->dev->name);
+ return;
+ }
+
+ if (phydev->speed != 1000)
+ conf |= MII_PORTSELECT;
+
+ if (phydev->speed == 100)
+ conf |= FES_100;
+
+ if (phydev->duplex)
+ conf |= FULLDPLXMODE;
+
+ writel(conf, &mac_p->conf);
+
+ printf("Speed: %d, %s duplex%s\n", phydev->speed,
+ (phydev->duplex) ? "full" : "half",
+ (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
+}
+
+static void dw_eth_halt(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+
+ writel(readl(&mac_p->conf) & ~(RXENABLE | TXENABLE), &mac_p->conf);
+ writel(readl(&dma_p->opmode) & ~(RXSTART | TXSTART), &dma_p->opmode);
+
+ phy_shutdown(priv->phydev);
+}
+
+static int dw_eth_init(struct eth_device *dev, bd_t *bis)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ unsigned int start;
+
+ writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode);
+
+ start = get_timer(0);
+ while (readl(&dma_p->busmode) & DMAMAC_SRST) {
+ if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT)
+ return -1;
+
+ mdelay(100);
+ };
+
+ /* Soft reset above clears HW address registers.
+ * So we have to set it here once again */
+ dw_write_hwaddr(dev);
+
+ rx_descs_init(dev);
+ tx_descs_init(dev);
+
+ writel(FIXEDBURST | PRIORXTX_41 | BURST_16, &dma_p->busmode);
+
+ writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD,
+ &dma_p->opmode);
+
+ writel(readl(&dma_p->opmode) | RXSTART | TXSTART, &dma_p->opmode);
+
+ /* Start up the PHY */
+ if (phy_startup(priv->phydev)) {
+ printf("Could not initialize PHY %s\n",
+ priv->phydev->dev->name);
+ return -1;
+ }
+
+ dw_adjust_link(mac_p, priv->phydev);
+
+ if (!priv->phydev->link)
+ return -1;
+
+ writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
+
+ return 0;
+}
+
+static int dw_eth_send(struct eth_device *dev, void *packet, int length)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ u32 desc_num = priv->tx_currdescnum;
+ struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
+
+ /* Invalidate only "status" field for the following check */
+ invalidate_dcache_range((unsigned long)&desc_p->txrx_status,
+ (unsigned long)&desc_p->txrx_status +
+ sizeof(desc_p->txrx_status));
+
+ /* Check if the descriptor is owned by CPU */
+ if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
+ printf("CPU not owner of tx frame\n");
+ return -1;
+ }
+
+ memcpy((void *)desc_p->dmamac_addr, packet, length);
+
+ /* Flush data to be sent */
+ flush_dcache_range((unsigned long)desc_p->dmamac_addr,
+ (unsigned long)desc_p->dmamac_addr + length);
+
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+ desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
+ desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \
+ DESC_TXCTRL_SIZE1MASK;
+
+ desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
+ desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
+#else
+ desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \
+ DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \
+ DESC_TXCTRL_TXFIRST;
+
+ desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
+#endif
+
+ /* Flush modified buffer descriptor */
+ flush_dcache_range((unsigned long)desc_p,
+ (unsigned long)desc_p + sizeof(struct dmamacdescr));
+
+ /* Test the wrap-around condition. */
+ if (++desc_num >= CONFIG_TX_DESCR_NUM)
+ desc_num = 0;
+
+ priv->tx_currdescnum = desc_num;
+
+ /* Start the transmission */
+ writel(POLL_DATA, &dma_p->txpolldemand);
+
+ return 0;
+}
+
+static int dw_eth_recv(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ u32 status, desc_num = priv->rx_currdescnum;
+ struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
+ int length = 0;
+
+ /* Invalidate entire buffer descriptor */
+ invalidate_dcache_range((unsigned long)desc_p,
+ (unsigned long)desc_p +
+ sizeof(struct dmamacdescr));
+
+ status = desc_p->txrx_status;
+
+ /* Check if the owner is the CPU */
+ if (!(status & DESC_RXSTS_OWNBYDMA)) {
+
+ length = (status & DESC_RXSTS_FRMLENMSK) >> \
+ DESC_RXSTS_FRMLENSHFT;
+
+ /* Invalidate received data */
+ invalidate_dcache_range((unsigned long)desc_p->dmamac_addr,
+ (unsigned long)desc_p->dmamac_addr +
+ length);
+
+ NetReceive(desc_p->dmamac_addr, length);
+
+ /*
+ * Make the current descriptor valid again and go to
+ * the next one
+ */
+ desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
+
+ /* Flush only status field - others weren't changed */
+ flush_dcache_range((unsigned long)&desc_p->txrx_status,
+ (unsigned long)&desc_p->txrx_status +
+ sizeof(desc_p->txrx_status));
+
+ /* Test the wrap-around condition. */
+ if (++desc_num >= CONFIG_RX_DESCR_NUM)
+ desc_num = 0;
+ }
+
+ priv->rx_currdescnum = desc_num;
+
+ return length;
+}
+
+static int dw_phy_init(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct phy_device *phydev;
+ int mask = 0xffffffff;
+
+#ifdef CONFIG_PHY_ADDR
+ mask = 1 << CONFIG_PHY_ADDR;
+#endif
+
+ phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
+ if (!phydev)
+ return -1;
+
+ phy_connect_dev(phydev, dev);
+
+ phydev->supported &= PHY_GBIT_FEATURES;
+ phydev->advertising = phydev->supported;
+
+ priv->phydev = phydev;
+ phy_config(phydev);
+
+ return 1;
+}
+
+int designware_initialize(ulong base_addr, u32 interface)
+{
+ struct eth_device *dev;
+ struct dw_eth_dev *priv;
+
+ dev = (struct eth_device *) malloc(sizeof(struct eth_device));
+ if (!dev)
+ return -ENOMEM;
+
+ /*
+ * Since the priv structure contains the descriptors which need a strict
+ * buswidth alignment, memalign is used to allocate memory
+ */
+ priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev));
+ if (!priv) {
+ free(dev);
+ return -ENOMEM;
+ }
+
+ memset(dev, 0, sizeof(struct eth_device));
+ memset(priv, 0, sizeof(struct dw_eth_dev));
+
+ sprintf(dev->name, "dwmac.%lx", base_addr);
+ dev->iobase = (int)base_addr;
+ dev->priv = priv;
+
+ priv->dev = dev;
+ priv->mac_regs_p = (struct eth_mac_regs *)base_addr;
+ priv->dma_regs_p = (struct eth_dma_regs *)(base_addr +
+ DW_DMA_BASE_OFFSET);
+
+ dev->init = dw_eth_init;
+ dev->send = dw_eth_send;
+ dev->recv = dw_eth_recv;
+ dev->halt = dw_eth_halt;
+ dev->write_hwaddr = dw_write_hwaddr;
+
+ eth_register(dev);
+
+ priv->interface = interface;
+
+ dw_mdio_init(dev->name, priv->mac_regs_p);
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+
+ return dw_phy_init(dev);
+}
diff --git a/qemu/roms/u-boot/drivers/net/designware.h b/qemu/roms/u-boot/drivers/net/designware.h
new file mode 100644
index 000000000..382b0c7f0
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/designware.h
@@ -0,0 +1,236 @@
+/*
+ * (C) Copyright 2010
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DW_ETH_H
+#define _DW_ETH_H
+
+#define CONFIG_TX_DESCR_NUM 16
+#define CONFIG_RX_DESCR_NUM 16
+#define CONFIG_ETH_BUFSIZE 2048
+#define TX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
+#define RX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
+
+#define CONFIG_MACRESET_TIMEOUT (3 * CONFIG_SYS_HZ)
+#define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ)
+
+struct eth_mac_regs {
+ u32 conf; /* 0x00 */
+ u32 framefilt; /* 0x04 */
+ u32 hashtablehigh; /* 0x08 */
+ u32 hashtablelow; /* 0x0c */
+ u32 miiaddr; /* 0x10 */
+ u32 miidata; /* 0x14 */
+ u32 flowcontrol; /* 0x18 */
+ u32 vlantag; /* 0x1c */
+ u32 version; /* 0x20 */
+ u8 reserved_1[20];
+ u32 intreg; /* 0x38 */
+ u32 intmask; /* 0x3c */
+ u32 macaddr0hi; /* 0x40 */
+ u32 macaddr0lo; /* 0x44 */
+};
+
+/* MAC configuration register definitions */
+#define FRAMEBURSTENABLE (1 << 21)
+#define MII_PORTSELECT (1 << 15)
+#define FES_100 (1 << 14)
+#define DISABLERXOWN (1 << 13)
+#define FULLDPLXMODE (1 << 11)
+#define RXENABLE (1 << 2)
+#define TXENABLE (1 << 3)
+
+/* MII address register definitions */
+#define MII_BUSY (1 << 0)
+#define MII_WRITE (1 << 1)
+#define MII_CLKRANGE_60_100M (0)
+#define MII_CLKRANGE_100_150M (0x4)
+#define MII_CLKRANGE_20_35M (0x8)
+#define MII_CLKRANGE_35_60M (0xC)
+#define MII_CLKRANGE_150_250M (0x10)
+#define MII_CLKRANGE_250_300M (0x14)
+
+#define MIIADDRSHIFT (11)
+#define MIIREGSHIFT (6)
+#define MII_REGMSK (0x1F << 6)
+#define MII_ADDRMSK (0x1F << 11)
+
+
+struct eth_dma_regs {
+ u32 busmode; /* 0x00 */
+ u32 txpolldemand; /* 0x04 */
+ u32 rxpolldemand; /* 0x08 */
+ u32 rxdesclistaddr; /* 0x0c */
+ u32 txdesclistaddr; /* 0x10 */
+ u32 status; /* 0x14 */
+ u32 opmode; /* 0x18 */
+ u32 intenable; /* 0x1c */
+ u8 reserved[40];
+ u32 currhosttxdesc; /* 0x48 */
+ u32 currhostrxdesc; /* 0x4c */
+ u32 currhosttxbuffaddr; /* 0x50 */
+ u32 currhostrxbuffaddr; /* 0x54 */
+};
+
+#define DW_DMA_BASE_OFFSET (0x1000)
+
+/* Bus mode register definitions */
+#define FIXEDBURST (1 << 16)
+#define PRIORXTX_41 (3 << 14)
+#define PRIORXTX_31 (2 << 14)
+#define PRIORXTX_21 (1 << 14)
+#define PRIORXTX_11 (0 << 14)
+#define BURST_1 (1 << 8)
+#define BURST_2 (2 << 8)
+#define BURST_4 (4 << 8)
+#define BURST_8 (8 << 8)
+#define BURST_16 (16 << 8)
+#define BURST_32 (32 << 8)
+#define RXHIGHPRIO (1 << 1)
+#define DMAMAC_SRST (1 << 0)
+
+/* Poll demand definitions */
+#define POLL_DATA (0xFFFFFFFF)
+
+/* Operation mode definitions */
+#define STOREFORWARD (1 << 21)
+#define FLUSHTXFIFO (1 << 20)
+#define TXSTART (1 << 13)
+#define TXSECONDFRAME (1 << 2)
+#define RXSTART (1 << 1)
+
+/* Descriptior related definitions */
+#define MAC_MAX_FRAME_SZ (1600)
+
+struct dmamacdescr {
+ u32 txrx_status;
+ u32 dmamac_cntl;
+ void *dmamac_addr;
+ struct dmamacdescr *dmamac_next;
+} __aligned(ARCH_DMA_MINALIGN);
+
+/*
+ * txrx_status definitions
+ */
+
+/* tx status bits definitions */
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+
+#define DESC_TXSTS_OWNBYDMA (1 << 31)
+#define DESC_TXSTS_TXINT (1 << 30)
+#define DESC_TXSTS_TXLAST (1 << 29)
+#define DESC_TXSTS_TXFIRST (1 << 28)
+#define DESC_TXSTS_TXCRCDIS (1 << 27)
+
+#define DESC_TXSTS_TXPADDIS (1 << 26)
+#define DESC_TXSTS_TXCHECKINSCTRL (3 << 22)
+#define DESC_TXSTS_TXRINGEND (1 << 21)
+#define DESC_TXSTS_TXCHAIN (1 << 20)
+#define DESC_TXSTS_MSK (0x1FFFF << 0)
+
+#else
+
+#define DESC_TXSTS_OWNBYDMA (1 << 31)
+#define DESC_TXSTS_MSK (0x1FFFF << 0)
+
+#endif
+
+/* rx status bits definitions */
+#define DESC_RXSTS_OWNBYDMA (1 << 31)
+#define DESC_RXSTS_DAFILTERFAIL (1 << 30)
+#define DESC_RXSTS_FRMLENMSK (0x3FFF << 16)
+#define DESC_RXSTS_FRMLENSHFT (16)
+
+#define DESC_RXSTS_ERROR (1 << 15)
+#define DESC_RXSTS_RXTRUNCATED (1 << 14)
+#define DESC_RXSTS_SAFILTERFAIL (1 << 13)
+#define DESC_RXSTS_RXIPC_GIANTFRAME (1 << 12)
+#define DESC_RXSTS_RXDAMAGED (1 << 11)
+#define DESC_RXSTS_RXVLANTAG (1 << 10)
+#define DESC_RXSTS_RXFIRST (1 << 9)
+#define DESC_RXSTS_RXLAST (1 << 8)
+#define DESC_RXSTS_RXIPC_GIANT (1 << 7)
+#define DESC_RXSTS_RXCOLLISION (1 << 6)
+#define DESC_RXSTS_RXFRAMEETHER (1 << 5)
+#define DESC_RXSTS_RXWATCHDOG (1 << 4)
+#define DESC_RXSTS_RXMIIERROR (1 << 3)
+#define DESC_RXSTS_RXDRIBBLING (1 << 2)
+#define DESC_RXSTS_RXCRC (1 << 1)
+
+/*
+ * dmamac_cntl definitions
+ */
+
+/* tx control bits definitions */
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+
+#define DESC_TXCTRL_SIZE1MASK (0x1FFF << 0)
+#define DESC_TXCTRL_SIZE1SHFT (0)
+#define DESC_TXCTRL_SIZE2MASK (0x1FFF << 16)
+#define DESC_TXCTRL_SIZE2SHFT (16)
+
+#else
+
+#define DESC_TXCTRL_TXINT (1 << 31)
+#define DESC_TXCTRL_TXLAST (1 << 30)
+#define DESC_TXCTRL_TXFIRST (1 << 29)
+#define DESC_TXCTRL_TXCHECKINSCTRL (3 << 27)
+#define DESC_TXCTRL_TXCRCDIS (1 << 26)
+#define DESC_TXCTRL_TXRINGEND (1 << 25)
+#define DESC_TXCTRL_TXCHAIN (1 << 24)
+
+#define DESC_TXCTRL_SIZE1MASK (0x7FF << 0)
+#define DESC_TXCTRL_SIZE1SHFT (0)
+#define DESC_TXCTRL_SIZE2MASK (0x7FF << 11)
+#define DESC_TXCTRL_SIZE2SHFT (11)
+
+#endif
+
+/* rx control bits definitions */
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+
+#define DESC_RXCTRL_RXINTDIS (1 << 31)
+#define DESC_RXCTRL_RXRINGEND (1 << 15)
+#define DESC_RXCTRL_RXCHAIN (1 << 14)
+
+#define DESC_RXCTRL_SIZE1MASK (0x1FFF << 0)
+#define DESC_RXCTRL_SIZE1SHFT (0)
+#define DESC_RXCTRL_SIZE2MASK (0x1FFF << 16)
+#define DESC_RXCTRL_SIZE2SHFT (16)
+
+#else
+
+#define DESC_RXCTRL_RXINTDIS (1 << 31)
+#define DESC_RXCTRL_RXRINGEND (1 << 25)
+#define DESC_RXCTRL_RXCHAIN (1 << 24)
+
+#define DESC_RXCTRL_SIZE1MASK (0x7FF << 0)
+#define DESC_RXCTRL_SIZE1SHFT (0)
+#define DESC_RXCTRL_SIZE2MASK (0x7FF << 11)
+#define DESC_RXCTRL_SIZE2SHFT (11)
+
+#endif
+
+struct dw_eth_dev {
+ u32 interface;
+ u32 tx_currdescnum;
+ u32 rx_currdescnum;
+
+ struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM];
+ struct dmamacdescr rx_mac_descrtable[CONFIG_RX_DESCR_NUM];
+
+ char txbuffs[TX_TOTAL_BUFSIZE];
+ char rxbuffs[RX_TOTAL_BUFSIZE];
+
+ struct eth_mac_regs *mac_regs_p;
+ struct eth_dma_regs *dma_regs_p;
+
+ struct eth_device *dev;
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+};
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/dm9000x.c b/qemu/roms/u-boot/drivers/net/dm9000x.c
new file mode 100644
index 000000000..4de9d4164
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/dm9000x.c
@@ -0,0 +1,643 @@
+/*
+ dm9000.c: Version 1.2 12/15/2003
+
+ A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
+ Copyright (C) 1997 Sten Wang
+
+ * SPDX-License-Identifier: GPL-2.0+
+
+ (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
+
+V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match
+ 06/22/2001 Support DM9801 progrmming
+ E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
+ E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
+ R17 = (R17 & 0xfff0) | NF + 3
+ E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
+ R17 = (R17 & 0xfff0) | NF
+
+v1.00 modify by simon 2001.9.5
+ change for kernel 2.4.x
+
+v1.1 11/09/2001 fix force mode bug
+
+v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>:
+ Fixed phy reset.
+ Added tx/rx 32 bit mode.
+ Cleaned up for kernel merge.
+
+--------------------------------------
+
+ 12/15/2003 Initial port to u-boot by
+ Sascha Hauer <saschahauer@web.de>
+
+ 06/03/2008 Remy Bohmer <linux@bohmer.net>
+ - Fixed the driver to work with DM9000A.
+ (check on ISR receive status bit before reading the
+ FIFO as described in DM9000 programming guide and
+ application notes)
+ - Added autodetect of databus width.
+ - Made debug code compile again.
+ - Adapt eth_send such that it matches the DM9000*
+ application notes. Needed to make it work properly
+ for DM9000A.
+ - Adapted reset procedure to match DM9000 application
+ notes (i.e. double reset)
+ - some minor code cleanups
+ These changes are tested with DM9000{A,EP,E} together
+ with a 200MHz Atmel AT91SAM9261 core
+
+TODO: external MII is not functional, only internal at the moment.
+*/
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <asm/io.h>
+#include <dm9000.h>
+
+#include "dm9000x.h"
+
+/* Board/System/Debug information/definition ---------------- */
+
+/* #define CONFIG_DM9000_DEBUG */
+
+#ifdef CONFIG_DM9000_DEBUG
+#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
+#define DM9000_DMP_PACKET(func,packet,length) \
+ do { \
+ int i; \
+ printf("%s: length: %d\n", func, length); \
+ for (i = 0; i < length; i++) { \
+ if (i % 8 == 0) \
+ printf("\n%s: %02x: ", func, i); \
+ printf("%02x ", ((unsigned char *) packet)[i]); \
+ } printf("\n"); \
+ } while(0)
+#else
+#define DM9000_DBG(fmt,args...)
+#define DM9000_DMP_PACKET(func,packet,length)
+#endif
+
+/* Structure/enum declaration ------------------------------- */
+typedef struct board_info {
+ u32 runt_length_counter; /* counter: RX length < 64byte */
+ u32 long_length_counter; /* counter: RX length > 1514byte */
+ u32 reset_counter; /* counter: RESET */
+ u32 reset_tx_timeout; /* RESET caused by TX Timeout */
+ u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
+ u16 tx_pkt_cnt;
+ u16 queue_start_addr;
+ u16 dbug_cnt;
+ u8 phy_addr;
+ u8 device_wait_reset; /* device state */
+ unsigned char srom[128];
+ void (*outblk)(volatile void *data_ptr, int count);
+ void (*inblk)(void *data_ptr, int count);
+ void (*rx_status)(u16 *RxStatus, u16 *RxLen);
+ struct eth_device netdev;
+} board_info_t;
+static board_info_t dm9000_info;
+
+
+/* function declaration ------------------------------------- */
+static int dm9000_probe(void);
+static u16 dm9000_phy_read(int);
+static void dm9000_phy_write(int, u16);
+static u8 DM9000_ior(int);
+static void DM9000_iow(int reg, u8 value);
+
+/* DM9000 network board routine ---------------------------- */
+#ifndef CONFIG_DM9000_BYTE_SWAPPED
+#define DM9000_outb(d,r) writeb(d, (volatile u8 *)(r))
+#define DM9000_outw(d,r) writew(d, (volatile u16 *)(r))
+#define DM9000_outl(d,r) writel(d, (volatile u32 *)(r))
+#define DM9000_inb(r) readb((volatile u8 *)(r))
+#define DM9000_inw(r) readw((volatile u16 *)(r))
+#define DM9000_inl(r) readl((volatile u32 *)(r))
+#else
+#define DM9000_outb(d, r) __raw_writeb(d, r)
+#define DM9000_outw(d, r) __raw_writew(d, r)
+#define DM9000_outl(d, r) __raw_writel(d, r)
+#define DM9000_inb(r) __raw_readb(r)
+#define DM9000_inw(r) __raw_readw(r)
+#define DM9000_inl(r) __raw_readl(r)
+#endif
+
+#ifdef CONFIG_DM9000_DEBUG
+static void
+dump_regs(void)
+{
+ DM9000_DBG("\n");
+ DM9000_DBG("NCR (0x00): %02x\n", DM9000_ior(0));
+ DM9000_DBG("NSR (0x01): %02x\n", DM9000_ior(1));
+ DM9000_DBG("TCR (0x02): %02x\n", DM9000_ior(2));
+ DM9000_DBG("TSRI (0x03): %02x\n", DM9000_ior(3));
+ DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
+ DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5));
+ DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6));
+ DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
+ DM9000_DBG("\n");
+}
+#endif
+
+static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
+{
+ int i;
+ for (i = 0; i < count; i++)
+ DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
+}
+
+static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
+{
+ int i;
+ u32 tmplen = (count + 1) / 2;
+
+ for (i = 0; i < tmplen; i++)
+ DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
+}
+static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
+{
+ int i;
+ u32 tmplen = (count + 3) / 4;
+
+ for (i = 0; i < tmplen; i++)
+ DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
+}
+
+static void dm9000_inblk_8bit(void *data_ptr, int count)
+{
+ int i;
+ for (i = 0; i < count; i++)
+ ((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
+}
+
+static void dm9000_inblk_16bit(void *data_ptr, int count)
+{
+ int i;
+ u32 tmplen = (count + 1) / 2;
+
+ for (i = 0; i < tmplen; i++)
+ ((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
+}
+static void dm9000_inblk_32bit(void *data_ptr, int count)
+{
+ int i;
+ u32 tmplen = (count + 3) / 4;
+
+ for (i = 0; i < tmplen; i++)
+ ((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
+}
+
+static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
+{
+ u32 tmpdata;
+
+ DM9000_outb(DM9000_MRCMD, DM9000_IO);
+
+ tmpdata = DM9000_inl(DM9000_DATA);
+ *RxStatus = __le16_to_cpu(tmpdata);
+ *RxLen = __le16_to_cpu(tmpdata >> 16);
+}
+
+static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
+{
+ DM9000_outb(DM9000_MRCMD, DM9000_IO);
+
+ *RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
+ *RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
+}
+
+static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
+{
+ DM9000_outb(DM9000_MRCMD, DM9000_IO);
+
+ *RxStatus =
+ __le16_to_cpu(DM9000_inb(DM9000_DATA) +
+ (DM9000_inb(DM9000_DATA) << 8));
+ *RxLen =
+ __le16_to_cpu(DM9000_inb(DM9000_DATA) +
+ (DM9000_inb(DM9000_DATA) << 8));
+}
+
+/*
+ Search DM9000 board, allocate space and register it
+*/
+int
+dm9000_probe(void)
+{
+ u32 id_val;
+ id_val = DM9000_ior(DM9000_VIDL);
+ id_val |= DM9000_ior(DM9000_VIDH) << 8;
+ id_val |= DM9000_ior(DM9000_PIDL) << 16;
+ id_val |= DM9000_ior(DM9000_PIDH) << 24;
+ if (id_val == DM9000_ID) {
+ printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
+ id_val);
+ return 0;
+ } else {
+ printf("dm9000 not found at 0x%08x id: 0x%08x\n",
+ CONFIG_DM9000_BASE, id_val);
+ return -1;
+ }
+}
+
+/* General Purpose dm9000 reset routine */
+static void
+dm9000_reset(void)
+{
+ DM9000_DBG("resetting DM9000\n");
+
+ /* Reset DM9000,
+ see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
+
+ /* DEBUG: Make all GPIO0 outputs, all others inputs */
+ DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
+ /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
+ DM9000_iow(DM9000_GPR, 0);
+ /* Step 2: Software reset */
+ DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
+
+ do {
+ DM9000_DBG("resetting the DM9000, 1st reset\n");
+ udelay(25); /* Wait at least 20 us */
+ } while (DM9000_ior(DM9000_NCR) & 1);
+
+ DM9000_iow(DM9000_NCR, 0);
+ DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
+
+ do {
+ DM9000_DBG("resetting the DM9000, 2nd reset\n");
+ udelay(25); /* Wait at least 20 us */
+ } while (DM9000_ior(DM9000_NCR) & 1);
+
+ /* Check whether the ethernet controller is present */
+ if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
+ (DM9000_ior(DM9000_PIDH) != 0x90))
+ printf("ERROR: resetting DM9000 -> not responding\n");
+}
+
+/* Initialize dm9000 board
+*/
+static int dm9000_init(struct eth_device *dev, bd_t *bd)
+{
+ int i, oft, lnk;
+ u8 io_mode;
+ struct board_info *db = &dm9000_info;
+
+ DM9000_DBG("%s\n", __func__);
+
+ /* RESET device */
+ dm9000_reset();
+
+ if (dm9000_probe() < 0)
+ return -1;
+
+ /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
+ io_mode = DM9000_ior(DM9000_ISR) >> 6;
+
+ switch (io_mode) {
+ case 0x0: /* 16-bit mode */
+ printf("DM9000: running in 16 bit mode\n");
+ db->outblk = dm9000_outblk_16bit;
+ db->inblk = dm9000_inblk_16bit;
+ db->rx_status = dm9000_rx_status_16bit;
+ break;
+ case 0x01: /* 32-bit mode */
+ printf("DM9000: running in 32 bit mode\n");
+ db->outblk = dm9000_outblk_32bit;
+ db->inblk = dm9000_inblk_32bit;
+ db->rx_status = dm9000_rx_status_32bit;
+ break;
+ case 0x02: /* 8 bit mode */
+ printf("DM9000: running in 8 bit mode\n");
+ db->outblk = dm9000_outblk_8bit;
+ db->inblk = dm9000_inblk_8bit;
+ db->rx_status = dm9000_rx_status_8bit;
+ break;
+ default:
+ /* Assume 8 bit mode, will probably not work anyway */
+ printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
+ db->outblk = dm9000_outblk_8bit;
+ db->inblk = dm9000_inblk_8bit;
+ db->rx_status = dm9000_rx_status_8bit;
+ break;
+ }
+
+ /* Program operating register, only internal phy supported */
+ DM9000_iow(DM9000_NCR, 0x0);
+ /* TX Polling clear */
+ DM9000_iow(DM9000_TCR, 0);
+ /* Less 3Kb, 200us */
+ DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
+ /* Flow Control : High/Low Water */
+ DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
+ /* SH FIXME: This looks strange! Flow Control */
+ DM9000_iow(DM9000_FCR, 0x0);
+ /* Special Mode */
+ DM9000_iow(DM9000_SMCR, 0);
+ /* clear TX status */
+ DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
+ /* Clear interrupt status */
+ DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
+
+ printf("MAC: %pM\n", dev->enetaddr);
+ if (!is_valid_ether_addr(dev->enetaddr)) {
+#ifdef CONFIG_RANDOM_MACADDR
+ printf("Bad MAC address (uninitialized EEPROM?), randomizing\n");
+ eth_random_addr(dev->enetaddr);
+ printf("MAC: %pM\n", dev->enetaddr);
+#else
+ printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
+#endif
+ }
+
+ /* fill device MAC address registers */
+ for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
+ DM9000_iow(oft, dev->enetaddr[i]);
+ for (i = 0, oft = 0x16; i < 8; i++, oft++)
+ DM9000_iow(oft, 0xff);
+
+ /* read back mac, just to be sure */
+ for (i = 0, oft = 0x10; i < 6; i++, oft++)
+ DM9000_DBG("%02x:", DM9000_ior(oft));
+ DM9000_DBG("\n");
+
+ /* Activate DM9000 */
+ /* RX enable */
+ DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
+ /* Enable TX/RX interrupt mask */
+ DM9000_iow(DM9000_IMR, IMR_PAR);
+
+ i = 0;
+ while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */
+ udelay(1000);
+ i++;
+ if (i == 10000) {
+ printf("could not establish link\n");
+ return 0;
+ }
+ }
+
+ /* see what we've got */
+ lnk = dm9000_phy_read(17) >> 12;
+ printf("operating at ");
+ switch (lnk) {
+ case 1:
+ printf("10M half duplex ");
+ break;
+ case 2:
+ printf("10M full duplex ");
+ break;
+ case 4:
+ printf("100M half duplex ");
+ break;
+ case 8:
+ printf("100M full duplex ");
+ break;
+ default:
+ printf("unknown: %d ", lnk);
+ break;
+ }
+ printf("mode\n");
+ return 0;
+}
+
+/*
+ Hardware start transmission.
+ Send a packet to media from the upper layer.
+*/
+static int dm9000_send(struct eth_device *netdev, void *packet, int length)
+{
+ int tmo;
+ struct board_info *db = &dm9000_info;
+
+ DM9000_DMP_PACKET(__func__ , packet, length);
+
+ DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
+
+ /* Move data to DM9000 TX RAM */
+ DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
+
+ /* push the data to the TX-fifo */
+ (db->outblk)(packet, length);
+
+ /* Set TX length to DM9000 */
+ DM9000_iow(DM9000_TXPLL, length & 0xff);
+ DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
+
+ /* Issue TX polling command */
+ DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
+
+ /* wait for end of transmission */
+ tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
+ while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
+ !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
+ if (get_timer(0) >= tmo) {
+ printf("transmission timeout\n");
+ break;
+ }
+ }
+ DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
+
+ DM9000_DBG("transmit done\n\n");
+ return 0;
+}
+
+/*
+ Stop the interface.
+ The interface is stopped when it is brought.
+*/
+static void dm9000_halt(struct eth_device *netdev)
+{
+ DM9000_DBG("%s\n", __func__);
+
+ /* RESET devie */
+ dm9000_phy_write(0, 0x8000); /* PHY RESET */
+ DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
+ DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
+ DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
+}
+
+/*
+ Received a packet and pass to upper layer
+*/
+static int dm9000_rx(struct eth_device *netdev)
+{
+ u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
+ u16 RxStatus, RxLen = 0;
+ struct board_info *db = &dm9000_info;
+
+ /* Check packet ready or not, we must check
+ the ISR status first for DM9000A */
+ if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
+ return 0;
+
+ DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
+
+ /* There is _at least_ 1 package in the fifo, read them all */
+ for (;;) {
+ DM9000_ior(DM9000_MRCMDX); /* Dummy read */
+
+ /* Get most updated data,
+ only look at bits 0:1, See application notes DM9000 */
+ rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
+
+ /* Status check: this byte must be 0 or 1 */
+ if (rxbyte > DM9000_PKT_RDY) {
+ DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
+ DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
+ printf("DM9000 error: status check fail: 0x%x\n",
+ rxbyte);
+ return 0;
+ }
+
+ if (rxbyte != DM9000_PKT_RDY)
+ return 0; /* No packet received, ignore */
+
+ DM9000_DBG("receiving packet\n");
+
+ /* A packet ready now & Get status/length */
+ (db->rx_status)(&RxStatus, &RxLen);
+
+ DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
+
+ /* Move data from DM9000 */
+ /* Read received packet from RX SRAM */
+ (db->inblk)(rdptr, RxLen);
+
+ if ((RxStatus & 0xbf00) || (RxLen < 0x40)
+ || (RxLen > DM9000_PKT_MAX)) {
+ if (RxStatus & 0x100) {
+ printf("rx fifo error\n");
+ }
+ if (RxStatus & 0x200) {
+ printf("rx crc error\n");
+ }
+ if (RxStatus & 0x8000) {
+ printf("rx length error\n");
+ }
+ if (RxLen > DM9000_PKT_MAX) {
+ printf("rx length too big\n");
+ dm9000_reset();
+ }
+ } else {
+ DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
+
+ DM9000_DBG("passing packet to upper layer\n");
+ NetReceive(NetRxPackets[0], RxLen);
+ }
+ }
+ return 0;
+}
+
+/*
+ Read a word data from SROM
+*/
+#if !defined(CONFIG_DM9000_NO_SROM)
+void dm9000_read_srom_word(int offset, u8 *to)
+{
+ DM9000_iow(DM9000_EPAR, offset);
+ DM9000_iow(DM9000_EPCR, 0x4);
+ udelay(8000);
+ DM9000_iow(DM9000_EPCR, 0x0);
+ to[0] = DM9000_ior(DM9000_EPDRL);
+ to[1] = DM9000_ior(DM9000_EPDRH);
+}
+
+void dm9000_write_srom_word(int offset, u16 val)
+{
+ DM9000_iow(DM9000_EPAR, offset);
+ DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
+ DM9000_iow(DM9000_EPDRL, (val & 0xff));
+ DM9000_iow(DM9000_EPCR, 0x12);
+ udelay(8000);
+ DM9000_iow(DM9000_EPCR, 0);
+}
+#endif
+
+static void dm9000_get_enetaddr(struct eth_device *dev)
+{
+#if !defined(CONFIG_DM9000_NO_SROM)
+ int i;
+ for (i = 0; i < 3; i++)
+ dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
+#endif
+}
+
+/*
+ Read a byte from I/O port
+*/
+static u8
+DM9000_ior(int reg)
+{
+ DM9000_outb(reg, DM9000_IO);
+ return DM9000_inb(DM9000_DATA);
+}
+
+/*
+ Write a byte to I/O port
+*/
+static void
+DM9000_iow(int reg, u8 value)
+{
+ DM9000_outb(reg, DM9000_IO);
+ DM9000_outb(value, DM9000_DATA);
+}
+
+/*
+ Read a word from phyxcer
+*/
+static u16
+dm9000_phy_read(int reg)
+{
+ u16 val;
+
+ /* Fill the phyxcer register into REG_0C */
+ DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
+ DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
+ udelay(100); /* Wait read complete */
+ DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
+ val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
+
+ /* The read data keeps on REG_0D & REG_0E */
+ DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
+ return val;
+}
+
+/*
+ Write a word to phyxcer
+*/
+static void
+dm9000_phy_write(int reg, u16 value)
+{
+
+ /* Fill the phyxcer register into REG_0C */
+ DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
+
+ /* Fill the written data into REG_0D & REG_0E */
+ DM9000_iow(DM9000_EPDRL, (value & 0xff));
+ DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
+ DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
+ udelay(500); /* Wait write complete */
+ DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
+ DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
+}
+
+int dm9000_initialize(bd_t *bis)
+{
+ struct eth_device *dev = &(dm9000_info.netdev);
+
+ /* Load MAC address from EEPROM */
+ dm9000_get_enetaddr(dev);
+
+ dev->init = dm9000_init;
+ dev->halt = dm9000_halt;
+ dev->send = dm9000_send;
+ dev->recv = dm9000_rx;
+ sprintf(dev->name, "dm9000");
+
+ eth_register(dev);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/dm9000x.h b/qemu/roms/u-boot/drivers/net/dm9000x.h
new file mode 100644
index 000000000..0d123e2e1
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/dm9000x.h
@@ -0,0 +1,140 @@
+/*
+ * dm9000 Ethernet
+ */
+
+#ifdef CONFIG_DRIVER_DM9000
+
+#define DM9000_ID 0x90000A46
+#define DM9000_PKT_MAX 1536 /* Received packet max size */
+#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */
+
+/* although the registers are 16 bit, they are 32-bit aligned.
+ */
+
+#define DM9000_NCR 0x00
+#define DM9000_NSR 0x01
+#define DM9000_TCR 0x02
+#define DM9000_TSR1 0x03
+#define DM9000_TSR2 0x04
+#define DM9000_RCR 0x05
+#define DM9000_RSR 0x06
+#define DM9000_ROCR 0x07
+#define DM9000_BPTR 0x08
+#define DM9000_FCTR 0x09
+#define DM9000_FCR 0x0A
+#define DM9000_EPCR 0x0B
+#define DM9000_EPAR 0x0C
+#define DM9000_EPDRL 0x0D
+#define DM9000_EPDRH 0x0E
+#define DM9000_WCR 0x0F
+
+#define DM9000_PAR 0x10
+#define DM9000_MAR 0x16
+
+#define DM9000_GPCR 0x1e
+#define DM9000_GPR 0x1f
+#define DM9000_TRPAL 0x22
+#define DM9000_TRPAH 0x23
+#define DM9000_RWPAL 0x24
+#define DM9000_RWPAH 0x25
+
+#define DM9000_VIDL 0x28
+#define DM9000_VIDH 0x29
+#define DM9000_PIDL 0x2A
+#define DM9000_PIDH 0x2B
+
+#define DM9000_CHIPR 0x2C
+#define DM9000_SMCR 0x2F
+
+#define DM9000_PHY 0x40 /* PHY address 0x01 */
+
+#define DM9000_MRCMDX 0xF0
+#define DM9000_MRCMD 0xF2
+#define DM9000_MRRL 0xF4
+#define DM9000_MRRH 0xF5
+#define DM9000_MWCMDX 0xF6
+#define DM9000_MWCMD 0xF8
+#define DM9000_MWRL 0xFA
+#define DM9000_MWRH 0xFB
+#define DM9000_TXPLL 0xFC
+#define DM9000_TXPLH 0xFD
+#define DM9000_ISR 0xFE
+#define DM9000_IMR 0xFF
+
+#define NCR_EXT_PHY (1<<7)
+#define NCR_WAKEEN (1<<6)
+#define NCR_FCOL (1<<4)
+#define NCR_FDX (1<<3)
+#define NCR_LBK (3<<1)
+#define NCR_LBK_INT_MAC (1<<1)
+#define NCR_LBK_INT_PHY (2<<1)
+#define NCR_RST (1<<0)
+
+#define NSR_SPEED (1<<7)
+#define NSR_LINKST (1<<6)
+#define NSR_WAKEST (1<<5)
+#define NSR_TX2END (1<<3)
+#define NSR_TX1END (1<<2)
+#define NSR_RXOV (1<<1)
+
+#define TCR_TJDIS (1<<6)
+#define TCR_EXCECM (1<<5)
+#define TCR_PAD_DIS2 (1<<4)
+#define TCR_CRC_DIS2 (1<<3)
+#define TCR_PAD_DIS1 (1<<2)
+#define TCR_CRC_DIS1 (1<<1)
+#define TCR_TXREQ (1<<0)
+
+#define TSR_TJTO (1<<7)
+#define TSR_LC (1<<6)
+#define TSR_NC (1<<5)
+#define TSR_LCOL (1<<4)
+#define TSR_COL (1<<3)
+#define TSR_EC (1<<2)
+
+#define RCR_WTDIS (1<<6)
+#define RCR_DIS_LONG (1<<5)
+#define RCR_DIS_CRC (1<<4)
+#define RCR_ALL (1<<3)
+#define RCR_RUNT (1<<2)
+#define RCR_PRMSC (1<<1)
+#define RCR_RXEN (1<<0)
+
+#define RSR_RF (1<<7)
+#define RSR_MF (1<<6)
+#define RSR_LCS (1<<5)
+#define RSR_RWTO (1<<4)
+#define RSR_PLE (1<<3)
+#define RSR_AE (1<<2)
+#define RSR_CE (1<<1)
+#define RSR_FOE (1<<0)
+
+#define EPCR_EPOS_PHY (1<<3)
+#define EPCR_EPOS_EE (0<<3)
+#define EPCR_ERPRR (1<<2)
+#define EPCR_ERPRW (1<<1)
+#define EPCR_ERRE (1<<0)
+
+#define FCTR_HWOT(ot) (( ot & 0xf ) << 4 )
+#define FCTR_LWOT(ot) ( ot & 0xf )
+
+#define BPTR_BPHW(x) ((x) << 4)
+#define BPTR_JPT_200US (0x07)
+#define BPTR_JPT_600US (0x0f)
+
+#define IMR_PAR (1<<7)
+#define IMR_ROOM (1<<3)
+#define IMR_ROM (1<<2)
+#define IMR_PTM (1<<1)
+#define IMR_PRM (1<<0)
+
+#define ISR_ROOS (1<<3)
+#define ISR_ROS (1<<2)
+#define ISR_PTS (1<<1)
+#define ISR_PRS (1<<0)
+
+#define GPCR_GPIO0_OUT (1<<0)
+
+#define GPR_PHY_PWROFF (1<<0)
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/dnet.c b/qemu/roms/u-boot/drivers/net/dnet.c
new file mode 100644
index 000000000..944a0c046
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/dnet.c
@@ -0,0 +1,392 @@
+/*
+ * Dave Ethernet Controller driver
+ *
+ * Copyright (C) 2008 Dave S.r.l. <www.dave.eu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+
+#ifndef CONFIG_DNET_AUTONEG_TIMEOUT
+#define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */
+#endif
+
+#include <net.h>
+#include <malloc.h>
+#include <linux/mii.h>
+
+#include <miiphy.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+#include "dnet.h"
+
+struct dnet_device {
+ struct dnet_registers *regs;
+ const struct device *dev;
+ struct eth_device netdev;
+ unsigned short phy_addr;
+};
+
+/* get struct dnet_device from given struct netdev */
+#define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev)
+
+/* function for reading internal MAC register */
+u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg)
+{
+ u16 data_read;
+
+ /* issue a read */
+ writel(reg, &dnet->regs->MACREG_ADDR);
+
+ /* since a read/write op to the MAC is very slow,
+ * we must wait before reading the data */
+ udelay(1);
+
+ /* read data read from the MAC register */
+ data_read = readl(&dnet->regs->MACREG_DATA);
+
+ /* all done */
+ return data_read;
+}
+
+/* function for writing internal MAC register */
+void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val)
+{
+ /* load data to write */
+ writel(val, &dnet->regs->MACREG_DATA);
+
+ /* issue a write */
+ writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR);
+
+ /* since a read/write op to the MAC is very slow,
+ * we must wait before exiting */
+ udelay(1);
+}
+
+static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value)
+{
+ u16 tmp;
+
+ debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n",
+ dnet->phy_addr, reg, value);
+
+ while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) &
+ DNET_INTERNAL_GMII_MNG_CMD_FIN))
+ ;
+
+ /* prepare for a write operation */
+ tmp = (1 << 13);
+
+ /* only 5 bits allowed for register offset */
+ reg &= 0x1f;
+
+ /* prepare reg_value for a write */
+ tmp |= (dnet->phy_addr << 8);
+ tmp |= reg;
+
+ /* write data to write first */
+ dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value);
+
+ /* write control word */
+ dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp);
+
+ while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) &
+ DNET_INTERNAL_GMII_MNG_CMD_FIN))
+ ;
+}
+
+static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg)
+{
+ u16 value;
+
+ while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) &
+ DNET_INTERNAL_GMII_MNG_CMD_FIN))
+ ;
+
+ /* only 5 bits allowed for register offset*/
+ reg &= 0x1f;
+
+ /* prepare reg_value for a read */
+ value = (dnet->phy_addr << 8);
+ value |= reg;
+
+ /* write control word */
+ dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value);
+
+ /* wait for end of transfer */
+ while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) &
+ DNET_INTERNAL_GMII_MNG_CMD_FIN))
+ ;
+
+ value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG);
+
+ debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n",
+ dnet->phy_addr, reg, value);
+
+ return value;
+}
+
+static int dnet_send(struct eth_device *netdev, void *packet, int length)
+{
+ struct dnet_device *dnet = to_dnet(netdev);
+ int i, wrsz;
+ unsigned int *bufp;
+ unsigned int tx_cmd;
+
+ debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length);
+
+ bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC);
+ wrsz = (u32)length + 3;
+ wrsz += ((u32)packet) & 0x3;
+ wrsz >>= 2;
+ tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length;
+
+ /* check if there is enough room for the current frame */
+ if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) {
+ for (i = 0; i < wrsz; i++)
+ writel(*bufp++, &dnet->regs->TX_DATA_FIFO);
+ /*
+ * inform MAC that a packet's written and ready
+ * to be shipped out
+ */
+ writel(tx_cmd, &dnet->regs->TX_LEN_FIFO);
+ } else {
+ printf(DRIVERNAME "No free space (actual %d, required %d "
+ "(words))\n", DNET_FIFO_SIZE -
+ readl(&dnet->regs->TX_FIFO_WCNT), wrsz);
+ }
+
+ /* No one cares anyway */
+ return 0;
+}
+
+
+static int dnet_recv(struct eth_device *netdev)
+{
+ struct dnet_device *dnet = to_dnet(netdev);
+ unsigned int *data_ptr;
+ int pkt_len, poll, i;
+ u32 cmd_word;
+
+ debug("Waiting for pkt (polling)\n");
+ poll = 50;
+ while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) {
+ udelay(10); /* wait 10 usec */
+ if (--poll == 0)
+ return 0; /* no pkt available */
+ }
+
+ cmd_word = readl(&dnet->regs->RX_LEN_FIFO);
+ pkt_len = cmd_word & 0xFFFF;
+
+ debug("Got pkt with size %d bytes\n", pkt_len);
+
+ if (cmd_word & 0xDF180000)
+ printf("%s packet receive error %x\n", __func__, cmd_word);
+
+ data_ptr = (unsigned int *) NetRxPackets[0];
+
+ for (i = 0; i < (pkt_len + 3) >> 2; i++)
+ *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO);
+
+ NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */
+
+ return 0;
+}
+
+static void dnet_set_hwaddr(struct eth_device *netdev)
+{
+ struct dnet_device *dnet = to_dnet(netdev);
+ u16 tmp;
+
+ tmp = get_unaligned_be16(netdev->enetaddr);
+ dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp);
+ tmp = get_unaligned_be16(&netdev->enetaddr[2]);
+ dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp);
+ tmp = get_unaligned_be16(&netdev->enetaddr[4]);
+ dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp);
+}
+
+static void dnet_phy_reset(struct dnet_device *dnet)
+{
+ struct eth_device *netdev = &dnet->netdev;
+ int i;
+ u16 status, adv;
+
+ adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+ dnet_mdio_write(dnet, MII_ADVERTISE, adv);
+ printf("%s: Starting autonegotiation...\n", netdev->name);
+ dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE
+ | BMCR_ANRESTART));
+
+ for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) {
+ status = dnet_mdio_read(dnet, MII_BMSR);
+ if (status & BMSR_ANEGCOMPLETE)
+ break;
+ udelay(100);
+ }
+
+ if (status & BMSR_ANEGCOMPLETE)
+ printf("%s: Autonegotiation complete\n", netdev->name);
+ else
+ printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+ netdev->name, status);
+}
+
+static int dnet_phy_init(struct dnet_device *dnet)
+{
+ struct eth_device *netdev = &dnet->netdev;
+ u16 phy_id, status, adv, lpa;
+ int media, speed, duplex;
+ int i;
+ u32 ctl_reg;
+
+ /* Find a PHY */
+ for (i = 0; i < 32; i++) {
+ dnet->phy_addr = i;
+ phy_id = dnet_mdio_read(dnet, MII_PHYSID1);
+ if (phy_id != 0xffff) {
+ /* ok we found it */
+ printf("Found PHY at address %d PHYID (%04x:%04x)\n",
+ i, phy_id,
+ dnet_mdio_read(dnet, MII_PHYSID2));
+ break;
+ }
+ }
+
+ /* Check if the PHY is up to snuff... */
+ phy_id = dnet_mdio_read(dnet, MII_PHYSID1);
+ if (phy_id == 0xffff) {
+ printf("%s: No PHY present\n", netdev->name);
+ return -1;
+ }
+
+ status = dnet_mdio_read(dnet, MII_BMSR);
+ if (!(status & BMSR_LSTATUS)) {
+ /* Try to re-negotiate if we don't have link already. */
+ dnet_phy_reset(dnet);
+
+ for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) {
+ status = dnet_mdio_read(dnet, MII_BMSR);
+ if (status & BMSR_LSTATUS)
+ break;
+ udelay(100);
+ }
+ }
+
+ if (!(status & BMSR_LSTATUS)) {
+ printf("%s: link down (status: 0x%04x)\n",
+ netdev->name, status);
+ return -1;
+ } else {
+ adv = dnet_mdio_read(dnet, MII_ADVERTISE);
+ lpa = dnet_mdio_read(dnet, MII_LPA);
+ media = mii_nway_result(lpa & adv);
+ speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+ ? 1 : 0);
+ duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+ /* 1000BaseT ethernet is not supported */
+ printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
+ netdev->name,
+ speed ? "100" : "10",
+ duplex ? "full" : "half",
+ lpa);
+
+ ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG);
+
+ if (duplex)
+ ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP);
+ else
+ ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP;
+
+ dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg);
+
+ return 0;
+ }
+}
+
+static int dnet_init(struct eth_device *netdev, bd_t *bd)
+{
+ struct dnet_device *dnet = to_dnet(netdev);
+ u32 config;
+
+ /*
+ * dnet_halt should have been called at some point before now,
+ * so we'll assume the controller is idle.
+ */
+
+ /* set hardware address */
+ dnet_set_hwaddr(netdev);
+
+ if (dnet_phy_init(dnet) < 0)
+ return -1;
+
+ /* flush rx/tx fifos */
+ writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH,
+ &dnet->regs->SYS_CTL);
+ udelay(1000);
+ writel(0, &dnet->regs->SYS_CTL);
+
+ config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG);
+
+ config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE |
+ DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST |
+ DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL |
+ DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS;
+
+ dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config);
+
+ /* Enable TX and RX */
+ dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG,
+ DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN);
+
+ return 0;
+}
+
+static void dnet_halt(struct eth_device *netdev)
+{
+ struct dnet_device *dnet = to_dnet(netdev);
+
+ /* Disable TX and RX */
+ dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0);
+}
+
+int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr)
+{
+ struct dnet_device *dnet;
+ struct eth_device *netdev;
+ unsigned int dev_capa;
+
+ dnet = malloc(sizeof(struct dnet_device));
+ if (!dnet) {
+ printf("Error: Failed to allocate memory for DNET%d\n", id);
+ return -1;
+ }
+ memset(dnet, 0, sizeof(struct dnet_device));
+
+ netdev = &dnet->netdev;
+
+ dnet->regs = (struct dnet_registers *)regs;
+ dnet->phy_addr = phy_addr;
+
+ sprintf(netdev->name, "dnet%d", id);
+ netdev->init = dnet_init;
+ netdev->halt = dnet_halt;
+ netdev->send = dnet_send;
+ netdev->recv = dnet_recv;
+
+ dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF;
+ debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name,
+ (dev_capa & DNET_HAS_MDIO) ? "" : "no ",
+ (dev_capa & DNET_HAS_IRQ) ? "" : "no ",
+ (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ",
+ (dev_capa & DNET_HAS_DMA) ? "" : "no ");
+
+ eth_register(netdev);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/dnet.h b/qemu/roms/u-boot/drivers/net/dnet.h
new file mode 100644
index 000000000..fdb4fd2d3
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/dnet.h
@@ -0,0 +1,166 @@
+/*
+ * Dave Ethernet Controller driver
+ *
+ * Copyright (C) 2008 Dave S.r.l. <www.dave.eu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_DNET_H__
+#define __DRIVERS_DNET_H__
+
+#define DRIVERNAME "dnet"
+
+struct dnet_registers {
+ /* ALL DNET FIFO REGISTERS */
+ u32 RX_LEN_FIFO;
+ u32 RX_DATA_FIFO;
+ u32 TX_LEN_FIFO;
+ u32 TX_DATA_FIFO;
+ u32 pad1[0x3c];
+ /* ALL DNET CONTROL/STATUS REGISTERS */
+ u32 VERCAPS;
+ u32 INTR_SRC;
+ u32 INTR_ENB;
+ u32 RX_STATUS;
+ u32 TX_STATUS;
+ u32 RX_FRAMES_CNT;
+ u32 TX_FRAMES_CNT;
+ u32 RX_FIFO_TH;
+ u32 TX_FIFO_TH;
+ u32 SYS_CTL;
+ u32 PAUSE_TMR;
+ u32 RX_FIFO_WCNT;
+ u32 TX_FIFO_WCNT;
+ u32 pad2[0x33];
+ /* ALL DNET MAC REGISTERS */
+ u32 MACREG_DATA; /* Mac-Reg Data */
+ u32 MACREG_ADDR; /* Mac-Reg Addr */
+ u32 pad3[0x3e];
+ /* ALL DNET RX STATISTICS COUNTERS */
+ u32 RX_PKT_IGNR_CNT;
+ u32 RX_LEN_CHK_ERR_CNT;
+ u32 RX_LNG_FRM_CNT;
+ u32 RX_SHRT_FRM_CNT;
+ u32 RX_IPG_VIOL_CNT;
+ u32 RX_CRC_ERR_CNT;
+ u32 RX_OK_PKT_CNT;
+ u32 RX_CTL_FRM_CNT;
+ u32 RX_PAUSE_FRM_CNT;
+ u32 RX_MULTICAST_CNT;
+ u32 RX_BROADCAST_CNT;
+ u32 RX_VLAN_TAG_CNT;
+ u32 RX_PRE_SHRINK_CNT;
+ u32 RX_DRIB_NIB_CNT;
+ u32 RX_UNSUP_OPCD_CNT;
+ u32 RX_BYTE_CNT;
+ u32 pad4[0x30];
+ /* DNET TX STATISTICS COUNTERS */
+ u32 TX_UNICAST_CNT;
+ u32 TX_PAUSE_FRM_CNT;
+ u32 TX_MULTICAST_CNT;
+ u32 TX_BRDCAST_CNT;
+ u32 TX_VLAN_TAG_CNT;
+ u32 TX_BAD_FCS_CNT;
+ u32 TX_JUMBO_CNT;
+ u32 TX_BYTE_CNT;
+};
+
+/* SOME INTERNAL MAC-CORE REGISTER */
+#define DNET_INTERNAL_MODE_REG 0x0
+#define DNET_INTERNAL_RXTX_CONTROL_REG 0x2
+#define DNET_INTERNAL_MAX_PKT_SIZE_REG 0x4
+#define DNET_INTERNAL_IGP_REG 0x8
+#define DNET_INTERNAL_MAC_ADDR_0_REG 0xa
+#define DNET_INTERNAL_MAC_ADDR_1_REG 0xc
+#define DNET_INTERNAL_MAC_ADDR_2_REG 0xe
+#define DNET_INTERNAL_TX_RX_STS_REG 0x12
+#define DNET_INTERNAL_GMII_MNG_CTL_REG 0x14
+#define DNET_INTERNAL_GMII_MNG_DAT_REG 0x16
+
+#define DNET_INTERNAL_GMII_MNG_CMD_FIN (1 << 14)
+
+#define DNET_INTERNAL_WRITE (1 << 31)
+
+/* MAC-CORE REGISTER FIELDS */
+
+/* MAC-CORE MODE REGISTER FIELDS */
+#define DNET_INTERNAL_MODE_GBITEN (1 << 0)
+#define DNET_INTERNAL_MODE_FCEN (1 << 1)
+#define DNET_INTERNAL_MODE_RXEN (1 << 2)
+#define DNET_INTERNAL_MODE_TXEN (1 << 3)
+
+/* MAC-CORE RXTX CONTROL REGISTER FIELDS */
+#define DNET_INTERNAL_RXTX_CONTROL_RXSHORTFRAME (1 << 8)
+#define DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST (1 << 7)
+#define DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST (1 << 4)
+#define DNET_INTERNAL_RXTX_CONTROL_RXPAUSE (1 << 3)
+#define DNET_INTERNAL_RXTX_CONTROL_DISTXFCS (1 << 2)
+#define DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS (1 << 1)
+#define DNET_INTERNAL_RXTX_CONTROL_ENPROMISC (1 << 0)
+#define DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL (1 << 6)
+#define DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP (1 << 5)
+
+/* SYSTEM CONTROL REGISTER FIELDS */
+#define DNET_SYS_CTL_IGNORENEXTPKT (1 << 0)
+#define DNET_SYS_CTL_SENDPAUSE (1 << 2)
+#define DNET_SYS_CTL_RXFIFOFLUSH (1 << 3)
+#define DNET_SYS_CTL_TXFIFOFLUSH (1 << 4)
+
+/* TX STATUS REGISTER FIELDS */
+#define DNET_TX_STATUS_FIFO_ALMOST_EMPTY (1 << 2)
+#define DNET_TX_STATUS_FIFO_ALMOST_FULL (1 << 1)
+
+/* INTERRUPT SOURCE REGISTER FIELDS */
+#define DNET_INTR_SRC_TX_PKTSENT (1 << 0)
+#define DNET_INTR_SRC_TX_FIFOAF (1 << 1)
+#define DNET_INTR_SRC_TX_FIFOAE (1 << 2)
+#define DNET_INTR_SRC_TX_DISCFRM (1 << 3)
+#define DNET_INTR_SRC_TX_FIFOFULL (1 << 4)
+#define DNET_INTR_SRC_RX_CMDFIFOAF (1 << 8)
+#define DNET_INTR_SRC_RX_CMDFIFOFF (1 << 9)
+#define DNET_INTR_SRC_RX_DATAFIFOFF (1 << 10)
+#define DNET_INTR_SRC_TX_SUMMARY (1 << 16)
+#define DNET_INTR_SRC_RX_SUMMARY (1 << 17)
+#define DNET_INTR_SRC_PHY (1 << 19)
+
+/* INTERRUPT ENABLE REGISTER FIELDS */
+#define DNET_INTR_ENB_TX_PKTSENT (1 << 0)
+#define DNET_INTR_ENB_TX_FIFOAF (1 << 1)
+#define DNET_INTR_ENB_TX_FIFOAE (1 << 2)
+#define DNET_INTR_ENB_TX_DISCFRM (1 << 3)
+#define DNET_INTR_ENB_TX_FIFOFULL (1 << 4)
+#define DNET_INTR_ENB_RX_PKTRDY (1 << 8)
+#define DNET_INTR_ENB_RX_FIFOAF (1 << 9)
+#define DNET_INTR_ENB_RX_FIFOERR (1 << 10)
+#define DNET_INTR_ENB_RX_ERROR (1 << 11)
+#define DNET_INTR_ENB_RX_FIFOFULL (1 << 12)
+#define DNET_INTR_ENB_RX_FIFOAE (1 << 13)
+#define DNET_INTR_ENB_TX_SUMMARY (1 << 16)
+#define DNET_INTR_ENB_RX_SUMMARY (1 << 17)
+#define DNET_INTR_ENB_GLOBAL_ENABLE (1 << 18)
+
+/*
+ * Capabilities. Used by the driver to know the capabilities that
+ * the ethernet controller inside the FPGA have.
+ */
+
+#define DNET_HAS_MDIO (1 << 0)
+#define DNET_HAS_IRQ (1 << 1)
+#define DNET_HAS_GIGABIT (1 << 2)
+#define DNET_HAS_DMA (1 << 3)
+
+#define DNET_HAS_MII (1 << 4) /* or GMII */
+#define DNET_HAS_RMII (1 << 5) /* or RGMII */
+
+#define DNET_CAPS_MASK 0xFFFF
+
+#define DNET_FIFO_SIZE 2048 /* 2K x 32 bit */
+#define DNET_FIFO_TX_DATA_AF_TH (DNET_FIFO_SIZE - 384) /* 384 = 1536 / 4 */
+#define DNET_FIFO_TX_DATA_AE_TH (384)
+
+#define DNET_FIFO_RX_CMD_AF_TH (1 << 16) /* just one frame inside the FIFO */
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/e1000.c b/qemu/roms/u-boot/drivers/net/e1000.c
new file mode 100644
index 000000000..9d9b259d6
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/e1000.c
@@ -0,0 +1,5307 @@
+/**************************************************************************
+Intel Pro 1000 for ppcboot/das-u-boot
+Drivers are port from Intel's Linux driver e1000-4.3.15
+and from Etherboot pro 1000 driver by mrakes at vivato dot net
+tested on both gig copper and gig fiber boards
+***************************************************************************/
+/*******************************************************************************
+
+
+ Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+
+ * SPDX-License-Identifier: GPL-2.0+
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+/*
+ * Copyright (C) Archway Digital Solutions.
+ *
+ * written by Chrsitopher Li <cli at arcyway dot com> or <chrisl at gnuchina dot org>
+ * 2/9/2002
+ *
+ * Copyright (C) Linux Networx.
+ * Massive upgrade to work with the new intel gigabit NICs.
+ * <ebiederman at lnxi dot com>
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ */
+
+#include "e1000.h"
+
+#define TOUT_LOOP 100000
+
+#define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v))
+#define bus_to_phys(devno, a) pci_mem_to_phys(devno, a)
+
+#define E1000_DEFAULT_PCI_PBA 0x00000030
+#define E1000_DEFAULT_PCIE_PBA 0x000a0026
+
+/* NIC specific static variables go here */
+
+static char tx_pool[128 + 16];
+static char rx_pool[128 + 16];
+static char packet[2096];
+
+static struct e1000_tx_desc *tx_base;
+static struct e1000_rx_desc *rx_base;
+
+static int tx_tail;
+static int rx_tail, rx_last;
+
+static struct pci_device_id e1000_supported[] = {
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82542},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82543GC_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82543GC_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544EI_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544EI_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544GC_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544GC_LOM},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545GM_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546GB_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541GI_LF},
+ /* E1000 PCIe card */
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_FIBER },
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES },
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571PT_QUAD_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_COPPER_LOWPROFILE},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES_DUAL},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES_QUAD},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_SERDES},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573E},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573E_IAMT},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573L},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82574L},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546GB_QUAD_COPPER_KSP3},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_COPPER_DPT},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_SERDES_DPT},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_COPPER_SPT},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_SERDES_SPT},
+ {}
+};
+
+/* Function forward declarations */
+static int e1000_setup_link(struct eth_device *nic);
+static int e1000_setup_fiber_link(struct eth_device *nic);
+static int e1000_setup_copper_link(struct eth_device *nic);
+static int e1000_phy_setup_autoneg(struct e1000_hw *hw);
+static void e1000_config_collision_dist(struct e1000_hw *hw);
+static int e1000_config_mac_to_phy(struct e1000_hw *hw);
+static int e1000_config_fc_after_link_up(struct e1000_hw *hw);
+static int e1000_check_for_link(struct eth_device *nic);
+static int e1000_wait_autoneg(struct e1000_hw *hw);
+static int e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed,
+ uint16_t * duplex);
+static int e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
+ uint16_t * phy_data);
+static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
+ uint16_t phy_data);
+static int32_t e1000_phy_hw_reset(struct e1000_hw *hw);
+static int e1000_phy_reset(struct e1000_hw *hw);
+static int e1000_detect_gig_phy(struct e1000_hw *hw);
+static void e1000_set_media_type(struct e1000_hw *hw);
+
+static int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
+static int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
+
+#ifndef CONFIG_E1000_NO_NVM
+static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
+static int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words,
+ uint16_t *data);
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
+{
+ /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+ * wait 50 microseconds.
+ */
+ *eecd = *eecd | E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(50);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
+{
+ /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+ * wait 50 microseconds.
+ */
+ *eecd = *eecd & ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(50);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count)
+{
+ uint32_t eecd;
+ uint32_t mask;
+
+ /* We need to shift "count" bits out to the EEPROM. So, value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01 << (count - 1);
+ eecd = E1000_READ_REG(hw, EECD);
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ do {
+ /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+ * and then raising and then lowering the clock (the SK bit controls
+ * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
+ * by setting "DI" to "0" and then raising and then lowering the clock.
+ */
+ eecd &= ~E1000_EECD_DI;
+
+ if (data & mask)
+ eecd |= E1000_EECD_DI;
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+
+ udelay(50);
+
+ e1000_raise_ee_clk(hw, &eecd);
+ e1000_lower_ee_clk(hw, &eecd);
+
+ mask = mask >> 1;
+
+ } while (mask);
+
+ /* We leave the "DI" bit set to "0" when we leave this routine. */
+ eecd &= ~E1000_EECD_DI;
+ E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count)
+{
+ uint32_t eecd;
+ uint32_t i;
+ uint16_t data;
+
+ /* In order to read a register from the EEPROM, we need to shift 'count'
+ * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+ * input to the EEPROM (setting the SK bit), and then reading the
+ * value of the "DO" bit. During this "shifting in" process the
+ * "DI" bit should always be clear.
+ */
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for (i = 0; i < count; i++) {
+ data = data << 1;
+ e1000_raise_ee_clk(hw, &eecd);
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DI);
+ if (eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_ee_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void e1000_standby_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if (eeprom->type == e1000_eeprom_microwire) {
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+
+ /* Clock high */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+
+ /* Clock low */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ } else if (eeprom->type == e1000_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ }
+}
+
+/***************************************************************************
+* Description: Determines if the onboard NVM is FLASH or EEPROM.
+*
+* hw - Struct containing variables accessed by shared code
+****************************************************************************/
+static bool e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
+{
+ uint32_t eecd = 0;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type == e1000_ich8lan)
+ return false;
+
+ if (hw->mac_type == e1000_82573 || hw->mac_type == e1000_82574) {
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Isolate bits 15 & 16 */
+ eecd = ((eecd >> 15) & 0x03);
+
+ /* If both bits are set, device is Flash type */
+ if (eecd == 0x03)
+ return false;
+ }
+ return true;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+int32_t e1000_acquire_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd, i = 0;
+
+ DEBUGFUNC();
+
+ if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM))
+ return -E1000_ERR_SWFW_SYNC;
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if (hw->mac_type != e1000_82573 || hw->mac_type != e1000_82574) {
+ /* Request EEPROM Access */
+ if (hw->mac_type > e1000_82544) {
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+ while ((!(eecd & E1000_EECD_GNT)) &&
+ (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+ i++;
+ udelay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if (!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ return -E1000_ERR_EEPROM;
+ }
+ }
+ }
+
+ /* Setup EEPROM for Read/Write */
+
+ if (eeprom->type == e1000_eeprom_microwire) {
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ } else if (eeprom->type == e1000_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ udelay(1);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Sets up eeprom variables in the hw struct. Must be called after mac_type
+ * is configured. Additionally, if this is ICH8, the flash controller GbE
+ * registers must be mapped, or this will crash.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd = E1000_READ_REG(hw, EECD);
+ int32_t ret_val = E1000_SUCCESS;
+ uint16_t eeprom_size;
+
+ DEBUGFUNC();
+
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+ case e1000_82544:
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->word_size = 64;
+ eeprom->opcode_bits = 3;
+ eeprom->address_bits = 6;
+ eeprom->delay_usec = 50;
+ eeprom->use_eerd = false;
+ eeprom->use_eewr = false;
+ break;
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82545_rev_3:
+ case e1000_82546:
+ case e1000_82546_rev_3:
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if (eecd & E1000_EECD_SIZE) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
+ }
+ eeprom->use_eerd = false;
+ eeprom->use_eewr = false;
+ break;
+ case e1000_82541:
+ case e1000_82541_rev_2:
+ case e1000_82547:
+ case e1000_82547_rev_2:
+ if (eecd & E1000_EECD_TYPE) {
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ } else {
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
+ }
+ }
+ eeprom->use_eerd = false;
+ eeprom->use_eewr = false;
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = false;
+ eeprom->use_eewr = false;
+ break;
+ case e1000_82573:
+ case e1000_82574:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = true;
+ eeprom->use_eewr = true;
+ if (e1000_is_onboard_nvm_eeprom(hw) == false) {
+ eeprom->type = e1000_eeprom_flash;
+ eeprom->word_size = 2048;
+
+ /* Ensure that the Autonomous FLASH update bit is cleared due to
+ * Flash update issue on parts which use a FLASH for NVM. */
+ eecd &= ~E1000_EECD_AUPDEN;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+ break;
+ case e1000_80003es2lan:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = true;
+ eeprom->use_eewr = false;
+ break;
+
+ /* ich8lan does not support currently. if needed, please
+ * add corresponding code and functions.
+ */
+#if 0
+ case e1000_ich8lan:
+ {
+ int32_t i = 0;
+
+ eeprom->type = e1000_eeprom_ich8;
+ eeprom->use_eerd = false;
+ eeprom->use_eewr = false;
+ eeprom->word_size = E1000_SHADOW_RAM_WORDS;
+ uint32_t flash_size = E1000_READ_ICH_FLASH_REG(hw,
+ ICH_FLASH_GFPREG);
+ /* Zero the shadow RAM structure. But don't load it from NVM
+ * so as to save time for driver init */
+ if (hw->eeprom_shadow_ram != NULL) {
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ hw->eeprom_shadow_ram[i].modified = false;
+ hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+ }
+ }
+
+ hw->flash_base_addr = (flash_size & ICH_GFPREG_BASE_MASK) *
+ ICH_FLASH_SECTOR_SIZE;
+
+ hw->flash_bank_size = ((flash_size >> 16)
+ & ICH_GFPREG_BASE_MASK) + 1;
+ hw->flash_bank_size -= (flash_size & ICH_GFPREG_BASE_MASK);
+
+ hw->flash_bank_size *= ICH_FLASH_SECTOR_SIZE;
+
+ hw->flash_bank_size /= 2 * sizeof(uint16_t);
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+
+ if (eeprom->type == e1000_eeprom_spi) {
+ /* eeprom_size will be an enum [0..8] that maps
+ * to eeprom sizes 128B to
+ * 32KB (incremented by powers of 2).
+ */
+ if (hw->mac_type <= e1000_82547_rev_2) {
+ /* Set to default value for initial eeprom read. */
+ eeprom->word_size = 64;
+ ret_val = e1000_read_eeprom(hw, EEPROM_CFG, 1,
+ &eeprom_size);
+ if (ret_val)
+ return ret_val;
+ eeprom_size = (eeprom_size & EEPROM_SIZE_MASK)
+ >> EEPROM_SIZE_SHIFT;
+ /* 256B eeprom size was not supported in earlier
+ * hardware, so we bump eeprom_size up one to
+ * ensure that "1" (which maps to 256B) is never
+ * the result used in the shifting logic below. */
+ if (eeprom_size)
+ eeprom_size++;
+ } else {
+ eeprom_size = (uint16_t)((eecd &
+ E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+ }
+
+ eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT);
+ }
+ return ret_val;
+}
+
+/******************************************************************************
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd)
+{
+ uint32_t attempts = 100000;
+ uint32_t i, reg = 0;
+ int32_t done = E1000_ERR_EEPROM;
+
+ for (i = 0; i < attempts; i++) {
+ if (eerd == E1000_EEPROM_POLL_READ)
+ reg = E1000_READ_REG(hw, EERD);
+ else
+ reg = E1000_READ_REG(hw, EEWR);
+
+ if (reg & E1000_EEPROM_RW_REG_DONE) {
+ done = E1000_SUCCESS;
+ break;
+ }
+ udelay(5);
+ }
+
+ return done;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+static int32_t
+e1000_read_eeprom_eerd(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ uint32_t i, eerd = 0;
+ int32_t error = 0;
+
+ for (i = 0; i < words; i++) {
+ eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
+ E1000_EEPROM_RW_REG_START;
+
+ E1000_WRITE_REG(hw, EERD, eerd);
+ error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
+
+ if (error)
+ break;
+ data[i] = (E1000_READ_REG(hw, EERD) >>
+ E1000_EEPROM_RW_REG_DATA);
+
+ }
+
+ return error;
+}
+
+void e1000_release_eeprom(struct e1000_hw *hw)
+{
+ uint32_t eecd;
+
+ DEBUGFUNC();
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if (hw->eeprom.type == e1000_eeprom_spi) {
+ eecd |= E1000_EECD_CS; /* Pull CS high */
+ eecd &= ~E1000_EECD_SK; /* Lower SCK */
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ udelay(hw->eeprom.delay_usec);
+ } else if (hw->eeprom.type == e1000_eeprom_microwire) {
+ /* cleanup eeprom */
+
+ /* CS on Microwire is active-high */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Rising edge of clock */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+
+ /* Falling edge of clock */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+ }
+
+ /* Stop requesting EEPROM access */
+ if (hw->mac_type > e1000_82544) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+}
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+e1000_spi_eeprom_ready(struct e1000_hw *hw)
+{
+ uint16_t retry_count = 0;
+ uint8_t spi_stat_reg;
+
+ DEBUGFUNC();
+
+ /* Read "Status Register" repeatedly until the LSB is cleared. The
+ * EEPROM will signal that the command has been completed by clearing
+ * bit 0 of the internal status register. If it's not cleared within
+ * 5 milliseconds, then error out.
+ */
+ retry_count = 0;
+ do {
+ e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+ hw->eeprom.opcode_bits);
+ spi_stat_reg = (uint8_t)e1000_shift_in_ee_bits(hw, 8);
+ if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+ break;
+
+ udelay(5);
+ retry_count += 5;
+
+ e1000_standby_eeprom(hw);
+ } while (retry_count < EEPROM_MAX_RETRY_SPI);
+
+ /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+ * only 0-5mSec on 5V devices)
+ */
+ if (retry_count >= EEPROM_MAX_RETRY_SPI) {
+ DEBUGOUT("SPI EEPROM Status error\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ *****************************************************************************/
+static int32_t
+e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t i = 0;
+
+ DEBUGFUNC();
+
+ /* If eeprom is not yet detected, do so now */
+ if (eeprom->word_size == 0)
+ e1000_init_eeprom_params(hw);
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= eeprom->word_size) ||
+ (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("\"words\" parameter out of bounds."
+ "Words = %d, size = %d\n", offset, eeprom->word_size);
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* EEPROM's that don't use EERD to read require us to bit-bang the SPI
+ * directly. In this case, we need to acquire the EEPROM so that
+ * FW or other port software does not interrupt.
+ */
+ if (e1000_is_onboard_nvm_eeprom(hw) == true &&
+ hw->eeprom.use_eerd == false) {
+
+ /* Prepare the EEPROM for bit-bang reading */
+ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Eerd register EEPROM access requires no eeprom aquire/release */
+ if (eeprom->use_eerd == true)
+ return e1000_read_eeprom_eerd(hw, offset, words, data);
+
+ /* ich8lan does not support currently. if needed, please
+ * add corresponding code and functions.
+ */
+#if 0
+ /* ICH EEPROM access is done via the ICH flash controller */
+ if (eeprom->type == e1000_eeprom_ich8)
+ return e1000_read_eeprom_ich8(hw, offset, words, data);
+#endif
+ /* Set up the SPI or Microwire EEPROM for bit-bang reading. We have
+ * acquired the EEPROM at this point, so any returns should relase it */
+ if (eeprom->type == e1000_eeprom_spi) {
+ uint16_t word_in;
+ uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
+
+ if (e1000_spi_eeprom_ready(hw)) {
+ e1000_release_eeprom(hw);
+ return -E1000_ERR_EEPROM;
+ }
+
+ e1000_standby_eeprom(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in
+ * the opcode */
+ if ((eeprom->address_bits == 8) && (offset >= 128))
+ read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2),
+ eeprom->address_bits);
+
+ /* Read the data. The address of the eeprom internally
+ * increments with each byte (spi) being read, saving on the
+ * overhead of eeprom setup and tear-down. The address
+ * counter will roll over if reading beyond the size of
+ * the eeprom, thus allowing the entire memory to be read
+ * starting from any offset. */
+ for (i = 0; i < words; i++) {
+ word_in = e1000_shift_in_ee_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
+ } else if (eeprom->type == e1000_eeprom_microwire) {
+ for (i = 0; i < words; i++) {
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw,
+ EEPROM_READ_OPCODE_MICROWIRE,
+ eeprom->opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset + i),
+ eeprom->address_bits);
+
+ /* Read the data. For microwire, each word requires
+ * the overhead of eeprom setup and tear-down. */
+ data[i] = e1000_shift_in_ee_bits(hw, 16);
+ e1000_standby_eeprom(hw);
+ }
+ }
+
+ /* End this read operation */
+ e1000_release_eeprom(hw);
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+static int e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+{
+ uint16_t i, checksum, checksum_reg, *buf;
+
+ DEBUGFUNC();
+
+ /* Allocate a temporary buffer */
+ buf = malloc(sizeof(buf[0]) * (EEPROM_CHECKSUM_REG + 1));
+ if (!buf) {
+ E1000_ERR(hw->nic, "Unable to allocate EEPROM buffer!\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Read the EEPROM */
+ if (e1000_read_eeprom(hw, 0, EEPROM_CHECKSUM_REG + 1, buf) < 0) {
+ E1000_ERR(hw->nic, "Unable to read EEPROM!\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Compute the checksum */
+ checksum = 0;
+ for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
+ checksum += buf[i];
+ checksum = ((uint16_t)EEPROM_SUM) - checksum;
+ checksum_reg = buf[i];
+
+ /* Verify it! */
+ if (checksum == checksum_reg)
+ return 0;
+
+ /* Hrm, verification failed, print an error */
+ E1000_ERR(hw->nic, "EEPROM checksum is incorrect!\n");
+ E1000_ERR(hw->nic, " ...register was 0x%04hx, calculated 0x%04hx\n",
+ checksum_reg, checksum);
+
+ return -E1000_ERR_EEPROM;
+}
+#endif /* CONFIG_E1000_NO_NVM */
+
+/*****************************************************************************
+ * Set PHY to class A mode
+ * Assumes the following operations will follow to enable the new class mode.
+ * 1. Do a PHY soft reset
+ * 2. Restart auto-negotiation or force link.
+ *
+ * hw - Struct containing variables accessed by shared code
+ ****************************************************************************/
+static int32_t
+e1000_set_phy_mode(struct e1000_hw *hw)
+{
+#ifndef CONFIG_E1000_NO_NVM
+ int32_t ret_val;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC();
+
+ if ((hw->mac_type == e1000_82545_rev_3) &&
+ (hw->media_type == e1000_media_type_copper)) {
+ ret_val = e1000_read_eeprom(hw, EEPROM_PHY_CLASS_WORD,
+ 1, &eeprom_data);
+ if (ret_val)
+ return ret_val;
+
+ if ((eeprom_data != EEPROM_RESERVED_WORD) &&
+ (eeprom_data & EEPROM_PHY_CLASS_A)) {
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_PHY_PAGE_SELECT, 0x000B);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_PHY_GEN_CONTROL, 0x8104);
+ if (ret_val)
+ return ret_val;
+
+ hw->phy_reset_disable = false;
+ }
+ }
+#endif
+ return E1000_SUCCESS;
+}
+
+#ifndef CONFIG_E1000_NO_NVM
+/***************************************************************************
+ *
+ * Obtaining software semaphore bit (SMBI) before resetting PHY.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to obtain semaphore.
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_software_semaphore(struct e1000_hw *hw)
+{
+ int32_t timeout = hw->eeprom.word_size + 1;
+ uint32_t swsm;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type != e1000_80003es2lan)
+ return E1000_SUCCESS;
+
+ while (timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ /* If SMBI bit cleared, it is now set and we hold
+ * the semaphore */
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+ mdelay(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return E1000_SUCCESS;
+}
+#endif
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+static void
+e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+#ifndef CONFIG_E1000_NO_NVM
+ uint32_t swsm;
+
+ DEBUGFUNC();
+
+ if (!hw->eeprom_semaphore_present)
+ return;
+
+ swsm = E1000_READ_REG(hw, SWSM);
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Release both semaphores. */
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ } else
+ swsm &= ~(E1000_SWSM_SWESMBI);
+ E1000_WRITE_REG(hw, SWSM, swsm);
+#endif
+}
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+#ifndef CONFIG_E1000_NO_NVM
+ int32_t timeout;
+ uint32_t swsm;
+
+ DEBUGFUNC();
+
+ if (!hw->eeprom_semaphore_present)
+ return E1000_SUCCESS;
+
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Get the SW semaphore. */
+ if (e1000_get_software_semaphore(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Get the FW semaphore. */
+ timeout = hw->eeprom.word_size + 1;
+ while (timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ swsm |= E1000_SWSM_SWESMBI;
+ E1000_WRITE_REG(hw, SWSM, swsm);
+ /* if we managed to set the bit we got the semaphore. */
+ swsm = E1000_READ_REG(hw, SWSM);
+ if (swsm & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ timeout--;
+ }
+
+ if (!timeout) {
+ /* Release semaphores */
+ e1000_put_hw_eeprom_semaphore(hw);
+ DEBUGOUT("Driver can't access the Eeprom - "
+ "SWESMBI bit is set.\n");
+ return -E1000_ERR_EEPROM;
+ }
+#endif
+ return E1000_SUCCESS;
+}
+
+static int32_t
+e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
+{
+ uint32_t swfw_sync = 0;
+ uint32_t swmask = mask;
+ uint32_t fwmask = mask << 16;
+ int32_t timeout = 200;
+
+ DEBUGFUNC();
+ while (timeout) {
+ if (e1000_get_hw_eeprom_semaphore(hw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /* firmware currently using resource (fwmask) */
+ /* or other software thread currently using resource (swmask) */
+ e1000_put_hw_eeprom_semaphore(hw);
+ mdelay(5);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ return -E1000_ERR_SWFW_SYNC;
+ }
+
+ swfw_sync |= swmask;
+ E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_eeprom_semaphore(hw);
+ return E1000_SUCCESS;
+}
+
+static bool e1000_is_second_port(struct e1000_hw *hw)
+{
+ switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ case e1000_82546:
+ case e1000_82571:
+ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+ return true;
+ /* Fallthrough */
+ default:
+ return false;
+ }
+}
+
+#ifndef CONFIG_E1000_NO_NVM
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * nic - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int
+e1000_read_mac_addr(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ uint16_t offset;
+ uint16_t eeprom_data;
+ int i;
+
+ DEBUGFUNC();
+
+ for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+ offset = i >> 1;
+ if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ nic->enetaddr[i] = eeprom_data & 0xff;
+ nic->enetaddr[i + 1] = (eeprom_data >> 8) & 0xff;
+ }
+
+ /* Invert the last bit if this is the second device */
+ if (e1000_is_second_port(hw))
+ nic->enetaddr[5] ^= 1;
+
+#ifdef CONFIG_E1000_FALLBACK_MAC
+ if (!is_valid_ether_addr(nic->enetaddr)) {
+ unsigned char fb_mac[NODE_ADDRESS_SIZE] = CONFIG_E1000_FALLBACK_MAC;
+
+ memcpy (nic->enetaddr, fb_mac, NODE_ADDRESS_SIZE);
+ }
+#endif
+ return 0;
+}
+#endif
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+static void
+e1000_init_rx_addrs(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ uint32_t i;
+ uint32_t addr_low;
+ uint32_t addr_high;
+
+ DEBUGFUNC();
+
+ /* Setup the receive address. */
+ DEBUGOUT("Programming MAC Address into RAR[0]\n");
+ addr_low = (nic->enetaddr[0] |
+ (nic->enetaddr[1] << 8) |
+ (nic->enetaddr[2] << 16) | (nic->enetaddr[3] << 24));
+
+ addr_high = (nic->enetaddr[4] | (nic->enetaddr[5] << 8) | E1000_RAH_AV);
+
+ E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
+ E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
+
+ /* Zero out the other 15 receive addresses. */
+ DEBUGOUT("Clearing RAR[1-15]\n");
+ for (i = 1; i < E1000_RAR_ENTRIES; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_clear_vfta(struct e1000_hw *hw)
+{
+ uint32_t offset;
+
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+}
+
+/******************************************************************************
+ * Set the mac type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_set_mac_type(struct e1000_hw *hw)
+{
+ DEBUGFUNC();
+
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82542:
+ switch (hw->revision_id) {
+ case E1000_82542_2_0_REV_ID:
+ hw->mac_type = e1000_82542_rev2_0;
+ break;
+ case E1000_82542_2_1_REV_ID:
+ hw->mac_type = e1000_82542_rev2_1;
+ break;
+ default:
+ /* Invalid 82542 revision ID */
+ return -E1000_ERR_MAC_TYPE;
+ }
+ break;
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ hw->mac_type = e1000_82543;
+ break;
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ hw->mac_type = e1000_82544;
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
+ hw->mac_type = e1000_82540;
+ break;
+ case E1000_DEV_ID_82545EM_COPPER:
+ case E1000_DEV_ID_82545EM_FIBER:
+ hw->mac_type = e1000_82545;
+ break;
+ case E1000_DEV_ID_82545GM_COPPER:
+ case E1000_DEV_ID_82545GM_FIBER:
+ case E1000_DEV_ID_82545GM_SERDES:
+ hw->mac_type = e1000_82545_rev_3;
+ break;
+ case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
+ hw->mac_type = e1000_82546;
+ break;
+ case E1000_DEV_ID_82546GB_COPPER:
+ case E1000_DEV_ID_82546GB_FIBER:
+ case E1000_DEV_ID_82546GB_SERDES:
+ case E1000_DEV_ID_82546GB_PCIE:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+ hw->mac_type = e1000_82546_rev_3;
+ break;
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541EI_MOBILE:
+ case E1000_DEV_ID_82541ER_LOM:
+ hw->mac_type = e1000_82541;
+ break;
+ case E1000_DEV_ID_82541ER:
+ case E1000_DEV_ID_82541GI:
+ case E1000_DEV_ID_82541GI_LF:
+ case E1000_DEV_ID_82541GI_MOBILE:
+ hw->mac_type = e1000_82541_rev_2;
+ break;
+ case E1000_DEV_ID_82547EI:
+ case E1000_DEV_ID_82547EI_MOBILE:
+ hw->mac_type = e1000_82547;
+ break;
+ case E1000_DEV_ID_82547GI:
+ hw->mac_type = e1000_82547_rev_2;
+ break;
+ case E1000_DEV_ID_82571EB_COPPER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES_DUAL:
+ case E1000_DEV_ID_82571EB_SERDES_QUAD:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571PT_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
+ hw->mac_type = e1000_82571;
+ break;
+ case E1000_DEV_ID_82572EI_COPPER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82572EI_SERDES:
+ case E1000_DEV_ID_82572EI:
+ hw->mac_type = e1000_82572;
+ break;
+ case E1000_DEV_ID_82573E:
+ case E1000_DEV_ID_82573E_IAMT:
+ case E1000_DEV_ID_82573L:
+ hw->mac_type = e1000_82573;
+ break;
+ case E1000_DEV_ID_82574L:
+ hw->mac_type = e1000_82574;
+ break;
+ case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
+ case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->mac_type = e1000_80003es2lan;
+ break;
+ case E1000_DEV_ID_ICH8_IGP_M_AMT:
+ case E1000_DEV_ID_ICH8_IGP_AMT:
+ case E1000_DEV_ID_ICH8_IGP_C:
+ case E1000_DEV_ID_ICH8_IFE:
+ case E1000_DEV_ID_ICH8_IFE_GT:
+ case E1000_DEV_ID_ICH8_IFE_G:
+ case E1000_DEV_ID_ICH8_IGP_M:
+ hw->mac_type = e1000_ich8lan;
+ break;
+ default:
+ /* Should never have loaded on this device */
+ return -E1000_ERR_MAC_TYPE;
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_reset_hw(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ctrl_ext;
+ uint32_t manc;
+ uint32_t pba = 0;
+
+ DEBUGFUNC();
+
+ /* get the correct pba value for both PCI and PCIe*/
+ if (hw->mac_type < e1000_82571)
+ pba = E1000_DEFAULT_PCI_PBA;
+ else
+ pba = E1000_DEFAULT_PCIE_PBA;
+
+ /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+ if (hw->mac_type == e1000_82542_rev2_0) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ pci_write_config_word(hw->pdev, PCI_COMMAND,
+ hw->pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
+ }
+
+ /* Clear interrupt mask to stop board from generating interrupts */
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+ /* Disable the Transmit and Receive units. Then delay to allow
+ * any pending transactions to complete before we hit the MAC with
+ * the global reset.
+ */
+ E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
+ hw->tbi_compatibility_on = false;
+
+ /* Delay to allow any outstanding PCI transactions to complete before
+ * resetting the device
+ */
+ mdelay(10);
+
+ /* Issue a global reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA, and link units. It will not effect
+ * the current PCI configuration. The global reset bit is self-
+ * clearing, and should clear within a microsecond.
+ */
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+
+ /* Force a reload from the EEPROM if necessary */
+ if (hw->mac_type < e1000_82540) {
+ /* Wait for reset to complete */
+ udelay(10);
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ /* Wait for EEPROM reload */
+ mdelay(2);
+ } else {
+ /* Wait for EEPROM reload (it happens automatically) */
+ mdelay(4);
+ /* Dissable HW ARPs on ASF enabled adapters */
+ manc = E1000_READ_REG(hw, MANC);
+ manc &= ~(E1000_MANC_ARP_EN);
+ E1000_WRITE_REG(hw, MANC, manc);
+ }
+
+ /* Clear interrupt mask to stop board from generating interrupts */
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+ /* Clear any pending interrupt events. */
+ E1000_READ_REG(hw, ICR);
+
+ /* If MWI was previously enabled, reenable it. */
+ if (hw->mac_type == e1000_82542_rev2_0) {
+ pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word);
+ }
+ E1000_WRITE_REG(hw, PBA, pba);
+}
+
+/******************************************************************************
+ *
+ * Initialize a number of hardware-dependent bits
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * This function contains hardware limitation workarounds for PCI-E adapters
+ *
+ *****************************************************************************/
+static void
+e1000_initialize_hardware_bits(struct e1000_hw *hw)
+{
+ if ((hw->mac_type >= e1000_82571) &&
+ (!hw->initialize_hw_bits_disable)) {
+ /* Settings common to all PCI-express silicon */
+ uint32_t reg_ctrl, reg_ctrl_ext;
+ uint32_t reg_tarc0, reg_tarc1;
+ uint32_t reg_tctl;
+ uint32_t reg_txdctl, reg_txdctl1;
+
+ /* link autonegotiation/sync workarounds */
+ reg_tarc0 = E1000_READ_REG(hw, TARC0);
+ reg_tarc0 &= ~((1 << 30)|(1 << 29)|(1 << 28)|(1 << 27));
+
+ /* Enable not-done TX descriptor counting */
+ reg_txdctl = E1000_READ_REG(hw, TXDCTL);
+ reg_txdctl |= E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, TXDCTL, reg_txdctl);
+
+ reg_txdctl1 = E1000_READ_REG(hw, TXDCTL1);
+ reg_txdctl1 |= E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, TXDCTL1, reg_txdctl1);
+
+ switch (hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ /* Clear PHY TX compatible mode bits */
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ reg_tarc1 &= ~((1 << 30)|(1 << 29));
+
+ /* link autonegotiation/sync workarounds */
+ reg_tarc0 |= ((1 << 26)|(1 << 25)|(1 << 24)|(1 << 23));
+
+ /* TX ring control fixes */
+ reg_tarc1 |= ((1 << 26)|(1 << 25)|(1 << 24));
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ case e1000_82573:
+ case e1000_82574:
+ reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ reg_ctrl_ext &= ~(1 << 23);
+ reg_ctrl_ext |= (1 << 22);
+
+ /* TX byte count fix */
+ reg_ctrl = E1000_READ_REG(hw, CTRL);
+ reg_ctrl &= ~(1 << 29);
+
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
+ E1000_WRITE_REG(hw, CTRL, reg_ctrl);
+ break;
+ case e1000_80003es2lan:
+ /* improve small packet performace for fiber/serdes */
+ if ((hw->media_type == e1000_media_type_fiber)
+ || (hw->media_type ==
+ e1000_media_type_internal_serdes)) {
+ reg_tarc0 &= ~(1 << 20);
+ }
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ case e1000_ich8lan:
+ /* Reduce concurrent DMA requests to 3 from 4 */
+ if ((hw->revision_id < 3) ||
+ ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
+ (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))
+ reg_tarc0 |= ((1 << 29)|(1 << 28));
+
+ reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ reg_ctrl_ext |= (1 << 22);
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
+
+ /* workaround TX hang with TSO=on */
+ reg_tarc0 |= ((1 << 27)|(1 << 26)|(1 << 24)|(1 << 23));
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ /* workaround TX hang with TSO=on */
+ reg_tarc1 |= ((1 << 30)|(1 << 26)|(1 << 24));
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ default:
+ break;
+ }
+
+ E1000_WRITE_REG(hw, TARC0, reg_tarc0);
+ }
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+static int
+e1000_init_hw(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ uint32_t ctrl;
+ uint32_t i;
+ int32_t ret_val;
+ uint16_t pcix_cmd_word;
+ uint16_t pcix_stat_hi_word;
+ uint16_t cmd_mmrbc;
+ uint16_t stat_mmrbc;
+ uint32_t mta_size;
+ uint32_t reg_data;
+ uint32_t ctrl_ext;
+ DEBUGFUNC();
+ /* force full DMA clock frequency for 10/100 on ICH8 A0-B0 */
+ if ((hw->mac_type == e1000_ich8lan) &&
+ ((hw->revision_id < 3) ||
+ ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
+ (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))) {
+ reg_data = E1000_READ_REG(hw, STATUS);
+ reg_data &= ~0x80000000;
+ E1000_WRITE_REG(hw, STATUS, reg_data);
+ }
+ /* Do not need initialize Identification LED */
+
+ /* Set the media type and TBI compatibility */
+ e1000_set_media_type(hw);
+
+ /* Must be called after e1000_set_media_type
+ * because media_type is used */
+ e1000_initialize_hardware_bits(hw);
+
+ /* Disabling VLAN filtering. */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
+ if (hw->mac_type != e1000_ich8lan) {
+ if (hw->mac_type < e1000_82545_rev_3)
+ E1000_WRITE_REG(hw, VET, 0);
+ e1000_clear_vfta(hw);
+ }
+
+ /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+ if (hw->mac_type == e1000_82542_rev2_0) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ pci_write_config_word(hw->pdev, PCI_COMMAND,
+ hw->
+ pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
+ E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+ E1000_WRITE_FLUSH(hw);
+ mdelay(5);
+ }
+
+ /* Setup the receive address. This involves initializing all of the Receive
+ * Address Registers (RARs 0 - 15).
+ */
+ e1000_init_rx_addrs(nic);
+
+ /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+ if (hw->mac_type == e1000_82542_rev2_0) {
+ E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_FLUSH(hw);
+ mdelay(1);
+ pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word);
+ }
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ mta_size = E1000_MC_TBL_SIZE;
+ if (hw->mac_type == e1000_ich8lan)
+ mta_size = E1000_MC_TBL_SIZE_ICH8LAN;
+ for (i = 0; i < mta_size; i++) {
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ /* use write flush to prevent Memory Write Block (MWB) from
+ * occuring when accessing our register space */
+ E1000_WRITE_FLUSH(hw);
+ }
+#if 0
+ /* Set the PCI priority bit correctly in the CTRL register. This
+ * determines if the adapter gives priority to receives, or if it
+ * gives equal priority to transmits and receives. Valid only on
+ * 82542 and 82543 silicon.
+ */
+ if (hw->dma_fairness && hw->mac_type <= e1000_82543) {
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+ }
+#endif
+ switch (hw->mac_type) {
+ case e1000_82545_rev_3:
+ case e1000_82546_rev_3:
+ break;
+ default:
+ /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+ if (hw->bus_type == e1000_bus_type_pcix) {
+ pci_read_config_word(hw->pdev, PCIX_COMMAND_REGISTER,
+ &pcix_cmd_word);
+ pci_read_config_word(hw->pdev, PCIX_STATUS_REGISTER_HI,
+ &pcix_stat_hi_word);
+ cmd_mmrbc =
+ (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
+ PCIX_COMMAND_MMRBC_SHIFT;
+ stat_mmrbc =
+ (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+ PCIX_STATUS_HI_MMRBC_SHIFT;
+ if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+ stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+ if (cmd_mmrbc > stat_mmrbc) {
+ pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+ pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+ pci_write_config_word(hw->pdev, PCIX_COMMAND_REGISTER,
+ pcix_cmd_word);
+ }
+ }
+ break;
+ }
+
+ /* More time needed for PHY to initialize */
+ if (hw->mac_type == e1000_ich8lan)
+ mdelay(15);
+
+ /* Call a subroutine to configure the link and setup flow control. */
+ ret_val = e1000_setup_link(nic);
+
+ /* Set the transmit descriptor write-back policy */
+ if (hw->mac_type > e1000_82544) {
+ ctrl = E1000_READ_REG(hw, TXDCTL);
+ ctrl =
+ (ctrl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ E1000_WRITE_REG(hw, TXDCTL, ctrl);
+ }
+
+ /* Set the receive descriptor write back policy */
+
+ if (hw->mac_type >= e1000_82571) {
+ ctrl = E1000_READ_REG(hw, RXDCTL);
+ ctrl =
+ (ctrl & ~E1000_RXDCTL_WTHRESH) |
+ E1000_RXDCTL_FULL_RX_DESC_WB;
+ E1000_WRITE_REG(hw, RXDCTL, ctrl);
+ }
+
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_80003es2lan:
+ /* Enable retransmit on late collisions */
+ reg_data = E1000_READ_REG(hw, TCTL);
+ reg_data |= E1000_TCTL_RTLC;
+ E1000_WRITE_REG(hw, TCTL, reg_data);
+
+ /* Configure Gigabit Carry Extend Padding */
+ reg_data = E1000_READ_REG(hw, TCTL_EXT);
+ reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+ reg_data |= DEFAULT_80003ES2LAN_TCTL_EXT_GCEX;
+ E1000_WRITE_REG(hw, TCTL_EXT, reg_data);
+
+ /* Configure Transmit Inter-Packet Gap */
+ reg_data = E1000_READ_REG(hw, TIPG);
+ reg_data &= ~E1000_TIPG_IPGT_MASK;
+ reg_data |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
+ E1000_WRITE_REG(hw, TIPG, reg_data);
+
+ reg_data = E1000_READ_REG_ARRAY(hw, FFLT, 0x0001);
+ reg_data &= ~0x00100000;
+ E1000_WRITE_REG_ARRAY(hw, FFLT, 0x0001, reg_data);
+ /* Fall through */
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_ich8lan:
+ ctrl = E1000_READ_REG(hw, TXDCTL1);
+ ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH)
+ | E1000_TXDCTL_FULL_TX_DESC_WB;
+ E1000_WRITE_REG(hw, TXDCTL1, ctrl);
+ break;
+ case e1000_82573:
+ case e1000_82574:
+ reg_data = E1000_READ_REG(hw, GCR);
+ reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+ E1000_WRITE_REG(hw, GCR, reg_data);
+ }
+
+#if 0
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs(hw);
+
+ /* ICH8 No-snoop bits are opposite polarity.
+ * Set to snoop by default after reset. */
+ if (hw->mac_type == e1000_ich8lan)
+ e1000_set_pci_ex_no_snoop(hw, PCI_EX_82566_SNOOP_ALL);
+#endif
+
+ if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER ||
+ hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) {
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ /* Relaxed ordering must be disabled to avoid a parity
+ * error crash in a PCI slot. */
+ ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+static int
+e1000_setup_link(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ int32_t ret_val;
+#ifndef CONFIG_E1000_NO_NVM
+ uint32_t ctrl_ext;
+ uint16_t eeprom_data;
+#endif
+
+ DEBUGFUNC();
+
+ /* In the case of the phy reset being blocked, we already have a link.
+ * We do not have to set it up again. */
+ if (e1000_check_phy_reset_block(hw))
+ return E1000_SUCCESS;
+
+#ifndef CONFIG_E1000_NO_NVM
+ /* Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ if (e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1,
+ &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+#endif
+ if (hw->fc == e1000_fc_default) {
+ switch (hw->mac_type) {
+ case e1000_ich8lan:
+ case e1000_82573:
+ case e1000_82574:
+ hw->fc = e1000_fc_full;
+ break;
+ default:
+#ifndef CONFIG_E1000_NO_NVM
+ ret_val = e1000_read_eeprom(hw,
+ EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
+ if (ret_val) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+ hw->fc = e1000_fc_none;
+ else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+ EEPROM_WORD0F_ASM_DIR)
+ hw->fc = e1000_fc_tx_pause;
+ else
+#endif
+ hw->fc = e1000_fc_full;
+ break;
+ }
+ }
+
+ /* We want to save off the original Flow Control configuration just
+ * in case we get disconnected and then reconnected into a different
+ * hub or switch with different Flow Control capabilities.
+ */
+ if (hw->mac_type == e1000_82542_rev2_0)
+ hw->fc &= (~e1000_fc_tx_pause);
+
+ if ((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+ hw->fc &= (~e1000_fc_rx_pause);
+
+ hw->original_fc = hw->fc;
+
+ DEBUGOUT("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+#ifndef CONFIG_E1000_NO_NVM
+ /* Take the 4 bits from EEPROM word 0x0F that determine the initial
+ * polarity value for the SW controlled pins, and setup the
+ * Extended Device Control reg with that info.
+ * This is needed because one of the SW controlled pins is used for
+ * signal detection. So this should be done before e1000_setup_pcs_link()
+ * or e1000_phy_setup() is called.
+ */
+ if (hw->mac_type == e1000_82543) {
+ ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
+ SWDPIO__EXT_SHIFT);
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+#endif
+
+ /* Call the necessary subroutine to configure the link. */
+ ret_val = (hw->media_type == e1000_media_type_fiber) ?
+ e1000_setup_fiber_link(nic) : e1000_setup_copper_link(nic);
+ if (ret_val < 0) {
+ return ret_val;
+ }
+
+ /* Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ DEBUGOUT("Initializing the Flow Control address, type"
+ "and timer regs\n");
+
+ /* FCAL/H and FCT are hardcoded to standard values in e1000_ich8lan. */
+ if (hw->mac_type != e1000_ich8lan) {
+ E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+ E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+ }
+
+ E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+ /* Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames in not enabled, then these
+ * registers will be set to 0.
+ */
+ if (!(hw->fc & e1000_fc_tx_pause)) {
+ E1000_WRITE_REG(hw, FCRTL, 0);
+ E1000_WRITE_REG(hw, FCRTH, 0);
+ } else {
+ /* We need to set up the Receive Threshold high and low water marks
+ * as well as (optionally) enabling the transmission of XON frames.
+ */
+ if (hw->fc_send_xon) {
+ E1000_WRITE_REG(hw, FCRTL,
+ (hw->fc_low_water | E1000_FCRTL_XONE));
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ } else {
+ E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ }
+ }
+ return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int
+e1000_setup_fiber_link(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t txcw = 0;
+ uint32_t i;
+ uint32_t signal;
+ int32_t ret_val;
+
+ DEBUGFUNC();
+ /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ if ((hw->mac_type > e1000_82544) && !(ctrl & E1000_CTRL_ILOS))
+ signal = E1000_CTRL_SWDPIN1;
+ else
+ signal = 0;
+
+ printf("signal for %s is %x (ctrl %08x)!!!!\n", nic->name, signal,
+ ctrl);
+ /* Take the link out of reset */
+ ctrl &= ~(E1000_CTRL_LRST);
+
+ e1000_config_collision_dist(hw);
+
+ /* Check for a software override of the flow control settings, and setup
+ * the device accordingly. If auto-negotiation is enabled, then software
+ * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+ * Config Word Register (TXCW) and re-start auto-negotiation. However, if
+ * auto-negotiation is disabled, then software will have to manually
+ * configure the two flow control enable bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames, but
+ * not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we do
+ * not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ */
+ switch (hw->fc) {
+ case e1000_fc_none:
+ /* Flow control is completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case e1000_fc_rx_pause:
+ /* RX Flow control is enabled and TX Flow control is disabled by a
+ * software over-ride. Since there really isn't a way to advertise
+ * that we are capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later, we will
+ * disable the adapter's ability to send PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case e1000_fc_tx_pause:
+ /* TX Flow control is enabled, and RX Flow control is disabled, by a
+ * software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case e1000_fc_full:
+ /* Flow control (both RX and TX) is enabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ /* Since auto-negotiation is enabled, take the link out of reset (the link
+ * will be in reset, because we previously reset the chip). This will
+ * restart auto-negotiation. If auto-neogtiation is successful then the
+ * link-up status bit will be set and the flow control enable bits (RFCE
+ * and TFCE) will be set according to their negotiated value.
+ */
+ DEBUGOUT("Auto-negotiation enabled (%#x)\n", txcw);
+
+ E1000_WRITE_REG(hw, TXCW, txcw);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ hw->txcw = txcw;
+ mdelay(1);
+
+ /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+ * indication in the Device Status Register. Time-out if a link isn't
+ * seen in 500 milliseconds seconds (Auto-negotiation should complete in
+ * less than 500 milliseconds even if the other end is doing it in SW).
+ */
+ if ((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+ DEBUGOUT("Looking for Link\n");
+ for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+ mdelay(10);
+ status = E1000_READ_REG(hw, STATUS);
+ if (status & E1000_STATUS_LU)
+ break;
+ }
+ if (i == (LINK_UP_TIMEOUT / 10)) {
+ /* AutoNeg failed to achieve a link, so we'll call
+ * e1000_check_for_link. This routine will force the link up if we
+ * detect a signal. This will allow us to communicate with
+ * non-autonegotiating link partners.
+ */
+ DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+ hw->autoneg_failed = 1;
+ ret_val = e1000_check_for_link(nic);
+ if (ret_val < 0) {
+ DEBUGOUT("Error while checking for link\n");
+ return ret_val;
+ }
+ hw->autoneg_failed = 0;
+ } else {
+ hw->autoneg_failed = 0;
+ DEBUGOUT("Valid Link Found\n");
+ }
+ } else {
+ DEBUGOUT("No Signal Detected\n");
+ return -E1000_ERR_NOLINK;
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Make sure we have a valid PHY and change PHY mode before link setup.
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_copper_link_preconfig(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* With 82543, we need to force speed and duplex on the MAC equal to what
+ * the PHY speed and duplex configuration is. In addition, we need to
+ * perform a hardware reset on the PHY to take it out of reset.
+ */
+ if (hw->mac_type > e1000_82543) {
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ } else {
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX
+ | E1000_CTRL_SLU);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Make sure we have a valid PHY */
+ ret_val = e1000_detect_gig_phy(hw);
+ if (ret_val) {
+ DEBUGOUT("Error, did not detect valid phy.\n");
+ return ret_val;
+ }
+ DEBUGOUT("Phy ID = %x \n", hw->phy_id);
+
+ /* Set PHY to class A mode (if necessary) */
+ ret_val = e1000_set_phy_mode(hw);
+ if (ret_val)
+ return ret_val;
+ if ((hw->mac_type == e1000_82545_rev_3) ||
+ (hw->mac_type == e1000_82546_rev_3)) {
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+ &phy_data);
+ phy_data |= 0x00000008;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+ phy_data);
+ }
+
+ if (hw->mac_type <= e1000_82543 ||
+ hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
+ hw->mac_type == e1000_82541_rev_2
+ || hw->mac_type == e1000_82547_rev_2)
+ hw->phy_reset_disable = false;
+
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu state according to the active flag. When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ * E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+static int32_t
+e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+ uint32_t phy_ctrl = 0;
+ int32_t ret_val;
+ uint16_t phy_data;
+ DEBUGFUNC();
+
+ if (hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2
+ && hw->phy_type != e1000_phy_igp_3)
+ return E1000_SUCCESS;
+
+ /* During driver activity LPLU should not be used or it will attain link
+ * from the lowest speeds starting from 10Mbps. The capability is used
+ * for Dx transitions and states */
+ if (hw->mac_type == e1000_82541_rev_2
+ || hw->mac_type == e1000_82547_rev_2) {
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->mac_type == e1000_ich8lan) {
+ /* MAC writes into PHY register based on the state transition
+ * and start auto-negotiation. SW driver can overwrite the
+ * settings in CSR PHY power control E1000_PHY_CTRL register. */
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+ } else {
+ ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ if (!active) {
+ if (hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547_rev_2) {
+ phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
+ phy_data &= ~IGP02E1000_PM_D3_LPLU;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
+ * Dx states where the power conservation is most important. During
+ * driver activity we should enable SmartSpeed, so performance is
+ * maintained. */
+ if (hw->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ } else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT)
+ || (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL) ||
+ (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
+
+ if (hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547_rev_2) {
+ phy_data |= IGP01E1000_GMII_FLEX_SPD;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_GMII_FIFO, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
+ phy_data |= IGP02E1000_PM_D3_LPLU;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ /* When LPLU is enabled we should disable SmartSpeed */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu d0 state according to the active flag. When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ * E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+static int32_t
+e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
+{
+ uint32_t phy_ctrl = 0;
+ int32_t ret_val;
+ uint16_t phy_data;
+ DEBUGFUNC();
+
+ if (hw->mac_type <= e1000_82547_rev_2)
+ return E1000_SUCCESS;
+
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+ } else {
+ ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ if (!active) {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
+ phy_data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
+ * Dx states where the power conservation is most important. During
+ * driver activity we should enable SmartSpeed, so performance is
+ * maintained. */
+ if (hw->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+
+ } else {
+
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
+ phy_data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* When LPLU is enabled we should disable SmartSpeed */
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ }
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_igp series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_igp_setup(struct e1000_hw *hw)
+{
+ uint32_t led_ctrl;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+
+ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ ret_val = e1000_phy_reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ /* Wait 15ms for MAC to configure PHY from eeprom settings */
+ mdelay(15);
+ if (hw->mac_type != e1000_ich8lan) {
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
+
+ /* The NVM settings will configure LPLU in D3 for IGP2 and IGP3 PHYs */
+ if (hw->phy_type == e1000_phy_igp) {
+ /* disable lplu d3 during driver init */
+ ret_val = e1000_set_d3_lplu_state(hw, false);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D3\n");
+ return ret_val;
+ }
+ }
+
+ /* disable lplu d0 during driver init */
+ ret_val = e1000_set_d0_lplu_state(hw, false);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D0\n");
+ return ret_val;
+ }
+ /* Configure mdi-mdix settings */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ hw->dsp_config_state = e1000_dsp_config_disabled;
+ /* Force MDI for earlier revs of the IGP PHY */
+ phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX
+ | IGP01E1000_PSCR_FORCE_MDI_MDIX);
+ hw->mdix = 1;
+
+ } else {
+ hw->dsp_config_state = e1000_dsp_config_enabled;
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 2:
+ phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 0:
+ default:
+ phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
+ break;
+ }
+ }
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* set auto-master slave resolution settings */
+ if (hw->autoneg) {
+ e1000_ms_type phy_ms_setting = hw->master_slave;
+
+ if (hw->ffe_config_state == e1000_ffe_config_active)
+ hw->ffe_config_state = e1000_ffe_config_enabled;
+
+ if (hw->dsp_config_state == e1000_dsp_config_activated)
+ hw->dsp_config_state = e1000_dsp_config_enabled;
+
+ /* when autonegotiation advertisment is only 1000Mbps then we
+ * should disable SmartSpeed and enable Auto MasterSlave
+ * resolution as hardware default. */
+ if (hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ /* Set auto Master/Slave resolution process */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* load defaults for future use */
+ hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
+ ((phy_data & CR_1000T_MS_VALUE) ?
+ e1000_ms_force_master :
+ e1000_ms_force_slave) :
+ e1000_ms_auto;
+
+ switch (phy_ms_setting) {
+ case e1000_ms_force_master:
+ phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_force_slave:
+ phy_data |= CR_1000T_MS_ENABLE;
+ phy_data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_auto:
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ default:
+ break;
+ }
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * This function checks the mode of the firmware.
+ *
+ * returns - true when the mode is IAMT or false.
+ ****************************************************************************/
+bool
+e1000_check_mng_mode(struct e1000_hw *hw)
+{
+ uint32_t fwsm;
+ DEBUGFUNC();
+
+ fwsm = E1000_READ_REG(hw, FWSM);
+
+ if (hw->mac_type == e1000_ich8lan) {
+ if ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ return true;
+ } else if ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ return true;
+
+ return false;
+}
+
+static int32_t
+e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data)
+{
+ uint16_t swfw = E1000_SWFW_PHY0_SM;
+ uint32_t reg_val;
+ DEBUGFUNC();
+
+ if (e1000_is_second_port(hw))
+ swfw = E1000_SWFW_PHY1_SM;
+
+ if (e1000_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT)
+ & E1000_KUMCTRLSTA_OFFSET) | data;
+ E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
+ udelay(2);
+
+ return E1000_SUCCESS;
+}
+
+static int32_t
+e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data)
+{
+ uint16_t swfw = E1000_SWFW_PHY0_SM;
+ uint32_t reg_val;
+ DEBUGFUNC();
+
+ if (e1000_is_second_port(hw))
+ swfw = E1000_SWFW_PHY1_SM;
+
+ if (e1000_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ /* Write register address */
+ reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) &
+ E1000_KUMCTRLSTA_OFFSET) | E1000_KUMCTRLSTA_REN;
+ E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
+ udelay(2);
+
+ /* Read the data returned */
+ reg_val = E1000_READ_REG(hw, KUMCTRLSTA);
+ *data = (uint16_t)reg_val;
+
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_gg82563 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_ggp_setup(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+ uint32_t reg_data;
+
+ DEBUGFUNC();
+
+ if (!hw->phy_reset_disable) {
+ /* Enable CRS on TX for half-duplex operation. */
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ /* Use 25MHz for both link down and 1000BASE-T for Tx clock */
+ phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
+
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+ break;
+ case 2:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+ break;
+ case 0:
+ default:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_SPEC_CTRL, phy_data);
+
+ if (ret_val)
+ return ret_val;
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+ } /* phy_reset_disable */
+
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Bypass RX and TX FIFO's */
+ ret_val = e1000_write_kmrn_reg(hw,
+ E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL,
+ E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS
+ | E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_SPEC_CTRL_2, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_SPEC_CTRL_2, phy_data);
+
+ if (ret_val)
+ return ret_val;
+
+ reg_data = E1000_READ_REG(hw, CTRL_EXT);
+ reg_data &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_data);
+
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_PWR_MGMT_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Do not init these registers when the HW is in IAMT mode, since the
+ * firmware will have already initialized them. We only initialize
+ * them if the HW is not in IAMT mode.
+ */
+ if (e1000_check_mng_mode(hw) == false) {
+ /* Enable Electrical Idle on the PHY */
+ phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_PWR_MGMT_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_KMRN_MODE_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_KMRN_MODE_CTRL, phy_data);
+
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Workaround: Disable padding in Kumeran interface in the MAC
+ * and in the PHY to avoid CRC errors.
+ */
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_INBAND_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_data |= GG82563_ICR_DIS_PADDING;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_INBAND_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_m88 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_mgp_setup(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+
+ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (hw->phy_revision < M88E1011_I_REV_4) {
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = e1000_read_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if ((hw->phy_revision == E1000_REVISION_2) &&
+ (hw->phy_id == M88E1111_I_PHY_ID)) {
+ /* Vidalia Phy, set the downshift counter to 5x */
+ phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK);
+ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK
+ | M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X
+ | M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Setup auto-negotiation and flow control advertisements,
+* and then perform auto-negotiation.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+
+ /* Perform some bounds checking on the hw->autoneg_advertised
+ * parameter. If this variable is zero, then set it to the default.
+ */
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ /* If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if (hw->autoneg_advertised == 0)
+ hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ /* IFE phy only supports 10/100 */
+ if (hw->phy_type == e1000_phy_ife)
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL;
+
+ DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Setting up Auto-Negotiation\n");
+ return ret_val;
+ }
+ DEBUGOUT("Restarting Auto-Neg\n");
+
+ /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ /* If we do not wait for autonegtation to complete I
+ * do not see a valid link status.
+ * wait_autoneg_complete = 1 .
+ */
+ if (hw->wait_autoneg_complete) {
+ ret_val = e1000_wait_autoneg(hw);
+ if (ret_val) {
+ DEBUGOUT("Error while waiting for autoneg"
+ "to complete\n");
+ return ret_val;
+ }
+ }
+
+ hw->get_link_status = true;
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Config the MAC and the PHY after link is up.
+* 1) Set up the MAC to the current PHY speed/duplex
+* if we are on 82543. If we
+* are on newer silicon, we only need to configure
+* collision distance in the Transmit Control Register.
+* 2) Set up flow control on the MAC to that established with
+* the link partner.
+* 3) Config DSP to improve Gigabit link quality for some PHY revisions.
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_copper_link_postconfig(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ DEBUGFUNC();
+
+ if (hw->mac_type >= e1000_82544) {
+ e1000_config_collision_dist(hw);
+ } else {
+ ret_val = e1000_config_mac_to_phy(hw);
+ if (ret_val) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Configuring Flow Control\n");
+ return ret_val;
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Detects which PHY is present and setup the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int
+e1000_setup_copper_link(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ int32_t ret_val;
+ uint16_t i;
+ uint16_t phy_data;
+ uint16_t reg_data;
+
+ DEBUGFUNC();
+
+ switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ case e1000_ich8lan:
+ /* Set the mac to wait the maximum time between each
+ * iteration and increase the max iterations when
+ * polling the phy; this fixes erroneous timeouts at 10Mbps. */
+ ret_val = e1000_write_kmrn_reg(hw,
+ GG82563_REG(0x34, 4), 0xFFFF);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_kmrn_reg(hw,
+ GG82563_REG(0x34, 9), &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= 0x3F;
+ ret_val = e1000_write_kmrn_reg(hw,
+ GG82563_REG(0x34, 9), reg_data);
+ if (ret_val)
+ return ret_val;
+ default:
+ break;
+ }
+
+ /* Check if it is a valid PHY and set PHY mode if necessary. */
+ ret_val = e1000_copper_link_preconfig(hw);
+ if (ret_val)
+ return ret_val;
+ switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ /* Kumeran registers are written-only */
+ reg_data =
+ E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT;
+ reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING;
+ ret_val = e1000_write_kmrn_reg(hw,
+ E1000_KUMCTRLSTA_OFFSET_INB_CTRL, reg_data);
+ if (ret_val)
+ return ret_val;
+ break;
+ default:
+ break;
+ }
+
+ if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
+ hw->phy_type == e1000_phy_igp_2) {
+ ret_val = e1000_copper_link_igp_setup(hw);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->phy_type == e1000_phy_m88) {
+ ret_val = e1000_copper_link_mgp_setup(hw);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+ ret_val = e1000_copper_link_ggp_setup(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* always auto */
+ /* Setup autoneg and flow control advertisement
+ * and perform autonegotiation */
+ ret_val = e1000_copper_link_autoneg(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ for (i = 0; i < 10; i++) {
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (phy_data & MII_SR_LINK_STATUS) {
+ /* Config the MAC and PHY after link is up */
+ ret_val = e1000_copper_link_postconfig(hw);
+ if (ret_val)
+ return ret_val;
+
+ DEBUGOUT("Valid link established!!!\n");
+ return E1000_SUCCESS;
+ }
+ udelay(10);
+ }
+
+ DEBUGOUT("Unable to establish link!!!\n");
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t mii_autoneg_adv_reg;
+ uint16_t mii_1000t_ctrl_reg;
+
+ DEBUGFUNC();
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ if (hw->phy_type != e1000_phy_ife) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
+ &mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ } else
+ mii_1000t_ctrl_reg = 0;
+
+ /* Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+ mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+ DEBUGOUT("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if (hw->autoneg_advertised & ADVERTISE_10_HALF) {
+ DEBUGOUT("Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if (hw->autoneg_advertised & ADVERTISE_10_FULL) {
+ DEBUGOUT("Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if (hw->autoneg_advertised & ADVERTISE_100_HALF) {
+ DEBUGOUT("Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if (hw->autoneg_advertised & ADVERTISE_100_FULL) {
+ DEBUGOUT("Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if (hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+ DEBUGOUT
+ ("Advertise 1000mb Half duplex requested, request denied!\n");
+ }
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if (hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+ DEBUGOUT("Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /* Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->fc) {
+ case e1000_fc_none: /* 0 */
+ /* Flow control (RX & TX) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_rx_pause: /* 1 */
+ /* RX Flow control is enabled, and TX Flow control is
+ * disabled, by a software over-ride.
+ */
+ /* Since there really isn't a way to advertise that we are
+ * capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later
+ * (in e1000_config_fc_after_link_up) we will disable the
+ *hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_tx_pause: /* 2 */
+ /* TX Flow control is enabled, and RX Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case e1000_fc_full: /* 3 */
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ DEBUGOUT("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ if (hw->phy_type != e1000_phy_ife) {
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+ mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+static void
+e1000_config_collision_dist(struct e1000_hw *hw)
+{
+ uint32_t tctl, coll_dist;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type < e1000_82543)
+ coll_dist = E1000_COLLISION_DISTANCE_82542;
+ else
+ coll_dist = E1000_COLLISION_DISTANCE;
+
+ tctl = E1000_READ_REG(hw, TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= coll_dist << E1000_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, TCTL, tctl);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int
+e1000_config_mac_to_phy(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+
+ /* Read the Device Control Register and set the bits to Force Speed
+ * and Duplex.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+ /* Set up duplex in the Device Control and Transmit Control
+ * registers depending on negotiated values.
+ */
+ if (e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if (phy_data & M88E1000_PSSR_DPLX)
+ ctrl |= E1000_CTRL_FD;
+ else
+ ctrl &= ~E1000_CTRL_FD;
+
+ e1000_config_collision_dist(hw);
+
+ /* Set up speed in the Device Control register depending on
+ * negotiated values.
+ */
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+ ctrl |= E1000_CTRL_SPD_1000;
+ else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+ ctrl |= E1000_CTRL_SPD_100;
+ /* Write the configured values back to the Device Control Reg. */
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ return 0;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+static int
+e1000_force_mac_fc(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+
+ DEBUGFUNC();
+
+ /* Get the current configuration of the Device Control Register */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "hw->fc" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and TX flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+
+ switch (hw->fc) {
+ case e1000_fc_none:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+ case e1000_fc_rx_pause:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+ case e1000_fc_tx_pause:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+ case e1000_fc_full:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ /* Disable TX Flow Control for 82542 (rev 2.0) */
+ if (hw->mac_type == e1000_82542_rev2_0)
+ ctrl &= (~E1000_CTRL_TFCE);
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ return 0;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+static int32_t
+e1000_config_fc_after_link_up(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t mii_status_reg;
+ uint16_t mii_nway_adv_reg;
+ uint16_t mii_nway_lp_ability_reg;
+ uint16_t speed;
+ uint16_t duplex;
+
+ DEBUGFUNC();
+
+ /* Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if (((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed))
+ || ((hw->media_type == e1000_media_type_internal_serdes)
+ && (hw->autoneg_failed))
+ || ((hw->media_type == e1000_media_type_copper)
+ && (!hw->autoneg))) {
+ ret_val = e1000_force_mac_fc(hw);
+ if (ret_val < 0) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ }
+
+ /* Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if (hw->media_type == e1000_media_type_copper) {
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ if (e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error \n");
+ return -E1000_ERR_PHY;
+ }
+ if (e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error \n");
+ return -E1000_ERR_PHY;
+ }
+
+ if (mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement Register
+ * (Address 4) and the Auto_Negotiation Base Page Ability
+ * Register (Address 5) to determine how flow control was
+ * negotiated.
+ */
+ if (e1000_read_phy_reg
+ (hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if (e1000_read_phy_reg
+ (hw, PHY_LP_ABILITY,
+ &mii_nway_lp_ability_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | e1000_fc_none
+ * 0 | 1 | 0 | DC | e1000_fc_none
+ * 0 | 1 | 1 | 0 | e1000_fc_none
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 1 | 0 | 0 | DC | e1000_fc_none
+ * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | 1 | 0 | 0 | e1000_fc_none
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ /* Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | e1000_fc_full
+ *
+ */
+ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if (hw->original_fc == e1000_fc_full) {
+ hw->fc = e1000_fc_full;
+ DEBUGOUT("Flow Control = FULL.\r\n");
+ } else {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT
+ ("Flow Control = RX PAUSE frames only.\r\n");
+ }
+ }
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ *
+ */
+ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR))
+ {
+ hw->fc = e1000_fc_tx_pause;
+ DEBUGOUT
+ ("Flow Control = TX PAUSE frames only.\r\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR))
+ {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT
+ ("Flow Control = RX PAUSE frames only.\r\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+ * disabled. However, we want to consider that we could
+ * be connected to a legacy switch that doesn't advertise
+ * desired flow control, but can be forced on the link
+ * partner. So if we advertised no flow control, that is
+ * what we will resolve to. If we advertised some kind of
+ * receive capability (Rx Pause Only or Full Flow Control)
+ * and the link partner advertised none, we will configure
+ * ourselves to enable Rx Flow Control only. We can do
+ * this safely for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx, no
+ * harm done since we won't be receiving any PAUSE frames
+ * anyway. If the intent on the link partner was to have
+ * flow control enabled, then by us enabling RX only, we
+ * can at least receive pause frames and process them.
+ * This is a good idea because in most cases, since we are
+ * predominantly a server NIC, more times than not we will
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+ else if (hw->original_fc == e1000_fc_none ||
+ hw->original_fc == e1000_fc_tx_pause) {
+ hw->fc = e1000_fc_none;
+ DEBUGOUT("Flow Control = NONE.\r\n");
+ } else {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT
+ ("Flow Control = RX PAUSE frames only.\r\n");
+ }
+
+ /* Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ e1000_get_speed_and_duplex(hw, &speed, &duplex);
+
+ if (duplex == HALF_DUPLEX)
+ hw->fc = e1000_fc_none;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = e1000_force_mac_fc(hw);
+ if (ret_val < 0) {
+ DEBUGOUT
+ ("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ } else {
+ DEBUGOUT
+ ("Copper PHY and Auto Neg has not completed.\r\n");
+ }
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+static int
+e1000_check_for_link(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ uint32_t rxcw;
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t rctl;
+ uint32_t signal;
+ int32_t ret_val;
+ uint16_t phy_data;
+ uint16_t lp_capability;
+
+ DEBUGFUNC();
+
+ /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ if ((hw->mac_type > e1000_82544) && !(ctrl & E1000_CTRL_ILOS))
+ signal = E1000_CTRL_SWDPIN1;
+ else
+ signal = 0;
+
+ status = E1000_READ_REG(hw, STATUS);
+ rxcw = E1000_READ_REG(hw, RXCW);
+ DEBUGOUT("ctrl: %#08x status %#08x rxcw %#08x\n", ctrl, status, rxcw);
+
+ /* If we have a copper PHY then we only want to go out to the PHY
+ * registers to see if Auto-Neg has completed and/or if our link
+ * status has changed. The get_link_status flag will be set if we
+ * receive a Link Status Change interrupt or we have Rx Sequence
+ * Errors.
+ */
+ if ((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ * Read the register twice since the link bit is sticky.
+ */
+ if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ if (phy_data & MII_SR_LINK_STATUS) {
+ hw->get_link_status = false;
+ } else {
+ /* No link detected */
+ return -E1000_ERR_NOLINK;
+ }
+
+ /* We have a M88E1000 PHY and Auto-Neg is enabled. If we
+ * have Si on board that is 82544 or newer, Auto
+ * Speed Detection takes care of MAC speed/duplex
+ * configuration. So we only need to configure Collision
+ * Distance in the MAC. Otherwise, we need to force
+ * speed/duplex on the MAC to the current PHY speed/duplex
+ * settings.
+ */
+ if (hw->mac_type >= e1000_82544)
+ e1000_config_collision_dist(hw);
+ else {
+ ret_val = e1000_config_mac_to_phy(hw);
+ if (ret_val < 0) {
+ DEBUGOUT
+ ("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+
+ /* Configure Flow Control now that Auto-Neg has completed. First, we
+ * need to restore the desired flow control settings because we may
+ * have had to re-autoneg with a different link partner.
+ */
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if (ret_val < 0) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+
+ /* At this point we know that we are on copper and we have
+ * auto-negotiated link. These are conditions for checking the link
+ * parter capability register. We use the link partner capability to
+ * determine if TBI Compatibility needs to be turned on or off. If
+ * the link partner advertises any speed in addition to Gigabit, then
+ * we assume that they are GMII-based, and TBI compatibility is not
+ * needed. If no other speeds are advertised, we assume the link
+ * partner is TBI-based, and we turn on TBI Compatibility.
+ */
+ if (hw->tbi_compatibility_en) {
+ if (e1000_read_phy_reg
+ (hw, PHY_LP_ABILITY, &lp_capability) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if (lp_capability & (NWAY_LPAR_10T_HD_CAPS |
+ NWAY_LPAR_10T_FD_CAPS |
+ NWAY_LPAR_100TX_HD_CAPS |
+ NWAY_LPAR_100TX_FD_CAPS |
+ NWAY_LPAR_100T4_CAPS)) {
+ /* If our link partner advertises anything in addition to
+ * gigabit, we do not need to enable TBI compatibility.
+ */
+ if (hw->tbi_compatibility_on) {
+ /* If we previously were in the mode, turn it off. */
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl &= ~E1000_RCTL_SBP;
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ hw->tbi_compatibility_on = false;
+ }
+ } else {
+ /* If TBI compatibility is was previously off, turn it on. For
+ * compatibility with a TBI link partner, we will store bad
+ * packets. Some frames have an additional byte on the end and
+ * will look like CRC errors to to the hardware.
+ */
+ if (!hw->tbi_compatibility_on) {
+ hw->tbi_compatibility_on = true;
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl |= E1000_RCTL_SBP;
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ }
+ }
+ }
+ }
+ /* If we don't have link (auto-negotiation failed or link partner cannot
+ * auto-negotiate), the cable is plugged in (we have signal), and our
+ * link partner is not trying to auto-negotiate with us (we are receiving
+ * idles or data), we need to force link up. We also need to give
+ * auto-negotiation time to complete, in case the cable was just plugged
+ * in. The autoneg_failed flag does this.
+ */
+ else if ((hw->media_type == e1000_media_type_fiber) &&
+ (!(status & E1000_STATUS_LU)) &&
+ ((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if (hw->autoneg_failed == 0) {
+ hw->autoneg_failed = 1;
+ return 0;
+ }
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if (ret_val < 0) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+ }
+ /* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+ * auto-negotiation in the TXCW register and disable forced link in the
+ * Device Control register in an attempt to auto-negotiate with our link
+ * partner.
+ */
+ else if ((hw->media_type == e1000_media_type_fiber) &&
+ (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ DEBUGOUT
+ ("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+ E1000_WRITE_REG(hw, TXCW, hw->txcw);
+ E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Configure the MAC-to-PHY interface for 10/100Mbps
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, uint16_t duplex)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint32_t tipg;
+ uint16_t reg_data;
+
+ DEBUGFUNC();
+
+ reg_data = E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT;
+ ret_val = e1000_write_kmrn_reg(hw,
+ E1000_KUMCTRLSTA_OFFSET_HD_CTRL, reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100;
+ E1000_WRITE_REG(hw, TIPG, tipg);
+
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+ if (ret_val)
+ return ret_val;
+
+ if (duplex == HALF_DUPLEX)
+ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ else
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+ return ret_val;
+}
+
+static int32_t
+e1000_configure_kmrn_for_1000(struct e1000_hw *hw)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint16_t reg_data;
+ uint32_t tipg;
+
+ DEBUGFUNC();
+
+ reg_data = E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT;
+ ret_val = e1000_write_kmrn_reg(hw,
+ E1000_KUMCTRLSTA_OFFSET_HD_CTRL, reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
+ E1000_WRITE_REG(hw, TIPG, tipg);
+
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+ if (ret_val)
+ return ret_val;
+
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+static int
+e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t *speed,
+ uint16_t *duplex)
+{
+ uint32_t status;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type >= e1000_82543) {
+ status = E1000_READ_REG(hw, STATUS);
+ if (status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ DEBUGOUT("1000 Mbs, ");
+ } else if (status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ DEBUGOUT("100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ DEBUGOUT("10 Mbs, ");
+ }
+
+ if (status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\r\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ DEBUGOUT(" Half Duplex\r\n");
+ }
+ } else {
+ DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+ *speed = SPEED_1000;
+ *duplex = FULL_DUPLEX;
+ }
+
+ /* IGP01 PHY may advertise full duplex operation after speed downgrade
+ * even if it is operating at half duplex. Here we set the duplex
+ * settings to match the duplex in the link partner's capabilities.
+ */
+ if (hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
+ ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(phy_data & NWAY_ER_LP_NWAY_CAPS))
+ *duplex = HALF_DUPLEX;
+ else {
+ ret_val = e1000_read_phy_reg(hw,
+ PHY_LP_ABILITY, &phy_data);
+ if (ret_val)
+ return ret_val;
+ if ((*speed == SPEED_100 &&
+ !(phy_data & NWAY_LPAR_100TX_FD_CAPS))
+ || (*speed == SPEED_10
+ && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
+ *duplex = HALF_DUPLEX;
+ }
+ }
+
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (hw->media_type == e1000_media_type_copper)) {
+ if (*speed == SPEED_1000)
+ ret_val = e1000_configure_kmrn_for_1000(hw);
+ else
+ ret_val = e1000_configure_kmrn_for_10_100(hw, *duplex);
+ if (ret_val)
+ return ret_val;
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int
+e1000_wait_autoneg(struct e1000_hw *hw)
+{
+ uint16_t i;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+ DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+ for (i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg
+ * Complete bit to be set.
+ */
+ if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if (phy_data & MII_SR_AUTONEG_COMPLETE) {
+ DEBUGOUT("Auto-Neg complete.\n");
+ return 0;
+ }
+ mdelay(100);
+ }
+ DEBUGOUT("Auto-Neg timedout.\n");
+ return -E1000_ERR_TIMEOUT;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t * ctrl)
+{
+ /* Raise the clock input to the Management Data Clock (by setting the MDC
+ * bit), and then delay 2 microseconds.
+ */
+ E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+ E1000_WRITE_FLUSH(hw);
+ udelay(2);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t * ctrl)
+{
+ /* Lower the clock input to the Management Data Clock (by clearing the MDC
+ * bit), and then delay 2 microseconds.
+ */
+ E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+ E1000_WRITE_FLUSH(hw);
+ udelay(2);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count)
+{
+ uint32_t ctrl;
+ uint32_t mask;
+
+ /* We need to shift "count" number of bits out to the PHY. So, the value
+ * in the "data" parameter will be shifted out to the PHY one bit at a
+ * time. In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01;
+ mask <<= (count - 1);
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+ ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+ while (mask) {
+ /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+ * then raising and lowering the Management Data Clock. A "0" is
+ * shifted out to the PHY by setting the MDIO bit to "0" and then
+ * raising and lowering the clock.
+ */
+ if (data & mask)
+ ctrl |= E1000_CTRL_MDIO;
+ else
+ ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ udelay(2);
+
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ mask = mask >> 1;
+ }
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order.
+******************************************************************************/
+static uint16_t
+e1000_shift_in_mdi_bits(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint16_t data = 0;
+ uint8_t i;
+
+ /* In order to read a register from the PHY, we need to shift in a total
+ * of 18 bits from the PHY. The first two bit (turnaround) times are used
+ * to avoid contention on the MDIO pin when a read operation is performed.
+ * These two bits are ignored by us and thrown away. Bits are "shifted in"
+ * by raising the input to the Management Data Clock (setting the MDC bit),
+ * and then reading the value of the MDIO bit.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+ ctrl &= ~E1000_CTRL_MDIO_DIR;
+ ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ /* Raise and Lower the clock before reading in the data. This accounts for
+ * the turnaround bits. The first clock occurred when we clocked out the
+ * last bit of the Register Address.
+ */
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ for (data = 0, i = 0; i < 16; i++) {
+ data = data << 1;
+ e1000_raise_mdi_clk(hw, &ctrl);
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Check to see if we shifted in a "1". */
+ if (ctrl & E1000_CTRL_MDIO)
+ data |= 1;
+ e1000_lower_mdi_clk(hw, &ctrl);
+ }
+
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+static int
+e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t * phy_data)
+{
+ uint32_t i;
+ uint32_t mdic = 0;
+ const uint32_t phy_addr = 1;
+
+ if (reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+ if (hw->mac_type > e1000_82543) {
+ /* Set up Op-code, Phy Address, and register address in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for (i = 0; i < 64; i++) {
+ udelay(10);
+ mdic = E1000_READ_REG(hw, MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
+ *phy_data = (uint16_t) mdic;
+ } else {
+ /* We must first send a preamble through the MDIO pin to signal the
+ * beginning of an MII instruction. This is done by sending 32
+ * consecutive "1" bits.
+ */
+ e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+ /* Now combine the next few fields that are required for a read
+ * operation. We use this method instead of calling the
+ * e1000_shift_out_mdi_bits routine five different times. The format of
+ * a MII read instruction consists of a shift out of 14 bits and is
+ * defined as follows:
+ * <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+ * followed by a shift in of 18 bits. This first two bits shifted in
+ * are TurnAround bits used to avoid contention on the MDIO pin when a
+ * READ operation is performed. These two bits are thrown away
+ * followed by a shift in of 16 bits which contains the desired data.
+ */
+ mdic = ((reg_addr) | (phy_addr << 5) |
+ (PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+ e1000_shift_out_mdi_bits(hw, mdic, 14);
+
+ /* Now that we've shifted out the read command to the MII, we need to
+ * "shift in" the 16-bit value (18 total bits) of the requested PHY
+ * register address.
+ */
+ *phy_data = e1000_shift_in_mdi_bits(hw);
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+static int
+e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t phy_data)
+{
+ uint32_t i;
+ uint32_t mdic = 0;
+ const uint32_t phy_addr = 1;
+
+ if (reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+ if (hw->mac_type > e1000_82543) {
+ /* Set up Op-code, Phy Address, register address, and data intended
+ * for the PHY register in the MDI Control register. The MAC will take
+ * care of interfacing with the PHY to send the desired data.
+ */
+ mdic = (((uint32_t) phy_data) |
+ (reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for (i = 0; i < 64; i++) {
+ udelay(10);
+ mdic = E1000_READ_REG(hw, MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ } else {
+ /* We'll need to use the SW defined pins to shift the write command
+ * out to the PHY. We first send a preamble to the PHY to signal the
+ * beginning of the MII instruction. This is done by sending 32
+ * consecutive "1" bits.
+ */
+ e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+ /* Now combine the remaining required fields that will indicate a
+ * write operation. We use this method instead of calling the
+ * e1000_shift_out_mdi_bits routine for each field in the command. The
+ * format of a MII write instruction is as follows:
+ * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+ */
+ mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+ (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+ mdic <<= 16;
+ mdic |= (uint32_t) phy_data;
+
+ e1000_shift_out_mdi_bits(hw, mdic, 32);
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Checks if PHY reset is blocked due to SOL/IDER session, for example.
+ * Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to
+ * the caller to figure out how to deal with it.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_BLK_PHY_RESET
+ * E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+e1000_check_phy_reset_block(struct e1000_hw *hw)
+{
+ uint32_t manc = 0;
+ uint32_t fwsm = 0;
+
+ if (hw->mac_type == e1000_ich8lan) {
+ fwsm = E1000_READ_REG(hw, FWSM);
+ return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS
+ : E1000_BLK_PHY_RESET;
+ }
+
+ if (hw->mac_type > e1000_82547_rev_2)
+ manc = E1000_READ_REG(hw, MANC);
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+ E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * Checks if the PHY configuration is done
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_phy_cfg_done(struct e1000_hw *hw)
+{
+ int32_t timeout = PHY_CFG_TIMEOUT;
+ uint32_t cfg_mask = E1000_EEPROM_CFG_DONE;
+
+ DEBUGFUNC();
+
+ switch (hw->mac_type) {
+ default:
+ mdelay(10);
+ break;
+
+ case e1000_80003es2lan:
+ /* Separate *_CFG_DONE_* bit for each port */
+ if (e1000_is_second_port(hw))
+ cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1;
+ /* Fall Through */
+
+ case e1000_82571:
+ case e1000_82572:
+ while (timeout) {
+ if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
+ break;
+ else
+ mdelay(1);
+ timeout--;
+ }
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not "
+ "completed.\n");
+ return -E1000_ERR_RESET;
+ }
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+ uint16_t swfw = E1000_SWFW_PHY0_SM;
+ uint32_t ctrl, ctrl_ext;
+ uint32_t led_ctrl;
+ int32_t ret_val;
+
+ DEBUGFUNC();
+
+ /* In the case of the phy reset being blocked, it's not an error, we
+ * simply return success without performing the reset. */
+ ret_val = e1000_check_phy_reset_block(hw);
+ if (ret_val)
+ return E1000_SUCCESS;
+
+ DEBUGOUT("Resetting Phy...\n");
+
+ if (hw->mac_type > e1000_82543) {
+ if (e1000_is_second_port(hw))
+ swfw = E1000_SWFW_PHY1_SM;
+
+ if (e1000_swfw_sync_acquire(hw, swfw)) {
+ DEBUGOUT("Unable to acquire swfw sync\n");
+ return -E1000_ERR_SWFW_SYNC;
+ }
+
+ /* Read the device control register and assert the E1000_CTRL_PHY_RST
+ * bit. Then, take it out of reset.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+ E1000_WRITE_FLUSH(hw);
+
+ if (hw->mac_type < e1000_82571)
+ udelay(10);
+ else
+ udelay(100);
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ if (hw->mac_type >= e1000_82571)
+ mdelay(10);
+
+ } else {
+ /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+ * bit to put the PHY into reset. Then, take it out of reset.
+ */
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+ ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ mdelay(10);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
+ udelay(150);
+
+ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
+
+ /* Wait for FW to finish PHY configuration. */
+ ret_val = e1000_get_phy_cfg_done(hw);
+ if (ret_val != E1000_SUCCESS)
+ return ret_val;
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * IGP phy init script - initializes the GbE PHY
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_phy_init_script(struct e1000_hw *hw)
+{
+ uint32_t ret_val;
+ uint16_t phy_saved_data;
+ DEBUGFUNC();
+
+ if (hw->phy_init_script) {
+ mdelay(20);
+
+ /* Save off the current value of register 0x2F5B to be
+ * restored at the end of this routine. */
+ ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+ /* Disabled the PHY transmitter */
+ e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+ mdelay(20);
+
+ e1000_write_phy_reg(hw, 0x0000, 0x0140);
+
+ mdelay(5);
+
+ switch (hw->mac_type) {
+ case e1000_82541:
+ case e1000_82547:
+ e1000_write_phy_reg(hw, 0x1F95, 0x0001);
+
+ e1000_write_phy_reg(hw, 0x1F71, 0xBD21);
+
+ e1000_write_phy_reg(hw, 0x1F79, 0x0018);
+
+ e1000_write_phy_reg(hw, 0x1F30, 0x1600);
+
+ e1000_write_phy_reg(hw, 0x1F31, 0x0014);
+
+ e1000_write_phy_reg(hw, 0x1F32, 0x161C);
+
+ e1000_write_phy_reg(hw, 0x1F94, 0x0003);
+
+ e1000_write_phy_reg(hw, 0x1F96, 0x003F);
+
+ e1000_write_phy_reg(hw, 0x2010, 0x0008);
+ break;
+
+ case e1000_82541_rev_2:
+ case e1000_82547_rev_2:
+ e1000_write_phy_reg(hw, 0x1F73, 0x0099);
+ break;
+ default:
+ break;
+ }
+
+ e1000_write_phy_reg(hw, 0x0000, 0x3300);
+
+ mdelay(20);
+
+ /* Now enable the transmitter */
+ if (!ret_val)
+ e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+ if (hw->mac_type == e1000_82547) {
+ uint16_t fused, fine, coarse;
+
+ /* Move to analog registers page */
+ e1000_read_phy_reg(hw,
+ IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
+
+ if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
+ e1000_read_phy_reg(hw,
+ IGP01E1000_ANALOG_FUSE_STATUS, &fused);
+
+ fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
+ coarse = fused
+ & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
+
+ if (coarse >
+ IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
+ coarse -=
+ IGP01E1000_ANALOG_FUSE_COARSE_10;
+ fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
+ } else if (coarse
+ == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
+ fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
+
+ fused = (fused
+ & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
+ (fine
+ & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
+ (coarse
+ & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
+
+ e1000_write_phy_reg(hw,
+ IGP01E1000_ANALOG_FUSE_CONTROL, fused);
+ e1000_write_phy_reg(hw,
+ IGP01E1000_ANALOG_FUSE_BYPASS,
+ IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
+ }
+ }
+ }
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control register
+******************************************************************************/
+int32_t
+e1000_phy_reset(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+
+ /* In the case of the phy reset being blocked, it's not an error, we
+ * simply return success without performing the reset. */
+ ret_val = e1000_check_phy_reset_block(hw);
+ if (ret_val)
+ return E1000_SUCCESS;
+
+ switch (hw->phy_type) {
+ case e1000_phy_igp:
+ case e1000_phy_igp_2:
+ case e1000_phy_igp_3:
+ case e1000_phy_ife:
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val)
+ return ret_val;
+ break;
+ default:
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= MII_CR_RESET;
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+ break;
+ }
+
+ if (hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2)
+ e1000_phy_init_script(hw);
+
+ return E1000_SUCCESS;
+}
+
+static int e1000_set_phy_type (struct e1000_hw *hw)
+{
+ DEBUGFUNC ();
+
+ if (hw->mac_type == e1000_undefined)
+ return -E1000_ERR_PHY_TYPE;
+
+ switch (hw->phy_id) {
+ case M88E1000_E_PHY_ID:
+ case M88E1000_I_PHY_ID:
+ case M88E1011_I_PHY_ID:
+ case M88E1111_I_PHY_ID:
+ hw->phy_type = e1000_phy_m88;
+ break;
+ case IGP01E1000_I_PHY_ID:
+ if (hw->mac_type == e1000_82541 ||
+ hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547 ||
+ hw->mac_type == e1000_82547_rev_2) {
+ hw->phy_type = e1000_phy_igp;
+ break;
+ }
+ case IGP03E1000_E_PHY_ID:
+ hw->phy_type = e1000_phy_igp_3;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ hw->phy_type = e1000_phy_ife;
+ break;
+ case GG82563_E_PHY_ID:
+ if (hw->mac_type == e1000_80003es2lan) {
+ hw->phy_type = e1000_phy_gg82563;
+ break;
+ }
+ case BME1000_E_PHY_ID:
+ hw->phy_type = e1000_phy_bm;
+ break;
+ /* Fall Through */
+ default:
+ /* Should never have loaded on this device */
+ hw->phy_type = e1000_phy_undefined;
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_detect_gig_phy(struct e1000_hw *hw)
+{
+ int32_t phy_init_status, ret_val;
+ uint16_t phy_id_high, phy_id_low;
+ bool match = false;
+
+ DEBUGFUNC();
+
+ /* The 82571 firmware may still be configuring the PHY. In this
+ * case, we cannot access the PHY until the configuration is done. So
+ * we explicitly set the PHY values. */
+ if (hw->mac_type == e1000_82571 ||
+ hw->mac_type == e1000_82572) {
+ hw->phy_id = IGP01E1000_I_PHY_ID;
+ hw->phy_type = e1000_phy_igp_2;
+ return E1000_SUCCESS;
+ }
+
+ /* ESB-2 PHY reads require e1000_phy_gg82563 to be set because of a
+ * work- around that forces PHY page 0 to be set or the reads fail.
+ * The rest of the code in this routine uses e1000_read_phy_reg to
+ * read the PHY ID. So for ESB-2 we need to have this set so our
+ * reads won't fail. If the attached PHY is not a e1000_phy_gg82563,
+ * the routines below will figure this out as well. */
+ if (hw->mac_type == e1000_80003es2lan)
+ hw->phy_type = e1000_phy_gg82563;
+
+ /* Read the PHY ID Registers to identify which PHY is onboard. */
+ ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
+ if (ret_val)
+ return ret_val;
+
+ hw->phy_id = (uint32_t) (phy_id_high << 16);
+ udelay(20);
+ ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low);
+ if (ret_val)
+ return ret_val;
+
+ hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+ hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
+ switch (hw->mac_type) {
+ case e1000_82543:
+ if (hw->phy_id == M88E1000_E_PHY_ID)
+ match = true;
+ break;
+ case e1000_82544:
+ if (hw->phy_id == M88E1000_I_PHY_ID)
+ match = true;
+ break;
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82545_rev_3:
+ case e1000_82546:
+ case e1000_82546_rev_3:
+ if (hw->phy_id == M88E1011_I_PHY_ID)
+ match = true;
+ break;
+ case e1000_82541:
+ case e1000_82541_rev_2:
+ case e1000_82547:
+ case e1000_82547_rev_2:
+ if(hw->phy_id == IGP01E1000_I_PHY_ID)
+ match = true;
+
+ break;
+ case e1000_82573:
+ if (hw->phy_id == M88E1111_I_PHY_ID)
+ match = true;
+ break;
+ case e1000_82574:
+ if (hw->phy_id == BME1000_E_PHY_ID)
+ match = true;
+ break;
+ case e1000_80003es2lan:
+ if (hw->phy_id == GG82563_E_PHY_ID)
+ match = true;
+ break;
+ case e1000_ich8lan:
+ if (hw->phy_id == IGP03E1000_E_PHY_ID)
+ match = true;
+ if (hw->phy_id == IFE_E_PHY_ID)
+ match = true;
+ if (hw->phy_id == IFE_PLUS_E_PHY_ID)
+ match = true;
+ if (hw->phy_id == IFE_C_E_PHY_ID)
+ match = true;
+ break;
+ default:
+ DEBUGOUT("Invalid MAC type %d\n", hw->mac_type);
+ return -E1000_ERR_CONFIG;
+ }
+
+ phy_init_status = e1000_set_phy_type(hw);
+
+ if ((match) && (phy_init_status == E1000_SUCCESS)) {
+ DEBUGOUT("PHY ID 0x%X detected\n", hw->phy_id);
+ return 0;
+ }
+ DEBUGOUT("Invalid PHY ID 0x%X\n", hw->phy_id);
+ return -E1000_ERR_PHY;
+}
+
+/*****************************************************************************
+ * Set media type and TBI compatibility.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * **************************************************************************/
+void
+e1000_set_media_type(struct e1000_hw *hw)
+{
+ uint32_t status;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type != e1000_82543) {
+ /* tbi_compatibility is only valid on 82543 */
+ hw->tbi_compatibility_en = false;
+ }
+
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82545GM_SERDES:
+ case E1000_DEV_ID_82546GB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES_DUAL:
+ case E1000_DEV_ID_82571EB_SERDES_QUAD:
+ case E1000_DEV_ID_82572EI_SERDES:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->media_type = e1000_media_type_internal_serdes;
+ break;
+ default:
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ hw->media_type = e1000_media_type_fiber;
+ break;
+ case e1000_ich8lan:
+ case e1000_82573:
+ case e1000_82574:
+ /* The STATUS_TBIMODE bit is reserved or reused
+ * for the this device.
+ */
+ hw->media_type = e1000_media_type_copper;
+ break;
+ default:
+ status = E1000_READ_REG(hw, STATUS);
+ if (status & E1000_STATUS_TBIMODE) {
+ hw->media_type = e1000_media_type_fiber;
+ /* tbi_compatibility not valid on fiber */
+ hw->tbi_compatibility_en = false;
+ } else {
+ hw->media_type = e1000_media_type_copper;
+ }
+ break;
+ }
+ }
+}
+
+/**
+ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
+ *
+ * e1000_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+
+static int
+e1000_sw_init(struct eth_device *nic)
+{
+ struct e1000_hw *hw = (typeof(hw)) nic->priv;
+ int result;
+
+ /* PCI config space info */
+ pci_read_config_word(hw->pdev, PCI_VENDOR_ID, &hw->vendor_id);
+ pci_read_config_word(hw->pdev, PCI_DEVICE_ID, &hw->device_id);
+ pci_read_config_word(hw->pdev, PCI_SUBSYSTEM_VENDOR_ID,
+ &hw->subsystem_vendor_id);
+ pci_read_config_word(hw->pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_id);
+
+ pci_read_config_byte(hw->pdev, PCI_REVISION_ID, &hw->revision_id);
+ pci_read_config_word(hw->pdev, PCI_COMMAND, &hw->pci_cmd_word);
+
+ /* identify the MAC */
+ result = e1000_set_mac_type(hw);
+ if (result) {
+ E1000_ERR(hw->nic, "Unknown MAC Type\n");
+ return result;
+ }
+
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_82541:
+ case e1000_82547:
+ case e1000_82541_rev_2:
+ case e1000_82547_rev_2:
+ hw->phy_init_script = 1;
+ break;
+ }
+
+ /* flow control settings */
+ hw->fc_high_water = E1000_FC_HIGH_THRESH;
+ hw->fc_low_water = E1000_FC_LOW_THRESH;
+ hw->fc_pause_time = E1000_FC_PAUSE_TIME;
+ hw->fc_send_xon = 1;
+
+ /* Media type - copper or fiber */
+ e1000_set_media_type(hw);
+
+ if (hw->mac_type >= e1000_82543) {
+ uint32_t status = E1000_READ_REG(hw, STATUS);
+
+ if (status & E1000_STATUS_TBIMODE) {
+ DEBUGOUT("fiber interface\n");
+ hw->media_type = e1000_media_type_fiber;
+ } else {
+ DEBUGOUT("copper interface\n");
+ hw->media_type = e1000_media_type_copper;
+ }
+ } else {
+ hw->media_type = e1000_media_type_fiber;
+ }
+
+ hw->tbi_compatibility_en = true;
+ hw->wait_autoneg_complete = true;
+ if (hw->mac_type < e1000_82543)
+ hw->report_tx_early = 0;
+ else
+ hw->report_tx_early = 1;
+
+ return E1000_SUCCESS;
+}
+
+void
+fill_rx(struct e1000_hw *hw)
+{
+ struct e1000_rx_desc *rd;
+
+ rx_last = rx_tail;
+ rd = rx_base + rx_tail;
+ rx_tail = (rx_tail + 1) % 8;
+ memset(rd, 0, 16);
+ rd->buffer_addr = cpu_to_le64((u32) & packet);
+ E1000_WRITE_REG(hw, RDT, rx_tail);
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+
+static void
+e1000_configure_tx(struct e1000_hw *hw)
+{
+ unsigned long ptr;
+ unsigned long tctl;
+ unsigned long tipg, tarc;
+ uint32_t ipgr1, ipgr2;
+
+ ptr = (u32) tx_pool;
+ if (ptr & 0xf)
+ ptr = (ptr + 0x10) & (~0xf);
+
+ tx_base = (typeof(tx_base)) ptr;
+
+ E1000_WRITE_REG(hw, TDBAL, (u32) tx_base);
+ E1000_WRITE_REG(hw, TDBAH, 0);
+
+ E1000_WRITE_REG(hw, TDLEN, 128);
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ E1000_WRITE_REG(hw, TDH, 0);
+ E1000_WRITE_REG(hw, TDT, 0);
+ tx_tail = 0;
+
+ /* Set the default values for the Tx Inter Packet Gap timer */
+ if (hw->mac_type <= e1000_82547_rev_2 &&
+ (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes))
+ tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+ else
+ tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+
+ /* Set the default values for the Tx Inter Packet Gap timer */
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ tipg = DEFAULT_82542_TIPG_IPGT;
+ ipgr1 = DEFAULT_82542_TIPG_IPGR1;
+ ipgr2 = DEFAULT_82542_TIPG_IPGR2;
+ break;
+ case e1000_80003es2lan:
+ ipgr1 = DEFAULT_82543_TIPG_IPGR1;
+ ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2;
+ break;
+ default:
+ ipgr1 = DEFAULT_82543_TIPG_IPGR1;
+ ipgr2 = DEFAULT_82543_TIPG_IPGR2;
+ break;
+ }
+ tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
+ tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
+ E1000_WRITE_REG(hw, TIPG, tipg);
+ /* Program the Transmit Control Register */
+ tctl = E1000_READ_REG(hw, TCTL);
+ tctl &= ~E1000_TCTL_CT;
+ tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
+ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+ if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) {
+ tarc = E1000_READ_REG(hw, TARC0);
+ /* set the speed mode bit, we'll clear it if we're not at
+ * gigabit link later */
+ /* git bit can be set to 1*/
+ } else if (hw->mac_type == e1000_80003es2lan) {
+ tarc = E1000_READ_REG(hw, TARC0);
+ tarc |= 1;
+ E1000_WRITE_REG(hw, TARC0, tarc);
+ tarc = E1000_READ_REG(hw, TARC1);
+ tarc |= 1;
+ E1000_WRITE_REG(hw, TARC1, tarc);
+ }
+
+
+ e1000_config_collision_dist(hw);
+ /* Setup Transmit Descriptor Settings for eop descriptor */
+ hw->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
+
+ /* Need to set up RS bit */
+ if (hw->mac_type < e1000_82543)
+ hw->txd_cmd |= E1000_TXD_CMD_RPS;
+ else
+ hw->txd_cmd |= E1000_TXD_CMD_RS;
+ E1000_WRITE_REG(hw, TCTL, tctl);
+}
+
+/**
+ * e1000_setup_rctl - configure the receive control register
+ * @adapter: Board private structure
+ **/
+static void
+e1000_setup_rctl(struct e1000_hw *hw)
+{
+ uint32_t rctl;
+
+ rctl = E1000_READ_REG(hw, RCTL);
+
+ rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+
+ rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO
+ | E1000_RCTL_RDMTS_HALF; /* |
+ (hw.mc_filter_type << E1000_RCTL_MO_SHIFT); */
+
+ if (hw->tbi_compatibility_on == 1)
+ rctl |= E1000_RCTL_SBP;
+ else
+ rctl &= ~E1000_RCTL_SBP;
+
+ rctl &= ~(E1000_RCTL_SZ_4096);
+ rctl |= E1000_RCTL_SZ_2048;
+ rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
+ E1000_WRITE_REG(hw, RCTL, rctl);
+}
+
+/**
+ * e1000_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void
+e1000_configure_rx(struct e1000_hw *hw)
+{
+ unsigned long ptr;
+ unsigned long rctl, ctrl_ext;
+ rx_tail = 0;
+ /* make sure receives are disabled while setting up the descriptors */
+ rctl = E1000_READ_REG(hw, RCTL);
+ E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
+ if (hw->mac_type >= e1000_82540) {
+ /* Set the interrupt throttling rate. Value is calculated
+ * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC 8000
+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256)
+ E1000_WRITE_REG(hw, ITR, DEFAULT_ITR);
+ }
+
+ if (hw->mac_type >= e1000_82571) {
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ /* Reset delay timers after every interrupt */
+ ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
+ /* Setup the Base and Length of the Rx Descriptor Ring */
+ ptr = (u32) rx_pool;
+ if (ptr & 0xf)
+ ptr = (ptr + 0x10) & (~0xf);
+ rx_base = (typeof(rx_base)) ptr;
+ E1000_WRITE_REG(hw, RDBAL, (u32) rx_base);
+ E1000_WRITE_REG(hw, RDBAH, 0);
+
+ E1000_WRITE_REG(hw, RDLEN, 128);
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers */
+ E1000_WRITE_REG(hw, RDH, 0);
+ E1000_WRITE_REG(hw, RDT, 0);
+ /* Enable Receives */
+
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ fill_rx(hw);
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int
+e1000_poll(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ struct e1000_rx_desc *rd;
+ /* return true if there's an ethernet packet ready to read */
+ rd = rx_base + rx_last;
+ if (!(le32_to_cpu(rd->status)) & E1000_RXD_STAT_DD)
+ return 0;
+ /*DEBUGOUT("recv: packet len=%d \n", rd->length); */
+ NetReceive((uchar *)packet, le32_to_cpu(rd->length));
+ fill_rx(hw);
+ return 1;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static int e1000_transmit(struct eth_device *nic, void *packet, int length)
+{
+ void *nv_packet = (void *)packet;
+ struct e1000_hw *hw = nic->priv;
+ struct e1000_tx_desc *txp;
+ int i = 0;
+
+ txp = tx_base + tx_tail;
+ tx_tail = (tx_tail + 1) % 8;
+
+ txp->buffer_addr = cpu_to_le64(virt_to_bus(hw->pdev, nv_packet));
+ txp->lower.data = cpu_to_le32(hw->txd_cmd | length);
+ txp->upper.data = 0;
+ E1000_WRITE_REG(hw, TDT, tx_tail);
+
+ E1000_WRITE_FLUSH(hw);
+ while (!(le32_to_cpu(txp->upper.data) & E1000_TXD_STAT_DD)) {
+ if (i++ > TOUT_LOOP) {
+ DEBUGOUT("e1000: tx timeout\n");
+ return 0;
+ }
+ udelay(10); /* give the nic a chance to write to the register */
+ }
+ return 1;
+}
+
+/*reset function*/
+static inline int
+e1000_reset(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+
+ e1000_reset_hw(hw);
+ if (hw->mac_type >= e1000_82544) {
+ E1000_WRITE_REG(hw, WUC, 0);
+ }
+ return e1000_init_hw(nic);
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void
+e1000_disable(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+
+ /* Turn off the ethernet interface */
+ E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_REG(hw, TCTL, 0);
+
+ /* Clear the transmit ring */
+ E1000_WRITE_REG(hw, TDH, 0);
+ E1000_WRITE_REG(hw, TDT, 0);
+
+ /* Clear the receive ring */
+ E1000_WRITE_REG(hw, RDH, 0);
+ E1000_WRITE_REG(hw, RDT, 0);
+
+ /* put the card in its initial state */
+#if 0
+ E1000_WRITE_REG(hw, CTRL, E1000_CTRL_RST);
+#endif
+ mdelay(10);
+
+}
+
+/**************************************************************************
+INIT - set up ethernet interface(s)
+***************************************************************************/
+static int
+e1000_init(struct eth_device *nic, bd_t * bis)
+{
+ struct e1000_hw *hw = nic->priv;
+ int ret_val = 0;
+
+ ret_val = e1000_reset(nic);
+ if (ret_val < 0) {
+ if ((ret_val == -E1000_ERR_NOLINK) ||
+ (ret_val == -E1000_ERR_TIMEOUT)) {
+ E1000_ERR(hw->nic, "Valid Link not detected\n");
+ } else {
+ E1000_ERR(hw->nic, "Hardware Initialization Failed\n");
+ }
+ return 0;
+ }
+ e1000_configure_tx(hw);
+ e1000_setup_rctl(hw);
+ e1000_configure_rx(hw);
+ return 1;
+}
+
+/******************************************************************************
+ * Gets the current PCI bus type of hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void e1000_get_bus_type(struct e1000_hw *hw)
+{
+ uint32_t status;
+
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ hw->bus_type = e1000_bus_type_pci;
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_82573:
+ case e1000_82574:
+ case e1000_80003es2lan:
+ hw->bus_type = e1000_bus_type_pci_express;
+ break;
+ case e1000_ich8lan:
+ hw->bus_type = e1000_bus_type_pci_express;
+ break;
+ default:
+ status = E1000_READ_REG(hw, STATUS);
+ hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+ e1000_bus_type_pcix : e1000_bus_type_pci;
+ break;
+ }
+}
+
+/* A list of all registered e1000 devices */
+static LIST_HEAD(e1000_hw_list);
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+You should omit the last argument struct pci_device * for a non-PCI NIC
+***************************************************************************/
+int
+e1000_initialize(bd_t * bis)
+{
+ unsigned int i;
+ pci_dev_t devno;
+
+ DEBUGFUNC();
+
+ /* Find and probe all the matching PCI devices */
+ for (i = 0; (devno = pci_find_devices(e1000_supported, i)) >= 0; i++) {
+ u32 val;
+
+ /*
+ * These will never get freed due to errors, this allows us to
+ * perform SPI EEPROM programming from U-boot, for example.
+ */
+ struct eth_device *nic = malloc(sizeof(*nic));
+ struct e1000_hw *hw = malloc(sizeof(*hw));
+ if (!nic || !hw) {
+ printf("e1000#%u: Out of Memory!\n", i);
+ free(nic);
+ free(hw);
+ continue;
+ }
+
+ /* Make sure all of the fields are initially zeroed */
+ memset(nic, 0, sizeof(*nic));
+ memset(hw, 0, sizeof(*hw));
+
+ /* Assign the passed-in values */
+ hw->cardnum = i;
+ hw->pdev = devno;
+ hw->nic = nic;
+ nic->priv = hw;
+
+ /* Generate a card name */
+ sprintf(nic->name, "e1000#%u", hw->cardnum);
+
+ /* Print a debug message with the IO base address */
+ pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &val);
+ E1000_DBG(nic, "iobase 0x%08x\n", val & 0xfffffff0);
+
+ /* Try to enable I/O accesses and bus-mastering */
+ val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_dword(devno, PCI_COMMAND, val);
+
+ /* Make sure it worked */
+ pci_read_config_dword(devno, PCI_COMMAND, &val);
+ if (!(val & PCI_COMMAND_MEMORY)) {
+ E1000_ERR(nic, "Can't enable I/O memory\n");
+ continue;
+ }
+ if (!(val & PCI_COMMAND_MASTER)) {
+ E1000_ERR(nic, "Can't enable bus-mastering\n");
+ continue;
+ }
+
+ /* Are these variables needed? */
+ hw->fc = e1000_fc_default;
+ hw->original_fc = e1000_fc_default;
+ hw->autoneg_failed = 0;
+ hw->autoneg = 1;
+ hw->get_link_status = true;
+ hw->hw_addr = pci_map_bar(devno, PCI_BASE_ADDRESS_0,
+ PCI_REGION_MEM);
+ hw->mac_type = e1000_undefined;
+
+ /* MAC and Phy settings */
+ if (e1000_sw_init(nic) < 0) {
+ E1000_ERR(nic, "Software init failed\n");
+ continue;
+ }
+ if (e1000_check_phy_reset_block(hw))
+ E1000_ERR(nic, "PHY Reset is blocked!\n");
+
+ /* Basic init was OK, reset the hardware and allow SPI access */
+ e1000_reset_hw(hw);
+ list_add_tail(&hw->list_node, &e1000_hw_list);
+
+#ifndef CONFIG_E1000_NO_NVM
+ /* Validate the EEPROM and get chipset information */
+#if !defined(CONFIG_MVBC_1G)
+ if (e1000_init_eeprom_params(hw)) {
+ E1000_ERR(nic, "EEPROM is invalid!\n");
+ continue;
+ }
+ if (e1000_validate_eeprom_checksum(hw))
+ continue;
+#endif
+ e1000_read_mac_addr(nic);
+#endif
+ e1000_get_bus_type(hw);
+
+#ifndef CONFIG_E1000_NO_NVM
+ printf("e1000: %02x:%02x:%02x:%02x:%02x:%02x\n ",
+ nic->enetaddr[0], nic->enetaddr[1], nic->enetaddr[2],
+ nic->enetaddr[3], nic->enetaddr[4], nic->enetaddr[5]);
+#else
+ memset(nic->enetaddr, 0, 6);
+ printf("e1000: no NVM\n");
+#endif
+
+ /* Set up the function pointers and register the device */
+ nic->init = e1000_init;
+ nic->recv = e1000_poll;
+ nic->send = e1000_transmit;
+ nic->halt = e1000_disable;
+ eth_register(nic);
+ }
+
+ return i;
+}
+
+struct e1000_hw *e1000_find_card(unsigned int cardnum)
+{
+ struct e1000_hw *hw;
+
+ list_for_each_entry(hw, &e1000_hw_list, list_node)
+ if (hw->cardnum == cardnum)
+ return hw;
+
+ return NULL;
+}
+
+#ifdef CONFIG_CMD_E1000
+static int do_e1000(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct e1000_hw *hw;
+
+ if (argc < 3) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ /* Make sure we can find the requested e1000 card */
+ hw = e1000_find_card(simple_strtoul(argv[1], NULL, 10));
+ if (!hw) {
+ printf("e1000: ERROR: No such device: e1000#%s\n", argv[1]);
+ return 1;
+ }
+
+ if (!strcmp(argv[2], "print-mac-address")) {
+ unsigned char *mac = hw->nic->enetaddr;
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ return 0;
+ }
+
+#ifdef CONFIG_E1000_SPI
+ /* Handle the "SPI" subcommand */
+ if (!strcmp(argv[2], "spi"))
+ return do_e1000_spi(cmdtp, hw, argc - 3, argv + 3);
+#endif
+
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD(
+ e1000, 7, 0, do_e1000,
+ "Intel e1000 controller management",
+ /* */"<card#> print-mac-address\n"
+#ifdef CONFIG_E1000_SPI
+ "e1000 <card#> spi show [<offset> [<length>]]\n"
+ "e1000 <card#> spi dump <addr> <offset> <length>\n"
+ "e1000 <card#> spi program <addr> <offset> <length>\n"
+ "e1000 <card#> spi checksum [update]\n"
+#endif
+ " - Manage the Intel E1000 PCI device"
+);
+#endif /* not CONFIG_CMD_E1000 */
diff --git a/qemu/roms/u-boot/drivers/net/e1000.h b/qemu/roms/u-boot/drivers/net/e1000.h
new file mode 100644
index 000000000..ff87af2ef
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/e1000.h
@@ -0,0 +1,2601 @@
+/*******************************************************************************
+
+
+ Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright 2011 Freescale Semiconductor, Inc.
+
+ * SPDX-License-Identifier: GPL-2.0+
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include <common.h>
+#include <linux/list.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#ifdef CONFIG_E1000_SPI
+#include <spi.h>
+#endif
+
+#define E1000_ERR(NIC, fmt, args...) \
+ printf("e1000: %s: ERROR: " fmt, (NIC)->name ,##args)
+
+#ifdef E1000_DEBUG
+#define E1000_DBG(NIC, fmt, args...) \
+ printf("e1000: %s: DEBUG: " fmt, (NIC)->name ,##args)
+#define DEBUGOUT(fmt, args...) printf(fmt ,##args)
+#define DEBUGFUNC() printf("%s\n", __func__);
+#else
+#define E1000_DBG(HW, args...) do { } while (0)
+#define DEBUGFUNC() do { } while (0)
+#define DEBUGOUT(fmt, args...) do { } while (0)
+#endif
+
+/* I/O wrapper functions */
+#define E1000_WRITE_REG(a, reg, value) \
+ writel((value), ((a)->hw_addr + E1000_##reg))
+#define E1000_READ_REG(a, reg) \
+ readl((a)->hw_addr + E1000_##reg)
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
+ writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2)))
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
+ readl((a)->hw_addr + E1000_##reg + ((offset) << 2))
+#define E1000_WRITE_FLUSH(a) \
+ do { E1000_READ_REG(a, STATUS); } while (0)
+
+/* Forward declarations of structures used by the shared code */
+struct e1000_hw;
+struct e1000_hw_stats;
+
+/* Internal E1000 helper functions */
+struct e1000_hw *e1000_find_card(unsigned int cardnum);
+
+#ifndef CONFIG_E1000_NO_NVM
+int32_t e1000_acquire_eeprom(struct e1000_hw *hw);
+void e1000_standby_eeprom(struct e1000_hw *hw);
+void e1000_release_eeprom(struct e1000_hw *hw);
+void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+#endif
+
+#ifdef CONFIG_E1000_SPI
+int do_e1000_spi(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
+ int argc, char * const argv[]);
+#endif
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+typedef enum {
+ e1000_undefined = 0,
+ e1000_82542_rev2_0,
+ e1000_82542_rev2_1,
+ e1000_82543,
+ e1000_82544,
+ e1000_82540,
+ e1000_82545,
+ e1000_82545_rev_3,
+ e1000_82546,
+ e1000_82546_rev_3,
+ e1000_82541,
+ e1000_82541_rev_2,
+ e1000_82547,
+ e1000_82547_rev_2,
+ e1000_82571,
+ e1000_82572,
+ e1000_82573,
+ e1000_82574,
+ e1000_80003es2lan,
+ e1000_ich8lan,
+ e1000_num_macs
+} e1000_mac_type;
+
+/* Media Types */
+typedef enum {
+ e1000_media_type_copper = 0,
+ e1000_media_type_fiber = 1,
+ e1000_media_type_internal_serdes = 2,
+ e1000_num_media_types
+} e1000_media_type;
+
+typedef enum {
+ e1000_eeprom_uninitialized = 0,
+ e1000_eeprom_spi,
+ e1000_eeprom_microwire,
+ e1000_eeprom_flash,
+ e1000_eeprom_ich8,
+ e1000_eeprom_none, /* No NVM support */
+ e1000_num_eeprom_types
+} e1000_eeprom_type;
+
+typedef enum {
+ e1000_10_half = 0,
+ e1000_10_full = 1,
+ e1000_100_half = 2,
+ e1000_100_full = 3
+} e1000_speed_duplex_type;
+
+/* Flow Control Settings */
+typedef enum {
+ e1000_fc_none = 0,
+ e1000_fc_rx_pause = 1,
+ e1000_fc_tx_pause = 2,
+ e1000_fc_full = 3,
+ e1000_fc_default = 0xFF
+} e1000_fc_type;
+
+/* PCI bus types */
+typedef enum {
+ e1000_bus_type_unknown = 0,
+ e1000_bus_type_pci,
+ e1000_bus_type_pcix,
+ e1000_bus_type_pci_express,
+ e1000_bus_type_reserved
+} e1000_bus_type;
+
+/* PCI bus speeds */
+typedef enum {
+ e1000_bus_speed_unknown = 0,
+ e1000_bus_speed_33,
+ e1000_bus_speed_66,
+ e1000_bus_speed_100,
+ e1000_bus_speed_133,
+ e1000_bus_speed_reserved
+} e1000_bus_speed;
+
+/* PCI bus widths */
+typedef enum {
+ e1000_bus_width_unknown = 0,
+ e1000_bus_width_32,
+ e1000_bus_width_64
+} e1000_bus_width;
+
+/* PHY status info structure and supporting enums */
+typedef enum {
+ e1000_cable_length_50 = 0,
+ e1000_cable_length_50_80,
+ e1000_cable_length_80_110,
+ e1000_cable_length_110_140,
+ e1000_cable_length_140,
+ e1000_cable_length_undefined = 0xFF
+} e1000_cable_length;
+
+typedef enum {
+ e1000_10bt_ext_dist_enable_normal = 0,
+ e1000_10bt_ext_dist_enable_lower,
+ e1000_10bt_ext_dist_enable_undefined = 0xFF
+} e1000_10bt_ext_dist_enable;
+
+typedef enum {
+ e1000_rev_polarity_normal = 0,
+ e1000_rev_polarity_reversed,
+ e1000_rev_polarity_undefined = 0xFF
+} e1000_rev_polarity;
+
+typedef enum {
+ e1000_polarity_reversal_enabled = 0,
+ e1000_polarity_reversal_disabled,
+ e1000_polarity_reversal_undefined = 0xFF
+} e1000_polarity_reversal;
+
+typedef enum {
+ e1000_auto_x_mode_manual_mdi = 0,
+ e1000_auto_x_mode_manual_mdix,
+ e1000_auto_x_mode_auto1,
+ e1000_auto_x_mode_auto2,
+ e1000_auto_x_mode_undefined = 0xFF
+} e1000_auto_x_mode;
+
+typedef enum {
+ e1000_1000t_rx_status_not_ok = 0,
+ e1000_1000t_rx_status_ok,
+ e1000_1000t_rx_status_undefined = 0xFF
+} e1000_1000t_rx_status;
+
+typedef enum {
+ e1000_phy_m88 = 0,
+ e1000_phy_igp,
+ e1000_phy_igp_2,
+ e1000_phy_gg82563,
+ e1000_phy_igp_3,
+ e1000_phy_ife,
+ e1000_phy_bm,
+ e1000_phy_undefined = 0xFF
+} e1000_phy_type;
+
+struct e1000_phy_info {
+ e1000_cable_length cable_length;
+ e1000_10bt_ext_dist_enable extended_10bt_distance;
+ e1000_rev_polarity cable_polarity;
+ e1000_polarity_reversal polarity_correction;
+ e1000_auto_x_mode mdix_mode;
+ e1000_1000t_rx_status local_rx;
+ e1000_1000t_rx_status remote_rx;
+};
+
+struct e1000_phy_stats {
+ uint32_t idle_errors;
+ uint32_t receive_errors;
+};
+
+/* Error Codes */
+#define E1000_SUCCESS 0
+#define E1000_ERR_EEPROM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+#define E1000_ERR_MAC_TYPE 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_NOLINK 7
+#define E1000_ERR_TIMEOUT 8
+#define E1000_ERR_RESET 9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET 12
+#define E1000_ERR_SWFW_SYNC 13
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542 0x1000
+#define E1000_DEV_ID_82543GC_FIBER 0x1001
+#define E1000_DEV_ID_82543GC_COPPER 0x1004
+#define E1000_DEV_ID_82544EI_COPPER 0x1008
+#define E1000_DEV_ID_82544EI_FIBER 0x1009
+#define E1000_DEV_ID_82544GC_COPPER 0x100C
+#define E1000_DEV_ID_82544GC_LOM 0x100D
+#define E1000_DEV_ID_82540EM 0x100E
+#define E1000_DEV_ID_82540EM_LOM 0x1015
+#define E1000_DEV_ID_82540EP_LOM 0x1016
+#define E1000_DEV_ID_82540EP 0x1017
+#define E1000_DEV_ID_82540EP_LP 0x101E
+#define E1000_DEV_ID_82545EM_COPPER 0x100F
+#define E1000_DEV_ID_82545EM_FIBER 0x1011
+#define E1000_DEV_ID_82545GM_COPPER 0x1026
+#define E1000_DEV_ID_82545GM_FIBER 0x1027
+#define E1000_DEV_ID_82545GM_SERDES 0x1028
+#define E1000_DEV_ID_82546EB_COPPER 0x1010
+#define E1000_DEV_ID_82546EB_FIBER 0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI 0x1013
+#define E1000_DEV_ID_82541EI_MOBILE 0x1018
+#define E1000_DEV_ID_82541ER_LOM 0x1014
+#define E1000_DEV_ID_82541ER 0x1078
+#define E1000_DEV_ID_82547GI 0x1075
+#define E1000_DEV_ID_82541GI 0x1076
+#define E1000_DEV_ID_82541GI_MOBILE 0x1077
+#define E1000_DEV_ID_82541GI_LF 0x107C
+#define E1000_DEV_ID_82546GB_COPPER 0x1079
+#define E1000_DEV_ID_82546GB_FIBER 0x107A
+#define E1000_DEV_ID_82546GB_SERDES 0x107B
+#define E1000_DEV_ID_82546GB_PCIE 0x108A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+#define E1000_DEV_ID_82547EI 0x1019
+#define E1000_DEV_ID_82547EI_MOBILE 0x101A
+#define E1000_DEV_ID_82571EB_COPPER 0x105E
+#define E1000_DEV_ID_82571EB_FIBER 0x105F
+#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC
+#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
+#define E1000_DEV_ID_82572EI_COPPER 0x107D
+#define E1000_DEV_ID_82572EI_FIBER 0x107E
+#define E1000_DEV_ID_82572EI_SERDES 0x107F
+#define E1000_DEV_ID_82572EI 0x10B9
+#define E1000_DEV_ID_82573E 0x108B
+#define E1000_DEV_ID_82573E_IAMT 0x108C
+#define E1000_DEV_ID_82573L 0x109A
+#define E1000_DEV_ID_82574L 0x10D3
+#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
+#define E1000_DEV_ID_ICH8_IGP_C 0x104B
+#define E1000_DEV_ID_ICH8_IFE 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M 0x104D
+
+#define IGP03E1000_E_PHY_ID 0x02A80390
+#define IFE_E_PHY_ID 0x02A80330 /* 10/100 PHY */
+#define IFE_PLUS_E_PHY_ID 0x02A80320
+#define IFE_C_E_PHY_ID 0x02A80310
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 /* 100BaseTx Extended Status,
+ Control and Address */
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY special
+ control register */
+#define IFE_PHY_RCV_FALSE_CARRIER 0x13 /* 100BaseTx Receive false
+ Carrier Counter */
+#define IFE_PHY_RCV_DISCONNECT 0x14 /* 100BaseTx Receive Disconnet
+ Counter */
+#define IFE_PHY_RCV_ERROT_FRAME 0x15 /* 100BaseTx Receive Error
+ Frame Counter */
+#define IFE_PHY_RCV_SYMBOL_ERR 0x16 /* Receive Symbol Error
+ Counter */
+#define IFE_PHY_PREM_EOF_ERR 0x17 /* 100BaseTx Receive
+ Premature End Of Frame
+ Error Counter */
+#define IFE_PHY_RCV_EOF_ERR 0x18 /* 10BaseT Receive End Of
+ Frame Error Counter */
+#define IFE_PHY_TX_JABBER_DETECT 0x19 /* 10BaseT Transmit Jabber
+ Detect Counter */
+#define IFE_PHY_EQUALIZER 0x1A /* PHY Equalizer Control and
+ Status */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY special control and
+ LED configuration */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control register */
+#define IFE_PHY_HWI_CONTROL 0x1D /* Hardware Integrity Control
+ (HWI) */
+
+#define IFE_PESC_REDUCED_POWER_DOWN_DISABLE 0x2000 /* Defaut 1 = Disable auto
+ reduced power down */
+#define IFE_PESC_100BTX_POWER_DOWN 0x0400 /* Indicates the power
+ state of 100BASE-TX */
+#define IFE_PESC_10BTX_POWER_DOWN 0x0200 /* Indicates the power
+ state of 10BASE-T */
+#define IFE_PESC_POLARITY_REVERSED 0x0100 /* Indicates 10BASE-T
+ polarity */
+#define IFE_PESC_PHY_ADDR_MASK 0x007C /* Bit 6:2 for sampled PHY
+ address */
+#define IFE_PESC_SPEED 0x0002 /* Auto-negotiation speed
+ result 1=100Mbs, 0=10Mbs */
+#define IFE_PESC_DUPLEX 0x0001 /* Auto-negotiation
+ duplex result 1=Full, 0=Half */
+#define IFE_PESC_POLARITY_REVERSED_SHIFT 8
+
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 /* 1 = Dyanmic Power Down
+ disabled */
+#define IFE_PSC_FORCE_POLARITY 0x0020 /* 1=Reversed Polarity,
+ 0=Normal */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 /* 1=Auto Polarity
+ Disabled, 0=Enabled */
+#define IFE_PSC_JABBER_FUNC_DISABLE 0x0001 /* 1=Jabber Disabled,
+ 0=Normal Jabber Operation */
+#define IFE_PSC_FORCE_POLARITY_SHIFT 5
+#define IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT 4
+
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable MDI/MDI-X
+ feature, default 0=disabled */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDIX-X,
+ 0=force MDI */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorithm
+ is completed */
+#define IFE_PMC_MDIX_MODE_SHIFT 6
+#define IFE_PHC_MDIX_RESET_ALL_MASK 0x0000 /* Disable auto MDI-X */
+
+#define IFE_PHC_HWI_ENABLE 0x8000 /* Enable the HWI
+ feature */
+#define IFE_PHC_ABILITY_CHECK 0x4000 /* 1= Test Passed,
+ 0=failed */
+#define IFE_PHC_TEST_EXEC 0x2000 /* PHY launch test pulses
+ on the wire */
+#define IFE_PHC_HIGHZ 0x0200 /* 1 = Open Circuit */
+#define IFE_PHC_LOWZ 0x0400 /* 1 = Short Circuit */
+#define IFE_PHC_LOW_HIGH_Z_MASK 0x0600 /* Mask for indication
+ type of problem on the line */
+#define IFE_PHC_DISTANCE_MASK 0x01FF /* Mask for distance to
+ the cable problem, in 80cm granularity */
+#define IFE_PHC_RESET_ALL_MASK 0x0000 /* Disable HWI */
+#define IFE_PSCL_PROBE_MODE 0x0020 /* LED Probe mode */
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2
+ off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+
+#define NUM_DEV_IDS 16
+
+#define NODE_ADDRESS_SIZE 6
+#define ETH_LENGTH_OF_ADDRESS 6
+
+/* MAC decode size is 128K - This is the size of BAR0 */
+#define MAC_DECODE_SIZE (128 * 1024)
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
+
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE 14
+#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */
+#define ETHERNET_FCS_SIZE 4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+ (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+ (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH ETHERNET_FCS_SIZE
+#define MAX_JUMBO_FRAME_SIZE 0x3F00
+
+/* 802.1q VLAN Packet Sizes */
+#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */
+#define ETHERNET_IP_TYPE 0x0800 /* IP packets */
+#define ETHERNET_ARP_TYPE 0x0806 /* Address Resolution Protocol (ARP) */
+
+/* Packet Header defines */
+#define IP_PROTOCOL_TCP 6
+#define IP_PROTOCOL_UDP 0x11
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ)
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXT0 = Receiver Timer Interrupt (ring 0)
+ * o TXDW = Transmit Descriptor Written Back
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ * o LSC = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+ E1000_IMS_RXT0 | \
+ E1000_IMS_TXDW | \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ | \
+ E1000_IMS_LSC)
+
+/* The number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor. We
+ * reserve one of these spots for our directed address, allowing us room for
+ * E1000_RAR_ENTRIES - 1 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES 16
+
+#define MIN_NUMBER_OF_DESCRIPTORS 8
+#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+ uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+ uint16_t length; /* Length of data DMAed into data buffer */
+ uint16_t csum; /* Packet checksum */
+ uint8_t status; /* Descriptor status */
+ uint8_t errors; /* Descriptor Errors */
+ uint16_t special;
+};
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
+#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
+#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */
+#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
+#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
+#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
+#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 0x000D /* Priority is in upper 3 of 16 */
+#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 0x000C /* CFI is bit 12 */
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+ E1000_RXD_ERR_CE | \
+ E1000_RXD_ERR_SE | \
+ E1000_RXD_ERR_SEQ | \
+ E1000_RXD_ERR_CXE | \
+ E1000_RXD_ERR_RXE)
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+ uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ uint32_t data;
+ struct {
+ uint16_t length; /* Data buffer length */
+ uint8_t cso; /* Checksum offset */
+ uint8_t cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ uint32_t data;
+ struct {
+ uint8_t status; /* Descriptor status */
+ uint8_t css; /* Checksum start */
+ uint16_t special;
+ } fields;
+ } upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+ union {
+ uint32_t ip_config;
+ struct {
+ uint8_t ipcss; /* IP checksum start */
+ uint8_t ipcso; /* IP checksum offset */
+ uint16_t ipcse; /* IP checksum end */
+ } ip_fields;
+ } lower_setup;
+ union {
+ uint32_t tcp_config;
+ struct {
+ uint8_t tucss; /* TCP checksum start */
+ uint8_t tucso; /* TCP checksum offset */
+ uint16_t tucse; /* TCP checksum end */
+ } tcp_fields;
+ } upper_setup;
+ uint32_t cmd_and_length; /* */
+ union {
+ uint32_t data;
+ struct {
+ uint8_t status; /* Descriptor status */
+ uint8_t hdr_len; /* Header length */
+ uint16_t mss; /* Maximum segment size */
+ } fields;
+ } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+ uint64_t buffer_addr; /* Address of the descriptor's buffer address */
+ union {
+ uint32_t data;
+ struct {
+ uint16_t length; /* Data buffer length */
+ uint8_t typ_len_ext; /* */
+ uint8_t cmd; /* */
+ } flags;
+ } lower;
+ union {
+ uint32_t data;
+ struct {
+ uint8_t status; /* Descriptor status */
+ uint8_t popts; /* Packet Options */
+ uint16_t special; /* */
+ } fields;
+ } upper;
+};
+
+/* Filters */
+#define E1000_NUM_UNICAST 16 /* Unicast filter entries */
+#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address Register */
+struct e1000_rar {
+ volatile uint32_t low; /* receive address low */
+ volatile uint32_t high; /* receive address high */
+};
+
+/* The number of entries in the Multicast Table Array (MTA). */
+#define E1000_NUM_MTA_REGISTERS 128
+
+/* IPv4 Address Table Entry */
+struct e1000_ipv4_at_entry {
+ volatile uint32_t ipv4_addr; /* IP Address (RW) */
+ volatile uint32_t reserved;
+};
+
+/* Four wakeup IP addresses are supported */
+#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
+#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP6AT_SIZE 1
+
+/* IPv6 Address Table Entry */
+struct e1000_ipv6_at_entry {
+ volatile uint8_t ipv6_addr[16];
+};
+
+/* Flexible Filter Length Table Entry */
+struct e1000_fflt_entry {
+ volatile uint32_t length; /* Flexible Filter Length (RW) */
+ volatile uint32_t reserved;
+};
+
+/* Flexible Filter Mask Table Entry */
+struct e1000_ffmt_entry {
+ volatile uint32_t mask; /* Flexible Filter Mask (RW) */
+ volatile uint32_t reserved;
+};
+
+/* Flexible Filter Value Table Entry */
+struct e1000_ffvt_entry {
+ volatile uint32_t value; /* Flexible Filter Value (RW) */
+ volatile uint32_t reserved;
+};
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL 0x00000 /* Device Control - RW */
+#define E1000_STATUS 0x00008 /* Device Status - RO */
+#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
+#define E1000_EERD 0x00014 /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
+#define E1000_MDIC 0x00020 /* MDI Control - RW */
+#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
+#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
+#define E1000_FCT 0x00030 /* Flow Control Type - RW */
+#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
+#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
+#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
+#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
+#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
+#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
+#define E1000_RCTL 0x00100 /* RX Control - RW */
+#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */
+#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */
+#define E1000_TCTL 0x00400 /* TX Control - RW */
+#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */
+#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
+#define E1000_TBT 0x00448 /* TX Burst Timer - RW */
+#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
+#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
+#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
+#define FEXTNVM_SW_CONFIG 0x0001
+#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
+#define E1000_PBS 0x01008 /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
+#define E1000_FLASH_UPDATES 1000
+#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT 0x01028 /* FLASH Timer Register */
+#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL 0x01030 /* FLASH control register */
+#define E1000_FLSWDATA 0x01034 /* FLASH data register */
+#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */
+#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
+#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
+#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
+#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */
+#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */
+#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */
+#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */
+#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */
+#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
+#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */
+#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */
+#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
+#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
+#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
+#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */
+#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */
+#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */
+#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */
+#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */
+#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */
+#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */
+#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */
+#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */
+#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
+#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
+#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
+#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
+#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
+#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
+#define E1000_COLC 0x04028 /* Collision Count - R/clr */
+#define E1000_DC 0x04030 /* Defer Count - R/clr */
+#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */
+#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */
+#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */
+#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */
+#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */
+#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */
+#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */
+#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */
+#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */
+#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */
+#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */
+#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */
+#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */
+#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */
+#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */
+#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */
+#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */
+#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */
+#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
+#define E1000_RA 0x05400 /* Receive Address - RW Array */
+#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC 0x05800 /* Wakeup Control - RW */
+#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
+#define E1000_WUS 0x05810 /* Wakeup Status - RO */
+#define E1000_MANC 0x05820 /* Management Control - RW */
+#define E1000_IPAV 0x05838 /* IP Address Valid - RW */
+#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */
+#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
+#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
+#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
+#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */
+
+/* Register Set (82542)
+ *
+ * Some of the 82542 registers are located at different offsets than they are
+ * in more current versions of the 8254x. Despite the difference in location,
+ * the registers function in the same manner.
+ */
+#define E1000_82542_CTRL E1000_CTRL
+#define E1000_82542_STATUS E1000_STATUS
+#define E1000_82542_EECD E1000_EECD
+#define E1000_82542_EERD E1000_EERD
+#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_MDIC E1000_MDIC
+#define E1000_82542_FCAL E1000_FCAL
+#define E1000_82542_FCAH E1000_FCAH
+#define E1000_82542_FCT E1000_FCT
+#define E1000_82542_VET E1000_VET
+#define E1000_82542_RA 0x00040
+#define E1000_82542_ICR E1000_ICR
+#define E1000_82542_ITR E1000_ITR
+#define E1000_82542_ICS E1000_ICS
+#define E1000_82542_IMS E1000_IMS
+#define E1000_82542_IMC E1000_IMC
+#define E1000_82542_RCTL E1000_RCTL
+#define E1000_82542_RDTR 0x00108
+#define E1000_82542_RDBAL 0x00110
+#define E1000_82542_RDBAH 0x00114
+#define E1000_82542_RDLEN 0x00118
+#define E1000_82542_RDH 0x00120
+#define E1000_82542_RDT 0x00128
+#define E1000_82542_FCRTH 0x00160
+#define E1000_82542_FCRTL 0x00168
+#define E1000_82542_FCTTV E1000_FCTTV
+#define E1000_82542_TXCW E1000_TXCW
+#define E1000_82542_RXCW E1000_RXCW
+#define E1000_82542_MTA 0x00200
+#define E1000_82542_TCTL E1000_TCTL
+#define E1000_82542_TIPG E1000_TIPG
+#define E1000_82542_TDBAL 0x00420
+#define E1000_82542_TDBAH 0x00424
+#define E1000_82542_TDLEN 0x00428
+#define E1000_82542_TDH 0x00430
+#define E1000_82542_TDT 0x00438
+#define E1000_82542_TIDV 0x00440
+#define E1000_82542_TBT E1000_TBT
+#define E1000_82542_AIT E1000_AIT
+#define E1000_82542_VFTA 0x00600
+#define E1000_82542_LEDCTL E1000_LEDCTL
+#define E1000_82542_PBA E1000_PBA
+#define E1000_82542_RXDCTL E1000_RXDCTL
+#define E1000_82542_RADV E1000_RADV
+#define E1000_82542_RSRPD E1000_RSRPD
+#define E1000_82542_TXDMAC E1000_TXDMAC
+#define E1000_82542_TXDCTL E1000_TXDCTL
+#define E1000_82542_TADV E1000_TADV
+#define E1000_82542_TSPMT E1000_TSPMT
+#define E1000_82542_CRCERRS E1000_CRCERRS
+#define E1000_82542_ALGNERRC E1000_ALGNERRC
+#define E1000_82542_SYMERRS E1000_SYMERRS
+#define E1000_82542_RXERRC E1000_RXERRC
+#define E1000_82542_MPC E1000_MPC
+#define E1000_82542_SCC E1000_SCC
+#define E1000_82542_ECOL E1000_ECOL
+#define E1000_82542_MCC E1000_MCC
+#define E1000_82542_LATECOL E1000_LATECOL
+#define E1000_82542_COLC E1000_COLC
+#define E1000_82542_DC E1000_DC
+#define E1000_82542_TNCRS E1000_TNCRS
+#define E1000_82542_SEC E1000_SEC
+#define E1000_82542_CEXTERR E1000_CEXTERR
+#define E1000_82542_RLEC E1000_RLEC
+#define E1000_82542_XONRXC E1000_XONRXC
+#define E1000_82542_XONTXC E1000_XONTXC
+#define E1000_82542_XOFFRXC E1000_XOFFRXC
+#define E1000_82542_XOFFTXC E1000_XOFFTXC
+#define E1000_82542_FCRUC E1000_FCRUC
+#define E1000_82542_PRC64 E1000_PRC64
+#define E1000_82542_PRC127 E1000_PRC127
+#define E1000_82542_PRC255 E1000_PRC255
+#define E1000_82542_PRC511 E1000_PRC511
+#define E1000_82542_PRC1023 E1000_PRC1023
+#define E1000_82542_PRC1522 E1000_PRC1522
+#define E1000_82542_GPRC E1000_GPRC
+#define E1000_82542_BPRC E1000_BPRC
+#define E1000_82542_MPRC E1000_MPRC
+#define E1000_82542_GPTC E1000_GPTC
+#define E1000_82542_GORCL E1000_GORCL
+#define E1000_82542_GORCH E1000_GORCH
+#define E1000_82542_GOTCL E1000_GOTCL
+#define E1000_82542_GOTCH E1000_GOTCH
+#define E1000_82542_RNBC E1000_RNBC
+#define E1000_82542_RUC E1000_RUC
+#define E1000_82542_RFC E1000_RFC
+#define E1000_82542_ROC E1000_ROC
+#define E1000_82542_RJC E1000_RJC
+#define E1000_82542_MGTPRC E1000_MGTPRC
+#define E1000_82542_MGTPDC E1000_MGTPDC
+#define E1000_82542_MGTPTC E1000_MGTPTC
+#define E1000_82542_TORL E1000_TORL
+#define E1000_82542_TORH E1000_TORH
+#define E1000_82542_TOTL E1000_TOTL
+#define E1000_82542_TOTH E1000_TOTH
+#define E1000_82542_TPR E1000_TPR
+#define E1000_82542_TPT E1000_TPT
+#define E1000_82542_PTC64 E1000_PTC64
+#define E1000_82542_PTC127 E1000_PTC127
+#define E1000_82542_PTC255 E1000_PTC255
+#define E1000_82542_PTC511 E1000_PTC511
+#define E1000_82542_PTC1023 E1000_PTC1023
+#define E1000_82542_PTC1522 E1000_PTC1522
+#define E1000_82542_MPTC E1000_MPTC
+#define E1000_82542_BPTC E1000_BPTC
+#define E1000_82542_TSCTC E1000_TSCTC
+#define E1000_82542_TSCTFC E1000_TSCTFC
+#define E1000_82542_RXCSUM E1000_RXCSUM
+#define E1000_82542_WUC E1000_WUC
+#define E1000_82542_WUFC E1000_WUFC
+#define E1000_82542_WUS E1000_WUS
+#define E1000_82542_MANC E1000_MANC
+#define E1000_82542_IPAV E1000_IPAV
+#define E1000_82542_IP4AT E1000_IP4AT
+#define E1000_82542_IP6AT E1000_IP6AT
+#define E1000_82542_WUPL E1000_WUPL
+#define E1000_82542_WUPM E1000_WUPM
+#define E1000_82542_FFLT E1000_FFLT
+#define E1000_82542_FFMT E1000_FFMT
+#define E1000_82542_FFVT E1000_FFVT
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+ uint64_t crcerrs;
+ uint64_t algnerrc;
+ uint64_t symerrs;
+ uint64_t rxerrc;
+ uint64_t mpc;
+ uint64_t scc;
+ uint64_t ecol;
+ uint64_t mcc;
+ uint64_t latecol;
+ uint64_t colc;
+ uint64_t dc;
+ uint64_t tncrs;
+ uint64_t sec;
+ uint64_t cexterr;
+ uint64_t rlec;
+ uint64_t xonrxc;
+ uint64_t xontxc;
+ uint64_t xoffrxc;
+ uint64_t xofftxc;
+ uint64_t fcruc;
+ uint64_t prc64;
+ uint64_t prc127;
+ uint64_t prc255;
+ uint64_t prc511;
+ uint64_t prc1023;
+ uint64_t prc1522;
+ uint64_t gprc;
+ uint64_t bprc;
+ uint64_t mprc;
+ uint64_t gptc;
+ uint64_t gorcl;
+ uint64_t gorch;
+ uint64_t gotcl;
+ uint64_t gotch;
+ uint64_t rnbc;
+ uint64_t ruc;
+ uint64_t rfc;
+ uint64_t roc;
+ uint64_t rjc;
+ uint64_t mgprc;
+ uint64_t mgpdc;
+ uint64_t mgptc;
+ uint64_t torl;
+ uint64_t torh;
+ uint64_t totl;
+ uint64_t toth;
+ uint64_t tpr;
+ uint64_t tpt;
+ uint64_t ptc64;
+ uint64_t ptc127;
+ uint64_t ptc255;
+ uint64_t ptc511;
+ uint64_t ptc1023;
+ uint64_t ptc1522;
+ uint64_t mptc;
+ uint64_t bptc;
+ uint64_t tsctc;
+ uint64_t tsctfc;
+};
+
+#ifndef CONFIG_E1000_NO_NVM
+struct e1000_eeprom_info {
+e1000_eeprom_type type;
+ uint16_t word_size;
+ uint16_t opcode_bits;
+ uint16_t address_bits;
+ uint16_t delay_usec;
+ uint16_t page_size;
+ bool use_eerd;
+ bool use_eewr;
+};
+#endif
+
+typedef enum {
+ e1000_smart_speed_default = 0,
+ e1000_smart_speed_on,
+ e1000_smart_speed_off
+} e1000_smart_speed;
+
+typedef enum {
+ e1000_dsp_config_disabled = 0,
+ e1000_dsp_config_enabled,
+ e1000_dsp_config_activated,
+ e1000_dsp_config_undefined = 0xFF
+} e1000_dsp_config;
+
+typedef enum {
+ e1000_ms_hw_default = 0,
+ e1000_ms_force_master,
+ e1000_ms_force_slave,
+ e1000_ms_auto
+} e1000_ms_type;
+
+typedef enum {
+ e1000_ffe_config_enabled = 0,
+ e1000_ffe_config_active,
+ e1000_ffe_config_blocked
+} e1000_ffe_config;
+
+
+/* Structure containing variables used by the shared code (e1000_hw.c) */
+struct e1000_hw {
+ struct list_head list_node;
+ struct eth_device *nic;
+#ifdef CONFIG_E1000_SPI
+ struct spi_slave spi;
+#endif
+ unsigned int cardnum;
+
+ pci_dev_t pdev;
+ uint8_t *hw_addr;
+ e1000_mac_type mac_type;
+ e1000_phy_type phy_type;
+ uint32_t phy_init_script;
+ uint32_t txd_cmd;
+ e1000_media_type media_type;
+ e1000_fc_type fc;
+ e1000_bus_type bus_type;
+#if 0
+ e1000_bus_speed bus_speed;
+ e1000_bus_width bus_width;
+ uint32_t io_base;
+#endif
+ uint32_t asf_firmware_present;
+#ifndef CONFIG_E1000_NO_NVM
+ uint32_t eeprom_semaphore_present;
+#endif
+ uint32_t swfw_sync_present;
+ uint32_t swfwhw_semaphore_present;
+#ifndef CONFIG_E1000_NO_NVM
+ struct e1000_eeprom_info eeprom;
+#endif
+ e1000_ms_type master_slave;
+ e1000_ms_type original_master_slave;
+ e1000_ffe_config ffe_config_state;
+ uint32_t phy_id;
+ uint32_t phy_revision;
+ uint32_t phy_addr;
+ uint32_t original_fc;
+ uint32_t txcw;
+ uint32_t autoneg_failed;
+#if 0
+ uint32_t max_frame_size;
+ uint32_t min_frame_size;
+ uint32_t mc_filter_type;
+ uint32_t num_mc_addrs;
+ uint32_t collision_delta;
+ uint32_t tx_packet_delta;
+ uint32_t ledctl_default;
+ uint32_t ledctl_mode1;
+ uint32_t ledctl_mode2;
+#endif
+ uint16_t autoneg_advertised;
+ uint16_t pci_cmd_word;
+ uint16_t fc_high_water;
+ uint16_t fc_low_water;
+ uint16_t fc_pause_time;
+#if 0
+ uint16_t current_ifs_val;
+ uint16_t ifs_min_val;
+ uint16_t ifs_max_val;
+ uint16_t ifs_step_size;
+ uint16_t ifs_ratio;
+#endif
+ uint16_t device_id;
+ uint16_t vendor_id;
+ uint16_t subsystem_id;
+ uint16_t subsystem_vendor_id;
+ uint8_t revision_id;
+ uint8_t autoneg;
+ uint8_t mdix;
+ uint8_t forced_speed_duplex;
+ uint8_t wait_autoneg_complete;
+ uint8_t dma_fairness;
+#if 0
+ uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+#endif
+ bool disable_polarity_correction;
+ bool speed_downgraded;
+ bool get_link_status;
+ bool tbi_compatibility_en;
+ bool tbi_compatibility_on;
+ bool fc_strict_ieee;
+ bool fc_send_xon;
+ bool report_tx_early;
+ bool phy_reset_disable;
+ bool initialize_hw_bits_disable;
+#if 0
+ bool adaptive_ifs;
+ bool ifs_params_forced;
+ bool in_ifs_mode;
+#endif
+ e1000_smart_speed smart_speed;
+ e1000_dsp_config dsp_config_state;
+};
+
+#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */
+#define E1000_EEPROM_RW_REG_DATA 16 /* Offset to data in EEPROM
+ read/write registers */
+#define E1000_EEPROM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START 1 /* First bit for telling part to start
+ operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write
+ complete */
+#define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */
+#define EEPROM_RESERVED_WORD 0xFFFF
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */
+#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */
+#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */
+#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */
+#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
+#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST 0x04000000 /* Global reset */
+#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
+#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
+#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
+#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */
+#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
+#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
+#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */
+#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */
+#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */
+#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK 0x00000030
+#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+ * (0-small, 1-large) */
+
+#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD 0x00000200 /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT 11
+#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT 22
+#define E1000_STM_OPCODE 0xDB00
+#define E1000_HICR_FW_RESET 0xC0
+
+#define E1000_SHADOW_RAM_WORDS 2048
+#define E1000_ICH_NVM_SIG_WORD 0x13
+#define E1000_ICH_NVM_SIG_MASK 0xC0
+
+/* EEPROM Read */
+#define E1000_EERD_START 0x00000001 /* Start Read */
+#define E1000_EERD_DONE 0x00000010 /* Read Done */
+#define E1000_EERD_ADDR_SHIFT 8
+#define E1000_EERD_ADDR_MASK 0x0000FF00 /* Read Address */
+#define E1000_EERD_DATA_SHIFT 16
+#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */
+
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Commands - SPI */
+#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI 0x04 /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status register */
+#define EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */
+#define EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */
+#define EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */
+
+/* EEPROM Size definitions */
+#define EEPROM_WORD_SIZE_SHIFT 6
+#define EEPROM_SIZE_SHIFT 10
+#define EEPROM_SIZE_MASK 0x1C00
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT 0x0003
+#define EEPROM_ID_LED_SETTINGS 0x0004
+#define EEPROM_VERSION 0x0005
+#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude
+ adjustment. */
+#define EEPROM_PHY_CLASS_WORD 0x0007
+#define EEPROM_INIT_CONTROL1_REG 0x000A
+#define EEPROM_INIT_CONTROL2_REG 0x000F
+#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define EEPROM_INIT_CONTROL3_PORT_B 0x0014
+#define EEPROM_INIT_3GIO_3 0x001A
+#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define EEPROM_INIT_CONTROL3_PORT_A 0x0024
+#define EEPROM_CFG 0x0012
+#define EEPROM_FLASH_VERSION 0x0032
+#define EEPROM_CHECKSUM_REG 0x003F
+
+#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
+#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable
+ Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable
+ Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
+#define E1000_CTRL_EXT_SWDPIN6 0x00000040 /* SWDPIN 6 value */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SWDPIN7 0x00000080 /* SWDPIN 7 value */
+#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SWDPIO6 0x00000400 /* SWDPIN 6 Input or output */
+#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_SWDPIO7 0x00000800 /* SWDPIN 7 Input or output */
+#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000
+#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK 0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK 0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE 0x04000000
+#define E1000_MDIC_OP_READ 0x08000000
+#define E1000_MDIC_READY 0x10000000
+#define E1000_MDIC_INT_EN 0x20000000
+#define E1000_MDIC_ERROR 0x40000000
+
+#define E1000_PHY_CTRL_SPD_EN 0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU 0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
+#define E1000_PHY_CTRL_B2B_EN 0x00000080
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_IVRT 0x00000040
+#define E1000_LEDCTL_LED0_BLINK 0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT 8
+#define E1000_LEDCTL_LED1_IVRT 0x00004000
+#define E1000_LEDCTL_LED1_BLINK 0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT 16
+#define E1000_LEDCTL_LED2_IVRT 0x00400000
+#define E1000_LEDCTL_LED2_BLINK 0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_IVRT 0x40000000
+#define E1000_LEDCTL_LED3_BLINK 0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000 0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP 0x2
+#define E1000_LEDCTL_MODE_ACTIVITY 0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10 0x5
+#define E1000_LEDCTL_MODE_LINK_100 0x6
+#define E1000_LEDCTL_MODE_LINK_1000 0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE 0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9
+#define E1000_LEDCTL_MODE_COLLISION 0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED 0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE 0xC
+#define E1000_LEDCTL_MODE_PAUSED 0xD
+#define E1000_LEDCTL_MODE_LED_ON 0xE
+#define E1000_LEDCTL_MODE_LED_OFF 0xF
+
+/* Receive Address */
+#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC 0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO 0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW 0x00008000
+#define E1000_ICR_SRPD 0x00010000
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
+#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD E1000_ICR_SRPD
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
+#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD E1000_ICR_SRPD
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */
+#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD E1000_ICR_SRPD
+
+/* Receive Control */
+#define E1000_RCTL_RST 0x00000001 /* Software reset */
+#define E1000_RCTL_EN 0x00000002 /* enable */
+#define E1000_RCTL_SBP 0x00000004 /* store bad packet */
+#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */
+#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */
+#define E1000_RCTL_LPE 0x00000020 /* long packet enable */
+#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */
+#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
+#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
+#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */
+#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */
+#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */
+#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
+#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
+#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
+#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */
+#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
+#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
+
+/* SW_W_SYNC definitions */
+#define E1000_SWFW_EEP_SM 0x0001
+#define E1000_SWFW_PHY0_SM 0x0002
+#define E1000_SWFW_PHY1_SM 0x0004
+#define E1000_SWFW_MAC_CSR_SM 0x0008
+
+/* Receive Descriptor */
+#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */
+#define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */
+#define E1000_RDLEN_LEN 0x0007ff80 /* descriptor length */
+#define E1000_RDH_RDH 0x0000ffff /* receive descriptor head */
+#define E1000_RDT_RDT 0x0000ffff /* receive descriptor tail */
+
+/* Flow Control */
+#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */
+#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+
+/* Receive Descriptor Control */
+#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
+#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
+#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
+#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */
+#define E1000_RXDCTL_FULL_RX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+ still to be processed. */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */
+#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */
+#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */
+#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */
+#define E1000_TXCW_NP 0x00008000 /* TXCW next page */
+#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */
+#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */
+#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */
+#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */
+#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */
+#define E1000_RXCW_CC 0x10000000 /* Receive config change */
+#define E1000_RXCW_C 0x20000000 /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
+#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */
+
+/* Transmit Control */
+#define E1000_TCTL_RST 0x00000001 /* software reset */
+#define E1000_TCTL_EN 0x00000002 /* enable tx */
+#define E1000_TCTL_BCE 0x00000004 /* busy check enable */
+#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
+#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
+#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
+#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */
+#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME 0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */
+#define E1000_WUS_MAG 0x00000002 /* Magic Packet Received */
+#define E1000_WUS_EX 0x00000004 /* Directed Exact Received */
+#define E1000_WUS_MC 0x00000008 /* Directed Multicast Received */
+#define E1000_WUS_BC 0x00000010 /* Broadcast Received */
+#define E1000_WUS_ARP 0x00000020 /* ARP Request Packet Received */
+#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */
+#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */
+#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */
+#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */
+#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */
+#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */
+#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery
+ * Filtering */
+#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */
+
+#define E1000_MDALIGN 4096
+
+/* EEPROM Commands */
+#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */
+#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */
+#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */
+#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */
+#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2 0x1
+#define ID_LED_DEF1_ON2 0x2
+#define ID_LED_DEF1_OFF2 0x3
+#define ID_LED_ON1_DEF2 0x4
+#define ID_LED_ON1_ON2 0x5
+#define ID_LED_ON1_OFF2 0x6
+#define ID_LED_OFF1_DEF2 0x7
+#define ID_LED_OFF1_ON2 0x8
+#define ID_LED_OFF1_OFF2 0x9
+
+/* Mask bits for fields in Word 0x03 of the EEPROM */
+#define EEPROM_COMPAT_SERVER 0x0400
+#define EEPROM_COMPAT_CLIENT 0x0200
+
+/* Mask bits for fields in Word 0x0a of the EEPROM */
+#define EEPROM_WORD0A_ILOS 0x0010
+#define EEPROM_WORD0A_SWDPIO 0x01E0
+#define EEPROM_WORD0A_LRST 0x0200
+#define EEPROM_WORD0A_FD 0x0400
+#define EEPROM_WORD0A_66MHZ 0x0800
+
+/* Mask bits for fields in Word 0x0f of the EEPROM */
+#define EEPROM_WORD0F_PAUSE_MASK 0x3000
+#define EEPROM_WORD0F_PAUSE 0x1000
+#define EEPROM_WORD0F_ASM_DIR 0x2000
+#define EEPROM_WORD0F_ANE 0x0800
+#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+/* EEPROM Map defines (WORD OFFSETS)*/
+#define EEPROM_NODE_ADDRESS_BYTE_0 0
+#define EEPROM_PBA_BYTE_1 8
+
+/* EEPROM Map Sizes (Byte Counts) */
+#define PBA_SIZE 4
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD 0xF
+#define E1000_CT_SHIFT 4
+#define E1000_COLLISION_DISTANCE 63
+#define E1000_COLLISION_DISTANCE_82542 64
+#define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
+#define E1000_GB_HDX_COLLISION_DISTANCE 512
+#define E1000_COLD_SHIFT 12
+
+/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define REQ_RX_DESCRIPTOR_MULTIPLE 8
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82542_TIPG_IPGT 10
+#define DEFAULT_82543_TIPG_IPGT_FIBER 9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK 0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT 10
+
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT 20
+
+#define E1000_TXDMAC_DPP 0x00000001
+
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START 8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP 190
+#define TX_THRESHOLD_DISABLE 0
+#define TX_THRESHOLD_TIMER_MS 10000
+#define MIN_NUM_XMITS 1000
+#define IFS_MAX 80
+#define IFS_STEP 10
+#define IFS_MIN 40
+#define IFS_RATIO 4
+
+/* PBA constants */
+#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_38K 0x0026
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE 0x8808
+
+/* The historical defaults for the flow control values are given below. */
+#define FC_DEFAULT_HI_THRESH (0x8000) /* 32KB */
+#define FC_DEFAULT_LO_THRESH (0x4000) /* 16KB */
+#define FC_DEFAULT_TX_TIMER (0x100) /* ~130 us */
+
+/* Flow Control High-Watermark: 43464 bytes */
+#define E1000_FC_HIGH_THRESH 0xA9C8
+/* Flow Control Low-Watermark: 43456 bytes */
+#define E1000_FC_LOW_THRESH 0xA9C0
+/* Flow Control Pause Time: 858 usec */
+#define E1000_FC_PAUSE_TIME 0x0680
+
+/* PCIX Config space */
+#define PCIX_COMMAND_REGISTER 0xE6
+#define PCIX_STATUS_REGISTER_LO 0xE8
+#define PCIX_STATUS_REGISTER_HI 0xEA
+
+#define PCIX_COMMAND_MMRBC_MASK 0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT 0x2
+#define PCIX_STATUS_HI_MMRBC_MASK 0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5
+#define PCIX_STATUS_HI_MMRBC_4K 0x3
+#define PCIX_STATUS_HI_MMRBC_2K 0x2
+
+/* The number of bits that we need to shift right to move the "pause"
+ * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
+ * in the TXCW register
+ */
+#define PAUSE_SHIFT 5
+
+/* The number of bits that we need to shift left to move the "SWDPIO"
+ * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
+ * in the CTRL register
+ */
+#define SWDPIO_SHIFT 17
+
+/* The number of bits that we need to shift left to move the "SWDPIO_EXT"
+ * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
+ * Extended CTRL register.
+ * in the CTRL register
+ */
+#define SWDPIO__EXT_SHIFT 4
+
+/* The number of bits that we need to shift left to move the "ILOS"
+ * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
+ * in the CTRL register
+ */
+#define ILOS_SHIFT 3
+
+#define RECEIVE_BUFFER_ALIGN_SIZE (256)
+
+/* The number of milliseconds we wait for auto-negotiation to complete */
+#define LINK_UP_TIMEOUT 500
+
+#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION 0x0F
+
+/* TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ * adapter = a pointer to struct e1000_hw
+ * status = the 8 bit status field of the RX descriptor with EOP set
+ * error = the 8 bit error field of the RX descriptor with EOP set
+ * length = the sum of all the length fields of the RX descriptors that
+ * make up the current frame
+ * last_byte = the last byte of the frame DMAed by the hardware
+ * max_frame_length = the maximum frame length we want to accept.
+ * min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ * ...
+ * if (TBI_ACCEPT) {
+ * accept_frame = true;
+ * e1000_tbi_adjust_stats(adapter, MacAddress);
+ * frame_length--;
+ * } else {
+ * accept_frame = false;
+ * }
+ * ...
+ */
+
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
+ ((adapter)->tbi_compatibility_on && \
+ (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+ ((last_byte) == CARRIER_EXTENSION) && \
+ (((status) & E1000_RXD_STAT_VP) ? \
+ (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+ ((length) <= ((adapter)->max_frame_size + 1))) : \
+ (((length) > (adapter)->min_frame_size) && \
+ ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+
+#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
+
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00
+
+/* IGP01E1000 specifics */
+#define IGP01E1000_IEEE_REGS_PAGE 0x0000
+#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300
+#define IGP01E1000_IEEE_FORCE_GIGA 0x0140
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* PHY Specific Control Register */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
+#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP02E1000_PHY_POWER_MGMT 0x19
+#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */
+
+/* IGP01E1000 AGC Registers - stores the cable length values*/
+#define IGP01E1000_PHY_AGC_A 0x1172
+#define IGP01E1000_PHY_AGC_B 0x1272
+#define IGP01E1000_PHY_AGC_C 0x1472
+#define IGP01E1000_PHY_AGC_D 0x1872
+
+/* IGP01E1000 Specific Port Config Register - R/W */
+#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010
+#define IGP01E1000_PSCFR_PRE_EN 0x0020
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK 0x0100
+#define IGP01E1000_PSCFR_DISABLE_JABBER 0x0400
+#define IGP01E1000_PSCFR_DISABLE_TRANSMIT 0x2000
+/* IGP02E1000 AGC Registers for cable length values */
+#define IGP02E1000_PHY_AGC_A 0x11B1
+#define IGP02E1000_PHY_AGC_B 0x12B1
+#define IGP02E1000_PHY_AGC_C 0x14B1
+#define IGP02E1000_PHY_AGC_D 0x18B1
+
+#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D3_LPLU 0x0004 /* Enable LPLU in
+ non-D0a modes */
+#define IGP02E1000_PM_D0_LPLU 0x0002 /* Enable LPLU in
+ D0a mode */
+
+/* IGP01E1000 DSP Reset Register */
+#define IGP01E1000_PHY_DSP_RESET 0x1F33
+#define IGP01E1000_PHY_DSP_SET 0x1F71
+#define IGP01E1000_PHY_DSP_FFE 0x1F35
+
+#define IGP01E1000_PHY_CHANNEL_NUM 4
+#define IGP02E1000_PHY_CHANNEL_NUM 4
+
+#define IGP01E1000_PHY_AGC_PARAM_A 0x1171
+#define IGP01E1000_PHY_AGC_PARAM_B 0x1271
+#define IGP01E1000_PHY_AGC_PARAM_C 0x1471
+#define IGP01E1000_PHY_AGC_PARAM_D 0x1871
+
+#define IGP01E1000_PHY_EDAC_MU_INDEX 0xC000
+#define IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS 0x8000
+
+#define IGP01E1000_PHY_ANALOG_TX_STATE 0x2890
+#define IGP01E1000_PHY_ANALOG_CLASS_A 0x2000
+#define IGP01E1000_PHY_FORCE_ANALOG_ENABLE 0x0004
+#define IGP01E1000_PHY_DSP_FFE_CM_CP 0x0069
+
+#define IGP01E1000_PHY_DSP_FFE_DEFAULT 0x002A
+/* IGP01E1000 PCS Initialization register - stores the polarity status when
+ * speed = 1000 Mbps. */
+#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+#define IGP01E1000_PHY_PCS_CTRL_REG 0x00B5
+
+#define IGP01E1000_ANALOG_REGS_PAGE 0x20C0
+
+/* IGP01E1000 GMII FIFO Register */
+#define IGP01E1000_GMII_FLEX_SPD 0x10 /* Enable flexible speed
+ * on Link-Up */
+#define IGP01E1000_GMII_SPD 0x20 /* Enable SPD */
+
+/* IGP01E1000 Analog Register */
+#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS 0x20D1
+#define IGP01E1000_ANALOG_FUSE_STATUS 0x20D0
+#define IGP01E1000_ANALOG_FUSE_CONTROL 0x20DC
+#define IGP01E1000_ANALOG_FUSE_BYPASS 0x20DE
+
+#define IGP01E1000_ANALOG_FUSE_POLY_MASK 0xF000
+#define IGP01E1000_ANALOG_FUSE_FINE_MASK 0x0F80
+#define IGP01E1000_ANALOG_FUSE_COARSE_MASK 0x0070
+#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED 0x0100
+#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL 0x0002
+
+#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH 0x0040
+#define IGP01E1000_ANALOG_FUSE_COARSE_10 0x0010
+#define IGP01E1000_ANALOG_FUSE_FINE_1 0x0080
+#define IGP01E1000_ANALOG_FUSE_FINE_10 0x0500
+
+/* IGP01E1000 Specific Port Control Register - R/W */
+#define IGP01E1000_PSCR_TP_LOOPBACK 0x0010
+#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR 0x0200
+#define IGP01E1000_PSCR_TEN_CRS_SELECT 0x0400
+#define IGP01E1000_PSCR_FLIP_CHIP 0x0800
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0-MDI, 1-MDIX */
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_DISABLE_JABBER 0x0001 /* 1=Disable Jabber */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Polarity Reversal
+ Disabled */
+#define GG82563_PSCR_POWER_DOWN 0x0004 /* 1=Power Down */
+#define GG82563_PSCR_COPPER_TRANSMITER_DISABLE 0x0008 /* 1=Transmitter
+ Disabled */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI
+ configuration */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX
+ configuration */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Automatic
+ crossover */
+#define GG82563_PSCR_ENALBE_EXTENDED_DISTANCE 0x0080 /* 1=Enable Extended
+ Distance */
+#define GG82563_PSCR_ENERGY_DETECT_MASK 0x0300
+#define GG82563_PSCR_ENERGY_DETECT_OFF 0x0000 /* 00,01=Off */
+#define GG82563_PSCR_ENERGY_DETECT_RX 0x0200 /* 10=Sense on Rx only
+ (Energy Detect) */
+#define GG82563_PSCR_ENERGY_DETECT_RX_TM 0x0300 /* 11=Sense and Tx NLP */
+#define GG82563_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force Link Good */
+#define GG82563_PSCR_DOWNSHIFT_ENABLE 0x0800 /* 1=Enable Downshift */
+#define GG82563_PSCR_DOWNSHIFT_COUNTER_MASK 0x7000
+#define GG82563_PSCR_DOWNSHIFT_COUNTER_SHIFT 12
+
+/* PHY Specific Status Register (Page 0, Register 17) */
+#define GG82563_PSSR_JABBER 0x0001 /* 1=Jabber */
+#define GG82563_PSSR_POLARITY 0x0002 /* 1=Polarity Reversed */
+#define GG82563_PSSR_LINK 0x0008 /* 1=Link is Up */
+#define GG82563_PSSR_ENERGY_DETECT 0x0010 /* 1=Sleep, 0=Active */
+#define GG82563_PSSR_DOWNSHIFT 0x0020 /* 1=Downshift */
+#define GG82563_PSSR_CROSSOVER_STATUS 0x0040 /* 1=MDIX, 0=MDI */
+#define GG82563_PSSR_RX_PAUSE_ENABLED 0x0100 /* 1=Receive Pause Enabled */
+#define GG82563_PSSR_TX_PAUSE_ENABLED 0x0200 /* 1=Transmit Pause Enabled */
+#define GG82563_PSSR_LINK_UP 0x0400 /* 1=Link Up */
+#define GG82563_PSSR_SPEED_DUPLEX_RESOLVED 0x0800 /* 1=Resolved */
+#define GG82563_PSSR_PAGE_RECEIVED 0x1000 /* 1=Page Received */
+#define GG82563_PSSR_DUPLEX 0x2000 /* 1-Full-Duplex */
+#define GG82563_PSSR_SPEED_MASK 0xC000
+#define GG82563_PSSR_SPEED_10MBPS 0x0000 /* 00=10Mbps */
+#define GG82563_PSSR_SPEED_100MBPS 0x4000 /* 01=100Mbps */
+#define GG82563_PSSR_SPEED_1000MBPS 0x8000 /* 10=1000Mbps */
+
+/* PHY Specific Status Register 2 (Page 0, Register 19) */
+#define GG82563_PSSR2_JABBER 0x0001 /* 1=Jabber */
+#define GG82563_PSSR2_POLARITY_CHANGED 0x0002 /* 1=Polarity Changed */
+#define GG82563_PSSR2_ENERGY_DETECT_CHANGED 0x0010 /* 1=Energy Detect Changed */
+#define GG82563_PSSR2_DOWNSHIFT_INTERRUPT 0x0020 /* 1=Downshift Detected */
+#define GG82563_PSSR2_MDI_CROSSOVER_CHANGE 0x0040 /* 1=Crossover Changed */
+#define GG82563_PSSR2_FALSE_CARRIER 0x0100 /* 1=false Carrier */
+#define GG82563_PSSR2_SYMBOL_ERROR 0x0200 /* 1=Symbol Error */
+#define GG82563_PSSR2_LINK_STATUS_CHANGED 0x0400 /* 1=Link Status Changed */
+#define GG82563_PSSR2_AUTO_NEG_COMPLETED 0x0800 /* 1=Auto-Neg Completed */
+#define GG82563_PSSR2_PAGE_RECEIVED 0x1000 /* 1=Page Received */
+#define GG82563_PSSR2_DUPLEX_CHANGED 0x2000 /* 1=Duplex Changed */
+#define GG82563_PSSR2_SPEED_CHANGED 0x4000 /* 1=Speed Changed */
+#define GG82563_PSSR2_AUTO_NEG_ERROR 0x8000 /* 1=Auto-Neg Error */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_10BT_POLARITY_FORCE 0x0002 /* 1=Force Negative
+ Polarity */
+#define GG82563_PSCR2_1000MB_TEST_SELECT_MASK 0x000C
+#define GG82563_PSCR2_1000MB_TEST_SELECT_NORMAL 0x0000 /* 00,01=Normal
+ Operation */
+#define GG82563_PSCR2_1000MB_TEST_SELECT_112NS 0x0008 /* 10=Select 112ns
+ Sequence */
+#define GG82563_PSCR2_1000MB_TEST_SELECT_16NS 0x000C /* 11=Select 16ns
+ Sequence */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 /* 1=Reverse
+ Auto-Negotiation */
+#define GG82563_PSCR2_1000BT_DISABLE 0x4000 /* 1=Disable
+ 1000BASE-T */
+#define GG82563_PSCR2_TRANSMITER_TYPE_MASK 0x8000
+#define GG82563_PSCR2_TRANSMITTER_TYPE_CLASS_B 0x0000 /* 0=Class B */
+#define GG82563_PSCR2_TRANSMITTER_TYPE_CLASS_A 0x8000 /* 1=Class A */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK 0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ 0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25MHZ 0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_2_5MHZ 0x0006
+#define GG82563_MSCR_TX_CLK_1000MBPS_25MHZ 0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M;
+ 1 = 50-80M;
+ 2 = 80-110M;
+ 3 = 110-140M;
+ 4 = >140M */
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PHY_LEDS_EN 0x0020 /* 1=PHY LEDs,
+ 0=Kumeran Inband LEDs */
+#define GG82563_KMCR_FORCE_LINK_UP 0x0040 /* 1=Force Link Up */
+#define GG82563_KMCR_SUPPRESS_SGMII_EPD_EXT 0x0080
+#define GG82563_KMCR_MDIO_BUS_SPEED_SELECT_MASK 0x0400
+#define GG82563_KMCR_MDIO_BUS_SPEED_SELECT 0x0400 /* 1=6.25MHz,
+ 0=0.8MHz */
+#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 /* 1=Enalbe SERDES
+ Electrical Idle */
+#define GG82563_PMCR_DISABLE_PORT 0x0002 /* 1=Disable Port */
+#define GG82563_PMCR_DISABLE_SERDES 0x0004 /* 1=Disable SERDES */
+#define GG82563_PMCR_REVERSE_AUTO_NEG 0x0008 /* 1=Enable Reverse
+ Auto-Negotiation */
+#define GG82563_PMCR_DISABLE_1000_NON_D0 0x0010 /* 1=Disable 1000Mbps
+ Auto-Neg in non D0 */
+#define GG82563_PMCR_DISABLE_1000 0x0020 /* 1=Disable 1000Mbps
+ Auto-Neg Always */
+#define GG82563_PMCR_REVERSE_AUTO_NEG_D0A 0x0040 /* 1=Enable D0a
+ Reverse Auto-Negotiation */
+#define GG82563_PMCR_FORCE_POWER_STATE 0x0080 /* 1=Force Power State */
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_MASK 0x0300
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_DR 0x0000 /* 00=Dr */
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D0U 0x0100 /* 01=D0u */
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D0A 0x0200 /* 10=D0a */
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D3 0x0300 /* 11=D3 */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding Use */
+
+
+/* Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT 5
+#define GG82563_REG(page, reg) \
+ (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG 30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL \
+ GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS \
+ GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE \
+ GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2 \
+ GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR \
+ GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT \
+ GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2 \
+ GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT \
+ GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL \
+ GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL \
+ GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2 \
+ GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE \
+ GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL \
+ GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET \
+ GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID \
+ GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID \
+ GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL \
+ GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL \
+ GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+ GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL \
+ GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL \
+ GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC \
+ GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS \
+ GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY \
+ GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+ GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE \
+ GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+ GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC \
+ GG82563_REG(194, 26) /* Misc. */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */
+ /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low,
+ * 0=CLK125 toggling
+ */
+#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
+ /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover,
+ * 100BASE-TX/10BASE-T:
+ * MDI Mode
+ */
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
+ * all speeds.
+ */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+ /* 1=Enable Extended 10BASE-T distance
+ * (Lower 10BASE-T RX Threshold)
+ * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100
+ /* 1=5-Bit interface in 100BASE-TX
+ * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+ * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_MDIX_SHIFT 6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+
+/* Bit definitions for valid PHY IDs. */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define IGP01E1000_I_PHY_ID 0x02A80380
+#define M88E1011_I_REV_4 0x04
+#define M88E1111_I_PHY_ID 0x01410CC0
+#define L1LXT971A_PHY_ID 0x001378E0
+#define GG82563_E_PHY_ID 0x01410CA0
+
+#define BME1000_E_PHY_ID 0x01410CB0
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE 0xFFFFFFFF
+#define PHY_SOF 0x01
+#define PHY_OP_READ 0x02
+#define PHY_OP_WRITE 0x01
+#define PHY_TURNAROUND 0x02
+#define PHY_PREAMBLE_SIZE 32
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+#define E1000_PHY_ADDRESS 0x01
+#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK 0x01E0
+#define REG9_SPEED_MASK 0x0300
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+
+#define ICH_FLASH_GFPREG 0x0000
+#define ICH_FLASH_HSFSTS 0x0004
+#define ICH_FLASH_HSFCTL 0x0006
+#define ICH_FLASH_FADDR 0x0008
+#define ICH_FLASH_FDATA0 0x0010
+#define ICH_FLASH_FRACC 0x0050
+#define ICH_FLASH_FREG0 0x0054
+#define ICH_FLASH_FREG1 0x0058
+#define ICH_FLASH_FREG2 0x005C
+#define ICH_FLASH_FREG3 0x0060
+#define ICH_FLASH_FPR0 0x0074
+#define ICH_FLASH_FPR1 0x0078
+#define ICH_FLASH_SSFSTS 0x0090
+#define ICH_FLASH_SSFCTL 0x0092
+#define ICH_FLASH_PREOP 0x0094
+#define ICH_FLASH_OPTYPE 0x0096
+#define ICH_FLASH_OPMENU 0x0098
+
+#define ICH_FLASH_REG_MAPSIZE 0x00A0
+#define ICH_FLASH_SECTOR_SIZE 4096
+#define ICH_GFPREG_BASE_MASK 0x1FFF
+#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+
+#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+
+/* SPI EEPROM Status Register */
+#define EEPROM_STATUS_RDY_SPI 0x01
+#define EEPROM_STATUS_WEN_SPI 0x02
+#define EEPROM_STATUS_BP0_SPI 0x04
+#define EEPROM_STATUS_BP1_SPI 0x08
+#define EEPROM_STATUS_WPEN_SPI 0x80
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */
+
+/* FW Semaphore Register */
+#define E1000_FWSM_MODE_MASK 0x0000000E /* FW mode */
+#define E1000_FWSM_MODE_SHIFT 1
+#define E1000_FWSM_FW_VALID 0x00008000 /* FW established a valid mode */
+
+#define E1000_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI reset */
+#define E1000_FWSM_DISSW 0x10000000 /* FW disable SW Write Access */
+#define E1000_FWSM_SKUSEL_MASK 0x60000000 /* LAN SKU select */
+#define E1000_FWSM_SKUEL_SHIFT 29
+#define E1000_FWSM_SKUSEL_EMB 0x0 /* Embedded SKU */
+#define E1000_FWSM_SKUSEL_CONS 0x1 /* Consumer SKU */
+#define E1000_FWSM_SKUSEL_PERF_100 0x2 /* Perf & Corp 10/100 SKU */
+#define E1000_FWSM_SKUSEL_PERF_GBE 0x3 /* Perf & Copr GbE SKU */
+
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM 0x05B50 /* SW Semaphore */
+#define E1000_FWSM 0x05B54 /* FW Semaphore */
+#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
+#define E1000_HICR 0x08F00 /* Host Inteface Control */
+
+#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE 0x07000000
+
+/* Mask bit for PHY class in Word 7 of the EEPROM */
+#define EEPROM_PHY_CLASS_A 0x8000
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds*/
+#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds*/
+
+#define E1000_KUMCTRLSTA_MASK 0x0000FFFF
+#define E1000_KUMCTRLSTA_OFFSET 0x001F0000
+#define E1000_KUMCTRLSTA_OFFSET_SHIFT 16
+#define E1000_KUMCTRLSTA_REN 0x00200000
+
+#define E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL 0x00000000
+#define E1000_KUMCTRLSTA_OFFSET_CTRL 0x00000001
+#define E1000_KUMCTRLSTA_OFFSET_INB_CTRL 0x00000002
+#define E1000_KUMCTRLSTA_OFFSET_DIAG 0x00000003
+#define E1000_KUMCTRLSTA_OFFSET_TIMEOUTS 0x00000004
+#define E1000_KUMCTRLSTA_OFFSET_INB_PARAM 0x00000009
+#define E1000_KUMCTRLSTA_OFFSET_HD_CTRL 0x00000010
+#define E1000_KUMCTRLSTA_OFFSET_M2P_SERDES 0x0000001E
+#define E1000_KUMCTRLSTA_OFFSET_M2P_MODES 0x0000001F
+
+/* FIFO Control */
+#define E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS 0x00000008
+#define E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS 0x00000800
+
+/* In-Band Control */
+#define E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT 0x00000500
+#define E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010
+
+/* Half-Duplex Control */
+#define E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004
+#define E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000
+
+#define E1000_KUMCTRLSTA_OFFSET_K0S_CTRL 0x0000001E
+
+#define E1000_KUMCTRLSTA_DIAG_FELPBK 0x2000
+#define E1000_KUMCTRLSTA_DIAG_NELPBK 0x1000
+
+#define E1000_KUMCTRLSTA_K0S_100_EN 0x2000
+#define E1000_KUMCTRLSTA_K0S_GBE_EN 0x1000
+#define E1000_KUMCTRLSTA_K0S_ENTRY_LATENCY_MASK 0x0003
+
+#define E1000_MNG_ICH_IAMT_MODE 0x2
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
+#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT 100
+#define DEFAULT_80003ES2LAN_TIPG_IPGT_10_100 0x00000009
+#define DEFAULT_80003ES2LAN_TIPG_IPGT_1000 0x00000008
+#define AUTO_ALL_MODES 0
+
+#ifndef E1000_MASTER_SLAVE
+/* Switch to override PHY master/slave setting */
+#define E1000_MASTER_SLAVE e1000_ms_hw_default
+#endif
+/* Extended Transmit Control */
+#define E1000_TCTL_EXT_BST_MASK 0x000003FF /* Backoff Slot Time */
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+
+#define DEFAULT_80003ES2LAN_TCTL_EXT_GCEX 0x00010000
+
+#define PCI_EX_82566_SNOOP_ALL PCI_EX_NO_SNOOP_ALL
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+#define E1000_MC_TBL_SIZE_ICH8LAN 32
+
+#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers
+ after IMS clear */
+#endif /* _E1000_HW_H_ */
diff --git a/qemu/roms/u-boot/drivers/net/e1000_spi.c b/qemu/roms/u-boot/drivers/net/e1000_spi.c
new file mode 100644
index 000000000..93043a1ad
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/e1000_spi.c
@@ -0,0 +1,577 @@
+#include "e1000.h"
+#include <linux/compiler.h>
+
+/*-----------------------------------------------------------------------
+ * SPI transfer
+ *
+ * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
+ * "bitlen" bits in the SPI MISO port. That's just the way SPI works.
+ *
+ * The source of the outgoing bits is the "dout" parameter and the
+ * destination of the input bits is the "din" parameter. Note that "dout"
+ * and "din" can point to the same memory location, in which case the
+ * input data overwrites the output data (since both are buffered by
+ * temporary variables, this is OK).
+ *
+ * This may be interrupted with Ctrl-C if "intr" is true, otherwise it will
+ * never return an error.
+ */
+static int e1000_spi_xfer(struct e1000_hw *hw, unsigned int bitlen,
+ const void *dout_mem, void *din_mem, bool intr)
+{
+ const uint8_t *dout = dout_mem;
+ uint8_t *din = din_mem;
+
+ uint8_t mask = 0;
+ uint32_t eecd;
+ unsigned long i;
+
+ /* Pre-read the control register */
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Iterate over each bit */
+ for (i = 0, mask = 0x80; i < bitlen; i++, mask = (mask >> 1)?:0x80) {
+ /* Check for interrupt */
+ if (intr && ctrlc())
+ return -1;
+
+ /* Determine the output bit */
+ if (dout && dout[i >> 3] & mask)
+ eecd |= E1000_EECD_DI;
+ else
+ eecd &= ~E1000_EECD_DI;
+
+ /* Write the output bit and wait 50us */
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(50);
+
+ /* Poke the clock (waits 50us) */
+ e1000_raise_ee_clk(hw, &eecd);
+
+ /* Now read the input bit */
+ eecd = E1000_READ_REG(hw, EECD);
+ if (din) {
+ if (eecd & E1000_EECD_DO)
+ din[i >> 3] |= mask;
+ else
+ din[i >> 3] &= ~mask;
+ }
+
+ /* Poke the clock again (waits 50us) */
+ e1000_lower_ee_clk(hw, &eecd);
+ }
+
+ /* Now clear any remaining bits of the input */
+ if (din && (i & 7))
+ din[i >> 3] &= ~((mask << 1) - 1);
+
+ return 0;
+}
+
+#ifdef CONFIG_E1000_SPI_GENERIC
+static inline struct e1000_hw *e1000_hw_from_spi(struct spi_slave *spi)
+{
+ return container_of(spi, struct e1000_hw, spi);
+}
+
+/* Not sure why all of these are necessary */
+void spi_init_r(void) { /* Nothing to do */ }
+void spi_init_f(void) { /* Nothing to do */ }
+void spi_init(void) { /* Nothing to do */ }
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ /* Find the right PCI device */
+ struct e1000_hw *hw = e1000_find_card(bus);
+ if (!hw) {
+ printf("ERROR: No such e1000 device: e1000#%u\n", bus);
+ return NULL;
+ }
+
+ /* Make sure it has an SPI chip */
+ if (hw->eeprom.type != e1000_eeprom_spi) {
+ E1000_ERR(hw->nic, "No attached SPI EEPROM found!\n");
+ return NULL;
+ }
+
+ /* Argument sanity checks */
+ if (cs != 0) {
+ E1000_ERR(hw->nic, "No such SPI chip: %u\n", cs);
+ return NULL;
+ }
+ if (mode != SPI_MODE_0) {
+ E1000_ERR(hw->nic, "Only SPI MODE-0 is supported!\n");
+ return NULL;
+ }
+
+ /* TODO: Use max_hz somehow */
+ E1000_DBG(hw->nic, "EEPROM SPI access requested\n");
+ return &hw->spi;
+}
+
+void spi_free_slave(struct spi_slave *spi)
+{
+ __maybe_unused struct e1000_hw *hw = e1000_hw_from_spi(spi);
+ E1000_DBG(hw->nic, "EEPROM SPI access released\n");
+}
+
+int spi_claim_bus(struct spi_slave *spi)
+{
+ struct e1000_hw *hw = e1000_hw_from_spi(spi);
+
+ if (e1000_acquire_eeprom(hw)) {
+ E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *spi)
+{
+ struct e1000_hw *hw = e1000_hw_from_spi(spi);
+ e1000_release_eeprom(hw);
+}
+
+/* Skinny wrapper around e1000_spi_xfer */
+int spi_xfer(struct spi_slave *spi, unsigned int bitlen,
+ const void *dout_mem, void *din_mem, unsigned long flags)
+{
+ struct e1000_hw *hw = e1000_hw_from_spi(spi);
+ int ret;
+
+ if (flags & SPI_XFER_BEGIN)
+ e1000_standby_eeprom(hw);
+
+ ret = e1000_spi_xfer(hw, bitlen, dout_mem, din_mem, true);
+
+ if (flags & SPI_XFER_END)
+ e1000_standby_eeprom(hw);
+
+ return ret;
+}
+
+#endif /* not CONFIG_E1000_SPI_GENERIC */
+
+#ifdef CONFIG_CMD_E1000
+
+/* The EEPROM opcodes */
+#define SPI_EEPROM_ENABLE_WR 0x06
+#define SPI_EEPROM_DISABLE_WR 0x04
+#define SPI_EEPROM_WRITE_STATUS 0x01
+#define SPI_EEPROM_READ_STATUS 0x05
+#define SPI_EEPROM_WRITE_PAGE 0x02
+#define SPI_EEPROM_READ_PAGE 0x03
+
+/* The EEPROM status bits */
+#define SPI_EEPROM_STATUS_BUSY 0x01
+#define SPI_EEPROM_STATUS_WREN 0x02
+
+static int e1000_spi_eeprom_enable_wr(struct e1000_hw *hw, bool intr)
+{
+ u8 op[] = { SPI_EEPROM_ENABLE_WR };
+ e1000_standby_eeprom(hw);
+ return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
+}
+
+/*
+ * These have been tested to perform correctly, but they are not used by any
+ * of the EEPROM commands at this time.
+ */
+#if 0
+static int e1000_spi_eeprom_disable_wr(struct e1000_hw *hw, bool intr)
+{
+ u8 op[] = { SPI_EEPROM_DISABLE_WR };
+ e1000_standby_eeprom(hw);
+ return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
+}
+
+static int e1000_spi_eeprom_write_status(struct e1000_hw *hw,
+ u8 status, bool intr)
+{
+ u8 op[] = { SPI_EEPROM_WRITE_STATUS, status };
+ e1000_standby_eeprom(hw);
+ return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
+}
+#endif
+
+static int e1000_spi_eeprom_read_status(struct e1000_hw *hw, bool intr)
+{
+ u8 op[] = { SPI_EEPROM_READ_STATUS, 0 };
+ e1000_standby_eeprom(hw);
+ if (e1000_spi_xfer(hw, 8*sizeof(op), op, op, intr))
+ return -1;
+ return op[1];
+}
+
+static int e1000_spi_eeprom_write_page(struct e1000_hw *hw,
+ const void *data, u16 off, u16 len, bool intr)
+{
+ u8 op[] = {
+ SPI_EEPROM_WRITE_PAGE,
+ (off >> (hw->eeprom.address_bits - 8)) & 0xff, off & 0xff
+ };
+
+ e1000_standby_eeprom(hw);
+
+ if (e1000_spi_xfer(hw, 8 + hw->eeprom.address_bits, op, NULL, intr))
+ return -1;
+ if (e1000_spi_xfer(hw, len << 3, data, NULL, intr))
+ return -1;
+
+ return 0;
+}
+
+static int e1000_spi_eeprom_read_page(struct e1000_hw *hw,
+ void *data, u16 off, u16 len, bool intr)
+{
+ u8 op[] = {
+ SPI_EEPROM_READ_PAGE,
+ (off >> (hw->eeprom.address_bits - 8)) & 0xff, off & 0xff
+ };
+
+ e1000_standby_eeprom(hw);
+
+ if (e1000_spi_xfer(hw, 8 + hw->eeprom.address_bits, op, NULL, intr))
+ return -1;
+ if (e1000_spi_xfer(hw, len << 3, NULL, data, intr))
+ return -1;
+
+ return 0;
+}
+
+static int e1000_spi_eeprom_poll_ready(struct e1000_hw *hw, bool intr)
+{
+ int status;
+ while ((status = e1000_spi_eeprom_read_status(hw, intr)) >= 0) {
+ if (!(status & SPI_EEPROM_STATUS_BUSY))
+ return 0;
+ }
+ return -1;
+}
+
+static int e1000_spi_eeprom_dump(struct e1000_hw *hw,
+ void *data, u16 off, unsigned int len, bool intr)
+{
+ /* Interruptibly wait for the EEPROM to be ready */
+ if (e1000_spi_eeprom_poll_ready(hw, intr))
+ return -1;
+
+ /* Dump each page in sequence */
+ while (len) {
+ /* Calculate the data bytes on this page */
+ u16 pg_off = off & (hw->eeprom.page_size - 1);
+ u16 pg_len = hw->eeprom.page_size - pg_off;
+ if (pg_len > len)
+ pg_len = len;
+
+ /* Now dump the page */
+ if (e1000_spi_eeprom_read_page(hw, data, off, pg_len, intr))
+ return -1;
+
+ /* Otherwise go on to the next page */
+ len -= pg_len;
+ off += pg_len;
+ data += pg_len;
+ }
+
+ /* We're done! */
+ return 0;
+}
+
+static int e1000_spi_eeprom_program(struct e1000_hw *hw,
+ const void *data, u16 off, u16 len, bool intr)
+{
+ /* Program each page in sequence */
+ while (len) {
+ /* Calculate the data bytes on this page */
+ u16 pg_off = off & (hw->eeprom.page_size - 1);
+ u16 pg_len = hw->eeprom.page_size - pg_off;
+ if (pg_len > len)
+ pg_len = len;
+
+ /* Interruptibly wait for the EEPROM to be ready */
+ if (e1000_spi_eeprom_poll_ready(hw, intr))
+ return -1;
+
+ /* Enable write access */
+ if (e1000_spi_eeprom_enable_wr(hw, intr))
+ return -1;
+
+ /* Now program the page */
+ if (e1000_spi_eeprom_write_page(hw, data, off, pg_len, intr))
+ return -1;
+
+ /* Otherwise go on to the next page */
+ len -= pg_len;
+ off += pg_len;
+ data += pg_len;
+ }
+
+ /* Wait for the last write to complete */
+ if (e1000_spi_eeprom_poll_ready(hw, intr))
+ return -1;
+
+ /* We're done! */
+ return 0;
+}
+
+static int do_e1000_spi_show(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
+ int argc, char * const argv[])
+{
+ unsigned int length = 0;
+ u16 i, offset = 0;
+ u8 *buffer;
+ int err;
+
+ if (argc > 2) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ /* Parse the offset and length */
+ if (argc >= 1)
+ offset = simple_strtoul(argv[0], NULL, 0);
+ if (argc == 2)
+ length = simple_strtoul(argv[1], NULL, 0);
+ else if (offset < (hw->eeprom.word_size << 1))
+ length = (hw->eeprom.word_size << 1) - offset;
+
+ /* Extra sanity checks */
+ if (!length) {
+ E1000_ERR(hw->nic, "Requested zero-sized dump!\n");
+ return 1;
+ }
+ if ((0x10000 < length) || (0x10000 - length < offset)) {
+ E1000_ERR(hw->nic, "Can't dump past 0xFFFF!\n");
+ return 1;
+ }
+
+ /* Allocate a buffer to hold stuff */
+ buffer = malloc(length);
+ if (!buffer) {
+ E1000_ERR(hw->nic, "Out of Memory!\n");
+ return 1;
+ }
+
+ /* Acquire the EEPROM and perform the dump */
+ if (e1000_acquire_eeprom(hw)) {
+ E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ free(buffer);
+ return 1;
+ }
+ err = e1000_spi_eeprom_dump(hw, buffer, offset, length, true);
+ e1000_release_eeprom(hw);
+ if (err) {
+ E1000_ERR(hw->nic, "Interrupted!\n");
+ free(buffer);
+ return 1;
+ }
+
+ /* Now hexdump the result */
+ printf("%s: ===== Intel e1000 EEPROM (0x%04hX - 0x%04hX) =====",
+ hw->nic->name, offset, offset + length - 1);
+ for (i = 0; i < length; i++) {
+ if ((i & 0xF) == 0)
+ printf("\n%s: %04hX: ", hw->nic->name, offset + i);
+ else if ((i & 0xF) == 0x8)
+ printf(" ");
+ printf(" %02hx", buffer[i]);
+ }
+ printf("\n");
+
+ /* Success! */
+ free(buffer);
+ return 0;
+}
+
+static int do_e1000_spi_dump(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
+ int argc, char * const argv[])
+{
+ unsigned int length;
+ u16 offset;
+ void *dest;
+
+ if (argc != 3) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ /* Parse the arguments */
+ dest = (void *)simple_strtoul(argv[0], NULL, 16);
+ offset = simple_strtoul(argv[1], NULL, 0);
+ length = simple_strtoul(argv[2], NULL, 0);
+
+ /* Extra sanity checks */
+ if (!length) {
+ E1000_ERR(hw->nic, "Requested zero-sized dump!\n");
+ return 1;
+ }
+ if ((0x10000 < length) || (0x10000 - length < offset)) {
+ E1000_ERR(hw->nic, "Can't dump past 0xFFFF!\n");
+ return 1;
+ }
+
+ /* Acquire the EEPROM */
+ if (e1000_acquire_eeprom(hw)) {
+ E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ return 1;
+ }
+
+ /* Perform the programming operation */
+ if (e1000_spi_eeprom_dump(hw, dest, offset, length, true) < 0) {
+ E1000_ERR(hw->nic, "Interrupted!\n");
+ e1000_release_eeprom(hw);
+ return 1;
+ }
+
+ e1000_release_eeprom(hw);
+ printf("%s: ===== EEPROM DUMP COMPLETE =====\n", hw->nic->name);
+ return 0;
+}
+
+static int do_e1000_spi_program(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
+ int argc, char * const argv[])
+{
+ unsigned int length;
+ const void *source;
+ u16 offset;
+
+ if (argc != 3) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ /* Parse the arguments */
+ source = (const void *)simple_strtoul(argv[0], NULL, 16);
+ offset = simple_strtoul(argv[1], NULL, 0);
+ length = simple_strtoul(argv[2], NULL, 0);
+
+ /* Acquire the EEPROM */
+ if (e1000_acquire_eeprom(hw)) {
+ E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ return 1;
+ }
+
+ /* Perform the programming operation */
+ if (e1000_spi_eeprom_program(hw, source, offset, length, true) < 0) {
+ E1000_ERR(hw->nic, "Interrupted!\n");
+ e1000_release_eeprom(hw);
+ return 1;
+ }
+
+ e1000_release_eeprom(hw);
+ printf("%s: ===== EEPROM PROGRAMMED =====\n", hw->nic->name);
+ return 0;
+}
+
+static int do_e1000_spi_checksum(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
+ int argc, char * const argv[])
+{
+ uint16_t i, length, checksum = 0, checksum_reg;
+ uint16_t *buffer;
+ bool upd;
+
+ if (argc == 0)
+ upd = 0;
+ else if ((argc == 1) && !strcmp(argv[0], "update"))
+ upd = 1;
+ else {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ /* Allocate a temporary buffer */
+ length = sizeof(uint16_t) * (EEPROM_CHECKSUM_REG + 1);
+ buffer = malloc(length);
+ if (!buffer) {
+ E1000_ERR(hw->nic, "Unable to allocate EEPROM buffer!\n");
+ return 1;
+ }
+
+ /* Acquire the EEPROM */
+ if (e1000_acquire_eeprom(hw)) {
+ E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ return 1;
+ }
+
+ /* Read the EEPROM */
+ if (e1000_spi_eeprom_dump(hw, buffer, 0, length, true) < 0) {
+ E1000_ERR(hw->nic, "Interrupted!\n");
+ e1000_release_eeprom(hw);
+ return 1;
+ }
+
+ /* Compute the checksum and read the expected value */
+ for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
+ checksum += le16_to_cpu(buffer[i]);
+ checksum = ((uint16_t)EEPROM_SUM) - checksum;
+ checksum_reg = le16_to_cpu(buffer[i]);
+
+ /* Verify it! */
+ if (checksum_reg == checksum) {
+ printf("%s: INFO: EEPROM checksum is correct! (0x%04hx)\n",
+ hw->nic->name, checksum);
+ e1000_release_eeprom(hw);
+ return 0;
+ }
+
+ /* Hrm, verification failed, print an error */
+ E1000_ERR(hw->nic, "EEPROM checksum is incorrect!\n");
+ E1000_ERR(hw->nic, " ...register was 0x%04hx, calculated 0x%04hx\n",
+ checksum_reg, checksum);
+
+ /* If they didn't ask us to update it, just return an error */
+ if (!upd) {
+ e1000_release_eeprom(hw);
+ return 1;
+ }
+
+ /* Ok, correct it! */
+ printf("%s: Reprogramming the EEPROM checksum...\n", hw->nic->name);
+ buffer[i] = cpu_to_le16(checksum);
+ if (e1000_spi_eeprom_program(hw, &buffer[i], i * sizeof(uint16_t),
+ sizeof(uint16_t), true)) {
+ E1000_ERR(hw->nic, "Interrupted!\n");
+ e1000_release_eeprom(hw);
+ return 1;
+ }
+
+ e1000_release_eeprom(hw);
+ return 0;
+}
+
+int do_e1000_spi(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
+ int argc, char * const argv[])
+{
+ if (argc < 1) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ /* Make sure it has an SPI chip */
+ if (hw->eeprom.type != e1000_eeprom_spi) {
+ E1000_ERR(hw->nic, "No attached SPI EEPROM found!\n");
+ return 1;
+ }
+
+ /* Check the eeprom sub-sub-command arguments */
+ if (!strcmp(argv[0], "show"))
+ return do_e1000_spi_show(cmdtp, hw, argc - 1, argv + 1);
+
+ if (!strcmp(argv[0], "dump"))
+ return do_e1000_spi_dump(cmdtp, hw, argc - 1, argv + 1);
+
+ if (!strcmp(argv[0], "program"))
+ return do_e1000_spi_program(cmdtp, hw, argc - 1, argv + 1);
+
+ if (!strcmp(argv[0], "checksum"))
+ return do_e1000_spi_checksum(cmdtp, hw, argc - 1, argv + 1);
+
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+#endif /* not CONFIG_CMD_E1000 */
diff --git a/qemu/roms/u-boot/drivers/net/eepro100.c b/qemu/roms/u-boot/drivers/net/eepro100.c
new file mode 100644
index 000000000..1e4ea0c89
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/eepro100.c
@@ -0,0 +1,931 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <miiphy.h>
+
+#undef DEBUG
+
+ /* Ethernet chip registers.
+ */
+#define SCBStatus 0 /* Rx/Command Unit Status *Word* */
+#define SCBIntAckByte 1 /* Rx/Command Unit STAT/ACK byte */
+#define SCBCmd 2 /* Rx/Command Unit Command *Word* */
+#define SCBIntrCtlByte 3 /* Rx/Command Unit Intr.Control Byte */
+#define SCBPointer 4 /* General purpose pointer. */
+#define SCBPort 8 /* Misc. commands and operands. */
+#define SCBflash 12 /* Flash memory control. */
+#define SCBeeprom 14 /* EEPROM memory control. */
+#define SCBCtrlMDI 16 /* MDI interface control. */
+#define SCBEarlyRx 20 /* Early receive byte count. */
+#define SCBGenControl 28 /* 82559 General Control Register */
+#define SCBGenStatus 29 /* 82559 General Status register */
+
+ /* 82559 SCB status word defnitions
+ */
+#define SCB_STATUS_CX 0x8000 /* CU finished command (transmit) */
+#define SCB_STATUS_FR 0x4000 /* frame received */
+#define SCB_STATUS_CNA 0x2000 /* CU left active state */
+#define SCB_STATUS_RNR 0x1000 /* receiver left ready state */
+#define SCB_STATUS_MDI 0x0800 /* MDI read/write cycle done */
+#define SCB_STATUS_SWI 0x0400 /* software generated interrupt */
+#define SCB_STATUS_FCP 0x0100 /* flow control pause interrupt */
+
+#define SCB_INTACK_MASK 0xFD00 /* all the above */
+
+#define SCB_INTACK_TX (SCB_STATUS_CX | SCB_STATUS_CNA)
+#define SCB_INTACK_RX (SCB_STATUS_FR | SCB_STATUS_RNR)
+
+ /* System control block commands
+ */
+/* CU Commands */
+#define CU_NOP 0x0000
+#define CU_START 0x0010
+#define CU_RESUME 0x0020
+#define CU_STATSADDR 0x0040 /* Load Dump Statistics ctrs addr */
+#define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */
+#define CU_ADDR_LOAD 0x0060 /* Base address to add to CU commands */
+#define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */
+
+/* RUC Commands */
+#define RUC_NOP 0x0000
+#define RUC_START 0x0001
+#define RUC_RESUME 0x0002
+#define RUC_ABORT 0x0004
+#define RUC_ADDR_LOAD 0x0006 /* (seems not to clear on acceptance) */
+#define RUC_RESUMENR 0x0007
+
+#define CU_CMD_MASK 0x00f0
+#define RU_CMD_MASK 0x0007
+
+#define SCB_M 0x0100 /* 0 = enable interrupt, 1 = disable */
+#define SCB_SWI 0x0200 /* 1 - cause device to interrupt */
+
+#define CU_STATUS_MASK 0x00C0
+#define RU_STATUS_MASK 0x003C
+
+#define RU_STATUS_IDLE (0<<2)
+#define RU_STATUS_SUS (1<<2)
+#define RU_STATUS_NORES (2<<2)
+#define RU_STATUS_READY (4<<2)
+#define RU_STATUS_NO_RBDS_SUS ((1<<2)|(8<<2))
+#define RU_STATUS_NO_RBDS_NORES ((2<<2)|(8<<2))
+#define RU_STATUS_NO_RBDS_READY ((4<<2)|(8<<2))
+
+ /* 82559 Port interface commands.
+ */
+#define I82559_RESET 0x00000000 /* Software reset */
+#define I82559_SELFTEST 0x00000001 /* 82559 Selftest command */
+#define I82559_SELECTIVE_RESET 0x00000002
+#define I82559_DUMP 0x00000003
+#define I82559_DUMP_WAKEUP 0x00000007
+
+ /* 82559 Eeprom interface.
+ */
+#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
+#define EE_CS 0x02 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x01
+#define EE_WRITE_1 0x05
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_ENB (0x4800 | EE_CS)
+#define EE_CMD_BITS 3
+#define EE_DATA_BITS 16
+
+ /* The EEPROM commands include the alway-set leading bit.
+ */
+#define EE_EWENB_CMD (4 << addr_len)
+#define EE_WRITE_CMD (5 << addr_len)
+#define EE_READ_CMD (6 << addr_len)
+#define EE_ERASE_CMD (7 << addr_len)
+
+ /* Receive frame descriptors.
+ */
+struct RxFD {
+ volatile u16 status;
+ volatile u16 control;
+ volatile u32 link; /* struct RxFD * */
+ volatile u32 rx_buf_addr; /* void * */
+ volatile u32 count;
+
+ volatile u8 data[PKTSIZE_ALIGN];
+};
+
+#define RFD_STATUS_C 0x8000 /* completion of received frame */
+#define RFD_STATUS_OK 0x2000 /* frame received with no errors */
+
+#define RFD_CONTROL_EL 0x8000 /* 1=last RFD in RFA */
+#define RFD_CONTROL_S 0x4000 /* 1=suspend RU after receiving frame */
+#define RFD_CONTROL_H 0x0010 /* 1=RFD is a header RFD */
+#define RFD_CONTROL_SF 0x0008 /* 0=simplified, 1=flexible mode */
+
+#define RFD_COUNT_MASK 0x3fff
+#define RFD_COUNT_F 0x4000
+#define RFD_COUNT_EOF 0x8000
+
+#define RFD_RX_CRC 0x0800 /* crc error */
+#define RFD_RX_ALIGNMENT 0x0400 /* alignment error */
+#define RFD_RX_RESOURCE 0x0200 /* out of space, no resources */
+#define RFD_RX_DMA_OVER 0x0100 /* DMA overrun */
+#define RFD_RX_SHORT 0x0080 /* short frame error */
+#define RFD_RX_LENGTH 0x0020
+#define RFD_RX_ERROR 0x0010 /* receive error */
+#define RFD_RX_NO_ADR_MATCH 0x0004 /* no address match */
+#define RFD_RX_IA_MATCH 0x0002 /* individual address does not match */
+#define RFD_RX_TCO 0x0001 /* TCO indication */
+
+ /* Transmit frame descriptors
+ */
+struct TxFD { /* Transmit frame descriptor set. */
+ volatile u16 status;
+ volatile u16 command;
+ volatile u32 link; /* void * */
+ volatile u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
+ volatile s32 count;
+
+ volatile u32 tx_buf_addr0; /* void *, frame to be transmitted. */
+ volatile s32 tx_buf_size0; /* Length of Tx frame. */
+ volatile u32 tx_buf_addr1; /* void *, frame to be transmitted. */
+ volatile s32 tx_buf_size1; /* Length of Tx frame. */
+};
+
+#define TxCB_CMD_TRANSMIT 0x0004 /* transmit command */
+#define TxCB_CMD_SF 0x0008 /* 0=simplified, 1=flexible mode */
+#define TxCB_CMD_NC 0x0010 /* 0=CRC insert by controller */
+#define TxCB_CMD_I 0x2000 /* generate interrupt on completion */
+#define TxCB_CMD_S 0x4000 /* suspend on completion */
+#define TxCB_CMD_EL 0x8000 /* last command block in CBL */
+
+#define TxCB_COUNT_MASK 0x3fff
+#define TxCB_COUNT_EOF 0x8000
+
+ /* The Speedo3 Rx and Tx frame/buffer descriptors.
+ */
+struct descriptor { /* A generic descriptor. */
+ volatile u16 status;
+ volatile u16 command;
+ volatile u32 link; /* struct descriptor * */
+
+ unsigned char params[0];
+};
+
+#define CONFIG_SYS_CMD_EL 0x8000
+#define CONFIG_SYS_CMD_SUSPEND 0x4000
+#define CONFIG_SYS_CMD_INT 0x2000
+#define CONFIG_SYS_CMD_IAS 0x0001 /* individual address setup */
+#define CONFIG_SYS_CMD_CONFIGURE 0x0002 /* configure */
+
+#define CONFIG_SYS_STATUS_C 0x8000
+#define CONFIG_SYS_STATUS_OK 0x2000
+
+ /* Misc.
+ */
+#define NUM_RX_DESC PKTBUFSRX
+#define NUM_TX_DESC 1 /* Number of TX descriptors */
+
+#define TOUT_LOOP 1000000
+
+#define ETH_ALEN 6
+
+static struct RxFD rx_ring[NUM_RX_DESC]; /* RX descriptor ring */
+static struct TxFD tx_ring[NUM_TX_DESC]; /* TX descriptor ring */
+static int rx_next; /* RX descriptor ring pointer */
+static int tx_next; /* TX descriptor ring pointer */
+static int tx_threshold;
+
+/*
+ * The parameters for a CmdConfigure operation.
+ * There are so many options that it would be difficult to document
+ * each bit. We mostly use the default or recommended settings.
+ */
+static const char i82557_config_cmd[] = {
+ 22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
+ 0, 0x2E, 0, 0x60, 0,
+ 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
+ 0x3f, 0x05,
+};
+static const char i82558_config_cmd[] = {
+ 22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
+ 0, 0x2E, 0, 0x60, 0x08, 0x88,
+ 0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */
+ 0x31, 0x05,
+};
+
+static void init_rx_ring (struct eth_device *dev);
+static void purge_tx_ring (struct eth_device *dev);
+
+static void read_hw_addr (struct eth_device *dev, bd_t * bis);
+
+static int eepro100_init (struct eth_device *dev, bd_t * bis);
+static int eepro100_send(struct eth_device *dev, void *packet, int length);
+static int eepro100_recv (struct eth_device *dev);
+static void eepro100_halt (struct eth_device *dev);
+
+#if defined(CONFIG_E500) || defined(CONFIG_DB64360) || defined(CONFIG_DB64460)
+#define bus_to_phys(a) (a)
+#define phys_to_bus(a) (a)
+#else
+#define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
+#endif
+
+static inline int INW (struct eth_device *dev, u_long addr)
+{
+ return le16_to_cpu (*(volatile u16 *) (addr + dev->iobase));
+}
+
+static inline void OUTW (struct eth_device *dev, int command, u_long addr)
+{
+ *(volatile u16 *) ((addr + dev->iobase)) = cpu_to_le16 (command);
+}
+
+static inline void OUTL (struct eth_device *dev, int command, u_long addr)
+{
+ *(volatile u32 *) ((addr + dev->iobase)) = cpu_to_le32 (command);
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static inline int INL (struct eth_device *dev, u_long addr)
+{
+ return le32_to_cpu (*(volatile u32 *) (addr + dev->iobase));
+}
+
+static int get_phyreg (struct eth_device *dev, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ int cmd;
+ int timeout = 50;
+
+ /* read requested data */
+ cmd = (2 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16);
+ OUTL (dev, cmd, SCBCtrlMDI);
+
+ do {
+ udelay(1000);
+ cmd = INL (dev, SCBCtrlMDI);
+ } while (!(cmd & (1 << 28)) && (--timeout));
+
+ if (timeout == 0)
+ return -1;
+
+ *value = (unsigned short) (cmd & 0xffff);
+
+ return 0;
+}
+
+static int set_phyreg (struct eth_device *dev, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ int cmd;
+ int timeout = 50;
+
+ /* write requested data */
+ cmd = (1 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16);
+ OUTL (dev, cmd | value, SCBCtrlMDI);
+
+ while (!(INL (dev, SCBCtrlMDI) & (1 << 28)) && (--timeout))
+ udelay(1000);
+
+ if (timeout == 0)
+ return -1;
+
+ return 0;
+}
+
+/* Check if given phyaddr is valid, i.e. there is a PHY connected.
+ * Do this by checking model value field from ID2 register.
+ */
+static struct eth_device* verify_phyaddr (const char *devname,
+ unsigned char addr)
+{
+ struct eth_device *dev;
+ unsigned short value;
+ unsigned char model;
+
+ dev = eth_get_dev_by_name(devname);
+ if (dev == NULL) {
+ printf("%s: no such device\n", devname);
+ return NULL;
+ }
+
+ /* read id2 register */
+ if (get_phyreg(dev, addr, MII_PHYSID2, &value) != 0) {
+ printf("%s: mii read timeout!\n", devname);
+ return NULL;
+ }
+
+ /* get model */
+ model = (unsigned char)((value >> 4) & 0x003f);
+
+ if (model == 0) {
+ printf("%s: no PHY at address %d\n", devname, addr);
+ return NULL;
+ }
+
+ return dev;
+}
+
+static int eepro100_miiphy_read(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ struct eth_device *dev;
+
+ dev = verify_phyaddr(devname, addr);
+ if (dev == NULL)
+ return -1;
+
+ if (get_phyreg(dev, addr, reg, value) != 0) {
+ printf("%s: mii read timeout!\n", devname);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int eepro100_miiphy_write(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ struct eth_device *dev;
+
+ dev = verify_phyaddr(devname, addr);
+ if (dev == NULL)
+ return -1;
+
+ if (set_phyreg(dev, addr, reg, value) != 0) {
+ printf("%s: mii write timeout!\n", devname);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif
+
+/* Wait for the chip get the command.
+*/
+static int wait_for_eepro100 (struct eth_device *dev)
+{
+ int i;
+
+ for (i = 0; INW (dev, SCBCmd) & (CU_CMD_MASK | RU_CMD_MASK); i++) {
+ if (i >= TOUT_LOOP) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static struct pci_device_id supported[] = {
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER},
+ {}
+};
+
+int eepro100_initialize (bd_t * bis)
+{
+ pci_dev_t devno;
+ int card_number = 0;
+ struct eth_device *dev;
+ u32 iobase, status;
+ int idx = 0;
+
+ while (1) {
+ /* Find PCI device
+ */
+ if ((devno = pci_find_devices (supported, idx++)) < 0) {
+ break;
+ }
+
+ pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase);
+ iobase &= ~0xf;
+
+#ifdef DEBUG
+ printf ("eepro100: Intel i82559 PCI EtherExpressPro @0x%x\n",
+ iobase);
+#endif
+
+ pci_write_config_dword (devno,
+ PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ /* Check if I/O accesses and Bus Mastering are enabled.
+ */
+ pci_read_config_dword (devno, PCI_COMMAND, &status);
+ if (!(status & PCI_COMMAND_MEMORY)) {
+ printf ("Error: Can not enable MEM access.\n");
+ continue;
+ }
+
+ if (!(status & PCI_COMMAND_MASTER)) {
+ printf ("Error: Can not enable Bus Mastering.\n");
+ continue;
+ }
+
+ dev = (struct eth_device *) malloc (sizeof *dev);
+ if (!dev) {
+ printf("eepro100: Can not allocate memory\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf (dev->name, "i82559#%d", card_number);
+ dev->priv = (void *) devno; /* this have to come before bus_to_phys() */
+ dev->iobase = bus_to_phys (iobase);
+ dev->init = eepro100_init;
+ dev->halt = eepro100_halt;
+ dev->send = eepro100_send;
+ dev->recv = eepro100_recv;
+
+ eth_register (dev);
+
+#if defined (CONFIG_MII) || defined(CONFIG_CMD_MII)
+ /* register mii command access routines */
+ miiphy_register(dev->name,
+ eepro100_miiphy_read, eepro100_miiphy_write);
+#endif
+
+ card_number++;
+
+ /* Set the latency timer for value.
+ */
+ pci_write_config_byte (devno, PCI_LATENCY_TIMER, 0x20);
+
+ udelay (10 * 1000);
+
+ read_hw_addr (dev, bis);
+ }
+
+ return card_number;
+}
+
+
+static int eepro100_init (struct eth_device *dev, bd_t * bis)
+{
+ int i, status = -1;
+ int tx_cur;
+ struct descriptor *ias_cmd, *cfg_cmd;
+
+ /* Reset the ethernet controller
+ */
+ OUTL (dev, I82559_SELECTIVE_RESET, SCBPort);
+ udelay (20);
+
+ OUTL (dev, I82559_RESET, SCBPort);
+ udelay (20);
+
+ if (!wait_for_eepro100 (dev)) {
+ printf ("Error: Can not reset ethernet controller.\n");
+ goto Done;
+ }
+ OUTL (dev, 0, SCBPointer);
+ OUTW (dev, SCB_M | RUC_ADDR_LOAD, SCBCmd);
+
+ if (!wait_for_eepro100 (dev)) {
+ printf ("Error: Can not reset ethernet controller.\n");
+ goto Done;
+ }
+ OUTL (dev, 0, SCBPointer);
+ OUTW (dev, SCB_M | CU_ADDR_LOAD, SCBCmd);
+
+ /* Initialize Rx and Tx rings.
+ */
+ init_rx_ring (dev);
+ purge_tx_ring (dev);
+
+ /* Tell the adapter where the RX ring is located.
+ */
+ if (!wait_for_eepro100 (dev)) {
+ printf ("Error: Can not reset ethernet controller.\n");
+ goto Done;
+ }
+
+ OUTL (dev, phys_to_bus ((u32) & rx_ring[rx_next]), SCBPointer);
+ OUTW (dev, SCB_M | RUC_START, SCBCmd);
+
+ /* Send the Configure frame */
+ tx_cur = tx_next;
+ tx_next = ((tx_next + 1) % NUM_TX_DESC);
+
+ cfg_cmd = (struct descriptor *) &tx_ring[tx_cur];
+ cfg_cmd->command = cpu_to_le16 ((CONFIG_SYS_CMD_SUSPEND | CONFIG_SYS_CMD_CONFIGURE));
+ cfg_cmd->status = 0;
+ cfg_cmd->link = cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
+
+ memcpy (cfg_cmd->params, i82558_config_cmd,
+ sizeof (i82558_config_cmd));
+
+ if (!wait_for_eepro100 (dev)) {
+ printf ("Error---CONFIG_SYS_CMD_CONFIGURE: Can not reset ethernet controller.\n");
+ goto Done;
+ }
+
+ OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
+ OUTW (dev, SCB_M | CU_START, SCBCmd);
+
+ for (i = 0;
+ !(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
+ i++) {
+ if (i >= TOUT_LOOP) {
+ printf ("%s: Tx error buffer not ready\n", dev->name);
+ goto Done;
+ }
+ }
+
+ if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
+ printf ("TX error status = 0x%08X\n",
+ le16_to_cpu (tx_ring[tx_cur].status));
+ goto Done;
+ }
+
+ /* Send the Individual Address Setup frame
+ */
+ tx_cur = tx_next;
+ tx_next = ((tx_next + 1) % NUM_TX_DESC);
+
+ ias_cmd = (struct descriptor *) &tx_ring[tx_cur];
+ ias_cmd->command = cpu_to_le16 ((CONFIG_SYS_CMD_SUSPEND | CONFIG_SYS_CMD_IAS));
+ ias_cmd->status = 0;
+ ias_cmd->link = cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
+
+ memcpy (ias_cmd->params, dev->enetaddr, 6);
+
+ /* Tell the adapter where the TX ring is located.
+ */
+ if (!wait_for_eepro100 (dev)) {
+ printf ("Error: Can not reset ethernet controller.\n");
+ goto Done;
+ }
+
+ OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
+ OUTW (dev, SCB_M | CU_START, SCBCmd);
+
+ for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
+ i++) {
+ if (i >= TOUT_LOOP) {
+ printf ("%s: Tx error buffer not ready\n",
+ dev->name);
+ goto Done;
+ }
+ }
+
+ if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
+ printf ("TX error status = 0x%08X\n",
+ le16_to_cpu (tx_ring[tx_cur].status));
+ goto Done;
+ }
+
+ status = 0;
+
+ Done:
+ return status;
+}
+
+static int eepro100_send(struct eth_device *dev, void *packet, int length)
+{
+ int i, status = -1;
+ int tx_cur;
+
+ if (length <= 0) {
+ printf ("%s: bad packet size: %d\n", dev->name, length);
+ goto Done;
+ }
+
+ tx_cur = tx_next;
+ tx_next = (tx_next + 1) % NUM_TX_DESC;
+
+ tx_ring[tx_cur].command = cpu_to_le16 ( TxCB_CMD_TRANSMIT |
+ TxCB_CMD_SF |
+ TxCB_CMD_S |
+ TxCB_CMD_EL );
+ tx_ring[tx_cur].status = 0;
+ tx_ring[tx_cur].count = cpu_to_le32 (tx_threshold);
+ tx_ring[tx_cur].link =
+ cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
+ tx_ring[tx_cur].tx_desc_addr =
+ cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_cur].tx_buf_addr0));
+ tx_ring[tx_cur].tx_buf_addr0 =
+ cpu_to_le32 (phys_to_bus ((u_long) packet));
+ tx_ring[tx_cur].tx_buf_size0 = cpu_to_le32 (length);
+
+ if (!wait_for_eepro100 (dev)) {
+ printf ("%s: Tx error ethernet controller not ready.\n",
+ dev->name);
+ goto Done;
+ }
+
+ /* Send the packet.
+ */
+ OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
+ OUTW (dev, SCB_M | CU_START, SCBCmd);
+
+ for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
+ i++) {
+ if (i >= TOUT_LOOP) {
+ printf ("%s: Tx error buffer not ready\n", dev->name);
+ goto Done;
+ }
+ }
+
+ if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
+ printf ("TX error status = 0x%08X\n",
+ le16_to_cpu (tx_ring[tx_cur].status));
+ goto Done;
+ }
+
+ status = length;
+
+ Done:
+ return status;
+}
+
+static int eepro100_recv (struct eth_device *dev)
+{
+ u16 status, stat;
+ int rx_prev, length = 0;
+
+ stat = INW (dev, SCBStatus);
+ OUTW (dev, stat & SCB_STATUS_RNR, SCBStatus);
+
+ for (;;) {
+ status = le16_to_cpu (rx_ring[rx_next].status);
+
+ if (!(status & RFD_STATUS_C)) {
+ break;
+ }
+
+ /* Valid frame status.
+ */
+ if ((status & RFD_STATUS_OK)) {
+ /* A valid frame received.
+ */
+ length = le32_to_cpu (rx_ring[rx_next].count) & 0x3fff;
+
+ /* Pass the packet up to the protocol
+ * layers.
+ */
+ NetReceive((u8 *)rx_ring[rx_next].data, length);
+ } else {
+ /* There was an error.
+ */
+ printf ("RX error status = 0x%08X\n", status);
+ }
+
+ rx_ring[rx_next].control = cpu_to_le16 (RFD_CONTROL_S);
+ rx_ring[rx_next].status = 0;
+ rx_ring[rx_next].count = cpu_to_le32 (PKTSIZE_ALIGN << 16);
+
+ rx_prev = (rx_next + NUM_RX_DESC - 1) % NUM_RX_DESC;
+ rx_ring[rx_prev].control = 0;
+
+ /* Update entry information.
+ */
+ rx_next = (rx_next + 1) % NUM_RX_DESC;
+ }
+
+ if (stat & SCB_STATUS_RNR) {
+
+ printf ("%s: Receiver is not ready, restart it !\n", dev->name);
+
+ /* Reinitialize Rx ring.
+ */
+ init_rx_ring (dev);
+
+ if (!wait_for_eepro100 (dev)) {
+ printf ("Error: Can not restart ethernet controller.\n");
+ goto Done;
+ }
+
+ OUTL (dev, phys_to_bus ((u32) & rx_ring[rx_next]), SCBPointer);
+ OUTW (dev, SCB_M | RUC_START, SCBCmd);
+ }
+
+ Done:
+ return length;
+}
+
+static void eepro100_halt (struct eth_device *dev)
+{
+ /* Reset the ethernet controller
+ */
+ OUTL (dev, I82559_SELECTIVE_RESET, SCBPort);
+ udelay (20);
+
+ OUTL (dev, I82559_RESET, SCBPort);
+ udelay (20);
+
+ if (!wait_for_eepro100 (dev)) {
+ printf ("Error: Can not reset ethernet controller.\n");
+ goto Done;
+ }
+ OUTL (dev, 0, SCBPointer);
+ OUTW (dev, SCB_M | RUC_ADDR_LOAD, SCBCmd);
+
+ if (!wait_for_eepro100 (dev)) {
+ printf ("Error: Can not reset ethernet controller.\n");
+ goto Done;
+ }
+ OUTL (dev, 0, SCBPointer);
+ OUTW (dev, SCB_M | CU_ADDR_LOAD, SCBCmd);
+
+ Done:
+ return;
+}
+
+ /* SROM Read.
+ */
+static int read_eeprom (struct eth_device *dev, int location, int addr_len)
+{
+ unsigned short retval = 0;
+ int read_cmd = location | EE_READ_CMD;
+ int i;
+
+ OUTW (dev, EE_ENB & ~EE_CS, SCBeeprom);
+ OUTW (dev, EE_ENB, SCBeeprom);
+
+ /* Shift the read command bits out. */
+ for (i = 12; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+
+ OUTW (dev, EE_ENB | dataval, SCBeeprom);
+ udelay (1);
+ OUTW (dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+ udelay (1);
+ }
+ OUTW (dev, EE_ENB, SCBeeprom);
+
+ for (i = 15; i >= 0; i--) {
+ OUTW (dev, EE_ENB | EE_SHIFT_CLK, SCBeeprom);
+ udelay (1);
+ retval = (retval << 1) |
+ ((INW (dev, SCBeeprom) & EE_DATA_READ) ? 1 : 0);
+ OUTW (dev, EE_ENB, SCBeeprom);
+ udelay (1);
+ }
+
+ /* Terminate the EEPROM access. */
+ OUTW (dev, EE_ENB & ~EE_CS, SCBeeprom);
+ return retval;
+}
+
+#ifdef CONFIG_EEPRO100_SROM_WRITE
+int eepro100_write_eeprom (struct eth_device* dev, int location, int addr_len, unsigned short data)
+{
+ unsigned short dataval;
+ int enable_cmd = 0x3f | EE_EWENB_CMD;
+ int write_cmd = location | EE_WRITE_CMD;
+ int i;
+ unsigned long datalong, tmplong;
+
+ OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
+ udelay(1);
+ OUTW(dev, EE_ENB, SCBeeprom);
+
+ /* Shift the enable command bits out. */
+ for (i = (addr_len+EE_CMD_BITS-1); i >= 0; i--)
+ {
+ dataval = (enable_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ OUTW(dev, EE_ENB | dataval, SCBeeprom);
+ udelay(1);
+ OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+ udelay(1);
+ }
+
+ OUTW(dev, EE_ENB, SCBeeprom);
+ udelay(1);
+ OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
+ udelay(1);
+ OUTW(dev, EE_ENB, SCBeeprom);
+
+
+ /* Shift the write command bits out. */
+ for (i = (addr_len+EE_CMD_BITS-1); i >= 0; i--)
+ {
+ dataval = (write_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ OUTW(dev, EE_ENB | dataval, SCBeeprom);
+ udelay(1);
+ OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+ udelay(1);
+ }
+
+ /* Write the data */
+ datalong= (unsigned long) ((((data) & 0x00ff) << 8) | ( (data) >> 8));
+
+ for (i = 0; i< EE_DATA_BITS; i++)
+ {
+ /* Extract and move data bit to bit DI */
+ dataval = ((datalong & 0x8000)>>13) ? EE_DATA_WRITE : 0;
+
+ OUTW(dev, EE_ENB | dataval, SCBeeprom);
+ udelay(1);
+ OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
+ udelay(1);
+ OUTW(dev, EE_ENB | dataval, SCBeeprom);
+ udelay(1);
+
+ datalong = datalong << 1; /* Adjust significant data bit*/
+ }
+
+ /* Finish up command (toggle CS) */
+ OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
+ udelay(1); /* delay for more than 250 ns */
+ OUTW(dev, EE_ENB, SCBeeprom);
+
+ /* Wait for programming ready (D0 = 1) */
+ tmplong = 10;
+ do
+ {
+ dataval = INW(dev, SCBeeprom);
+ if (dataval & EE_DATA_READ)
+ break;
+ udelay(10000);
+ }
+ while (-- tmplong);
+
+ if (tmplong == 0)
+ {
+ printf ("Write i82559 eeprom timed out (100 ms waiting for data ready.\n");
+ return -1;
+ }
+
+ /* Terminate the EEPROM access. */
+ OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
+
+ return 0;
+}
+#endif
+
+static void init_rx_ring (struct eth_device *dev)
+{
+ int i;
+
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ rx_ring[i].status = 0;
+ rx_ring[i].control =
+ (i == NUM_RX_DESC - 1) ? cpu_to_le16 (RFD_CONTROL_S) : 0;
+ rx_ring[i].link =
+ cpu_to_le32 (phys_to_bus
+ ((u32) & rx_ring[(i + 1) % NUM_RX_DESC]));
+ rx_ring[i].rx_buf_addr = 0xffffffff;
+ rx_ring[i].count = cpu_to_le32 (PKTSIZE_ALIGN << 16);
+ }
+
+ rx_next = 0;
+}
+
+static void purge_tx_ring (struct eth_device *dev)
+{
+ int i;
+
+ tx_next = 0;
+ tx_threshold = 0x01208000;
+
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ tx_ring[i].status = 0;
+ tx_ring[i].command = 0;
+ tx_ring[i].link = 0;
+ tx_ring[i].tx_desc_addr = 0;
+ tx_ring[i].count = 0;
+
+ tx_ring[i].tx_buf_addr0 = 0;
+ tx_ring[i].tx_buf_size0 = 0;
+ tx_ring[i].tx_buf_addr1 = 0;
+ tx_ring[i].tx_buf_size1 = 0;
+ }
+}
+
+static void read_hw_addr (struct eth_device *dev, bd_t * bis)
+{
+ u16 sum = 0;
+ int i, j;
+ int addr_len = read_eeprom (dev, 0, 6) == 0xffff ? 8 : 6;
+
+ for (j = 0, i = 0; i < 0x40; i++) {
+ u16 value = read_eeprom (dev, i, addr_len);
+
+ sum += value;
+ if (i < 3) {
+ dev->enetaddr[j++] = value;
+ dev->enetaddr[j++] = value >> 8;
+ }
+ }
+
+ if (sum != 0xBABA) {
+ memset (dev->enetaddr, 0, ETH_ALEN);
+#ifdef DEBUG
+ printf ("%s: Invalid EEPROM checksum %#4.4x, "
+ "check settings before activating this device!\n",
+ dev->name, sum);
+#endif
+ }
+}
diff --git a/qemu/roms/u-boot/drivers/net/enc28j60.c b/qemu/roms/u-boot/drivers/net/enc28j60.c
new file mode 100644
index 000000000..ec33764f5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/enc28j60.c
@@ -0,0 +1,963 @@
+/*
+ * (C) Copyright 2010
+ * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
+ * Martin Krause, Martin.Krause@tqs.de
+ * reworked original enc28j60.c
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <net.h>
+#include <spi.h>
+#include <malloc.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include "enc28j60.h"
+
+/*
+ * IMPORTANT: spi_claim_bus() and spi_release_bus()
+ * are called at begin and end of each of the following functions:
+ * enc_miiphy_read(), enc_miiphy_write(), enc_write_hwaddr(),
+ * enc_init(), enc_recv(), enc_send(), enc_halt()
+ * ALL other functions assume that the bus has already been claimed!
+ * Since NetReceive() might call enc_send() in return, the bus must be
+ * released, NetReceive() called and claimed again.
+ */
+
+/*
+ * Controller memory layout.
+ * We only allow 1 frame for transmission and reserve the rest
+ * for reception to handle as many broadcast packets as possible.
+ * Also use the memory from 0x0000 for receiver buffer. See errata pt. 5
+ * 0x0000 - 0x19ff 6656 bytes receive buffer
+ * 0x1a00 - 0x1fff 1536 bytes transmit buffer =
+ * control(1)+frame(1518)+status(7)+reserve(10).
+ */
+#define ENC_RX_BUF_START 0x0000
+#define ENC_RX_BUF_END 0x19ff
+#define ENC_TX_BUF_START 0x1a00
+#define ENC_TX_BUF_END 0x1fff
+#define ENC_MAX_FRM_LEN 1518
+#define RX_RESET_COUNTER 1000
+
+/*
+ * For non data transfer functions, like phy read/write, set hwaddr, init
+ * we do not need a full, time consuming init including link ready wait.
+ * This enum helps to bring the chip through the minimum necessary inits.
+ */
+enum enc_initstate {none=0, setupdone, linkready};
+typedef struct enc_device {
+ struct eth_device *dev; /* back pointer */
+ struct spi_slave *slave;
+ int rx_reset_counter;
+ u16 next_pointer;
+ u8 bank; /* current bank in enc28j60 */
+ enum enc_initstate initstate;
+} enc_dev_t;
+
+/*
+ * enc_bset: set bits in a common register
+ * enc_bclr: clear bits in a common register
+ *
+ * making the reg parameter u8 will give a compile time warning if the
+ * functions are called with a register not accessible in all Banks
+ */
+static void enc_bset(enc_dev_t *enc, const u8 reg, const u8 data)
+{
+ u8 dout[2];
+
+ dout[0] = CMD_BFS(reg);
+ dout[1] = data;
+ spi_xfer(enc->slave, 2 * 8, dout, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+static void enc_bclr(enc_dev_t *enc, const u8 reg, const u8 data)
+{
+ u8 dout[2];
+
+ dout[0] = CMD_BFC(reg);
+ dout[1] = data;
+ spi_xfer(enc->slave, 2 * 8, dout, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+/*
+ * high byte of the register contains bank number:
+ * 0: no bank switch necessary
+ * 1: switch to bank 0
+ * 2: switch to bank 1
+ * 3: switch to bank 2
+ * 4: switch to bank 3
+ */
+static void enc_set_bank(enc_dev_t *enc, const u16 reg)
+{
+ u8 newbank = reg >> 8;
+
+ if (newbank == 0 || newbank == enc->bank)
+ return;
+ switch (newbank) {
+ case 1:
+ enc_bclr(enc, CTL_REG_ECON1,
+ ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
+ break;
+ case 2:
+ enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0);
+ enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1);
+ break;
+ case 3:
+ enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0);
+ enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1);
+ break;
+ case 4:
+ enc_bset(enc, CTL_REG_ECON1,
+ ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
+ break;
+ }
+ enc->bank = newbank;
+}
+
+/*
+ * local functions to access SPI
+ *
+ * reg: register inside ENC28J60
+ * data: 8/16 bits to write
+ * c: number of retries
+ *
+ * enc_r8: read 8 bits
+ * enc_r16: read 16 bits
+ * enc_w8: write 8 bits
+ * enc_w16: write 16 bits
+ * enc_w8_retry: write 8 bits, verify and retry
+ * enc_rbuf: read from ENC28J60 into buffer
+ * enc_wbuf: write from buffer into ENC28J60
+ */
+
+/*
+ * MAC and MII registers need a 3 byte SPI transfer to read,
+ * all other registers need a 2 byte SPI transfer.
+ */
+static int enc_reg2nbytes(const u16 reg)
+{
+ /* check if MAC or MII register */
+ return ((reg >= CTL_REG_MACON1 && reg <= CTL_REG_MIRDH) ||
+ (reg >= CTL_REG_MAADR1 && reg <= CTL_REG_MAADR4) ||
+ (reg == CTL_REG_MISTAT)) ? 3 : 2;
+}
+
+/*
+ * Read a byte register
+ */
+static u8 enc_r8(enc_dev_t *enc, const u16 reg)
+{
+ u8 dout[3];
+ u8 din[3];
+ int nbytes = enc_reg2nbytes(reg);
+
+ enc_set_bank(enc, reg);
+ dout[0] = CMD_RCR(reg);
+ spi_xfer(enc->slave, nbytes * 8, dout, din,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+ return din[nbytes-1];
+}
+
+/*
+ * Read a L/H register pair and return a word.
+ * Must be called with the L register's address.
+ */
+static u16 enc_r16(enc_dev_t *enc, const u16 reg)
+{
+ u8 dout[3];
+ u8 din[3];
+ u16 result;
+ int nbytes = enc_reg2nbytes(reg);
+
+ enc_set_bank(enc, reg);
+ dout[0] = CMD_RCR(reg);
+ spi_xfer(enc->slave, nbytes * 8, dout, din,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+ result = din[nbytes-1];
+ dout[0]++; /* next register */
+ spi_xfer(enc->slave, nbytes * 8, dout, din,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+ result |= din[nbytes-1] << 8;
+ return result;
+}
+
+/*
+ * Write a byte register
+ */
+static void enc_w8(enc_dev_t *enc, const u16 reg, const u8 data)
+{
+ u8 dout[2];
+
+ enc_set_bank(enc, reg);
+ dout[0] = CMD_WCR(reg);
+ dout[1] = data;
+ spi_xfer(enc->slave, 2 * 8, dout, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+/*
+ * Write a L/H register pair.
+ * Must be called with the L register's address.
+ */
+static void enc_w16(enc_dev_t *enc, const u16 reg, const u16 data)
+{
+ u8 dout[2];
+
+ enc_set_bank(enc, reg);
+ dout[0] = CMD_WCR(reg);
+ dout[1] = data;
+ spi_xfer(enc->slave, 2 * 8, dout, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+ dout[0]++; /* next register */
+ dout[1] = data >> 8;
+ spi_xfer(enc->slave, 2 * 8, dout, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+/*
+ * Write a byte register, verify and retry
+ */
+static void enc_w8_retry(enc_dev_t *enc, const u16 reg, const u8 data, const int c)
+{
+ u8 dout[2];
+ u8 readback;
+ int i;
+
+ enc_set_bank(enc, reg);
+ for (i = 0; i < c; i++) {
+ dout[0] = CMD_WCR(reg);
+ dout[1] = data;
+ spi_xfer(enc->slave, 2 * 8, dout, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+ readback = enc_r8(enc, reg);
+ if (readback == data)
+ break;
+ /* wait 1ms */
+ udelay(1000);
+ }
+ if (i == c) {
+ printf("%s: write reg 0x%03x failed\n", enc->dev->name, reg);
+ }
+}
+
+/*
+ * Read ENC RAM into buffer
+ */
+static void enc_rbuf(enc_dev_t *enc, const u16 length, u8 *buf)
+{
+ u8 dout[1];
+
+ dout[0] = CMD_RBM;
+ spi_xfer(enc->slave, 8, dout, NULL, SPI_XFER_BEGIN);
+ spi_xfer(enc->slave, length * 8, NULL, buf, SPI_XFER_END);
+#ifdef DEBUG
+ puts("Rx:\n");
+ print_buffer(0, buf, 1, length, 0);
+#endif
+}
+
+/*
+ * Write buffer into ENC RAM
+ */
+static void enc_wbuf(enc_dev_t *enc, const u16 length, const u8 *buf, const u8 control)
+{
+ u8 dout[2];
+ dout[0] = CMD_WBM;
+ dout[1] = control;
+ spi_xfer(enc->slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN);
+ spi_xfer(enc->slave, length * 8, buf, NULL, SPI_XFER_END);
+#ifdef DEBUG
+ puts("Tx:\n");
+ print_buffer(0, buf, 1, length, 0);
+#endif
+}
+
+/*
+ * Try to claim the SPI bus.
+ * Print error message on failure.
+ */
+static int enc_claim_bus(enc_dev_t *enc)
+{
+ int rc = spi_claim_bus(enc->slave);
+ if (rc)
+ printf("%s: failed to claim SPI bus\n", enc->dev->name);
+ return rc;
+}
+
+/*
+ * Release previously claimed SPI bus.
+ * This function is mainly for symmetry to enc_claim_bus().
+ * Let the toolchain decide to inline it...
+ */
+static void enc_release_bus(enc_dev_t *enc)
+{
+ spi_release_bus(enc->slave);
+}
+
+/*
+ * Read PHY register
+ */
+static u16 enc_phy_read(enc_dev_t *enc, const u8 addr)
+{
+ uint64_t etime;
+ u8 status;
+
+ enc_w8(enc, CTL_REG_MIREGADR, addr);
+ enc_w8(enc, CTL_REG_MICMD, ENC_MICMD_MIIRD);
+ /* 1 second timeout - only happens on hardware problem */
+ etime = get_ticks() + get_tbclk();
+ /* poll MISTAT.BUSY bit until operation is complete */
+ do
+ {
+ status = enc_r8(enc, CTL_REG_MISTAT);
+ } while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY));
+ if (status & ENC_MISTAT_BUSY) {
+ printf("%s: timeout reading phy\n", enc->dev->name);
+ return 0;
+ }
+ enc_w8(enc, CTL_REG_MICMD, 0);
+ return enc_r16(enc, CTL_REG_MIRDL);
+}
+
+/*
+ * Write PHY register
+ */
+static void enc_phy_write(enc_dev_t *enc, const u8 addr, const u16 data)
+{
+ uint64_t etime;
+ u8 status;
+
+ enc_w8(enc, CTL_REG_MIREGADR, addr);
+ enc_w16(enc, CTL_REG_MIWRL, data);
+ /* 1 second timeout - only happens on hardware problem */
+ etime = get_ticks() + get_tbclk();
+ /* poll MISTAT.BUSY bit until operation is complete */
+ do
+ {
+ status = enc_r8(enc, CTL_REG_MISTAT);
+ } while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY));
+ if (status & ENC_MISTAT_BUSY) {
+ printf("%s: timeout writing phy\n", enc->dev->name);
+ return;
+ }
+}
+
+/*
+ * Verify link status, wait if necessary
+ *
+ * Note: with a 10 MBit/s only PHY there is no autonegotiation possible,
+ * half/full duplex is a pure setup matter. For the time being, this driver
+ * will setup in half duplex mode only.
+ */
+static int enc_phy_link_wait(enc_dev_t *enc)
+{
+ u16 status;
+ int duplex;
+ uint64_t etime;
+
+#ifdef CONFIG_ENC_SILENTLINK
+ /* check if we have a link, then just return */
+ status = enc_phy_read(enc, PHY_REG_PHSTAT1);
+ if (status & ENC_PHSTAT1_LLSTAT)
+ return 0;
+#endif
+
+ /* wait for link with 1 second timeout */
+ etime = get_ticks() + get_tbclk();
+ while (get_ticks() <= etime) {
+ status = enc_phy_read(enc, PHY_REG_PHSTAT1);
+ if (status & ENC_PHSTAT1_LLSTAT) {
+ /* now we have a link */
+ status = enc_phy_read(enc, PHY_REG_PHSTAT2);
+ duplex = (status & ENC_PHSTAT2_DPXSTAT) ? 1 : 0;
+ printf("%s: link up, 10Mbps %s-duplex\n",
+ enc->dev->name, duplex ? "full" : "half");
+ return 0;
+ }
+ udelay(1000);
+ }
+
+ /* timeout occured */
+ printf("%s: link down\n", enc->dev->name);
+ return 1;
+}
+
+/*
+ * This function resets the receiver only.
+ */
+static void enc_reset_rx(enc_dev_t *enc)
+{
+ u8 econ1;
+
+ econ1 = enc_r8(enc, CTL_REG_ECON1);
+ if ((econ1 & ENC_ECON1_RXRST) == 0) {
+ enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXRST);
+ enc->rx_reset_counter = RX_RESET_COUNTER;
+ }
+}
+
+/*
+ * Reset receiver and reenable it.
+ */
+static void enc_reset_rx_call(enc_dev_t *enc)
+{
+ enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXRST);
+ enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
+}
+
+/*
+ * Copy a packet from the receive ring and forward it to
+ * the protocol stack.
+ */
+static void enc_receive(enc_dev_t *enc)
+{
+ u8 *packet = (u8 *)NetRxPackets[0];
+ u16 pkt_len;
+ u16 copy_len;
+ u16 status;
+ u8 pkt_cnt = 0;
+ u16 rxbuf_rdpt;
+ u8 hbuf[6];
+
+ enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer);
+ do {
+ enc_rbuf(enc, 6, hbuf);
+ enc->next_pointer = hbuf[0] | (hbuf[1] << 8);
+ pkt_len = hbuf[2] | (hbuf[3] << 8);
+ status = hbuf[4] | (hbuf[5] << 8);
+ debug("next_pointer=$%04x pkt_len=%u status=$%04x\n",
+ enc->next_pointer, pkt_len, status);
+ if (pkt_len <= ENC_MAX_FRM_LEN)
+ copy_len = pkt_len;
+ else
+ copy_len = 0;
+ if ((status & (1L << 7)) == 0) /* check Received Ok bit */
+ copy_len = 0;
+ /* check if next pointer is resonable */
+ if (enc->next_pointer >= ENC_TX_BUF_START)
+ copy_len = 0;
+ if (copy_len > 0) {
+ enc_rbuf(enc, copy_len, packet);
+ }
+ /* advance read pointer to next pointer */
+ enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer);
+ /* decrease packet counter */
+ enc_bset(enc, CTL_REG_ECON2, ENC_ECON2_PKTDEC);
+ /*
+ * Only odd values should be written to ERXRDPTL,
+ * see errata B4 pt.13
+ */
+ rxbuf_rdpt = enc->next_pointer - 1;
+ if ((rxbuf_rdpt < enc_r16(enc, CTL_REG_ERXSTL)) ||
+ (rxbuf_rdpt > enc_r16(enc, CTL_REG_ERXNDL))) {
+ enc_w16(enc, CTL_REG_ERXRDPTL,
+ enc_r16(enc, CTL_REG_ERXNDL));
+ } else {
+ enc_w16(enc, CTL_REG_ERXRDPTL, rxbuf_rdpt);
+ }
+ /* read pktcnt */
+ pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT);
+ if (copy_len == 0) {
+ (void)enc_r8(enc, CTL_REG_EIR);
+ enc_reset_rx(enc);
+ printf("%s: receive copy_len=0\n", enc->dev->name);
+ continue;
+ }
+ /*
+ * Because NetReceive() might call enc_send(), we need to
+ * release the SPI bus, call NetReceive(), reclaim the bus
+ */
+ enc_release_bus(enc);
+ NetReceive(packet, pkt_len);
+ if (enc_claim_bus(enc))
+ return;
+ (void)enc_r8(enc, CTL_REG_EIR);
+ } while (pkt_cnt);
+ /* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */
+}
+
+/*
+ * Poll for completely received packets.
+ */
+static void enc_poll(enc_dev_t *enc)
+{
+ u8 eir_reg;
+ u8 pkt_cnt;
+
+#ifdef CONFIG_USE_IRQ
+ /* clear global interrupt enable bit in enc28j60 */
+ enc_bclr(enc, CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+ (void)enc_r8(enc, CTL_REG_ESTAT);
+ eir_reg = enc_r8(enc, CTL_REG_EIR);
+ if (eir_reg & ENC_EIR_TXIF) {
+ /* clear TXIF bit in EIR */
+ enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXIF);
+ }
+ /* We have to use pktcnt and not pktif bit, see errata pt. 6 */
+ pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT);
+ if (pkt_cnt > 0) {
+ if ((eir_reg & ENC_EIR_PKTIF) == 0) {
+ debug("enc_poll: pkt cnt > 0, but pktif not set\n");
+ }
+ enc_receive(enc);
+ /*
+ * clear PKTIF bit in EIR, this should not need to be done
+ * but it seems like we get problems if we do not
+ */
+ enc_bclr(enc, CTL_REG_EIR, ENC_EIR_PKTIF);
+ }
+ if (eir_reg & ENC_EIR_RXERIF) {
+ printf("%s: rx error\n", enc->dev->name);
+ enc_bclr(enc, CTL_REG_EIR, ENC_EIR_RXERIF);
+ }
+ if (eir_reg & ENC_EIR_TXERIF) {
+ printf("%s: tx error\n", enc->dev->name);
+ enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXERIF);
+ }
+#ifdef CONFIG_USE_IRQ
+ /* set global interrupt enable bit in enc28j60 */
+ enc_bset(enc, CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+}
+
+/*
+ * Completely Reset the ENC
+ */
+static void enc_reset(enc_dev_t *enc)
+{
+ u8 dout[1];
+
+ dout[0] = CMD_SRC;
+ spi_xfer(enc->slave, 8, dout, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+ /* sleep 1 ms. See errata pt. 2 */
+ udelay(1000);
+}
+
+/*
+ * Initialisation data for most of the ENC registers
+ */
+static const u16 enc_initdata[] = {
+ /*
+ * Setup the buffer space. The reset values are valid for the
+ * other pointers.
+ *
+ * We shall not write to ERXST, see errata pt. 5. Instead we
+ * have to make sure that ENC_RX_BUS_START is 0.
+ */
+ CTL_REG_ERXSTL, ENC_RX_BUF_START,
+ CTL_REG_ERXSTH, ENC_RX_BUF_START >> 8,
+ CTL_REG_ERXNDL, ENC_RX_BUF_END,
+ CTL_REG_ERXNDH, ENC_RX_BUF_END >> 8,
+ CTL_REG_ERDPTL, ENC_RX_BUF_START,
+ CTL_REG_ERDPTH, ENC_RX_BUF_START >> 8,
+ /*
+ * Set the filter to receive only good-CRC, unicast and broadcast
+ * frames.
+ * Note: some DHCP servers return their answers as broadcasts!
+ * So its unwise to remove broadcast from this. This driver
+ * might incur receiver overruns with packet loss on a broadcast
+ * flooded network.
+ */
+ CTL_REG_ERXFCON, ENC_RFR_BCEN | ENC_RFR_UCEN | ENC_RFR_CRCEN,
+
+ /* enable MAC to receive frames */
+ CTL_REG_MACON1,
+ ENC_MACON1_MARXEN | ENC_MACON1_TXPAUS | ENC_MACON1_RXPAUS,
+
+ /* configure pad, tx-crc and duplex */
+ CTL_REG_MACON3,
+ ENC_MACON3_PADCFG0 | ENC_MACON3_TXCRCEN |
+ ENC_MACON3_FRMLNEN,
+
+ /* Allow infinite deferals if the medium is continously busy */
+ CTL_REG_MACON4, ENC_MACON4_DEFER,
+
+ /* Late collisions occur beyond 63 bytes */
+ CTL_REG_MACLCON2, 63,
+
+ /*
+ * Set (low byte) Non-Back-to_Back Inter-Packet Gap.
+ * Recommended 0x12
+ */
+ CTL_REG_MAIPGL, 0x12,
+
+ /*
+ * Set (high byte) Non-Back-to_Back Inter-Packet Gap.
+ * Recommended 0x0c for half-duplex. Nothing for full-duplex
+ */
+ CTL_REG_MAIPGH, 0x0C,
+
+ /* set maximum frame length */
+ CTL_REG_MAMXFLL, ENC_MAX_FRM_LEN,
+ CTL_REG_MAMXFLH, ENC_MAX_FRM_LEN >> 8,
+
+ /*
+ * Set MAC back-to-back inter-packet gap.
+ * Recommended 0x12 for half duplex
+ * and 0x15 for full duplex.
+ */
+ CTL_REG_MABBIPG, 0x12,
+
+ /* end of table */
+ 0xffff
+};
+
+/*
+ * Wait for the XTAL oscillator to become ready
+ */
+static int enc_clock_wait(enc_dev_t *enc)
+{
+ uint64_t etime;
+
+ /* one second timeout */
+ etime = get_ticks() + get_tbclk();
+
+ /*
+ * Wait for CLKRDY to become set (i.e., check that we can
+ * communicate with the ENC)
+ */
+ do
+ {
+ if (enc_r8(enc, CTL_REG_ESTAT) & ENC_ESTAT_CLKRDY)
+ return 0;
+ } while (get_ticks() <= etime);
+
+ printf("%s: timeout waiting for CLKRDY\n", enc->dev->name);
+ return -1;
+}
+
+/*
+ * Write the MAC address into the ENC
+ */
+static int enc_write_macaddr(enc_dev_t *enc)
+{
+ unsigned char *p = enc->dev->enetaddr;
+
+ enc_w8_retry(enc, CTL_REG_MAADR5, *p++, 5);
+ enc_w8_retry(enc, CTL_REG_MAADR4, *p++, 5);
+ enc_w8_retry(enc, CTL_REG_MAADR3, *p++, 5);
+ enc_w8_retry(enc, CTL_REG_MAADR2, *p++, 5);
+ enc_w8_retry(enc, CTL_REG_MAADR1, *p++, 5);
+ enc_w8_retry(enc, CTL_REG_MAADR0, *p, 5);
+ return 0;
+}
+
+/*
+ * Setup most of the ENC registers
+ */
+static int enc_setup(enc_dev_t *enc)
+{
+ u16 phid1 = 0;
+ u16 phid2 = 0;
+ const u16 *tp;
+
+ /* reset enc struct values */
+ enc->next_pointer = ENC_RX_BUF_START;
+ enc->rx_reset_counter = RX_RESET_COUNTER;
+ enc->bank = 0xff; /* invalidate current bank in enc28j60 */
+
+ /* verify PHY identification */
+ phid1 = enc_phy_read(enc, PHY_REG_PHID1);
+ phid2 = enc_phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK;
+ if (phid1 != ENC_PHID1_VALUE || phid2 != ENC_PHID2_VALUE) {
+ printf("%s: failed to identify PHY. Found %04x:%04x\n",
+ enc->dev->name, phid1, phid2);
+ return -1;
+ }
+
+ /* now program registers */
+ for (tp = enc_initdata; *tp != 0xffff; tp += 2)
+ enc_w8_retry(enc, tp[0], tp[1], 10);
+
+ /*
+ * Prevent automatic loopback of data beeing transmitted by setting
+ * ENC_PHCON2_HDLDIS
+ */
+ enc_phy_write(enc, PHY_REG_PHCON2, (1<<8));
+
+ /*
+ * LEDs configuration
+ * LEDA: LACFG = 0100 -> display link status
+ * LEDB: LBCFG = 0111 -> display TX & RX activity
+ * STRCH = 1 -> LED pulses
+ */
+ enc_phy_write(enc, PHY_REG_PHLCON, 0x0472);
+
+ /* Reset PDPXMD-bit => half duplex */
+ enc_phy_write(enc, PHY_REG_PHCON1, 0);
+
+#ifdef CONFIG_USE_IRQ
+ /* enable interrupts */
+ enc_bset(enc, CTL_REG_EIE, ENC_EIE_PKTIE);
+ enc_bset(enc, CTL_REG_EIE, ENC_EIE_TXIE);
+ enc_bset(enc, CTL_REG_EIE, ENC_EIE_RXERIE);
+ enc_bset(enc, CTL_REG_EIE, ENC_EIE_TXERIE);
+ enc_bset(enc, CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+
+ return 0;
+}
+
+/*
+ * Check if ENC has been initialized.
+ * If not, try to initialize it.
+ * Remember initialized state in struct.
+ */
+static int enc_initcheck(enc_dev_t *enc, const enum enc_initstate requiredstate)
+{
+ if (enc->initstate >= requiredstate)
+ return 0;
+
+ if (enc->initstate < setupdone) {
+ /* Initialize the ENC only */
+ enc_reset(enc);
+ /* if any of functions fails, skip the rest and return an error */
+ if (enc_clock_wait(enc) || enc_setup(enc) || enc_write_macaddr(enc)) {
+ return -1;
+ }
+ enc->initstate = setupdone;
+ }
+ /* if that's all we need, return here */
+ if (enc->initstate >= requiredstate)
+ return 0;
+
+ /* now wait for link ready condition */
+ if (enc_phy_link_wait(enc)) {
+ return -1;
+ }
+ enc->initstate = linkready;
+ return 0;
+}
+
+#if defined(CONFIG_CMD_MII)
+/*
+ * Read a PHY register.
+ *
+ * This function is registered with miiphy_register().
+ */
+int enc_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ enc_dev_t *enc;
+
+ if (!dev || phy_adr != 0)
+ return -1;
+
+ enc = dev->priv;
+ if (enc_claim_bus(enc))
+ return -1;
+ if (enc_initcheck(enc, setupdone)) {
+ enc_release_bus(enc);
+ return -1;
+ }
+ *value = enc_phy_read(enc, reg);
+ enc_release_bus(enc);
+ return 0;
+}
+
+/*
+ * Write a PHY register.
+ *
+ * This function is registered with miiphy_register().
+ */
+int enc_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ enc_dev_t *enc;
+
+ if (!dev || phy_adr != 0)
+ return -1;
+
+ enc = dev->priv;
+ if (enc_claim_bus(enc))
+ return -1;
+ if (enc_initcheck(enc, setupdone)) {
+ enc_release_bus(enc);
+ return -1;
+ }
+ enc_phy_write(enc, reg, value);
+ enc_release_bus(enc);
+ return 0;
+}
+#endif
+
+/*
+ * Write hardware (MAC) address.
+ *
+ * This function entered into eth_device structure.
+ */
+static int enc_write_hwaddr(struct eth_device *dev)
+{
+ enc_dev_t *enc = dev->priv;
+
+ if (enc_claim_bus(enc))
+ return -1;
+ if (enc_initcheck(enc, setupdone)) {
+ enc_release_bus(enc);
+ return -1;
+ }
+ enc_release_bus(enc);
+ return 0;
+}
+
+/*
+ * Initialize ENC28J60 for use.
+ *
+ * This function entered into eth_device structure.
+ */
+static int enc_init(struct eth_device *dev, bd_t *bis)
+{
+ enc_dev_t *enc = dev->priv;
+
+ if (enc_claim_bus(enc))
+ return -1;
+ if (enc_initcheck(enc, linkready)) {
+ enc_release_bus(enc);
+ return -1;
+ }
+ /* enable receive */
+ enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
+ enc_release_bus(enc);
+ return 0;
+}
+
+/*
+ * Check for received packets.
+ *
+ * This function entered into eth_device structure.
+ */
+static int enc_recv(struct eth_device *dev)
+{
+ enc_dev_t *enc = dev->priv;
+
+ if (enc_claim_bus(enc))
+ return -1;
+ if (enc_initcheck(enc, linkready)) {
+ enc_release_bus(enc);
+ return -1;
+ }
+ /* Check for dead receiver */
+ if (enc->rx_reset_counter > 0)
+ enc->rx_reset_counter--;
+ else
+ enc_reset_rx_call(enc);
+ enc_poll(enc);
+ enc_release_bus(enc);
+ return 0;
+}
+
+/*
+ * Send a packet.
+ *
+ * This function entered into eth_device structure.
+ *
+ * Should we wait here until we have a Link? Or shall we leave that to
+ * protocol retries?
+ */
+static int enc_send(
+ struct eth_device *dev,
+ void *packet,
+ int length)
+{
+ enc_dev_t *enc = dev->priv;
+
+ if (enc_claim_bus(enc))
+ return -1;
+ if (enc_initcheck(enc, linkready)) {
+ enc_release_bus(enc);
+ return -1;
+ }
+ /* setup transmit pointers */
+ enc_w16(enc, CTL_REG_EWRPTL, ENC_TX_BUF_START);
+ enc_w16(enc, CTL_REG_ETXNDL, length + ENC_TX_BUF_START);
+ enc_w16(enc, CTL_REG_ETXSTL, ENC_TX_BUF_START);
+ /* write packet to ENC */
+ enc_wbuf(enc, length, (u8 *) packet, 0x00);
+ /*
+ * Check that the internal transmit logic has not been altered
+ * by excessive collisions. Reset transmitter if so.
+ * See Errata B4 12 and 14.
+ */
+ if (enc_r8(enc, CTL_REG_EIR) & ENC_EIR_TXERIF) {
+ enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRST);
+ enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_TXRST);
+ }
+ enc_bclr(enc, CTL_REG_EIR, (ENC_EIR_TXERIF | ENC_EIR_TXIF));
+ /* start transmitting */
+ enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRTS);
+ enc_release_bus(enc);
+ return 0;
+}
+
+/*
+ * Finish use of ENC.
+ *
+ * This function entered into eth_device structure.
+ */
+static void enc_halt(struct eth_device *dev)
+{
+ enc_dev_t *enc = dev->priv;
+
+ if (enc_claim_bus(enc))
+ return;
+ /* Just disable receiver */
+ enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
+ enc_release_bus(enc);
+}
+
+/*
+ * This is the only exported function.
+ *
+ * It may be called several times with different bus:cs combinations.
+ */
+int enc28j60_initialize(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct eth_device *dev;
+ enc_dev_t *enc;
+
+ /* try to allocate, check and clear eth_device object */
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ return -1;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ /* try to allocate, check and clear enc_dev_t object */
+ enc = malloc(sizeof(*enc));
+ if (!enc) {
+ free(dev);
+ return -1;
+ }
+ memset(enc, 0, sizeof(*enc));
+
+ /* try to setup the SPI slave */
+ enc->slave = spi_setup_slave(bus, cs, max_hz, mode);
+ if (!enc->slave) {
+ printf("enc28j60: invalid SPI device %i:%i\n", bus, cs);
+ free(enc);
+ free(dev);
+ return -1;
+ }
+
+ enc->dev = dev;
+ /* now fill the eth_device object */
+ dev->priv = enc;
+ dev->init = enc_init;
+ dev->halt = enc_halt;
+ dev->send = enc_send;
+ dev->recv = enc_recv;
+ dev->write_hwaddr = enc_write_hwaddr;
+ sprintf(dev->name, "enc%i.%i", bus, cs);
+ eth_register(dev);
+#if defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, enc_miiphy_read, enc_miiphy_write);
+#endif
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/enc28j60.h b/qemu/roms/u-boot/drivers/net/enc28j60.h
new file mode 100644
index 000000000..289e41288
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/enc28j60.h
@@ -0,0 +1,238 @@
+/*
+ * (X) extracted from enc28j60.c
+ * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _enc28j60_h
+#define _enc28j60_h
+
+/*
+ * SPI Commands
+ *
+ * Bits 7-5: Command
+ * Bits 4-0: Register
+ */
+#define CMD_RCR(x) (0x00+((x)&0x1f)) /* Read Control Register */
+#define CMD_RBM 0x3a /* Read Buffer Memory */
+#define CMD_WCR(x) (0x40+((x)&0x1f)) /* Write Control Register */
+#define CMD_WBM 0x7a /* Write Buffer Memory */
+#define CMD_BFS(x) (0x80+((x)&0x1f)) /* Bit Field Set */
+#define CMD_BFC(x) (0xa0+((x)&0x1f)) /* Bit Field Clear */
+#define CMD_SRC 0xff /* System Reset Command */
+
+/* NEW: encode (bank number+1) in upper byte */
+
+/* Common Control Registers accessible in all Banks */
+#define CTL_REG_EIE 0x01B
+#define CTL_REG_EIR 0x01C
+#define CTL_REG_ESTAT 0x01D
+#define CTL_REG_ECON2 0x01E
+#define CTL_REG_ECON1 0x01F
+
+/* Control Registers accessible in Bank 0 */
+#define CTL_REG_ERDPTL 0x100
+#define CTL_REG_ERDPTH 0x101
+#define CTL_REG_EWRPTL 0x102
+#define CTL_REG_EWRPTH 0x103
+#define CTL_REG_ETXSTL 0x104
+#define CTL_REG_ETXSTH 0x105
+#define CTL_REG_ETXNDL 0x106
+#define CTL_REG_ETXNDH 0x107
+#define CTL_REG_ERXSTL 0x108
+#define CTL_REG_ERXSTH 0x109
+#define CTL_REG_ERXNDL 0x10A
+#define CTL_REG_ERXNDH 0x10B
+#define CTL_REG_ERXRDPTL 0x10C
+#define CTL_REG_ERXRDPTH 0x10D
+#define CTL_REG_ERXWRPTL 0x10E
+#define CTL_REG_ERXWRPTH 0x10F
+#define CTL_REG_EDMASTL 0x110
+#define CTL_REG_EDMASTH 0x111
+#define CTL_REG_EDMANDL 0x112
+#define CTL_REG_EDMANDH 0x113
+#define CTL_REG_EDMADSTL 0x114
+#define CTL_REG_EDMADSTH 0x115
+#define CTL_REG_EDMACSL 0x116
+#define CTL_REG_EDMACSH 0x117
+
+/* Control Registers accessible in Bank 1 */
+#define CTL_REG_EHT0 0x200
+#define CTL_REG_EHT1 0x201
+#define CTL_REG_EHT2 0x202
+#define CTL_REG_EHT3 0x203
+#define CTL_REG_EHT4 0x204
+#define CTL_REG_EHT5 0x205
+#define CTL_REG_EHT6 0x206
+#define CTL_REG_EHT7 0x207
+#define CTL_REG_EPMM0 0x208
+#define CTL_REG_EPMM1 0x209
+#define CTL_REG_EPMM2 0x20A
+#define CTL_REG_EPMM3 0x20B
+#define CTL_REG_EPMM4 0x20C
+#define CTL_REG_EPMM5 0x20D
+#define CTL_REG_EPMM6 0x20E
+#define CTL_REG_EPMM7 0x20F
+#define CTL_REG_EPMCSL 0x210
+#define CTL_REG_EPMCSH 0x211
+#define CTL_REG_EPMOL 0x214
+#define CTL_REG_EPMOH 0x215
+#define CTL_REG_EWOLIE 0x216
+#define CTL_REG_EWOLIR 0x217
+#define CTL_REG_ERXFCON 0x218
+#define CTL_REG_EPKTCNT 0x219
+
+/* Control Registers accessible in Bank 2 */
+#define CTL_REG_MACON1 0x300
+#define CTL_REG_MACON2 0x301
+#define CTL_REG_MACON3 0x302
+#define CTL_REG_MACON4 0x303
+#define CTL_REG_MABBIPG 0x304
+#define CTL_REG_MAIPGL 0x306
+#define CTL_REG_MAIPGH 0x307
+#define CTL_REG_MACLCON1 0x308
+#define CTL_REG_MACLCON2 0x309
+#define CTL_REG_MAMXFLL 0x30A
+#define CTL_REG_MAMXFLH 0x30B
+#define CTL_REG_MAPHSUP 0x30D
+#define CTL_REG_MICON 0x311
+#define CTL_REG_MICMD 0x312
+#define CTL_REG_MIREGADR 0x314
+#define CTL_REG_MIWRL 0x316
+#define CTL_REG_MIWRH 0x317
+#define CTL_REG_MIRDL 0x318
+#define CTL_REG_MIRDH 0x319
+
+/* Control Registers accessible in Bank 3 */
+#define CTL_REG_MAADR1 0x400
+#define CTL_REG_MAADR0 0x401
+#define CTL_REG_MAADR3 0x402
+#define CTL_REG_MAADR2 0x403
+#define CTL_REG_MAADR5 0x404
+#define CTL_REG_MAADR4 0x405
+#define CTL_REG_EBSTSD 0x406
+#define CTL_REG_EBSTCON 0x407
+#define CTL_REG_EBSTCSL 0x408
+#define CTL_REG_EBSTCSH 0x409
+#define CTL_REG_MISTAT 0x40A
+#define CTL_REG_EREVID 0x412
+#define CTL_REG_ECOCON 0x415
+#define CTL_REG_EFLOCON 0x417
+#define CTL_REG_EPAUSL 0x418
+#define CTL_REG_EPAUSH 0x419
+
+/* PHY Register */
+#define PHY_REG_PHCON1 0x00
+#define PHY_REG_PHSTAT1 0x01
+#define PHY_REG_PHID1 0x02
+#define PHY_REG_PHID2 0x03
+#define PHY_REG_PHCON2 0x10
+#define PHY_REG_PHSTAT2 0x11
+#define PHY_REG_PHLCON 0x14
+
+/* Receive Filter Register (ERXFCON) bits */
+#define ENC_RFR_UCEN 0x80
+#define ENC_RFR_ANDOR 0x40
+#define ENC_RFR_CRCEN 0x20
+#define ENC_RFR_PMEN 0x10
+#define ENC_RFR_MPEN 0x08
+#define ENC_RFR_HTEN 0x04
+#define ENC_RFR_MCEN 0x02
+#define ENC_RFR_BCEN 0x01
+
+/* ECON1 Register Bits */
+#define ENC_ECON1_TXRST 0x80
+#define ENC_ECON1_RXRST 0x40
+#define ENC_ECON1_DMAST 0x20
+#define ENC_ECON1_CSUMEN 0x10
+#define ENC_ECON1_TXRTS 0x08
+#define ENC_ECON1_RXEN 0x04
+#define ENC_ECON1_BSEL1 0x02
+#define ENC_ECON1_BSEL0 0x01
+
+/* ECON2 Register Bits */
+#define ENC_ECON2_AUTOINC 0x80
+#define ENC_ECON2_PKTDEC 0x40
+#define ENC_ECON2_PWRSV 0x20
+#define ENC_ECON2_VRPS 0x08
+
+/* EIR Register Bits */
+#define ENC_EIR_PKTIF 0x40
+#define ENC_EIR_DMAIF 0x20
+#define ENC_EIR_LINKIF 0x10
+#define ENC_EIR_TXIF 0x08
+#define ENC_EIR_WOLIF 0x04
+#define ENC_EIR_TXERIF 0x02
+#define ENC_EIR_RXERIF 0x01
+
+/* ESTAT Register Bits */
+#define ENC_ESTAT_INT 0x80
+#define ENC_ESTAT_LATECOL 0x10
+#define ENC_ESTAT_RXBUSY 0x04
+#define ENC_ESTAT_TXABRT 0x02
+#define ENC_ESTAT_CLKRDY 0x01
+
+/* EIE Register Bits */
+#define ENC_EIE_INTIE 0x80
+#define ENC_EIE_PKTIE 0x40
+#define ENC_EIE_DMAIE 0x20
+#define ENC_EIE_LINKIE 0x10
+#define ENC_EIE_TXIE 0x08
+#define ENC_EIE_WOLIE 0x04
+#define ENC_EIE_TXERIE 0x02
+#define ENC_EIE_RXERIE 0x01
+
+/* MACON1 Register Bits */
+#define ENC_MACON1_LOOPBK 0x10
+#define ENC_MACON1_TXPAUS 0x08
+#define ENC_MACON1_RXPAUS 0x04
+#define ENC_MACON1_PASSALL 0x02
+#define ENC_MACON1_MARXEN 0x01
+
+/* MACON2 Register Bits */
+#define ENC_MACON2_MARST 0x80
+#define ENC_MACON2_RNDRST 0x40
+#define ENC_MACON2_MARXRST 0x08
+#define ENC_MACON2_RFUNRST 0x04
+#define ENC_MACON2_MATXRST 0x02
+#define ENC_MACON2_TFUNRST 0x01
+
+/* MACON3 Register Bits */
+#define ENC_MACON3_PADCFG2 0x80
+#define ENC_MACON3_PADCFG1 0x40
+#define ENC_MACON3_PADCFG0 0x20
+#define ENC_MACON3_TXCRCEN 0x10
+#define ENC_MACON3_PHDRLEN 0x08
+#define ENC_MACON3_HFRMEN 0x04
+#define ENC_MACON3_FRMLNEN 0x02
+#define ENC_MACON3_FULDPX 0x01
+
+/* MACON4 Register Bits */
+#define ENC_MACON4_DEFER 0x40
+
+/* MICMD Register Bits */
+#define ENC_MICMD_MIISCAN 0x02
+#define ENC_MICMD_MIIRD 0x01
+
+/* MISTAT Register Bits */
+#define ENC_MISTAT_NVALID 0x04
+#define ENC_MISTAT_SCAN 0x02
+#define ENC_MISTAT_BUSY 0x01
+
+/* PHID1 and PHID2 values */
+#define ENC_PHID1_VALUE 0x0083
+#define ENC_PHID2_VALUE 0x1400
+#define ENC_PHID2_MASK 0xFC00
+
+/* PHCON1 values */
+#define ENC_PHCON1_PDPXMD 0x0100
+
+/* PHSTAT1 values */
+#define ENC_PHSTAT1_LLSTAT 0x0004
+
+/* PHSTAT2 values */
+#define ENC_PHSTAT2_LSTAT 0x0400
+#define ENC_PHSTAT2_DPXSTAT 0x0200
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/ep93xx_eth.c b/qemu/roms/u-boot/drivers/net/ep93xx_eth.c
new file mode 100644
index 000000000..1c09f1004
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ep93xx_eth.c
@@ -0,0 +1,639 @@
+/*
+ * Cirrus Logic EP93xx ethernet MAC / MII driver.
+ *
+ * Copyright (C) 2010, 2009
+ * Matthias Kaehlcke <matthias@kaehlcke.net>
+ *
+ * Copyright (C) 2004, 2005
+ * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
+ *
+ * Based on the original eth.[ch] Cirrus Logic EP93xx Rev D. Ethernet Driver,
+ * which is
+ *
+ * (C) Copyright 2002 2003
+ * Adam Bezanson, Network Audio Technologies, Inc.
+ * <bezanson@netaudiotech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <command.h>
+#include <common.h>
+#include <asm/arch/ep93xx.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <linux/types.h>
+#include "ep93xx_eth.h"
+
+#define GET_PRIV(eth_dev) ((struct ep93xx_priv *)(eth_dev)->priv)
+#define GET_REGS(eth_dev) (GET_PRIV(eth_dev)->regs)
+
+/* ep93xx_miiphy ops forward declarations */
+static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
+ unsigned char const reg, unsigned short * const value);
+static int ep93xx_miiphy_write(const char * const dev, unsigned char const addr,
+ unsigned char const reg, unsigned short const value);
+
+#if defined(EP93XX_MAC_DEBUG)
+/**
+ * Dump ep93xx_mac values to the terminal.
+ */
+static void dump_dev(struct eth_device *dev)
+{
+ struct ep93xx_priv *priv = GET_PRIV(dev);
+ int i;
+
+ printf("\ndump_dev()\n");
+ printf(" rx_dq.base %p\n", priv->rx_dq.base);
+ printf(" rx_dq.current %p\n", priv->rx_dq.current);
+ printf(" rx_dq.end %p\n", priv->rx_dq.end);
+ printf(" rx_sq.base %p\n", priv->rx_sq.base);
+ printf(" rx_sq.current %p\n", priv->rx_sq.current);
+ printf(" rx_sq.end %p\n", priv->rx_sq.end);
+
+ for (i = 0; i < NUMRXDESC; i++)
+ printf(" rx_buffer[%2.d] %p\n", i, NetRxPackets[i]);
+
+ printf(" tx_dq.base %p\n", priv->tx_dq.base);
+ printf(" tx_dq.current %p\n", priv->tx_dq.current);
+ printf(" tx_dq.end %p\n", priv->tx_dq.end);
+ printf(" tx_sq.base %p\n", priv->tx_sq.base);
+ printf(" tx_sq.current %p\n", priv->tx_sq.current);
+ printf(" tx_sq.end %p\n", priv->tx_sq.end);
+}
+
+/**
+ * Dump all RX status queue entries to the terminal.
+ */
+static void dump_rx_status_queue(struct eth_device *dev)
+{
+ struct ep93xx_priv *priv = GET_PRIV(dev);
+ int i;
+
+ printf("\ndump_rx_status_queue()\n");
+ printf(" descriptor address word1 word2\n");
+ for (i = 0; i < NUMRXDESC; i++) {
+ printf(" [ %p ] %08X %08X\n",
+ priv->rx_sq.base + i,
+ (priv->rx_sq.base + i)->word1,
+ (priv->rx_sq.base + i)->word2);
+ }
+}
+
+/**
+ * Dump all RX descriptor queue entries to the terminal.
+ */
+static void dump_rx_descriptor_queue(struct eth_device *dev)
+{
+ struct ep93xx_priv *priv = GET_PRIV(dev);
+ int i;
+
+ printf("\ndump_rx_descriptor_queue()\n");
+ printf(" descriptor address word1 word2\n");
+ for (i = 0; i < NUMRXDESC; i++) {
+ printf(" [ %p ] %08X %08X\n",
+ priv->rx_dq.base + i,
+ (priv->rx_dq.base + i)->word1,
+ (priv->rx_dq.base + i)->word2);
+ }
+}
+
+/**
+ * Dump all TX descriptor queue entries to the terminal.
+ */
+static void dump_tx_descriptor_queue(struct eth_device *dev)
+{
+ struct ep93xx_priv *priv = GET_PRIV(dev);
+ int i;
+
+ printf("\ndump_tx_descriptor_queue()\n");
+ printf(" descriptor address word1 word2\n");
+ for (i = 0; i < NUMTXDESC; i++) {
+ printf(" [ %p ] %08X %08X\n",
+ priv->tx_dq.base + i,
+ (priv->tx_dq.base + i)->word1,
+ (priv->tx_dq.base + i)->word2);
+ }
+}
+
+/**
+ * Dump all TX status queue entries to the terminal.
+ */
+static void dump_tx_status_queue(struct eth_device *dev)
+{
+ struct ep93xx_priv *priv = GET_PRIV(dev);
+ int i;
+
+ printf("\ndump_tx_status_queue()\n");
+ printf(" descriptor address word1\n");
+ for (i = 0; i < NUMTXDESC; i++) {
+ printf(" [ %p ] %08X\n",
+ priv->rx_sq.base + i,
+ (priv->rx_sq.base + i)->word1);
+ }
+}
+#else
+#define dump_dev(x)
+#define dump_rx_descriptor_queue(x)
+#define dump_rx_status_queue(x)
+#define dump_tx_descriptor_queue(x)
+#define dump_tx_status_queue(x)
+#endif /* defined(EP93XX_MAC_DEBUG) */
+
+/**
+ * Reset the EP93xx MAC by twiddling the soft reset bit and spinning until
+ * it's cleared.
+ */
+static void ep93xx_mac_reset(struct eth_device *dev)
+{
+ struct mac_regs *mac = GET_REGS(dev);
+ uint32_t value;
+
+ debug("+ep93xx_mac_reset");
+
+ value = readl(&mac->selfctl);
+ value |= SELFCTL_RESET;
+ writel(value, &mac->selfctl);
+
+ while (readl(&mac->selfctl) & SELFCTL_RESET)
+ ; /* noop */
+
+ debug("-ep93xx_mac_reset");
+}
+
+/* Eth device open */
+static int ep93xx_eth_open(struct eth_device *dev, bd_t *bd)
+{
+ struct ep93xx_priv *priv = GET_PRIV(dev);
+ struct mac_regs *mac = GET_REGS(dev);
+ uchar *mac_addr = dev->enetaddr;
+ int i;
+
+ debug("+ep93xx_eth_open");
+
+ /* Reset the MAC */
+ ep93xx_mac_reset(dev);
+
+ /* Reset the descriptor queues' current and end address values */
+ priv->tx_dq.current = priv->tx_dq.base;
+ priv->tx_dq.end = (priv->tx_dq.base + NUMTXDESC);
+
+ priv->tx_sq.current = priv->tx_sq.base;
+ priv->tx_sq.end = (priv->tx_sq.base + NUMTXDESC);
+
+ priv->rx_dq.current = priv->rx_dq.base;
+ priv->rx_dq.end = (priv->rx_dq.base + NUMRXDESC);
+
+ priv->rx_sq.current = priv->rx_sq.base;
+ priv->rx_sq.end = (priv->rx_sq.base + NUMRXDESC);
+
+ /*
+ * Set the transmit descriptor and status queues' base address,
+ * current address, and length registers. Set the maximum frame
+ * length and threshold. Enable the transmit descriptor processor.
+ */
+ writel((uint32_t)priv->tx_dq.base, &mac->txdq.badd);
+ writel((uint32_t)priv->tx_dq.base, &mac->txdq.curadd);
+ writel(sizeof(struct tx_descriptor) * NUMTXDESC, &mac->txdq.blen);
+
+ writel((uint32_t)priv->tx_sq.base, &mac->txstsq.badd);
+ writel((uint32_t)priv->tx_sq.base, &mac->txstsq.curadd);
+ writel(sizeof(struct tx_status) * NUMTXDESC, &mac->txstsq.blen);
+
+ writel(0x00040000, &mac->txdthrshld);
+ writel(0x00040000, &mac->txststhrshld);
+
+ writel((TXSTARTMAX << 0) | (PKTSIZE_ALIGN << 16), &mac->maxfrmlen);
+ writel(BMCTL_TXEN, &mac->bmctl);
+
+ /*
+ * Set the receive descriptor and status queues' base address,
+ * current address, and length registers. Enable the receive
+ * descriptor processor.
+ */
+ writel((uint32_t)priv->rx_dq.base, &mac->rxdq.badd);
+ writel((uint32_t)priv->rx_dq.base, &mac->rxdq.curadd);
+ writel(sizeof(struct rx_descriptor) * NUMRXDESC, &mac->rxdq.blen);
+
+ writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.badd);
+ writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.curadd);
+ writel(sizeof(struct rx_status) * NUMRXDESC, &mac->rxstsq.blen);
+
+ writel(0x00040000, &mac->rxdthrshld);
+
+ writel(BMCTL_RXEN, &mac->bmctl);
+
+ writel(0x00040000, &mac->rxststhrshld);
+
+ /* Wait until the receive descriptor processor is active */
+ while (!(readl(&mac->bmsts) & BMSTS_RXACT))
+ ; /* noop */
+
+ /*
+ * Initialize the RX descriptor queue. Clear the TX descriptor queue.
+ * Clear the RX and TX status queues. Enqueue the RX descriptor and
+ * status entries to the MAC.
+ */
+ for (i = 0; i < NUMRXDESC; i++) {
+ /* set buffer address */
+ (priv->rx_dq.base + i)->word1 = (uint32_t)NetRxPackets[i];
+
+ /* set buffer length, clear buffer index and NSOF */
+ (priv->rx_dq.base + i)->word2 = PKTSIZE_ALIGN;
+ }
+
+ memset(priv->tx_dq.base, 0,
+ (sizeof(struct tx_descriptor) * NUMTXDESC));
+ memset(priv->rx_sq.base, 0,
+ (sizeof(struct rx_status) * NUMRXDESC));
+ memset(priv->tx_sq.base, 0,
+ (sizeof(struct tx_status) * NUMTXDESC));
+
+ writel(NUMRXDESC, &mac->rxdqenq);
+ writel(NUMRXDESC, &mac->rxstsqenq);
+
+ /* Set the primary MAC address */
+ writel(AFP_IAPRIMARY, &mac->afp);
+ writel(mac_addr[0] | (mac_addr[1] << 8) |
+ (mac_addr[2] << 16) | (mac_addr[3] << 24),
+ &mac->indad);
+ writel(mac_addr[4] | (mac_addr[5] << 8), &mac->indad_upper);
+
+ /* Turn on RX and TX */
+ writel(RXCTL_IA0 | RXCTL_BA | RXCTL_SRXON |
+ RXCTL_RCRCA | RXCTL_MA, &mac->rxctl);
+ writel(TXCTL_STXON, &mac->txctl);
+
+ /* Dump data structures if we're debugging */
+ dump_dev(dev);
+ dump_rx_descriptor_queue(dev);
+ dump_rx_status_queue(dev);
+ dump_tx_descriptor_queue(dev);
+ dump_tx_status_queue(dev);
+
+ debug("-ep93xx_eth_open");
+
+ return 1;
+}
+
+/**
+ * Halt EP93xx MAC transmit and receive by clearing the TxCTL and RxCTL
+ * registers.
+ */
+static void ep93xx_eth_close(struct eth_device *dev)
+{
+ struct mac_regs *mac = GET_REGS(dev);
+
+ debug("+ep93xx_eth_close");
+
+ writel(0x00000000, &mac->rxctl);
+ writel(0x00000000, &mac->txctl);
+
+ debug("-ep93xx_eth_close");
+}
+
+/**
+ * Copy a frame of data from the MAC into the protocol layer for further
+ * processing.
+ */
+static int ep93xx_eth_rcv_packet(struct eth_device *dev)
+{
+ struct mac_regs *mac = GET_REGS(dev);
+ struct ep93xx_priv *priv = GET_PRIV(dev);
+ int len = -1;
+
+ debug("+ep93xx_eth_rcv_packet");
+
+ if (RX_STATUS_RFP(priv->rx_sq.current)) {
+ if (RX_STATUS_RWE(priv->rx_sq.current)) {
+ /*
+ * We have a good frame. Extract the frame's length
+ * from the current rx_status_queue entry, and copy
+ * the frame's data into NetRxPackets[] of the
+ * protocol stack. We track the total number of
+ * bytes in the frame (nbytes_frame) which will be
+ * used when we pass the data off to the protocol
+ * layer via NetReceive().
+ */
+ len = RX_STATUS_FRAME_LEN(priv->rx_sq.current);
+
+ NetReceive((uchar *)priv->rx_dq.current->word1, len);
+
+ debug("reporting %d bytes...\n", len);
+ } else {
+ /* Do we have an erroneous packet? */
+ error("packet rx error, status %08X %08X",
+ priv->rx_sq.current->word1,
+ priv->rx_sq.current->word2);
+ dump_rx_descriptor_queue(dev);
+ dump_rx_status_queue(dev);
+ }
+
+ /*
+ * Clear the associated status queue entry, and
+ * increment our current pointers to the next RX
+ * descriptor and status queue entries (making sure
+ * we wrap properly).
+ */
+ memset((void *)priv->rx_sq.current, 0,
+ sizeof(struct rx_status));
+
+ priv->rx_sq.current++;
+ if (priv->rx_sq.current >= priv->rx_sq.end)
+ priv->rx_sq.current = priv->rx_sq.base;
+
+ priv->rx_dq.current++;
+ if (priv->rx_dq.current >= priv->rx_dq.end)
+ priv->rx_dq.current = priv->rx_dq.base;
+
+ /*
+ * Finally, return the RX descriptor and status entries
+ * back to the MAC engine, and loop again, checking for
+ * more descriptors to process.
+ */
+ writel(1, &mac->rxdqenq);
+ writel(1, &mac->rxstsqenq);
+ } else {
+ len = 0;
+ }
+
+ debug("-ep93xx_eth_rcv_packet %d", len);
+ return len;
+}
+
+/**
+ * Send a block of data via ethernet.
+ */
+static int ep93xx_eth_send_packet(struct eth_device *dev,
+ void * const packet, int const length)
+{
+ struct mac_regs *mac = GET_REGS(dev);
+ struct ep93xx_priv *priv = GET_PRIV(dev);
+ int ret = -1;
+
+ debug("+ep93xx_eth_send_packet");
+
+ /* Parameter check */
+ BUG_ON(packet == NULL);
+
+ /*
+ * Initialize the TX descriptor queue with the new packet's info.
+ * Clear the associated status queue entry. Enqueue the packet
+ * to the MAC for transmission.
+ */
+
+ /* set buffer address */
+ priv->tx_dq.current->word1 = (uint32_t)packet;
+
+ /* set buffer length and EOF bit */
+ priv->tx_dq.current->word2 = length | TX_DESC_EOF;
+
+ /* clear tx status */
+ priv->tx_sq.current->word1 = 0;
+
+ /* enqueue the TX descriptor */
+ writel(1, &mac->txdqenq);
+
+ /* wait for the frame to become processed */
+ while (!TX_STATUS_TXFP(priv->tx_sq.current))
+ ; /* noop */
+
+ if (!TX_STATUS_TXWE(priv->tx_sq.current)) {
+ error("packet tx error, status %08X",
+ priv->tx_sq.current->word1);
+ dump_tx_descriptor_queue(dev);
+ dump_tx_status_queue(dev);
+
+ /* TODO: Add better error handling? */
+ goto eth_send_out;
+ }
+
+ ret = 0;
+ /* Fall through */
+
+eth_send_out:
+ debug("-ep93xx_eth_send_packet %d", ret);
+ return ret;
+}
+
+#if defined(CONFIG_MII)
+int ep93xx_miiphy_initialize(bd_t * const bd)
+{
+ miiphy_register("ep93xx_eth0", ep93xx_miiphy_read, ep93xx_miiphy_write);
+ return 0;
+}
+#endif
+
+/**
+ * Initialize the EP93xx MAC. The MAC hardware is reset. Buffers are
+ * allocated, if necessary, for the TX and RX descriptor and status queues,
+ * as well as for received packets. The EP93XX MAC hardware is initialized.
+ * Transmit and receive operations are enabled.
+ */
+int ep93xx_eth_initialize(u8 dev_num, int base_addr)
+{
+ int ret = -1;
+ struct eth_device *dev;
+ struct ep93xx_priv *priv;
+
+ debug("+ep93xx_eth_initialize");
+
+ priv = malloc(sizeof(*priv));
+ if (!priv) {
+ error("malloc() failed");
+ goto eth_init_failed_0;
+ }
+ memset(priv, 0, sizeof(*priv));
+
+ priv->regs = (struct mac_regs *)base_addr;
+
+ priv->tx_dq.base = calloc(NUMTXDESC,
+ sizeof(struct tx_descriptor));
+ if (priv->tx_dq.base == NULL) {
+ error("calloc() failed");
+ goto eth_init_failed_1;
+ }
+
+ priv->tx_sq.base = calloc(NUMTXDESC,
+ sizeof(struct tx_status));
+ if (priv->tx_sq.base == NULL) {
+ error("calloc() failed");
+ goto eth_init_failed_2;
+ }
+
+ priv->rx_dq.base = calloc(NUMRXDESC,
+ sizeof(struct rx_descriptor));
+ if (priv->rx_dq.base == NULL) {
+ error("calloc() failed");
+ goto eth_init_failed_3;
+ }
+
+ priv->rx_sq.base = calloc(NUMRXDESC,
+ sizeof(struct rx_status));
+ if (priv->rx_sq.base == NULL) {
+ error("calloc() failed");
+ goto eth_init_failed_4;
+ }
+
+ dev = malloc(sizeof *dev);
+ if (dev == NULL) {
+ error("malloc() failed");
+ goto eth_init_failed_5;
+ }
+ memset(dev, 0, sizeof *dev);
+
+ dev->iobase = base_addr;
+ dev->priv = priv;
+ dev->init = ep93xx_eth_open;
+ dev->halt = ep93xx_eth_close;
+ dev->send = ep93xx_eth_send_packet;
+ dev->recv = ep93xx_eth_rcv_packet;
+
+ sprintf(dev->name, "ep93xx_eth-%hu", dev_num);
+
+ eth_register(dev);
+
+ /* Done! */
+ ret = 1;
+ goto eth_init_done;
+
+eth_init_failed_5:
+ free(priv->rx_sq.base);
+ /* Fall through */
+
+eth_init_failed_4:
+ free(priv->rx_dq.base);
+ /* Fall through */
+
+eth_init_failed_3:
+ free(priv->tx_sq.base);
+ /* Fall through */
+
+eth_init_failed_2:
+ free(priv->tx_dq.base);
+ /* Fall through */
+
+eth_init_failed_1:
+ free(priv);
+ /* Fall through */
+
+eth_init_failed_0:
+ /* Fall through */
+
+eth_init_done:
+ debug("-ep93xx_eth_initialize %d", ret);
+ return ret;
+}
+
+#if defined(CONFIG_MII)
+
+/**
+ * Maximum MII address we support
+ */
+#define MII_ADDRESS_MAX 31
+
+/**
+ * Maximum MII register address we support
+ */
+#define MII_REGISTER_MAX 31
+
+/**
+ * Read a 16-bit value from an MII register.
+ */
+static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
+ unsigned char const reg, unsigned short * const value)
+{
+ struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
+ int ret = -1;
+ uint32_t self_ctl;
+
+ debug("+ep93xx_miiphy_read");
+
+ /* Parameter checks */
+ BUG_ON(dev == NULL);
+ BUG_ON(addr > MII_ADDRESS_MAX);
+ BUG_ON(reg > MII_REGISTER_MAX);
+ BUG_ON(value == NULL);
+
+ /*
+ * Save the current SelfCTL register value. Set MAC to suppress
+ * preamble bits. Wait for any previous MII command to complete
+ * before issuing the new command.
+ */
+ self_ctl = readl(&mac->selfctl);
+#if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
+ writel(self_ctl & ~(1 << 8), &mac->selfctl);
+#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
+
+ while (readl(&mac->miists) & MIISTS_BUSY)
+ ; /* noop */
+
+ /*
+ * Issue the MII 'read' command. Wait for the command to complete.
+ * Read the MII data value.
+ */
+ writel(MIICMD_OPCODE_READ | ((uint32_t)addr << 5) | (uint32_t)reg,
+ &mac->miicmd);
+ while (readl(&mac->miists) & MIISTS_BUSY)
+ ; /* noop */
+
+ *value = (unsigned short)readl(&mac->miidata);
+
+ /* Restore the saved SelfCTL value and return. */
+ writel(self_ctl, &mac->selfctl);
+
+ ret = 0;
+ /* Fall through */
+
+ debug("-ep93xx_miiphy_read");
+ return ret;
+}
+
+/**
+ * Write a 16-bit value to an MII register.
+ */
+static int ep93xx_miiphy_write(const char * const dev, unsigned char const addr,
+ unsigned char const reg, unsigned short const value)
+{
+ struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
+ int ret = -1;
+ uint32_t self_ctl;
+
+ debug("+ep93xx_miiphy_write");
+
+ /* Parameter checks */
+ BUG_ON(dev == NULL);
+ BUG_ON(addr > MII_ADDRESS_MAX);
+ BUG_ON(reg > MII_REGISTER_MAX);
+
+ /*
+ * Save the current SelfCTL register value. Set MAC to suppress
+ * preamble bits. Wait for any previous MII command to complete
+ * before issuing the new command.
+ */
+ self_ctl = readl(&mac->selfctl);
+#if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
+ writel(self_ctl & ~(1 << 8), &mac->selfctl);
+#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
+
+ while (readl(&mac->miists) & MIISTS_BUSY)
+ ; /* noop */
+
+ /* Issue the MII 'write' command. Wait for the command to complete. */
+ writel((uint32_t)value, &mac->miidata);
+ writel(MIICMD_OPCODE_WRITE | ((uint32_t)addr << 5) | (uint32_t)reg,
+ &mac->miicmd);
+ while (readl(&mac->miists) & MIISTS_BUSY)
+ ; /* noop */
+
+ /* Restore the saved SelfCTL value and return. */
+ writel(self_ctl, &mac->selfctl);
+
+ ret = 0;
+ /* Fall through */
+
+ debug("-ep93xx_miiphy_write");
+ return ret;
+}
+#endif /* defined(CONFIG_MII) */
diff --git a/qemu/roms/u-boot/drivers/net/ep93xx_eth.h b/qemu/roms/u-boot/drivers/net/ep93xx_eth.h
new file mode 100644
index 000000000..e6c949ffc
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ep93xx_eth.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
+ *
+ * Copyright (C) 2004, 2005
+ * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _EP93XX_ETH_H
+#define _EP93XX_ETH_H
+
+#include <net.h>
+
+/**
+ * #define this to dump device status and queue info during initialization and
+ * following errors.
+ */
+#undef EP93XX_MAC_DEBUG
+
+/**
+ * Number of descriptor and status entries in our RX queues.
+ * It must be power of 2 !
+ */
+#define NUMRXDESC PKTBUFSRX
+
+/**
+ * Number of descriptor and status entries in our TX queues.
+ */
+#define NUMTXDESC 1
+
+/**
+ * 944 = (1024 - 64) - 16, Fifo size - Minframesize - 16 (Chip FACT)
+ */
+#define TXSTARTMAX 944
+
+/**
+ * Receive descriptor queue entry
+ */
+struct rx_descriptor {
+ uint32_t word1;
+ uint32_t word2;
+};
+
+/**
+ * Receive status queue entry
+ */
+struct rx_status {
+ uint32_t word1;
+ uint32_t word2;
+};
+
+#define RX_STATUS_RWE(rx_status) ((rx_status->word1 >> 30) & 0x01)
+#define RX_STATUS_RFP(rx_status) ((rx_status->word1 >> 31) & 0x01)
+#define RX_STATUS_FRAME_LEN(rx_status) (rx_status->word2 & 0xFFFF)
+
+/**
+ * Transmit descriptor queue entry
+ */
+struct tx_descriptor {
+ uint32_t word1;
+ uint32_t word2;
+};
+
+#define TX_DESC_EOF (1 << 31)
+
+/**
+ * Transmit status queue entry
+ */
+struct tx_status {
+ uint32_t word1;
+};
+
+#define TX_STATUS_TXWE(tx_status) (((tx_status)->word1 >> 30) & 0x01)
+#define TX_STATUS_TXFP(tx_status) (((tx_status)->word1 >> 31) & 0x01)
+
+/**
+ * Transmit descriptor queue
+ */
+struct tx_descriptor_queue {
+ struct tx_descriptor *base;
+ struct tx_descriptor *current;
+ struct tx_descriptor *end;
+};
+
+/**
+ * Transmit status queue
+ */
+struct tx_status_queue {
+ struct tx_status *base;
+ volatile struct tx_status *current;
+ struct tx_status *end;
+};
+
+/**
+ * Receive descriptor queue
+ */
+struct rx_descriptor_queue {
+ struct rx_descriptor *base;
+ struct rx_descriptor *current;
+ struct rx_descriptor *end;
+};
+
+/**
+ * Receive status queue
+ */
+struct rx_status_queue {
+ struct rx_status *base;
+ volatile struct rx_status *current;
+ struct rx_status *end;
+};
+
+/**
+ * EP93xx MAC private data structure
+ */
+struct ep93xx_priv {
+ struct rx_descriptor_queue rx_dq;
+ struct rx_status_queue rx_sq;
+ void *rx_buffer[NUMRXDESC];
+
+ struct tx_descriptor_queue tx_dq;
+ struct tx_status_queue tx_sq;
+
+ struct mac_regs *regs;
+};
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/ethoc.c b/qemu/roms/u-boot/drivers/net/ethoc.c
new file mode 100644
index 000000000..af06d4fb8
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ethoc.c
@@ -0,0 +1,511 @@
+/*
+ * Opencore 10/100 ethernet mac driver
+ *
+ * Copyright (C) 2007-2008 Avionic Design Development GmbH
+ * Copyright (C) 2008-2009 Avionic Design GmbH
+ * Thierry Reding <thierry.reding@avionic-design.de>
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <asm/io.h>
+#include <asm/cache.h>
+
+/* register offsets */
+#define MODER 0x00
+#define INT_SOURCE 0x04
+#define INT_MASK 0x08
+#define IPGT 0x0c
+#define IPGR1 0x10
+#define IPGR2 0x14
+#define PACKETLEN 0x18
+#define COLLCONF 0x1c
+#define TX_BD_NUM 0x20
+#define CTRLMODER 0x24
+#define MIIMODER 0x28
+#define MIICOMMAND 0x2c
+#define MIIADDRESS 0x30
+#define MIITX_DATA 0x34
+#define MIIRX_DATA 0x38
+#define MIISTATUS 0x3c
+#define MAC_ADDR0 0x40
+#define MAC_ADDR1 0x44
+#define ETH_HASH0 0x48
+#define ETH_HASH1 0x4c
+#define ETH_TXCTRL 0x50
+
+/* mode register */
+#define MODER_RXEN (1 << 0) /* receive enable */
+#define MODER_TXEN (1 << 1) /* transmit enable */
+#define MODER_NOPRE (1 << 2) /* no preamble */
+#define MODER_BRO (1 << 3) /* broadcast address */
+#define MODER_IAM (1 << 4) /* individual address mode */
+#define MODER_PRO (1 << 5) /* promiscuous mode */
+#define MODER_IFG (1 << 6) /* interframe gap for incoming frames */
+#define MODER_LOOP (1 << 7) /* loopback */
+#define MODER_NBO (1 << 8) /* no back-off */
+#define MODER_EDE (1 << 9) /* excess defer enable */
+#define MODER_FULLD (1 << 10) /* full duplex */
+#define MODER_RESET (1 << 11) /* FIXME: reset (undocumented) */
+#define MODER_DCRC (1 << 12) /* delayed CRC enable */
+#define MODER_CRC (1 << 13) /* CRC enable */
+#define MODER_HUGE (1 << 14) /* huge packets enable */
+#define MODER_PAD (1 << 15) /* padding enabled */
+#define MODER_RSM (1 << 16) /* receive small packets */
+
+/* interrupt source and mask registers */
+#define INT_MASK_TXF (1 << 0) /* transmit frame */
+#define INT_MASK_TXE (1 << 1) /* transmit error */
+#define INT_MASK_RXF (1 << 2) /* receive frame */
+#define INT_MASK_RXE (1 << 3) /* receive error */
+#define INT_MASK_BUSY (1 << 4)
+#define INT_MASK_TXC (1 << 5) /* transmit control frame */
+#define INT_MASK_RXC (1 << 6) /* receive control frame */
+
+#define INT_MASK_TX (INT_MASK_TXF | INT_MASK_TXE)
+#define INT_MASK_RX (INT_MASK_RXF | INT_MASK_RXE)
+
+#define INT_MASK_ALL ( \
+ INT_MASK_TXF | INT_MASK_TXE | \
+ INT_MASK_RXF | INT_MASK_RXE | \
+ INT_MASK_TXC | INT_MASK_RXC | \
+ INT_MASK_BUSY \
+ )
+
+/* packet length register */
+#define PACKETLEN_MIN(min) (((min) & 0xffff) << 16)
+#define PACKETLEN_MAX(max) (((max) & 0xffff) << 0)
+#define PACKETLEN_MIN_MAX(min, max) (PACKETLEN_MIN(min) | \
+ PACKETLEN_MAX(max))
+
+/* transmit buffer number register */
+#define TX_BD_NUM_VAL(x) (((x) <= 0x80) ? (x) : 0x80)
+
+/* control module mode register */
+#define CTRLMODER_PASSALL (1 << 0) /* pass all receive frames */
+#define CTRLMODER_RXFLOW (1 << 1) /* receive control flow */
+#define CTRLMODER_TXFLOW (1 << 2) /* transmit control flow */
+
+/* MII mode register */
+#define MIIMODER_CLKDIV(x) ((x) & 0xfe) /* needs to be an even number */
+#define MIIMODER_NOPRE (1 << 8) /* no preamble */
+
+/* MII command register */
+#define MIICOMMAND_SCAN (1 << 0) /* scan status */
+#define MIICOMMAND_READ (1 << 1) /* read status */
+#define MIICOMMAND_WRITE (1 << 2) /* write control data */
+
+/* MII address register */
+#define MIIADDRESS_FIAD(x) (((x) & 0x1f) << 0)
+#define MIIADDRESS_RGAD(x) (((x) & 0x1f) << 8)
+#define MIIADDRESS_ADDR(phy, reg) (MIIADDRESS_FIAD(phy) | \
+ MIIADDRESS_RGAD(reg))
+
+/* MII transmit data register */
+#define MIITX_DATA_VAL(x) ((x) & 0xffff)
+
+/* MII receive data register */
+#define MIIRX_DATA_VAL(x) ((x) & 0xffff)
+
+/* MII status register */
+#define MIISTATUS_LINKFAIL (1 << 0)
+#define MIISTATUS_BUSY (1 << 1)
+#define MIISTATUS_INVALID (1 << 2)
+
+/* TX buffer descriptor */
+#define TX_BD_CS (1 << 0) /* carrier sense lost */
+#define TX_BD_DF (1 << 1) /* defer indication */
+#define TX_BD_LC (1 << 2) /* late collision */
+#define TX_BD_RL (1 << 3) /* retransmission limit */
+#define TX_BD_RETRY_MASK (0x00f0)
+#define TX_BD_RETRY(x) (((x) & 0x00f0) >> 4)
+#define TX_BD_UR (1 << 8) /* transmitter underrun */
+#define TX_BD_CRC (1 << 11) /* TX CRC enable */
+#define TX_BD_PAD (1 << 12) /* pad enable */
+#define TX_BD_WRAP (1 << 13)
+#define TX_BD_IRQ (1 << 14) /* interrupt request enable */
+#define TX_BD_READY (1 << 15) /* TX buffer ready */
+#define TX_BD_LEN(x) (((x) & 0xffff) << 16)
+#define TX_BD_LEN_MASK (0xffff << 16)
+
+#define TX_BD_STATS (TX_BD_CS | TX_BD_DF | TX_BD_LC | \
+ TX_BD_RL | TX_BD_RETRY_MASK | TX_BD_UR)
+
+/* RX buffer descriptor */
+#define RX_BD_LC (1 << 0) /* late collision */
+#define RX_BD_CRC (1 << 1) /* RX CRC error */
+#define RX_BD_SF (1 << 2) /* short frame */
+#define RX_BD_TL (1 << 3) /* too long */
+#define RX_BD_DN (1 << 4) /* dribble nibble */
+#define RX_BD_IS (1 << 5) /* invalid symbol */
+#define RX_BD_OR (1 << 6) /* receiver overrun */
+#define RX_BD_MISS (1 << 7)
+#define RX_BD_CF (1 << 8) /* control frame */
+#define RX_BD_WRAP (1 << 13)
+#define RX_BD_IRQ (1 << 14) /* interrupt request enable */
+#define RX_BD_EMPTY (1 << 15)
+#define RX_BD_LEN(x) (((x) & 0xffff) << 16)
+
+#define RX_BD_STATS (RX_BD_LC | RX_BD_CRC | RX_BD_SF | RX_BD_TL | \
+ RX_BD_DN | RX_BD_IS | RX_BD_OR | RX_BD_MISS)
+
+#define ETHOC_BUFSIZ 1536
+#define ETHOC_ZLEN 64
+#define ETHOC_BD_BASE 0x400
+#define ETHOC_TIMEOUT (HZ / 2)
+#define ETHOC_MII_TIMEOUT (1 + (HZ / 5))
+
+/**
+ * struct ethoc - driver-private device structure
+ * @num_tx: number of send buffers
+ * @cur_tx: last send buffer written
+ * @dty_tx: last buffer actually sent
+ * @num_rx: number of receive buffers
+ * @cur_rx: current receive buffer
+ */
+struct ethoc {
+ u32 num_tx;
+ u32 cur_tx;
+ u32 dty_tx;
+ u32 num_rx;
+ u32 cur_rx;
+};
+
+/**
+ * struct ethoc_bd - buffer descriptor
+ * @stat: buffer statistics
+ * @addr: physical memory address
+ */
+struct ethoc_bd {
+ u32 stat;
+ u32 addr;
+};
+
+static inline u32 ethoc_read(struct eth_device *dev, loff_t offset)
+{
+ return readl(dev->iobase + offset);
+}
+
+static inline void ethoc_write(struct eth_device *dev, loff_t offset, u32 data)
+{
+ writel(data, dev->iobase + offset);
+}
+
+static inline void ethoc_read_bd(struct eth_device *dev, int index,
+ struct ethoc_bd *bd)
+{
+ loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
+ bd->stat = ethoc_read(dev, offset + 0);
+ bd->addr = ethoc_read(dev, offset + 4);
+}
+
+static inline void ethoc_write_bd(struct eth_device *dev, int index,
+ const struct ethoc_bd *bd)
+{
+ loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
+ ethoc_write(dev, offset + 0, bd->stat);
+ ethoc_write(dev, offset + 4, bd->addr);
+}
+
+static int ethoc_set_mac_address(struct eth_device *dev)
+{
+ u8 *mac = dev->enetaddr;
+
+ ethoc_write(dev, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) |
+ (mac[4] << 8) | (mac[5] << 0));
+ ethoc_write(dev, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0));
+ return 0;
+}
+
+static inline void ethoc_ack_irq(struct eth_device *dev, u32 mask)
+{
+ ethoc_write(dev, INT_SOURCE, mask);
+}
+
+static inline void ethoc_enable_rx_and_tx(struct eth_device *dev)
+{
+ u32 mode = ethoc_read(dev, MODER);
+ mode |= MODER_RXEN | MODER_TXEN;
+ ethoc_write(dev, MODER, mode);
+}
+
+static inline void ethoc_disable_rx_and_tx(struct eth_device *dev)
+{
+ u32 mode = ethoc_read(dev, MODER);
+ mode &= ~(MODER_RXEN | MODER_TXEN);
+ ethoc_write(dev, MODER, mode);
+}
+
+static int ethoc_init_ring(struct eth_device *dev)
+{
+ struct ethoc *priv = (struct ethoc *)dev->priv;
+ struct ethoc_bd bd;
+ int i;
+
+ priv->cur_tx = 0;
+ priv->dty_tx = 0;
+ priv->cur_rx = 0;
+
+ /* setup transmission buffers */
+ bd.stat = TX_BD_IRQ | TX_BD_CRC;
+
+ for (i = 0; i < priv->num_tx; i++) {
+ if (i == priv->num_tx - 1)
+ bd.stat |= TX_BD_WRAP;
+
+ ethoc_write_bd(dev, i, &bd);
+ }
+
+ bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
+
+ for (i = 0; i < priv->num_rx; i++) {
+ bd.addr = (u32)NetRxPackets[i];
+ if (i == priv->num_rx - 1)
+ bd.stat |= RX_BD_WRAP;
+
+ flush_dcache_range(bd.addr, bd.addr + PKTSIZE_ALIGN);
+ ethoc_write_bd(dev, priv->num_tx + i, &bd);
+ }
+
+ return 0;
+}
+
+static int ethoc_reset(struct eth_device *dev)
+{
+ u32 mode;
+
+ /* TODO: reset controller? */
+
+ ethoc_disable_rx_and_tx(dev);
+
+ /* TODO: setup registers */
+
+ /* enable FCS generation and automatic padding */
+ mode = ethoc_read(dev, MODER);
+ mode |= MODER_CRC | MODER_PAD;
+ ethoc_write(dev, MODER, mode);
+
+ /* set full-duplex mode */
+ mode = ethoc_read(dev, MODER);
+ mode |= MODER_FULLD;
+ ethoc_write(dev, MODER, mode);
+ ethoc_write(dev, IPGT, 0x15);
+
+ ethoc_ack_irq(dev, INT_MASK_ALL);
+ ethoc_enable_rx_and_tx(dev);
+ return 0;
+}
+
+static int ethoc_init(struct eth_device *dev, bd_t * bd)
+{
+ struct ethoc *priv = (struct ethoc *)dev->priv;
+ printf("ethoc\n");
+
+ priv->num_tx = 1;
+ priv->num_rx = PKTBUFSRX;
+ ethoc_write(dev, TX_BD_NUM, priv->num_tx);
+ ethoc_init_ring(dev);
+ ethoc_reset(dev);
+
+ return 0;
+}
+
+static int ethoc_update_rx_stats(struct ethoc_bd *bd)
+{
+ int ret = 0;
+
+ if (bd->stat & RX_BD_TL) {
+ debug("ETHOC: " "RX: frame too long\n");
+ ret++;
+ }
+
+ if (bd->stat & RX_BD_SF) {
+ debug("ETHOC: " "RX: frame too short\n");
+ ret++;
+ }
+
+ if (bd->stat & RX_BD_DN)
+ debug("ETHOC: " "RX: dribble nibble\n");
+
+ if (bd->stat & RX_BD_CRC) {
+ debug("ETHOC: " "RX: wrong CRC\n");
+ ret++;
+ }
+
+ if (bd->stat & RX_BD_OR) {
+ debug("ETHOC: " "RX: overrun\n");
+ ret++;
+ }
+
+ if (bd->stat & RX_BD_LC) {
+ debug("ETHOC: " "RX: late collision\n");
+ ret++;
+ }
+
+ return ret;
+}
+
+static int ethoc_rx(struct eth_device *dev, int limit)
+{
+ struct ethoc *priv = (struct ethoc *)dev->priv;
+ int count;
+
+ for (count = 0; count < limit; ++count) {
+ u32 entry;
+ struct ethoc_bd bd;
+
+ entry = priv->num_tx + (priv->cur_rx % priv->num_rx);
+ ethoc_read_bd(dev, entry, &bd);
+ if (bd.stat & RX_BD_EMPTY)
+ break;
+
+ debug("%s(): RX buffer %d, %x received\n",
+ __func__, priv->cur_rx, bd.stat);
+ if (ethoc_update_rx_stats(&bd) == 0) {
+ int size = bd.stat >> 16;
+ size -= 4; /* strip the CRC */
+ NetReceive((void *)bd.addr, size);
+ }
+
+ /* clear the buffer descriptor so it can be reused */
+ flush_dcache_range(bd.addr, bd.addr + PKTSIZE_ALIGN);
+ bd.stat &= ~RX_BD_STATS;
+ bd.stat |= RX_BD_EMPTY;
+ ethoc_write_bd(dev, entry, &bd);
+ priv->cur_rx++;
+ }
+
+ return count;
+}
+
+static int ethoc_update_tx_stats(struct ethoc_bd *bd)
+{
+ if (bd->stat & TX_BD_LC)
+ debug("ETHOC: " "TX: late collision\n");
+
+ if (bd->stat & TX_BD_RL)
+ debug("ETHOC: " "TX: retransmit limit\n");
+
+ if (bd->stat & TX_BD_UR)
+ debug("ETHOC: " "TX: underrun\n");
+
+ if (bd->stat & TX_BD_CS)
+ debug("ETHOC: " "TX: carrier sense lost\n");
+
+ return 0;
+}
+
+static void ethoc_tx(struct eth_device *dev)
+{
+ struct ethoc *priv = (struct ethoc *)dev->priv;
+ u32 entry = priv->dty_tx % priv->num_tx;
+ struct ethoc_bd bd;
+
+ ethoc_read_bd(dev, entry, &bd);
+ if ((bd.stat & TX_BD_READY) == 0)
+ (void)ethoc_update_tx_stats(&bd);
+}
+
+static int ethoc_send(struct eth_device *dev, void *packet, int length)
+{
+ struct ethoc *priv = (struct ethoc *)dev->priv;
+ struct ethoc_bd bd;
+ u32 entry;
+ u32 pending;
+ int tmo;
+
+ entry = priv->cur_tx % priv->num_tx;
+ ethoc_read_bd(dev, entry, &bd);
+ if (unlikely(length < ETHOC_ZLEN))
+ bd.stat |= TX_BD_PAD;
+ else
+ bd.stat &= ~TX_BD_PAD;
+ bd.addr = (u32)packet;
+
+ flush_dcache_range(bd.addr, bd.addr + length);
+ bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
+ bd.stat |= TX_BD_LEN(length);
+ ethoc_write_bd(dev, entry, &bd);
+
+ /* start transmit */
+ bd.stat |= TX_BD_READY;
+ ethoc_write_bd(dev, entry, &bd);
+
+ /* wait for transfer to succeed */
+ tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
+ while (1) {
+ pending = ethoc_read(dev, INT_SOURCE);
+ ethoc_ack_irq(dev, pending & ~INT_MASK_RX);
+ if (pending & INT_MASK_BUSY)
+ debug("%s(): packet dropped\n", __func__);
+
+ if (pending & INT_MASK_TX) {
+ ethoc_tx(dev);
+ break;
+ }
+ if (get_timer(0) >= tmo) {
+ debug("%s(): timed out\n", __func__);
+ return -1;
+ }
+ }
+
+ debug("%s(): packet sent\n", __func__);
+ return 0;
+}
+
+static void ethoc_halt(struct eth_device *dev)
+{
+ ethoc_disable_rx_and_tx(dev);
+}
+
+static int ethoc_recv(struct eth_device *dev)
+{
+ u32 pending;
+
+ pending = ethoc_read(dev, INT_SOURCE);
+ ethoc_ack_irq(dev, pending);
+ if (pending & INT_MASK_BUSY)
+ debug("%s(): packet dropped\n", __func__);
+ if (pending & INT_MASK_RX) {
+ debug("%s(): rx irq\n", __func__);
+ ethoc_rx(dev, PKTBUFSRX);
+ }
+
+ return 0;
+}
+
+int ethoc_initialize(u8 dev_num, int base_addr)
+{
+ struct ethoc *priv;
+ struct eth_device *dev;
+
+ priv = malloc(sizeof(*priv));
+ if (!priv)
+ return 0;
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ free(priv);
+ return 0;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ dev->priv = priv;
+ dev->iobase = base_addr;
+ dev->init = ethoc_init;
+ dev->halt = ethoc_halt;
+ dev->send = ethoc_send;
+ dev->recv = ethoc_recv;
+ dev->write_hwaddr = ethoc_set_mac_address;
+ sprintf(dev->name, "%s-%hu", "ETHOC", dev_num);
+
+ eth_register(dev);
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fec_mxc.c b/qemu/roms/u-boot/drivers/net/fec_mxc.c
new file mode 100644
index 000000000..4cefda48e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fec_mxc.c
@@ -0,0 +1,1102 @@
+/*
+ * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
+ * (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org>
+ * (C) Copyright 2008 Armadeus Systems nc
+ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include "fec_mxc.h"
+
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Timeout the transfer after 5 mS. This is usually a bit more, since
+ * the code in the tightloops this timeout is used in adds some overhead.
+ */
+#define FEC_XFER_TIMEOUT 5000
+
+#ifndef CONFIG_MII
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#ifndef CONFIG_FEC_XCV_TYPE
+#define CONFIG_FEC_XCV_TYPE MII100
+#endif
+
+/*
+ * The i.MX28 operates with packets in big endian. We need to swap them before
+ * sending and after receiving.
+ */
+#ifdef CONFIG_MX28
+#define CONFIG_FEC_MXC_SWAP_PACKET
+#endif
+
+#define RXDESC_PER_CACHELINE (ARCH_DMA_MINALIGN/sizeof(struct fec_bd))
+
+/* Check various alignment issues at compile time */
+#if ((ARCH_DMA_MINALIGN < 16) || (ARCH_DMA_MINALIGN % 16 != 0))
+#error "ARCH_DMA_MINALIGN must be multiple of 16!"
+#endif
+
+#if ((PKTALIGN < ARCH_DMA_MINALIGN) || \
+ (PKTALIGN % ARCH_DMA_MINALIGN != 0))
+#error "PKTALIGN must be multiple of ARCH_DMA_MINALIGN!"
+#endif
+
+#undef DEBUG
+
+struct nbuf {
+ uint8_t data[1500]; /**< actual data */
+ int length; /**< actual length */
+ int used; /**< buffer in use or not */
+ uint8_t head[16]; /**< MAC header(6 + 6 + 2) + 2(aligned) */
+};
+
+#ifdef CONFIG_FEC_MXC_SWAP_PACKET
+static void swap_packet(uint32_t *packet, int length)
+{
+ int i;
+
+ for (i = 0; i < DIV_ROUND_UP(length, 4); i++)
+ packet[i] = __swab32(packet[i]);
+}
+#endif
+
+/*
+ * MII-interface related functions
+ */
+static int fec_mdio_read(struct ethernet_regs *eth, uint8_t phyAddr,
+ uint8_t regAddr)
+{
+ uint32_t reg; /* convenient holder for the PHY register */
+ uint32_t phy; /* convenient holder for the PHY */
+ uint32_t start;
+ int val;
+
+ /*
+ * reading from any PHY's register is done by properly
+ * programming the FEC's MII data register.
+ */
+ writel(FEC_IEVENT_MII, &eth->ievent);
+ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+ writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA |
+ phy | reg, &eth->mii_data);
+
+ /*
+ * wait for the related interrupt
+ */
+ start = get_timer(0);
+ while (!(readl(&eth->ievent) & FEC_IEVENT_MII)) {
+ if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+ printf("Read MDIO failed...\n");
+ return -1;
+ }
+ }
+
+ /*
+ * clear mii interrupt bit
+ */
+ writel(FEC_IEVENT_MII, &eth->ievent);
+
+ /*
+ * it's now safe to read the PHY's register
+ */
+ val = (unsigned short)readl(&eth->mii_data);
+ debug("%s: phy: %02x reg:%02x val:%#x\n", __func__, phyAddr,
+ regAddr, val);
+ return val;
+}
+
+static void fec_mii_setspeed(struct ethernet_regs *eth)
+{
+ /*
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+ * and do not drop the Preamble.
+ */
+ register u32 speed = DIV_ROUND_UP(imx_get_fecclk(), 5000000);
+#ifdef FEC_QUIRK_ENET_MAC
+ speed--;
+#endif
+ speed <<= 1;
+ writel(speed, &eth->mii_speed);
+ debug("%s: mii_speed %08x\n", __func__, readl(&eth->mii_speed));
+}
+
+static int fec_mdio_write(struct ethernet_regs *eth, uint8_t phyAddr,
+ uint8_t regAddr, uint16_t data)
+{
+ uint32_t reg; /* convenient holder for the PHY register */
+ uint32_t phy; /* convenient holder for the PHY */
+ uint32_t start;
+
+ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+ writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
+ FEC_MII_DATA_TA | phy | reg | data, &eth->mii_data);
+
+ /*
+ * wait for the MII interrupt
+ */
+ start = get_timer(0);
+ while (!(readl(&eth->ievent) & FEC_IEVENT_MII)) {
+ if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+ printf("Write MDIO failed...\n");
+ return -1;
+ }
+ }
+
+ /*
+ * clear MII interrupt bit
+ */
+ writel(FEC_IEVENT_MII, &eth->ievent);
+ debug("%s: phy: %02x reg:%02x val:%#x\n", __func__, phyAddr,
+ regAddr, data);
+
+ return 0;
+}
+
+int fec_phy_read(struct mii_dev *bus, int phyAddr, int dev_addr, int regAddr)
+{
+ return fec_mdio_read(bus->priv, phyAddr, regAddr);
+}
+
+int fec_phy_write(struct mii_dev *bus, int phyAddr, int dev_addr, int regAddr,
+ u16 data)
+{
+ return fec_mdio_write(bus->priv, phyAddr, regAddr, data);
+}
+
+#ifndef CONFIG_PHYLIB
+static int miiphy_restart_aneg(struct eth_device *dev)
+{
+ int ret = 0;
+#if !defined(CONFIG_FEC_MXC_NO_ANEG)
+ struct fec_priv *fec = (struct fec_priv *)dev->priv;
+ struct ethernet_regs *eth = fec->bus->priv;
+
+ /*
+ * Wake up from sleep if necessary
+ * Reset PHY, then delay 300ns
+ */
+#ifdef CONFIG_MX27
+ fec_mdio_write(eth, fec->phy_id, MII_DCOUNTER, 0x00FF);
+#endif
+ fec_mdio_write(eth, fec->phy_id, MII_BMCR, BMCR_RESET);
+ udelay(1000);
+
+ /*
+ * Set the auto-negotiation advertisement register bits
+ */
+ fec_mdio_write(eth, fec->phy_id, MII_ADVERTISE,
+ LPA_100FULL | LPA_100HALF | LPA_10FULL |
+ LPA_10HALF | PHY_ANLPAR_PSB_802_3);
+ fec_mdio_write(eth, fec->phy_id, MII_BMCR,
+ BMCR_ANENABLE | BMCR_ANRESTART);
+
+ if (fec->mii_postcall)
+ ret = fec->mii_postcall(fec->phy_id);
+
+#endif
+ return ret;
+}
+
+static int miiphy_wait_aneg(struct eth_device *dev)
+{
+ uint32_t start;
+ int status;
+ struct fec_priv *fec = (struct fec_priv *)dev->priv;
+ struct ethernet_regs *eth = fec->bus->priv;
+
+ /*
+ * Wait for AN completion
+ */
+ start = get_timer(0);
+ do {
+ if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
+ printf("%s: Autonegotiation timeout\n", dev->name);
+ return -1;
+ }
+
+ status = fec_mdio_read(eth, fec->phy_id, MII_BMSR);
+ if (status < 0) {
+ printf("%s: Autonegotiation failed. status: %d\n",
+ dev->name, status);
+ return -1;
+ }
+ } while (!(status & BMSR_LSTATUS));
+
+ return 0;
+}
+#endif
+
+static int fec_rx_task_enable(struct fec_priv *fec)
+{
+ writel(FEC_R_DES_ACTIVE_RDAR, &fec->eth->r_des_active);
+ return 0;
+}
+
+static int fec_rx_task_disable(struct fec_priv *fec)
+{
+ return 0;
+}
+
+static int fec_tx_task_enable(struct fec_priv *fec)
+{
+ writel(FEC_X_DES_ACTIVE_TDAR, &fec->eth->x_des_active);
+ return 0;
+}
+
+static int fec_tx_task_disable(struct fec_priv *fec)
+{
+ return 0;
+}
+
+/**
+ * Initialize receive task's buffer descriptors
+ * @param[in] fec all we know about the device yet
+ * @param[in] count receive buffer count to be allocated
+ * @param[in] dsize desired size of each receive buffer
+ * @return 0 on success
+ *
+ * Init all RX descriptors to default values.
+ */
+static void fec_rbd_init(struct fec_priv *fec, int count, int dsize)
+{
+ uint32_t size;
+ uint8_t *data;
+ int i;
+
+ /*
+ * Reload the RX descriptors with default values and wipe
+ * the RX buffers.
+ */
+ size = roundup(dsize, ARCH_DMA_MINALIGN);
+ for (i = 0; i < count; i++) {
+ data = (uint8_t *)fec->rbd_base[i].data_pointer;
+ memset(data, 0, dsize);
+ flush_dcache_range((uint32_t)data, (uint32_t)data + size);
+
+ fec->rbd_base[i].status = FEC_RBD_EMPTY;
+ fec->rbd_base[i].data_length = 0;
+ }
+
+ /* Mark the last RBD to close the ring. */
+ fec->rbd_base[i - 1].status = FEC_RBD_WRAP | FEC_RBD_EMPTY;
+ fec->rbd_index = 0;
+
+ flush_dcache_range((unsigned)fec->rbd_base,
+ (unsigned)fec->rbd_base + size);
+}
+
+/**
+ * Initialize transmit task's buffer descriptors
+ * @param[in] fec all we know about the device yet
+ *
+ * Transmit buffers are created externally. We only have to init the BDs here.\n
+ * Note: There is a race condition in the hardware. When only one BD is in
+ * use it must be marked with the WRAP bit to use it for every transmitt.
+ * This bit in combination with the READY bit results into double transmit
+ * of each data buffer. It seems the state machine checks READY earlier then
+ * resetting it after the first transfer.
+ * Using two BDs solves this issue.
+ */
+static void fec_tbd_init(struct fec_priv *fec)
+{
+ unsigned addr = (unsigned)fec->tbd_base;
+ unsigned size = roundup(2 * sizeof(struct fec_bd),
+ ARCH_DMA_MINALIGN);
+
+ memset(fec->tbd_base, 0, size);
+ fec->tbd_base[0].status = 0;
+ fec->tbd_base[1].status = FEC_TBD_WRAP;
+ fec->tbd_index = 0;
+ flush_dcache_range(addr, addr + size);
+}
+
+/**
+ * Mark the given read buffer descriptor as free
+ * @param[in] last 1 if this is the last buffer descriptor in the chain, else 0
+ * @param[in] pRbd buffer descriptor to mark free again
+ */
+static void fec_rbd_clean(int last, struct fec_bd *pRbd)
+{
+ unsigned short flags = FEC_RBD_EMPTY;
+ if (last)
+ flags |= FEC_RBD_WRAP;
+ writew(flags, &pRbd->status);
+ writew(0, &pRbd->data_length);
+}
+
+static int fec_get_hwaddr(struct eth_device *dev, int dev_id,
+ unsigned char *mac)
+{
+ imx_get_mac_from_fuse(dev_id, mac);
+ return !is_valid_ether_addr(mac);
+}
+
+static int fec_set_hwaddr(struct eth_device *dev)
+{
+ uchar *mac = dev->enetaddr;
+ struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+ writel(0, &fec->eth->iaddr1);
+ writel(0, &fec->eth->iaddr2);
+ writel(0, &fec->eth->gaddr1);
+ writel(0, &fec->eth->gaddr2);
+
+ /*
+ * Set physical address
+ */
+ writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
+ &fec->eth->paddr1);
+ writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2);
+
+ return 0;
+}
+
+/*
+ * Do initial configuration of the FEC registers
+ */
+static void fec_reg_setup(struct fec_priv *fec)
+{
+ uint32_t rcntrl;
+
+ /*
+ * Set interrupt mask register
+ */
+ writel(0x00000000, &fec->eth->imask);
+
+ /*
+ * Clear FEC-Lite interrupt event register(IEVENT)
+ */
+ writel(0xffffffff, &fec->eth->ievent);
+
+
+ /*
+ * Set FEC-Lite receive control register(R_CNTRL):
+ */
+
+ /* Start with frame length = 1518, common for all modes. */
+ rcntrl = PKTSIZE << FEC_RCNTRL_MAX_FL_SHIFT;
+ if (fec->xcv_type != SEVENWIRE) /* xMII modes */
+ rcntrl |= FEC_RCNTRL_FCE | FEC_RCNTRL_MII_MODE;
+ if (fec->xcv_type == RGMII)
+ rcntrl |= FEC_RCNTRL_RGMII;
+ else if (fec->xcv_type == RMII)
+ rcntrl |= FEC_RCNTRL_RMII;
+
+ writel(rcntrl, &fec->eth->r_cntrl);
+}
+
+/**
+ * Start the FEC engine
+ * @param[in] dev Our device to handle
+ */
+static int fec_open(struct eth_device *edev)
+{
+ struct fec_priv *fec = (struct fec_priv *)edev->priv;
+ int speed;
+ uint32_t addr, size;
+ int i;
+
+ debug("fec_open: fec_open(dev)\n");
+ /* full-duplex, heartbeat disabled */
+ writel(1 << 2, &fec->eth->x_cntrl);
+ fec->rbd_index = 0;
+
+ /* Invalidate all descriptors */
+ for (i = 0; i < FEC_RBD_NUM - 1; i++)
+ fec_rbd_clean(0, &fec->rbd_base[i]);
+ fec_rbd_clean(1, &fec->rbd_base[i]);
+
+ /* Flush the descriptors into RAM */
+ size = roundup(FEC_RBD_NUM * sizeof(struct fec_bd),
+ ARCH_DMA_MINALIGN);
+ addr = (uint32_t)fec->rbd_base;
+ flush_dcache_range(addr, addr + size);
+
+#ifdef FEC_QUIRK_ENET_MAC
+ /* Enable ENET HW endian SWAP */
+ writel(readl(&fec->eth->ecntrl) | FEC_ECNTRL_DBSWAP,
+ &fec->eth->ecntrl);
+ /* Enable ENET store and forward mode */
+ writel(readl(&fec->eth->x_wmrk) | FEC_X_WMRK_STRFWD,
+ &fec->eth->x_wmrk);
+#endif
+ /*
+ * Enable FEC-Lite controller
+ */
+ writel(readl(&fec->eth->ecntrl) | FEC_ECNTRL_ETHER_EN,
+ &fec->eth->ecntrl);
+#if defined(CONFIG_MX25) || defined(CONFIG_MX53) || defined(CONFIG_MX6SL)
+ udelay(100);
+ /*
+ * setup the MII gasket for RMII mode
+ */
+
+ /* disable the gasket */
+ writew(0, &fec->eth->miigsk_enr);
+
+ /* wait for the gasket to be disabled */
+ while (readw(&fec->eth->miigsk_enr) & MIIGSK_ENR_READY)
+ udelay(2);
+
+ /* configure gasket for RMII, 50 MHz, no loopback, and no echo */
+ writew(MIIGSK_CFGR_IF_MODE_RMII, &fec->eth->miigsk_cfgr);
+
+ /* re-enable the gasket */
+ writew(MIIGSK_ENR_EN, &fec->eth->miigsk_enr);
+
+ /* wait until MII gasket is ready */
+ int max_loops = 10;
+ while ((readw(&fec->eth->miigsk_enr) & MIIGSK_ENR_READY) == 0) {
+ if (--max_loops <= 0) {
+ printf("WAIT for MII Gasket ready timed out\n");
+ break;
+ }
+ }
+#endif
+
+#ifdef CONFIG_PHYLIB
+ {
+ /* Start up the PHY */
+ int ret = phy_startup(fec->phydev);
+
+ if (ret) {
+ printf("Could not initialize PHY %s\n",
+ fec->phydev->dev->name);
+ return ret;
+ }
+ speed = fec->phydev->speed;
+ }
+#else
+ miiphy_wait_aneg(edev);
+ speed = miiphy_speed(edev->name, fec->phy_id);
+ miiphy_duplex(edev->name, fec->phy_id);
+#endif
+
+#ifdef FEC_QUIRK_ENET_MAC
+ {
+ u32 ecr = readl(&fec->eth->ecntrl) & ~FEC_ECNTRL_SPEED;
+ u32 rcr = readl(&fec->eth->r_cntrl) & ~FEC_RCNTRL_RMII_10T;
+ if (speed == _1000BASET)
+ ecr |= FEC_ECNTRL_SPEED;
+ else if (speed != _100BASET)
+ rcr |= FEC_RCNTRL_RMII_10T;
+ writel(ecr, &fec->eth->ecntrl);
+ writel(rcr, &fec->eth->r_cntrl);
+ }
+#endif
+ debug("%s:Speed=%i\n", __func__, speed);
+
+ /*
+ * Enable SmartDMA receive task
+ */
+ fec_rx_task_enable(fec);
+
+ udelay(100000);
+ return 0;
+}
+
+static int fec_init(struct eth_device *dev, bd_t* bd)
+{
+ struct fec_priv *fec = (struct fec_priv *)dev->priv;
+ uint32_t mib_ptr = (uint32_t)&fec->eth->rmon_t_drop;
+ int i;
+
+ /* Initialize MAC address */
+ fec_set_hwaddr(dev);
+
+ /*
+ * Setup transmit descriptors, there are two in total.
+ */
+ fec_tbd_init(fec);
+
+ /* Setup receive descriptors. */
+ fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE);
+
+ fec_reg_setup(fec);
+
+ if (fec->xcv_type != SEVENWIRE)
+ fec_mii_setspeed(fec->bus->priv);
+
+ /*
+ * Set Opcode/Pause Duration Register
+ */
+ writel(0x00010020, &fec->eth->op_pause); /* FIXME 0xffff0020; */
+ writel(0x2, &fec->eth->x_wmrk);
+ /*
+ * Set multicast address filter
+ */
+ writel(0x00000000, &fec->eth->gaddr1);
+ writel(0x00000000, &fec->eth->gaddr2);
+
+
+ /* clear MIB RAM */
+ for (i = mib_ptr; i <= mib_ptr + 0xfc; i += 4)
+ writel(0, i);
+
+ /* FIFO receive start register */
+ writel(0x520, &fec->eth->r_fstart);
+
+ /* size and address of each buffer */
+ writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr);
+ writel((uint32_t)fec->tbd_base, &fec->eth->etdsr);
+ writel((uint32_t)fec->rbd_base, &fec->eth->erdsr);
+
+#ifndef CONFIG_PHYLIB
+ if (fec->xcv_type != SEVENWIRE)
+ miiphy_restart_aneg(dev);
+#endif
+ fec_open(dev);
+ return 0;
+}
+
+/**
+ * Halt the FEC engine
+ * @param[in] dev Our device to handle
+ */
+static void fec_halt(struct eth_device *dev)
+{
+ struct fec_priv *fec = (struct fec_priv *)dev->priv;
+ int counter = 0xffff;
+
+ /*
+ * issue graceful stop command to the FEC transmitter if necessary
+ */
+ writel(FEC_TCNTRL_GTS | readl(&fec->eth->x_cntrl),
+ &fec->eth->x_cntrl);
+
+ debug("eth_halt: wait for stop regs\n");
+ /*
+ * wait for graceful stop to register
+ */
+ while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA)))
+ udelay(1);
+
+ /*
+ * Disable SmartDMA tasks
+ */
+ fec_tx_task_disable(fec);
+ fec_rx_task_disable(fec);
+
+ /*
+ * Disable the Ethernet Controller
+ * Note: this will also reset the BD index counter!
+ */
+ writel(readl(&fec->eth->ecntrl) & ~FEC_ECNTRL_ETHER_EN,
+ &fec->eth->ecntrl);
+ fec->rbd_index = 0;
+ fec->tbd_index = 0;
+ debug("eth_halt: done\n");
+}
+
+/**
+ * Transmit one frame
+ * @param[in] dev Our ethernet device to handle
+ * @param[in] packet Pointer to the data to be transmitted
+ * @param[in] length Data count in bytes
+ * @return 0 on success
+ */
+static int fec_send(struct eth_device *dev, void *packet, int length)
+{
+ unsigned int status;
+ uint32_t size, end;
+ uint32_t addr;
+ int timeout = FEC_XFER_TIMEOUT;
+ int ret = 0;
+
+ /*
+ * This routine transmits one frame. This routine only accepts
+ * 6-byte Ethernet addresses.
+ */
+ struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+ /*
+ * Check for valid length of data.
+ */
+ if ((length > 1500) || (length <= 0)) {
+ printf("Payload (%d) too large\n", length);
+ return -1;
+ }
+
+ /*
+ * Setup the transmit buffer. We are always using the first buffer for
+ * transmission, the second will be empty and only used to stop the DMA
+ * engine. We also flush the packet to RAM here to avoid cache trouble.
+ */
+#ifdef CONFIG_FEC_MXC_SWAP_PACKET
+ swap_packet((uint32_t *)packet, length);
+#endif
+
+ addr = (uint32_t)packet;
+ end = roundup(addr + length, ARCH_DMA_MINALIGN);
+ addr &= ~(ARCH_DMA_MINALIGN - 1);
+ flush_dcache_range(addr, end);
+
+ writew(length, &fec->tbd_base[fec->tbd_index].data_length);
+ writel(addr, &fec->tbd_base[fec->tbd_index].data_pointer);
+
+ /*
+ * update BD's status now
+ * This block:
+ * - is always the last in a chain (means no chain)
+ * - should transmitt the CRC
+ * - might be the last BD in the list, so the address counter should
+ * wrap (-> keep the WRAP flag)
+ */
+ status = readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_WRAP;
+ status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+ writew(status, &fec->tbd_base[fec->tbd_index].status);
+
+ /*
+ * Flush data cache. This code flushes both TX descriptors to RAM.
+ * After this code, the descriptors will be safely in RAM and we
+ * can start DMA.
+ */
+ size = roundup(2 * sizeof(struct fec_bd), ARCH_DMA_MINALIGN);
+ addr = (uint32_t)fec->tbd_base;
+ flush_dcache_range(addr, addr + size);
+
+ /*
+ * Below we read the DMA descriptor's last four bytes back from the
+ * DRAM. This is important in order to make sure that all WRITE
+ * operations on the bus that were triggered by previous cache FLUSH
+ * have completed.
+ *
+ * Otherwise, on MX28, it is possible to observe a corruption of the
+ * DMA descriptors. Please refer to schematic "Figure 1-2" in MX28RM
+ * for the bus structure of MX28. The scenario is as follows:
+ *
+ * 1) ARM core triggers a series of WRITEs on the AHB_ARB2 bus going
+ * to DRAM due to flush_dcache_range()
+ * 2) ARM core writes the FEC registers via AHB_ARB2
+ * 3) FEC DMA starts reading/writing from/to DRAM via AHB_ARB3
+ *
+ * Note that 2) does sometimes finish before 1) due to reordering of
+ * WRITE accesses on the AHB bus, therefore triggering 3) before the
+ * DMA descriptor is fully written into DRAM. This results in occasional
+ * corruption of the DMA descriptor.
+ */
+ readl(addr + size - 4);
+
+ /*
+ * Enable SmartDMA transmit task
+ */
+ fec_tx_task_enable(fec);
+
+ /*
+ * Wait until frame is sent. On each turn of the wait cycle, we must
+ * invalidate data cache to see what's really in RAM. Also, we need
+ * barrier here.
+ */
+ while (--timeout) {
+ if (!(readl(&fec->eth->x_des_active) & FEC_X_DES_ACTIVE_TDAR))
+ break;
+ }
+
+ if (!timeout)
+ ret = -EINVAL;
+
+ invalidate_dcache_range(addr, addr + size);
+ if (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY)
+ ret = -EINVAL;
+
+ debug("fec_send: status 0x%x index %d ret %i\n",
+ readw(&fec->tbd_base[fec->tbd_index].status),
+ fec->tbd_index, ret);
+ /* for next transmission use the other buffer */
+ if (fec->tbd_index)
+ fec->tbd_index = 0;
+ else
+ fec->tbd_index = 1;
+
+ return ret;
+}
+
+/**
+ * Pull one frame from the card
+ * @param[in] dev Our ethernet device to handle
+ * @return Length of packet read
+ */
+static int fec_recv(struct eth_device *dev)
+{
+ struct fec_priv *fec = (struct fec_priv *)dev->priv;
+ struct fec_bd *rbd = &fec->rbd_base[fec->rbd_index];
+ unsigned long ievent;
+ int frame_length, len = 0;
+ struct nbuf *frame;
+ uint16_t bd_status;
+ uint32_t addr, size, end;
+ int i;
+ ALLOC_CACHE_ALIGN_BUFFER(uchar, buff, FEC_MAX_PKT_SIZE);
+
+ /*
+ * Check if any critical events have happened
+ */
+ ievent = readl(&fec->eth->ievent);
+ writel(ievent, &fec->eth->ievent);
+ debug("fec_recv: ievent 0x%lx\n", ievent);
+ if (ievent & FEC_IEVENT_BABR) {
+ fec_halt(dev);
+ fec_init(dev, fec->bd);
+ printf("some error: 0x%08lx\n", ievent);
+ return 0;
+ }
+ if (ievent & FEC_IEVENT_HBERR) {
+ /* Heartbeat error */
+ writel(0x00000001 | readl(&fec->eth->x_cntrl),
+ &fec->eth->x_cntrl);
+ }
+ if (ievent & FEC_IEVENT_GRA) {
+ /* Graceful stop complete */
+ if (readl(&fec->eth->x_cntrl) & 0x00000001) {
+ fec_halt(dev);
+ writel(~0x00000001 & readl(&fec->eth->x_cntrl),
+ &fec->eth->x_cntrl);
+ fec_init(dev, fec->bd);
+ }
+ }
+
+ /*
+ * Read the buffer status. Before the status can be read, the data cache
+ * must be invalidated, because the data in RAM might have been changed
+ * by DMA. The descriptors are properly aligned to cachelines so there's
+ * no need to worry they'd overlap.
+ *
+ * WARNING: By invalidating the descriptor here, we also invalidate
+ * the descriptors surrounding this one. Therefore we can NOT change the
+ * contents of this descriptor nor the surrounding ones. The problem is
+ * that in order to mark the descriptor as processed, we need to change
+ * the descriptor. The solution is to mark the whole cache line when all
+ * descriptors in the cache line are processed.
+ */
+ addr = (uint32_t)rbd;
+ addr &= ~(ARCH_DMA_MINALIGN - 1);
+ size = roundup(sizeof(struct fec_bd), ARCH_DMA_MINALIGN);
+ invalidate_dcache_range(addr, addr + size);
+
+ bd_status = readw(&rbd->status);
+ debug("fec_recv: status 0x%x\n", bd_status);
+
+ if (!(bd_status & FEC_RBD_EMPTY)) {
+ if ((bd_status & FEC_RBD_LAST) && !(bd_status & FEC_RBD_ERR) &&
+ ((readw(&rbd->data_length) - 4) > 14)) {
+ /*
+ * Get buffer address and size
+ */
+ frame = (struct nbuf *)readl(&rbd->data_pointer);
+ frame_length = readw(&rbd->data_length) - 4;
+ /*
+ * Invalidate data cache over the buffer
+ */
+ addr = (uint32_t)frame;
+ end = roundup(addr + frame_length, ARCH_DMA_MINALIGN);
+ addr &= ~(ARCH_DMA_MINALIGN - 1);
+ invalidate_dcache_range(addr, end);
+
+ /*
+ * Fill the buffer and pass it to upper layers
+ */
+#ifdef CONFIG_FEC_MXC_SWAP_PACKET
+ swap_packet((uint32_t *)frame->data, frame_length);
+#endif
+ memcpy(buff, frame->data, frame_length);
+ NetReceive(buff, frame_length);
+ len = frame_length;
+ } else {
+ if (bd_status & FEC_RBD_ERR)
+ printf("error frame: 0x%08lx 0x%08x\n",
+ (ulong)rbd->data_pointer,
+ bd_status);
+ }
+
+ /*
+ * Free the current buffer, restart the engine and move forward
+ * to the next buffer. Here we check if the whole cacheline of
+ * descriptors was already processed and if so, we mark it free
+ * as whole.
+ */
+ size = RXDESC_PER_CACHELINE - 1;
+ if ((fec->rbd_index & size) == size) {
+ i = fec->rbd_index - size;
+ addr = (uint32_t)&fec->rbd_base[i];
+ for (; i <= fec->rbd_index ; i++) {
+ fec_rbd_clean(i == (FEC_RBD_NUM - 1),
+ &fec->rbd_base[i]);
+ }
+ flush_dcache_range(addr,
+ addr + ARCH_DMA_MINALIGN);
+ }
+
+ fec_rx_task_enable(fec);
+ fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM;
+ }
+ debug("fec_recv: stop\n");
+
+ return len;
+}
+
+static void fec_set_dev_name(char *dest, int dev_id)
+{
+ sprintf(dest, (dev_id == -1) ? "FEC" : "FEC%i", dev_id);
+}
+
+static int fec_alloc_descs(struct fec_priv *fec)
+{
+ unsigned int size;
+ int i;
+ uint8_t *data;
+
+ /* Allocate TX descriptors. */
+ size = roundup(2 * sizeof(struct fec_bd), ARCH_DMA_MINALIGN);
+ fec->tbd_base = memalign(ARCH_DMA_MINALIGN, size);
+ if (!fec->tbd_base)
+ goto err_tx;
+
+ /* Allocate RX descriptors. */
+ size = roundup(FEC_RBD_NUM * sizeof(struct fec_bd), ARCH_DMA_MINALIGN);
+ fec->rbd_base = memalign(ARCH_DMA_MINALIGN, size);
+ if (!fec->rbd_base)
+ goto err_rx;
+
+ memset(fec->rbd_base, 0, size);
+
+ /* Allocate RX buffers. */
+
+ /* Maximum RX buffer size. */
+ size = roundup(FEC_MAX_PKT_SIZE, ARCH_DMA_MINALIGN);
+ for (i = 0; i < FEC_RBD_NUM; i++) {
+ data = memalign(ARCH_DMA_MINALIGN, size);
+ if (!data) {
+ printf("%s: error allocating rxbuf %d\n", __func__, i);
+ goto err_ring;
+ }
+
+ memset(data, 0, size);
+
+ fec->rbd_base[i].data_pointer = (uint32_t)data;
+ fec->rbd_base[i].status = FEC_RBD_EMPTY;
+ fec->rbd_base[i].data_length = 0;
+ /* Flush the buffer to memory. */
+ flush_dcache_range((uint32_t)data, (uint32_t)data + size);
+ }
+
+ /* Mark the last RBD to close the ring. */
+ fec->rbd_base[i - 1].status = FEC_RBD_WRAP | FEC_RBD_EMPTY;
+
+ fec->rbd_index = 0;
+ fec->tbd_index = 0;
+
+ return 0;
+
+err_ring:
+ for (; i >= 0; i--)
+ free((void *)fec->rbd_base[i].data_pointer);
+ free(fec->rbd_base);
+err_rx:
+ free(fec->tbd_base);
+err_tx:
+ return -ENOMEM;
+}
+
+static void fec_free_descs(struct fec_priv *fec)
+{
+ int i;
+
+ for (i = 0; i < FEC_RBD_NUM; i++)
+ free((void *)fec->rbd_base[i].data_pointer);
+ free(fec->rbd_base);
+ free(fec->tbd_base);
+}
+
+#ifdef CONFIG_PHYLIB
+int fec_probe(bd_t *bd, int dev_id, uint32_t base_addr,
+ struct mii_dev *bus, struct phy_device *phydev)
+#else
+static int fec_probe(bd_t *bd, int dev_id, uint32_t base_addr,
+ struct mii_dev *bus, int phy_id)
+#endif
+{
+ struct eth_device *edev;
+ struct fec_priv *fec;
+ unsigned char ethaddr[6];
+ uint32_t start;
+ int ret = 0;
+
+ /* create and fill edev struct */
+ edev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ if (!edev) {
+ puts("fec_mxc: not enough malloc memory for eth_device\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ fec = (struct fec_priv *)malloc(sizeof(struct fec_priv));
+ if (!fec) {
+ puts("fec_mxc: not enough malloc memory for fec_priv\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ memset(edev, 0, sizeof(*edev));
+ memset(fec, 0, sizeof(*fec));
+
+ ret = fec_alloc_descs(fec);
+ if (ret)
+ goto err3;
+
+ edev->priv = fec;
+ edev->init = fec_init;
+ edev->send = fec_send;
+ edev->recv = fec_recv;
+ edev->halt = fec_halt;
+ edev->write_hwaddr = fec_set_hwaddr;
+
+ fec->eth = (struct ethernet_regs *)base_addr;
+ fec->bd = bd;
+
+ fec->xcv_type = CONFIG_FEC_XCV_TYPE;
+
+ /* Reset chip. */
+ writel(readl(&fec->eth->ecntrl) | FEC_ECNTRL_RESET, &fec->eth->ecntrl);
+ start = get_timer(0);
+ while (readl(&fec->eth->ecntrl) & FEC_ECNTRL_RESET) {
+ if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
+ printf("FEC MXC: Timeout reseting chip\n");
+ goto err4;
+ }
+ udelay(10);
+ }
+
+ fec_reg_setup(fec);
+ fec_set_dev_name(edev->name, dev_id);
+ fec->dev_id = (dev_id == -1) ? 0 : dev_id;
+ fec->bus = bus;
+ fec_mii_setspeed(bus->priv);
+#ifdef CONFIG_PHYLIB
+ fec->phydev = phydev;
+ phy_connect_dev(phydev, edev);
+ /* Configure phy */
+ phy_config(phydev);
+#else
+ fec->phy_id = phy_id;
+#endif
+ eth_register(edev);
+
+ if (fec_get_hwaddr(edev, dev_id, ethaddr) == 0) {
+ debug("got MAC%d address from fuse: %pM\n", dev_id, ethaddr);
+ memcpy(edev->enetaddr, ethaddr, 6);
+ if (!getenv("ethaddr"))
+ eth_setenv_enetaddr("ethaddr", ethaddr);
+ }
+ return ret;
+err4:
+ fec_free_descs(fec);
+err3:
+ free(fec);
+err2:
+ free(edev);
+err1:
+ return ret;
+}
+
+struct mii_dev *fec_get_miibus(uint32_t base_addr, int dev_id)
+{
+ struct ethernet_regs *eth = (struct ethernet_regs *)base_addr;
+ struct mii_dev *bus;
+ int ret;
+
+ bus = mdio_alloc();
+ if (!bus) {
+ printf("mdio_alloc failed\n");
+ return NULL;
+ }
+ bus->read = fec_phy_read;
+ bus->write = fec_phy_write;
+ bus->priv = eth;
+ fec_set_dev_name(bus->name, dev_id);
+
+ ret = mdio_register(bus);
+ if (ret) {
+ printf("mdio_register failed\n");
+ free(bus);
+ return NULL;
+ }
+ fec_mii_setspeed(eth);
+ return bus;
+}
+
+int fecmxc_initialize_multi(bd_t *bd, int dev_id, int phy_id, uint32_t addr)
+{
+ uint32_t base_mii;
+ struct mii_dev *bus = NULL;
+#ifdef CONFIG_PHYLIB
+ struct phy_device *phydev = NULL;
+#endif
+ int ret;
+
+#ifdef CONFIG_MX28
+ /*
+ * The i.MX28 has two ethernet interfaces, but they are not equal.
+ * Only the first one can access the MDIO bus.
+ */
+ base_mii = MXS_ENET0_BASE;
+#else
+ base_mii = addr;
+#endif
+ debug("eth_init: fec_probe(bd, %i, %i) @ %08x\n", dev_id, phy_id, addr);
+ bus = fec_get_miibus(base_mii, dev_id);
+ if (!bus)
+ return -ENOMEM;
+#ifdef CONFIG_PHYLIB
+ phydev = phy_find_by_mask(bus, 1 << phy_id, PHY_INTERFACE_MODE_RGMII);
+ if (!phydev) {
+ free(bus);
+ return -ENOMEM;
+ }
+ ret = fec_probe(bd, dev_id, addr, bus, phydev);
+#else
+ ret = fec_probe(bd, dev_id, addr, bus, phy_id);
+#endif
+ if (ret) {
+#ifdef CONFIG_PHYLIB
+ free(phydev);
+#endif
+ free(bus);
+ }
+ return ret;
+}
+
+#ifdef CONFIG_FEC_MXC_PHYADDR
+int fecmxc_initialize(bd_t *bd)
+{
+ return fecmxc_initialize_multi(bd, -1, CONFIG_FEC_MXC_PHYADDR,
+ IMX_FEC_BASE);
+}
+#endif
+
+#ifndef CONFIG_PHYLIB
+int fecmxc_register_mii_postcall(struct eth_device *dev, int (*cb)(int))
+{
+ struct fec_priv *fec = (struct fec_priv *)dev->priv;
+ fec->mii_postcall = cb;
+ return 0;
+}
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/fec_mxc.h b/qemu/roms/u-boot/drivers/net/fec_mxc.h
new file mode 100644
index 000000000..0717cc6c3
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fec_mxc.h
@@ -0,0 +1,323 @@
+/*
+ * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
+ * (C) Copyright 2008 Armadeus Systems, nc
+ * (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
+ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.h
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+
+#ifndef __FEC_MXC_H
+#define __FEC_MXC_H
+
+void imx_get_mac_from_fuse(int dev_id, unsigned char *mac);
+
+/**
+ * Layout description of the FEC
+ */
+struct ethernet_regs {
+
+/* [10:2]addr = 00 */
+
+/* Control and status Registers (offset 000-1FF) */
+
+ uint32_t res0[1]; /* MBAR_ETH + 0x000 */
+ uint32_t ievent; /* MBAR_ETH + 0x004 */
+ uint32_t imask; /* MBAR_ETH + 0x008 */
+
+ uint32_t res1[1]; /* MBAR_ETH + 0x00C */
+ uint32_t r_des_active; /* MBAR_ETH + 0x010 */
+ uint32_t x_des_active; /* MBAR_ETH + 0x014 */
+ uint32_t res2[3]; /* MBAR_ETH + 0x018-20 */
+ uint32_t ecntrl; /* MBAR_ETH + 0x024 */
+
+ uint32_t res3[6]; /* MBAR_ETH + 0x028-03C */
+ uint32_t mii_data; /* MBAR_ETH + 0x040 */
+ uint32_t mii_speed; /* MBAR_ETH + 0x044 */
+ uint32_t res4[7]; /* MBAR_ETH + 0x048-60 */
+ uint32_t mib_control; /* MBAR_ETH + 0x064 */
+
+ uint32_t res5[7]; /* MBAR_ETH + 0x068-80 */
+ uint32_t r_cntrl; /* MBAR_ETH + 0x084 */
+ uint32_t res6[15]; /* MBAR_ETH + 0x088-C0 */
+ uint32_t x_cntrl; /* MBAR_ETH + 0x0C4 */
+ uint32_t res7[7]; /* MBAR_ETH + 0x0C8-E0 */
+ uint32_t paddr1; /* MBAR_ETH + 0x0E4 */
+ uint32_t paddr2; /* MBAR_ETH + 0x0E8 */
+ uint32_t op_pause; /* MBAR_ETH + 0x0EC */
+
+ uint32_t res8[10]; /* MBAR_ETH + 0x0F0-114 */
+ uint32_t iaddr1; /* MBAR_ETH + 0x118 */
+ uint32_t iaddr2; /* MBAR_ETH + 0x11C */
+ uint32_t gaddr1; /* MBAR_ETH + 0x120 */
+ uint32_t gaddr2; /* MBAR_ETH + 0x124 */
+ uint32_t res9[7]; /* MBAR_ETH + 0x128-140 */
+
+ uint32_t x_wmrk; /* MBAR_ETH + 0x144 */
+ uint32_t res10[1]; /* MBAR_ETH + 0x148 */
+ uint32_t r_bound; /* MBAR_ETH + 0x14C */
+ uint32_t r_fstart; /* MBAR_ETH + 0x150 */
+ uint32_t res11[11]; /* MBAR_ETH + 0x154-17C */
+ uint32_t erdsr; /* MBAR_ETH + 0x180 */
+ uint32_t etdsr; /* MBAR_ETH + 0x184 */
+ uint32_t emrbr; /* MBAR_ETH + 0x188 */
+ uint32_t res12[29]; /* MBAR_ETH + 0x18C-1FC */
+
+/* MIB COUNTERS (Offset 200-2FF) */
+
+ uint32_t rmon_t_drop; /* MBAR_ETH + 0x200 */
+ uint32_t rmon_t_packets; /* MBAR_ETH + 0x204 */
+ uint32_t rmon_t_bc_pkt; /* MBAR_ETH + 0x208 */
+ uint32_t rmon_t_mc_pkt; /* MBAR_ETH + 0x20C */
+ uint32_t rmon_t_crc_align; /* MBAR_ETH + 0x210 */
+ uint32_t rmon_t_undersize; /* MBAR_ETH + 0x214 */
+ uint32_t rmon_t_oversize; /* MBAR_ETH + 0x218 */
+ uint32_t rmon_t_frag; /* MBAR_ETH + 0x21C */
+ uint32_t rmon_t_jab; /* MBAR_ETH + 0x220 */
+ uint32_t rmon_t_col; /* MBAR_ETH + 0x224 */
+ uint32_t rmon_t_p64; /* MBAR_ETH + 0x228 */
+ uint32_t rmon_t_p65to127; /* MBAR_ETH + 0x22C */
+ uint32_t rmon_t_p128to255; /* MBAR_ETH + 0x230 */
+ uint32_t rmon_t_p256to511; /* MBAR_ETH + 0x234 */
+ uint32_t rmon_t_p512to1023; /* MBAR_ETH + 0x238 */
+ uint32_t rmon_t_p1024to2047; /* MBAR_ETH + 0x23C */
+ uint32_t rmon_t_p_gte2048; /* MBAR_ETH + 0x240 */
+ uint32_t rmon_t_octets; /* MBAR_ETH + 0x244 */
+ uint32_t ieee_t_drop; /* MBAR_ETH + 0x248 */
+ uint32_t ieee_t_frame_ok; /* MBAR_ETH + 0x24C */
+ uint32_t ieee_t_1col; /* MBAR_ETH + 0x250 */
+ uint32_t ieee_t_mcol; /* MBAR_ETH + 0x254 */
+ uint32_t ieee_t_def; /* MBAR_ETH + 0x258 */
+ uint32_t ieee_t_lcol; /* MBAR_ETH + 0x25C */
+ uint32_t ieee_t_excol; /* MBAR_ETH + 0x260 */
+ uint32_t ieee_t_macerr; /* MBAR_ETH + 0x264 */
+ uint32_t ieee_t_cserr; /* MBAR_ETH + 0x268 */
+ uint32_t ieee_t_sqe; /* MBAR_ETH + 0x26C */
+ uint32_t t_fdxfc; /* MBAR_ETH + 0x270 */
+ uint32_t ieee_t_octets_ok; /* MBAR_ETH + 0x274 */
+
+ uint32_t res13[2]; /* MBAR_ETH + 0x278-27C */
+ uint32_t rmon_r_drop; /* MBAR_ETH + 0x280 */
+ uint32_t rmon_r_packets; /* MBAR_ETH + 0x284 */
+ uint32_t rmon_r_bc_pkt; /* MBAR_ETH + 0x288 */
+ uint32_t rmon_r_mc_pkt; /* MBAR_ETH + 0x28C */
+ uint32_t rmon_r_crc_align; /* MBAR_ETH + 0x290 */
+ uint32_t rmon_r_undersize; /* MBAR_ETH + 0x294 */
+ uint32_t rmon_r_oversize; /* MBAR_ETH + 0x298 */
+ uint32_t rmon_r_frag; /* MBAR_ETH + 0x29C */
+ uint32_t rmon_r_jab; /* MBAR_ETH + 0x2A0 */
+
+ uint32_t rmon_r_resvd_0; /* MBAR_ETH + 0x2A4 */
+
+ uint32_t rmon_r_p64; /* MBAR_ETH + 0x2A8 */
+ uint32_t rmon_r_p65to127; /* MBAR_ETH + 0x2AC */
+ uint32_t rmon_r_p128to255; /* MBAR_ETH + 0x2B0 */
+ uint32_t rmon_r_p256to511; /* MBAR_ETH + 0x2B4 */
+ uint32_t rmon_r_p512to1023; /* MBAR_ETH + 0x2B8 */
+ uint32_t rmon_r_p1024to2047; /* MBAR_ETH + 0x2BC */
+ uint32_t rmon_r_p_gte2048; /* MBAR_ETH + 0x2C0 */
+ uint32_t rmon_r_octets; /* MBAR_ETH + 0x2C4 */
+ uint32_t ieee_r_drop; /* MBAR_ETH + 0x2C8 */
+ uint32_t ieee_r_frame_ok; /* MBAR_ETH + 0x2CC */
+ uint32_t ieee_r_crc; /* MBAR_ETH + 0x2D0 */
+ uint32_t ieee_r_align; /* MBAR_ETH + 0x2D4 */
+ uint32_t r_macerr; /* MBAR_ETH + 0x2D8 */
+ uint32_t r_fdxfc; /* MBAR_ETH + 0x2DC */
+ uint32_t ieee_r_octets_ok; /* MBAR_ETH + 0x2E0 */
+
+ uint32_t res14[7]; /* MBAR_ETH + 0x2E4-2FC */
+
+#if defined(CONFIG_MX25) || defined(CONFIG_MX53) || defined(CONFIG_MX6SL)
+ uint16_t miigsk_cfgr; /* MBAR_ETH + 0x300 */
+ uint16_t res15[3]; /* MBAR_ETH + 0x302-306 */
+ uint16_t miigsk_enr; /* MBAR_ETH + 0x308 */
+ uint16_t res16[3]; /* MBAR_ETH + 0x30a-30e */
+ uint32_t res17[60]; /* MBAR_ETH + 0x300-3FF */
+#else
+ uint32_t res15[64]; /* MBAR_ETH + 0x300-3FF */
+#endif
+};
+
+#define FEC_IEVENT_HBERR 0x80000000
+#define FEC_IEVENT_BABR 0x40000000
+#define FEC_IEVENT_BABT 0x20000000
+#define FEC_IEVENT_GRA 0x10000000
+#define FEC_IEVENT_TXF 0x08000000
+#define FEC_IEVENT_TXB 0x04000000
+#define FEC_IEVENT_RXF 0x02000000
+#define FEC_IEVENT_RXB 0x01000000
+#define FEC_IEVENT_MII 0x00800000
+#define FEC_IEVENT_EBERR 0x00400000
+#define FEC_IEVENT_LC 0x00200000
+#define FEC_IEVENT_RL 0x00100000
+#define FEC_IEVENT_UN 0x00080000
+
+#define FEC_IMASK_HBERR 0x80000000
+#define FEC_IMASK_BABR 0x40000000
+#define FEC_IMASKT_BABT 0x20000000
+#define FEC_IMASK_GRA 0x10000000
+#define FEC_IMASKT_TXF 0x08000000
+#define FEC_IMASK_TXB 0x04000000
+#define FEC_IMASKT_RXF 0x02000000
+#define FEC_IMASK_RXB 0x01000000
+#define FEC_IMASK_MII 0x00800000
+#define FEC_IMASK_EBERR 0x00400000
+#define FEC_IMASK_LC 0x00200000
+#define FEC_IMASKT_RL 0x00100000
+#define FEC_IMASK_UN 0x00080000
+
+
+#define FEC_RCNTRL_MAX_FL_SHIFT 16
+#define FEC_RCNTRL_LOOP 0x00000001
+#define FEC_RCNTRL_DRT 0x00000002
+#define FEC_RCNTRL_MII_MODE 0x00000004
+#define FEC_RCNTRL_PROM 0x00000008
+#define FEC_RCNTRL_BC_REJ 0x00000010
+#define FEC_RCNTRL_FCE 0x00000020
+#define FEC_RCNTRL_RGMII 0x00000040
+#define FEC_RCNTRL_RMII 0x00000100
+#define FEC_RCNTRL_RMII_10T 0x00000200
+
+#define FEC_TCNTRL_GTS 0x00000001
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_TFC_PAUSE 0x00000008
+#define FEC_TCNTRL_RFC_PAUSE 0x00000010
+
+#define FEC_ECNTRL_RESET 0x00000001 /* reset the FEC */
+#define FEC_ECNTRL_ETHER_EN 0x00000002 /* enable the FEC */
+#define FEC_ECNTRL_SPEED 0x00000020
+#define FEC_ECNTRL_DBSWAP 0x00000100
+
+#define FEC_X_WMRK_STRFWD 0x00000100
+
+#define FEC_X_DES_ACTIVE_TDAR 0x01000000
+#define FEC_R_DES_ACTIVE_RDAR 0x01000000
+
+#if defined(CONFIG_MX25) || defined(CONFIG_MX53) || defined(CONFIG_MX6SL)
+/* defines for MIIGSK */
+/* RMII frequency control: 0=50MHz, 1=5MHz */
+#define MIIGSK_CFGR_FRCONT (1 << 6)
+/* loopback mode */
+#define MIIGSK_CFGR_LBMODE (1 << 4)
+/* echo mode */
+#define MIIGSK_CFGR_EMODE (1 << 3)
+/* MII gasket mode field */
+#define MIIGSK_CFGR_IF_MODE_MASK (3 << 0)
+/* MMI/7-Wire mode */
+#define MIIGSK_CFGR_IF_MODE_MII (0 << 0)
+/* RMII mode */
+#define MIIGSK_CFGR_IF_MODE_RMII (1 << 0)
+/* reflects MIIGSK Enable bit (RO) */
+#define MIIGSK_ENR_READY (1 << 2)
+/* enable MIGSK (set by default) */
+#define MIIGSK_ENR_EN (1 << 1)
+#endif
+
+/**
+ * @brief Receive & Transmit Buffer Descriptor definitions
+ *
+ * Note: The first BD must be aligned (see DB_ALIGNMENT)
+ */
+struct fec_bd {
+ uint16_t data_length; /* payload's length in bytes */
+ uint16_t status; /* BD's staus (see datasheet) */
+ uint32_t data_pointer; /* payload's buffer address */
+};
+
+/**
+ * Supported phy types on this platform
+ */
+enum xceiver_type {
+ SEVENWIRE, /* 7-wire */
+ MII10, /* MII 10Mbps */
+ MII100, /* MII 100Mbps */
+ RMII, /* RMII */
+ RGMII, /* RGMII */
+};
+
+/**
+ * @brief i.MX27-FEC private structure
+ */
+struct fec_priv {
+ struct ethernet_regs *eth; /* pointer to register'S base */
+ enum xceiver_type xcv_type; /* transceiver type */
+ struct fec_bd *rbd_base; /* RBD ring */
+ int rbd_index; /* next receive BD to read */
+ struct fec_bd *tbd_base; /* TBD ring */
+ int tbd_index; /* next transmit BD to write */
+ bd_t *bd;
+ uint8_t *tdb_ptr;
+ int dev_id;
+ struct mii_dev *bus;
+#ifdef CONFIG_PHYLIB
+ struct phy_device *phydev;
+#else
+ int phy_id;
+ int (*mii_postcall)(int);
+#endif
+};
+
+/**
+ * @brief Numbers of buffer descriptors for receiving
+ *
+ * The number defines the stocked memory buffers for the receiving task.
+ * Larger values makes no sense in this limited environment.
+ */
+#define FEC_RBD_NUM 64
+
+/**
+ * @brief Define the ethernet packet size limit in memory
+ *
+ * Note: Do not shrink this number. This will force the FEC to spread larger
+ * frames in more than one BD. This is nothing to worry about, but the current
+ * driver can't handle it.
+ */
+#define FEC_MAX_PKT_SIZE 1536
+
+/* Receive BD status bits */
+#define FEC_RBD_EMPTY 0x8000 /* Receive BD status: Buffer is empty */
+#define FEC_RBD_WRAP 0x2000 /* Receive BD status: Last BD in ring */
+/* Receive BD status: Buffer is last in frame (useless here!) */
+#define FEC_RBD_LAST 0x0800
+#define FEC_RBD_MISS 0x0100 /* Receive BD status: Miss bit for prom mode */
+/* Receive BD status: The received frame is broadcast frame */
+#define FEC_RBD_BC 0x0080
+/* Receive BD status: The received frame is multicast frame */
+#define FEC_RBD_MC 0x0040
+#define FEC_RBD_LG 0x0020 /* Receive BD status: Frame length violation */
+#define FEC_RBD_NO 0x0010 /* Receive BD status: Nonoctet align frame */
+#define FEC_RBD_CR 0x0004 /* Receive BD status: CRC error */
+#define FEC_RBD_OV 0x0002 /* Receive BD status: Receive FIFO overrun */
+#define FEC_RBD_TR 0x0001 /* Receive BD status: Frame is truncated */
+#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+ FEC_RBD_OV | FEC_RBD_TR)
+
+/* Transmit BD status bits */
+#define FEC_TBD_READY 0x8000 /* Tansmit BD status: Buffer is ready */
+#define FEC_TBD_WRAP 0x2000 /* Tansmit BD status: Mark as last BD in ring */
+#define FEC_TBD_LAST 0x0800 /* Tansmit BD status: Buffer is last in frame */
+#define FEC_TBD_TC 0x0400 /* Tansmit BD status: Transmit the CRC */
+#define FEC_TBD_ABC 0x0200 /* Tansmit BD status: Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST 0x40000000 /* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform a read operation */
+#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register field mask */
+#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
+#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */
+
+#endif /* __FEC_MXC_H */
diff --git a/qemu/roms/u-boot/drivers/net/fm/Makefile b/qemu/roms/u-boot/drivers/net/fm/Makefile
new file mode 100644
index 000000000..5ae3b167a
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright 2009-2011 Freescale Semiconductor, Inc.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += dtsec.o
+obj-y += eth.o
+obj-y += fm.o
+obj-y += init.o
+obj-y += tgec.o
+obj-y += tgec_phy.o
+
+# Soc have FMAN v3 with mEMAC
+obj-$(CONFIG_SYS_FMAN_V3) += memac_phy.o
+obj-$(CONFIG_SYS_FMAN_V3) += memac.o
+
+# SoC specific SERDES support
+obj-$(CONFIG_P1017) += p1023.o
+obj-$(CONFIG_P1023) += p1023.o
+# The P204x, P304x, and P5020 are the same
+obj-$(CONFIG_PPC_P2041) += p5020.o
+obj-$(CONFIG_PPC_P3041) += p5020.o
+obj-$(CONFIG_PPC_P4080) += p4080.o
+obj-$(CONFIG_PPC_P5020) += p5020.o
+obj-$(CONFIG_PPC_P5040) += p5040.o
+obj-$(CONFIG_PPC_T1040) += t1040.o
+obj-$(CONFIG_PPC_T1042) += t1040.o
+obj-$(CONFIG_PPC_T1020) += t1040.o
+obj-$(CONFIG_PPC_T1022) += t1040.o
+obj-$(CONFIG_PPC_T2080) += t2080.o
+obj-$(CONFIG_PPC_T2081) += t2080.o
+obj-$(CONFIG_PPC_T4240) += t4240.o
+obj-$(CONFIG_PPC_T4160) += t4240.o
+obj-$(CONFIG_PPC_T4080) += t4240.o
+obj-$(CONFIG_PPC_B4420) += b4860.o
+obj-$(CONFIG_PPC_B4860) += b4860.o
diff --git a/qemu/roms/u-boot/drivers/net/fm/b4860.c b/qemu/roms/u-boot/drivers/net/fm/b4860.c
new file mode 100644
index 000000000..373cc4f42
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/b4860.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Roy Zang <tie-fei.zang@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
+ [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
+ [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
+ [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
+ [FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
+ [FM1_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC1_6,
+ [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1,
+ [FM1_10GEC2] = FSL_CORENET_DEVDISR2_10GEC1_2,
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr2 = in_be32(&gur->devdisr2);
+
+ return port_to_devdisr[port] & devdisr2;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+void fman_enable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ /*B4860 has two 10Gig Mac*/
+ if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
+ ((is_serdes_configured(XAUI_FM1_MAC9)) ||
+ (is_serdes_configured(XAUI_FM1_MAC10))))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ /* Fix me need to handle RGMII here first */
+
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ case FM1_DTSEC5:
+ case FM1_DTSEC6:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ default:
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/dtsec.c b/qemu/roms/u-boot/drivers/net/fm/dtsec.c
new file mode 100644
index 000000000..78bbd439f
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/dtsec.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <asm/fsl_enet.h>
+#include <asm/fsl_dtsec.h>
+#include <fsl_mdio.h>
+#include <phy.h>
+
+#include "fm.h"
+
+#define RCTRL_INIT (RCTRL_GRS | RCTRL_UPROM)
+#define TCTRL_INIT TCTRL_GTS
+#define MACCFG1_INIT MACCFG1_SOFT_RST
+
+#define MACCFG2_INIT (MACCFG2_PRE_LEN(0x7) | MACCFG2_LEN_CHECK | \
+ MACCFG2_PAD_CRC | MACCFG2_FULL_DUPLEX | \
+ MACCFG2_IF_MODE_NIBBLE)
+
+/* MAXFRM - maximum frame length register */
+#define MAXFRM_MASK 0x00003fff
+
+static void dtsec_init_mac(struct fsl_enet_mac *mac)
+{
+ struct dtsec *regs = mac->base;
+
+ /* soft reset */
+ out_be32(&regs->maccfg1, MACCFG1_SOFT_RST);
+ udelay(1000);
+
+ /* clear soft reset, Rx/Tx MAC disable */
+ out_be32(&regs->maccfg1, 0);
+
+ /* graceful stop rx */
+ out_be32(&regs->rctrl, RCTRL_INIT);
+ udelay(1000);
+
+ /* graceful stop tx */
+ out_be32(&regs->tctrl, TCTRL_INIT);
+ udelay(1000);
+
+ /* disable all interrupts */
+ out_be32(&regs->imask, IMASK_MASK_ALL);
+
+ /* clear all events */
+ out_be32(&regs->ievent, IEVENT_CLEAR_ALL);
+
+ /* set the max Rx length */
+ out_be32(&regs->maxfrm, mac->max_rx_len & MAXFRM_MASK);
+
+ /* set the ecntrl to reset value */
+ out_be32(&regs->ecntrl, ECNTRL_DEFAULT);
+
+ /*
+ * Rx length check, no strip CRC for Rx, pad and append CRC for Tx,
+ * full duplex
+ */
+ out_be32(&regs->maccfg2, MACCFG2_INIT);
+}
+
+static void dtsec_enable_mac(struct fsl_enet_mac *mac)
+{
+ struct dtsec *regs = mac->base;
+
+ /* enable Rx/Tx MAC */
+ setbits_be32(&regs->maccfg1, MACCFG1_RXTX_EN);
+
+ /* clear the graceful Rx stop */
+ clrbits_be32(&regs->rctrl, RCTRL_GRS);
+
+ /* clear the graceful Tx stop */
+ clrbits_be32(&regs->tctrl, TCTRL_GTS);
+}
+
+static void dtsec_disable_mac(struct fsl_enet_mac *mac)
+{
+ struct dtsec *regs = mac->base;
+
+ /* graceful Rx stop */
+ setbits_be32(&regs->rctrl, RCTRL_GRS);
+
+ /* graceful Tx stop */
+ setbits_be32(&regs->tctrl, TCTRL_GTS);
+
+ /* disable Rx/Tx MAC */
+ clrbits_be32(&regs->maccfg1, MACCFG1_RXTX_EN);
+}
+
+static void dtsec_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr)
+{
+ struct dtsec *regs = mac->base;
+ u32 mac_addr1, mac_addr2;
+
+ /*
+ * if a station address of 0x12345678ABCD, perform a write to
+ * MACSTNADDR1 of 0xCDAB7856, MACSTNADDR2 of 0x34120000
+ */
+ mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) | \
+ (mac_addr[3] << 8) | (mac_addr[2]);
+ out_be32(&regs->macstnaddr1, mac_addr1);
+
+ mac_addr2 = ((mac_addr[1] << 24) | (mac_addr[0] << 16)) & 0xffff0000;
+ out_be32(&regs->macstnaddr2, mac_addr2);
+}
+
+static void dtsec_set_interface_mode(struct fsl_enet_mac *mac,
+ phy_interface_t type, int speed)
+{
+ struct dtsec *regs = mac->base;
+ u32 ecntrl, maccfg2;
+
+ /* clear all bits relative with interface mode */
+ ecntrl = in_be32(&regs->ecntrl);
+ ecntrl &= ~(ECNTRL_TBIM | ECNTRL_GMIIM | ECNTRL_RPM |
+ ECNTRL_R100M | ECNTRL_SGMIIM);
+
+ maccfg2 = in_be32(&regs->maccfg2);
+ maccfg2 &= ~MACCFG2_IF_MODE_MASK;
+
+ if (speed == SPEED_1000)
+ maccfg2 |= MACCFG2_IF_MODE_BYTE;
+ else
+ maccfg2 |= MACCFG2_IF_MODE_NIBBLE;
+
+ /* set interface mode */
+ switch (type) {
+ case PHY_INTERFACE_MODE_GMII:
+ ecntrl |= ECNTRL_GMIIM;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ ecntrl |= (ECNTRL_GMIIM | ECNTRL_RPM);
+ if (speed == SPEED_100)
+ ecntrl |= ECNTRL_R100M;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if (speed == SPEED_100)
+ ecntrl |= ECNTRL_R100M;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ ecntrl |= (ECNTRL_SGMIIM | ECNTRL_TBIM);
+ if (speed == SPEED_100)
+ ecntrl |= ECNTRL_R100M;
+ break;
+ default:
+ break;
+ }
+
+ out_be32(&regs->ecntrl, ecntrl);
+ out_be32(&regs->maccfg2, maccfg2);
+}
+
+void init_dtsec(struct fsl_enet_mac *mac, void *base,
+ void *phyregs, int max_rx_len)
+{
+ mac->base = base;
+ mac->phyregs = phyregs;
+ mac->max_rx_len = max_rx_len;
+ mac->init_mac = dtsec_init_mac;
+ mac->enable_mac = dtsec_enable_mac;
+ mac->disable_mac = dtsec_disable_mac;
+ mac->set_mac_addr = dtsec_set_mac_addr;
+ mac->set_if_mode = dtsec_set_interface_mode;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/eth.c b/qemu/roms/u-boot/drivers/net/fm/eth.c
new file mode 100644
index 000000000..218a5ed17
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/eth.c
@@ -0,0 +1,712 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <net.h>
+#include <hwconfig.h>
+#include <fm_eth.h>
+#include <fsl_mdio.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <asm/fsl_dtsec.h>
+#include <asm/fsl_tgec.h>
+#include <asm/fsl_memac.h>
+
+#include "fm.h"
+
+static struct eth_device *devlist[NUM_FM_PORTS];
+static int num_controllers;
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII)
+
+#define TBIANA_SETTINGS (TBIANA_ASYMMETRIC_PAUSE | TBIANA_SYMMETRIC_PAUSE | \
+ TBIANA_FULL_DUPLEX)
+
+#define TBIANA_SGMII_ACK 0x4001
+
+#define TBICR_SETTINGS (TBICR_ANEG_ENABLE | TBICR_RESTART_ANEG | \
+ TBICR_FULL_DUPLEX | TBICR_SPEED1_SET)
+
+/* Configure the TBI for SGMII operation */
+static void dtsec_configure_serdes(struct fm_eth *priv)
+{
+#ifdef CONFIG_SYS_FMAN_V3
+ u32 value;
+ struct mii_dev bus;
+ bus.priv = priv->mac->phyregs;
+
+ /* SGMII IF mode + AN enable */
+ value = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII;
+ memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x14, value);
+
+ /* Dev ability according to SGMII specification */
+ value = PHY_SGMII_DEV_ABILITY_SGMII;
+ memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x4, value);
+
+ /* Adjust link timer for SGMII -
+ 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40 */
+ memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x3);
+ memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0xd40);
+
+ /* Restart AN */
+ value = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0, value);
+#else
+ struct dtsec *regs = priv->mac->base;
+ struct tsec_mii_mng *phyregs = priv->mac->phyregs;
+
+ /*
+ * Access TBI PHY registers at given TSEC register offset as
+ * opposed to the register offset used for external PHY accesses
+ */
+ tsec_local_mdio_write(phyregs, in_be32(&regs->tbipa), 0, TBI_TBICON,
+ TBICON_CLK_SELECT);
+ tsec_local_mdio_write(phyregs, in_be32(&regs->tbipa), 0, TBI_ANA,
+ TBIANA_SGMII_ACK);
+ tsec_local_mdio_write(phyregs, in_be32(&regs->tbipa), 0,
+ TBI_CR, TBICR_SETTINGS);
+#endif
+}
+
+static void dtsec_init_phy(struct eth_device *dev)
+{
+ struct fm_eth *fm_eth = dev->priv;
+#ifndef CONFIG_SYS_FMAN_V3
+ struct dtsec *regs = (struct dtsec *)CONFIG_SYS_FSL_FM1_DTSEC1_ADDR;
+
+ /* Assign a Physical address to the TBI */
+ out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
+#endif
+
+ if (fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII)
+ dtsec_configure_serdes(fm_eth);
+}
+
+static int tgec_is_fibre(struct eth_device *dev)
+{
+ struct fm_eth *fm = dev->priv;
+ char phyopt[20];
+
+ sprintf(phyopt, "fsl_fm%d_xaui_phy", fm->fm_index + 1);
+
+ return hwconfig_arg_cmp(phyopt, "xfi");
+}
+#endif
+
+static u16 muram_readw(u16 *addr)
+{
+ u32 base = (u32)addr & ~0x3;
+ u32 val32 = *(u32 *)base;
+ int byte_pos;
+ u16 ret;
+
+ byte_pos = (u32)addr & 0x3;
+ if (byte_pos)
+ ret = (u16)(val32 & 0x0000ffff);
+ else
+ ret = (u16)((val32 & 0xffff0000) >> 16);
+
+ return ret;
+}
+
+static void muram_writew(u16 *addr, u16 val)
+{
+ u32 base = (u32)addr & ~0x3;
+ u32 org32 = *(u32 *)base;
+ u32 val32;
+ int byte_pos;
+
+ byte_pos = (u32)addr & 0x3;
+ if (byte_pos)
+ val32 = (org32 & 0xffff0000) | val;
+ else
+ val32 = (org32 & 0x0000ffff) | ((u32)val << 16);
+
+ *(u32 *)base = val32;
+}
+
+static void bmi_rx_port_disable(struct fm_bmi_rx_port *rx_port)
+{
+ int timeout = 1000000;
+
+ clrbits_be32(&rx_port->fmbm_rcfg, FMBM_RCFG_EN);
+
+ /* wait until the rx port is not busy */
+ while ((in_be32(&rx_port->fmbm_rst) & FMBM_RST_BSY) && timeout--)
+ ;
+}
+
+static void bmi_rx_port_init(struct fm_bmi_rx_port *rx_port)
+{
+ /* set BMI to independent mode, Rx port disable */
+ out_be32(&rx_port->fmbm_rcfg, FMBM_RCFG_IM);
+ /* clear FOF in IM case */
+ out_be32(&rx_port->fmbm_rim, 0);
+ /* Rx frame next engine -RISC */
+ out_be32(&rx_port->fmbm_rfne, NIA_ENG_RISC | NIA_RISC_AC_IM_RX);
+ /* Rx command attribute - no order, MR[3] = 1 */
+ clrbits_be32(&rx_port->fmbm_rfca, FMBM_RFCA_ORDER | FMBM_RFCA_MR_MASK);
+ setbits_be32(&rx_port->fmbm_rfca, FMBM_RFCA_MR(4));
+ /* enable Rx statistic counters */
+ out_be32(&rx_port->fmbm_rstc, FMBM_RSTC_EN);
+ /* disable Rx performance counters */
+ out_be32(&rx_port->fmbm_rpc, 0);
+}
+
+static void bmi_tx_port_disable(struct fm_bmi_tx_port *tx_port)
+{
+ int timeout = 1000000;
+
+ clrbits_be32(&tx_port->fmbm_tcfg, FMBM_TCFG_EN);
+
+ /* wait until the tx port is not busy */
+ while ((in_be32(&tx_port->fmbm_tst) & FMBM_TST_BSY) && timeout--)
+ ;
+}
+
+static void bmi_tx_port_init(struct fm_bmi_tx_port *tx_port)
+{
+ /* set BMI to independent mode, Tx port disable */
+ out_be32(&tx_port->fmbm_tcfg, FMBM_TCFG_IM);
+ /* Tx frame next engine -RISC */
+ out_be32(&tx_port->fmbm_tfne, NIA_ENG_RISC | NIA_RISC_AC_IM_TX);
+ out_be32(&tx_port->fmbm_tfene, NIA_ENG_RISC | NIA_RISC_AC_IM_TX);
+ /* Tx command attribute - no order, MR[3] = 1 */
+ clrbits_be32(&tx_port->fmbm_tfca, FMBM_TFCA_ORDER | FMBM_TFCA_MR_MASK);
+ setbits_be32(&tx_port->fmbm_tfca, FMBM_TFCA_MR(4));
+ /* enable Tx statistic counters */
+ out_be32(&tx_port->fmbm_tstc, FMBM_TSTC_EN);
+ /* disable Tx performance counters */
+ out_be32(&tx_port->fmbm_tpc, 0);
+}
+
+static int fm_eth_rx_port_parameter_init(struct fm_eth *fm_eth)
+{
+ struct fm_port_global_pram *pram;
+ u32 pram_page_offset;
+ void *rx_bd_ring_base;
+ void *rx_buf_pool;
+ struct fm_port_bd *rxbd;
+ struct fm_port_qd *rxqd;
+ struct fm_bmi_rx_port *bmi_rx_port = fm_eth->rx_port;
+ int i;
+
+ /* alloc global parameter ram at MURAM */
+ pram = (struct fm_port_global_pram *)fm_muram_alloc(fm_eth->fm_index,
+ FM_PRAM_SIZE, FM_PRAM_ALIGN);
+ fm_eth->rx_pram = pram;
+
+ /* parameter page offset to MURAM */
+ pram_page_offset = (u32)pram - fm_muram_base(fm_eth->fm_index);
+
+ /* enable global mode- snooping data buffers and BDs */
+ pram->mode = PRAM_MODE_GLOBAL;
+
+ /* init the Rx queue descriptor pionter */
+ pram->rxqd_ptr = pram_page_offset + 0x20;
+
+ /* set the max receive buffer length, power of 2 */
+ muram_writew(&pram->mrblr, MAX_RXBUF_LOG2);
+
+ /* alloc Rx buffer descriptors from main memory */
+ rx_bd_ring_base = malloc(sizeof(struct fm_port_bd)
+ * RX_BD_RING_SIZE);
+ if (!rx_bd_ring_base)
+ return 0;
+ memset(rx_bd_ring_base, 0, sizeof(struct fm_port_bd)
+ * RX_BD_RING_SIZE);
+
+ /* alloc Rx buffer from main memory */
+ rx_buf_pool = malloc(MAX_RXBUF_LEN * RX_BD_RING_SIZE);
+ if (!rx_buf_pool)
+ return 0;
+ memset(rx_buf_pool, 0, MAX_RXBUF_LEN * RX_BD_RING_SIZE);
+
+ /* save them to fm_eth */
+ fm_eth->rx_bd_ring = rx_bd_ring_base;
+ fm_eth->cur_rxbd = rx_bd_ring_base;
+ fm_eth->rx_buf = rx_buf_pool;
+
+ /* init Rx BDs ring */
+ rxbd = (struct fm_port_bd *)rx_bd_ring_base;
+ for (i = 0; i < RX_BD_RING_SIZE; i++) {
+ rxbd->status = RxBD_EMPTY;
+ rxbd->len = 0;
+ rxbd->buf_ptr_hi = 0;
+ rxbd->buf_ptr_lo = (u32)rx_buf_pool + i * MAX_RXBUF_LEN;
+ rxbd++;
+ }
+
+ /* set the Rx queue descriptor */
+ rxqd = &pram->rxqd;
+ muram_writew(&rxqd->gen, 0);
+ muram_writew(&rxqd->bd_ring_base_hi, 0);
+ rxqd->bd_ring_base_lo = (u32)rx_bd_ring_base;
+ muram_writew(&rxqd->bd_ring_size, sizeof(struct fm_port_bd)
+ * RX_BD_RING_SIZE);
+ muram_writew(&rxqd->offset_in, 0);
+ muram_writew(&rxqd->offset_out, 0);
+
+ /* set IM parameter ram pointer to Rx Frame Queue ID */
+ out_be32(&bmi_rx_port->fmbm_rfqid, pram_page_offset);
+
+ return 1;
+}
+
+static int fm_eth_tx_port_parameter_init(struct fm_eth *fm_eth)
+{
+ struct fm_port_global_pram *pram;
+ u32 pram_page_offset;
+ void *tx_bd_ring_base;
+ struct fm_port_bd *txbd;
+ struct fm_port_qd *txqd;
+ struct fm_bmi_tx_port *bmi_tx_port = fm_eth->tx_port;
+ int i;
+
+ /* alloc global parameter ram at MURAM */
+ pram = (struct fm_port_global_pram *)fm_muram_alloc(fm_eth->fm_index,
+ FM_PRAM_SIZE, FM_PRAM_ALIGN);
+ fm_eth->tx_pram = pram;
+
+ /* parameter page offset to MURAM */
+ pram_page_offset = (u32)pram - fm_muram_base(fm_eth->fm_index);
+
+ /* enable global mode- snooping data buffers and BDs */
+ pram->mode = PRAM_MODE_GLOBAL;
+
+ /* init the Tx queue descriptor pionter */
+ pram->txqd_ptr = pram_page_offset + 0x40;
+
+ /* alloc Tx buffer descriptors from main memory */
+ tx_bd_ring_base = malloc(sizeof(struct fm_port_bd)
+ * TX_BD_RING_SIZE);
+ if (!tx_bd_ring_base)
+ return 0;
+ memset(tx_bd_ring_base, 0, sizeof(struct fm_port_bd)
+ * TX_BD_RING_SIZE);
+ /* save it to fm_eth */
+ fm_eth->tx_bd_ring = tx_bd_ring_base;
+ fm_eth->cur_txbd = tx_bd_ring_base;
+
+ /* init Tx BDs ring */
+ txbd = (struct fm_port_bd *)tx_bd_ring_base;
+ for (i = 0; i < TX_BD_RING_SIZE; i++) {
+ txbd->status = TxBD_LAST;
+ txbd->len = 0;
+ txbd->buf_ptr_hi = 0;
+ txbd->buf_ptr_lo = 0;
+ }
+
+ /* set the Tx queue decriptor */
+ txqd = &pram->txqd;
+ muram_writew(&txqd->bd_ring_base_hi, 0);
+ txqd->bd_ring_base_lo = (u32)tx_bd_ring_base;
+ muram_writew(&txqd->bd_ring_size, sizeof(struct fm_port_bd)
+ * TX_BD_RING_SIZE);
+ muram_writew(&txqd->offset_in, 0);
+ muram_writew(&txqd->offset_out, 0);
+
+ /* set IM parameter ram pointer to Tx Confirmation Frame Queue ID */
+ out_be32(&bmi_tx_port->fmbm_tcfqid, pram_page_offset);
+
+ return 1;
+}
+
+static int fm_eth_init(struct fm_eth *fm_eth)
+{
+
+ if (!fm_eth_rx_port_parameter_init(fm_eth))
+ return 0;
+
+ if (!fm_eth_tx_port_parameter_init(fm_eth))
+ return 0;
+
+ return 1;
+}
+
+static int fm_eth_startup(struct fm_eth *fm_eth)
+{
+ struct fsl_enet_mac *mac;
+ mac = fm_eth->mac;
+
+ /* Rx/TxBDs, Rx/TxQDs, Rx buff and parameter ram init */
+ if (!fm_eth_init(fm_eth))
+ return 0;
+ /* setup the MAC controller */
+ mac->init_mac(mac);
+
+ /* For some reason we need to set SPEED_100 */
+ if (((fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII) ||
+ (fm_eth->enet_if == PHY_INTERFACE_MODE_QSGMII)) &&
+ mac->set_if_mode)
+ mac->set_if_mode(mac, fm_eth->enet_if, SPEED_100);
+
+ /* init bmi rx port, IM mode and disable */
+ bmi_rx_port_init(fm_eth->rx_port);
+ /* init bmi tx port, IM mode and disable */
+ bmi_tx_port_init(fm_eth->tx_port);
+
+ return 1;
+}
+
+static void fmc_tx_port_graceful_stop_enable(struct fm_eth *fm_eth)
+{
+ struct fm_port_global_pram *pram;
+
+ pram = fm_eth->tx_pram;
+ /* graceful stop transmission of frames */
+ pram->mode |= PRAM_MODE_GRACEFUL_STOP;
+ sync();
+}
+
+static void fmc_tx_port_graceful_stop_disable(struct fm_eth *fm_eth)
+{
+ struct fm_port_global_pram *pram;
+
+ pram = fm_eth->tx_pram;
+ /* re-enable transmission of frames */
+ pram->mode &= ~PRAM_MODE_GRACEFUL_STOP;
+ sync();
+}
+
+static int fm_eth_open(struct eth_device *dev, bd_t *bd)
+{
+ struct fm_eth *fm_eth;
+ struct fsl_enet_mac *mac;
+#ifdef CONFIG_PHYLIB
+ int ret;
+#endif
+
+ fm_eth = (struct fm_eth *)dev->priv;
+ mac = fm_eth->mac;
+
+ /* setup the MAC address */
+ if (dev->enetaddr[0] & 0x01) {
+ printf("%s: MacAddress is multcast address\n", __func__);
+ return 1;
+ }
+ mac->set_mac_addr(mac, dev->enetaddr);
+
+ /* enable bmi Rx port */
+ setbits_be32(&fm_eth->rx_port->fmbm_rcfg, FMBM_RCFG_EN);
+ /* enable MAC rx/tx port */
+ mac->enable_mac(mac);
+ /* enable bmi Tx port */
+ setbits_be32(&fm_eth->tx_port->fmbm_tcfg, FMBM_TCFG_EN);
+ /* re-enable transmission of frame */
+ fmc_tx_port_graceful_stop_disable(fm_eth);
+
+#ifdef CONFIG_PHYLIB
+ ret = phy_startup(fm_eth->phydev);
+ if (ret) {
+ printf("%s: Could not initialize\n", fm_eth->phydev->dev->name);
+ return ret;
+ }
+#else
+ fm_eth->phydev->speed = SPEED_1000;
+ fm_eth->phydev->link = 1;
+ fm_eth->phydev->duplex = DUPLEX_FULL;
+#endif
+
+ /* set the MAC-PHY mode */
+ mac->set_if_mode(mac, fm_eth->enet_if, fm_eth->phydev->speed);
+
+ if (!fm_eth->phydev->link)
+ printf("%s: No link.\n", fm_eth->phydev->dev->name);
+
+ return fm_eth->phydev->link ? 0 : -1;
+}
+
+static void fm_eth_halt(struct eth_device *dev)
+{
+ struct fm_eth *fm_eth;
+ struct fsl_enet_mac *mac;
+
+ fm_eth = (struct fm_eth *)dev->priv;
+ mac = fm_eth->mac;
+
+ /* graceful stop the transmission of frames */
+ fmc_tx_port_graceful_stop_enable(fm_eth);
+ /* disable bmi Tx port */
+ bmi_tx_port_disable(fm_eth->tx_port);
+ /* disable MAC rx/tx port */
+ mac->disable_mac(mac);
+ /* disable bmi Rx port */
+ bmi_rx_port_disable(fm_eth->rx_port);
+
+ phy_shutdown(fm_eth->phydev);
+}
+
+static int fm_eth_send(struct eth_device *dev, void *buf, int len)
+{
+ struct fm_eth *fm_eth;
+ struct fm_port_global_pram *pram;
+ struct fm_port_bd *txbd, *txbd_base;
+ u16 offset_in;
+ int i;
+
+ fm_eth = (struct fm_eth *)dev->priv;
+ pram = fm_eth->tx_pram;
+ txbd = fm_eth->cur_txbd;
+
+ /* find one empty TxBD */
+ for (i = 0; txbd->status & TxBD_READY; i++) {
+ udelay(100);
+ if (i > 0x1000) {
+ printf("%s: Tx buffer not ready\n", dev->name);
+ return 0;
+ }
+ }
+ /* setup TxBD */
+ txbd->buf_ptr_hi = 0;
+ txbd->buf_ptr_lo = (u32)buf;
+ txbd->len = len;
+ sync();
+ txbd->status = TxBD_READY | TxBD_LAST;
+ sync();
+
+ /* update TxQD, let RISC to send the packet */
+ offset_in = muram_readw(&pram->txqd.offset_in);
+ offset_in += sizeof(struct fm_port_bd);
+ if (offset_in >= muram_readw(&pram->txqd.bd_ring_size))
+ offset_in = 0;
+ muram_writew(&pram->txqd.offset_in, offset_in);
+ sync();
+
+ /* wait for buffer to be transmitted */
+ for (i = 0; txbd->status & TxBD_READY; i++) {
+ udelay(100);
+ if (i > 0x10000) {
+ printf("%s: Tx error\n", dev->name);
+ return 0;
+ }
+ }
+
+ /* advance the TxBD */
+ txbd++;
+ txbd_base = (struct fm_port_bd *)fm_eth->tx_bd_ring;
+ if (txbd >= (txbd_base + TX_BD_RING_SIZE))
+ txbd = txbd_base;
+ /* update current txbd */
+ fm_eth->cur_txbd = (void *)txbd;
+
+ return 1;
+}
+
+static int fm_eth_recv(struct eth_device *dev)
+{
+ struct fm_eth *fm_eth;
+ struct fm_port_global_pram *pram;
+ struct fm_port_bd *rxbd, *rxbd_base;
+ u16 status, len;
+ u8 *data;
+ u16 offset_out;
+
+ fm_eth = (struct fm_eth *)dev->priv;
+ pram = fm_eth->rx_pram;
+ rxbd = fm_eth->cur_rxbd;
+ status = rxbd->status;
+
+ while (!(status & RxBD_EMPTY)) {
+ if (!(status & RxBD_ERROR)) {
+ data = (u8 *)rxbd->buf_ptr_lo;
+ len = rxbd->len;
+ NetReceive(data, len);
+ } else {
+ printf("%s: Rx error\n", dev->name);
+ return 0;
+ }
+
+ /* clear the RxBDs */
+ rxbd->status = RxBD_EMPTY;
+ rxbd->len = 0;
+ sync();
+
+ /* advance RxBD */
+ rxbd++;
+ rxbd_base = (struct fm_port_bd *)fm_eth->rx_bd_ring;
+ if (rxbd >= (rxbd_base + RX_BD_RING_SIZE))
+ rxbd = rxbd_base;
+ /* read next status */
+ status = rxbd->status;
+
+ /* update RxQD */
+ offset_out = muram_readw(&pram->rxqd.offset_out);
+ offset_out += sizeof(struct fm_port_bd);
+ if (offset_out >= muram_readw(&pram->rxqd.bd_ring_size))
+ offset_out = 0;
+ muram_writew(&pram->rxqd.offset_out, offset_out);
+ sync();
+ }
+ fm_eth->cur_rxbd = (void *)rxbd;
+
+ return 1;
+}
+
+static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
+{
+ struct fsl_enet_mac *mac;
+ int num;
+ void *base, *phyregs = NULL;
+
+ num = fm_eth->num;
+
+#ifdef CONFIG_SYS_FMAN_V3
+ if (fm_eth->type == FM_ETH_10G_E) {
+ /* 10GEC1/10GEC2 use mEMAC9/mEMAC10
+ * 10GEC3/10GEC4 use mEMAC1/mEMAC2
+ * so it needs to change the num.
+ */
+ if (fm_eth->num >= 2)
+ num -= 2;
+ else
+ num += 8;
+ }
+ base = &reg->memac[num].fm_memac;
+ phyregs = &reg->memac[num].fm_memac_mdio;
+#else
+ /* Get the mac registers base address */
+ if (fm_eth->type == FM_ETH_1G_E) {
+ base = &reg->mac_1g[num].fm_dtesc;
+ phyregs = &reg->mac_1g[num].fm_mdio.miimcfg;
+ } else {
+ base = &reg->mac_10g[num].fm_10gec;
+ phyregs = &reg->mac_10g[num].fm_10gec_mdio;
+ }
+#endif
+
+ /* alloc mac controller */
+ mac = malloc(sizeof(struct fsl_enet_mac));
+ if (!mac)
+ return 0;
+ memset(mac, 0, sizeof(struct fsl_enet_mac));
+
+ /* save the mac to fm_eth struct */
+ fm_eth->mac = mac;
+
+#ifdef CONFIG_SYS_FMAN_V3
+ init_memac(mac, base, phyregs, MAX_RXBUF_LEN);
+#else
+ if (fm_eth->type == FM_ETH_1G_E)
+ init_dtsec(mac, base, phyregs, MAX_RXBUF_LEN);
+ else
+ init_tgec(mac, base, phyregs, MAX_RXBUF_LEN);
+#endif
+
+ return 1;
+}
+
+static int init_phy(struct eth_device *dev)
+{
+ struct fm_eth *fm_eth = dev->priv;
+ struct phy_device *phydev = NULL;
+ u32 supported;
+
+#ifdef CONFIG_PHYLIB
+ if (fm_eth->type == FM_ETH_1G_E)
+ dtsec_init_phy(dev);
+
+ if (fm_eth->bus) {
+ phydev = phy_connect(fm_eth->bus, fm_eth->phyaddr, dev,
+ fm_eth->enet_if);
+ }
+
+ if (!phydev) {
+ printf("Failed to connect\n");
+ return -1;
+ }
+
+ if (fm_eth->type == FM_ETH_1G_E) {
+ supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full);
+ } else {
+ supported = SUPPORTED_10000baseT_Full;
+
+ if (tgec_is_fibre(dev))
+ phydev->port = PORT_FIBRE;
+ }
+
+ phydev->supported &= supported;
+ phydev->advertising = phydev->supported;
+
+ fm_eth->phydev = phydev;
+
+ phy_config(phydev);
+#endif
+
+ return 0;
+}
+
+int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info)
+{
+ struct eth_device *dev;
+ struct fm_eth *fm_eth;
+ int i, num = info->num;
+
+ /* alloc eth device */
+ dev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ if (!dev)
+ return 0;
+ memset(dev, 0, sizeof(struct eth_device));
+
+ /* alloc the FMan ethernet private struct */
+ fm_eth = (struct fm_eth *)malloc(sizeof(struct fm_eth));
+ if (!fm_eth)
+ return 0;
+ memset(fm_eth, 0, sizeof(struct fm_eth));
+
+ /* save off some things we need from the info struct */
+ fm_eth->fm_index = info->index - 1; /* keep as 0 based for muram */
+ fm_eth->num = num;
+ fm_eth->type = info->type;
+
+ fm_eth->rx_port = (void *)&reg->port[info->rx_port_id - 1].fm_bmi;
+ fm_eth->tx_port = (void *)&reg->port[info->tx_port_id - 1].fm_bmi;
+
+ /* set the ethernet max receive length */
+ fm_eth->max_rx_len = MAX_RXBUF_LEN;
+
+ /* init global mac structure */
+ if (!fm_eth_init_mac(fm_eth, reg))
+ return 0;
+
+ /* keep same as the manual, we call FMAN1, FMAN2, DTSEC1, DTSEC2, etc */
+ if (fm_eth->type == FM_ETH_1G_E)
+ sprintf(dev->name, "FM%d@DTSEC%d", info->index, num + 1);
+ else
+ sprintf(dev->name, "FM%d@TGEC%d", info->index, num + 1);
+
+ devlist[num_controllers++] = dev;
+ dev->iobase = 0;
+ dev->priv = (void *)fm_eth;
+ dev->init = fm_eth_open;
+ dev->halt = fm_eth_halt;
+ dev->send = fm_eth_send;
+ dev->recv = fm_eth_recv;
+ fm_eth->dev = dev;
+ fm_eth->bus = info->bus;
+ fm_eth->phyaddr = info->phy_addr;
+ fm_eth->enet_if = info->enet_if;
+
+ /* startup the FM im */
+ if (!fm_eth_startup(fm_eth))
+ return 0;
+
+ if (init_phy(dev))
+ return 0;
+
+ /* clear the ethernet address */
+ for (i = 0; i < 6; i++)
+ dev->enetaddr[i] = 0;
+ eth_register(dev);
+
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/fm.c b/qemu/roms/u-boot/drivers/net/fm/fm.c
new file mode 100644
index 000000000..400e9dd5e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/fm.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+#include "fm.h"
+#include "../../qe/qe.h" /* For struct qe_firmware */
+
+#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NAND
+#include <nand.h>
+#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
+#include <spi_flash.h>
+#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC)
+#include <mmc.h>
+#endif
+
+struct fm_muram muram[CONFIG_SYS_NUM_FMAN];
+
+u32 fm_muram_base(int fm_idx)
+{
+ return muram[fm_idx].base;
+}
+
+u32 fm_muram_alloc(int fm_idx, u32 size, u32 align)
+{
+ u32 ret;
+ u32 align_mask, off;
+ u32 save;
+
+ align_mask = align - 1;
+ save = muram[fm_idx].alloc;
+
+ off = save & align_mask;
+ if (off != 0)
+ muram[fm_idx].alloc += (align - off);
+ off = size & align_mask;
+ if (off != 0)
+ size += (align - off);
+ if ((muram[fm_idx].alloc + size) >= muram[fm_idx].top) {
+ muram[fm_idx].alloc = save;
+ printf("%s: run out of ram.\n", __func__);
+ }
+
+ ret = muram[fm_idx].alloc;
+ muram[fm_idx].alloc += size;
+ memset((void *)ret, 0, size);
+
+ return ret;
+}
+
+static void fm_init_muram(int fm_idx, void *reg)
+{
+ u32 base = (u32)reg;
+
+ muram[fm_idx].base = base;
+ muram[fm_idx].size = CONFIG_SYS_FM_MURAM_SIZE;
+ muram[fm_idx].alloc = base + FM_MURAM_RES_SIZE;
+ muram[fm_idx].top = base + CONFIG_SYS_FM_MURAM_SIZE;
+}
+
+/*
+ * fm_upload_ucode - Fman microcode upload worker function
+ *
+ * This function does the actual uploading of an Fman microcode
+ * to an Fman.
+ */
+static void fm_upload_ucode(int fm_idx, struct fm_imem *imem,
+ u32 *ucode, unsigned int size)
+{
+ unsigned int i;
+ unsigned int timeout = 1000000;
+
+ /* enable address auto increase */
+ out_be32(&imem->iadd, IRAM_IADD_AIE);
+ /* write microcode to IRAM */
+ for (i = 0; i < size / 4; i++)
+ out_be32(&imem->idata, ucode[i]);
+
+ /* verify if the writing is over */
+ out_be32(&imem->iadd, 0);
+ while ((in_be32(&imem->idata) != ucode[0]) && --timeout)
+ ;
+ if (!timeout)
+ printf("Fman%u: microcode upload timeout\n", fm_idx + 1);
+
+ /* enable microcode from IRAM */
+ out_be32(&imem->iready, IRAM_READY);
+}
+
+/*
+ * Upload an Fman firmware
+ *
+ * This function is similar to qe_upload_firmware(), exception that it uploads
+ * a microcode to the Fman instead of the QE.
+ *
+ * Because the process for uploading a microcode to the Fman is similar for
+ * that of the QE, the QE firmware binary format is used for Fman microcode.
+ * It should be possible to unify these two functions, but for now we keep them
+ * separate.
+ */
+static int fman_upload_firmware(int fm_idx,
+ struct fm_imem *fm_imem,
+ const struct qe_firmware *firmware)
+{
+ unsigned int i;
+ u32 crc;
+ size_t calc_size = sizeof(struct qe_firmware);
+ size_t length;
+ const struct qe_header *hdr;
+
+ if (!firmware) {
+ printf("Fman%u: Invalid address for firmware\n", fm_idx + 1);
+ return -EINVAL;
+ }
+
+ hdr = &firmware->header;
+ length = be32_to_cpu(hdr->length);
+
+ /* Check the magic */
+ if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
+ (hdr->magic[2] != 'F')) {
+ printf("Fman%u: Data at %p is not a firmware\n", fm_idx + 1,
+ firmware);
+ return -EPERM;
+ }
+
+ /* Check the version */
+ if (hdr->version != 1) {
+ printf("Fman%u: Unsupported firmware version %u\n", fm_idx + 1,
+ hdr->version);
+ return -EPERM;
+ }
+
+ /* Validate some of the fields */
+ if ((firmware->count != 1)) {
+ printf("Fman%u: Invalid data in firmware header\n", fm_idx + 1);
+ return -EINVAL;
+ }
+
+ /* Validate the length and check if there's a CRC */
+ calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
+
+ for (i = 0; i < firmware->count; i++)
+ /*
+ * For situations where the second RISC uses the same microcode
+ * as the first, the 'code_offset' and 'count' fields will be
+ * zero, so it's okay to add those.
+ */
+ calc_size += sizeof(u32) *
+ be32_to_cpu(firmware->microcode[i].count);
+
+ /* Validate the length */
+ if (length != calc_size + sizeof(u32)) {
+ printf("Fman%u: Invalid length in firmware header\n",
+ fm_idx + 1);
+ return -EPERM;
+ }
+
+ /*
+ * Validate the CRC. We would normally call crc32_no_comp(), but that
+ * function isn't available unless you turn on JFFS support.
+ */
+ crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
+ if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
+ printf("Fman%u: Firmware CRC is invalid\n", fm_idx + 1);
+ return -EIO;
+ }
+
+ /* Loop through each microcode. */
+ for (i = 0; i < firmware->count; i++) {
+ const struct qe_microcode *ucode = &firmware->microcode[i];
+
+ /* Upload a microcode if it's present */
+ if (ucode->code_offset) {
+ u32 ucode_size;
+ u32 *code;
+ printf("Fman%u: Uploading microcode version %u.%u.%u\n",
+ fm_idx + 1, ucode->major, ucode->minor,
+ ucode->revision);
+ code = (void *)firmware + ucode->code_offset;
+ ucode_size = sizeof(u32) * ucode->count;
+ fm_upload_ucode(fm_idx, fm_imem, code, ucode_size);
+ }
+ }
+
+ return 0;
+}
+
+static u32 fm_assign_risc(int port_id)
+{
+ u32 risc_sel, val;
+ risc_sel = (port_id & 0x1) ? FMFPPRC_RISC2 : FMFPPRC_RISC1;
+ val = (port_id << FMFPPRC_PORTID_SHIFT) & FMFPPRC_PORTID_MASK;
+ val |= ((risc_sel << FMFPPRC_ORA_SHIFT) | risc_sel);
+
+ return val;
+}
+
+static void fm_init_fpm(struct fm_fpm *fpm)
+{
+ int i, port_id;
+ u32 val;
+
+ setbits_be32(&fpm->fmfpee, FMFPEE_EHM | FMFPEE_UEC |
+ FMFPEE_CER | FMFPEE_DER);
+
+ /* IM mode, each even port ID to RISC#1, each odd port ID to RISC#2 */
+
+ /* offline/parser port */
+ for (i = 0; i < MAX_NUM_OH_PORT; i++) {
+ port_id = OH_PORT_ID_BASE + i;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+ }
+ /* Rx 1G port */
+ for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
+ port_id = RX_PORT_1G_BASE + i;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+ }
+ /* Tx 1G port */
+ for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
+ port_id = TX_PORT_1G_BASE + i;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+ }
+ /* Rx 10G port */
+ port_id = RX_PORT_10G_BASE;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+ /* Tx 10G port */
+ port_id = TX_PORT_10G_BASE;
+ val = fm_assign_risc(port_id);
+ out_be32(&fpm->fpmprc, val);
+
+ /* disable the dispatch limit in IM case */
+ out_be32(&fpm->fpmflc, FMFP_FLC_DISP_LIM_NONE);
+ /* clear events */
+ out_be32(&fpm->fmfpee, FMFPEE_CLEAR_EVENT);
+
+ /* clear risc events */
+ for (i = 0; i < 4; i++)
+ out_be32(&fpm->fpmcev[i], 0xffffffff);
+
+ /* clear error */
+ out_be32(&fpm->fpmrcr, FMFP_RCR_MDEC | FMFP_RCR_IDEC);
+}
+
+static int fm_init_bmi(int fm_idx, struct fm_bmi_common *bmi)
+{
+ int blk, i, port_id;
+ u32 val, offset, base;
+
+ /* alloc free buffer pool in MURAM */
+ base = fm_muram_alloc(fm_idx, FM_FREE_POOL_SIZE, FM_FREE_POOL_ALIGN);
+ if (!base) {
+ printf("%s: no muram for free buffer pool\n", __func__);
+ return -ENOMEM;
+ }
+ offset = base - fm_muram_base(fm_idx);
+
+ /* Need 128KB total free buffer pool size */
+ val = offset / 256;
+ blk = FM_FREE_POOL_SIZE / 256;
+ /* in IM, we must not begin from offset 0 in MURAM */
+ val |= ((blk - 1) << FMBM_CFG1_FBPS_SHIFT);
+ out_be32(&bmi->fmbm_cfg1, val);
+
+ /* disable all BMI interrupt */
+ out_be32(&bmi->fmbm_ier, FMBM_IER_DISABLE_ALL);
+
+ /* clear all events */
+ out_be32(&bmi->fmbm_ievr, FMBM_IEVR_CLEAR_ALL);
+
+ /*
+ * set port parameters - FMBM_PP_x
+ * max tasks 10G Rx/Tx=12, 1G Rx/Tx 4, others is 1
+ * max dma 10G Rx/Tx=3, others is 1
+ * set port FIFO size - FMBM_PFS_x
+ * 4KB for all Rx and Tx ports
+ */
+ /* offline/parser port */
+ for (i = 0; i < MAX_NUM_OH_PORT; i++) {
+ port_id = OH_PORT_ID_BASE + i - 1;
+ /* max tasks=1, max dma=1, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], 0);
+ /* port FIFO size - 256 bytes, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], 0);
+ }
+ /* Rx 1G port */
+ for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
+ port_id = RX_PORT_1G_BASE + i - 1;
+ /* max tasks=4, max dma=1, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
+ /* FIFO size - 4KB, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
+ }
+ /* Tx 1G port FIFO size - 4KB, no extra */
+ for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
+ port_id = TX_PORT_1G_BASE + i - 1;
+ /* max tasks=4, max dma=1, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
+ /* FIFO size - 4KB, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
+ }
+ /* Rx 10G port */
+ port_id = RX_PORT_10G_BASE - 1;
+ /* max tasks=12, max dma=3, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
+ /* FIFO size - 4KB, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
+
+ /* Tx 10G port */
+ port_id = TX_PORT_10G_BASE - 1;
+ /* max tasks=12, max dma=3, no extra */
+ out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
+ /* FIFO size - 4KB, no extra */
+ out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
+
+ /* initialize internal buffers data base (linked list) */
+ out_be32(&bmi->fmbm_init, FMBM_INIT_START);
+
+ return 0;
+}
+
+static void fm_init_qmi(struct fm_qmi_common *qmi)
+{
+ /* disable enqueue and dequeue of QMI */
+ clrbits_be32(&qmi->fmqm_gc, FMQM_GC_ENQ_EN | FMQM_GC_DEQ_EN);
+
+ /* disable all error interrupts */
+ out_be32(&qmi->fmqm_eien, FMQM_EIEN_DISABLE_ALL);
+ /* clear all error events */
+ out_be32(&qmi->fmqm_eie, FMQM_EIE_CLEAR_ALL);
+
+ /* disable all interrupts */
+ out_be32(&qmi->fmqm_ien, FMQM_IEN_DISABLE_ALL);
+ /* clear all interrupts */
+ out_be32(&qmi->fmqm_ie, FMQM_IE_CLEAR_ALL);
+}
+
+/* Init common part of FM, index is fm num# like fm as above */
+int fm_init_common(int index, struct ccsr_fman *reg)
+{
+ int rc;
+#if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR)
+ void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR;
+#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NAND)
+ size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH;
+ void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
+
+ rc = nand_read(&nand_info[0], (loff_t)CONFIG_SYS_FMAN_FW_ADDR,
+ &fw_length, (u_char *)addr);
+ if (rc == -EUCLEAN) {
+ printf("NAND read of FMAN firmware at offset 0x%x failed %d\n",
+ CONFIG_SYS_FMAN_FW_ADDR, rc);
+ }
+#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
+ struct spi_flash *ucode_flash;
+ void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
+ int ret = 0;
+
+ ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (!ucode_flash)
+ printf("SF: probe for ucode failed\n");
+ else {
+ ret = spi_flash_read(ucode_flash, CONFIG_SYS_FMAN_FW_ADDR,
+ CONFIG_SYS_QE_FMAN_FW_LENGTH, addr);
+ if (ret)
+ printf("SF: read for ucode failed\n");
+ spi_flash_free(ucode_flash);
+ }
+#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC)
+ int dev = CONFIG_SYS_MMC_ENV_DEV;
+ void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
+ u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
+ u32 blk = CONFIG_SYS_FMAN_FW_ADDR / 512;
+ struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
+
+ if (!mmc)
+ printf("\nMMC cannot find device for ucode\n");
+ else {
+ printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
+ dev, blk, cnt);
+ mmc_init(mmc);
+ (void)mmc->block_dev.block_read(dev, blk, cnt, addr);
+ /* flush cache after read */
+ flush_cache((ulong)addr, cnt * 512);
+ }
+#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_REMOTE)
+ void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR;
+#else
+ void *addr = NULL;
+#endif
+
+ /* Upload the Fman microcode if it's present */
+ rc = fman_upload_firmware(index, &reg->fm_imem, addr);
+ if (rc)
+ return rc;
+ setenv_addr("fman_ucode", addr);
+
+ fm_init_muram(index, &reg->muram);
+ fm_init_qmi(&reg->fm_qmi_common);
+ fm_init_fpm(&reg->fm_fpm);
+
+ /* clear DMA status */
+ setbits_be32(&reg->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL);
+
+ /* set DMA mode */
+ setbits_be32(&reg->fm_dma.fmdmmr, FMDMMR_SBER);
+
+ return fm_init_bmi(index, &reg->fm_bmi_common);
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/fm.h b/qemu/roms/u-boot/drivers/net/fm/fm.h
new file mode 100644
index 000000000..43de114b5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/fm.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __FM_H__
+#define __FM_H__
+
+#include <common.h>
+#include <fm_eth.h>
+#include <asm/fsl_enet.h>
+#include <asm/fsl_fman.h>
+
+/* Port ID */
+#define OH_PORT_ID_BASE 0x01
+#define MAX_NUM_OH_PORT 7
+#define RX_PORT_1G_BASE 0x08
+#define MAX_NUM_RX_PORT_1G CONFIG_SYS_NUM_FM1_DTSEC
+#define RX_PORT_10G_BASE 0x10
+#define RX_PORT_10G_BASE2 0x08
+#define TX_PORT_1G_BASE 0x28
+#define MAX_NUM_TX_PORT_1G CONFIG_SYS_NUM_FM1_DTSEC
+#define TX_PORT_10G_BASE 0x30
+#define TX_PORT_10G_BASE2 0x28
+#define MIIM_TIMEOUT 0xFFFF
+
+struct fm_muram {
+ u32 base;
+ u32 top;
+ u32 size;
+ u32 alloc;
+};
+#define FM_MURAM_RES_SIZE 0x01000
+
+/* Rx/Tx buffer descriptor */
+struct fm_port_bd {
+ u16 status;
+ u16 len;
+ u32 res0;
+ u16 res1;
+ u16 buf_ptr_hi;
+ u32 buf_ptr_lo;
+};
+
+/* Common BD flags */
+#define BD_LAST 0x0800
+
+/* Rx BD status flags */
+#define RxBD_EMPTY 0x8000
+#define RxBD_LAST BD_LAST
+#define RxBD_FIRST 0x0400
+#define RxBD_PHYS_ERR 0x0008
+#define RxBD_SIZE_ERR 0x0004
+#define RxBD_ERROR (RxBD_PHYS_ERR | RxBD_SIZE_ERR)
+
+/* Tx BD status flags */
+#define TxBD_READY 0x8000
+#define TxBD_LAST BD_LAST
+
+/* Rx/Tx queue descriptor */
+struct fm_port_qd {
+ u16 gen;
+ u16 bd_ring_base_hi;
+ u32 bd_ring_base_lo;
+ u16 bd_ring_size;
+ u16 offset_in;
+ u16 offset_out;
+ u16 res0;
+ u32 res1[0x4];
+};
+
+/* IM global parameter RAM */
+struct fm_port_global_pram {
+ u32 mode; /* independent mode register */
+ u32 rxqd_ptr; /* Rx queue descriptor pointer */
+ u32 txqd_ptr; /* Tx queue descriptor pointer */
+ u16 mrblr; /* max Rx buffer length */
+ u16 rxqd_bsy_cnt; /* RxQD busy counter, should be cleared */
+ u32 res0[0x4];
+ struct fm_port_qd rxqd; /* Rx queue descriptor */
+ struct fm_port_qd txqd; /* Tx queue descriptor */
+ u32 res1[0x28];
+};
+
+#define FM_PRAM_SIZE sizeof(struct fm_port_global_pram)
+#define FM_PRAM_ALIGN 256
+#define PRAM_MODE_GLOBAL 0x20000000
+#define PRAM_MODE_GRACEFUL_STOP 0x00800000
+
+#if defined(CONFIG_P1017) || defined(CONFIG_P1023)
+#define FM_FREE_POOL_SIZE 0x2000 /* 8K bytes */
+#else
+#define FM_FREE_POOL_SIZE 0x20000 /* 128K bytes */
+#endif
+#define FM_FREE_POOL_ALIGN 256
+
+u32 fm_muram_alloc(int fm_idx, u32 size, u32 align);
+u32 fm_muram_base(int fm_idx);
+int fm_init_common(int index, struct ccsr_fman *reg);
+int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info);
+phy_interface_t fman_port_enet_if(enum fm_port port);
+void fman_disable_port(enum fm_port port);
+void fman_enable_port(enum fm_port port);
+
+struct fsl_enet_mac {
+ void *base; /* MAC controller registers base address */
+ void *phyregs;
+ int max_rx_len;
+ void (*init_mac)(struct fsl_enet_mac *mac);
+ void (*enable_mac)(struct fsl_enet_mac *mac);
+ void (*disable_mac)(struct fsl_enet_mac *mac);
+ void (*set_mac_addr)(struct fsl_enet_mac *mac, u8 *mac_addr);
+ void (*set_if_mode)(struct fsl_enet_mac *mac, phy_interface_t type,
+ int speed);
+};
+
+/* Fman ethernet private struct */
+struct fm_eth {
+ int fm_index; /* Fman index */
+ u32 num; /* 0..n-1 for give type */
+ struct fm_bmi_tx_port *tx_port;
+ struct fm_bmi_rx_port *rx_port;
+ enum fm_eth_type type; /* 1G or 10G ethernet */
+ phy_interface_t enet_if;
+ struct fsl_enet_mac *mac; /* MAC controller */
+ struct mii_dev *bus;
+ struct phy_device *phydev;
+ int phyaddr;
+ struct eth_device *dev;
+ int max_rx_len;
+ struct fm_port_global_pram *rx_pram; /* Rx parameter table */
+ struct fm_port_global_pram *tx_pram; /* Tx parameter table */
+ void *rx_bd_ring; /* Rx BD ring base */
+ void *cur_rxbd; /* current Rx BD */
+ void *rx_buf; /* Rx buffer base */
+ void *tx_bd_ring; /* Tx BD ring base */
+ void *cur_txbd; /* current Tx BD */
+};
+
+#define RX_BD_RING_SIZE 8
+#define TX_BD_RING_SIZE 8
+#define MAX_RXBUF_LOG2 11
+#define MAX_RXBUF_LEN (1 << MAX_RXBUF_LOG2)
+
+#define PORT_IS_ENABLED(port) fm_info[fm_port_to_index(port)].enabled
+
+#endif /* __FM_H__ */
diff --git a/qemu/roms/u-boot/drivers/net/fm/init.c b/qemu/roms/u-boot/drivers/net/fm/init.c
new file mode 100644
index 000000000..cd787f4ee
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/init.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_serdes.h>
+
+#include "fm.h"
+
+struct fm_eth_info fm_info[] = {
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 1)
+ FM_DTSEC_INFO_INITIALIZER(1, 1),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 2)
+ FM_DTSEC_INFO_INITIALIZER(1, 2),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 3)
+ FM_DTSEC_INFO_INITIALIZER(1, 3),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 4)
+ FM_DTSEC_INFO_INITIALIZER(1, 4),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 5)
+ FM_DTSEC_INFO_INITIALIZER(1, 5),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 6)
+ FM_DTSEC_INFO_INITIALIZER(1, 6),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 7)
+ FM_DTSEC_INFO_INITIALIZER(1, 9),
+#endif
+#if (CONFIG_SYS_NUM_FM1_DTSEC >= 8)
+ FM_DTSEC_INFO_INITIALIZER(1, 10),
+#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 1)
+ FM_DTSEC_INFO_INITIALIZER(2, 1),
+#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 2)
+ FM_DTSEC_INFO_INITIALIZER(2, 2),
+#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 3)
+ FM_DTSEC_INFO_INITIALIZER(2, 3),
+#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 4)
+ FM_DTSEC_INFO_INITIALIZER(2, 4),
+#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 5)
+ FM_DTSEC_INFO_INITIALIZER(2, 5),
+#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 6)
+ FM_DTSEC_INFO_INITIALIZER(2, 6),
+#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 7)
+ FM_DTSEC_INFO_INITIALIZER(2, 9),
+#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 8)
+ FM_DTSEC_INFO_INITIALIZER(2, 10),
+#endif
+#if (CONFIG_SYS_NUM_FM1_10GEC >= 1)
+ FM_TGEC_INFO_INITIALIZER(1, 1),
+#endif
+#if (CONFIG_SYS_NUM_FM1_10GEC >= 2)
+ FM_TGEC_INFO_INITIALIZER(1, 2),
+#endif
+#if (CONFIG_SYS_NUM_FM1_10GEC >= 3)
+ FM_TGEC_INFO_INITIALIZER2(1, 3),
+#endif
+#if (CONFIG_SYS_NUM_FM1_10GEC >= 4)
+ FM_TGEC_INFO_INITIALIZER2(1, 4),
+#endif
+#if (CONFIG_SYS_NUM_FM2_10GEC >= 1)
+ FM_TGEC_INFO_INITIALIZER(2, 1),
+#endif
+#if (CONFIG_SYS_NUM_FM2_10GEC >= 2)
+ FM_TGEC_INFO_INITIALIZER(2, 2),
+#endif
+};
+
+int fm_standard_init(bd_t *bis)
+{
+ int i;
+ struct ccsr_fman *reg;
+
+ reg = (void *)CONFIG_SYS_FSL_FM1_ADDR;
+ if (fm_init_common(0, reg))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
+ if ((fm_info[i].enabled) && (fm_info[i].index == 1))
+ fm_eth_initialize(reg, &fm_info[i]);
+ }
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ reg = (void *)CONFIG_SYS_FSL_FM2_ADDR;
+ if (fm_init_common(1, reg))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
+ if ((fm_info[i].enabled) && (fm_info[i].index == 2))
+ fm_eth_initialize(reg, &fm_info[i]);
+ }
+#endif
+
+ return 1;
+}
+
+/* simple linear search to map from port to array index */
+static int fm_port_to_index(enum fm_port port)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
+ if (fm_info[i].port == port)
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+ * Determine if an interface is actually active based on HW config
+ * we expect fman_port_enet_if() to report PHY_INTERFACE_MODE_NONE if
+ * the interface is not active based on HW cfg of the SoC
+ */
+void fman_enet_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
+ phy_interface_t enet_if;
+
+ enet_if = fman_port_enet_if(fm_info[i].port);
+ if (enet_if != PHY_INTERFACE_MODE_NONE) {
+ fm_info[i].enabled = 1;
+ fm_info[i].enet_if = enet_if;
+ } else {
+ fm_info[i].enabled = 0;
+ }
+ }
+
+ return ;
+}
+
+void fm_disable_port(enum fm_port port)
+{
+ int i = fm_port_to_index(port);
+
+ fm_info[i].enabled = 0;
+ fman_disable_port(port);
+}
+
+void fm_enable_port(enum fm_port port)
+{
+ int i = fm_port_to_index(port);
+
+ fm_info[i].enabled = 1;
+ fman_enable_port(port);
+}
+
+void fm_info_set_mdio(enum fm_port port, struct mii_dev *bus)
+{
+ int i = fm_port_to_index(port);
+
+ if (i == -1)
+ return;
+
+ fm_info[i].bus = bus;
+}
+
+void fm_info_set_phy_address(enum fm_port port, int address)
+{
+ int i = fm_port_to_index(port);
+
+ if (i == -1)
+ return;
+
+ fm_info[i].phy_addr = address;
+}
+
+/*
+ * Returns the PHY address for a given Fman port
+ *
+ * The port must be set via a prior call to fm_info_set_phy_address().
+ * A negative error code is returned if the port is invalid.
+ */
+int fm_info_get_phy_address(enum fm_port port)
+{
+ int i = fm_port_to_index(port);
+
+ if (i == -1)
+ return -1;
+
+ return fm_info[i].phy_addr;
+}
+
+/*
+ * Returns the type of the data interface between the given MAC and its PHY.
+ * This is typically determined by the RCW.
+ */
+phy_interface_t fm_info_get_enet_if(enum fm_port port)
+{
+ int i = fm_port_to_index(port);
+
+ if (i == -1)
+ return PHY_INTERFACE_MODE_NONE;
+
+ if (fm_info[i].enabled)
+ return fm_info[i].enet_if;
+
+ return PHY_INTERFACE_MODE_NONE;
+}
+
+static void
+__def_board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
+ enum fm_port port, int offset)
+{
+ return ;
+}
+
+void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
+ enum fm_port port, int offset)
+ __attribute__((weak, alias("__def_board_ft_fman_fixup_port")));
+
+static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
+{
+ int off;
+ uint32_t ph;
+ phys_addr_t paddr = CONFIG_SYS_CCSRBAR_PHYS + info->compat_offset;
+ u64 dtsec1_addr = (u64)CONFIG_SYS_CCSRBAR_PHYS +
+ CONFIG_SYS_FSL_FM1_DTSEC1_OFFSET;
+
+ off = fdt_node_offset_by_compat_reg(blob, prop, paddr);
+
+ if (info->enabled) {
+ fdt_fixup_phy_connection(blob, off, info->enet_if);
+ board_ft_fman_fixup_port(blob, prop, paddr, info->port, off);
+ return ;
+ }
+
+#ifdef CONFIG_SYS_FMAN_V3
+ /*
+ * Physically FM1_DTSEC9 and FM1_10GEC1 use the same dual-role MAC, when
+ * FM1_10GEC1 is enabled and FM1_DTSEC9 is disabled, ensure that the
+ * dual-role MAC is not disabled, ditto for other dual-role MACs.
+ */
+ if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) ||
+ ((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) ||
+ ((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC3))) ||
+ ((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC4))) ||
+ ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) ||
+ ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10))) ||
+ ((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC1))) ||
+ ((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC2)))
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ ||
+ ((info->port == FM2_DTSEC9) && (PORT_IS_ENABLED(FM2_10GEC1))) ||
+ ((info->port == FM2_DTSEC10) && (PORT_IS_ENABLED(FM2_10GEC2))) ||
+ ((info->port == FM2_10GEC1) && (PORT_IS_ENABLED(FM2_DTSEC9))) ||
+ ((info->port == FM2_10GEC2) && (PORT_IS_ENABLED(FM2_DTSEC10)))
+#endif
+ )
+ return;
+#endif
+ /* board code might have caused offset to change */
+ off = fdt_node_offset_by_compat_reg(blob, prop, paddr);
+
+ /* Don't disable FM1-DTSEC1 MAC as its used for MDIO */
+ if (paddr != dtsec1_addr)
+ fdt_status_disabled(blob, off); /* disable the MAC node */
+
+ /* disable the fsl,dpa-ethernet node that points to the MAC */
+ ph = fdt_get_phandle(blob, off);
+ do_fixup_by_prop(blob, "fsl,fman-mac", &ph, sizeof(ph),
+ "status", "disabled", strlen("disabled") + 1, 1);
+}
+
+void fdt_fixup_fman_ethernet(void *blob)
+{
+ int i;
+
+#ifdef CONFIG_SYS_FMAN_V3
+ for (i = 0; i < ARRAY_SIZE(fm_info); i++)
+ ft_fixup_port(blob, &fm_info[i], "fsl,fman-memac");
+#else
+ for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
+ if (fm_info[i].type == FM_ETH_1G_E)
+ ft_fixup_port(blob, &fm_info[i], "fsl,fman-1g-mac");
+ else
+ ft_fixup_port(blob, &fm_info[i], "fsl,fman-10g-mac");
+ }
+#endif
+}
+
+/*QSGMII Riser Card can work in SGMII mode, but the PHY address is different.
+ *This function scans which Riser Card being used(QSGMII or SGMII Riser Card),
+ *then set the correct PHY address
+ */
+void set_sgmii_phy(struct mii_dev *bus, enum fm_port base_port,
+ unsigned int port_num, int phy_base_addr)
+{
+ unsigned int regnum = 0;
+ int qsgmii;
+ int i;
+ int phy_real_addr;
+
+ qsgmii = is_qsgmii_riser_card(bus, phy_base_addr, port_num, regnum);
+
+ if (!qsgmii)
+ return;
+
+ for (i = base_port; i < base_port + port_num; i++) {
+ if (fm_info_get_enet_if(i) == PHY_INTERFACE_MODE_SGMII) {
+ phy_real_addr = phy_base_addr + i - base_port;
+ fm_info_set_phy_address(i, phy_real_addr);
+ }
+ }
+}
+
+/*to check whether qsgmii riser card is used*/
+int is_qsgmii_riser_card(struct mii_dev *bus, int phy_base_addr,
+ unsigned int port_num, unsigned regnum)
+{
+ int i;
+ int val;
+
+ if (!bus)
+ return 0;
+
+ for (i = phy_base_addr; i < phy_base_addr + port_num; i++) {
+ val = bus->read(bus, i, MDIO_DEVAD_NONE, regnum);
+ if (val != MIIM_TIMEOUT)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/memac.c b/qemu/roms/u-boot/drivers/net/fm/memac.c
new file mode 100644
index 000000000..592a67f2a
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/memac.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Roy Zang <tie-fei.zang@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* MAXFRM - maximum frame length */
+#define MAXFRM_MASK 0x0000ffff
+
+#include <common.h>
+#include <phy.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <asm/fsl_enet.h>
+#include <asm/fsl_memac.h>
+
+#include "fm.h"
+
+static void memac_init_mac(struct fsl_enet_mac *mac)
+{
+ struct memac *regs = mac->base;
+
+ /* mask all interrupt */
+ out_be32(&regs->imask, IMASK_MASK_ALL);
+
+ /* clear all events */
+ out_be32(&regs->ievent, IEVENT_CLEAR_ALL);
+
+ /* set the max receive length */
+ out_be32(&regs->maxfrm, mac->max_rx_len & MAXFRM_MASK);
+
+ /* multicast frame reception for the hash entry disable */
+ out_be32(&regs->hashtable_ctrl, 0);
+}
+
+static void memac_enable_mac(struct fsl_enet_mac *mac)
+{
+ struct memac *regs = mac->base;
+
+ setbits_be32(&regs->command_config, MEMAC_CMD_CFG_RXTX_EN);
+}
+
+static void memac_disable_mac(struct fsl_enet_mac *mac)
+{
+ struct memac *regs = mac->base;
+
+ clrbits_be32(&regs->command_config, MEMAC_CMD_CFG_RXTX_EN);
+}
+
+static void memac_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr)
+{
+ struct memac *regs = mac->base;
+ u32 mac_addr0, mac_addr1;
+
+ /*
+ * if a station address of 0x12345678ABCD, perform a write to
+ * MAC_ADDR0 of 0x78563412, MAC_ADDR1 of 0x0000CDAB
+ */
+ mac_addr0 = (mac_addr[3] << 24) | (mac_addr[2] << 16) | \
+ (mac_addr[1] << 8) | (mac_addr[0]);
+ out_be32(&regs->mac_addr_0, mac_addr0);
+
+ mac_addr1 = ((mac_addr[5] << 8) | mac_addr[4]) & 0x0000ffff;
+ out_be32(&regs->mac_addr_1, mac_addr1);
+}
+
+static void memac_set_interface_mode(struct fsl_enet_mac *mac,
+ phy_interface_t type, int speed)
+{
+ /* Roy need more work here */
+
+ struct memac *regs = mac->base;
+ u32 if_mode, if_status;
+
+ /* clear all bits relative with interface mode */
+ if_mode = in_be32(&regs->if_mode);
+ if_status = in_be32(&regs->if_status);
+
+ /* set interface mode */
+ switch (type) {
+ case PHY_INTERFACE_MODE_GMII:
+ if_mode &= ~IF_MODE_MASK;
+ if_mode |= IF_MODE_GMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ if_mode |= (IF_MODE_GMII | IF_MODE_RG);
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if_mode |= (IF_MODE_GMII | IF_MODE_RM);
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ if_mode &= ~IF_MODE_MASK;
+ if_mode |= (IF_MODE_GMII);
+ break;
+ default:
+ break;
+ }
+ /* Enable automatic speed selection */
+ if_mode |= IF_MODE_EN_AUTO;
+
+ if (type == PHY_INTERFACE_MODE_RGMII) {
+ if_mode &= ~IF_MODE_EN_AUTO;
+ if_mode &= ~IF_MODE_SETSP_MASK;
+ switch (speed) {
+ case SPEED_1000:
+ if_mode |= IF_MODE_SETSP_1000M;
+ break;
+ case SPEED_100:
+ if_mode |= IF_MODE_SETSP_100M;
+ break;
+ case SPEED_10:
+ if_mode |= IF_MODE_SETSP_10M;
+ default:
+ break;
+ }
+ }
+
+ debug(" %s, if_mode = %x\n", __func__, if_mode);
+ debug(" %s, if_status = %x\n", __func__, if_status);
+ out_be32(&regs->if_mode, if_mode);
+ return;
+}
+
+void init_memac(struct fsl_enet_mac *mac, void *base,
+ void *phyregs, int max_rx_len)
+{
+ mac->base = base;
+ mac->phyregs = phyregs;
+ mac->max_rx_len = max_rx_len;
+ mac->init_mac = memac_init_mac;
+ mac->enable_mac = memac_enable_mac;
+ mac->disable_mac = memac_disable_mac;
+ mac->set_mac_addr = memac_set_mac_addr;
+ mac->set_if_mode = memac_set_interface_mode;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/memac_phy.c b/qemu/roms/u-boot/drivers/net/fm/memac_phy.c
new file mode 100644
index 000000000..de9c0e9cd
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/memac_phy.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Andy Fleming <afleming@freescale.com>
+ * Roy Zang <tie-fei.zang@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ * Some part is taken from tsec.c
+ */
+#include <common.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <asm/io.h>
+#include <asm/fsl_memac.h>
+#include <fm_eth.h>
+
+/*
+ * Write value to the PHY for this device to the register at regnum, waiting
+ * until the write is done before it returns. All PHY configuration has to be
+ * done through the TSEC1 MIIM regs
+ */
+int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
+ int regnum, u16 value)
+{
+ u32 mdio_ctl;
+ struct memac_mdio_controller *regs = bus->priv;
+ u32 c45 = 1; /* Default to 10G interface */
+
+ if (dev_addr == MDIO_DEVAD_NONE) {
+ c45 = 0; /* clause 22 */
+ dev_addr = regnum & 0x1f;
+ clrbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
+ } else
+ setbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
+
+ /* Wait till the bus is free */
+ while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Set the port and dev addr */
+ mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
+ out_be32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Set the register address */
+ if (c45)
+ out_be32(&regs->mdio_addr, regnum & 0xffff);
+
+ /* Wait till the bus is free */
+ while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Write the value to the register */
+ out_be32(&regs->mdio_data, MDIO_DATA(value));
+
+ /* Wait till the MDIO write is complete */
+ while ((in_be32(&regs->mdio_data)) & MDIO_DATA_BSY)
+ ;
+
+ return 0;
+}
+
+/*
+ * Reads from register regnum in the PHY for device dev, returning the value.
+ * Clears miimcom first. All PHY configuration has to be done through the
+ * TSEC1 MIIM regs
+ */
+int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
+ int regnum)
+{
+ u32 mdio_ctl;
+ struct memac_mdio_controller *regs = bus->priv;
+ u32 c45 = 1;
+
+ if (dev_addr == MDIO_DEVAD_NONE) {
+ c45 = 0; /* clause 22 */
+ dev_addr = regnum & 0x1f;
+ clrbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
+ } else
+ setbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
+
+ /* Wait till the bus is free */
+ while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Set the Port and Device Addrs */
+ mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
+ out_be32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Set the register address */
+ if (c45)
+ out_be32(&regs->mdio_addr, regnum & 0xffff);
+
+ /* Wait till the bus is free */
+ while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Initiate the read */
+ mdio_ctl |= MDIO_CTL_READ;
+ out_be32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Wait till the MDIO write is complete */
+ while ((in_be32(&regs->mdio_data)) & MDIO_DATA_BSY)
+ ;
+
+ /* Return all Fs if nothing was there */
+ if (in_be32(&regs->mdio_stat) & MDIO_STAT_RD_ER)
+ return 0xffff;
+
+ return in_be32(&regs->mdio_data) & 0xffff;
+}
+
+int memac_mdio_reset(struct mii_dev *bus)
+{
+ return 0;
+}
+
+int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info)
+{
+ struct mii_dev *bus = mdio_alloc();
+
+ if (!bus) {
+ printf("Failed to allocate FM TGEC MDIO bus\n");
+ return -1;
+ }
+
+ bus->read = memac_mdio_read;
+ bus->write = memac_mdio_write;
+ bus->reset = memac_mdio_reset;
+ sprintf(bus->name, info->name);
+
+ bus->priv = info->regs;
+
+ /*
+ * On some platforms like B4860, default value of MDIO_CLK_DIV bits
+ * in mdio_stat(mdio_cfg) register generates MDIO clock too high
+ * (much higher than 2.5MHz), violating the IEEE specs.
+ * On other platforms like T1040, default value of MDIO_CLK_DIV bits
+ * is zero, so MDIO clock is disabled.
+ * So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to
+ * be properly initialized.
+ */
+ setbits_be32(&((struct memac_mdio_controller *)info->regs)->mdio_stat,
+ MDIO_STAT_CLKDIV(258));
+
+ return mdio_register(bus);
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/p1023.c b/qemu/roms/u-boot/drivers/net/fm/p1023.c
new file mode 100644
index 000000000..b25d10ae0
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/p1023.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+static u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = MPC85xx_DEVDISR_TSEC1,
+ [FM1_DTSEC2] = MPC85xx_DEVDISR_TSEC2,
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr = in_be32(&gur->devdisr);
+
+ return port_to_devdisr[port] & devdisr;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ /* don't allow disabling of DTSEC1 as its needed for MDIO */
+ if (port == FM1_DTSEC1)
+ return;
+
+ setbits_be32(&gur->devdisr, port_to_devdisr[port]);
+}
+
+void fman_enable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ clrbits_be32(&gur->devdisr, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 pordevsr = in_be32(&gur->pordevsr);
+
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ /* DTSEC1 can be SGMII, RGMII or RMII */
+ if (port == FM1_DTSEC1) {
+ if (is_serdes_configured(SGMII_FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ if (pordevsr & MPC85xx_PORDEVSR_SGMII1_DIS) {
+ if (pordevsr & MPC85xx_PORDEVSR_TSEC1_PRTC)
+ return PHY_INTERFACE_MODE_RGMII;
+ else
+ return PHY_INTERFACE_MODE_RMII;
+ }
+ }
+
+ /* DTSEC2 only supports SGMII or RGMII */
+ if (port == FM1_DTSEC2) {
+ if (is_serdes_configured(SGMII_FM1_DTSEC2))
+ return PHY_INTERFACE_MODE_SGMII;
+ if (pordevsr & MPC85xx_PORDEVSR_SGMII2_DIS)
+ return PHY_INTERFACE_MODE_RGMII;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/p4080.c b/qemu/roms/u-boot/drivers/net/fm/p4080.c
new file mode 100644
index 000000000..de7191135
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/p4080.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+static u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
+ [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
+ [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
+ [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
+ [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1,
+ [FM2_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC2_1,
+ [FM2_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC2_2,
+ [FM2_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC2_3,
+ [FM2_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC2_4,
+ [FM2_10GEC1] = FSL_CORENET_DEVDISR2_10GEC2,
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr2 = in_be32(&gur->devdisr2);
+
+ return port_to_devdisr[port] & devdisr2;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ /* don't allow disabling of DTSEC1 as its needed for MDIO */
+ if (port == FM1_DTSEC1)
+ return;
+
+ setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+void fman_enable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
+
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ if ((port == FM1_10GEC1) && (is_serdes_configured(XAUI_FM1)))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ if ((port == FM2_10GEC1) && (is_serdes_configured(XAUI_FM2)))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ /* handle RGMII first */
+ if ((port == FM1_DTSEC1) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
+ FSL_CORENET_RCWSR11_EC1_FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC2) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
+ FSL_CORENET_RCWSR11_EC2_FM1_DTSEC2))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM2_DTSEC1) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
+ FSL_CORENET_RCWSR11_EC2_FM2_DTSEC1))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ case FM2_DTSEC1:
+ case FM2_DTSEC2:
+ case FM2_DTSEC3:
+ case FM2_DTSEC4:
+ if (is_serdes_configured(SGMII_FM2_DTSEC1 + port - FM2_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ default:
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/p5020.c b/qemu/roms/u-boot/drivers/net/fm/p5020.c
new file mode 100644
index 000000000..5c158cd5d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/p5020.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+static u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
+ [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
+ [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
+ [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
+ [FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
+ [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1,
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr2 = in_be32(&gur->devdisr2);
+
+ return port_to_devdisr[port] & devdisr2;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ /* don't allow disabling of DTSEC1 as its needed for MDIO */
+ if (port == FM1_DTSEC1)
+ return;
+
+ setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+void fman_enable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
+
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ if ((port == FM1_10GEC1) && (is_serdes_configured(XAUI_FM1)))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ /* handle RGMII first */
+ if ((port == FM1_DTSEC4) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
+ FSL_CORENET_RCWSR11_EC1_FM1_DTSEC4_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC4) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
+ FSL_CORENET_RCWSR11_EC1_FM1_DTSEC4_MII))
+ return PHY_INTERFACE_MODE_MII;
+
+ if ((port == FM1_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
+ FSL_CORENET_RCWSR11_EC2_FM1_DTSEC5_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
+ FSL_CORENET_RCWSR11_EC2_FM1_DTSEC5_MII))
+ return PHY_INTERFACE_MODE_MII;
+
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ case FM1_DTSEC5:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ default:
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/p5040.c b/qemu/roms/u-boot/drivers/net/fm/p5040.c
new file mode 100644
index 000000000..403d7d794
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/p5040.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
+ [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
+ [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
+ [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
+ [FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
+ [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1,
+ [FM2_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC2_1,
+ [FM2_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC2_2,
+ [FM2_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC2_3,
+ [FM2_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC2_4,
+ [FM2_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC2_5,
+ [FM2_10GEC1] = FSL_CORENET_DEVDISR2_10GEC2,
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr2 = in_be32(&gur->devdisr2);
+
+ return port_to_devdisr[port] & devdisr2;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ /* don't allow disabling of DTSEC1 as its needed for MDIO */
+ if (port == FM1_DTSEC1)
+ return;
+
+ setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+void fman_enable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
+
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ if ((port == FM1_10GEC1) && (is_serdes_configured(XAUI_FM1)))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ if ((port == FM2_10GEC1) && (is_serdes_configured(XAUI_FM2)))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ /* handle RGMII first */
+ if ((port == FM1_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
+ FSL_CORENET_RCWSR11_EC1_FM1_DTSEC5_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
+ FSL_CORENET_RCWSR11_EC1_FM1_DTSEC5_MII))
+ return PHY_INTERFACE_MODE_MII;
+
+ if ((port == FM2_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
+ FSL_CORENET_RCWSR11_EC2_FM2_DTSEC5_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM2_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
+ FSL_CORENET_RCWSR11_EC2_FM2_DTSEC5_MII))
+ return PHY_INTERFACE_MODE_MII;
+
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ case FM1_DTSEC5:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ case FM2_DTSEC1:
+ case FM2_DTSEC2:
+ case FM2_DTSEC3:
+ case FM2_DTSEC4:
+ case FM2_DTSEC5:
+ if (is_serdes_configured(SGMII_FM2_DTSEC1 + port - FM2_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ default:
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/t1040.c b/qemu/roms/u-boot/drivers/net/fm/t1040.c
new file mode 100644
index 000000000..bcc871d84
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/t1040.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
+
+ /* handle RGMII first */
+ if ((port == FM1_DTSEC2) &&
+ ((rcwsr13 & FSL_CORENET_RCWSR13_MAC2_GMII_SEL) ==
+ FSL_CORENET_RCWSR13_MAC2_GMII_SEL_ENET_PORT)) {
+ if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
+ FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_RGMII)
+ return PHY_INTERFACE_MODE_RGMII;
+ else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
+ FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII)
+ return PHY_INTERFACE_MODE_MII;
+ else
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ if ((port == FM1_DTSEC4) &&
+ ((rcwsr13 & FSL_CORENET_RCWSR13_MAC2_GMII_SEL) ==
+ FSL_CORENET_RCWSR13_MAC2_GMII_SEL_L2_SWITCH)) {
+ if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
+ FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_RGMII)
+ return PHY_INTERFACE_MODE_RGMII;
+ else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
+ FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII)
+ return PHY_INTERFACE_MODE_MII;
+ else
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ if (port == FM1_DTSEC5) {
+ if ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
+ FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_RGMII)
+ return PHY_INTERFACE_MODE_RGMII;
+ else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
+ FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_MII)
+ return PHY_INTERFACE_MODE_MII;
+ else
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ if (is_serdes_configured(QSGMII_SW1_A + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_QSGMII;
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ case FM1_DTSEC5:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ default:
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/t2080.c b/qemu/roms/u-boot/drivers/net/fm/t2080.c
new file mode 100644
index 000000000..3b6212f85
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/t2080.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * Shengzhou Liu <Shengzhou.Liu@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
+ [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
+ [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
+ [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
+ [FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
+ [FM1_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC1_6,
+ [FM1_DTSEC9] = FSL_CORENET_DEVDISR2_DTSEC1_9,
+ [FM1_DTSEC10] = FSL_CORENET_DEVDISR2_DTSEC1_10,
+ [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1,
+ [FM1_10GEC2] = FSL_CORENET_DEVDISR2_10GEC1_2,
+ [FM1_10GEC3] = FSL_CORENET_DEVDISR2_10GEC1_3,
+ [FM1_10GEC4] = FSL_CORENET_DEVDISR2_10GEC1_4,
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr2 = in_be32(&gur->devdisr2);
+
+ return port_to_devdisr[port] & devdisr2;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
+
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
+ ((is_serdes_configured(XAUI_FM1_MAC9)) ||
+ (is_serdes_configured(XFI_FM1_MAC9)) ||
+ (is_serdes_configured(XFI_FM1_MAC10))))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ if ((port == FM1_10GEC3 || port == FM1_10GEC4) &&
+ ((is_serdes_configured(XFI_FM1_MAC1)) ||
+ (is_serdes_configured(XFI_FM1_MAC2))))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ if ((port == FM1_DTSEC3) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
+ FSL_CORENET_RCWSR13_EC1_DTSEC3_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC4) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
+ FSL_CORENET_RCWSR13_EC2_DTSEC4_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC10) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
+ FSL_CORENET_RCWSR13_EC2_DTSEC10_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ case FM1_DTSEC5:
+ case FM1_DTSEC6:
+ case FM1_DTSEC9:
+ case FM1_DTSEC10:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ default:
+ return PHY_INTERFACE_MODE_NONE;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/t4240.c b/qemu/roms/u-boot/drivers/net/fm/t4240.c
new file mode 100644
index 000000000..1eacb2284
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/t4240.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Roy Zang <tie-fei.zang@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
+ [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
+ [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
+ [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
+ [FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
+ [FM1_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC1_6,
+ [FM1_DTSEC9] = FSL_CORENET_DEVDISR2_DTSEC1_9,
+ [FM1_DTSEC10] = FSL_CORENET_DEVDISR2_DTSEC1_10,
+ [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1,
+ [FM1_10GEC2] = FSL_CORENET_DEVDISR2_10GEC1_2,
+ [FM2_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC2_1,
+ [FM2_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC2_2,
+ [FM2_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC2_3,
+ [FM2_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC2_4,
+ [FM2_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC2_5,
+ [FM2_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC2_6,
+ [FM2_DTSEC9] = FSL_CORENET_DEVDISR2_DTSEC2_9,
+ [FM2_DTSEC10] = FSL_CORENET_DEVDISR2_DTSEC2_10,
+ [FM2_10GEC1] = FSL_CORENET_DEVDISR2_10GEC2_1,
+ [FM2_10GEC2] = FSL_CORENET_DEVDISR2_10GEC2_2,
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr2 = in_be32(&gur->devdisr2);
+
+ return port_to_devdisr[port] & devdisr2;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+void fman_enable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
+
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
+ ((is_serdes_configured(XAUI_FM1_MAC9)) ||
+ (is_serdes_configured(XAUI_FM1_MAC10)) ||
+ (is_serdes_configured(XFI_FM1_MAC9)) ||
+ (is_serdes_configured(XFI_FM1_MAC10))))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ if ((port == FM2_10GEC1 || port == FM2_10GEC2) &&
+ ((is_serdes_configured(XAUI_FM2_MAC9)) ||
+ (is_serdes_configured(XAUI_FM2_MAC10)) ||
+ (is_serdes_configured(XFI_FM2_MAC9)) ||
+ (is_serdes_configured(XFI_FM2_MAC10))))
+ return PHY_INTERFACE_MODE_XGMII;
+
+#define FSL_CORENET_RCWSR13_EC1 0x60000000 /* bits 417..418 */
+#define FSL_CORENET_RCWSR13_EC1_FM2_DTSEC5_RGMII 0x00000000
+#define FSL_CORENET_RCWSR13_EC1_FM2_GPIO 0x40000000
+#define FSL_CORENET_RCWSR13_EC2 0x18000000 /* bits 419..420 */
+#define FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_RGMII 0x00000000
+#define FSL_CORENET_RCWSR13_EC2_FM2_DTSEC6_RGMII 0x08000000
+#define FSL_CORENET_RCWSR13_EC2_FM1_GPIO 0x10000000
+ /* handle RGMII first */
+ if ((port == FM2_DTSEC5) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
+ FSL_CORENET_RCWSR13_EC1_FM2_DTSEC5_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC5) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
+ FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM2_DTSEC6) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
+ FSL_CORENET_RCWSR13_EC2_FM2_DTSEC6_RGMII))
+ return PHY_INTERFACE_MODE_RGMII;
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ case FM1_DTSEC5:
+ case FM1_DTSEC6:
+ case FM1_DTSEC9:
+ case FM1_DTSEC10:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ case FM2_DTSEC1:
+ case FM2_DTSEC2:
+ case FM2_DTSEC3:
+ case FM2_DTSEC4:
+ case FM2_DTSEC5:
+ case FM2_DTSEC6:
+ case FM2_DTSEC9:
+ case FM2_DTSEC10:
+ if (is_serdes_configured(SGMII_FM2_DTSEC1 + port - FM2_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ break;
+ default:
+ break;
+ }
+
+ /* handle QSGMII */
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ /* check lane G on SerDes1 */
+ if (is_serdes_configured(QSGMII_FM1_A))
+ return PHY_INTERFACE_MODE_QSGMII;
+ break;
+ case FM1_DTSEC5:
+ case FM1_DTSEC6:
+ case FM1_DTSEC9:
+ case FM1_DTSEC10:
+ /* check lane C on SerDes1 */
+ if (is_serdes_configured(QSGMII_FM1_B))
+ return PHY_INTERFACE_MODE_QSGMII;
+ break;
+ case FM2_DTSEC1:
+ case FM2_DTSEC2:
+ case FM2_DTSEC3:
+ case FM2_DTSEC4:
+ /* check lane G on SerDes2 */
+ if (is_serdes_configured(QSGMII_FM2_A))
+ return PHY_INTERFACE_MODE_QSGMII;
+ break;
+ case FM2_DTSEC5:
+ case FM2_DTSEC6:
+ case FM2_DTSEC9:
+ case FM2_DTSEC10:
+ /* check lane C on SerDes2 */
+ if (is_serdes_configured(QSGMII_FM2_B))
+ return PHY_INTERFACE_MODE_QSGMII;
+ break;
+ default:
+ break;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/tgec.c b/qemu/roms/u-boot/drivers/net/fm/tgec.c
new file mode 100644
index 000000000..f450f800e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/tgec.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* MAXFRM - maximum frame length */
+#define MAXFRM_MASK 0x0000ffff
+
+#include <common.h>
+#include <phy.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <asm/fsl_enet.h>
+#include <asm/fsl_tgec.h>
+
+#include "fm.h"
+
+#define TGEC_CMD_CFG_INIT (TGEC_CMD_CFG_NO_LEN_CHK | \
+ TGEC_CMD_CFG_RX_ER_DISC | \
+ TGEC_CMD_CFG_STAT_CLR | \
+ TGEC_CMD_CFG_PAUSE_IGNORE | \
+ TGEC_CMD_CFG_CRC_FWD)
+#define TGEC_CMD_CFG_FINAL (TGEC_CMD_CFG_NO_LEN_CHK | \
+ TGEC_CMD_CFG_RX_ER_DISC | \
+ TGEC_CMD_CFG_PAUSE_IGNORE | \
+ TGEC_CMD_CFG_CRC_FWD)
+
+static void tgec_init_mac(struct fsl_enet_mac *mac)
+{
+ struct tgec *regs = mac->base;
+
+ /* mask all interrupt */
+ out_be32(&regs->imask, IMASK_MASK_ALL);
+
+ /* clear all events */
+ out_be32(&regs->ievent, IEVENT_CLEAR_ALL);
+
+ /* set the max receive length */
+ out_be32(&regs->maxfrm, mac->max_rx_len & MAXFRM_MASK);
+
+ /*
+ * 1588 disable, insert second mac disable payload length check
+ * disable, normal operation, any rx error frame is discarded, clear
+ * counters, pause frame ignore, no promiscuous, LAN mode Rx CRC no
+ * strip, Tx CRC append, Rx disable and Tx disable
+ */
+ out_be32(&regs->command_config, TGEC_CMD_CFG_INIT);
+ udelay(1000);
+ out_be32(&regs->command_config, TGEC_CMD_CFG_FINAL);
+
+ /* multicast frame reception for the hash entry disable */
+ out_be32(&regs->hashtable_ctrl, 0);
+}
+
+static void tgec_enable_mac(struct fsl_enet_mac *mac)
+{
+ struct tgec *regs = mac->base;
+
+ setbits_be32(&regs->command_config, TGEC_CMD_CFG_RXTX_EN);
+}
+
+static void tgec_disable_mac(struct fsl_enet_mac *mac)
+{
+ struct tgec *regs = mac->base;
+
+ clrbits_be32(&regs->command_config, TGEC_CMD_CFG_RXTX_EN);
+}
+
+static void tgec_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr)
+{
+ struct tgec *regs = mac->base;
+ u32 mac_addr0, mac_addr1;
+
+ /*
+ * if a station address of 0x12345678ABCD, perform a write to
+ * MAC_ADDR0 of 0x78563412, MAC_ADDR1 of 0x0000CDAB
+ */
+ mac_addr0 = (mac_addr[3] << 24) | (mac_addr[2] << 16) | \
+ (mac_addr[1] << 8) | (mac_addr[0]);
+ out_be32(&regs->mac_addr_0, mac_addr0);
+
+ mac_addr1 = ((mac_addr[5] << 8) | mac_addr[4]) & 0x0000ffff;
+ out_be32(&regs->mac_addr_1, mac_addr1);
+}
+
+static void tgec_set_interface_mode(struct fsl_enet_mac *mac,
+ phy_interface_t type, int speed)
+{
+ /* nothing right now */
+ return;
+}
+
+void init_tgec(struct fsl_enet_mac *mac, void *base,
+ void *phyregs, int max_rx_len)
+{
+ mac->base = base;
+ mac->phyregs = phyregs;
+ mac->max_rx_len = max_rx_len;
+ mac->init_mac = tgec_init_mac;
+ mac->enable_mac = tgec_enable_mac;
+ mac->disable_mac = tgec_disable_mac;
+ mac->set_mac_addr = tgec_set_mac_addr;
+ mac->set_if_mode = tgec_set_interface_mode;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fm/tgec_phy.c b/qemu/roms/u-boot/drivers/net/fm/tgec_phy.c
new file mode 100644
index 000000000..faec317a0
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fm/tgec_phy.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ * Andy Fleming <afleming@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ * Some part is taken from tsec.c
+ */
+#include <common.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <asm/io.h>
+#include <asm/fsl_tgec.h>
+#include <fm_eth.h>
+
+/*
+ * Write value to the PHY for this device to the register at regnum, waiting
+ * until the write is done before it returns. All PHY configuration has to be
+ * done through the TSEC1 MIIM regs
+ */
+static int tgec_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
+ int regnum, u16 value)
+{
+ u32 mdio_ctl;
+ u32 stat_val;
+ struct tgec_mdio_controller *regs = bus->priv;
+
+ if (dev_addr == MDIO_DEVAD_NONE)
+ return 0;
+
+ /* Wait till the bus is free */
+ stat_val = MDIO_STAT_CLKDIV(100);
+ out_be32(&regs->mdio_stat, stat_val);
+ while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Set the port and dev addr */
+ mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
+ out_be32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Set the register address */
+ out_be32(&regs->mdio_addr, regnum & 0xffff);
+
+ /* Wait till the bus is free */
+ while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Write the value to the register */
+ out_be32(&regs->mdio_data, MDIO_DATA(value));
+
+ /* Wait till the MDIO write is complete */
+ while ((in_be32(&regs->mdio_data)) & MDIO_DATA_BSY)
+ ;
+
+ return 0;
+}
+
+/*
+ * Reads from register regnum in the PHY for device dev, returning the value.
+ * Clears miimcom first. All PHY configuration has to be done through the
+ * TSEC1 MIIM regs
+ */
+static int tgec_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
+ int regnum)
+{
+ u32 mdio_ctl;
+ u32 stat_val;
+ struct tgec_mdio_controller *regs = bus->priv;
+
+ if (dev_addr == MDIO_DEVAD_NONE)
+ return 0xffff;
+
+ stat_val = MDIO_STAT_CLKDIV(100);
+ out_be32(&regs->mdio_stat, stat_val);
+ /* Wait till the bus is free */
+ while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Set the Port and Device Addrs */
+ mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
+ out_be32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Set the register address */
+ out_be32(&regs->mdio_addr, regnum & 0xffff);
+
+ /* Wait till the bus is free */
+ while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
+ ;
+
+ /* Initiate the read */
+ mdio_ctl |= MDIO_CTL_READ;
+ out_be32(&regs->mdio_ctl, mdio_ctl);
+
+ /* Wait till the MDIO write is complete */
+ while ((in_be32(&regs->mdio_data)) & MDIO_DATA_BSY)
+ ;
+
+ /* Return all Fs if nothing was there */
+ if (in_be32(&regs->mdio_stat) & MDIO_STAT_RD_ER)
+ return 0xffff;
+
+ return in_be32(&regs->mdio_data) & 0xffff;
+}
+
+static int tgec_mdio_reset(struct mii_dev *bus)
+{
+ return 0;
+}
+
+int fm_tgec_mdio_init(bd_t *bis, struct tgec_mdio_info *info)
+{
+ struct mii_dev *bus = mdio_alloc();
+
+ if (!bus) {
+ printf("Failed to allocate FM TGEC MDIO bus\n");
+ return -1;
+ }
+
+ bus->read = tgec_mdio_read;
+ bus->write = tgec_mdio_write;
+ bus->reset = tgec_mdio_reset;
+ sprintf(bus->name, info->name);
+
+ bus->priv = info->regs;
+
+ return mdio_register(bus);
+}
diff --git a/qemu/roms/u-boot/drivers/net/fsl_mcdmafec.c b/qemu/roms/u-boot/drivers/net/fsl_mcdmafec.c
new file mode 100644
index 000000000..6391f9b32
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fsl_mcdmafec.c
@@ -0,0 +1,571 @@
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2007 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <miiphy.h>
+
+#undef ET_DEBUG
+#undef MII_DEBUG
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+#define PKT_MAXBLR_SIZE 1536
+#define LAST_PKTBUFSRX PKTBUFSRX - 1
+#define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY)
+#define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST)
+#define FIFO_ERRSTAT (FIFO_STAT_RXW | FIFO_STAT_UF | FIFO_STAT_OF)
+
+/* RxBD bits definitions */
+#define BD_ENET_RX_ERR (BD_ENET_RX_LG | BD_ENET_RX_NO | BD_ENET_RX_CR | \
+ BD_ENET_RX_OV | BD_ENET_RX_TR)
+
+#include <asm/immap.h>
+#include <asm/fsl_mcdmafec.h>
+
+#include "MCD_dma.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct fec_info_dma fec_info[] = {
+#ifdef CONFIG_SYS_FEC0_IOBASE
+ {
+ 0, /* index */
+ CONFIG_SYS_FEC0_IOBASE, /* io base */
+ CONFIG_SYS_FEC0_PINMUX, /* gpio pin muxing */
+ CONFIG_SYS_FEC0_MIIBASE, /* mii base */
+ -1, /* phy_addr */
+ 0, /* duplex and speed */
+ 0, /* phy name */
+ 0, /* phyname init */
+ 0, /* RX BD */
+ 0, /* TX BD */
+ 0, /* rx Index */
+ 0, /* tx Index */
+ 0, /* tx buffer */
+ 0, /* initialized flag */
+ (struct fec_info_dma *)-1, /* next */
+ FEC0_RX_TASK, /* rxTask */
+ FEC0_TX_TASK, /* txTask */
+ FEC0_RX_PRIORITY, /* rxPri */
+ FEC0_TX_PRIORITY, /* txPri */
+ FEC0_RX_INIT, /* rxInit */
+ FEC0_TX_INIT, /* txInit */
+ 0, /* usedTbdIndex */
+ 0, /* cleanTbdNum */
+ },
+#endif
+#ifdef CONFIG_SYS_FEC1_IOBASE
+ {
+ 1, /* index */
+ CONFIG_SYS_FEC1_IOBASE, /* io base */
+ CONFIG_SYS_FEC1_PINMUX, /* gpio pin muxing */
+ CONFIG_SYS_FEC1_MIIBASE, /* mii base */
+ -1, /* phy_addr */
+ 0, /* duplex and speed */
+ 0, /* phy name */
+ 0, /* phy name init */
+#ifdef CONFIG_SYS_DMA_USE_INTSRAM
+ (cbd_t *)DBUF_LENGTH, /* RX BD */
+#else
+ 0, /* RX BD */
+#endif
+ 0, /* TX BD */
+ 0, /* rx Index */
+ 0, /* tx Index */
+ 0, /* tx buffer */
+ 0, /* initialized flag */
+ (struct fec_info_dma *)-1, /* next */
+ FEC1_RX_TASK, /* rxTask */
+ FEC1_TX_TASK, /* txTask */
+ FEC1_RX_PRIORITY, /* rxPri */
+ FEC1_TX_PRIORITY, /* txPri */
+ FEC1_RX_INIT, /* rxInit */
+ FEC1_TX_INIT, /* txInit */
+ 0, /* usedTbdIndex */
+ 0, /* cleanTbdNum */
+ }
+#endif
+};
+
+static int fec_send(struct eth_device *dev, void *packet, int length);
+static int fec_recv(struct eth_device *dev);
+static int fec_init(struct eth_device *dev, bd_t * bd);
+static void fec_halt(struct eth_device *dev);
+
+#ifdef ET_DEBUG
+static void dbg_fec_regs(struct eth_device *dev)
+{
+ struct fec_info_dma *info = dev->priv;
+ volatile fecdma_t *fecp = (fecdma_t *) (info->iobase);
+
+ printf("=====\n");
+ printf("ievent %x - %x\n", (int)&fecp->eir, fecp->eir);
+ printf("imask %x - %x\n", (int)&fecp->eimr, fecp->eimr);
+ printf("ecntrl %x - %x\n", (int)&fecp->ecr, fecp->ecr);
+ printf("mii_mframe %x - %x\n", (int)&fecp->mmfr, fecp->mmfr);
+ printf("mii_speed %x - %x\n", (int)&fecp->mscr, fecp->mscr);
+ printf("mii_ctrlstat %x - %x\n", (int)&fecp->mibc, fecp->mibc);
+ printf("r_cntrl %x - %x\n", (int)&fecp->rcr, fecp->rcr);
+ printf("r hash %x - %x\n", (int)&fecp->rhr, fecp->rhr);
+ printf("x_cntrl %x - %x\n", (int)&fecp->tcr, fecp->tcr);
+ printf("padr_l %x - %x\n", (int)&fecp->palr, fecp->palr);
+ printf("padr_u %x - %x\n", (int)&fecp->paur, fecp->paur);
+ printf("op_pause %x - %x\n", (int)&fecp->opd, fecp->opd);
+ printf("iadr_u %x - %x\n", (int)&fecp->iaur, fecp->iaur);
+ printf("iadr_l %x - %x\n", (int)&fecp->ialr, fecp->ialr);
+ printf("gadr_u %x - %x\n", (int)&fecp->gaur, fecp->gaur);
+ printf("gadr_l %x - %x\n", (int)&fecp->galr, fecp->galr);
+ printf("x_wmrk %x - %x\n", (int)&fecp->tfwr, fecp->tfwr);
+ printf("r_fdata %x - %x\n", (int)&fecp->rfdr, fecp->rfdr);
+ printf("r_fstat %x - %x\n", (int)&fecp->rfsr, fecp->rfsr);
+ printf("r_fctrl %x - %x\n", (int)&fecp->rfcr, fecp->rfcr);
+ printf("r_flrfp %x - %x\n", (int)&fecp->rlrfp, fecp->rlrfp);
+ printf("r_flwfp %x - %x\n", (int)&fecp->rlwfp, fecp->rlwfp);
+ printf("r_frfar %x - %x\n", (int)&fecp->rfar, fecp->rfar);
+ printf("r_frfrp %x - %x\n", (int)&fecp->rfrp, fecp->rfrp);
+ printf("r_frfwp %x - %x\n", (int)&fecp->rfwp, fecp->rfwp);
+ printf("t_fdata %x - %x\n", (int)&fecp->tfdr, fecp->tfdr);
+ printf("t_fstat %x - %x\n", (int)&fecp->tfsr, fecp->tfsr);
+ printf("t_fctrl %x - %x\n", (int)&fecp->tfcr, fecp->tfcr);
+ printf("t_flrfp %x - %x\n", (int)&fecp->tlrfp, fecp->tlrfp);
+ printf("t_flwfp %x - %x\n", (int)&fecp->tlwfp, fecp->tlwfp);
+ printf("t_ftfar %x - %x\n", (int)&fecp->tfar, fecp->tfar);
+ printf("t_ftfrp %x - %x\n", (int)&fecp->tfrp, fecp->tfrp);
+ printf("t_ftfwp %x - %x\n", (int)&fecp->tfwp, fecp->tfwp);
+ printf("frst %x - %x\n", (int)&fecp->frst, fecp->frst);
+ printf("ctcwr %x - %x\n", (int)&fecp->ctcwr, fecp->ctcwr);
+}
+#endif
+
+static void set_fec_duplex_speed(volatile fecdma_t * fecp, bd_t * bd,
+ int dup_spd)
+{
+ if ((dup_spd >> 16) == FULL) {
+ /* Set maximum frame length */
+ fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE |
+ FEC_RCR_PROM | 0x100;
+ fecp->tcr = FEC_TCR_FDEN;
+ } else {
+ /* Half duplex mode */
+ fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) |
+ FEC_RCR_MII_MODE | FEC_RCR_DRT;
+ fecp->tcr &= ~FEC_TCR_FDEN;
+ }
+
+ if ((dup_spd & 0xFFFF) == _100BASET) {
+#ifdef MII_DEBUG
+ printf("100Mbps\n");
+#endif
+ bd->bi_ethspeed = 100;
+ } else {
+#ifdef MII_DEBUG
+ printf("10Mbps\n");
+#endif
+ bd->bi_ethspeed = 10;
+ }
+}
+
+static int fec_send(struct eth_device *dev, void *packet, int length)
+{
+ struct fec_info_dma *info = dev->priv;
+ cbd_t *pTbd, *pUsedTbd;
+ u16 phyStatus;
+
+ miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phyStatus);
+
+ /* process all the consumed TBDs */
+ while (info->cleanTbdNum < CONFIG_SYS_TX_ETH_BUFFER) {
+ pUsedTbd = &info->txbd[info->usedTbdIdx];
+ if (pUsedTbd->cbd_sc & BD_ENET_TX_READY) {
+#ifdef ET_DEBUG
+ printf("Cannot clean TBD %d, in use\n",
+ info->cleanTbdNum);
+#endif
+ return 0;
+ }
+
+ /* clean this buffer descriptor */
+ if (info->usedTbdIdx == (CONFIG_SYS_TX_ETH_BUFFER - 1))
+ pUsedTbd->cbd_sc = BD_ENET_TX_WRAP;
+ else
+ pUsedTbd->cbd_sc = 0;
+
+ /* update some indeces for a correct handling of the TBD ring */
+ info->cleanTbdNum++;
+ info->usedTbdIdx = (info->usedTbdIdx + 1) % CONFIG_SYS_TX_ETH_BUFFER;
+ }
+
+ /* Check for valid length of data. */
+ if ((length > 1500) || (length <= 0)) {
+ return -1;
+ }
+
+ /* Check the number of vacant TxBDs. */
+ if (info->cleanTbdNum < 1) {
+ printf("No available TxBDs ...\n");
+ return -1;
+ }
+
+ /* Get the first TxBD to send the mac header */
+ pTbd = &info->txbd[info->txIdx];
+ pTbd->cbd_datlen = length;
+ pTbd->cbd_bufaddr = (u32) packet;
+ pTbd->cbd_sc |= BD_ENET_TX_LAST | BD_ENET_TX_TC | BD_ENET_TX_READY;
+ info->txIdx = (info->txIdx + 1) % CONFIG_SYS_TX_ETH_BUFFER;
+
+ /* Enable DMA transmit task */
+ MCD_continDma(info->txTask);
+
+ info->cleanTbdNum -= 1;
+
+ /* wait until frame is sent . */
+ while (pTbd->cbd_sc & BD_ENET_TX_READY) {
+ udelay(10);
+ }
+
+ return (int)(info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_STATS);
+}
+
+static int fec_recv(struct eth_device *dev)
+{
+ struct fec_info_dma *info = dev->priv;
+ volatile fecdma_t *fecp = (fecdma_t *) (info->iobase);
+
+ cbd_t *pRbd = &info->rxbd[info->rxIdx];
+ u32 ievent;
+ int frame_length, len = 0;
+
+ /* Check if any critical events have happened */
+ ievent = fecp->eir;
+ if (ievent != 0) {
+ fecp->eir = ievent;
+
+ if (ievent & (FEC_EIR_BABT | FEC_EIR_TXERR | FEC_EIR_RXERR)) {
+ printf("fec_recv: error\n");
+ fec_halt(dev);
+ fec_init(dev, NULL);
+ return 0;
+ }
+
+ if (ievent & FEC_EIR_HBERR) {
+ /* Heartbeat error */
+ fecp->tcr |= FEC_TCR_GTS;
+ }
+
+ if (ievent & FEC_EIR_GRA) {
+ /* Graceful stop complete */
+ if (fecp->tcr & FEC_TCR_GTS) {
+ printf("fec_recv: tcr_gts\n");
+ fec_halt(dev);
+ fecp->tcr &= ~FEC_TCR_GTS;
+ fec_init(dev, NULL);
+ }
+ }
+ }
+
+ if (!(pRbd->cbd_sc & BD_ENET_RX_EMPTY)) {
+ if ((pRbd->cbd_sc & BD_ENET_RX_LAST)
+ && !(pRbd->cbd_sc & BD_ENET_RX_ERR)
+ && ((pRbd->cbd_datlen - 4) > 14)) {
+
+ /* Get buffer address and size */
+ frame_length = pRbd->cbd_datlen - 4;
+
+ /* Fill the buffer and pass it to upper layers */
+ NetReceive((uchar *)pRbd->cbd_bufaddr, frame_length);
+ len = frame_length;
+ }
+
+ /* Reset buffer descriptor as empty */
+ if ((info->rxIdx) == (PKTBUFSRX - 1))
+ pRbd->cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+ else
+ pRbd->cbd_sc = BD_ENET_RX_EMPTY;
+
+ pRbd->cbd_datlen = PKTSIZE_ALIGN;
+
+ /* Now, we have an empty RxBD, restart the DMA receive task */
+ MCD_continDma(info->rxTask);
+
+ /* Increment BD count */
+ info->rxIdx = (info->rxIdx + 1) % PKTBUFSRX;
+ }
+
+ return len;
+}
+
+static void fec_set_hwaddr(volatile fecdma_t * fecp, u8 * mac)
+{
+ u8 currByte; /* byte for which to compute the CRC */
+ int byte; /* loop - counter */
+ int bit; /* loop - counter */
+ u32 crc = 0xffffffff; /* initial value */
+
+ for (byte = 0; byte < 6; byte++) {
+ currByte = mac[byte];
+ for (bit = 0; bit < 8; bit++) {
+ if ((currByte & 0x01) ^ (crc & 0x01)) {
+ crc >>= 1;
+ crc = crc ^ 0xedb88320;
+ } else {
+ crc >>= 1;
+ }
+ currByte >>= 1;
+ }
+ }
+
+ crc = crc >> 26;
+
+ /* Set individual hash table register */
+ if (crc >= 32) {
+ fecp->ialr = (1 << (crc - 32));
+ fecp->iaur = 0;
+ } else {
+ fecp->ialr = 0;
+ fecp->iaur = (1 << crc);
+ }
+
+ /* Set physical address */
+ fecp->palr = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
+ fecp->paur = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
+
+ /* Clear multicast address hash table */
+ fecp->gaur = 0;
+ fecp->galr = 0;
+}
+
+static int fec_init(struct eth_device *dev, bd_t * bd)
+{
+ struct fec_info_dma *info = dev->priv;
+ volatile fecdma_t *fecp = (fecdma_t *) (info->iobase);
+ int i;
+ uchar enetaddr[6];
+
+#ifdef ET_DEBUG
+ printf("fec_init: iobase 0x%08x ...\n", info->iobase);
+#endif
+
+ fecpin_setclear(dev, 1);
+
+ fec_halt(dev);
+
+#if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \
+ defined (CONFIG_SYS_DISCOVER_PHY)
+
+ mii_init();
+
+ set_fec_duplex_speed(fecp, bd, info->dup_spd);
+#else
+#ifndef CONFIG_SYS_DISCOVER_PHY
+ set_fec_duplex_speed(fecp, bd, (FECDUPLEX << 16) | FECSPEED);
+#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */
+#endif /* CONFIG_CMD_MII || CONFIG_MII */
+
+ /* We use strictly polling mode only */
+ fecp->eimr = 0;
+
+ /* Clear any pending interrupt */
+ fecp->eir = 0xffffffff;
+
+ /* Set station address */
+ if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE)
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ else
+ eth_getenv_enetaddr("eth1addr", enetaddr);
+ fec_set_hwaddr(fecp, enetaddr);
+
+ /* Set Opcode/Pause Duration Register */
+ fecp->opd = 0x00010020;
+
+ /* Setup Buffers and Buffer Desriptors */
+ info->rxIdx = 0;
+ info->txIdx = 0;
+
+ /* Setup Receiver Buffer Descriptors (13.14.24.18)
+ * Settings: Empty, Wrap */
+ for (i = 0; i < PKTBUFSRX; i++) {
+ info->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ info->rxbd[i].cbd_datlen = PKTSIZE_ALIGN;
+ info->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
+ }
+ info->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /* Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+ * Settings: Last, Tx CRC */
+ for (i = 0; i < CONFIG_SYS_TX_ETH_BUFFER; i++) {
+ info->txbd[i].cbd_sc = 0;
+ info->txbd[i].cbd_datlen = 0;
+ info->txbd[i].cbd_bufaddr = (uint) (&info->txbuf[0]);
+ }
+ info->txbd[CONFIG_SYS_TX_ETH_BUFFER - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ info->usedTbdIdx = 0;
+ info->cleanTbdNum = CONFIG_SYS_TX_ETH_BUFFER;
+
+ /* Set Rx FIFO alarm and granularity value */
+ fecp->rfcr = 0x0c000000;
+ fecp->rfar = 0x0000030c;
+
+ /* Set Tx FIFO granularity value */
+ fecp->tfcr = FIFO_CTRL_FRAME | FIFO_CTRL_GR(6) | 0x00040000;
+ fecp->tfar = 0x00000080;
+
+ fecp->tfwr = 0x2;
+ fecp->ctcwr = 0x03000000;
+
+ /* Enable DMA receive task */
+ MCD_startDma(info->rxTask, /* Dma channel */
+ (s8 *) info->rxbd, /*Source Address */
+ 0, /* Source increment */
+ (s8 *) (&fecp->rfdr), /* dest */
+ 4, /* dest increment */
+ 0, /* DMA size */
+ 4, /* xfer size */
+ info->rxInit, /* initiator */
+ info->rxPri, /* priority */
+ (MCD_FECRX_DMA | MCD_TT_FLAGS_DEF), /* Flags */
+ (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) /* Function description */
+ );
+
+ /* Enable DMA tx task with no ready buffer descriptors */
+ MCD_startDma(info->txTask, /* Dma channel */
+ (s8 *) info->txbd, /*Source Address */
+ 0, /* Source increment */
+ (s8 *) (&fecp->tfdr), /* dest */
+ 4, /* dest incr */
+ 0, /* DMA size */
+ 4, /* xfer size */
+ info->txInit, /* initiator */
+ info->txPri, /* priority */
+ (MCD_FECTX_DMA | MCD_TT_FLAGS_DEF), /* Flags */
+ (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) /* Function description */
+ );
+
+ /* Now enable the transmit and receive processing */
+ fecp->ecr |= FEC_ECR_ETHER_EN;
+
+ return 1;
+}
+
+static void fec_halt(struct eth_device *dev)
+{
+ struct fec_info_dma *info = dev->priv;
+ volatile fecdma_t *fecp = (fecdma_t *) (info->iobase);
+ int counter = 0xffff;
+
+ /* issue graceful stop command to the FEC transmitter if necessary */
+ fecp->tcr |= FEC_TCR_GTS;
+
+ /* wait for graceful stop to register */
+ while ((counter--) && (!(fecp->eir & FEC_EIR_GRA))) ;
+
+ /* Disable DMA tasks */
+ MCD_killDma(info->txTask);
+ MCD_killDma(info->rxTask);;
+
+ /* Disable the Ethernet Controller */
+ fecp->ecr &= ~FEC_ECR_ETHER_EN;
+
+ /* Clear FIFO status registers */
+ fecp->rfsr &= FIFO_ERRSTAT;
+ fecp->tfsr &= FIFO_ERRSTAT;
+
+ fecp->frst = 0x01000000;
+
+ /* Issue a reset command to the FEC chip */
+ fecp->ecr |= FEC_ECR_RESET;
+
+ /* wait at least 20 clock cycles */
+ udelay(10000);
+
+#ifdef ET_DEBUG
+ printf("Ethernet task stopped\n");
+#endif
+}
+
+int mcdmafec_initialize(bd_t * bis)
+{
+ struct eth_device *dev;
+ int i;
+#ifdef CONFIG_SYS_DMA_USE_INTSRAM
+ u32 tmp = CONFIG_SYS_INTSRAM + 0x2000;
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(fec_info); i++) {
+
+ dev =
+ (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE,
+ sizeof *dev);
+ if (dev == NULL)
+ hang();
+
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf(dev->name, "FEC%d", fec_info[i].index);
+
+ dev->priv = &fec_info[i];
+ dev->init = fec_init;
+ dev->halt = fec_halt;
+ dev->send = fec_send;
+ dev->recv = fec_recv;
+
+ /* setup Receive and Transmit buffer descriptor */
+#ifdef CONFIG_SYS_DMA_USE_INTSRAM
+ fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp);
+ tmp = (u32)fec_info[i].rxbd;
+ fec_info[i].txbd =
+ (cbd_t *)((u32)fec_info[i].txbd + tmp +
+ (PKTBUFSRX * sizeof(cbd_t)));
+ tmp = (u32)fec_info[i].txbd;
+ fec_info[i].txbuf =
+ (char *)((u32)fec_info[i].txbuf + tmp +
+ (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
+ tmp = (u32)fec_info[i].txbuf;
+#else
+ fec_info[i].rxbd =
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ (PKTBUFSRX * sizeof(cbd_t)));
+ fec_info[i].txbd =
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
+ fec_info[i].txbuf =
+ (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH);
+#endif
+
+#ifdef ET_DEBUG
+ printf("rxbd %x txbd %x\n",
+ (int)fec_info[i].rxbd, (int)fec_info[i].txbd);
+#endif
+
+ fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name,
+ mcffec_miiphy_read, mcffec_miiphy_write);
+#endif
+
+ if (i > 0)
+ fec_info[i - 1].next = &fec_info[i];
+ }
+ fec_info[i - 1].next = &fec_info[0];
+
+ /* default speed */
+ bis->bi_ethspeed = 10;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/fsl_mdio.c b/qemu/roms/u-boot/drivers/net/fsl_mdio.c
new file mode 100644
index 000000000..1d88e6504
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/fsl_mdio.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2009-2010, 2013 Freescale Semiconductor, Inc.
+ * Jun-jie Zhang <b18070@freescale.com>
+ * Mingkai Hu <Mingkai.hu@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <fsl_mdio.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/fsl_enet.h>
+
+void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr,
+ int dev_addr, int regnum, int value)
+{
+ int timeout = 1000000;
+
+ out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
+ out_be32(&phyregs->miimcon, value);
+ asm("sync");
+
+ while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--)
+ ;
+}
+
+int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
+ int dev_addr, int regnum)
+{
+ int value;
+ int timeout = 1000000;
+
+ /* Put the address of the phy, and the register
+ * number into MIIMADD */
+ out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
+
+ /* Clear the command register, and wait */
+ out_be32(&phyregs->miimcom, 0);
+ asm("sync");
+
+ /* Initiate a read command, and wait */
+ out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE);
+ asm("sync");
+
+ /* Wait for the the indication that the read is done */
+ while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
+ && timeout--)
+ ;
+
+ /* Grab the value read from the PHY */
+ value = in_be32(&phyregs->miimstat);
+
+ return value;
+}
+
+static int fsl_pq_mdio_reset(struct mii_dev *bus)
+{
+ struct tsec_mii_mng __iomem *regs =
+ (struct tsec_mii_mng __iomem *)bus->priv;
+
+ /* Reset MII (due to new addresses) */
+ out_be32(&regs->miimcfg, MIIMCFG_RESET_MGMT);
+
+ out_be32(&regs->miimcfg, MIIMCFG_INIT_VALUE);
+
+ while (in_be32(&regs->miimind) & MIIMIND_BUSY)
+ ;
+
+ return 0;
+}
+
+int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum)
+{
+ struct tsec_mii_mng __iomem *phyregs =
+ (struct tsec_mii_mng __iomem *)bus->priv;
+
+ return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum);
+}
+
+int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum,
+ u16 value)
+{
+ struct tsec_mii_mng __iomem *phyregs =
+ (struct tsec_mii_mng __iomem *)bus->priv;
+
+ tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value);
+
+ return 0;
+}
+
+int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info)
+{
+ struct mii_dev *bus = mdio_alloc();
+
+ if (!bus) {
+ printf("Failed to allocate FSL MDIO bus\n");
+ return -1;
+ }
+
+ bus->read = tsec_phy_read;
+ bus->write = tsec_phy_write;
+ bus->reset = fsl_pq_mdio_reset;
+ sprintf(bus->name, info->name);
+
+ bus->priv = (void *)info->regs;
+
+ return mdio_register(bus);
+}
diff --git a/qemu/roms/u-boot/drivers/net/ftgmac100.c b/qemu/roms/u-boot/drivers/net/ftgmac100.c
new file mode 100644
index 000000000..85193140a
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ftgmac100.c
@@ -0,0 +1,583 @@
+/*
+ * Faraday FTGMAC100 Ethernet
+ *
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * (C) Copyright 2010 Andes Technology
+ * Macpaul Lin <macpaul@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+#include <linux/mii.h>
+
+#include "ftgmac100.h"
+
+#define ETH_ZLEN 60
+#define CFG_XBUF_SIZE 1536
+
+/* RBSR - hw default init value is also 0x640 */
+#define RBSR_DEFAULT_VALUE 0x640
+
+/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */
+#define PKTBUFSTX 4 /* must be power of 2 */
+
+struct ftgmac100_data {
+ ulong txdes_dma;
+ struct ftgmac100_txdes *txdes;
+ ulong rxdes_dma;
+ struct ftgmac100_rxdes *rxdes;
+ int tx_index;
+ int rx_index;
+ int phy_addr;
+};
+
+/*
+ * struct mii_bus functions
+ */
+static int ftgmac100_mdiobus_read(struct eth_device *dev, int phy_addr,
+ int regnum)
+{
+ struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
+ int phycr;
+ int i;
+
+ phycr = readl(&ftgmac100->phycr);
+
+ /* preserve MDC cycle threshold */
+ phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
+
+ phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr)
+ | FTGMAC100_PHYCR_REGAD(regnum)
+ | FTGMAC100_PHYCR_MIIRD;
+
+ writel(phycr, &ftgmac100->phycr);
+
+ for (i = 0; i < 10; i++) {
+ phycr = readl(&ftgmac100->phycr);
+
+ if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
+ int data;
+
+ data = readl(&ftgmac100->phydata);
+ return FTGMAC100_PHYDATA_MIIRDATA(data);
+ }
+
+ mdelay(10);
+ }
+
+ debug("mdio read timed out\n");
+ return -1;
+}
+
+static int ftgmac100_mdiobus_write(struct eth_device *dev, int phy_addr,
+ int regnum, u16 value)
+{
+ struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
+ int phycr;
+ int data;
+ int i;
+
+ phycr = readl(&ftgmac100->phycr);
+
+ /* preserve MDC cycle threshold */
+ phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
+
+ phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr)
+ | FTGMAC100_PHYCR_REGAD(regnum)
+ | FTGMAC100_PHYCR_MIIWR;
+
+ data = FTGMAC100_PHYDATA_MIIWDATA(value);
+
+ writel(data, &ftgmac100->phydata);
+ writel(phycr, &ftgmac100->phycr);
+
+ for (i = 0; i < 10; i++) {
+ phycr = readl(&ftgmac100->phycr);
+
+ if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
+ debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
+ "phy_addr: %x\n", phy_addr);
+ return 0;
+ }
+
+ mdelay(1);
+ }
+
+ debug("mdio write timed out\n");
+ return -1;
+}
+
+int ftgmac100_phy_read(struct eth_device *dev, int addr, int reg, u16 *value)
+{
+ *value = ftgmac100_mdiobus_read(dev , addr, reg);
+
+ if (*value == -1)
+ return -1;
+
+ return 0;
+}
+
+int ftgmac100_phy_write(struct eth_device *dev, int addr, int reg, u16 value)
+{
+ if (ftgmac100_mdiobus_write(dev, addr, reg, value) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int ftgmac100_phy_reset(struct eth_device *dev)
+{
+ struct ftgmac100_data *priv = dev->priv;
+ int i;
+ u16 status, adv;
+
+ adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+
+ ftgmac100_phy_write(dev, priv->phy_addr, MII_ADVERTISE, adv);
+
+ printf("%s: Starting autonegotiation...\n", dev->name);
+
+ ftgmac100_phy_write(dev, priv->phy_addr,
+ MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART));
+
+ for (i = 0; i < 100000 / 100; i++) {
+ ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status);
+
+ if (status & BMSR_ANEGCOMPLETE)
+ break;
+ mdelay(1);
+ }
+
+ if (status & BMSR_ANEGCOMPLETE) {
+ printf("%s: Autonegotiation complete\n", dev->name);
+ } else {
+ printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+ dev->name, status);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ftgmac100_phy_init(struct eth_device *dev)
+{
+ struct ftgmac100_data *priv = dev->priv;
+
+ int phy_addr;
+ u16 phy_id, status, adv, lpa, stat_ge;
+ int media, speed, duplex;
+ int i;
+
+ /* Check if the PHY is up to snuff... */
+ for (phy_addr = 0; phy_addr < CONFIG_PHY_MAX_ADDR; phy_addr++) {
+
+ ftgmac100_phy_read(dev, phy_addr, MII_PHYSID1, &phy_id);
+
+ /*
+ * When it is unable to found PHY,
+ * the interface usually return 0xffff or 0x0000
+ */
+ if (phy_id != 0xffff && phy_id != 0x0) {
+ printf("%s: found PHY at 0x%02x\n",
+ dev->name, phy_addr);
+ priv->phy_addr = phy_addr;
+ break;
+ }
+ }
+
+ if (phy_id == 0xffff || phy_id == 0x0) {
+ printf("%s: no PHY present\n", dev->name);
+ return 0;
+ }
+
+ ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status);
+
+ if (!(status & BMSR_LSTATUS)) {
+ /* Try to re-negotiate if we don't have link already. */
+ ftgmac100_phy_reset(dev);
+
+ for (i = 0; i < 100000 / 100; i++) {
+ ftgmac100_phy_read(dev, priv->phy_addr,
+ MII_BMSR, &status);
+ if (status & BMSR_LSTATUS)
+ break;
+ udelay(100);
+ }
+ }
+
+ if (!(status & BMSR_LSTATUS)) {
+ printf("%s: link down\n", dev->name);
+ return 0;
+ }
+
+#ifdef CONFIG_FTGMAC100_EGIGA
+ /* 1000 Base-T Status Register */
+ ftgmac100_phy_read(dev, priv->phy_addr,
+ MII_STAT1000, &stat_ge);
+
+ speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF)
+ ? 1 : 0);
+
+ duplex = ((stat_ge & LPA_1000FULL)
+ ? 1 : 0);
+
+ if (speed) { /* Speed is 1000 */
+ printf("%s: link up, 1000bps %s-duplex\n",
+ dev->name, duplex ? "full" : "half");
+ return 0;
+ }
+#endif
+
+ ftgmac100_phy_read(dev, priv->phy_addr, MII_ADVERTISE, &adv);
+ ftgmac100_phy_read(dev, priv->phy_addr, MII_LPA, &lpa);
+
+ media = mii_nway_result(lpa & adv);
+ speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0);
+ duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+
+ printf("%s: link up, %sMbps %s-duplex\n",
+ dev->name, speed ? "100" : "10", duplex ? "full" : "half");
+
+ return 1;
+}
+
+static int ftgmac100_update_link_speed(struct eth_device *dev)
+{
+ struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
+ struct ftgmac100_data *priv = dev->priv;
+
+ unsigned short stat_fe;
+ unsigned short stat_ge;
+ unsigned int maccr;
+
+#ifdef CONFIG_FTGMAC100_EGIGA
+ /* 1000 Base-T Status Register */
+ ftgmac100_phy_read(dev, priv->phy_addr, MII_STAT1000, &stat_ge);
+#endif
+
+ ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &stat_fe);
+
+ if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */
+ return 0;
+
+ /* read MAC control register and clear related bits */
+ maccr = readl(&ftgmac100->maccr) &
+ ~(FTGMAC100_MACCR_GIGA_MODE |
+ FTGMAC100_MACCR_FAST_MODE |
+ FTGMAC100_MACCR_FULLDUP);
+
+#ifdef CONFIG_FTGMAC100_EGIGA
+ if (stat_ge & LPA_1000FULL) {
+ /* set gmac for 1000BaseTX and Full Duplex */
+ maccr |= FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP;
+ }
+
+ if (stat_ge & LPA_1000HALF) {
+ /* set gmac for 1000BaseTX and Half Duplex */
+ maccr |= FTGMAC100_MACCR_GIGA_MODE;
+ }
+#endif
+
+ if (stat_fe & BMSR_100FULL) {
+ /* set MII for 100BaseTX and Full Duplex */
+ maccr |= FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP;
+ }
+
+ if (stat_fe & BMSR_10FULL) {
+ /* set MII for 10BaseT and Full Duplex */
+ maccr |= FTGMAC100_MACCR_FULLDUP;
+ }
+
+ if (stat_fe & BMSR_100HALF) {
+ /* set MII for 100BaseTX and Half Duplex */
+ maccr |= FTGMAC100_MACCR_FAST_MODE;
+ }
+
+ if (stat_fe & BMSR_10HALF) {
+ /* set MII for 10BaseT and Half Duplex */
+ /* we have already clear these bits, do nothing */
+ ;
+ }
+
+ /* update MII config into maccr */
+ writel(maccr, &ftgmac100->maccr);
+
+ return 1;
+}
+
+/*
+ * Reset MAC
+ */
+static void ftgmac100_reset(struct eth_device *dev)
+{
+ struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
+
+ debug("%s()\n", __func__);
+
+ writel(FTGMAC100_MACCR_SW_RST, &ftgmac100->maccr);
+
+ while (readl(&ftgmac100->maccr) & FTGMAC100_MACCR_SW_RST)
+ ;
+}
+
+/*
+ * Set MAC address
+ */
+static void ftgmac100_set_mac(struct eth_device *dev,
+ const unsigned char *mac)
+{
+ struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
+ unsigned int maddr = mac[0] << 8 | mac[1];
+ unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
+
+ debug("%s(%x %x)\n", __func__, maddr, laddr);
+
+ writel(maddr, &ftgmac100->mac_madr);
+ writel(laddr, &ftgmac100->mac_ladr);
+}
+
+static void ftgmac100_set_mac_from_env(struct eth_device *dev)
+{
+ eth_getenv_enetaddr("ethaddr", dev->enetaddr);
+
+ ftgmac100_set_mac(dev, dev->enetaddr);
+}
+
+/*
+ * disable transmitter, receiver
+ */
+static void ftgmac100_halt(struct eth_device *dev)
+{
+ struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
+
+ debug("%s()\n", __func__);
+
+ writel(0, &ftgmac100->maccr);
+}
+
+static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
+{
+ struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
+ struct ftgmac100_data *priv = dev->priv;
+ struct ftgmac100_txdes *txdes;
+ struct ftgmac100_rxdes *rxdes;
+ unsigned int maccr;
+ void *buf;
+ int i;
+
+ debug("%s()\n", __func__);
+
+ if (!priv->txdes) {
+ txdes = dma_alloc_coherent(
+ sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
+ if (!txdes)
+ panic("ftgmac100: out of memory\n");
+ memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
+ priv->txdes = txdes;
+ }
+ txdes = priv->txdes;
+
+ if (!priv->rxdes) {
+ rxdes = dma_alloc_coherent(
+ sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
+ if (!rxdes)
+ panic("ftgmac100: out of memory\n");
+ memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
+ priv->rxdes = rxdes;
+ }
+ rxdes = priv->rxdes;
+
+ /* set the ethernet address */
+ ftgmac100_set_mac_from_env(dev);
+
+ /* disable all interrupts */
+ writel(0, &ftgmac100->ier);
+
+ /* initialize descriptors */
+ priv->tx_index = 0;
+ priv->rx_index = 0;
+
+ txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR;
+ rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR;
+
+ for (i = 0; i < PKTBUFSTX; i++) {
+ /* TXBUF_BADR */
+ if (!txdes[i].txdes2) {
+ buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+ if (!buf)
+ panic("ftgmac100: out of memory\n");
+ txdes[i].txdes3 = virt_to_phys(buf);
+ txdes[i].txdes2 = (uint)buf;
+ }
+ txdes[i].txdes1 = 0;
+ }
+
+ for (i = 0; i < PKTBUFSRX; i++) {
+ /* RXBUF_BADR */
+ if (!rxdes[i].rxdes2) {
+ buf = NetRxPackets[i];
+ rxdes[i].rxdes3 = virt_to_phys(buf);
+ rxdes[i].rxdes2 = (uint)buf;
+ }
+ rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
+ }
+
+ /* transmit ring */
+ writel(priv->txdes_dma, &ftgmac100->txr_badr);
+
+ /* receive ring */
+ writel(priv->rxdes_dma, &ftgmac100->rxr_badr);
+
+ /* poll receive descriptor automatically */
+ writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
+
+ /* config receive buffer size register */
+ writel(FTGMAC100_RBSR_SIZE(RBSR_DEFAULT_VALUE), &ftgmac100->rbsr);
+
+ /* enable transmitter, receiver */
+ maccr = FTGMAC100_MACCR_TXMAC_EN |
+ FTGMAC100_MACCR_RXMAC_EN |
+ FTGMAC100_MACCR_TXDMA_EN |
+ FTGMAC100_MACCR_RXDMA_EN |
+ FTGMAC100_MACCR_CRC_APD |
+ FTGMAC100_MACCR_FULLDUP |
+ FTGMAC100_MACCR_RX_RUNT |
+ FTGMAC100_MACCR_RX_BROADPKT;
+
+ writel(maccr, &ftgmac100->maccr);
+
+ if (!ftgmac100_phy_init(dev)) {
+ if (!ftgmac100_update_link_speed(dev))
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Get a data block via Ethernet
+ */
+static int ftgmac100_recv(struct eth_device *dev)
+{
+ struct ftgmac100_data *priv = dev->priv;
+ struct ftgmac100_rxdes *curr_des;
+ unsigned short rxlen;
+
+ curr_des = &priv->rxdes[priv->rx_index];
+
+ if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY))
+ return -1;
+
+ if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR |
+ FTGMAC100_RXDES0_CRC_ERR |
+ FTGMAC100_RXDES0_FTL |
+ FTGMAC100_RXDES0_RUNT |
+ FTGMAC100_RXDES0_RX_ODD_NB)) {
+ return -1;
+ }
+
+ rxlen = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0);
+
+ debug("%s(): RX buffer %d, %x received\n",
+ __func__, priv->rx_index, rxlen);
+
+ /* invalidate d-cache */
+ dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
+
+ /* pass the packet up to the protocol layers. */
+ NetReceive((void *)curr_des->rxdes2, rxlen);
+
+ /* release buffer to DMA */
+ curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
+
+ priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
+
+ return 0;
+}
+
+/*
+ * Send a data block via Ethernet
+ */
+static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
+{
+ struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
+ struct ftgmac100_data *priv = dev->priv;
+ struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
+
+ if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
+ debug("%s(): no TX descriptor available\n", __func__);
+ return -1;
+ }
+
+ debug("%s(%x, %x)\n", __func__, (int)packet, length);
+
+ length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
+
+ memcpy((void *)curr_des->txdes2, (void *)packet, length);
+ dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);
+
+ /* only one descriptor on TXBUF */
+ curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
+ curr_des->txdes0 |= FTGMAC100_TXDES0_FTS |
+ FTGMAC100_TXDES0_LTS |
+ FTGMAC100_TXDES0_TXBUF_SIZE(length) |
+ FTGMAC100_TXDES0_TXDMA_OWN ;
+
+ /* start transmit */
+ writel(1, &ftgmac100->txpd);
+
+ debug("%s(): packet sent\n", __func__);
+
+ priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
+
+ return 0;
+}
+
+int ftgmac100_initialize(bd_t *bd)
+{
+ struct eth_device *dev;
+ struct ftgmac100_data *priv;
+
+ dev = malloc(sizeof *dev);
+ if (!dev) {
+ printf("%s(): failed to allocate dev\n", __func__);
+ goto out;
+ }
+
+ /* Transmit and receive descriptors should align to 16 bytes */
+ priv = memalign(16, sizeof(struct ftgmac100_data));
+ if (!priv) {
+ printf("%s(): failed to allocate priv\n", __func__);
+ goto free_dev;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ memset(priv, 0, sizeof(*priv));
+
+ sprintf(dev->name, "FTGMAC100");
+ dev->iobase = CONFIG_FTGMAC100_BASE;
+ dev->init = ftgmac100_init;
+ dev->halt = ftgmac100_halt;
+ dev->send = ftgmac100_send;
+ dev->recv = ftgmac100_recv;
+ dev->priv = priv;
+
+ eth_register(dev);
+
+ ftgmac100_reset(dev);
+
+ return 1;
+
+free_dev:
+ free(dev);
+out:
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ftgmac100.h b/qemu/roms/u-boot/drivers/net/ftgmac100.h
new file mode 100644
index 000000000..71121ba9d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ftgmac100.h
@@ -0,0 +1,243 @@
+/*
+ * Faraday FTGMAC100 Ethernet
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * (C) Copyright 2010 Andes Technology
+ * Macpaul Lin <macpaul@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __FTGMAC100_H
+#define __FTGMAC100_H
+
+/* The registers offset table of ftgmac100 */
+struct ftgmac100 {
+ unsigned int isr; /* 0x00 */
+ unsigned int ier; /* 0x04 */
+ unsigned int mac_madr; /* 0x08 */
+ unsigned int mac_ladr; /* 0x0c */
+ unsigned int maht0; /* 0x10 */
+ unsigned int maht1; /* 0x14 */
+ unsigned int txpd; /* 0x18 */
+ unsigned int rxpd; /* 0x1c */
+ unsigned int txr_badr; /* 0x20 */
+ unsigned int rxr_badr; /* 0x24 */
+ unsigned int hptxpd; /* 0x28 */
+ unsigned int hptxpd_badr; /* 0x2c */
+ unsigned int itc; /* 0x30 */
+ unsigned int aptc; /* 0x34 */
+ unsigned int dblac; /* 0x38 */
+ unsigned int dmafifos; /* 0x3c */
+ unsigned int revr; /* 0x40 */
+ unsigned int fear; /* 0x44 */
+ unsigned int tpafcr; /* 0x48 */
+ unsigned int rbsr; /* 0x4c */
+ unsigned int maccr; /* 0x50 */
+ unsigned int macsr; /* 0x54 */
+ unsigned int tm; /* 0x58 */
+ unsigned int resv1; /* 0x5c */ /* not defined in spec */
+ unsigned int phycr; /* 0x60 */
+ unsigned int phydata; /* 0x64 */
+ unsigned int fcr; /* 0x68 */
+ unsigned int bpr; /* 0x6c */
+ unsigned int wolcr; /* 0x70 */
+ unsigned int wolsr; /* 0x74 */
+ unsigned int wfcrc; /* 0x78 */
+ unsigned int resv2; /* 0x7c */ /* not defined in spec */
+ unsigned int wfbm1; /* 0x80 */
+ unsigned int wfbm2; /* 0x84 */
+ unsigned int wfbm3; /* 0x88 */
+ unsigned int wfbm4; /* 0x8c */
+ unsigned int nptxr_ptr; /* 0x90 */
+ unsigned int hptxr_ptr; /* 0x94 */
+ unsigned int rxr_ptr; /* 0x98 */
+ unsigned int resv3; /* 0x9c */ /* not defined in spec */
+ unsigned int tx; /* 0xa0 */
+ unsigned int tx_mcol_scol; /* 0xa4 */
+ unsigned int tx_ecol_fail; /* 0xa8 */
+ unsigned int tx_lcol_und; /* 0xac */
+ unsigned int rx; /* 0xb0 */
+ unsigned int rx_bc; /* 0xb4 */
+ unsigned int rx_mc; /* 0xb8 */
+ unsigned int rx_pf_aep; /* 0xbc */
+ unsigned int rx_runt; /* 0xc0 */
+ unsigned int rx_crcer_ftl; /* 0xc4 */
+ unsigned int rx_col_lost; /* 0xc8 */
+};
+
+/*
+ * Interrupt status register & interrupt enable register
+ */
+#define FTGMAC100_INT_RPKT_BUF (1 << 0)
+#define FTGMAC100_INT_RPKT_FIFO (1 << 1)
+#define FTGMAC100_INT_NO_RXBUF (1 << 2)
+#define FTGMAC100_INT_RPKT_LOST (1 << 3)
+#define FTGMAC100_INT_XPKT_ETH (1 << 4)
+#define FTGMAC100_INT_XPKT_FIFO (1 << 5)
+#define FTGMAC100_INT_NO_NPTXBUF (1 << 6)
+#define FTGMAC100_INT_XPKT_LOST (1 << 7)
+#define FTGMAC100_INT_AHB_ERR (1 << 8)
+#define FTGMAC100_INT_PHYSTS_CHG (1 << 9)
+#define FTGMAC100_INT_NO_HPTXBUF (1 << 10)
+
+/*
+ * Interrupt timer control register
+ */
+#define FTGMAC100_ITC_RXINT_CNT(x) (((x) & 0xf) << 0)
+#define FTGMAC100_ITC_RXINT_THR(x) (((x) & 0x7) << 4)
+#define FTGMAC100_ITC_RXINT_TIME_SEL (1 << 7)
+#define FTGMAC100_ITC_TXINT_CNT(x) (((x) & 0xf) << 8)
+#define FTGMAC100_ITC_TXINT_THR(x) (((x) & 0x7) << 12)
+#define FTGMAC100_ITC_TXINT_TIME_SEL (1 << 15)
+
+/*
+ * Automatic polling timer control register
+ */
+#define FTGMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0)
+#define FTGMAC100_APTC_RXPOLL_TIME_SEL (1 << 4)
+#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8)
+#define FTGMAC100_APTC_TXPOLL_TIME_SEL (1 << 12)
+
+/*
+ * DMA burst length and arbitration control register
+ */
+#define FTGMAC100_DBLAC_RXFIFO_LTHR(x) (((x) & 0x7) << 0)
+#define FTGMAC100_DBLAC_RXFIFO_HTHR(x) (((x) & 0x7) << 3)
+#define FTGMAC100_DBLAC_RX_THR_EN (1 << 6)
+#define FTGMAC100_DBLAC_RXBURST_SIZE(x) (((x) & 0x3) << 8)
+#define FTGMAC100_DBLAC_TXBURST_SIZE(x) (((x) & 0x3) << 10)
+#define FTGMAC100_DBLAC_RXDES_SIZE(x) (((x) & 0xf) << 12)
+#define FTGMAC100_DBLAC_TXDES_SIZE(x) (((x) & 0xf) << 16)
+#define FTGMAC100_DBLAC_IFG_CNT(x) (((x) & 0x7) << 20)
+#define FTGMAC100_DBLAC_IFG_INC (1 << 23)
+
+/*
+ * DMA FIFO status register
+ */
+#define FTGMAC100_DMAFIFOS_RXDMA1_SM(dmafifos) ((dmafifos) & 0xf)
+#define FTGMAC100_DMAFIFOS_RXDMA2_SM(dmafifos) (((dmafifos) >> 4) & 0xf)
+#define FTGMAC100_DMAFIFOS_RXDMA3_SM(dmafifos) (((dmafifos) >> 8) & 0x7)
+#define FTGMAC100_DMAFIFOS_TXDMA1_SM(dmafifos) (((dmafifos) >> 12) & 0xf)
+#define FTGMAC100_DMAFIFOS_TXDMA2_SM(dmafifos) (((dmafifos) >> 16) & 0x3)
+#define FTGMAC100_DMAFIFOS_TXDMA3_SM(dmafifos) (((dmafifos) >> 18) & 0xf)
+#define FTGMAC100_DMAFIFOS_RXFIFO_EMPTY (1 << 26)
+#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY (1 << 27)
+#define FTGMAC100_DMAFIFOS_RXDMA_GRANT (1 << 28)
+#define FTGMAC100_DMAFIFOS_TXDMA_GRANT (1 << 29)
+#define FTGMAC100_DMAFIFOS_RXDMA_REQ (1 << 30)
+#define FTGMAC100_DMAFIFOS_TXDMA_REQ (1 << 31)
+
+/*
+ * Receive buffer size register
+ */
+#define FTGMAC100_RBSR_SIZE(x) ((x) & 0x3fff)
+
+/*
+ * MAC control register
+ */
+#define FTGMAC100_MACCR_TXDMA_EN (1 << 0)
+#define FTGMAC100_MACCR_RXDMA_EN (1 << 1)
+#define FTGMAC100_MACCR_TXMAC_EN (1 << 2)
+#define FTGMAC100_MACCR_RXMAC_EN (1 << 3)
+#define FTGMAC100_MACCR_RM_VLAN (1 << 4)
+#define FTGMAC100_MACCR_HPTXR_EN (1 << 5)
+#define FTGMAC100_MACCR_LOOP_EN (1 << 6)
+#define FTGMAC100_MACCR_ENRX_IN_HALFTX (1 << 7)
+#define FTGMAC100_MACCR_FULLDUP (1 << 8)
+#define FTGMAC100_MACCR_GIGA_MODE (1 << 9)
+#define FTGMAC100_MACCR_CRC_APD (1 << 10)
+#define FTGMAC100_MACCR_RX_RUNT (1 << 12)
+#define FTGMAC100_MACCR_JUMBO_LF (1 << 13)
+#define FTGMAC100_MACCR_RX_ALL (1 << 14)
+#define FTGMAC100_MACCR_HT_MULTI_EN (1 << 15)
+#define FTGMAC100_MACCR_RX_MULTIPKT (1 << 16)
+#define FTGMAC100_MACCR_RX_BROADPKT (1 << 17)
+#define FTGMAC100_MACCR_DISCARD_CRCERR (1 << 18)
+#define FTGMAC100_MACCR_FAST_MODE (1 << 19)
+#define FTGMAC100_MACCR_SW_RST (1 << 31)
+
+/*
+ * PHY control register
+ */
+#define FTGMAC100_PHYCR_MDC_CYCTHR_MASK 0x3f
+#define FTGMAC100_PHYCR_MDC_CYCTHR(x) ((x) & 0x3f)
+#define FTGMAC100_PHYCR_PHYAD(x) (((x) & 0x1f) << 16)
+#define FTGMAC100_PHYCR_REGAD(x) (((x) & 0x1f) << 21)
+#define FTGMAC100_PHYCR_MIIRD (1 << 26)
+#define FTGMAC100_PHYCR_MIIWR (1 << 27)
+
+/*
+ * PHY data register
+ */
+#define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff)
+#define FTGMAC100_PHYDATA_MIIRDATA(phydata) (((phydata) >> 16) & 0xffff)
+
+/*
+ * Transmit descriptor, aligned to 16 bytes
+ */
+struct ftgmac100_txdes {
+ unsigned int txdes0;
+ unsigned int txdes1;
+ unsigned int txdes2; /* not used by HW */
+ unsigned int txdes3; /* TXBUF_BADR */
+} __attribute__ ((aligned(16)));
+
+#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff)
+#define FTGMAC100_TXDES0_EDOTR (1 << 15)
+#define FTGMAC100_TXDES0_CRC_ERR (1 << 19)
+#define FTGMAC100_TXDES0_LTS (1 << 28)
+#define FTGMAC100_TXDES0_FTS (1 << 29)
+#define FTGMAC100_TXDES0_TXDMA_OWN (1 << 31)
+
+#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff)
+#define FTGMAC100_TXDES1_INS_VLANTAG (1 << 16)
+#define FTGMAC100_TXDES1_TCP_CHKSUM (1 << 17)
+#define FTGMAC100_TXDES1_UDP_CHKSUM (1 << 18)
+#define FTGMAC100_TXDES1_IP_CHKSUM (1 << 19)
+#define FTGMAC100_TXDES1_LLC (1 << 22)
+#define FTGMAC100_TXDES1_TX2FIC (1 << 30)
+#define FTGMAC100_TXDES1_TXIC (1 << 31)
+
+/*
+ * Receive descriptor, aligned to 16 bytes
+ */
+struct ftgmac100_rxdes {
+ unsigned int rxdes0;
+ unsigned int rxdes1;
+ unsigned int rxdes2; /* not used by HW */
+ unsigned int rxdes3; /* RXBUF_BADR */
+} __attribute__ ((aligned(16)));
+
+#define FTGMAC100_RXDES0_VDBC(x) ((x) & 0x3fff)
+#define FTGMAC100_RXDES0_EDORR (1 << 15)
+#define FTGMAC100_RXDES0_MULTICAST (1 << 16)
+#define FTGMAC100_RXDES0_BROADCAST (1 << 17)
+#define FTGMAC100_RXDES0_RX_ERR (1 << 18)
+#define FTGMAC100_RXDES0_CRC_ERR (1 << 19)
+#define FTGMAC100_RXDES0_FTL (1 << 20)
+#define FTGMAC100_RXDES0_RUNT (1 << 21)
+#define FTGMAC100_RXDES0_RX_ODD_NB (1 << 22)
+#define FTGMAC100_RXDES0_FIFO_FULL (1 << 23)
+#define FTGMAC100_RXDES0_PAUSE_OPCODE (1 << 24)
+#define FTGMAC100_RXDES0_PAUSE_FRAME (1 << 25)
+#define FTGMAC100_RXDES0_LRS (1 << 28)
+#define FTGMAC100_RXDES0_FRS (1 << 29)
+#define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31)
+
+#define FTGMAC100_RXDES1_VLANTAG_CI 0xffff
+#define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20)
+#define FTGMAC100_RXDES1_PROT_NONIP (0x0 << 20)
+#define FTGMAC100_RXDES1_PROT_IP (0x1 << 20)
+#define FTGMAC100_RXDES1_PROT_TCPIP (0x2 << 20)
+#define FTGMAC100_RXDES1_PROT_UDPIP (0x3 << 20)
+#define FTGMAC100_RXDES1_LLC (1 << 22)
+#define FTGMAC100_RXDES1_DF (1 << 23)
+#define FTGMAC100_RXDES1_VLANTAG_AVAIL (1 << 24)
+#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR (1 << 25)
+#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26)
+#define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27)
+
+#endif /* __FTGMAC100_H */
diff --git a/qemu/roms/u-boot/drivers/net/ftmac100.c b/qemu/roms/u-boot/drivers/net/ftmac100.c
new file mode 100644
index 000000000..3e148db5c
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ftmac100.c
@@ -0,0 +1,265 @@
+/*
+ * Faraday FTMAC100 Ethernet
+ *
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+
+#include "ftmac100.h"
+
+#define ETH_ZLEN 60
+
+struct ftmac100_data {
+ struct ftmac100_txdes txdes[1];
+ struct ftmac100_rxdes rxdes[PKTBUFSRX];
+ int rx_index;
+};
+
+/*
+ * Reset MAC
+ */
+static void ftmac100_reset (struct eth_device *dev)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+
+ debug ("%s()\n", __func__);
+
+ writel (FTMAC100_MACCR_SW_RST, &ftmac100->maccr);
+
+ while (readl (&ftmac100->maccr) & FTMAC100_MACCR_SW_RST)
+ ;
+}
+
+/*
+ * Set MAC address
+ */
+static void ftmac100_set_mac (struct eth_device *dev, const unsigned char *mac)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+ unsigned int maddr = mac[0] << 8 | mac[1];
+ unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
+
+ debug ("%s(%x %x)\n", __func__, maddr, laddr);
+
+ writel (maddr, &ftmac100->mac_madr);
+ writel (laddr, &ftmac100->mac_ladr);
+}
+
+static void ftmac100_set_mac_from_env (struct eth_device *dev)
+{
+ eth_getenv_enetaddr ("ethaddr", dev->enetaddr);
+
+ ftmac100_set_mac (dev, dev->enetaddr);
+}
+
+/*
+ * disable transmitter, receiver
+ */
+static void ftmac100_halt (struct eth_device *dev)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+
+ debug ("%s()\n", __func__);
+
+ writel (0, &ftmac100->maccr);
+}
+
+static int ftmac100_init (struct eth_device *dev, bd_t *bd)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+ struct ftmac100_data *priv = dev->priv;
+ struct ftmac100_txdes *txdes = priv->txdes;
+ struct ftmac100_rxdes *rxdes = priv->rxdes;
+ unsigned int maccr;
+ int i;
+
+ debug ("%s()\n", __func__);
+
+ ftmac100_reset (dev);
+
+ /* set the ethernet address */
+
+ ftmac100_set_mac_from_env (dev);
+
+ /* disable all interrupts */
+
+ writel (0, &ftmac100->imr);
+
+ /* initialize descriptors */
+
+ priv->rx_index = 0;
+
+ txdes[0].txdes1 = FTMAC100_TXDES1_EDOTR;
+ rxdes[PKTBUFSRX - 1].rxdes1 = FTMAC100_RXDES1_EDORR;
+
+ for (i = 0; i < PKTBUFSRX; i++) {
+ /* RXBUF_BADR */
+ rxdes[i].rxdes2 = (unsigned int)NetRxPackets[i];
+ rxdes[i].rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE (PKTSIZE_ALIGN);
+ rxdes[i].rxdes0 = FTMAC100_RXDES0_RXDMA_OWN;
+ }
+
+ /* transmit ring */
+
+ writel ((unsigned int)txdes, &ftmac100->txr_badr);
+
+ /* receive ring */
+
+ writel ((unsigned int)rxdes, &ftmac100->rxr_badr);
+
+ /* poll receive descriptor automatically */
+
+ writel (FTMAC100_APTC_RXPOLL_CNT (1), &ftmac100->aptc);
+
+ /* enable transmitter, receiver */
+
+ maccr = FTMAC100_MACCR_XMT_EN |
+ FTMAC100_MACCR_RCV_EN |
+ FTMAC100_MACCR_XDMA_EN |
+ FTMAC100_MACCR_RDMA_EN |
+ FTMAC100_MACCR_CRC_APD |
+ FTMAC100_MACCR_ENRX_IN_HALFTX |
+ FTMAC100_MACCR_RX_RUNT |
+ FTMAC100_MACCR_RX_BROADPKT;
+
+ writel (maccr, &ftmac100->maccr);
+
+ return 0;
+}
+
+/*
+ * Get a data block via Ethernet
+ */
+static int ftmac100_recv (struct eth_device *dev)
+{
+ struct ftmac100_data *priv = dev->priv;
+ struct ftmac100_rxdes *curr_des;
+ unsigned short rxlen;
+
+ curr_des = &priv->rxdes[priv->rx_index];
+
+ if (curr_des->rxdes0 & FTMAC100_RXDES0_RXDMA_OWN)
+ return -1;
+
+ if (curr_des->rxdes0 & (FTMAC100_RXDES0_RX_ERR |
+ FTMAC100_RXDES0_CRC_ERR |
+ FTMAC100_RXDES0_FTL |
+ FTMAC100_RXDES0_RUNT |
+ FTMAC100_RXDES0_RX_ODD_NB)) {
+ return -1;
+ }
+
+ rxlen = FTMAC100_RXDES0_RFL (curr_des->rxdes0);
+
+ debug ("%s(): RX buffer %d, %x received\n",
+ __func__, priv->rx_index, rxlen);
+
+ /* pass the packet up to the protocol layers. */
+
+ NetReceive ((void *)curr_des->rxdes2, rxlen);
+
+ /* release buffer to DMA */
+
+ curr_des->rxdes0 |= FTMAC100_RXDES0_RXDMA_OWN;
+
+ priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
+
+ return 0;
+}
+
+/*
+ * Send a data block via Ethernet
+ */
+static int ftmac100_send(struct eth_device *dev, void *packet, int length)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+ struct ftmac100_data *priv = dev->priv;
+ struct ftmac100_txdes *curr_des = priv->txdes;
+ ulong start;
+
+ if (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) {
+ debug ("%s(): no TX descriptor available\n", __func__);
+ return -1;
+ }
+
+ debug ("%s(%x, %x)\n", __func__, (int)packet, length);
+
+ length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
+
+ /* initiate a transmit sequence */
+
+ curr_des->txdes2 = (unsigned int)packet; /* TXBUF_BADR */
+
+ curr_des->txdes1 &= FTMAC100_TXDES1_EDOTR;
+ curr_des->txdes1 |= FTMAC100_TXDES1_FTS |
+ FTMAC100_TXDES1_LTS |
+ FTMAC100_TXDES1_TXBUF_SIZE (length);
+
+ curr_des->txdes0 = FTMAC100_TXDES0_TXDMA_OWN;
+
+ /* start transmit */
+
+ writel (1, &ftmac100->txpd);
+
+ /* wait for transfer to succeed */
+
+ start = get_timer(0);
+ while (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) {
+ if (get_timer(start) >= 5) {
+ debug ("%s(): timed out\n", __func__);
+ return -1;
+ }
+ }
+
+ debug ("%s(): packet sent\n", __func__);
+
+ return 0;
+}
+
+int ftmac100_initialize (bd_t *bd)
+{
+ struct eth_device *dev;
+ struct ftmac100_data *priv;
+
+ dev = malloc (sizeof *dev);
+ if (!dev) {
+ printf ("%s(): failed to allocate dev\n", __func__);
+ goto out;
+ }
+
+ /* Transmit and receive descriptors should align to 16 bytes */
+
+ priv = memalign (16, sizeof (struct ftmac100_data));
+ if (!priv) {
+ printf ("%s(): failed to allocate priv\n", __func__);
+ goto free_dev;
+ }
+
+ memset (dev, 0, sizeof (*dev));
+ memset (priv, 0, sizeof (*priv));
+
+ sprintf (dev->name, "FTMAC100");
+ dev->iobase = CONFIG_FTMAC100_BASE;
+ dev->init = ftmac100_init;
+ dev->halt = ftmac100_halt;
+ dev->send = ftmac100_send;
+ dev->recv = ftmac100_recv;
+ dev->priv = priv;
+
+ eth_register (dev);
+
+ return 1;
+
+free_dev:
+ free (dev);
+out:
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ftmac100.h b/qemu/roms/u-boot/drivers/net/ftmac100.h
new file mode 100644
index 000000000..b674d0291
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ftmac100.h
@@ -0,0 +1,142 @@
+/*
+ * Faraday FTMAC100 Ethernet
+ *
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __FTMAC100_H
+#define __FTMAC100_H
+
+struct ftmac100 {
+ unsigned int isr; /* 0x00 */
+ unsigned int imr; /* 0x04 */
+ unsigned int mac_madr; /* 0x08 */
+ unsigned int mac_ladr; /* 0x0c */
+ unsigned int maht0; /* 0x10 */
+ unsigned int maht1; /* 0x14 */
+ unsigned int txpd; /* 0x18 */
+ unsigned int rxpd; /* 0x1c */
+ unsigned int txr_badr; /* 0x20 */
+ unsigned int rxr_badr; /* 0x24 */
+ unsigned int itc; /* 0x28 */
+ unsigned int aptc; /* 0x2c */
+ unsigned int dblac; /* 0x30 */
+ unsigned int pad1[3]; /* 0x34 - 0x3c */
+ unsigned int pad2[16]; /* 0x40 - 0x7c */
+ unsigned int pad3[2]; /* 0x80 - 0x84 */
+ unsigned int maccr; /* 0x88 */
+ unsigned int macsr; /* 0x8c */
+ unsigned int phycr; /* 0x90 */
+ unsigned int phywdata; /* 0x94 */
+ unsigned int fcr; /* 0x98 */
+ unsigned int bpr; /* 0x9c */
+ unsigned int pad4[8]; /* 0xa0 - 0xbc */
+ unsigned int pad5; /* 0xc0 */
+ unsigned int ts; /* 0xc4 */
+ unsigned int dmafifos; /* 0xc8 */
+ unsigned int tm; /* 0xcc */
+ unsigned int pad6; /* 0xd0 */
+ unsigned int tx_mcol_scol; /* 0xd4 */
+ unsigned int rpf_aep; /* 0xd8 */
+ unsigned int xm_pg; /* 0xdc */
+ unsigned int runt_tlcc; /* 0xe0 */
+ unsigned int crcer_ftl; /* 0xe4 */
+ unsigned int rlc_rcc; /* 0xe8 */
+ unsigned int broc; /* 0xec */
+ unsigned int mulca; /* 0xf0 */
+ unsigned int rp; /* 0xf4 */
+ unsigned int xp; /* 0xf8 */
+};
+
+/*
+ * Interrupt status register & interrupt mask register
+ */
+#define FTMAC100_INT_RPKT_FINISH (1 << 0)
+#define FTMAC100_INT_NORXBUF (1 << 1)
+#define FTMAC100_INT_XPKT_FINISH (1 << 2)
+#define FTMAC100_INT_NOTXBUF (1 << 3)
+#define FTMAC100_INT_XPKT_OK (1 << 4)
+#define FTMAC100_INT_XPKT_LOST (1 << 5)
+#define FTMAC100_INT_RPKT_SAV (1 << 6)
+#define FTMAC100_INT_RPKT_LOST (1 << 7)
+#define FTMAC100_INT_AHB_ERR (1 << 8)
+#define FTMAC100_INT_PHYSTS_CHG (1 << 9)
+
+/*
+ * Automatic polling timer control register
+ */
+#define FTMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0)
+#define FTMAC100_APTC_RXPOLL_TIME_SEL (1 << 4)
+#define FTMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8)
+#define FTMAC100_APTC_TXPOLL_TIME_SEL (1 << 12)
+
+/*
+ * MAC control register
+ */
+#define FTMAC100_MACCR_XDMA_EN (1 << 0)
+#define FTMAC100_MACCR_RDMA_EN (1 << 1)
+#define FTMAC100_MACCR_SW_RST (1 << 2)
+#define FTMAC100_MACCR_LOOP_EN (1 << 3)
+#define FTMAC100_MACCR_CRC_DIS (1 << 4)
+#define FTMAC100_MACCR_XMT_EN (1 << 5)
+#define FTMAC100_MACCR_ENRX_IN_HALFTX (1 << 6)
+#define FTMAC100_MACCR_RCV_EN (1 << 8)
+#define FTMAC100_MACCR_HT_MULTI_EN (1 << 9)
+#define FTMAC100_MACCR_RX_RUNT (1 << 10)
+#define FTMAC100_MACCR_RX_FTL (1 << 11)
+#define FTMAC100_MACCR_RCV_ALL (1 << 12)
+#define FTMAC100_MACCR_CRC_APD (1 << 14)
+#define FTMAC100_MACCR_FULLDUP (1 << 15)
+#define FTMAC100_MACCR_RX_MULTIPKT (1 << 16)
+#define FTMAC100_MACCR_RX_BROADPKT (1 << 17)
+
+/*
+ * Transmit descriptor, aligned to 16 bytes
+ */
+struct ftmac100_txdes {
+ unsigned int txdes0;
+ unsigned int txdes1;
+ unsigned int txdes2; /* TXBUF_BADR */
+ unsigned int txdes3; /* not used by HW */
+} __attribute__ ((aligned(16)));
+
+#define FTMAC100_TXDES0_TXPKT_LATECOL (1 << 0)
+#define FTMAC100_TXDES0_TXPKT_EXSCOL (1 << 1)
+#define FTMAC100_TXDES0_TXDMA_OWN (1 << 31)
+
+#define FTMAC100_TXDES1_TXBUF_SIZE(x) ((x) & 0x7ff)
+#define FTMAC100_TXDES1_LTS (1 << 27)
+#define FTMAC100_TXDES1_FTS (1 << 28)
+#define FTMAC100_TXDES1_TX2FIC (1 << 29)
+#define FTMAC100_TXDES1_TXIC (1 << 30)
+#define FTMAC100_TXDES1_EDOTR (1 << 31)
+
+/*
+ * Receive descriptor, aligned to 16 bytes
+ */
+struct ftmac100_rxdes {
+ unsigned int rxdes0;
+ unsigned int rxdes1;
+ unsigned int rxdes2; /* RXBUF_BADR */
+ unsigned int rxdes3; /* not used by HW */
+} __attribute__ ((aligned(16)));
+
+#define FTMAC100_RXDES0_RFL(des) ((des) & 0x7ff)
+#define FTMAC100_RXDES0_MULTICAST (1 << 16)
+#define FTMAC100_RXDES0_BROADCAST (1 << 17)
+#define FTMAC100_RXDES0_RX_ERR (1 << 18)
+#define FTMAC100_RXDES0_CRC_ERR (1 << 19)
+#define FTMAC100_RXDES0_FTL (1 << 20)
+#define FTMAC100_RXDES0_RUNT (1 << 21)
+#define FTMAC100_RXDES0_RX_ODD_NB (1 << 22)
+#define FTMAC100_RXDES0_LRS (1 << 28)
+#define FTMAC100_RXDES0_FRS (1 << 29)
+#define FTMAC100_RXDES0_RXDMA_OWN (1 << 31)
+
+#define FTMAC100_RXDES1_RXBUF_SIZE(x) ((x) & 0x7ff)
+#define FTMAC100_RXDES1_EDORR (1 << 31)
+
+#endif /* __FTMAC100_H */
diff --git a/qemu/roms/u-boot/drivers/net/ftmac110.c b/qemu/roms/u-boot/drivers/net/ftmac110.c
new file mode 100644
index 000000000..98c4f0962
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ftmac110.c
@@ -0,0 +1,480 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#include "ftmac110.h"
+
+#define CFG_RXDES_NUM 8
+#define CFG_TXDES_NUM 2
+#define CFG_XBUF_SIZE 1536
+
+#define CFG_MDIORD_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_MDIOWR_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_LINKUP_TIMEOUT (CONFIG_SYS_HZ << 2) /* 4 sec */
+
+/*
+ * FTMAC110 DMA design issue
+ *
+ * Its DMA engine has a weird restriction that its Rx DMA engine
+ * accepts only 16-bits aligned address, 32-bits aligned is not
+ * acceptable. However this restriction does not apply to Tx DMA.
+ *
+ * Conclusion:
+ * (1) Tx DMA Buffer Address:
+ * 1 bytes aligned: Invalid
+ * 2 bytes aligned: O.K
+ * 4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)
+ * (2) Rx DMA Buffer Address:
+ * 1 bytes aligned: Invalid
+ * 2 bytes aligned: O.K
+ * 4 bytes aligned: Invalid
+ */
+
+struct ftmac110_chip {
+ void __iomem *regs;
+ uint32_t imr;
+ uint32_t maccr;
+ uint32_t lnkup;
+ uint32_t phy_addr;
+
+ struct ftmac110_desc *rxd;
+ ulong rxd_dma;
+ uint32_t rxd_idx;
+
+ struct ftmac110_desc *txd;
+ ulong txd_dma;
+ uint32_t txd_idx;
+};
+
+static int ftmac110_reset(struct eth_device *dev);
+
+static uint16_t mdio_read(struct eth_device *dev,
+ uint8_t phyaddr, uint8_t phyreg)
+{
+ struct ftmac110_chip *chip = dev->priv;
+ struct ftmac110_regs *regs = chip->regs;
+ uint32_t tmp, ts;
+ uint16_t ret = 0xffff;
+
+ tmp = PHYCR_READ
+ | (phyaddr << PHYCR_ADDR_SHIFT)
+ | (phyreg << PHYCR_REG_SHIFT);
+
+ writel(tmp, &regs->phycr);
+
+ for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) {
+ tmp = readl(&regs->phycr);
+ if (tmp & PHYCR_READ)
+ continue;
+ break;
+ }
+
+ if (tmp & PHYCR_READ)
+ printf("ftmac110: mdio read timeout\n");
+ else
+ ret = (uint16_t)(tmp & 0xffff);
+
+ return ret;
+}
+
+static void mdio_write(struct eth_device *dev,
+ uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
+{
+ struct ftmac110_chip *chip = dev->priv;
+ struct ftmac110_regs *regs = chip->regs;
+ uint32_t tmp, ts;
+
+ tmp = PHYCR_WRITE
+ | (phyaddr << PHYCR_ADDR_SHIFT)
+ | (phyreg << PHYCR_REG_SHIFT);
+
+ writel(phydata, &regs->phydr);
+ writel(tmp, &regs->phycr);
+
+ for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) {
+ if (readl(&regs->phycr) & PHYCR_WRITE)
+ continue;
+ break;
+ }
+
+ if (readl(&regs->phycr) & PHYCR_WRITE)
+ printf("ftmac110: mdio write timeout\n");
+}
+
+static uint32_t ftmac110_phyqry(struct eth_device *dev)
+{
+ ulong ts;
+ uint32_t maccr;
+ uint16_t pa, tmp, bmsr, bmcr;
+ struct ftmac110_chip *chip = dev->priv;
+
+ /* Default = 100Mbps Full */
+ maccr = MACCR_100M | MACCR_FD;
+
+ /* 1. find the phy device */
+ for (pa = 0; pa < 32; ++pa) {
+ tmp = mdio_read(dev, pa, MII_PHYSID1);
+ if (tmp == 0xFFFF || tmp == 0x0000)
+ continue;
+ chip->phy_addr = pa;
+ break;
+ }
+ if (pa >= 32) {
+ puts("ftmac110: phy device not found!\n");
+ goto exit;
+ }
+
+ /* 2. wait until link-up & auto-negotiation complete */
+ chip->lnkup = 0;
+ bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR);
+ ts = get_timer(0);
+ do {
+ bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR);
+ chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0;
+ if (!chip->lnkup)
+ continue;
+ if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE))
+ break;
+ } while (get_timer(ts) < CFG_LINKUP_TIMEOUT);
+ if (!chip->lnkup) {
+ puts("ftmac110: link down\n");
+ goto exit;
+ }
+ if (!(bmcr & BMCR_ANENABLE))
+ puts("ftmac110: auto negotiation disabled\n");
+ else if (!(bmsr & BMSR_ANEGCOMPLETE))
+ puts("ftmac110: auto negotiation timeout\n");
+
+ /* 3. derive MACCR */
+ if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) {
+ tmp = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
+ tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
+ if (tmp & LPA_100FULL) /* 100Mbps full-duplex */
+ maccr = MACCR_100M | MACCR_FD;
+ else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */
+ maccr = MACCR_100M;
+ else if (tmp & LPA_10FULL) /* 10Mbps full-duplex */
+ maccr = MACCR_FD;
+ else if (tmp & LPA_10HALF) /* 10Mbps half-duplex */
+ maccr = 0;
+ } else {
+ if (bmcr & BMCR_SPEED100)
+ maccr = MACCR_100M;
+ else
+ maccr = 0;
+ if (bmcr & BMCR_FULLDPLX)
+ maccr |= MACCR_FD;
+ }
+
+exit:
+ printf("ftmac110: %d Mbps, %s\n",
+ (maccr & MACCR_100M) ? 100 : 10,
+ (maccr & MACCR_FD) ? "Full" : "half");
+ return maccr;
+}
+
+static int ftmac110_reset(struct eth_device *dev)
+{
+ uint8_t *a;
+ uint32_t i, maccr;
+ struct ftmac110_chip *chip = dev->priv;
+ struct ftmac110_regs *regs = chip->regs;
+
+ /* 1. MAC reset */
+ writel(MACCR_RESET, &regs->maccr);
+ for (i = get_timer(0); get_timer(i) < 1000; ) {
+ if (readl(&regs->maccr) & MACCR_RESET)
+ continue;
+ break;
+ }
+ if (readl(&regs->maccr) & MACCR_RESET) {
+ printf("ftmac110: reset failed\n");
+ return -ENXIO;
+ }
+
+ /* 1-1. Init tx ring */
+ for (i = 0; i < CFG_TXDES_NUM; ++i) {
+ /* owned by SW */
+ chip->txd[i].ctrl &= cpu_to_le64(FTMAC110_TXD_CLRMASK);
+ }
+ chip->txd_idx = 0;
+
+ /* 1-2. Init rx ring */
+ for (i = 0; i < CFG_RXDES_NUM; ++i) {
+ /* owned by HW */
+ chip->rxd[i].ctrl &= cpu_to_le64(FTMAC110_RXD_CLRMASK);
+ chip->rxd[i].ctrl |= cpu_to_le64(FTMAC110_RXD_OWNER);
+ }
+ chip->rxd_idx = 0;
+
+ /* 2. PHY status query */
+ maccr = ftmac110_phyqry(dev);
+
+ /* 3. Fix up the MACCR value */
+ chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
+ | MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
+
+ /* 4. MAC address setup */
+ a = dev->enetaddr;
+ writel(a[1] | (a[0] << 8), &regs->mac[0]);
+ writel(a[5] | (a[4] << 8) | (a[3] << 16)
+ | (a[2] << 24), &regs->mac[1]);
+
+ /* 5. MAC registers setup */
+ writel(chip->rxd_dma, &regs->rxba);
+ writel(chip->txd_dma, &regs->txba);
+ /* interrupt at each tx/rx */
+ writel(ITC_DEFAULT, &regs->itc);
+ /* no tx pool, rx poll = 1 normal cycle */
+ writel(APTC_DEFAULT, &regs->aptc);
+ /* rx threshold = [6/8 fifo, 2/8 fifo] */
+ writel(DBLAC_DEFAULT, &regs->dblac);
+ /* disable & clear all interrupt status */
+ chip->imr = 0;
+ writel(ISR_ALL, &regs->isr);
+ writel(chip->imr, &regs->imr);
+ /* enable mac */
+ writel(chip->maccr, &regs->maccr);
+
+ return 0;
+}
+
+static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
+{
+ debug("ftmac110: probe\n");
+
+ if (ftmac110_reset(dev))
+ return -1;
+
+ return 0;
+}
+
+static void ftmac110_halt(struct eth_device *dev)
+{
+ struct ftmac110_chip *chip = dev->priv;
+ struct ftmac110_regs *regs = chip->regs;
+
+ writel(0, &regs->imr);
+ writel(0, &regs->maccr);
+
+ debug("ftmac110: halt\n");
+}
+
+static int ftmac110_send(struct eth_device *dev, void *pkt, int len)
+{
+ struct ftmac110_chip *chip = dev->priv;
+ struct ftmac110_regs *regs = chip->regs;
+ struct ftmac110_desc *txd;
+ uint64_t ctrl;
+
+ if (!chip->lnkup)
+ return 0;
+
+ if (len <= 0 || len > CFG_XBUF_SIZE) {
+ printf("ftmac110: bad tx pkt len(%d)\n", len);
+ return 0;
+ }
+
+ len = max(60, len);
+
+ txd = &chip->txd[chip->txd_idx];
+ ctrl = le64_to_cpu(txd->ctrl);
+ if (ctrl & FTMAC110_TXD_OWNER) {
+ /* kick-off Tx DMA */
+ writel(0xffffffff, &regs->txpd);
+ printf("ftmac110: out of txd\n");
+ return 0;
+ }
+
+ memcpy(txd->vbuf, (void *)pkt, len);
+ dma_map_single(txd->vbuf, len, DMA_TO_DEVICE);
+
+ /* clear control bits */
+ ctrl &= FTMAC110_TXD_CLRMASK;
+ /* set len, fts and lts */
+ ctrl |= FTMAC110_TXD_LEN(len) | FTMAC110_TXD_FTS | FTMAC110_TXD_LTS;
+ /* set owner bit */
+ ctrl |= FTMAC110_TXD_OWNER;
+ /* write back to descriptor */
+ txd->ctrl = cpu_to_le64(ctrl);
+
+ /* kick-off Tx DMA */
+ writel(0xffffffff, &regs->txpd);
+
+ chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
+
+ return len;
+}
+
+static int ftmac110_recv(struct eth_device *dev)
+{
+ struct ftmac110_chip *chip = dev->priv;
+ struct ftmac110_desc *rxd;
+ uint32_t len, rlen = 0;
+ uint64_t ctrl;
+ uint8_t *buf;
+
+ if (!chip->lnkup)
+ return 0;
+
+ do {
+ rxd = &chip->rxd[chip->rxd_idx];
+ ctrl = le64_to_cpu(rxd->ctrl);
+ if (ctrl & FTMAC110_RXD_OWNER)
+ break;
+
+ len = (uint32_t)FTMAC110_RXD_LEN(ctrl);
+ buf = rxd->vbuf;
+
+ if (ctrl & FTMAC110_RXD_ERRMASK) {
+ printf("ftmac110: rx error\n");
+ } else {
+ dma_map_single(buf, len, DMA_FROM_DEVICE);
+ NetReceive(buf, len);
+ rlen += len;
+ }
+
+ /* owned by hardware */
+ ctrl &= FTMAC110_RXD_CLRMASK;
+ ctrl |= FTMAC110_RXD_OWNER;
+ rxd->ctrl |= cpu_to_le64(ctrl);
+
+ chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
+ } while (0);
+
+ return rlen;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+static int ftmac110_mdio_read(
+ const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+{
+ int ret = 0;
+ struct eth_device *dev;
+
+ dev = eth_get_dev_by_name(devname);
+ if (dev == NULL) {
+ printf("%s: no such device\n", devname);
+ ret = -1;
+ } else {
+ *value = mdio_read(dev, addr, reg);
+ }
+
+ return ret;
+}
+
+static int ftmac110_mdio_write(
+ const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+{
+ int ret = 0;
+ struct eth_device *dev;
+
+ dev = eth_get_dev_by_name(devname);
+ if (dev == NULL) {
+ printf("%s: no such device\n", devname);
+ ret = -1;
+ } else {
+ mdio_write(dev, addr, reg, value);
+ }
+
+ return ret;
+}
+
+#endif /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ftmac110_initialize(bd_t *bis)
+{
+ int i, card_nr = 0;
+ struct eth_device *dev;
+ struct ftmac110_chip *chip;
+
+ dev = malloc(sizeof(*dev) + sizeof(*chip));
+ if (dev == NULL) {
+ panic("ftmac110: out of memory 1\n");
+ return -1;
+ }
+ chip = (struct ftmac110_chip *)(dev + 1);
+ memset(dev, 0, sizeof(*dev) + sizeof(*chip));
+
+ sprintf(dev->name, "FTMAC110#%d", card_nr);
+
+ dev->iobase = CONFIG_FTMAC110_BASE;
+ chip->regs = (void __iomem *)dev->iobase;
+ dev->priv = chip;
+ dev->init = ftmac110_probe;
+ dev->halt = ftmac110_halt;
+ dev->send = ftmac110_send;
+ dev->recv = ftmac110_recv;
+
+ if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
+ eth_random_addr(dev->enetaddr);
+
+ /* allocate tx descriptors (it must be 16 bytes aligned) */
+ chip->txd = dma_alloc_coherent(
+ sizeof(struct ftmac110_desc) * CFG_TXDES_NUM, &chip->txd_dma);
+ if (!chip->txd)
+ panic("ftmac110: out of memory 3\n");
+ memset(chip->txd, 0,
+ sizeof(struct ftmac110_desc) * CFG_TXDES_NUM);
+ for (i = 0; i < CFG_TXDES_NUM; ++i) {
+ void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+
+ if (!va)
+ panic("ftmac110: out of memory 4\n");
+ chip->txd[i].vbuf = va;
+ chip->txd[i].pbuf = cpu_to_le32(virt_to_phys(va));
+ chip->txd[i].ctrl = 0; /* owned by SW */
+ }
+ chip->txd[i - 1].ctrl |= cpu_to_le64(FTMAC110_TXD_END);
+ chip->txd_idx = 0;
+
+ /* allocate rx descriptors (it must be 16 bytes aligned) */
+ chip->rxd = dma_alloc_coherent(
+ sizeof(struct ftmac110_desc) * CFG_RXDES_NUM, &chip->rxd_dma);
+ if (!chip->rxd)
+ panic("ftmac110: out of memory 4\n");
+ memset((void *)chip->rxd, 0,
+ sizeof(struct ftmac110_desc) * CFG_RXDES_NUM);
+ for (i = 0; i < CFG_RXDES_NUM; ++i) {
+ void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
+
+ if (!va)
+ panic("ftmac110: out of memory 5\n");
+ /* it needs to be exactly 2 bytes aligned */
+ va = ((uint8_t *)va + 2);
+ chip->rxd[i].vbuf = va;
+ chip->rxd[i].pbuf = cpu_to_le32(virt_to_phys(va));
+ chip->rxd[i].ctrl = cpu_to_le64(FTMAC110_RXD_OWNER
+ | FTMAC110_RXD_BUFSZ(CFG_XBUF_SIZE));
+ }
+ chip->rxd[i - 1].ctrl |= cpu_to_le64(FTMAC110_RXD_END);
+ chip->rxd_idx = 0;
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+#endif
+
+ card_nr++;
+
+ return card_nr;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ftmac110.h b/qemu/roms/u-boot/drivers/net/ftmac110.h
new file mode 100644
index 000000000..2772ae7b7
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ftmac110.h
@@ -0,0 +1,176 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _FTMAC110_H
+#define _FTMAC110_H
+
+struct ftmac110_regs {
+ uint32_t isr; /* 0x00: Interrups Status Register */
+ uint32_t imr; /* 0x04: Interrupt Mask Register */
+ uint32_t mac[2]; /* 0x08: MAC Address */
+ uint32_t mht[2]; /* 0x10: Multicast Hash Table Register */
+ uint32_t txpd; /* 0x18: Tx Poll Demand Register */
+ uint32_t rxpd; /* 0x1c: Rx Poll Demand Register */
+ uint32_t txba; /* 0x20: Tx Ring Base Address Register */
+ uint32_t rxba; /* 0x24: Rx Ring Base Address Register */
+ uint32_t itc; /* 0x28: Interrupt Timer Control Register */
+ uint32_t aptc; /* 0x2C: Automatic Polling Timer Control Register */
+ uint32_t dblac; /* 0x30: DMA Burst Length&Arbitration Control */
+ uint32_t revr; /* 0x34: Revision Register */
+ uint32_t fear; /* 0x38: Feature Register */
+ uint32_t rsvd[19];
+ uint32_t maccr; /* 0x88: MAC Control Register */
+ uint32_t macsr; /* 0x8C: MAC Status Register */
+ uint32_t phycr; /* 0x90: PHY Control Register */
+ uint32_t phydr; /* 0x94: PHY Data Register */
+ uint32_t fcr; /* 0x98: Flow Control Register */
+ uint32_t bpr; /* 0x9C: Back Pressure Register */
+};
+
+/*
+ * Interrupt status/mask register(ISR/IMR) bits
+ */
+#define ISR_ALL 0x3ff
+#define ISR_PHYSTCHG (1 << 9) /* phy status change */
+#define ISR_AHBERR (1 << 8) /* bus error */
+#define ISR_RXLOST (1 << 7) /* rx lost */
+#define ISR_RXFIFO (1 << 6) /* rx to fifo */
+#define ISR_TXLOST (1 << 5) /* tx lost */
+#define ISR_TXOK (1 << 4) /* tx to ethernet */
+#define ISR_NOTXBUF (1 << 3) /* out of tx buffer */
+#define ISR_TXFIFO (1 << 2) /* tx to fifo */
+#define ISR_NORXBUF (1 << 1) /* out of rx buffer */
+#define ISR_RXOK (1 << 0) /* rx to buffer */
+
+/*
+ * MACCR control bits
+ */
+#define MACCR_100M (1 << 18) /* 100Mbps mode */
+#define MACCR_RXBCST (1 << 17) /* rx broadcast packet */
+#define MACCR_RXMCST (1 << 16) /* rx multicast packet */
+#define MACCR_FD (1 << 15) /* full duplex */
+#define MACCR_CRCAPD (1 << 14) /* tx crc append */
+#define MACCR_RXALL (1 << 12) /* rx all packets */
+#define MACCR_RXFTL (1 << 11) /* rx packet even it's > 1518 byte */
+#define MACCR_RXRUNT (1 << 10) /* rx packet even it's < 64 byte */
+#define MACCR_RXMCSTHT (1 << 9) /* rx multicast hash table */
+#define MACCR_RXEN (1 << 8) /* rx enable */
+#define MACCR_RXINHDTX (1 << 6) /* rx in half duplex tx */
+#define MACCR_TXEN (1 << 5) /* tx enable */
+#define MACCR_CRCDIS (1 << 4) /* tx packet even it's crc error */
+#define MACCR_LOOPBACK (1 << 3) /* loop-back */
+#define MACCR_RESET (1 << 2) /* reset */
+#define MACCR_RXDMAEN (1 << 1) /* rx dma enable */
+#define MACCR_TXDMAEN (1 << 0) /* tx dma enable */
+
+/*
+ * PHYCR control bits
+ */
+#define PHYCR_READ (1 << 26)
+#define PHYCR_WRITE (1 << 27)
+#define PHYCR_REG_SHIFT 21
+#define PHYCR_ADDR_SHIFT 16
+
+/*
+ * ITC control bits
+ */
+
+/* Tx Cycle Length */
+#define ITC_TX_CYCLONG (1 << 15) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_TX_CYCNORM (0 << 15) /* 100Mbps=5.12us; 10Mbps=51.2us */
+/* Tx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_TX_THR(n) (((n) & 0x7) << 12)
+/* Tx Interrupt Timeout = n * Tx Cycle */
+#define ITC_TX_ITMO(n) (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define ITC_RX_CYCLONG (1 << 7) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_RX_CYCNORM (0 << 7) /* 100Mbps=5.12us; 10Mbps=51.2us */
+/* Rx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_RX_THR(n) (((n) & 0x7) << 4)
+/* Rx Interrupt Timeout = n * Rx Cycle */
+#define ITC_RX_ITMO(n) (((n) & 0xf) << 0)
+
+#define ITC_DEFAULT \
+ (ITC_TX_THR(1) | ITC_TX_ITMO(0) | ITC_RX_THR(1) | ITC_RX_ITMO(0))
+
+/*
+ * APTC contrl bits
+ */
+
+/* Tx Cycle Length */
+#define APTC_TX_CYCLONG (1 << 12) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_TX_CYCNORM (0 << 12) /* 100Mbps=5.12us; 10Mbps=51.2us */
+/* Tx Poll Timeout = n * Tx Cycle, 0=No auto polling */
+#define APTC_TX_PTMO(n) (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define APTC_RX_CYCLONG (1 << 4) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_RX_CYCNORM (0 << 4) /* 100Mbps=5.12us; 10Mbps=51.2us */
+/* Rx Poll Timeout = n * Rx Cycle, 0=No auto polling */
+#define APTC_RX_PTMO(n) (((n) & 0xf) << 0)
+
+#define APTC_DEFAULT (APTC_TX_PTMO(0) | APTC_RX_PTMO(1))
+
+/*
+ * DBLAC contrl bits
+ */
+#define DBLAC_BURST_MAX_ANY (0 << 14) /* un-limited */
+#define DBLAC_BURST_MAX_32X4 (2 << 14) /* max = 32 x 4 bytes */
+#define DBLAC_BURST_MAX_64X4 (3 << 14) /* max = 64 x 4 bytes */
+#define DBLAC_RXTHR_EN (1 << 9) /* enable rx threshold arbitration */
+#define DBLAC_RXTHR_HIGH(n) (((n) & 0x7) << 6) /* upper bound = n/8 fifo */
+#define DBLAC_RXTHR_LOW(n) (((n) & 0x7) << 3) /* lower bound = n/8 fifo */
+#define DBLAC_BURST_CAP16 (1 << 2) /* support burst 16 */
+#define DBLAC_BURST_CAP8 (1 << 1) /* support burst 8 */
+#define DBLAC_BURST_CAP4 (1 << 0) /* support burst 4 */
+
+#define DBLAC_DEFAULT \
+ (DBLAC_RXTHR_EN | DBLAC_RXTHR_HIGH(6) | DBLAC_RXTHR_LOW(2))
+
+/*
+ * descriptor structure
+ */
+struct ftmac110_desc {
+ uint64_t ctrl;
+ uint32_t pbuf;
+ void *vbuf;
+};
+
+#define FTMAC110_RXD_END ((uint64_t)1 << 63)
+#define FTMAC110_RXD_BUFSZ(x) (((uint64_t)(x) & 0x7ff) << 32)
+
+#define FTMAC110_RXD_OWNER ((uint64_t)1 << 31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_RXD_FRS ((uint64_t)1 << 29) /* first pkt desc */
+#define FTMAC110_RXD_LRS ((uint64_t)1 << 28) /* last pkt desc */
+#define FTMAC110_RXD_ODDNB ((uint64_t)1 << 22) /* odd nibble */
+#define FTMAC110_RXD_RUNT ((uint64_t)1 << 21) /* runt pkt */
+#define FTMAC110_RXD_FTL ((uint64_t)1 << 20) /* frame too long */
+#define FTMAC110_RXD_CRC ((uint64_t)1 << 19) /* pkt crc error */
+#define FTMAC110_RXD_ERR ((uint64_t)1 << 18) /* bus error */
+#define FTMAC110_RXD_ERRMASK ((uint64_t)0x1f << 18)
+#define FTMAC110_RXD_BCST ((uint64_t)1 << 17) /* Bcst pkt */
+#define FTMAC110_RXD_MCST ((uint64_t)1 << 16) /* Mcst pkt */
+#define FTMAC110_RXD_LEN(x) ((uint64_t)((x) & 0x7ff))
+
+#define FTMAC110_RXD_CLRMASK \
+ (FTMAC110_RXD_END | FTMAC110_RXD_BUFSZ(0x7ff))
+
+#define FTMAC110_TXD_END ((uint64_t)1 << 63) /* end of ring */
+#define FTMAC110_TXD_TXIC ((uint64_t)1 << 62) /* tx done interrupt */
+#define FTMAC110_TXD_TX2FIC ((uint64_t)1 << 61) /* tx fifo interrupt */
+#define FTMAC110_TXD_FTS ((uint64_t)1 << 60) /* first pkt desc */
+#define FTMAC110_TXD_LTS ((uint64_t)1 << 59) /* last pkt desc */
+#define FTMAC110_TXD_LEN(x) ((uint64_t)((x) & 0x7ff) << 32)
+
+#define FTMAC110_TXD_OWNER ((uint64_t)1 << 31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_TXD_COL ((uint64_t)3) /* collision */
+
+#define FTMAC110_TXD_CLRMASK \
+ (FTMAC110_TXD_END)
+
+#endif /* FTMAC110_H */
diff --git a/qemu/roms/u-boot/drivers/net/greth.c b/qemu/roms/u-boot/drivers/net/greth.c
new file mode 100644
index 000000000..c817af4da
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/greth.c
@@ -0,0 +1,670 @@
+/* Gaisler.com GRETH 10/100/1000 Ethernet MAC driver
+ *
+ * Driver use polling mode (no Interrupt)
+ *
+ * (C) Copyright 2007
+ * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <netdev.h>
+#include <malloc.h>
+#include <asm/processor.h>
+#include <ambapp.h>
+#include <asm/leon.h>
+
+#include "greth.h"
+
+/* Default to 3s timeout on autonegotiation */
+#ifndef GRETH_PHY_TIMEOUT_MS
+#define GRETH_PHY_TIMEOUT_MS 3000
+#endif
+
+/* Default to PHY adrress 0 not not specified */
+#ifdef CONFIG_SYS_GRLIB_GRETH_PHYADDR
+#define GRETH_PHY_ADR_DEFAULT CONFIG_SYS_GRLIB_GRETH_PHYADDR
+#else
+#define GRETH_PHY_ADR_DEFAULT 0
+#endif
+
+/* ByPass Cache when reading regs */
+#define GRETH_REGLOAD(addr) SPARC_NOCACHE_READ(addr)
+/* Write-through cache ==> no bypassing needed on writes */
+#define GRETH_REGSAVE(addr,data) (*(volatile unsigned int *)(addr) = (data))
+#define GRETH_REGORIN(addr,data) GRETH_REGSAVE(addr,GRETH_REGLOAD(addr)|data)
+#define GRETH_REGANDIN(addr,data) GRETH_REGSAVE(addr,GRETH_REGLOAD(addr)&data)
+
+#define GRETH_RXBD_CNT 4
+#define GRETH_TXBD_CNT 1
+
+#define GRETH_RXBUF_SIZE 1540
+#define GRETH_BUF_ALIGN 4
+#define GRETH_RXBUF_EFF_SIZE \
+ ( (GRETH_RXBUF_SIZE&~(GRETH_BUF_ALIGN-1))+GRETH_BUF_ALIGN )
+
+typedef struct {
+ greth_regs *regs;
+ int irq;
+ struct eth_device *dev;
+
+ /* Hardware info */
+ unsigned char phyaddr;
+ int gbit_mac;
+
+ /* Current operating Mode */
+ int gb; /* GigaBit */
+ int fd; /* Full Duplex */
+ int sp; /* 10/100Mbps speed (1=100,0=10) */
+ int auto_neg; /* Auto negotiate done */
+
+ unsigned char hwaddr[6]; /* MAC Address */
+
+ /* Descriptors */
+ greth_bd *rxbd_base, *rxbd_max;
+ greth_bd *txbd_base, *txbd_max;
+
+ greth_bd *rxbd_curr;
+
+ /* rx buffers in rx descriptors */
+ void *rxbuf_base; /* (GRETH_RXBUF_SIZE+ALIGNBYTES) * GRETH_RXBD_CNT */
+
+ /* unused for gbit_mac, temp buffer for sending packets with unligned
+ * start.
+ * Pointer to packet allocated with malloc.
+ */
+ void *txbuf;
+
+ struct {
+ /* rx status */
+ unsigned int rx_packets,
+ rx_crc_errors, rx_frame_errors, rx_length_errors, rx_errors;
+
+ /* tx stats */
+ unsigned int tx_packets,
+ tx_latecol_errors,
+ tx_underrun_errors, tx_limit_errors, tx_errors;
+ } stats;
+} greth_priv;
+
+/* Read MII register 'addr' from core 'regs' */
+static int read_mii(int phyaddr, int regaddr, volatile greth_regs * regs)
+{
+ while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
+ }
+
+ GRETH_REGSAVE(&regs->mdio, ((phyaddr & 0x1F) << 11) | ((regaddr & 0x1F) << 6) | 2);
+
+ while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
+ }
+
+ if (!(GRETH_REGLOAD(&regs->mdio) & GRETH_MII_NVALID)) {
+ return (GRETH_REGLOAD(&regs->mdio) >> 16) & 0xFFFF;
+ } else {
+ return -1;
+ }
+}
+
+static void write_mii(int phyaddr, int regaddr, int data, volatile greth_regs * regs)
+{
+ while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
+ }
+
+ GRETH_REGSAVE(&regs->mdio,
+ ((data & 0xFFFF) << 16) | ((phyaddr & 0x1F) << 11) |
+ ((regaddr & 0x1F) << 6) | 1);
+
+ while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
+ }
+
+}
+
+/* init/start hardware and allocate descriptor buffers for rx side
+ *
+ */
+int greth_init(struct eth_device *dev, bd_t * bis)
+{
+ int i;
+
+ greth_priv *greth = dev->priv;
+ greth_regs *regs = greth->regs;
+
+ debug("greth_init\n");
+
+ /* Reset core */
+ GRETH_REGSAVE(&regs->control, (GRETH_RESET | (greth->gb << 8) |
+ (greth->sp << 7) | (greth->fd << 4)));
+
+ /* Wait for Reset to complete */
+ while ( GRETH_REGLOAD(&regs->control) & GRETH_RESET) ;
+
+ GRETH_REGSAVE(&regs->control,
+ ((greth->gb << 8) | (greth->sp << 7) | (greth->fd << 4)));
+
+ if (!greth->rxbd_base) {
+
+ /* allocate descriptors */
+ greth->rxbd_base = (greth_bd *)
+ memalign(0x1000, GRETH_RXBD_CNT * sizeof(greth_bd));
+ greth->txbd_base = (greth_bd *)
+ memalign(0x1000, GRETH_TXBD_CNT * sizeof(greth_bd));
+
+ /* allocate buffers to all descriptors */
+ greth->rxbuf_base =
+ malloc(GRETH_RXBUF_EFF_SIZE * GRETH_RXBD_CNT);
+ }
+
+ /* initate rx decriptors */
+ for (i = 0; i < GRETH_RXBD_CNT; i++) {
+ greth->rxbd_base[i].addr = (unsigned int)
+ greth->rxbuf_base + (GRETH_RXBUF_EFF_SIZE * i);
+ /* enable desciptor & set wrap bit if last descriptor */
+ if (i >= (GRETH_RXBD_CNT - 1)) {
+ greth->rxbd_base[i].stat = GRETH_BD_EN | GRETH_BD_WR;
+ } else {
+ greth->rxbd_base[i].stat = GRETH_BD_EN;
+ }
+ }
+
+ /* initiate indexes */
+ greth->rxbd_curr = greth->rxbd_base;
+ greth->rxbd_max = greth->rxbd_base + (GRETH_RXBD_CNT - 1);
+ greth->txbd_max = greth->txbd_base + (GRETH_TXBD_CNT - 1);
+ /*
+ * greth->txbd_base->addr = 0;
+ * greth->txbd_base->stat = GRETH_BD_WR;
+ */
+
+ /* initate tx decriptors */
+ for (i = 0; i < GRETH_TXBD_CNT; i++) {
+ greth->txbd_base[i].addr = 0;
+ /* enable desciptor & set wrap bit if last descriptor */
+ if (i >= (GRETH_TXBD_CNT - 1)) {
+ greth->txbd_base[i].stat = GRETH_BD_WR;
+ } else {
+ greth->txbd_base[i].stat = 0;
+ }
+ }
+
+ /**** SET HARDWARE REGS ****/
+
+ /* Set pointer to tx/rx descriptor areas */
+ GRETH_REGSAVE(&regs->rx_desc_p, (unsigned int)&greth->rxbd_base[0]);
+ GRETH_REGSAVE(&regs->tx_desc_p, (unsigned int)&greth->txbd_base[0]);
+
+ /* Enable Transmitter, GRETH will now scan descriptors for packets
+ * to transmitt */
+ debug("greth_init: enabling receiver\n");
+ GRETH_REGORIN(&regs->control, GRETH_RXEN);
+
+ return 0;
+}
+
+/* Initiate PHY to a relevant speed
+ * return:
+ * - 0 = success
+ * - 1 = timeout/fail
+ */
+int greth_init_phy(greth_priv * dev, bd_t * bis)
+{
+ greth_regs *regs = dev->regs;
+ int tmp, tmp1, tmp2, i;
+ unsigned int start, timeout;
+ int phyaddr = GRETH_PHY_ADR_DEFAULT;
+
+#ifndef CONFIG_SYS_GRLIB_GRETH_PHYADDR
+ /* If BSP doesn't provide a hardcoded PHY address the driver will
+ * try to autodetect PHY address by stopping the search on the first
+ * PHY address which has REG0 implemented.
+ */
+ for (i=0; i<32; i++) {
+ tmp = read_mii(i, 0, regs);
+ if ( (tmp != 0) && (tmp != 0xffff) ) {
+ phyaddr = i;
+ break;
+ }
+ }
+#endif
+
+ /* Save PHY Address */
+ dev->phyaddr = phyaddr;
+
+ debug("GRETH PHY ADDRESS: %d\n", phyaddr);
+
+ /* X msecs to ticks */
+ timeout = usec2ticks(GRETH_PHY_TIMEOUT_MS * 1000);
+
+ /* Get system timer0 current value
+ * Total timeout is 5s
+ */
+ start = get_timer(0);
+
+ /* get phy control register default values */
+
+ while ((tmp = read_mii(phyaddr, 0, regs)) & 0x8000) {
+ if (get_timer(start) > timeout) {
+ debug("greth_init_phy: PHY read 1 failed\n");
+ return 1; /* Fail */
+ }
+ }
+
+ /* reset PHY and wait for completion */
+ write_mii(phyaddr, 0, 0x8000 | tmp, regs);
+
+ while (((tmp = read_mii(phyaddr, 0, regs))) & 0x8000) {
+ if (get_timer(start) > timeout) {
+ debug("greth_init_phy: PHY read 2 failed\n");
+ return 1; /* Fail */
+ }
+ }
+
+ /* Check if PHY is autoneg capable and then determine operating
+ * mode, otherwise force it to 10 Mbit halfduplex
+ */
+ dev->gb = 0;
+ dev->fd = 0;
+ dev->sp = 0;
+ dev->auto_neg = 0;
+ if (!((tmp >> 12) & 1)) {
+ write_mii(phyaddr, 0, 0, regs);
+ } else {
+ /* wait for auto negotiation to complete and then check operating mode */
+ dev->auto_neg = 1;
+ i = 0;
+ while (!(((tmp = read_mii(phyaddr, 1, regs)) >> 5) & 1)) {
+ if (get_timer(start) > timeout) {
+ printf("Auto negotiation timed out. "
+ "Selecting default config\n");
+ tmp = read_mii(phyaddr, 0, regs);
+ dev->gb = ((tmp >> 6) & 1)
+ && !((tmp >> 13) & 1);
+ dev->sp = !((tmp >> 6) & 1)
+ && ((tmp >> 13) & 1);
+ dev->fd = (tmp >> 8) & 1;
+ goto auto_neg_done;
+ }
+ }
+ if ((tmp >> 8) & 1) {
+ tmp1 = read_mii(phyaddr, 9, regs);
+ tmp2 = read_mii(phyaddr, 10, regs);
+ if ((tmp1 & GRETH_MII_EXTADV_1000FD) &&
+ (tmp2 & GRETH_MII_EXTPRT_1000FD)) {
+ dev->gb = 1;
+ dev->fd = 1;
+ }
+ if ((tmp1 & GRETH_MII_EXTADV_1000HD) &&
+ (tmp2 & GRETH_MII_EXTPRT_1000HD)) {
+ dev->gb = 1;
+ dev->fd = 0;
+ }
+ }
+ if ((dev->gb == 0) || ((dev->gb == 1) && (dev->gbit_mac == 0))) {
+ tmp1 = read_mii(phyaddr, 4, regs);
+ tmp2 = read_mii(phyaddr, 5, regs);
+ if ((tmp1 & GRETH_MII_100TXFD) &&
+ (tmp2 & GRETH_MII_100TXFD)) {
+ dev->sp = 1;
+ dev->fd = 1;
+ }
+ if ((tmp1 & GRETH_MII_100TXHD) &&
+ (tmp2 & GRETH_MII_100TXHD)) {
+ dev->sp = 1;
+ dev->fd = 0;
+ }
+ if ((tmp1 & GRETH_MII_10FD) && (tmp2 & GRETH_MII_10FD)) {
+ dev->fd = 1;
+ }
+ if ((dev->gb == 1) && (dev->gbit_mac == 0)) {
+ dev->gb = 0;
+ dev->fd = 0;
+ write_mii(phyaddr, 0, dev->sp << 13, regs);
+ }
+ }
+
+ }
+ auto_neg_done:
+ debug("%s GRETH Ethermac at [0x%x] irq %d. Running \
+ %d Mbps %s duplex\n", dev->gbit_mac ? "10/100/1000" : "10/100", (unsigned int)(regs), (unsigned int)(dev->irq), dev->gb ? 1000 : (dev->sp ? 100 : 10), dev->fd ? "full" : "half");
+ /* Read out PHY info if extended registers are available */
+ if (tmp & 1) {
+ tmp1 = read_mii(phyaddr, 2, regs);
+ tmp2 = read_mii(phyaddr, 3, regs);
+ tmp1 = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
+ tmp = tmp2 & 0xF;
+
+ tmp2 = (tmp2 >> 4) & 0x3F;
+ debug("PHY: Vendor %x Device %x Revision %d\n", tmp1,
+ tmp2, tmp);
+ } else {
+ printf("PHY info not available\n");
+ }
+
+ /* set speed and duplex bits in control register */
+ GRETH_REGORIN(&regs->control,
+ (dev->gb << 8) | (dev->sp << 7) | (dev->fd << 4));
+
+ return 0;
+}
+
+void greth_halt(struct eth_device *dev)
+{
+ greth_priv *greth;
+ greth_regs *regs;
+ int i;
+
+ debug("greth_halt\n");
+
+ if (!dev || !dev->priv)
+ return;
+
+ greth = dev->priv;
+ regs = greth->regs;
+
+ if (!regs)
+ return;
+
+ /* disable receiver/transmitter by clearing the enable bits */
+ GRETH_REGANDIN(&regs->control, ~(GRETH_RXEN | GRETH_TXEN));
+
+ /* reset rx/tx descriptors */
+ if (greth->rxbd_base) {
+ for (i = 0; i < GRETH_RXBD_CNT; i++) {
+ greth->rxbd_base[i].stat =
+ (i >= (GRETH_RXBD_CNT - 1)) ? GRETH_BD_WR : 0;
+ }
+ }
+
+ if (greth->txbd_base) {
+ for (i = 0; i < GRETH_TXBD_CNT; i++) {
+ greth->txbd_base[i].stat =
+ (i >= (GRETH_TXBD_CNT - 1)) ? GRETH_BD_WR : 0;
+ }
+ }
+}
+
+int greth_send(struct eth_device *dev, void *eth_data, int data_length)
+{
+ greth_priv *greth = dev->priv;
+ greth_regs *regs = greth->regs;
+ greth_bd *txbd;
+ void *txbuf;
+ unsigned int status;
+
+ debug("greth_send\n");
+
+ /* send data, wait for data to be sent, then return */
+ if (((unsigned int)eth_data & (GRETH_BUF_ALIGN - 1))
+ && !greth->gbit_mac) {
+ /* data not aligned as needed by GRETH 10/100, solve this by allocating 4 byte aligned buffer
+ * and copy data to before giving it to GRETH.
+ */
+ if (!greth->txbuf) {
+ greth->txbuf = malloc(GRETH_RXBUF_SIZE);
+ }
+
+ txbuf = greth->txbuf;
+
+ /* copy data info buffer */
+ memcpy((char *)txbuf, (char *)eth_data, data_length);
+
+ /* keep buffer to next time */
+ } else {
+ txbuf = (void *)eth_data;
+ }
+ /* get descriptor to use, only 1 supported... hehe easy */
+ txbd = greth->txbd_base;
+
+ /* setup descriptor to wrap around to it self */
+ txbd->addr = (unsigned int)txbuf;
+ txbd->stat = GRETH_BD_EN | GRETH_BD_WR | data_length;
+
+ /* Remind Core which descriptor to use when sending */
+ GRETH_REGSAVE(&regs->tx_desc_p, (unsigned int)txbd);
+
+ /* initate send by enabling transmitter */
+ GRETH_REGORIN(&regs->control, GRETH_TXEN);
+
+ /* Wait for data to be sent */
+ while ((status = GRETH_REGLOAD(&txbd->stat)) & GRETH_BD_EN) {
+ ;
+ }
+
+ /* was the packet transmitted succesfully? */
+ if (status & GRETH_TXBD_ERR_AL) {
+ greth->stats.tx_limit_errors++;
+ }
+
+ if (status & GRETH_TXBD_ERR_UE) {
+ greth->stats.tx_underrun_errors++;
+ }
+
+ if (status & GRETH_TXBD_ERR_LC) {
+ greth->stats.tx_latecol_errors++;
+ }
+
+ if (status &
+ (GRETH_TXBD_ERR_LC | GRETH_TXBD_ERR_UE | GRETH_TXBD_ERR_AL)) {
+ /* any error */
+ greth->stats.tx_errors++;
+ return -1;
+ }
+
+ /* bump tx packet counter */
+ greth->stats.tx_packets++;
+
+ /* return succefully */
+ return 0;
+}
+
+int greth_recv(struct eth_device *dev)
+{
+ greth_priv *greth = dev->priv;
+ greth_regs *regs = greth->regs;
+ greth_bd *rxbd;
+ unsigned int status, len = 0, bad;
+ char *d;
+ int enable = 0;
+ int i;
+
+ /* Receive One packet only, but clear as many error packets as there are
+ * available.
+ */
+ {
+ /* current receive descriptor */
+ rxbd = greth->rxbd_curr;
+
+ /* get status of next received packet */
+ status = GRETH_REGLOAD(&rxbd->stat);
+
+ bad = 0;
+
+ /* stop if no more packets received */
+ if (status & GRETH_BD_EN) {
+ goto done;
+ }
+
+ debug("greth_recv: packet 0x%x, 0x%x, len: %d\n",
+ (unsigned int)rxbd, status, status & GRETH_BD_LEN);
+
+ /* Check status for errors.
+ */
+ if (status & GRETH_RXBD_ERR_FT) {
+ greth->stats.rx_length_errors++;
+ bad = 1;
+ }
+ if (status & (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE)) {
+ greth->stats.rx_frame_errors++;
+ bad = 1;
+ }
+ if (status & GRETH_RXBD_ERR_CRC) {
+ greth->stats.rx_crc_errors++;
+ bad = 1;
+ }
+ if (bad) {
+ greth->stats.rx_errors++;
+ printf
+ ("greth_recv: Bad packet (%d, %d, %d, 0x%08x, %d)\n",
+ greth->stats.rx_length_errors,
+ greth->stats.rx_frame_errors,
+ greth->stats.rx_crc_errors, status,
+ greth->stats.rx_packets);
+ /* print all rx descriptors */
+ for (i = 0; i < GRETH_RXBD_CNT; i++) {
+ printf("[%d]: Stat=0x%lx, Addr=0x%lx\n", i,
+ GRETH_REGLOAD(&greth->rxbd_base[i].stat),
+ GRETH_REGLOAD(&greth->rxbd_base[i].addr));
+ }
+ } else {
+ /* Process the incoming packet. */
+ len = status & GRETH_BD_LEN;
+ d = (char *)rxbd->addr;
+
+ debug
+ ("greth_recv: new packet, length: %d. data: %x %x %x %x %x %x %x %x\n",
+ len, d[0], d[1], d[2], d[3], d[4], d[5], d[6],
+ d[7]);
+
+ /* flush all data cache to make sure we're not reading old packet data */
+ sparc_dcache_flush_all();
+
+ /* pass packet on to network subsystem */
+ NetReceive((void *)d, len);
+
+ /* bump stats counters */
+ greth->stats.rx_packets++;
+
+ /* bad is now 0 ==> will stop loop */
+ }
+
+ /* reenable descriptor to receive more packet with this descriptor, wrap around if needed */
+ rxbd->stat =
+ GRETH_BD_EN |
+ (((unsigned int)greth->rxbd_curr >=
+ (unsigned int)greth->rxbd_max) ? GRETH_BD_WR : 0);
+ enable = 1;
+
+ /* increase index */
+ greth->rxbd_curr =
+ ((unsigned int)greth->rxbd_curr >=
+ (unsigned int)greth->rxbd_max) ? greth->
+ rxbd_base : (greth->rxbd_curr + 1);
+
+ }
+
+ if (enable) {
+ GRETH_REGORIN(&regs->control, GRETH_RXEN);
+ }
+ done:
+ /* return positive length of packet or 0 if non received */
+ return len;
+}
+
+void greth_set_hwaddr(greth_priv * greth, unsigned char *mac)
+{
+ /* save new MAC address */
+ greth->dev->enetaddr[0] = greth->hwaddr[0] = mac[0];
+ greth->dev->enetaddr[1] = greth->hwaddr[1] = mac[1];
+ greth->dev->enetaddr[2] = greth->hwaddr[2] = mac[2];
+ greth->dev->enetaddr[3] = greth->hwaddr[3] = mac[3];
+ greth->dev->enetaddr[4] = greth->hwaddr[4] = mac[4];
+ greth->dev->enetaddr[5] = greth->hwaddr[5] = mac[5];
+ greth->regs->esa_msb = (mac[0] << 8) | mac[1];
+ greth->regs->esa_lsb =
+ (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5];
+
+ debug("GRETH: New MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+int greth_initialize(bd_t * bis)
+{
+ greth_priv *greth;
+ ambapp_apbdev apbdev;
+ struct eth_device *dev;
+ int i;
+ char *addr_str, *end;
+ unsigned char addr[6];
+
+ debug("Scanning for GRETH\n");
+
+ /* Find Device & IRQ via AMBA Plug&Play information */
+ if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_ETHMAC, &apbdev) != 1) {
+ return -1; /* GRETH not found */
+ }
+
+ greth = (greth_priv *) malloc(sizeof(greth_priv));
+ dev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ memset(dev, 0, sizeof(struct eth_device));
+ memset(greth, 0, sizeof(greth_priv));
+
+ greth->regs = (greth_regs *) apbdev.address;
+ greth->irq = apbdev.irq;
+ debug("Found GRETH at %p, irq %d\n", greth->regs, greth->irq);
+ dev->priv = (void *)greth;
+ dev->iobase = (unsigned int)greth->regs;
+ dev->init = greth_init;
+ dev->halt = greth_halt;
+ dev->send = greth_send;
+ dev->recv = greth_recv;
+ greth->dev = dev;
+
+ /* Reset Core */
+ GRETH_REGSAVE(&greth->regs->control, GRETH_RESET);
+
+ /* Wait for core to finish reset cycle */
+ while (GRETH_REGLOAD(&greth->regs->control) & GRETH_RESET) ;
+
+ /* Get the phy address which assumed to have been set
+ correctly with the reset value in hardware */
+ greth->phyaddr = (GRETH_REGLOAD(&greth->regs->mdio) >> 11) & 0x1F;
+
+ /* Check if mac is gigabit capable */
+ greth->gbit_mac = (GRETH_REGLOAD(&greth->regs->control) >> 27) & 1;
+
+ /* Make descriptor string */
+ if (greth->gbit_mac) {
+ sprintf(dev->name, "GRETH_10/100/GB");
+ } else {
+ sprintf(dev->name, "GRETH_10/100");
+ }
+
+ /* initiate PHY, select speed/duplex depending on connected PHY */
+ if (greth_init_phy(greth, bis)) {
+ /* Failed to init PHY (timedout) */
+ debug("GRETH[%p]: Failed to init PHY\n", greth->regs);
+ return -1;
+ }
+
+ /* Register Device to EtherNet subsystem */
+ eth_register(dev);
+
+ /* Get MAC address */
+ if ((addr_str = getenv("ethaddr")) != NULL) {
+ for (i = 0; i < 6; i++) {
+ addr[i] =
+ addr_str ? simple_strtoul(addr_str, &end, 16) : 0;
+ if (addr_str) {
+ addr_str = (*end) ? end + 1 : end;
+ }
+ }
+ } else {
+ /* HW Address not found in environment, Set default HW address */
+ addr[0] = GRETH_HWADDR_0; /* MSB */
+ addr[1] = GRETH_HWADDR_1;
+ addr[2] = GRETH_HWADDR_2;
+ addr[3] = GRETH_HWADDR_3;
+ addr[4] = GRETH_HWADDR_4;
+ addr[5] = GRETH_HWADDR_5; /* LSB */
+ }
+
+ /* set and remember MAC address */
+ greth_set_hwaddr(greth, addr);
+
+ debug("GRETH[%p]: Initialized successfully\n", greth->regs);
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/greth.h b/qemu/roms/u-boot/drivers/net/greth.h
new file mode 100644
index 000000000..5299b2861
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/greth.h
@@ -0,0 +1,81 @@
+/* Gaisler.com GRETH 10/100/1000 Ethernet MAC driver
+ *
+ * (C) Copyright 2007
+ * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#define GRETH_FD 0x10
+#define GRETH_RESET 0x40
+#define GRETH_MII_BUSY 0x8
+#define GRETH_MII_NVALID 0x10
+
+/* MII registers */
+#define GRETH_MII_EXTADV_1000FD 0x00000200
+#define GRETH_MII_EXTADV_1000HD 0x00000100
+#define GRETH_MII_EXTPRT_1000FD 0x00000800
+#define GRETH_MII_EXTPRT_1000HD 0x00000400
+
+#define GRETH_MII_100T4 0x00000200
+#define GRETH_MII_100TXFD 0x00000100
+#define GRETH_MII_100TXHD 0x00000080
+#define GRETH_MII_10FD 0x00000040
+#define GRETH_MII_10HD 0x00000020
+
+#define GRETH_BD_EN 0x800
+#define GRETH_BD_WR 0x1000
+#define GRETH_BD_IE 0x2000
+#define GRETH_BD_LEN 0x7FF
+
+#define GRETH_TXEN 0x1
+#define GRETH_INT_TX 0x8
+#define GRETH_TXI 0x4
+#define GRETH_TXBD_STATUS 0x0001C000
+#define GRETH_TXBD_MORE 0x20000
+#define GRETH_TXBD_IPCS 0x40000
+#define GRETH_TXBD_TCPCS 0x80000
+#define GRETH_TXBD_UDPCS 0x100000
+#define GRETH_TXBD_ERR_LC 0x10000
+#define GRETH_TXBD_ERR_UE 0x4000
+#define GRETH_TXBD_ERR_AL 0x8000
+#define GRETH_TXBD_NUM 128
+#define GRETH_TXBD_NUM_MASK (GRETH_TXBD_NUM-1)
+#define GRETH_TX_BUF_SIZE 2048
+
+#define GRETH_INT_RX 0x4
+#define GRETH_RXEN 0x2
+#define GRETH_RXI 0x8
+#define GRETH_RXBD_STATUS 0xFFFFC000
+#define GRETH_RXBD_ERR_AE 0x4000
+#define GRETH_RXBD_ERR_FT 0x8000
+#define GRETH_RXBD_ERR_CRC 0x10000
+#define GRETH_RXBD_ERR_OE 0x20000
+#define GRETH_RXBD_ERR_LE 0x40000
+#define GRETH_RXBD_IP_DEC 0x80000
+#define GRETH_RXBD_IP_CSERR 0x100000
+#define GRETH_RXBD_UDP_DEC 0x200000
+#define GRETH_RXBD_UDP_CSERR 0x400000
+#define GRETH_RXBD_TCP_DEC 0x800000
+#define GRETH_RXBD_TCP_CSERR 0x1000000
+
+#define GRETH_RXBD_NUM 128
+#define GRETH_RXBD_NUM_MASK (GRETH_RXBD_NUM-1)
+#define GRETH_RX_BUF_SIZE 2048
+
+/* Ethernet configuration registers */
+typedef struct _greth_regs {
+ volatile unsigned int control;
+ volatile unsigned int status;
+ volatile unsigned int esa_msb;
+ volatile unsigned int esa_lsb;
+ volatile unsigned int mdio;
+ volatile unsigned int tx_desc_p;
+ volatile unsigned int rx_desc_p;
+} greth_regs;
+
+/* Ethernet buffer descriptor */
+typedef struct _greth_bd {
+ volatile unsigned int stat;
+ unsigned int addr; /* Buffer address not changed by HW */
+} greth_bd;
diff --git a/qemu/roms/u-boot/drivers/net/keystone_net.c b/qemu/roms/u-boot/drivers/net/keystone_net.c
new file mode 100644
index 000000000..f95c92807
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/keystone_net.c
@@ -0,0 +1,716 @@
+/*
+ * Ethernet driver for TI K2HK EVM.
+ *
+ * (C) Copyright 2012-2014
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <command.h>
+
+#include <net.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <asm/arch/emac_defs.h>
+#include <asm/arch/psc_defs.h>
+#include <asm/arch/keystone_nav.h>
+
+unsigned int emac_dbg;
+
+unsigned int emac_open;
+static unsigned int sys_has_mdio = 1;
+
+#ifdef KEYSTONE2_EMAC_GIG_ENABLE
+#define emac_gigabit_enable(x) keystone2_eth_gigabit_enable(x)
+#else
+#define emac_gigabit_enable(x) /* no gigabit to enable */
+#endif
+
+#define RX_BUFF_NUMS 24
+#define RX_BUFF_LEN 1520
+#define MAX_SIZE_STREAM_BUFFER RX_BUFF_LEN
+
+static u8 rx_buffs[RX_BUFF_NUMS * RX_BUFF_LEN] __aligned(16);
+
+struct rx_buff_desc net_rx_buffs = {
+ .buff_ptr = rx_buffs,
+ .num_buffs = RX_BUFF_NUMS,
+ .buff_len = RX_BUFF_LEN,
+ .rx_flow = 22,
+};
+
+static void keystone2_eth_mdio_enable(void);
+
+static int gen_get_link_speed(int phy_addr);
+
+/* EMAC Addresses */
+static volatile struct emac_regs *adap_emac =
+ (struct emac_regs *)EMAC_EMACSL_BASE_ADDR;
+static volatile struct mdio_regs *adap_mdio =
+ (struct mdio_regs *)EMAC_MDIO_BASE_ADDR;
+
+int keystone2_eth_read_mac_addr(struct eth_device *dev)
+{
+ struct eth_priv_t *eth_priv;
+ u32 maca = 0;
+ u32 macb = 0;
+
+ eth_priv = (struct eth_priv_t *)dev->priv;
+
+ /* Read the e-fuse mac address */
+ if (eth_priv->slave_port == 1) {
+ maca = __raw_readl(MAC_ID_BASE_ADDR);
+ macb = __raw_readl(MAC_ID_BASE_ADDR + 4);
+ }
+
+ dev->enetaddr[0] = (macb >> 8) & 0xff;
+ dev->enetaddr[1] = (macb >> 0) & 0xff;
+ dev->enetaddr[2] = (maca >> 24) & 0xff;
+ dev->enetaddr[3] = (maca >> 16) & 0xff;
+ dev->enetaddr[4] = (maca >> 8) & 0xff;
+ dev->enetaddr[5] = (maca >> 0) & 0xff;
+
+ return 0;
+}
+
+static void keystone2_eth_mdio_enable(void)
+{
+ u_int32_t clkdiv;
+
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+
+ writel((clkdiv & 0xffff) |
+ MDIO_CONTROL_ENABLE |
+ MDIO_CONTROL_FAULT |
+ MDIO_CONTROL_FAULT_ENABLE,
+ &adap_mdio->control);
+
+ while (readl(&adap_mdio->control) & MDIO_CONTROL_IDLE)
+ ;
+}
+
+/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
+int keystone2_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
+{
+ int tmp;
+
+ while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO)
+ ;
+
+ writel(MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_READ |
+ ((reg_num & 0x1f) << 21) |
+ ((phy_addr & 0x1f) << 16),
+ &adap_mdio->useraccess0);
+
+ /* Wait for command to complete */
+ while ((tmp = readl(&adap_mdio->useraccess0)) & MDIO_USERACCESS0_GO)
+ ;
+
+ if (tmp & MDIO_USERACCESS0_ACK) {
+ *data = tmp & 0xffff;
+ return 0;
+ }
+
+ *data = -1;
+ return -1;
+}
+
+/*
+ * Write to a PHY register via MDIO inteface.
+ * Blocks until operation is complete.
+ */
+int keystone2_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
+{
+ while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO)
+ ;
+
+ writel(MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_WRITE |
+ ((reg_num & 0x1f) << 21) |
+ ((phy_addr & 0x1f) << 16) |
+ (data & 0xffff),
+ &adap_mdio->useraccess0);
+
+ /* Wait for command to complete */
+ while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO)
+ ;
+
+ return 0;
+}
+
+/* PHY functions for a generic PHY */
+static int gen_get_link_speed(int phy_addr)
+{
+ u_int16_t tmp;
+
+ if ((!keystone2_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp)) &&
+ (tmp & 0x04)) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static void __attribute__((unused))
+ keystone2_eth_gigabit_enable(struct eth_device *dev)
+{
+ u_int16_t data;
+ struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
+
+ if (sys_has_mdio) {
+ if (keystone2_eth_phy_read(eth_priv->phy_addr, 0, &data) ||
+ !(data & (1 << 6))) /* speed selection MSB */
+ return;
+ }
+
+ /*
+ * Check if link detected is giga-bit
+ * If Gigabit mode detected, enable gigbit in MAC
+ */
+ writel(readl(&(adap_emac[eth_priv->slave_port - 1].maccontrol)) |
+ EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE,
+ &(adap_emac[eth_priv->slave_port - 1].maccontrol))
+ ;
+}
+
+int keystone_sgmii_link_status(int port)
+{
+ u32 status = 0;
+
+ status = __raw_readl(SGMII_STATUS_REG(port));
+
+ return status & SGMII_REG_STATUS_LINK;
+}
+
+
+int keystone_get_link_status(struct eth_device *dev)
+{
+ struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
+ int sgmii_link;
+ int link_state = 0;
+#if CONFIG_GET_LINK_STATUS_ATTEMPTS > 1
+ int j;
+
+ for (j = 0; (j < CONFIG_GET_LINK_STATUS_ATTEMPTS) && (link_state == 0);
+ j++) {
+#endif
+ sgmii_link =
+ keystone_sgmii_link_status(eth_priv->slave_port - 1);
+
+ if (sgmii_link) {
+ link_state = 1;
+
+ if (eth_priv->sgmii_link_type == SGMII_LINK_MAC_PHY)
+ if (gen_get_link_speed(eth_priv->phy_addr))
+ link_state = 0;
+ }
+#if CONFIG_GET_LINK_STATUS_ATTEMPTS > 1
+ }
+#endif
+ return link_state;
+}
+
+int keystone_sgmii_config(int port, int interface)
+{
+ unsigned int i, status, mask;
+ unsigned int mr_adv_ability, control;
+
+ switch (interface) {
+ case SGMII_LINK_MAC_MAC_AUTONEG:
+ mr_adv_ability = (SGMII_REG_MR_ADV_ENABLE |
+ SGMII_REG_MR_ADV_LINK |
+ SGMII_REG_MR_ADV_FULL_DUPLEX |
+ SGMII_REG_MR_ADV_GIG_MODE);
+ control = (SGMII_REG_CONTROL_MASTER |
+ SGMII_REG_CONTROL_AUTONEG);
+
+ break;
+ case SGMII_LINK_MAC_PHY:
+ case SGMII_LINK_MAC_PHY_FORCED:
+ mr_adv_ability = SGMII_REG_MR_ADV_ENABLE;
+ control = SGMII_REG_CONTROL_AUTONEG;
+
+ break;
+ case SGMII_LINK_MAC_MAC_FORCED:
+ mr_adv_ability = (SGMII_REG_MR_ADV_ENABLE |
+ SGMII_REG_MR_ADV_LINK |
+ SGMII_REG_MR_ADV_FULL_DUPLEX |
+ SGMII_REG_MR_ADV_GIG_MODE);
+ control = SGMII_REG_CONTROL_MASTER;
+
+ break;
+ case SGMII_LINK_MAC_FIBER:
+ mr_adv_ability = 0x20;
+ control = SGMII_REG_CONTROL_AUTONEG;
+
+ break;
+ default:
+ mr_adv_ability = SGMII_REG_MR_ADV_ENABLE;
+ control = SGMII_REG_CONTROL_AUTONEG;
+ }
+
+ __raw_writel(0, SGMII_CTL_REG(port));
+
+ /*
+ * Wait for the SerDes pll to lock,
+ * but don't trap if lock is never read
+ */
+ for (i = 0; i < 1000; i++) {
+ udelay(2000);
+ status = __raw_readl(SGMII_STATUS_REG(port));
+ if ((status & SGMII_REG_STATUS_LOCK) != 0)
+ break;
+ }
+
+ __raw_writel(mr_adv_ability, SGMII_MRADV_REG(port));
+ __raw_writel(control, SGMII_CTL_REG(port));
+
+
+ mask = SGMII_REG_STATUS_LINK;
+
+ if (control & SGMII_REG_CONTROL_AUTONEG)
+ mask |= SGMII_REG_STATUS_AUTONEG;
+
+ for (i = 0; i < 1000; i++) {
+ status = __raw_readl(SGMII_STATUS_REG(port));
+ if ((status & mask) == mask)
+ break;
+ }
+
+ return 0;
+}
+
+int mac_sl_reset(u32 port)
+{
+ u32 i, v;
+
+ if (port >= DEVICE_N_GMACSL_PORTS)
+ return GMACSL_RET_INVALID_PORT;
+
+ /* Set the soft reset bit */
+ DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) +
+ CPGMACSL_REG_RESET, CPGMAC_REG_RESET_VAL_RESET);
+
+ /* Wait for the bit to clear */
+ for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) {
+ v = DEVICE_REG32_R(DEVICE_EMACSL_BASE(port) +
+ CPGMACSL_REG_RESET);
+ if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) !=
+ CPGMAC_REG_RESET_VAL_RESET)
+ return GMACSL_RET_OK;
+ }
+
+ /* Timeout on the reset */
+ return GMACSL_RET_WARN_RESET_INCOMPLETE;
+}
+
+int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg)
+{
+ u32 v, i;
+ int ret = GMACSL_RET_OK;
+
+ if (port >= DEVICE_N_GMACSL_PORTS)
+ return GMACSL_RET_INVALID_PORT;
+
+ if (cfg->max_rx_len > CPGMAC_REG_MAXLEN_LEN) {
+ cfg->max_rx_len = CPGMAC_REG_MAXLEN_LEN;
+ ret = GMACSL_RET_WARN_MAXLEN_TOO_BIG;
+ }
+
+ /* Must wait if the device is undergoing reset */
+ for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) {
+ v = DEVICE_REG32_R(DEVICE_EMACSL_BASE(port) +
+ CPGMACSL_REG_RESET);
+ if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) !=
+ CPGMAC_REG_RESET_VAL_RESET)
+ break;
+ }
+
+ if (i == DEVICE_EMACSL_RESET_POLL_COUNT)
+ return GMACSL_RET_CONFIG_FAIL_RESET_ACTIVE;
+
+ DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN,
+ cfg->max_rx_len);
+
+ DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL,
+ cfg->ctl);
+
+ return ret;
+}
+
+int ethss_config(u32 ctl, u32 max_pkt_size)
+{
+ u32 i;
+
+ /* Max length register */
+ DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_MAXLEN, max_pkt_size);
+
+ /* Control register */
+ DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_CTL, ctl);
+
+ /* All statistics enabled by default */
+ DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_STAT_PORT_EN,
+ CPSW_REG_VAL_STAT_ENABLE_ALL);
+
+ /* Reset and enable the ALE */
+ DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_ALE_CONTROL,
+ CPSW_REG_VAL_ALE_CTL_RESET_AND_ENABLE |
+ CPSW_REG_VAL_ALE_CTL_BYPASS);
+
+ /* All ports put into forward mode */
+ for (i = 0; i < DEVICE_CPSW_NUM_PORTS; i++)
+ DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_ALE_PORTCTL(i),
+ CPSW_REG_VAL_PORTCTL_FORWARD_MODE);
+
+ return 0;
+}
+
+int ethss_start(void)
+{
+ int i;
+ struct mac_sl_cfg cfg;
+
+ cfg.max_rx_len = MAX_SIZE_STREAM_BUFFER;
+ cfg.ctl = GMACSL_ENABLE | GMACSL_RX_ENABLE_EXT_CTL;
+
+ for (i = 0; i < DEVICE_N_GMACSL_PORTS; i++) {
+ mac_sl_reset(i);
+ mac_sl_config(i, &cfg);
+ }
+
+ return 0;
+}
+
+int ethss_stop(void)
+{
+ int i;
+
+ for (i = 0; i < DEVICE_N_GMACSL_PORTS; i++)
+ mac_sl_reset(i);
+
+ return 0;
+}
+
+int32_t cpmac_drv_send(u32 *buffer, int num_bytes, int slave_port_num)
+{
+ if (num_bytes < EMAC_MIN_ETHERNET_PKT_SIZE)
+ num_bytes = EMAC_MIN_ETHERNET_PKT_SIZE;
+
+ return netcp_send(buffer, num_bytes, (slave_port_num) << 16);
+}
+
+/* Eth device open */
+static int keystone2_eth_open(struct eth_device *dev, bd_t *bis)
+{
+ u_int32_t clkdiv;
+ int link;
+ struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
+
+ debug("+ emac_open\n");
+
+ net_rx_buffs.rx_flow = eth_priv->rx_flow;
+
+ sys_has_mdio =
+ (eth_priv->sgmii_link_type == SGMII_LINK_MAC_PHY) ? 1 : 0;
+
+ psc_enable_module(KS2_LPSC_PA);
+ psc_enable_module(KS2_LPSC_CPGMAC);
+
+ sgmii_serdes_setup_156p25mhz();
+
+ if (sys_has_mdio)
+ keystone2_eth_mdio_enable();
+
+ keystone_sgmii_config(eth_priv->slave_port - 1,
+ eth_priv->sgmii_link_type);
+
+ udelay(10000);
+
+ /* On chip switch configuration */
+ ethss_config(target_get_switch_ctl(), SWITCH_MAX_PKT_SIZE);
+
+ /* TODO: add error handling code */
+ if (qm_init()) {
+ printf("ERROR: qm_init()\n");
+ return -1;
+ }
+ if (netcp_init(&net_rx_buffs)) {
+ qm_close();
+ printf("ERROR: netcp_init()\n");
+ return -1;
+ }
+
+ /*
+ * Streaming switch configuration. If not present this
+ * statement is defined to void in target.h.
+ * If present this is usually defined to a series of register writes
+ */
+ hw_config_streaming_switch();
+
+ if (sys_has_mdio) {
+ /* Init MDIO & get link state */
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+ writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE |
+ MDIO_CONTROL_FAULT, &adap_mdio->control)
+ ;
+
+ /* We need to wait for MDIO to start */
+ udelay(1000);
+
+ link = keystone_get_link_status(dev);
+ if (link == 0) {
+ netcp_close();
+ qm_close();
+ return -1;
+ }
+ }
+
+ emac_gigabit_enable(dev);
+
+ ethss_start();
+
+ debug("- emac_open\n");
+
+ emac_open = 1;
+
+ return 0;
+}
+
+/* Eth device close */
+void keystone2_eth_close(struct eth_device *dev)
+{
+ debug("+ emac_close\n");
+
+ if (!emac_open)
+ return;
+
+ ethss_stop();
+
+ netcp_close();
+ qm_close();
+
+ emac_open = 0;
+
+ debug("- emac_close\n");
+}
+
+static int tx_send_loop;
+
+/*
+ * This function sends a single packet on the network and returns
+ * positive number (number of bytes transmitted) or negative for error
+ */
+static int keystone2_eth_send_packet(struct eth_device *dev,
+ void *packet, int length)
+{
+ int ret_status = -1;
+ struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
+
+ tx_send_loop = 0;
+
+ if (keystone_get_link_status(dev) == 0)
+ return -1;
+
+ emac_gigabit_enable(dev);
+
+ if (cpmac_drv_send((u32 *)packet, length, eth_priv->slave_port) != 0)
+ return ret_status;
+
+ if (keystone_get_link_status(dev) == 0)
+ return -1;
+
+ emac_gigabit_enable(dev);
+
+ return length;
+}
+
+/*
+ * This function handles receipt of a packet from the network
+ */
+static int keystone2_eth_rcv_packet(struct eth_device *dev)
+{
+ void *hd;
+ int pkt_size;
+ u32 *pkt;
+
+ hd = netcp_recv(&pkt, &pkt_size);
+ if (hd == NULL)
+ return 0;
+
+ NetReceive((uchar *)pkt, pkt_size);
+
+ netcp_release_rxhd(hd);
+
+ return pkt_size;
+}
+
+/*
+ * This function initializes the EMAC hardware.
+ */
+int keystone2_emac_initialize(struct eth_priv_t *eth_priv)
+{
+ struct eth_device *dev;
+
+ dev = malloc(sizeof(struct eth_device));
+ if (dev == NULL)
+ return -1;
+
+ memset(dev, 0, sizeof(struct eth_device));
+
+ strcpy(dev->name, eth_priv->int_name);
+ dev->priv = eth_priv;
+
+ keystone2_eth_read_mac_addr(dev);
+
+ dev->iobase = 0;
+ dev->init = keystone2_eth_open;
+ dev->halt = keystone2_eth_close;
+ dev->send = keystone2_eth_send_packet;
+ dev->recv = keystone2_eth_rcv_packet;
+
+ eth_register(dev);
+
+ return 0;
+}
+
+void sgmii_serdes_setup_156p25mhz(void)
+{
+ unsigned int cnt;
+
+ /*
+ * configure Serializer/Deserializer (SerDes) hardware. SerDes IP
+ * hardware vendor published only register addresses and their values
+ * to be used for configuring SerDes. So had to use hardcoded values
+ * below.
+ */
+ clrsetbits_le32(0x0232a000, 0xffff0000, 0x00800000);
+ clrsetbits_le32(0x0232a014, 0x0000ffff, 0x00008282);
+ clrsetbits_le32(0x0232a060, 0x00ffffff, 0x00142438);
+ clrsetbits_le32(0x0232a064, 0x00ffff00, 0x00c3c700);
+ clrsetbits_le32(0x0232a078, 0x0000ff00, 0x0000c000);
+
+ clrsetbits_le32(0x0232a204, 0xff0000ff, 0x38000080);
+ clrsetbits_le32(0x0232a208, 0x000000ff, 0x00000000);
+ clrsetbits_le32(0x0232a20c, 0xff000000, 0x02000000);
+ clrsetbits_le32(0x0232a210, 0xff000000, 0x1b000000);
+ clrsetbits_le32(0x0232a214, 0x0000ffff, 0x00006fb8);
+ clrsetbits_le32(0x0232a218, 0xffff00ff, 0x758000e4);
+ clrsetbits_le32(0x0232a2ac, 0x0000ff00, 0x00004400);
+ clrsetbits_le32(0x0232a22c, 0x00ffff00, 0x00200800);
+ clrsetbits_le32(0x0232a280, 0x00ff00ff, 0x00820082);
+ clrsetbits_le32(0x0232a284, 0xffffffff, 0x1d0f0385);
+
+ clrsetbits_le32(0x0232a404, 0xff0000ff, 0x38000080);
+ clrsetbits_le32(0x0232a408, 0x000000ff, 0x00000000);
+ clrsetbits_le32(0x0232a40c, 0xff000000, 0x02000000);
+ clrsetbits_le32(0x0232a410, 0xff000000, 0x1b000000);
+ clrsetbits_le32(0x0232a414, 0x0000ffff, 0x00006fb8);
+ clrsetbits_le32(0x0232a418, 0xffff00ff, 0x758000e4);
+ clrsetbits_le32(0x0232a4ac, 0x0000ff00, 0x00004400);
+ clrsetbits_le32(0x0232a42c, 0x00ffff00, 0x00200800);
+ clrsetbits_le32(0x0232a480, 0x00ff00ff, 0x00820082);
+ clrsetbits_le32(0x0232a484, 0xffffffff, 0x1d0f0385);
+
+ clrsetbits_le32(0x0232a604, 0xff0000ff, 0x38000080);
+ clrsetbits_le32(0x0232a608, 0x000000ff, 0x00000000);
+ clrsetbits_le32(0x0232a60c, 0xff000000, 0x02000000);
+ clrsetbits_le32(0x0232a610, 0xff000000, 0x1b000000);
+ clrsetbits_le32(0x0232a614, 0x0000ffff, 0x00006fb8);
+ clrsetbits_le32(0x0232a618, 0xffff00ff, 0x758000e4);
+ clrsetbits_le32(0x0232a6ac, 0x0000ff00, 0x00004400);
+ clrsetbits_le32(0x0232a62c, 0x00ffff00, 0x00200800);
+ clrsetbits_le32(0x0232a680, 0x00ff00ff, 0x00820082);
+ clrsetbits_le32(0x0232a684, 0xffffffff, 0x1d0f0385);
+
+ clrsetbits_le32(0x0232a804, 0xff0000ff, 0x38000080);
+ clrsetbits_le32(0x0232a808, 0x000000ff, 0x00000000);
+ clrsetbits_le32(0x0232a80c, 0xff000000, 0x02000000);
+ clrsetbits_le32(0x0232a810, 0xff000000, 0x1b000000);
+ clrsetbits_le32(0x0232a814, 0x0000ffff, 0x00006fb8);
+ clrsetbits_le32(0x0232a818, 0xffff00ff, 0x758000e4);
+ clrsetbits_le32(0x0232a8ac, 0x0000ff00, 0x00004400);
+ clrsetbits_le32(0x0232a82c, 0x00ffff00, 0x00200800);
+ clrsetbits_le32(0x0232a880, 0x00ff00ff, 0x00820082);
+ clrsetbits_le32(0x0232a884, 0xffffffff, 0x1d0f0385);
+
+ clrsetbits_le32(0x0232aa00, 0x0000ff00, 0x00000800);
+ clrsetbits_le32(0x0232aa08, 0xffff0000, 0x38a20000);
+ clrsetbits_le32(0x0232aa30, 0x00ffff00, 0x008a8a00);
+ clrsetbits_le32(0x0232aa84, 0x0000ff00, 0x00000600);
+ clrsetbits_le32(0x0232aa94, 0xff000000, 0x10000000);
+ clrsetbits_le32(0x0232aaa0, 0xff000000, 0x81000000);
+ clrsetbits_le32(0x0232aabc, 0xff000000, 0xff000000);
+ clrsetbits_le32(0x0232aac0, 0x000000ff, 0x0000008b);
+ clrsetbits_le32(0x0232ab08, 0xffff0000, 0x583f0000);
+ clrsetbits_le32(0x0232ab0c, 0x000000ff, 0x0000004e);
+ clrsetbits_le32(0x0232a000, 0x000000ff, 0x00000003);
+ clrsetbits_le32(0x0232aa00, 0x000000ff, 0x0000005f);
+
+ clrsetbits_le32(0x0232aa48, 0x00ffff00, 0x00fd8c00);
+ clrsetbits_le32(0x0232aa54, 0x00ffffff, 0x002fec72);
+ clrsetbits_le32(0x0232aa58, 0xffffff00, 0x00f92100);
+ clrsetbits_le32(0x0232aa5c, 0xffffffff, 0x00040060);
+ clrsetbits_le32(0x0232aa60, 0xffffffff, 0x00008000);
+ clrsetbits_le32(0x0232aa64, 0xffffffff, 0x0c581220);
+ clrsetbits_le32(0x0232aa68, 0xffffffff, 0xe13b0602);
+ clrsetbits_le32(0x0232aa6c, 0xffffffff, 0xb8074cc1);
+ clrsetbits_le32(0x0232aa70, 0xffffffff, 0x3f02e989);
+ clrsetbits_le32(0x0232aa74, 0x000000ff, 0x00000001);
+ clrsetbits_le32(0x0232ab20, 0x00ff0000, 0x00370000);
+ clrsetbits_le32(0x0232ab1c, 0xff000000, 0x37000000);
+ clrsetbits_le32(0x0232ab20, 0x000000ff, 0x0000005d);
+
+ /*Bring SerDes out of Reset if SerDes is Shutdown & is in Reset Mode*/
+ clrbits_le32(0x0232a010, 1 << 28);
+
+ /* Enable TX and RX via the LANExCTL_STS 0x0000 + x*4 */
+ clrbits_le32(0x0232a228, 1 << 29);
+ writel(0xF800F8C0, 0x0232bfe0);
+ clrbits_le32(0x0232a428, 1 << 29);
+ writel(0xF800F8C0, 0x0232bfe4);
+ clrbits_le32(0x0232a628, 1 << 29);
+ writel(0xF800F8C0, 0x0232bfe8);
+ clrbits_le32(0x0232a828, 1 << 29);
+ writel(0xF800F8C0, 0x0232bfec);
+
+ /*Enable pll via the pll_ctrl 0x0014*/
+ writel(0xe0000000, 0x0232bff4)
+ ;
+
+ /*Waiting for SGMII Serdes PLL lock.*/
+ for (cnt = 10000; cnt > 0 && ((readl(0x02090114) & 0x10) == 0); cnt--)
+ ;
+
+ for (cnt = 10000; cnt > 0 && ((readl(0x02090214) & 0x10) == 0); cnt--)
+ ;
+
+ for (cnt = 10000; cnt > 0 && ((readl(0x02090414) & 0x10) == 0); cnt--)
+ ;
+
+ for (cnt = 10000; cnt > 0 && ((readl(0x02090514) & 0x10) == 0); cnt--)
+ ;
+
+ udelay(45000);
+}
+
+void sgmii_serdes_shutdown(void)
+{
+ /*
+ * shutdown SerDes hardware. SerDes hardware vendor published only
+ * register addresses and their values. So had to use hardcoded
+ * values below.
+ */
+ clrbits_le32(0x0232bfe0, 3 << 29 | 3 << 13);
+ setbits_le32(0x02320228, 1 << 29);
+ clrbits_le32(0x0232bfe4, 3 << 29 | 3 << 13);
+ setbits_le32(0x02320428, 1 << 29);
+ clrbits_le32(0x0232bfe8, 3 << 29 | 3 << 13);
+ setbits_le32(0x02320628, 1 << 29);
+ clrbits_le32(0x0232bfec, 3 << 29 | 3 << 13);
+ setbits_le32(0x02320828, 1 << 29);
+
+ clrbits_le32(0x02320034, 3 << 29);
+ setbits_le32(0x02320010, 1 << 28);
+}
diff --git a/qemu/roms/u-boot/drivers/net/ks8695eth.c b/qemu/roms/u-boot/drivers/net/ks8695eth.c
new file mode 100644
index 000000000..b4822e950
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ks8695eth.c
@@ -0,0 +1,229 @@
+/*
+ * ks8695eth.c -- KS8695 ethernet driver
+ *
+ * (C) Copyright 2004-2005, Greg Ungerer <greg.ungerer@opengear.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/****************************************************************************/
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <asm/arch/platform.h>
+
+/****************************************************************************/
+
+/*
+ * Hardware register access to the KS8695 LAN ethernet port
+ * (well, it is the 4 port switch really).
+ */
+#define ks8695_read(a) *((volatile unsigned long *) (KS8695_IO_BASE + (a)))
+#define ks8695_write(a,v) *((volatile unsigned long *) (KS8695_IO_BASE + (a))) = (v)
+
+/****************************************************************************/
+
+/*
+ * Define the descriptor in-memory data structures.
+ */
+struct ks8695_txdesc {
+ uint32_t owner;
+ uint32_t ctrl;
+ uint32_t addr;
+ uint32_t next;
+};
+
+struct ks8695_rxdesc {
+ uint32_t status;
+ uint32_t ctrl;
+ uint32_t addr;
+ uint32_t next;
+};
+
+/****************************************************************************/
+
+/*
+ * Allocate local data structures to use for receiving and sending
+ * packets. Just to keep it all nice and simple.
+ */
+
+#define TXDESCS 4
+#define RXDESCS 4
+#define BUFSIZE 2048
+
+volatile struct ks8695_txdesc ks8695_tx[TXDESCS] __attribute__((aligned(256)));
+volatile struct ks8695_rxdesc ks8695_rx[RXDESCS] __attribute__((aligned(256)));
+volatile uint8_t ks8695_bufs[BUFSIZE*(TXDESCS+RXDESCS)] __attribute__((aligned(2048)));;
+
+/****************************************************************************/
+
+/*
+ * Ideally we want to use the MAC address stored in flash.
+ * But we do some sanity checks in case they are not present
+ * first.
+ */
+unsigned char eth_mac[] = {
+ 0x00, 0x13, 0xc6, 0x00, 0x00, 0x00
+};
+
+void ks8695_getmac(void)
+{
+ unsigned char *fp;
+ int i;
+
+ /* Check if flash MAC is valid */
+ fp = (unsigned char *) 0x0201c000;
+ for (i = 0; (i < 6); i++) {
+ if ((fp[i] != 0) && (fp[i] != 0xff))
+ break;
+ }
+
+ /* If we found a valid looking MAC address then use it */
+ if (i < 6)
+ memcpy(&eth_mac[0], fp, 6);
+}
+
+/****************************************************************************/
+
+static int ks8695_eth_init(struct eth_device *dev, bd_t *bd)
+{
+ int i;
+
+ debug ("%s(%d): eth_reset()\n", __FILE__, __LINE__);
+
+ /* Reset the ethernet engines first */
+ ks8695_write(KS8695_LAN_DMA_TX, 0x80000000);
+ ks8695_write(KS8695_LAN_DMA_RX, 0x80000000);
+
+ ks8695_getmac();
+
+ /* Set MAC address */
+ ks8695_write(KS8695_LAN_MAC_LOW, (eth_mac[5] | (eth_mac[4] << 8) |
+ (eth_mac[3] << 16) | (eth_mac[2] << 24)));
+ ks8695_write(KS8695_LAN_MAC_HIGH, (eth_mac[1] | (eth_mac[0] << 8)));
+
+ /* Turn the 4 port switch on */
+ i = ks8695_read(KS8695_SWITCH_CTRL0);
+ ks8695_write(KS8695_SWITCH_CTRL0, (i | 0x1));
+ /* ks8695_write(KS8695_WAN_CONTROL, 0x3f000066); */
+
+ /* Initialize descriptor rings */
+ for (i = 0; (i < TXDESCS); i++) {
+ ks8695_tx[i].owner = 0;
+ ks8695_tx[i].ctrl = 0;
+ ks8695_tx[i].addr = (uint32_t) &ks8695_bufs[i*BUFSIZE];
+ ks8695_tx[i].next = (uint32_t) &ks8695_tx[i+1];
+ }
+ ks8695_tx[TXDESCS-1].ctrl = 0x02000000;
+ ks8695_tx[TXDESCS-1].next = (uint32_t) &ks8695_tx[0];
+
+ for (i = 0; (i < RXDESCS); i++) {
+ ks8695_rx[i].status = 0x80000000;
+ ks8695_rx[i].ctrl = BUFSIZE - 4;
+ ks8695_rx[i].addr = (uint32_t) &ks8695_bufs[(i+TXDESCS)*BUFSIZE];
+ ks8695_rx[i].next = (uint32_t) &ks8695_rx[i+1];
+ }
+ ks8695_rx[RXDESCS-1].ctrl |= 0x00080000;
+ ks8695_rx[RXDESCS-1].next = (uint32_t) &ks8695_rx[0];
+
+ /* The KS8695 is pretty slow reseting the ethernets... */
+ udelay(2000000);
+
+ /* Enable the ethernet engine */
+ ks8695_write(KS8695_LAN_TX_LIST, (uint32_t) &ks8695_tx[0]);
+ ks8695_write(KS8695_LAN_RX_LIST, (uint32_t) &ks8695_rx[0]);
+ ks8695_write(KS8695_LAN_DMA_TX, 0x3);
+ ks8695_write(KS8695_LAN_DMA_RX, 0x71);
+ ks8695_write(KS8695_LAN_DMA_RX_START, 0x1);
+
+ printf("KS8695 ETHERNET: %pM\n", eth_mac);
+ return 0;
+}
+
+/****************************************************************************/
+
+static void ks8695_eth_halt(struct eth_device *dev)
+{
+ debug ("%s(%d): eth_halt()\n", __FILE__, __LINE__);
+
+ /* Reset the ethernet engines */
+ ks8695_write(KS8695_LAN_DMA_TX, 0x80000000);
+ ks8695_write(KS8695_LAN_DMA_RX, 0x80000000);
+}
+
+/****************************************************************************/
+
+static int ks8695_eth_recv(struct eth_device *dev)
+{
+ volatile struct ks8695_rxdesc *dp;
+ int i, len = 0;
+
+ debug ("%s(%d): eth_rx()\n", __FILE__, __LINE__);
+
+ for (i = 0; (i < RXDESCS); i++) {
+ dp= &ks8695_rx[i];
+ if ((dp->status & 0x80000000) == 0) {
+ len = (dp->status & 0x7ff) - 4;
+ NetReceive((void *) dp->addr, len);
+ dp->status = 0x80000000;
+ ks8695_write(KS8695_LAN_DMA_RX_START, 0x1);
+ break;
+ }
+ }
+
+ return len;
+}
+
+/****************************************************************************/
+
+static int ks8695_eth_send(struct eth_device *dev, void *packet, int len)
+{
+ volatile struct ks8695_txdesc *dp;
+ static int next = 0;
+
+ debug ("%s(%d): eth_send(packet=%p,len=%d)\n", __FILE__, __LINE__,
+ packet, len);
+
+ dp = &ks8695_tx[next];
+ memcpy((void *) dp->addr, (void *) packet, len);
+
+ if (len < 64) {
+ memset((void *) (dp->addr + len), 0, 64-len);
+ len = 64;
+ }
+
+ dp->ctrl = len | 0xe0000000;
+ dp->owner = 0x80000000;
+
+ ks8695_write(KS8695_LAN_DMA_TX, 0x3);
+ ks8695_write(KS8695_LAN_DMA_TX_START, 0x1);
+
+ if (++next >= TXDESCS)
+ next = 0;
+
+ return 0;
+}
+
+/****************************************************************************/
+
+int ks8695_eth_initialize(void)
+{
+ struct eth_device *dev;
+
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL)
+ return -1;
+ memset(dev, 0, sizeof(*dev));
+
+ dev->iobase = KS8695_IO_BASE + KS8695_LAN_DMA_TX;
+ dev->init = ks8695_eth_init;
+ dev->halt = ks8695_eth_halt;
+ dev->send = ks8695_eth_send;
+ dev->recv = ks8695_eth_recv;
+ strcpy(dev->name, "ks8695eth");
+
+ eth_register(dev);
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ks8851_mll.c b/qemu/roms/u-boot/drivers/net/ks8851_mll.c
new file mode 100644
index 000000000..05e5b14d2
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ks8851_mll.c
@@ -0,0 +1,633 @@
+/*
+ * Micrel KS8851_MLL 16bit Network driver
+ * Copyright (c) 2011 Roberto Cerati <roberto.cerati@bticino.it>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+
+#include "ks8851_mll.h"
+
+#define DRIVERNAME "ks8851_mll"
+
+#define MAX_RECV_FRAMES 32
+#define MAX_BUF_SIZE 2048
+#define TX_BUF_SIZE 2000
+#define RX_BUF_SIZE 2000
+
+static const struct chip_id chip_ids[] = {
+ {CIDER_ID, "KSZ8851"},
+ {0, NULL},
+};
+
+/*
+ * union ks_tx_hdr - tx header data
+ * @txb: The header as bytes
+ * @txw: The header as 16bit, little-endian words
+ *
+ * A dual representation of the tx header data to allow
+ * access to individual bytes, and to allow 16bit accesses
+ * with 16bit alignment.
+ */
+union ks_tx_hdr {
+ u8 txb[4];
+ __le16 txw[2];
+};
+
+/*
+ * struct ks_net - KS8851 driver private data
+ * @net_device : The network device we're bound to
+ * @txh : temporaly buffer to save status/length.
+ * @frame_head_info : frame header information for multi-pkt rx.
+ * @statelock : Lock on this structure for tx list.
+ * @msg_enable : The message flags controlling driver output (see ethtool).
+ * @frame_cnt : number of frames received.
+ * @bus_width : i/o bus width.
+ * @irq : irq number assigned to this device.
+ * @rc_rxqcr : Cached copy of KS_RXQCR.
+ * @rc_txcr : Cached copy of KS_TXCR.
+ * @rc_ier : Cached copy of KS_IER.
+ * @sharedbus : Multipex(addr and data bus) mode indicator.
+ * @cmd_reg_cache : command register cached.
+ * @cmd_reg_cache_int : command register cached. Used in the irq handler.
+ * @promiscuous : promiscuous mode indicator.
+ * @all_mcast : mutlicast indicator.
+ * @mcast_lst_size : size of multicast list.
+ * @mcast_lst : multicast list.
+ * @mcast_bits : multicast enabed.
+ * @mac_addr : MAC address assigned to this device.
+ * @fid : frame id.
+ * @extra_byte : number of extra byte prepended rx pkt.
+ * @enabled : indicator this device works.
+ */
+
+/* Receive multiplex framer header info */
+struct type_frame_head {
+ u16 sts; /* Frame status */
+ u16 len; /* Byte count */
+} fr_h_i[MAX_RECV_FRAMES];
+
+struct ks_net {
+ struct net_device *netdev;
+ union ks_tx_hdr txh;
+ struct type_frame_head *frame_head_info;
+ u32 msg_enable;
+ u32 frame_cnt;
+ int bus_width;
+ int irq;
+ u16 rc_rxqcr;
+ u16 rc_txcr;
+ u16 rc_ier;
+ u16 sharedbus;
+ u16 cmd_reg_cache;
+ u16 cmd_reg_cache_int;
+ u16 promiscuous;
+ u16 all_mcast;
+ u16 mcast_lst_size;
+ u8 mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN];
+ u8 mcast_bits[HW_MCAST_SIZE];
+ u8 mac_addr[6];
+ u8 fid;
+ u8 extra_byte;
+ u8 enabled;
+} ks_str, *ks;
+
+#define BE3 0x8000 /* Byte Enable 3 */
+#define BE2 0x4000 /* Byte Enable 2 */
+#define BE1 0x2000 /* Byte Enable 1 */
+#define BE0 0x1000 /* Byte Enable 0 */
+
+static u8 ks_rdreg8(struct eth_device *dev, u16 offset)
+{
+ u8 shift_bit = offset & 0x03;
+ u8 shift_data = (offset & 1) << 3;
+
+ writew(offset | (BE0 << shift_bit), dev->iobase + 2);
+
+ return (u8)(readw(dev->iobase) >> shift_data);
+}
+
+static u16 ks_rdreg16(struct eth_device *dev, u16 offset)
+{
+ writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2);
+
+ return readw(dev->iobase);
+}
+
+static void ks_wrreg8(struct eth_device *dev, u16 offset, u8 val)
+{
+ u8 shift_bit = (offset & 0x03);
+ u16 value_write = (u16)(val << ((offset & 1) << 3));
+
+ writew(offset | (BE0 << shift_bit), dev->iobase + 2);
+ writew(value_write, dev->iobase);
+}
+
+static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val)
+{
+ writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2);
+ writew(val, dev->iobase);
+}
+
+/*
+ * ks_inblk - read a block of data from QMU. This is called after sudo DMA mode
+ * enabled.
+ * @ks: The chip state
+ * @wptr: buffer address to save data
+ * @len: length in byte to read
+ */
+static inline void ks_inblk(struct eth_device *dev, u16 *wptr, u32 len)
+{
+ len >>= 1;
+
+ while (len--)
+ *wptr++ = readw(dev->iobase);
+}
+
+/*
+ * ks_outblk - write data to QMU. This is called after sudo DMA mode enabled.
+ * @ks: The chip information
+ * @wptr: buffer address
+ * @len: length in byte to write
+ */
+static inline void ks_outblk(struct eth_device *dev, u16 *wptr, u32 len)
+{
+ len >>= 1;
+
+ while (len--)
+ writew(*wptr++, dev->iobase);
+}
+
+static void ks_enable_int(struct eth_device *dev)
+{
+ ks_wrreg16(dev, KS_IER, ks->rc_ier);
+}
+
+static void ks_set_powermode(struct eth_device *dev, unsigned pwrmode)
+{
+ unsigned pmecr;
+
+ ks_rdreg16(dev, KS_GRR);
+ pmecr = ks_rdreg16(dev, KS_PMECR);
+ pmecr &= ~PMECR_PM_MASK;
+ pmecr |= pwrmode;
+
+ ks_wrreg16(dev, KS_PMECR, pmecr);
+}
+
+/*
+ * ks_read_config - read chip configuration of bus width.
+ * @ks: The chip information
+ */
+static void ks_read_config(struct eth_device *dev)
+{
+ u16 reg_data = 0;
+
+ /* Regardless of bus width, 8 bit read should always work. */
+ reg_data = ks_rdreg8(dev, KS_CCR) & 0x00FF;
+ reg_data |= ks_rdreg8(dev, KS_CCR + 1) << 8;
+
+ /* addr/data bus are multiplexed */
+ ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED;
+
+ /*
+ * There are garbage data when reading data from QMU,
+ * depending on bus-width.
+ */
+ if (reg_data & CCR_8BIT) {
+ ks->bus_width = ENUM_BUS_8BIT;
+ ks->extra_byte = 1;
+ } else if (reg_data & CCR_16BIT) {
+ ks->bus_width = ENUM_BUS_16BIT;
+ ks->extra_byte = 2;
+ } else {
+ ks->bus_width = ENUM_BUS_32BIT;
+ ks->extra_byte = 4;
+ }
+}
+
+/*
+ * ks_soft_reset - issue one of the soft reset to the device
+ * @ks: The device state.
+ * @op: The bit(s) to set in the GRR
+ *
+ * Issue the relevant soft-reset command to the device's GRR register
+ * specified by @op.
+ *
+ * Note, the delays are in there as a caution to ensure that the reset
+ * has time to take effect and then complete. Since the datasheet does
+ * not currently specify the exact sequence, we have chosen something
+ * that seems to work with our device.
+ */
+static void ks_soft_reset(struct eth_device *dev, unsigned op)
+{
+ /* Disable interrupt first */
+ ks_wrreg16(dev, KS_IER, 0x0000);
+ ks_wrreg16(dev, KS_GRR, op);
+ mdelay(10); /* wait a short time to effect reset */
+ ks_wrreg16(dev, KS_GRR, 0);
+ mdelay(1); /* wait for condition to clear */
+}
+
+void ks_enable_qmu(struct eth_device *dev)
+{
+ u16 w;
+
+ w = ks_rdreg16(dev, KS_TXCR);
+
+ /* Enables QMU Transmit (TXCR). */
+ ks_wrreg16(dev, KS_TXCR, w | TXCR_TXE);
+
+ /* Enable RX Frame Count Threshold and Auto-Dequeue RXQ Frame */
+ w = ks_rdreg16(dev, KS_RXQCR);
+ ks_wrreg16(dev, KS_RXQCR, w | RXQCR_RXFCTE);
+
+ /* Enables QMU Receive (RXCR1). */
+ w = ks_rdreg16(dev, KS_RXCR1);
+ ks_wrreg16(dev, KS_RXCR1, w | RXCR1_RXE);
+}
+
+static void ks_disable_qmu(struct eth_device *dev)
+{
+ u16 w;
+
+ w = ks_rdreg16(dev, KS_TXCR);
+
+ /* Disables QMU Transmit (TXCR). */
+ w &= ~TXCR_TXE;
+ ks_wrreg16(dev, KS_TXCR, w);
+
+ /* Disables QMU Receive (RXCR1). */
+ w = ks_rdreg16(dev, KS_RXCR1);
+ w &= ~RXCR1_RXE;
+ ks_wrreg16(dev, KS_RXCR1, w);
+}
+
+static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len)
+{
+ u32 r = ks->extra_byte & 0x1;
+ u32 w = ks->extra_byte - r;
+
+ /* 1. set sudo DMA mode */
+ ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI);
+ ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
+
+ /*
+ * 2. read prepend data
+ *
+ * read 4 + extra bytes and discard them.
+ * extra bytes for dummy, 2 for status, 2 for len
+ */
+
+ if (r)
+ ks_rdreg8(dev, 0);
+
+ ks_inblk(dev, buf, w + 2 + 2);
+
+ /* 3. read pkt data */
+ ks_inblk(dev, buf, ALIGN(len, 4));
+
+ /* 4. reset sudo DMA Mode */
+ ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff);
+}
+
+static void ks_rcv(struct eth_device *dev, uchar **pv_data)
+{
+ struct type_frame_head *frame_hdr = ks->frame_head_info;
+ int i;
+
+ ks->frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8;
+
+ /* read all header information */
+ for (i = 0; i < ks->frame_cnt; i++) {
+ /* Checking Received packet status */
+ frame_hdr->sts = ks_rdreg16(dev, KS_RXFHSR);
+ /* Get packet len from hardware */
+ frame_hdr->len = ks_rdreg16(dev, KS_RXFHBCR);
+ frame_hdr++;
+ }
+
+ frame_hdr = ks->frame_head_info;
+ while (ks->frame_cnt--) {
+ if ((frame_hdr->sts & RXFSHR_RXFV) &&
+ (frame_hdr->len < RX_BUF_SIZE) &&
+ frame_hdr->len) {
+ /* read data block including CRC 4 bytes */
+ ks_read_qmu(dev, (u16 *)(*pv_data), frame_hdr->len);
+
+ /* NetRxPackets buffer size is ok (*pv_data pointer) */
+ NetReceive(*pv_data, frame_hdr->len);
+ pv_data++;
+ } else {
+ ks_wrreg16(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
+ printf(DRIVERNAME ": bad packet\n");
+ }
+ frame_hdr++;
+ }
+}
+
+/*
+ * ks_read_selftest - read the selftest memory info.
+ * @ks: The device state
+ *
+ * Read and check the TX/RX memory selftest information.
+ */
+static int ks_read_selftest(struct eth_device *dev)
+{
+ u16 both_done = MBIR_TXMBF | MBIR_RXMBF;
+ u16 mbir;
+ int ret = 0;
+
+ mbir = ks_rdreg16(dev, KS_MBIR);
+
+ if ((mbir & both_done) != both_done) {
+ printf(DRIVERNAME ": Memory selftest not finished\n");
+ return 0;
+ }
+
+ if (mbir & MBIR_TXMBFA) {
+ printf(DRIVERNAME ": TX memory selftest fails\n");
+ ret |= 1;
+ }
+
+ if (mbir & MBIR_RXMBFA) {
+ printf(DRIVERNAME ": RX memory selftest fails\n");
+ ret |= 2;
+ }
+
+ debug(DRIVERNAME ": the selftest passes\n");
+
+ return ret;
+}
+
+static void ks_setup(struct eth_device *dev)
+{
+ u16 w;
+
+ /* Setup Transmit Frame Data Pointer Auto-Increment (TXFDPR) */
+ ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI);
+
+ /* Setup Receive Frame Data Pointer Auto-Increment */
+ ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI);
+
+ /* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */
+ ks_wrreg16(dev, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK);
+
+ /* Setup RxQ Command Control (RXQCR) */
+ ks->rc_rxqcr = RXQCR_CMD_CNTL;
+ ks_wrreg16(dev, KS_RXQCR, ks->rc_rxqcr);
+
+ /*
+ * set the force mode to half duplex, default is full duplex
+ * because if the auto-negotiation fails, most switch uses
+ * half-duplex.
+ */
+ w = ks_rdreg16(dev, KS_P1MBCR);
+ w &= ~P1MBCR_FORCE_FDX;
+ ks_wrreg16(dev, KS_P1MBCR, w);
+
+ w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP;
+ ks_wrreg16(dev, KS_TXCR, w);
+
+ w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC;
+
+ /* Normal mode */
+ w |= RXCR1_RXPAFMA;
+
+ ks_wrreg16(dev, KS_RXCR1, w);
+}
+
+static void ks_setup_int(struct eth_device *dev)
+{
+ ks->rc_ier = 0x00;
+
+ /* Clear the interrupts status of the hardware. */
+ ks_wrreg16(dev, KS_ISR, 0xffff);
+
+ /* Enables the interrupts of the hardware. */
+ ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI);
+}
+
+static int ks8851_mll_detect_chip(struct eth_device *dev)
+{
+ unsigned short val, i;
+
+ ks_read_config(dev);
+
+ val = ks_rdreg16(dev, KS_CIDER);
+
+ if (val == 0xffff) {
+ /* Special case -- no chip present */
+ printf(DRIVERNAME ": is chip mounted ?\n");
+ return -1;
+ } else if ((val & 0xfff0) != CIDER_ID) {
+ printf(DRIVERNAME ": Invalid chip id 0x%04x\n", val);
+ return -1;
+ }
+
+ debug("Read back KS8851 id 0x%x\n", val);
+
+ /* only one entry in the table */
+ val &= 0xfff0;
+ for (i = 0; chip_ids[i].id != 0; i++) {
+ if (chip_ids[i].id == val)
+ break;
+ }
+ if (!chip_ids[i].id) {
+ printf(DRIVERNAME ": Unknown chip ID %04x\n", val);
+ return -1;
+ }
+
+ dev->priv = (void *)&chip_ids[i];
+
+ return 0;
+}
+
+static void ks8851_mll_reset(struct eth_device *dev)
+{
+ /* wake up powermode to normal mode */
+ ks_set_powermode(dev, PMECR_PM_NORMAL);
+ mdelay(1); /* wait for normal mode to take effect */
+
+ /* Disable interrupt and reset */
+ ks_soft_reset(dev, GRR_GSR);
+
+ /* turn off the IRQs and ack any outstanding */
+ ks_wrreg16(dev, KS_IER, 0x0000);
+ ks_wrreg16(dev, KS_ISR, 0xffff);
+
+ /* shutdown RX/TX QMU */
+ ks_disable_qmu(dev);
+}
+
+static void ks8851_mll_phy_configure(struct eth_device *dev)
+{
+ u16 data;
+
+ ks_setup(dev);
+ ks_setup_int(dev);
+
+ /* Probing the phy */
+ data = ks_rdreg16(dev, KS_OBCR);
+ ks_wrreg16(dev, KS_OBCR, data | OBCR_ODS_16MA);
+
+ debug(DRIVERNAME ": phy initialized\n");
+}
+
+static void ks8851_mll_enable(struct eth_device *dev)
+{
+ ks_wrreg16(dev, KS_ISR, 0xffff);
+ ks_enable_int(dev);
+ ks_enable_qmu(dev);
+}
+
+static int ks8851_mll_init(struct eth_device *dev, bd_t *bd)
+{
+ struct chip_id *id = dev->priv;
+
+ debug(DRIVERNAME ": detected %s controller\n", id->name);
+
+ if (ks_read_selftest(dev)) {
+ printf(DRIVERNAME ": Selftest failed\n");
+ return -1;
+ }
+
+ ks8851_mll_reset(dev);
+
+ /* Configure the PHY, initialize the link state */
+ ks8851_mll_phy_configure(dev);
+
+ /* static allocation of private informations */
+ ks->frame_head_info = fr_h_i;
+
+ /* Turn on Tx + Rx */
+ ks8851_mll_enable(dev);
+
+ return 0;
+}
+
+static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len)
+{
+ /* start header at txb[0] to align txw entries */
+ ks->txh.txw[0] = 0;
+ ks->txh.txw[1] = cpu_to_le16(len);
+
+ /* 1. set sudo-DMA mode */
+ ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI);
+ ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
+ /* 2. write status/lenth info */
+ ks_outblk(dev, ks->txh.txw, 4);
+ /* 3. write pkt data */
+ ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4));
+ /* 4. reset sudo-DMA mode */
+ ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff);
+ /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */
+ ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE);
+ /* 6. wait until TXQCR_METFE is auto-cleared */
+ do { } while (ks_rdreg16(dev, KS_TXQCR) & TXQCR_METFE);
+}
+
+static int ks8851_mll_send(struct eth_device *dev, void *packet, int length)
+{
+ u8 *data = (u8 *)packet;
+ u16 tmplen = (u16)length;
+ u16 retv;
+
+ /*
+ * Extra space are required:
+ * 4 byte for alignment, 4 for status/length, 4 for CRC
+ */
+ retv = ks_rdreg16(dev, KS_TXMIR) & 0x1fff;
+ if (retv >= tmplen + 12) {
+ ks_write_qmu(dev, data, tmplen);
+ return 0;
+ } else {
+ printf(DRIVERNAME ": failed to send packet: No buffer\n");
+ return -1;
+ }
+}
+
+static void ks8851_mll_halt(struct eth_device *dev)
+{
+ ks8851_mll_reset(dev);
+}
+
+/*
+ * Maximum receive ring size; that is, the number of packets
+ * we can buffer before overflow happens. Basically, this just
+ * needs to be enough to prevent a packet being discarded while
+ * we are processing the previous one.
+ */
+static int ks8851_mll_recv(struct eth_device *dev)
+{
+ u16 status;
+
+ status = ks_rdreg16(dev, KS_ISR);
+
+ ks_wrreg16(dev, KS_ISR, status);
+
+ if ((status & IRQ_RXI))
+ ks_rcv(dev, (uchar **)NetRxPackets);
+
+ if ((status & IRQ_LDI)) {
+ u16 pmecr = ks_rdreg16(dev, KS_PMECR);
+ pmecr &= ~PMECR_WKEVT_MASK;
+ ks_wrreg16(dev, KS_PMECR, pmecr | PMECR_WKEVT_LINK);
+ }
+
+ return 0;
+}
+
+static int ks8851_mll_write_hwaddr(struct eth_device *dev)
+{
+ u16 addrl, addrm, addrh;
+
+ addrh = (dev->enetaddr[0] << 8) | dev->enetaddr[1];
+ addrm = (dev->enetaddr[2] << 8) | dev->enetaddr[3];
+ addrl = (dev->enetaddr[4] << 8) | dev->enetaddr[5];
+
+ ks_wrreg16(dev, KS_MARH, addrh);
+ ks_wrreg16(dev, KS_MARM, addrm);
+ ks_wrreg16(dev, KS_MARL, addrl);
+
+ return 0;
+}
+
+int ks8851_mll_initialize(u8 dev_num, int base_addr)
+{
+ struct eth_device *dev;
+
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ printf("Error: Failed to allocate memory\n");
+ return -1;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ dev->iobase = base_addr;
+
+ ks = &ks_str;
+
+ /* Try to detect chip. Will fail if not present. */
+ if (ks8851_mll_detect_chip(dev)) {
+ free(dev);
+ return -1;
+ }
+
+ dev->init = ks8851_mll_init;
+ dev->halt = ks8851_mll_halt;
+ dev->send = ks8851_mll_send;
+ dev->recv = ks8851_mll_recv;
+ dev->write_hwaddr = ks8851_mll_write_hwaddr;
+ sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num);
+
+ eth_register(dev);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ks8851_mll.h b/qemu/roms/u-boot/drivers/net/ks8851_mll.h
new file mode 100644
index 000000000..7f90ae4e5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ks8851_mll.h
@@ -0,0 +1,357 @@
+/*
+ * drivers/net/ks8851_mll.c
+ *
+ * Supports:
+ * KS8851 16bit MLL chip from Micrel Inc.
+ *
+ * Copyright (c) 2009 Micrel Inc.
+ *
+ * modified by
+ * (c) 2011 Bticino s.p.a, Roberto Cerati <roberto.cerati@bticino.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _KS8851_MLL_H_
+#define _KS8851_MLL_H_
+
+#include <linux/types.h>
+
+#define KS_CCR 0x08
+#define CCR_EEPROM (1 << 9)
+#define CCR_SPI (1 << 8)
+#define CCR_8BIT (1 << 7)
+#define CCR_16BIT (1 << 6)
+#define CCR_32BIT (1 << 5)
+#define CCR_SHARED (1 << 4)
+#define CCR_32PIN (1 << 0)
+
+/* MAC address registers */
+#define KS_MARL 0x10
+#define KS_MARM 0x12
+#define KS_MARH 0x14
+
+#define KS_OBCR 0x20
+#define OBCR_ODS_16MA (1 << 6)
+
+#define KS_EEPCR 0x22
+#define EEPCR_EESA (1 << 4)
+#define EEPCR_EESB (1 << 3)
+#define EEPCR_EEDO (1 << 2)
+#define EEPCR_EESCK (1 << 1)
+#define EEPCR_EECS (1 << 0)
+
+#define KS_MBIR 0x24
+#define MBIR_TXMBF (1 << 12)
+#define MBIR_TXMBFA (1 << 11)
+#define MBIR_RXMBF (1 << 4)
+#define MBIR_RXMBFA (1 << 3)
+
+#define KS_GRR 0x26
+#define GRR_QMU (1 << 1)
+#define GRR_GSR (1 << 0)
+
+#define KS_WFCR 0x2A
+#define WFCR_MPRXE (1 << 7)
+#define WFCR_WF3E (1 << 3)
+#define WFCR_WF2E (1 << 2)
+#define WFCR_WF1E (1 << 1)
+#define WFCR_WF0E (1 << 0)
+
+#define KS_WF0CRC0 0x30
+#define KS_WF0CRC1 0x32
+#define KS_WF0BM0 0x34
+#define KS_WF0BM1 0x36
+#define KS_WF0BM2 0x38
+#define KS_WF0BM3 0x3A
+
+#define KS_WF1CRC0 0x40
+#define KS_WF1CRC1 0x42
+#define KS_WF1BM0 0x44
+#define KS_WF1BM1 0x46
+#define KS_WF1BM2 0x48
+#define KS_WF1BM3 0x4A
+
+#define KS_WF2CRC0 0x50
+#define KS_WF2CRC1 0x52
+#define KS_WF2BM0 0x54
+#define KS_WF2BM1 0x56
+#define KS_WF2BM2 0x58
+#define KS_WF2BM3 0x5A
+
+#define KS_WF3CRC0 0x60
+#define KS_WF3CRC1 0x62
+#define KS_WF3BM0 0x64
+#define KS_WF3BM1 0x66
+#define KS_WF3BM2 0x68
+#define KS_WF3BM3 0x6A
+
+#define KS_TXCR 0x70
+#define TXCR_TCGICMP (1 << 8)
+#define TXCR_TCGUDP (1 << 7)
+#define TXCR_TCGTCP (1 << 6)
+#define TXCR_TCGIP (1 << 5)
+#define TXCR_FTXQ (1 << 4)
+#define TXCR_TXFCE (1 << 3)
+#define TXCR_TXPE (1 << 2)
+#define TXCR_TXCRC (1 << 1)
+#define TXCR_TXE (1 << 0)
+
+#define KS_TXSR 0x72
+#define TXSR_TXLC (1 << 13)
+#define TXSR_TXMC (1 << 12)
+#define TXSR_TXFID_MASK (0x3f << 0)
+#define TXSR_TXFID_SHIFT (0)
+#define TXSR_TXFID_GET(_v) (((_v) >> 0) & 0x3f)
+
+
+#define KS_RXCR1 0x74
+#define RXCR1_FRXQ (1 << 15)
+#define RXCR1_RXUDPFCC (1 << 14)
+#define RXCR1_RXTCPFCC (1 << 13)
+#define RXCR1_RXIPFCC (1 << 12)
+#define RXCR1_RXPAFMA (1 << 11)
+#define RXCR1_RXFCE (1 << 10)
+#define RXCR1_RXEFE (1 << 9)
+#define RXCR1_RXMAFMA (1 << 8)
+#define RXCR1_RXBE (1 << 7)
+#define RXCR1_RXME (1 << 6)
+#define RXCR1_RXUE (1 << 5)
+#define RXCR1_RXAE (1 << 4)
+#define RXCR1_RXINVF (1 << 1)
+#define RXCR1_RXE (1 << 0)
+#define RXCR1_FILTER_MASK (RXCR1_RXINVF | RXCR1_RXAE | \
+ RXCR1_RXMAFMA | RXCR1_RXPAFMA)
+
+#define KS_RXCR2 0x76
+#define RXCR2_SRDBL_MASK (0x7 << 5)
+#define RXCR2_SRDBL_SHIFT (5)
+#define RXCR2_SRDBL_4B (0x0 << 5)
+#define RXCR2_SRDBL_8B (0x1 << 5)
+#define RXCR2_SRDBL_16B (0x2 << 5)
+#define RXCR2_SRDBL_32B (0x3 << 5)
+/* #define RXCR2_SRDBL_FRAME (0x4 << 5) */
+#define RXCR2_IUFFP (1 << 4)
+#define RXCR2_RXIUFCEZ (1 << 3)
+#define RXCR2_UDPLFE (1 << 2)
+#define RXCR2_RXICMPFCC (1 << 1)
+#define RXCR2_RXSAF (1 << 0)
+
+#define KS_TXMIR 0x78
+
+#define KS_RXFHSR 0x7C
+#define RXFSHR_RXFV (1 << 15)
+#define RXFSHR_RXICMPFCS (1 << 13)
+#define RXFSHR_RXIPFCS (1 << 12)
+#define RXFSHR_RXTCPFCS (1 << 11)
+#define RXFSHR_RXUDPFCS (1 << 10)
+#define RXFSHR_RXBF (1 << 7)
+#define RXFSHR_RXMF (1 << 6)
+#define RXFSHR_RXUF (1 << 5)
+#define RXFSHR_RXMR (1 << 4)
+#define RXFSHR_RXFT (1 << 3)
+#define RXFSHR_RXFTL (1 << 2)
+#define RXFSHR_RXRF (1 << 1)
+#define RXFSHR_RXCE (1 << 0)
+#define RXFSHR_ERR (RXFSHR_RXCE | RXFSHR_RXRF |\
+ RXFSHR_RXFTL | RXFSHR_RXMR |\
+ RXFSHR_RXICMPFCS | RXFSHR_RXIPFCS |\
+ RXFSHR_RXTCPFCS)
+#define KS_RXFHBCR 0x7E
+#define RXFHBCR_CNT_MASK 0x0FFF
+
+#define KS_TXQCR 0x80
+#define TXQCR_AETFE (1 << 2)
+#define TXQCR_TXQMAM (1 << 1)
+#define TXQCR_METFE (1 << 0)
+
+#define KS_RXQCR 0x82
+#define RXQCR_RXDTTS (1 << 12)
+#define RXQCR_RXDBCTS (1 << 11)
+#define RXQCR_RXFCTS (1 << 10)
+#define RXQCR_RXIPHTOE (1 << 9)
+#define RXQCR_RXDTTE (1 << 7)
+#define RXQCR_RXDBCTE (1 << 6)
+#define RXQCR_RXFCTE (1 << 5)
+#define RXQCR_ADRFE (1 << 4)
+#define RXQCR_SDA (1 << 3)
+#define RXQCR_RRXEF (1 << 0)
+#define RXQCR_CMD_CNTL (RXQCR_RXFCTE|RXQCR_ADRFE)
+
+#define KS_TXFDPR 0x84
+#define TXFDPR_TXFPAI (1 << 14)
+#define TXFDPR_TXFP_MASK (0x7ff << 0)
+#define TXFDPR_TXFP_SHIFT (0)
+
+#define KS_RXFDPR 0x86
+#define RXFDPR_RXFPAI (1 << 14)
+
+#define KS_RXDTTR 0x8C
+#define KS_RXDBCTR 0x8E
+
+#define KS_IER 0x90
+#define KS_ISR 0x92
+#define IRQ_LCI (1 << 15)
+#define IRQ_TXI (1 << 14)
+#define IRQ_RXI (1 << 13)
+#define IRQ_RXOI (1 << 11)
+#define IRQ_TXPSI (1 << 9)
+#define IRQ_RXPSI (1 << 8)
+#define IRQ_TXSAI (1 << 6)
+#define IRQ_RXWFDI (1 << 5)
+#define IRQ_RXMPDI (1 << 4)
+#define IRQ_LDI (1 << 3)
+#define IRQ_EDI (1 << 2)
+#define IRQ_SPIBEI (1 << 1)
+#define IRQ_DEDI (1 << 0)
+
+#define KS_RXFCTR 0x9C
+#define RXFCTR_THRESHOLD_MASK 0x00FF
+
+#define KS_RXFC 0x9D
+#define RXFCTR_RXFC_MASK (0xff << 8)
+#define RXFCTR_RXFC_SHIFT (8)
+#define RXFCTR_RXFC_GET(_v) (((_v) >> 8) & 0xff)
+#define RXFCTR_RXFCT_MASK (0xff << 0)
+#define RXFCTR_RXFCT_SHIFT (0)
+
+#define KS_TXNTFSR 0x9E
+
+#define KS_MAHTR0 0xA0
+#define KS_MAHTR1 0xA2
+#define KS_MAHTR2 0xA4
+#define KS_MAHTR3 0xA6
+
+#define KS_FCLWR 0xB0
+#define KS_FCHWR 0xB2
+#define KS_FCOWR 0xB4
+
+#define KS_CIDER 0xC0
+#define CIDER_ID 0x8870
+#define CIDER_REV_MASK (0x7 << 1)
+#define CIDER_REV_SHIFT (1)
+#define CIDER_REV_GET(_v) (((_v) >> 1) & 0x7)
+
+#define KS_CGCR 0xC6
+#define KS_IACR 0xC8
+#define IACR_RDEN (1 << 12)
+#define IACR_TSEL_MASK (0x3 << 10)
+#define IACR_TSEL_SHIFT (10)
+#define IACR_TSEL_MIB (0x3 << 10)
+#define IACR_ADDR_MASK (0x1f << 0)
+#define IACR_ADDR_SHIFT (0)
+
+#define KS_IADLR 0xD0
+#define KS_IAHDR 0xD2
+
+#define KS_PMECR 0xD4
+#define PMECR_PME_DELAY (1 << 14)
+#define PMECR_PME_POL (1 << 12)
+#define PMECR_WOL_WAKEUP (1 << 11)
+#define PMECR_WOL_MAGICPKT (1 << 10)
+#define PMECR_WOL_LINKUP (1 << 9)
+#define PMECR_WOL_ENERGY (1 << 8)
+#define PMECR_AUTO_WAKE_EN (1 << 7)
+#define PMECR_WAKEUP_NORMAL (1 << 6)
+#define PMECR_WKEVT_MASK (0xf << 2)
+#define PMECR_WKEVT_SHIFT (2)
+#define PMECR_WKEVT_GET(_v) (((_v) >> 2) & 0xf)
+#define PMECR_WKEVT_ENERGY (0x1 << 2)
+#define PMECR_WKEVT_LINK (0x2 << 2)
+#define PMECR_WKEVT_MAGICPKT (0x4 << 2)
+#define PMECR_WKEVT_FRAME (0x8 << 2)
+#define PMECR_PM_MASK (0x3 << 0)
+#define PMECR_PM_SHIFT (0)
+#define PMECR_PM_NORMAL (0x0 << 0)
+#define PMECR_PM_ENERGY (0x1 << 0)
+#define PMECR_PM_SOFTDOWN (0x2 << 0)
+#define PMECR_PM_POWERSAVE (0x3 << 0)
+
+/* Standard MII PHY data */
+#define KS_P1MBCR 0xE4
+#define P1MBCR_FORCE_FDX (1 << 8)
+
+#define KS_P1MBSR 0xE6
+#define P1MBSR_AN_COMPLETE (1 << 5)
+#define P1MBSR_AN_CAPABLE (1 << 3)
+#define P1MBSR_LINK_UP (1 << 2)
+
+#define KS_PHY1ILR 0xE8
+#define KS_PHY1IHR 0xEA
+#define KS_P1ANAR 0xEC
+#define KS_P1ANLPR 0xEE
+
+#define KS_P1SCLMD 0xF4
+#define P1SCLMD_LEDOFF (1 << 15)
+#define P1SCLMD_TXIDS (1 << 14)
+#define P1SCLMD_RESTARTAN (1 << 13)
+#define P1SCLMD_DISAUTOMDIX (1 << 10)
+#define P1SCLMD_FORCEMDIX (1 << 9)
+#define P1SCLMD_AUTONEGEN (1 << 7)
+#define P1SCLMD_FORCE100 (1 << 6)
+#define P1SCLMD_FORCEFDX (1 << 5)
+#define P1SCLMD_ADV_FLOW (1 << 4)
+#define P1SCLMD_ADV_100BT_FDX (1 << 3)
+#define P1SCLMD_ADV_100BT_HDX (1 << 2)
+#define P1SCLMD_ADV_10BT_FDX (1 << 1)
+#define P1SCLMD_ADV_10BT_HDX (1 << 0)
+
+#define KS_P1CR 0xF6
+#define P1CR_HP_MDIX (1 << 15)
+#define P1CR_REV_POL (1 << 13)
+#define P1CR_OP_100M (1 << 10)
+#define P1CR_OP_FDX (1 << 9)
+#define P1CR_OP_MDI (1 << 7)
+#define P1CR_AN_DONE (1 << 6)
+#define P1CR_LINK_GOOD (1 << 5)
+#define P1CR_PNTR_FLOW (1 << 4)
+#define P1CR_PNTR_100BT_FDX (1 << 3)
+#define P1CR_PNTR_100BT_HDX (1 << 2)
+#define P1CR_PNTR_10BT_FDX (1 << 1)
+#define P1CR_PNTR_10BT_HDX (1 << 0)
+
+/* TX Frame control */
+#define TXFR_TXIC (1 << 15)
+#define TXFR_TXFID_MASK (0x3f << 0)
+#define TXFR_TXFID_SHIFT (0)
+
+#define KS_P1SR 0xF8
+#define P1SR_HP_MDIX (1 << 15)
+#define P1SR_REV_POL (1 << 13)
+#define P1SR_OP_100M (1 << 10)
+#define P1SR_OP_FDX (1 << 9)
+#define P1SR_OP_MDI (1 << 7)
+#define P1SR_AN_DONE (1 << 6)
+#define P1SR_LINK_GOOD (1 << 5)
+#define P1SR_PNTR_FLOW (1 << 4)
+#define P1SR_PNTR_100BT_FDX (1 << 3)
+#define P1SR_PNTR_100BT_HDX (1 << 2)
+#define P1SR_PNTR_10BT_FDX (1 << 1)
+#define P1SR_PNTR_10BT_HDX (1 << 0)
+
+#define ENUM_BUS_NONE 0
+#define ENUM_BUS_8BIT 1
+#define ENUM_BUS_16BIT 2
+#define ENUM_BUS_32BIT 3
+
+#define MAX_MCAST_LST 32
+#define HW_MCAST_SIZE 8
+#define MAC_ADDR_LEN 6
+
+/* Chip ID values */
+struct chip_id {
+ u16 id;
+ char *name;
+};
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/lan91c96.c b/qemu/roms/u-boot/drivers/net/lan91c96.c
new file mode 100644
index 000000000..229658abc
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/lan91c96.c
@@ -0,0 +1,804 @@
+/*------------------------------------------------------------------------
+ * lan91c96.c
+ * This is a driver for SMSC's LAN91C96 single-chip Ethernet device, based
+ * on the SMC91111 driver from U-boot.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Rolf Offermanns <rof@sysgo.de>
+ *
+ * Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ * Developed by Simple Network Magic Corporation (SNMC)
+ * Copyright (C) 1996 by Erik Stahlman (ES)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Information contained in this file was obtained from the LAN91C96
+ * manual from SMC. To get a copy, if you really want one, you can find
+ * information under www.smsc.com.
+ *
+ * "Features" of the SMC chip:
+ * 6144 byte packet memory. ( for the 91C96 )
+ * EEPROM for configuration
+ * AUI/TP selection ( mine has 10Base2/10BaseT select )
+ *
+ * Arguments:
+ * io = for the base address
+ * irq = for the IRQ
+ *
+ * author:
+ * Erik Stahlman ( erik@vt.edu )
+ * Daris A Nevil ( dnevil@snmc.com )
+ *
+ *
+ * Hardware multicast code from Peter Cammaert ( pc@denkart.be )
+ *
+ * Sources:
+ * o SMSC LAN91C96 databook (www.smsc.com)
+ * o smc91111.c (u-boot driver)
+ * o smc9194.c (linux kernel driver)
+ * o lan91c96.c (Intel Diagnostic Manager driver)
+ *
+ * History:
+ * 04/30/03 Mathijs Haarman Modified smc91111.c (u-boot version)
+ * for lan91c96
+ *---------------------------------------------------------------------------
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include "lan91c96.h"
+#include <net.h>
+#include <linux/compiler.h>
+
+/*------------------------------------------------------------------------
+ *
+ * Configuration options, for the experienced user to change.
+ *
+ -------------------------------------------------------------------------*/
+
+/* Use power-down feature of the chip */
+#define POWER_DOWN 0
+
+/*
+ * Wait time for memory to be free. This probably shouldn't be
+ * tuned that much, as waiting for this means nothing else happens
+ * in the system
+*/
+#define MEMORY_WAIT_TIME 16
+
+#define SMC_DEBUG 0
+
+#if (SMC_DEBUG > 2 )
+#define PRINTK3(args...) printf(args)
+#else
+#define PRINTK3(args...)
+#endif
+
+#if SMC_DEBUG > 1
+#define PRINTK2(args...) printf(args)
+#else
+#define PRINTK2(args...)
+#endif
+
+#ifdef SMC_DEBUG
+#define PRINTK(args...) printf(args)
+#else
+#define PRINTK(args...)
+#endif
+
+
+/*------------------------------------------------------------------------
+ *
+ * The internal workings of the driver. If you are changing anything
+ * here with the SMC stuff, you should have the datasheet and know
+ * what you are doing.
+ *
+ *------------------------------------------------------------------------
+ */
+#define DRIVER_NAME "LAN91C96"
+#define SMC_ALLOC_MAX_TRY 5
+#define SMC_TX_TIMEOUT 30
+
+#define ETH_ZLEN 60
+
+#ifdef CONFIG_LAN91C96_USE_32_BIT
+#define USE_32_BIT 1
+#else
+#undef USE_32_BIT
+#endif
+
+/* See if a MAC address is defined in the current environment. If so use it. If not
+ . print a warning and set the environment and other globals with the default.
+ . If an EEPROM is present it really should be consulted.
+*/
+static int smc_get_ethaddr(bd_t *bd, struct eth_device *dev);
+static int get_rom_mac(struct eth_device *dev, unsigned char *v_rom_mac);
+
+/* ------------------------------------------------------------
+ * Internal routines
+ * ------------------------------------------------------------
+ */
+
+static unsigned char smc_mac_addr[] = { 0xc0, 0x00, 0x00, 0x1b, 0x62, 0x9c };
+
+/*
+ * This function must be called before smc_open() if you want to override
+ * the default mac address.
+ */
+
+static void smc_set_mac_addr(const unsigned char *addr)
+{
+ int i;
+
+ for (i = 0; i < sizeof (smc_mac_addr); i++) {
+ smc_mac_addr[i] = addr[i];
+ }
+}
+
+/***********************************************
+ * Show available memory *
+ ***********************************************/
+void dump_memory_info(struct eth_device *dev)
+{
+ __maybe_unused word mem_info;
+ word old_bank;
+
+ old_bank = SMC_inw(dev, LAN91C96_BANK_SELECT) & 0xF;
+
+ SMC_SELECT_BANK(dev, 0);
+ mem_info = SMC_inw(dev, LAN91C96_MIR);
+ PRINTK2 ("Memory: %4d available\n", (mem_info >> 8) * 2048);
+
+ SMC_SELECT_BANK(dev, old_bank);
+}
+
+/*
+ * A rather simple routine to print out a packet for debugging purposes.
+ */
+#if SMC_DEBUG > 2
+static void print_packet (byte *, int);
+#endif
+
+static int poll4int (struct eth_device *dev, byte mask, int timeout)
+{
+ int tmo = get_timer (0) + timeout * CONFIG_SYS_HZ;
+ int is_timeout = 0;
+ word old_bank = SMC_inw(dev, LAN91C96_BANK_SELECT);
+
+ PRINTK2 ("Polling...\n");
+ SMC_SELECT_BANK(dev, 2);
+ while ((SMC_inw(dev, LAN91C96_INT_STATS) & mask) == 0) {
+ if (get_timer (0) >= tmo) {
+ is_timeout = 1;
+ break;
+ }
+ }
+
+ /* restore old bank selection */
+ SMC_SELECT_BANK(dev, old_bank);
+
+ if (is_timeout)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Function: smc_reset
+ * Purpose:
+ * This sets the SMC91111 chip to its normal state, hopefully from whatever
+ * mess that any other DOS driver has put it in.
+ *
+ * Maybe I should reset more registers to defaults in here? SOFTRST should
+ * do that for me.
+ *
+ * Method:
+ * 1. send a SOFT RESET
+ * 2. wait for it to finish
+ * 3. enable autorelease mode
+ * 4. reset the memory management unit
+ * 5. clear all interrupts
+ *
+*/
+static void smc_reset(struct eth_device *dev)
+{
+ PRINTK2("%s:smc_reset\n", dev->name);
+
+ /* This resets the registers mostly to defaults, but doesn't
+ affect EEPROM. That seems unnecessary */
+ SMC_SELECT_BANK(dev, 0);
+ SMC_outw(dev, LAN91C96_RCR_SOFT_RST, LAN91C96_RCR);
+
+ udelay (10);
+
+ /* Disable transmit and receive functionality */
+ SMC_outw(dev, 0, LAN91C96_RCR);
+ SMC_outw(dev, 0, LAN91C96_TCR);
+
+ /* set the control register */
+ SMC_SELECT_BANK(dev, 1);
+ SMC_outw(dev, SMC_inw(dev, LAN91C96_CONTROL) | LAN91C96_CTR_BIT_8,
+ LAN91C96_CONTROL);
+
+ /* Disable all interrupts */
+ SMC_outb(dev, 0, LAN91C96_INT_MASK);
+}
+
+/*
+ * Function: smc_enable
+ * Purpose: let the chip talk to the outside work
+ * Method:
+ * 1. Initialize the Memory Configuration Register
+ * 2. Enable the transmitter
+ * 3. Enable the receiver
+*/
+static void smc_enable(struct eth_device *dev)
+{
+ PRINTK2("%s:smc_enable\n", dev->name);
+ SMC_SELECT_BANK(dev, 0);
+
+ /* Initialize the Memory Configuration Register. See page
+ 49 of the LAN91C96 data sheet for details. */
+ SMC_outw(dev, LAN91C96_MCR_TRANSMIT_PAGES, LAN91C96_MCR);
+
+ /* Initialize the Transmit Control Register */
+ SMC_outw(dev, LAN91C96_TCR_TXENA, LAN91C96_TCR);
+ /* Initialize the Receive Control Register
+ * FIXME:
+ * The promiscuous bit set because I could not receive ARP reply
+ * packets from the server when I send a ARP request. It only works
+ * when I set the promiscuous bit
+ */
+ SMC_outw(dev, LAN91C96_RCR_RXEN | LAN91C96_RCR_PRMS, LAN91C96_RCR);
+}
+
+/*
+ * Function: smc_shutdown
+ * Purpose: closes down the SMC91xxx chip.
+ * Method:
+ * 1. zero the interrupt mask
+ * 2. clear the enable receive flag
+ * 3. clear the enable xmit flags
+ *
+ * TODO:
+ * (1) maybe utilize power down mode.
+ * Why not yet? Because while the chip will go into power down mode,
+ * the manual says that it will wake up in response to any I/O requests
+ * in the register space. Empirical results do not show this working.
+ */
+static void smc_shutdown(struct eth_device *dev)
+{
+ PRINTK2("%s:smc_shutdown\n", dev->name);
+
+ /* no more interrupts for me */
+ SMC_SELECT_BANK(dev, 2);
+ SMC_outb(dev, 0, LAN91C96_INT_MASK);
+
+ /* and tell the card to stay away from that nasty outside world */
+ SMC_SELECT_BANK(dev, 0);
+ SMC_outb(dev, 0, LAN91C96_RCR);
+ SMC_outb(dev, 0, LAN91C96_TCR);
+}
+
+
+/*
+ * Function: smc_hardware_send_packet(struct net_device * )
+ * Purpose:
+ * This sends the actual packet to the SMC9xxx chip.
+ *
+ * Algorithm:
+ * First, see if a saved_skb is available.
+ * ( this should NOT be called if there is no 'saved_skb'
+ * Now, find the packet number that the chip allocated
+ * Point the data pointers at it in memory
+ * Set the length word in the chip's memory
+ * Dump the packet to chip memory
+ * Check if a last byte is needed ( odd length packet )
+ * if so, set the control flag right
+ * Tell the card to send it
+ * Enable the transmit interrupt, so I know if it failed
+ * Free the kernel data if I actually sent it.
+ */
+static int smc_send_packet(struct eth_device *dev, void *packet,
+ int packet_length)
+{
+ byte packet_no;
+ byte *buf;
+ int length;
+ int numPages;
+ int try = 0;
+ int time_out;
+ byte status;
+
+
+ PRINTK3("%s:smc_hardware_send_packet\n", dev->name);
+
+ length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
+
+ /* allocate memory
+ ** The MMU wants the number of pages to be the number of 256 bytes
+ ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+ **
+ ** The 91C111 ignores the size bits, but the code is left intact
+ ** for backwards and future compatibility.
+ **
+ ** Pkt size for allocating is data length +6 (for additional status
+ ** words, length and ctl!)
+ **
+ ** If odd size then last byte is included in this header.
+ */
+ numPages = ((length & 0xfffe) + 6);
+ numPages >>= 8; /* Divide by 256 */
+
+ if (numPages > 7) {
+ printf("%s: Far too big packet error. \n", dev->name);
+ return 0;
+ }
+
+ /* now, try to allocate the memory */
+
+ SMC_SELECT_BANK(dev, 2);
+ SMC_outw(dev, LAN91C96_MMUCR_ALLOC_TX | numPages, LAN91C96_MMU);
+
+ again:
+ try++;
+ time_out = MEMORY_WAIT_TIME;
+ do {
+ status = SMC_inb(dev, LAN91C96_INT_STATS);
+ if (status & LAN91C96_IST_ALLOC_INT) {
+
+ SMC_outb(dev, LAN91C96_IST_ALLOC_INT,
+ LAN91C96_INT_STATS);
+ break;
+ }
+ } while (--time_out);
+
+ if (!time_out) {
+ PRINTK2 ("%s: memory allocation, try %d failed ...\n",
+ dev->name, try);
+ if (try < SMC_ALLOC_MAX_TRY)
+ goto again;
+ else
+ return 0;
+ }
+
+ PRINTK2 ("%s: memory allocation, try %d succeeded ...\n",
+ dev->name, try);
+
+ /* I can send the packet now.. */
+ buf = (byte *) packet;
+
+ /* If I get here, I _know_ there is a packet slot waiting for me */
+ packet_no = SMC_inb(dev, LAN91C96_ARR);
+ if (packet_no & LAN91C96_ARR_FAILED) {
+ /* or isn't there? BAD CHIP! */
+ printf("%s: Memory allocation failed. \n", dev->name);
+ return 0;
+ }
+
+ /* we have a packet address, so tell the card to use it */
+ SMC_outb(dev, packet_no, LAN91C96_PNR);
+
+ /* point to the beginning of the packet */
+ SMC_outw(dev, LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
+
+ PRINTK3("%s: Trying to xmit packet of length %x\n",
+ dev->name, length);
+
+#if SMC_DEBUG > 2
+ printf ("Transmitting Packet\n");
+ print_packet (buf, length);
+#endif
+
+ /* send the packet length ( +6 for status, length and ctl byte )
+ and the status word ( set to zeros ) */
+#ifdef USE_32_BIT
+ SMC_outl(dev, (length + 6) << 16, LAN91C96_DATA_HIGH);
+#else
+ SMC_outw(dev, 0, LAN91C96_DATA_HIGH);
+ /* send the packet length ( +6 for status words, length, and ctl */
+ SMC_outw(dev, (length + 6), LAN91C96_DATA_HIGH);
+#endif /* USE_32_BIT */
+
+ /* send the actual data
+ * I _think_ it's faster to send the longs first, and then
+ * mop up by sending the last word. It depends heavily
+ * on alignment, at least on the 486. Maybe it would be
+ * a good idea to check which is optimal? But that could take
+ * almost as much time as is saved?
+ */
+#ifdef USE_32_BIT
+ SMC_outsl(dev, LAN91C96_DATA_HIGH, buf, length >> 2);
+ if (length & 0x2)
+ SMC_outw(dev, *((word *) (buf + (length & 0xFFFFFFFC))),
+ LAN91C96_DATA_HIGH);
+#else
+ SMC_outsw(dev, LAN91C96_DATA_HIGH, buf, (length) >> 1);
+#endif /* USE_32_BIT */
+
+ /* Send the last byte, if there is one. */
+ if ((length & 1) == 0) {
+ SMC_outw(dev, 0, LAN91C96_DATA_HIGH);
+ } else {
+ SMC_outw(dev, buf[length - 1] | 0x2000, LAN91C96_DATA_HIGH);
+ }
+
+ /* and let the chipset deal with it */
+ SMC_outw(dev, LAN91C96_MMUCR_ENQUEUE, LAN91C96_MMU);
+
+ /* poll for TX INT */
+ if (poll4int (dev, LAN91C96_MSK_TX_INT, SMC_TX_TIMEOUT)) {
+ /* sending failed */
+ PRINTK2("%s: TX timeout, sending failed...\n", dev->name);
+
+ /* release packet */
+ SMC_outw(dev, LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
+
+ /* wait for MMU getting ready (low) */
+ while (SMC_inw(dev, LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+ udelay (10);
+
+ PRINTK2("MMU ready\n");
+
+
+ return 0;
+ } else {
+ /* ack. int */
+ SMC_outw(dev, LAN91C96_IST_TX_INT, LAN91C96_INT_STATS);
+
+ PRINTK2("%s: Sent packet of length %d \n", dev->name, length);
+
+ /* release packet */
+ SMC_outw(dev, LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
+
+ /* wait for MMU getting ready (low) */
+ while (SMC_inw(dev, LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+ udelay (10);
+
+ PRINTK2 ("MMU ready\n");
+ }
+
+ return length;
+}
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ *
+ */
+static int smc_open(bd_t *bd, struct eth_device *dev)
+{
+ int i, err; /* used to set hw ethernet address */
+
+ PRINTK2("%s:smc_open\n", dev->name);
+
+ /* reset the hardware */
+
+ smc_reset(dev);
+ smc_enable(dev);
+
+ SMC_SELECT_BANK(dev, 1);
+ /* set smc_mac_addr, and sync it with u-boot globals */
+ err = smc_get_ethaddr(bd, dev);
+ if (err < 0)
+ return -1;
+#ifdef USE_32_BIT
+ for (i = 0; i < 6; i += 2) {
+ word address;
+
+ address = smc_mac_addr[i + 1] << 8;
+ address |= smc_mac_addr[i];
+ SMC_outw(dev, address, LAN91C96_IA0 + i);
+ }
+#else
+ for (i = 0; i < 6; i++)
+ SMC_outb(dev, smc_mac_addr[i], LAN91C96_IA0 + i);
+#endif
+ return 0;
+}
+
+/*-------------------------------------------------------------
+ *
+ * smc_rcv - receive a packet from the card
+ *
+ * There is ( at least ) a packet waiting to be read from
+ * chip-memory.
+ *
+ * o Read the status
+ * o If an error, record it
+ * o otherwise, read in the packet
+ *-------------------------------------------------------------
+ */
+static int smc_rcv(struct eth_device *dev)
+{
+ int packet_number;
+ word status;
+ word packet_length;
+ int is_error = 0;
+
+#ifdef USE_32_BIT
+ dword stat_len;
+#endif
+
+
+ SMC_SELECT_BANK(dev, 2);
+ packet_number = SMC_inw(dev, LAN91C96_FIFO);
+
+ if (packet_number & LAN91C96_FIFO_RXEMPTY) {
+ return 0;
+ }
+
+ PRINTK3("%s:smc_rcv\n", dev->name);
+ /* start reading from the start of the packet */
+ SMC_outw(dev, LAN91C96_PTR_READ | LAN91C96_PTR_RCV |
+ LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
+
+ /* First two words are status and packet_length */
+#ifdef USE_32_BIT
+ stat_len = SMC_inl(dev, LAN91C96_DATA_HIGH);
+ status = stat_len & 0xffff;
+ packet_length = stat_len >> 16;
+#else
+ status = SMC_inw(dev, LAN91C96_DATA_HIGH);
+ packet_length = SMC_inw(dev, LAN91C96_DATA_HIGH);
+#endif
+
+ packet_length &= 0x07ff; /* mask off top bits */
+
+ PRINTK2 ("RCV: STATUS %4x LENGTH %4x\n", status, packet_length);
+
+ if (!(status & FRAME_FILTER)) {
+ /* Adjust for having already read the first two words */
+ packet_length -= 4; /*4; */
+
+
+ /* set odd length for bug in LAN91C111, */
+ /* which never sets RS_ODDFRAME */
+ /* TODO ? */
+
+
+#ifdef USE_32_BIT
+ PRINTK3 (" Reading %d dwords (and %d bytes) \n",
+ packet_length >> 2, packet_length & 3);
+ /* QUESTION: Like in the TX routine, do I want
+ to send the DWORDs or the bytes first, or some
+ mixture. A mixture might improve already slow PIO
+ performance */
+ SMC_insl(dev, LAN91C96_DATA_HIGH, NetRxPackets[0],
+ packet_length >> 2);
+ /* read the left over bytes */
+ if (packet_length & 3) {
+ int i;
+
+ byte *tail = (byte *) (NetRxPackets[0] + (packet_length & ~3));
+ dword leftover = SMC_inl(dev, LAN91C96_DATA_HIGH);
+
+ for (i = 0; i < (packet_length & 3); i++)
+ *tail++ = (byte) (leftover >> (8 * i)) & 0xff;
+ }
+#else
+ PRINTK3 (" Reading %d words and %d byte(s) \n",
+ (packet_length >> 1), packet_length & 1);
+ SMC_insw(dev, LAN91C96_DATA_HIGH, NetRxPackets[0],
+ packet_length >> 1);
+
+#endif /* USE_32_BIT */
+
+#if SMC_DEBUG > 2
+ printf ("Receiving Packet\n");
+ print_packet((byte *)NetRxPackets[0], packet_length);
+#endif
+ } else {
+ /* error ... */
+ /* TODO ? */
+ is_error = 1;
+ }
+
+ while (SMC_inw(dev, LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+ udelay (1); /* Wait until not busy */
+
+ /* error or good, tell the card to get rid of this packet */
+ SMC_outw(dev, LAN91C96_MMUCR_RELEASE_RX, LAN91C96_MMU);
+
+ while (SMC_inw(dev, LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+ udelay (1); /* Wait until not busy */
+
+ if (!is_error) {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive (NetRxPackets[0], packet_length);
+ return packet_length;
+ } else {
+ return 0;
+ }
+
+}
+
+/*----------------------------------------------------
+ * smc_close
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world. Caused by
+ * an 'ifconfig ethX down'
+ *
+ -----------------------------------------------------*/
+static int smc_close(struct eth_device *dev)
+{
+ PRINTK2("%s:smc_close\n", dev->name);
+
+ /* clear everything */
+ smc_shutdown(dev);
+
+ return 0;
+}
+
+#if SMC_DEBUG > 2
+static void print_packet(byte *buf, int length)
+{
+#if 0
+ int i;
+ int remainder;
+ int lines;
+
+ printf ("Packet of length %d \n", length);
+
+ lines = length / 16;
+ remainder = length % 16;
+
+ for (i = 0; i < lines; i++) {
+ int cur;
+
+ for (cur = 0; cur < 8; cur++) {
+ byte a, b;
+
+ a = *(buf++);
+ b = *(buf++);
+ printf ("%02x%02x ", a, b);
+ }
+ printf ("\n");
+ }
+ for (i = 0; i < remainder / 2; i++) {
+ byte a, b;
+
+ a = *(buf++);
+ b = *(buf++);
+ printf ("%02x%02x ", a, b);
+ }
+ printf ("\n");
+#endif /* 0 */
+}
+#endif /* SMC_DEBUG > 2 */
+
+static int lan91c96_init(struct eth_device *dev, bd_t *bd)
+{
+ return smc_open(bd, dev);
+}
+
+static void lan91c96_halt(struct eth_device *dev)
+{
+ smc_close(dev);
+}
+
+static int lan91c96_recv(struct eth_device *dev)
+{
+ return smc_rcv(dev);
+}
+
+static int lan91c96_send(struct eth_device *dev, void *packet,
+ int length)
+{
+ return smc_send_packet(dev, packet, length);
+}
+
+/* smc_get_ethaddr
+ *
+ * This checks both the environment and the ROM for an ethernet address. If
+ * found, the environment takes precedence.
+ */
+
+static int smc_get_ethaddr(bd_t *bd, struct eth_device *dev)
+{
+ uchar v_mac[6];
+
+ if (!eth_getenv_enetaddr("ethaddr", v_mac)) {
+ /* get ROM mac value if any */
+ if (!get_rom_mac(dev, v_mac)) {
+ printf("\n*** ERROR: ethaddr is NOT set !!\n");
+ return -1;
+ }
+ eth_setenv_enetaddr("ethaddr", v_mac);
+ }
+
+ smc_set_mac_addr(v_mac); /* use old function to update smc default */
+ PRINTK("Using MAC Address %pM\n", v_mac);
+ return 0;
+}
+
+/*
+ * get_rom_mac()
+ * Note, this has omly been tested for the OMAP730 P2.
+ */
+
+static int get_rom_mac(struct eth_device *dev, unsigned char *v_rom_mac)
+{
+#ifdef HARDCODE_MAC /* used for testing or to supress run time warnings */
+ char hw_mac_addr[] = { 0x02, 0x80, 0xad, 0x20, 0x31, 0xb8 };
+
+ memcpy (v_rom_mac, hw_mac_addr, 6);
+ return (1);
+#else
+ int i;
+ SMC_SELECT_BANK(dev, 1);
+ for (i=0; i<6; i++)
+ {
+ v_rom_mac[i] = SMC_inb(dev, LAN91C96_IA0 + i);
+ }
+ return (1);
+#endif
+}
+
+/* Structure to detect the device IDs */
+struct id_type {
+ u8 id;
+ char *name;
+};
+static struct id_type supported_chips[] = {
+ {0, ""}, /* Dummy entry to prevent id check failure */
+ {9, "LAN91C110"},
+ {8, "LAN91C100FD"},
+ {7, "LAN91C100"},
+ {5, "LAN91C95"},
+ {4, "LAN91C94/96"},
+ {3, "LAN91C90/92"},
+};
+/* lan91c96_detect_chip
+ * See:
+ * http://www.embeddedsys.com/subpages/resources/images/documents/LAN91C96_datasheet.pdf
+ * page 71 - that is the closest we get to detect this device
+ */
+static int lan91c96_detect_chip(struct eth_device *dev)
+{
+ u8 chip_id;
+ int r;
+ SMC_SELECT_BANK(dev, 3);
+ chip_id = (SMC_inw(dev, 0xA) & LAN91C96_REV_CHIPID) >> 4;
+ SMC_SELECT_BANK(dev, 0);
+ for (r = 0; r < ARRAY_SIZE(supported_chips); r++)
+ if (chip_id == supported_chips[r].id)
+ return r;
+ return 0;
+}
+
+int lan91c96_initialize(u8 dev_num, int base_addr)
+{
+ struct eth_device *dev;
+ int r = 0;
+
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ return 0;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ dev->iobase = base_addr;
+
+ /* Try to detect chip. Will fail if not present. */
+ r = lan91c96_detect_chip(dev);
+ if (!r) {
+ free(dev);
+ return 0;
+ }
+ get_rom_mac(dev, dev->enetaddr);
+
+ dev->init = lan91c96_init;
+ dev->halt = lan91c96_halt;
+ dev->send = lan91c96_send;
+ dev->recv = lan91c96_recv;
+ sprintf(dev->name, "%s-%hu", supported_chips[r].name, dev_num);
+
+ eth_register(dev);
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/lan91c96.h b/qemu/roms/u-boot/drivers/net/lan91c96.h
new file mode 100644
index 000000000..3e914ce5a
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/lan91c96.h
@@ -0,0 +1,617 @@
+/*------------------------------------------------------------------------
+ * lan91c96.h
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Rolf Offermanns <rof@sysgo.de>
+ * Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ * Developed by Simple Network Magic Corporation (SNMC)
+ * Copyright (C) 1996 by Erik Stahlman (ES)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This file contains register information and access macros for
+ * the LAN91C96 single chip ethernet controller. It is a modified
+ * version of the smc9111.h file.
+ *
+ * Information contained in this file was obtained from the LAN91C96
+ * manual from SMC. To get a copy, if you really want one, you can find
+ * information under www.smsc.com.
+ *
+ * Authors
+ * Erik Stahlman ( erik@vt.edu )
+ * Daris A Nevil ( dnevil@snmc.com )
+ *
+ * History
+ * 04/30/03 Mathijs Haarman Modified smc91111.h (u-boot version)
+ * for lan91c96
+ *-------------------------------------------------------------------------
+ */
+#ifndef _LAN91C96_H_
+#define _LAN91C96_H_
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <config.h>
+
+/* I want some simple types */
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long int dword;
+
+/*
+ * DEBUGGING LEVELS
+ *
+ * 0 for normal operation
+ * 1 for slightly more details
+ * >2 for various levels of increasingly useless information
+ * 2 for interrupt tracking, status flags
+ * 3 for packet info
+ * 4 for complete packet dumps
+ */
+/*#define SMC_DEBUG 0 */
+
+/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
+
+#define SMC_IO_EXTENT 16
+
+#ifdef CONFIG_CPU_PXA25X
+
+#define SMC_IO_SHIFT 0
+
+#define SMCREG(edev, r) ((edev)->iobase+((r)<<SMC_IO_SHIFT))
+
+#define SMC_inl(edev, r) (*((volatile dword *)SMCREG(edev, r)))
+#define SMC_inw(edev, r) (*((volatile word *)SMCREG(edev, r)))
+#define SMC_inb(edev, p) ({ \
+ unsigned int __p = p; \
+ unsigned int __v = SMC_inw(edev, __p & ~1); \
+ if (__p & 1) __v >>= 8; \
+ else __v &= 0xff; \
+ __v; })
+
+#define SMC_outl(edev, d, r) (*((volatile dword *)SMCREG(edev, r)) = d)
+#define SMC_outw(edev, d, r) (*((volatile word *)SMCREG(edev, r)) = d)
+#define SMC_outb(edev, d, r) ({ word __d = (byte)(d); \
+ word __w = SMC_inw(edev, (r)&~1); \
+ __w &= ((r)&1) ? 0x00FF : 0xFF00; \
+ __w |= ((r)&1) ? __d<<8 : __d; \
+ SMC_outw(edev, __w, (r)&~1); \
+ })
+
+#define SMC_outsl(edev, r, b, l) ({ int __i; \
+ dword *__b2; \
+ __b2 = (dword *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outl(edev, *(__b2 + __i),\
+ r); \
+ } \
+ })
+
+#define SMC_outsw(edev, r, b, l) ({ int __i; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outw(edev, *(__b2 + __i),\
+ r); \
+ } \
+ })
+
+#define SMC_insl(edev, r, b, l) ({ int __i ; \
+ dword *__b2; \
+ __b2 = (dword *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inl(edev,\
+ r); \
+ SMC_inl(edev, 0); \
+ }; \
+ })
+
+#define SMC_insw(edev, r, b, l) ({ int __i ; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inw(edev,\
+ r); \
+ SMC_inw(edev, 0); \
+ }; \
+ })
+
+#define SMC_insb(edev, r, b, l) ({ int __i ; \
+ byte *__b2; \
+ __b2 = (byte *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inb(edev,\
+ r); \
+ SMC_inb(edev, 0); \
+ }; \
+ })
+
+#else /* if not CONFIG_CPU_PXA25X */
+
+/*
+ * We have only 16 Bit PCMCIA access on Socket 0
+ */
+
+#define SMC_inw(edev, r) (*((volatile word *)((edev)->iobase+(r))))
+#define SMC_inb(edev, r) (((r)&1) ? SMC_inw(edev, (r)&~1)>>8 :\
+ SMC_inw(edev, r)&0xFF)
+
+#define SMC_outw(edev, d, r) (*((volatile word *)((edev)->iobase+(r))) = d)
+#define SMC_outb(edev, d, r) ({ word __d = (byte)(d); \
+ word __w = SMC_inw(edev, (r)&~1); \
+ __w &= ((r)&1) ? 0x00FF : 0xFF00; \
+ __w |= ((r)&1) ? __d<<8 : __d; \
+ SMC_outw(edev, __w, (r)&~1); \
+ })
+#define SMC_outsw(edev, r, b, l) ({ int __i; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outw(edev, *(__b2 + __i),\
+ r); \
+ } \
+ })
+
+#define SMC_insw(edev, r, b, l) ({ int __i ; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inw(edev,\
+ r); \
+ SMC_inw(edev, 0); \
+ }; \
+ })
+
+#endif
+
+/*
+ ****************************************************************************
+ * Bank Select Field
+ ****************************************************************************
+ */
+#define LAN91C96_BANK_SELECT 14 /* Bank Select Register */
+#define LAN91C96_BANKSELECT (0x3UC << 0)
+#define BANK0 0x00
+#define BANK1 0x01
+#define BANK2 0x02
+#define BANK3 0x03
+#define BANK4 0x04
+
+/*
+ ****************************************************************************
+ * EEPROM Addresses.
+ ****************************************************************************
+ */
+#define EEPROM_MAC_OFFSET_1 0x6020
+#define EEPROM_MAC_OFFSET_2 0x6021
+#define EEPROM_MAC_OFFSET_3 0x6022
+
+/*
+ ****************************************************************************
+ * Bank 0 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_TCR 0 /* Transmit Control Register */
+#define LAN91C96_EPH_STATUS 2 /* EPH Status Register */
+#define LAN91C96_RCR 4 /* Receive Control Register */
+#define LAN91C96_COUNTER 6 /* Counter Register */
+#define LAN91C96_MIR 8 /* Memory Information Register */
+#define LAN91C96_MCR 10 /* Memory Configuration Register */
+
+/*
+ ****************************************************************************
+ * Transmit Control Register - Bank 0 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_TCR_TXENA (0x1U << 0)
+#define LAN91C96_TCR_LOOP (0x1U << 1)
+#define LAN91C96_TCR_FORCOL (0x1U << 2)
+#define LAN91C96_TCR_TXP_EN (0x1U << 3)
+#define LAN91C96_TCR_PAD_EN (0x1U << 7)
+#define LAN91C96_TCR_NOCRC (0x1U << 8)
+#define LAN91C96_TCR_MON_CSN (0x1U << 10)
+#define LAN91C96_TCR_FDUPLX (0x1U << 11)
+#define LAN91C96_TCR_STP_SQET (0x1U << 12)
+#define LAN91C96_TCR_EPH_LOOP (0x1U << 13)
+#define LAN91C96_TCR_ETEN_TYPE (0x1U << 14)
+#define LAN91C96_TCR_FDSE (0x1U << 15)
+
+/*
+ ****************************************************************************
+ * EPH Status Register - Bank 0 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_EPHSR_TX_SUC (0x1U << 0)
+#define LAN91C96_EPHSR_SNGL_COL (0x1U << 1)
+#define LAN91C96_EPHSR_MUL_COL (0x1U << 2)
+#define LAN91C96_EPHSR_LTX_MULT (0x1U << 3)
+#define LAN91C96_EPHSR_16COL (0x1U << 4)
+#define LAN91C96_EPHSR_SQET (0x1U << 5)
+#define LAN91C96_EPHSR_LTX_BRD (0x1U << 6)
+#define LAN91C96_EPHSR_TX_DEFR (0x1U << 7)
+#define LAN91C96_EPHSR_WAKEUP (0x1U << 8)
+#define LAN91C96_EPHSR_LATCOL (0x1U << 9)
+#define LAN91C96_EPHSR_LOST_CARR (0x1U << 10)
+#define LAN91C96_EPHSR_EXC_DEF (0x1U << 11)
+#define LAN91C96_EPHSR_CTR_ROL (0x1U << 12)
+
+#define LAN91C96_EPHSR_LINK_OK (0x1U << 14)
+#define LAN91C96_EPHSR_TX_UNRN (0x1U << 15)
+
+#define LAN91C96_EPHSR_ERRORS (LAN91C96_EPHSR_SNGL_COL | \
+ LAN91C96_EPHSR_MUL_COL | \
+ LAN91C96_EPHSR_16COL | \
+ LAN91C96_EPHSR_SQET | \
+ LAN91C96_EPHSR_TX_DEFR | \
+ LAN91C96_EPHSR_LATCOL | \
+ LAN91C96_EPHSR_LOST_CARR | \
+ LAN91C96_EPHSR_EXC_DEF | \
+ LAN91C96_EPHSR_LINK_OK | \
+ LAN91C96_EPHSR_TX_UNRN)
+
+/*
+ ****************************************************************************
+ * Receive Control Register - Bank 0 - Offset 4
+ ****************************************************************************
+ */
+#define LAN91C96_RCR_RX_ABORT (0x1U << 0)
+#define LAN91C96_RCR_PRMS (0x1U << 1)
+#define LAN91C96_RCR_ALMUL (0x1U << 2)
+#define LAN91C96_RCR_RXEN (0x1U << 8)
+#define LAN91C96_RCR_STRIP_CRC (0x1U << 9)
+#define LAN91C96_RCR_FILT_CAR (0x1U << 14)
+#define LAN91C96_RCR_SOFT_RST (0x1U << 15)
+
+/*
+ ****************************************************************************
+ * Counter Register - Bank 0 - Offset 6
+ ****************************************************************************
+ */
+#define LAN91C96_ECR_SNGL_COL (0xFU << 0)
+#define LAN91C96_ECR_MULT_COL (0xFU << 5)
+#define LAN91C96_ECR_DEF_TX (0xFU << 8)
+#define LAN91C96_ECR_EXC_DEF_TX (0xFU << 12)
+
+/*
+ ****************************************************************************
+ * Memory Information Register - Bank 0 - OFfset 8
+ ****************************************************************************
+ */
+#define LAN91C96_MIR_SIZE (0x18 << 0) /* 6144 bytes */
+
+/*
+ ****************************************************************************
+ * Memory Configuration Register - Bank 0 - Offset 10
+ ****************************************************************************
+ */
+#define LAN91C96_MCR_MEM_RES (0xFFU << 0)
+#define LAN91C96_MCR_MEM_MULT (0x3U << 9)
+#define LAN91C96_MCR_HIGH_ID (0x3U << 12)
+
+#define LAN91C96_MCR_TRANSMIT_PAGES 0x6
+
+/*
+ ****************************************************************************
+ * Bank 1 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_CONFIG 0 /* Configuration Register */
+#define LAN91C96_BASE 2 /* Base Address Register */
+#define LAN91C96_IA0 4 /* Individual Address Register - 0 */
+#define LAN91C96_IA1 5 /* Individual Address Register - 1 */
+#define LAN91C96_IA2 6 /* Individual Address Register - 2 */
+#define LAN91C96_IA3 7 /* Individual Address Register - 3 */
+#define LAN91C96_IA4 8 /* Individual Address Register - 4 */
+#define LAN91C96_IA5 9 /* Individual Address Register - 5 */
+#define LAN91C96_GEN_PURPOSE 10 /* General Address Registers */
+#define LAN91C96_CONTROL 12 /* Control Register */
+
+/*
+ ****************************************************************************
+ * Configuration Register - Bank 1 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_CR_INT_SEL0 (0x1U << 1)
+#define LAN91C96_CR_INT_SEL1 (0x1U << 2)
+#define LAN91C96_CR_RES (0x3U << 3)
+#define LAN91C96_CR_DIS_LINK (0x1U << 6)
+#define LAN91C96_CR_16BIT (0x1U << 7)
+#define LAN91C96_CR_AUI_SELECT (0x1U << 8)
+#define LAN91C96_CR_SET_SQLCH (0x1U << 9)
+#define LAN91C96_CR_FULL_STEP (0x1U << 10)
+#define LAN91C96_CR_NO_WAIT (0x1U << 12)
+
+/*
+ ****************************************************************************
+ * Base Address Register - Bank 1 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_BAR_RA_BITS (0x27U << 0)
+#define LAN91C96_BAR_ROM_SIZE (0x1U << 6)
+#define LAN91C96_BAR_A_BITS (0xFFU << 8)
+
+/*
+ ****************************************************************************
+ * Control Register - Bank 1 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_CTR_STORE (0x1U << 0)
+#define LAN91C96_CTR_RELOAD (0x1U << 1)
+#define LAN91C96_CTR_EEPROM (0x1U << 2)
+#define LAN91C96_CTR_TE_ENABLE (0x1U << 5)
+#define LAN91C96_CTR_CR_ENABLE (0x1U << 6)
+#define LAN91C96_CTR_LE_ENABLE (0x1U << 7)
+#define LAN91C96_CTR_BIT_8 (0x1U << 8)
+#define LAN91C96_CTR_AUTO_RELEASE (0x1U << 11)
+#define LAN91C96_CTR_WAKEUP_EN (0x1U << 12)
+#define LAN91C96_CTR_PWRDN (0x1U << 13)
+#define LAN91C96_CTR_RCV_BAD (0x1U << 14)
+
+/*
+ ****************************************************************************
+ * Bank 2 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_MMU 0 /* MMU Command Register */
+#define LAN91C96_AUTO_TX_START 1 /* Auto Tx Start Register */
+#define LAN91C96_PNR 2 /* Packet Number Register */
+#define LAN91C96_ARR 3 /* Allocation Result Register */
+#define LAN91C96_FIFO 4 /* FIFO Ports Register */
+#define LAN91C96_POINTER 6 /* Pointer Register */
+#define LAN91C96_DATA_HIGH 8 /* Data High Register */
+#define LAN91C96_DATA_LOW 10 /* Data Low Register */
+#define LAN91C96_INT_STATS 12 /* Interrupt Status Register - RO */
+#define LAN91C96_INT_ACK 12 /* Interrupt Acknowledge Register -WO */
+#define LAN91C96_INT_MASK 13 /* Interrupt Mask Register */
+
+/*
+ ****************************************************************************
+ * MMU Command Register - Bank 2 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_MMUCR_NO_BUSY (0x1U << 0)
+#define LAN91C96_MMUCR_N1 (0x1U << 1)
+#define LAN91C96_MMUCR_N2 (0x1U << 2)
+#define LAN91C96_MMUCR_COMMAND (0xFU << 4)
+#define LAN91C96_MMUCR_ALLOC_TX (0x2U << 4) /* WXYZ = 0010 */
+#define LAN91C96_MMUCR_RESET_MMU (0x4U << 4) /* WXYZ = 0100 */
+#define LAN91C96_MMUCR_REMOVE_RX (0x6U << 4) /* WXYZ = 0110 */
+#define LAN91C96_MMUCR_REMOVE_TX (0x7U << 4) /* WXYZ = 0111 */
+#define LAN91C96_MMUCR_RELEASE_RX (0x8U << 4) /* WXYZ = 1000 */
+#define LAN91C96_MMUCR_RELEASE_TX (0xAU << 4) /* WXYZ = 1010 */
+#define LAN91C96_MMUCR_ENQUEUE (0xCU << 4) /* WXYZ = 1100 */
+#define LAN91C96_MMUCR_RESET_TX (0xEU << 4) /* WXYZ = 1110 */
+
+/*
+ ****************************************************************************
+ * Auto Tx Start Register - Bank 2 - Offset 1
+ ****************************************************************************
+ */
+#define LAN91C96_AUTOTX (0xFFU << 0)
+
+/*
+ ****************************************************************************
+ * Packet Number Register - Bank 2 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_PNR_TX (0x1FU << 0)
+
+/*
+ ****************************************************************************
+ * Allocation Result Register - Bank 2 - Offset 3
+ ****************************************************************************
+ */
+#define LAN91C96_ARR_ALLOC_PN (0x7FU << 0)
+#define LAN91C96_ARR_FAILED (0x1U << 7)
+
+/*
+ ****************************************************************************
+ * FIFO Ports Register - Bank 2 - Offset 4
+ ****************************************************************************
+ */
+#define LAN91C96_FIFO_TX_DONE_PN (0x1FU << 0)
+#define LAN91C96_FIFO_TEMPTY (0x1U << 7)
+#define LAN91C96_FIFO_RX_DONE_PN (0x1FU << 8)
+#define LAN91C96_FIFO_RXEMPTY (0x1U << 15)
+
+/*
+ ****************************************************************************
+ * Pointer Register - Bank 2 - Offset 6
+ ****************************************************************************
+ */
+#define LAN91C96_PTR_LOW (0xFFU << 0)
+#define LAN91C96_PTR_HIGH (0x7U << 8)
+#define LAN91C96_PTR_AUTO_TX (0x1U << 11)
+#define LAN91C96_PTR_ETEN (0x1U << 12)
+#define LAN91C96_PTR_READ (0x1U << 13)
+#define LAN91C96_PTR_AUTO_INCR (0x1U << 14)
+#define LAN91C96_PTR_RCV (0x1U << 15)
+
+#define LAN91C96_PTR_RX_FRAME (LAN91C96_PTR_RCV | \
+ LAN91C96_PTR_AUTO_INCR | \
+ LAN91C96_PTR_READ)
+
+/*
+ ****************************************************************************
+ * Data Register - Bank 2 - Offset 8
+ ****************************************************************************
+ */
+#define LAN91C96_CONTROL_CRC (0x1U << 4) /* CRC bit */
+#define LAN91C96_CONTROL_ODD (0x1U << 5) /* ODD bit */
+
+/*
+ ****************************************************************************
+ * Interrupt Status Register - Bank 2 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_IST_RCV_INT (0x1U << 0)
+#define LAN91C96_IST_TX_INT (0x1U << 1)
+#define LAN91C96_IST_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_IST_ALLOC_INT (0x1U << 3)
+#define LAN91C96_IST_RX_OVRN_INT (0x1U << 4)
+#define LAN91C96_IST_EPH_INT (0x1U << 5)
+#define LAN91C96_IST_ERCV_INT (0x1U << 6)
+#define LAN91C96_IST_RX_IDLE_INT (0x1U << 7)
+
+/*
+ ****************************************************************************
+ * Interrupt Acknowledge Register - Bank 2 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_ACK_TX_INT (0x1U << 1)
+#define LAN91C96_ACK_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_ACK_RX_OVRN_INT (0x1U << 4)
+#define LAN91C96_ACK_ERCV_INT (0x1U << 6)
+
+/*
+ ****************************************************************************
+ * Interrupt Mask Register - Bank 2 - Offset 13
+ ****************************************************************************
+ */
+#define LAN91C96_MSK_RCV_INT (0x1U << 0)
+#define LAN91C96_MSK_TX_INT (0x1U << 1)
+#define LAN91C96_MSK_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_MSK_ALLOC_INT (0x1U << 3)
+#define LAN91C96_MSK_RX_OVRN_INT (0x1U << 4)
+#define LAN91C96_MSK_EPH_INT (0x1U << 5)
+#define LAN91C96_MSK_ERCV_INT (0x1U << 6)
+#define LAN91C96_MSK_TX_IDLE_INT (0x1U << 7)
+
+/*
+ ****************************************************************************
+ * Bank 3 Register Map in I/O Space
+ **************************************************************************
+ */
+#define LAN91C96_MGMT_MDO (0x1U << 0)
+#define LAN91C96_MGMT_MDI (0x1U << 1)
+#define LAN91C96_MGMT_MCLK (0x1U << 2)
+#define LAN91C96_MGMT_MDOE (0x1U << 3)
+#define LAN91C96_MGMT_LOW_ID (0x3U << 4)
+#define LAN91C96_MGMT_IOS0 (0x1U << 8)
+#define LAN91C96_MGMT_IOS1 (0x1U << 9)
+#define LAN91C96_MGMT_IOS2 (0x1U << 10)
+#define LAN91C96_MGMT_nXNDEC (0x1U << 11)
+#define LAN91C96_MGMT_HIGH_ID (0x3U << 12)
+
+/*
+ ****************************************************************************
+ * Revision Register - Bank 3 - Offset 10
+ ****************************************************************************
+ */
+#define LAN91C96_REV_REVID (0xFU << 0)
+#define LAN91C96_REV_CHIPID (0xFU << 4)
+
+/*
+ ****************************************************************************
+ * Early RCV Register - Bank 3 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_ERCV_THRESHOLD (0x1FU << 0)
+#define LAN91C96_ERCV_RCV_DISCRD (0x1U << 7)
+
+/*
+ ****************************************************************************
+ * PCMCIA Configuration Registers
+ ****************************************************************************
+ */
+#define LAN91C96_ECOR 0x8000 /* Ethernet Configuration Register */
+#define LAN91C96_ECSR 0x8002 /* Ethernet Configuration and Status */
+
+/*
+ ****************************************************************************
+ * PCMCIA Ethernet Configuration Option Register (ECOR)
+ ****************************************************************************
+ */
+#define LAN91C96_ECOR_ENABLE (0x1U << 0)
+#define LAN91C96_ECOR_WR_ATTRIB (0x1U << 2)
+#define LAN91C96_ECOR_LEVEL_REQ (0x1U << 6)
+#define LAN91C96_ECOR_SRESET (0x1U << 7)
+
+/*
+ ****************************************************************************
+ * PCMCIA Ethernet Configuration and Status Register (ECSR)
+ ****************************************************************************
+ */
+#define LAN91C96_ECSR_INTR (0x1U << 1)
+#define LAN91C96_ECSR_PWRDWN (0x1U << 2)
+#define LAN91C96_ECSR_IOIS8 (0x1U << 5)
+
+/*
+ ****************************************************************************
+ * Receive Frame Status Word - See page 38 of the LAN91C96 specification.
+ ****************************************************************************
+ */
+#define LAN91C96_TOO_SHORT (0x1U << 10)
+#define LAN91C96_TOO_LONG (0x1U << 11)
+#define LAN91C96_ODD_FRM (0x1U << 12)
+#define LAN91C96_BAD_CRC (0x1U << 13)
+#define LAN91C96_BROD_CAST (0x1U << 14)
+#define LAN91C96_ALGN_ERR (0x1U << 15)
+
+#define FRAME_FILTER (LAN91C96_TOO_SHORT | LAN91C96_TOO_LONG | LAN91C96_BAD_CRC | LAN91C96_ALGN_ERR)
+
+/*
+ ****************************************************************************
+ * Default MAC Address
+ ****************************************************************************
+ */
+#define MAC_DEF_HI 0x0800
+#define MAC_DEF_MED 0x3333
+#define MAC_DEF_LO 0x0100
+
+/*
+ ****************************************************************************
+ * Default I/O Signature - 0x33
+ ****************************************************************************
+ */
+#define LAN91C96_LOW_SIGNATURE (0x33U << 0)
+#define LAN91C96_HIGH_SIGNATURE (0x33U << 8)
+#define LAN91C96_SIGNATURE (LAN91C96_HIGH_SIGNATURE | LAN91C96_LOW_SIGNATURE)
+
+#define LAN91C96_MAX_PAGES 6 /* Maximum number of 256 pages. */
+#define ETHERNET_MAX_LENGTH 1514
+
+
+/*-------------------------------------------------------------------------
+ * I define some macros to make it easier to do somewhat common
+ * or slightly complicated, repeated tasks.
+ *-------------------------------------------------------------------------
+ */
+
+/* select a register bank, 0 to 3 */
+
+#define SMC_SELECT_BANK(edev, x) { SMC_outw(edev, x, LAN91C96_BANK_SELECT); }
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(edev, x) {\
+ unsigned char mask;\
+ SMC_SELECT_BANK(edev, 2);\
+ mask = SMC_inb(edev, LAN91C96_INT_MASK);\
+ mask |= (x);\
+ SMC_outb(edev, mask, LAN91C96_INT_MASK); \
+}
+
+/* this disables an interrupt from the interrupt mask register */
+
+#define SMC_DISABLE_INT(edev, x) {\
+ unsigned char mask;\
+ SMC_SELECT_BANK(edev, 2);\
+ mask = SMC_inb(edev, LAN91C96_INT_MASK);\
+ mask &= ~(x);\
+ SMC_outb(edev, mask, LAN91C96_INT_MASK); \
+}
+
+/*----------------------------------------------------------------------
+ * Define the interrupts that I want to receive from the card
+ *
+ * I want:
+ * LAN91C96_IST_EPH_INT, for nasty errors
+ * LAN91C96_IST_RCV_INT, for happy received packets
+ * LAN91C96_IST_RX_OVRN_INT, because I have to kick the receiver
+ *-------------------------------------------------------------------------
+ */
+#define SMC_INTERRUPT_MASK (LAN91C96_IST_EPH_INT | LAN91C96_IST_RX_OVRN_INT | LAN91C96_IST_RCV_INT)
+
+#endif /* _LAN91C96_H_ */
diff --git a/qemu/roms/u-boot/drivers/net/macb.c b/qemu/roms/u-boot/drivers/net/macb.c
new file mode 100644
index 000000000..781a272cf
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/macb.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+
+/*
+ * The u-boot networking stack is a little weird. It seems like the
+ * networking core allocates receive buffers up front without any
+ * regard to the hardware that's supposed to actually receive those
+ * packets.
+ *
+ * The MACB receives packets into 128-byte receive buffers, so the
+ * buffers allocated by the core isn't very practical to use. We'll
+ * allocate our own, but we need one such buffer in case a packet
+ * wraps around the DMA ring so that we have to copy it.
+ *
+ * Therefore, define CONFIG_SYS_RX_ETH_BUFFER to 1 in the board-specific
+ * configuration header. This way, the core allocates one RX buffer
+ * and one TX buffer, each of which can hold a ethernet packet of
+ * maximum size.
+ *
+ * For some reason, the networking core unconditionally specifies a
+ * 32-byte packet "alignment" (which really should be called
+ * "padding"). MACB shouldn't need that, but we'll refrain from any
+ * core modifications here...
+ */
+
+#include <net.h>
+#include <netdev.h>
+#include <malloc.h>
+#include <miiphy.h>
+
+#include <linux/mii.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+#include <asm/arch/clk.h>
+#include <asm-generic/errno.h>
+
+#include "macb.h"
+
+#define CONFIG_SYS_MACB_RX_BUFFER_SIZE 4096
+#define CONFIG_SYS_MACB_RX_RING_SIZE (CONFIG_SYS_MACB_RX_BUFFER_SIZE / 128)
+#define CONFIG_SYS_MACB_TX_RING_SIZE 16
+#define CONFIG_SYS_MACB_TX_TIMEOUT 1000
+#define CONFIG_SYS_MACB_AUTONEG_TIMEOUT 5000000
+
+struct macb_dma_desc {
+ u32 addr;
+ u32 ctrl;
+};
+
+#define RXADDR_USED 0x00000001
+#define RXADDR_WRAP 0x00000002
+
+#define RXBUF_FRMLEN_MASK 0x00000fff
+#define RXBUF_FRAME_START 0x00004000
+#define RXBUF_FRAME_END 0x00008000
+#define RXBUF_TYPEID_MATCH 0x00400000
+#define RXBUF_ADDR4_MATCH 0x00800000
+#define RXBUF_ADDR3_MATCH 0x01000000
+#define RXBUF_ADDR2_MATCH 0x02000000
+#define RXBUF_ADDR1_MATCH 0x04000000
+#define RXBUF_BROADCAST 0x80000000
+
+#define TXBUF_FRMLEN_MASK 0x000007ff
+#define TXBUF_FRAME_END 0x00008000
+#define TXBUF_NOCRC 0x00010000
+#define TXBUF_EXHAUSTED 0x08000000
+#define TXBUF_UNDERRUN 0x10000000
+#define TXBUF_MAXRETRY 0x20000000
+#define TXBUF_WRAP 0x40000000
+#define TXBUF_USED 0x80000000
+
+struct macb_device {
+ void *regs;
+
+ unsigned int rx_tail;
+ unsigned int tx_head;
+ unsigned int tx_tail;
+
+ void *rx_buffer;
+ void *tx_buffer;
+ struct macb_dma_desc *rx_ring;
+ struct macb_dma_desc *tx_ring;
+
+ unsigned long rx_buffer_dma;
+ unsigned long rx_ring_dma;
+ unsigned long tx_ring_dma;
+
+ const struct device *dev;
+ struct eth_device netdev;
+ unsigned short phy_addr;
+ struct mii_dev *bus;
+};
+#define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
+
+static int macb_is_gem(struct macb_device *macb)
+{
+ return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2;
+}
+
+static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
+{
+ unsigned long netctl;
+ unsigned long netstat;
+ unsigned long frame;
+
+ netctl = macb_readl(macb, NCR);
+ netctl |= MACB_BIT(MPE);
+ macb_writel(macb, NCR, netctl);
+
+ frame = (MACB_BF(SOF, 1)
+ | MACB_BF(RW, 1)
+ | MACB_BF(PHYA, macb->phy_addr)
+ | MACB_BF(REGA, reg)
+ | MACB_BF(CODE, 2)
+ | MACB_BF(DATA, value));
+ macb_writel(macb, MAN, frame);
+
+ do {
+ netstat = macb_readl(macb, NSR);
+ } while (!(netstat & MACB_BIT(IDLE)));
+
+ netctl = macb_readl(macb, NCR);
+ netctl &= ~MACB_BIT(MPE);
+ macb_writel(macb, NCR, netctl);
+}
+
+static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
+{
+ unsigned long netctl;
+ unsigned long netstat;
+ unsigned long frame;
+
+ netctl = macb_readl(macb, NCR);
+ netctl |= MACB_BIT(MPE);
+ macb_writel(macb, NCR, netctl);
+
+ frame = (MACB_BF(SOF, 1)
+ | MACB_BF(RW, 2)
+ | MACB_BF(PHYA, macb->phy_addr)
+ | MACB_BF(REGA, reg)
+ | MACB_BF(CODE, 2));
+ macb_writel(macb, MAN, frame);
+
+ do {
+ netstat = macb_readl(macb, NSR);
+ } while (!(netstat & MACB_BIT(IDLE)));
+
+ frame = macb_readl(macb, MAN);
+
+ netctl = macb_readl(macb, NCR);
+ netctl &= ~MACB_BIT(MPE);
+ macb_writel(macb, NCR, netctl);
+
+ return MACB_BFEXT(DATA, frame);
+}
+
+void __weak arch_get_mdio_control(const char *name)
+{
+ return;
+}
+
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
+
+int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct macb_device *macb = to_macb(dev);
+
+ if ( macb->phy_addr != phy_adr )
+ return -1;
+
+ arch_get_mdio_control(devname);
+ *value = macb_mdio_read(macb, reg);
+
+ return 0;
+}
+
+int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct macb_device *macb = to_macb(dev);
+
+ if ( macb->phy_addr != phy_adr )
+ return -1;
+
+ arch_get_mdio_control(devname);
+ macb_mdio_write(macb, reg, value);
+
+ return 0;
+}
+#endif
+
+
+#if defined(CONFIG_CMD_NET)
+
+static int macb_send(struct eth_device *netdev, void *packet, int length)
+{
+ struct macb_device *macb = to_macb(netdev);
+ unsigned long paddr, ctrl;
+ unsigned int tx_head = macb->tx_head;
+ int i;
+
+ paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
+
+ ctrl = length & TXBUF_FRMLEN_MASK;
+ ctrl |= TXBUF_FRAME_END;
+ if (tx_head == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) {
+ ctrl |= TXBUF_WRAP;
+ macb->tx_head = 0;
+ } else
+ macb->tx_head++;
+
+ macb->tx_ring[tx_head].ctrl = ctrl;
+ macb->tx_ring[tx_head].addr = paddr;
+ barrier();
+ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
+
+ /*
+ * I guess this is necessary because the networking core may
+ * re-use the transmit buffer as soon as we return...
+ */
+ for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) {
+ barrier();
+ ctrl = macb->tx_ring[tx_head].ctrl;
+ if (ctrl & TXBUF_USED)
+ break;
+ udelay(1);
+ }
+
+ dma_unmap_single(packet, length, paddr);
+
+ if (i <= CONFIG_SYS_MACB_TX_TIMEOUT) {
+ if (ctrl & TXBUF_UNDERRUN)
+ printf("%s: TX underrun\n", netdev->name);
+ if (ctrl & TXBUF_EXHAUSTED)
+ printf("%s: TX buffers exhausted in mid frame\n",
+ netdev->name);
+ } else {
+ printf("%s: TX timeout\n", netdev->name);
+ }
+
+ /* No one cares anyway */
+ return 0;
+}
+
+static void reclaim_rx_buffers(struct macb_device *macb,
+ unsigned int new_tail)
+{
+ unsigned int i;
+
+ i = macb->rx_tail;
+ while (i > new_tail) {
+ macb->rx_ring[i].addr &= ~RXADDR_USED;
+ i++;
+ if (i > CONFIG_SYS_MACB_RX_RING_SIZE)
+ i = 0;
+ }
+
+ while (i < new_tail) {
+ macb->rx_ring[i].addr &= ~RXADDR_USED;
+ i++;
+ }
+
+ barrier();
+ macb->rx_tail = new_tail;
+}
+
+static int macb_recv(struct eth_device *netdev)
+{
+ struct macb_device *macb = to_macb(netdev);
+ unsigned int rx_tail = macb->rx_tail;
+ void *buffer;
+ int length;
+ int wrapped = 0;
+ u32 status;
+
+ for (;;) {
+ if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED))
+ return -1;
+
+ status = macb->rx_ring[rx_tail].ctrl;
+ if (status & RXBUF_FRAME_START) {
+ if (rx_tail != macb->rx_tail)
+ reclaim_rx_buffers(macb, rx_tail);
+ wrapped = 0;
+ }
+
+ if (status & RXBUF_FRAME_END) {
+ buffer = macb->rx_buffer + 128 * macb->rx_tail;
+ length = status & RXBUF_FRMLEN_MASK;
+ if (wrapped) {
+ unsigned int headlen, taillen;
+
+ headlen = 128 * (CONFIG_SYS_MACB_RX_RING_SIZE
+ - macb->rx_tail);
+ taillen = length - headlen;
+ memcpy((void *)NetRxPackets[0],
+ buffer, headlen);
+ memcpy((void *)NetRxPackets[0] + headlen,
+ macb->rx_buffer, taillen);
+ buffer = (void *)NetRxPackets[0];
+ }
+
+ NetReceive(buffer, length);
+ if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE)
+ rx_tail = 0;
+ reclaim_rx_buffers(macb, rx_tail);
+ } else {
+ if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) {
+ wrapped = 1;
+ rx_tail = 0;
+ }
+ }
+ barrier();
+ }
+
+ return 0;
+}
+
+static void macb_phy_reset(struct macb_device *macb)
+{
+ struct eth_device *netdev = &macb->netdev;
+ int i;
+ u16 status, adv;
+
+ adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+ macb_mdio_write(macb, MII_ADVERTISE, adv);
+ printf("%s: Starting autonegotiation...\n", netdev->name);
+ macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
+ | BMCR_ANRESTART));
+
+ for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) {
+ status = macb_mdio_read(macb, MII_BMSR);
+ if (status & BMSR_ANEGCOMPLETE)
+ break;
+ udelay(100);
+ }
+
+ if (status & BMSR_ANEGCOMPLETE)
+ printf("%s: Autonegotiation complete\n", netdev->name);
+ else
+ printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+ netdev->name, status);
+}
+
+#ifdef CONFIG_MACB_SEARCH_PHY
+static int macb_phy_find(struct macb_device *macb)
+{
+ int i;
+ u16 phy_id;
+
+ /* Search for PHY... */
+ for (i = 0; i < 32; i++) {
+ macb->phy_addr = i;
+ phy_id = macb_mdio_read(macb, MII_PHYSID1);
+ if (phy_id != 0xffff) {
+ printf("%s: PHY present at %d\n", macb->netdev.name, i);
+ return 1;
+ }
+ }
+
+ /* PHY isn't up to snuff */
+ printf("%s: PHY not found\n", macb->netdev.name);
+
+ return 0;
+}
+#endif /* CONFIG_MACB_SEARCH_PHY */
+
+
+static int macb_phy_init(struct macb_device *macb)
+{
+ struct eth_device *netdev = &macb->netdev;
+#ifdef CONFIG_PHYLIB
+ struct phy_device *phydev;
+#endif
+ u32 ncfgr;
+ u16 phy_id, status, adv, lpa;
+ int media, speed, duplex;
+ int i;
+
+ arch_get_mdio_control(netdev->name);
+#ifdef CONFIG_MACB_SEARCH_PHY
+ /* Auto-detect phy_addr */
+ if (!macb_phy_find(macb)) {
+ return 0;
+ }
+#endif /* CONFIG_MACB_SEARCH_PHY */
+
+ /* Check if the PHY is up to snuff... */
+ phy_id = macb_mdio_read(macb, MII_PHYSID1);
+ if (phy_id == 0xffff) {
+ printf("%s: No PHY present\n", netdev->name);
+ return 0;
+ }
+
+#ifdef CONFIG_PHYLIB
+ /* need to consider other phy interface mode */
+ phydev = phy_connect(macb->bus, macb->phy_addr, netdev,
+ PHY_INTERFACE_MODE_RGMII);
+ if (!phydev) {
+ printf("phy_connect failed\n");
+ return -ENODEV;
+ }
+
+ phy_config(phydev);
+#endif
+
+ status = macb_mdio_read(macb, MII_BMSR);
+ if (!(status & BMSR_LSTATUS)) {
+ /* Try to re-negotiate if we don't have link already. */
+ macb_phy_reset(macb);
+
+ for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) {
+ status = macb_mdio_read(macb, MII_BMSR);
+ if (status & BMSR_LSTATUS)
+ break;
+ udelay(100);
+ }
+ }
+
+ if (!(status & BMSR_LSTATUS)) {
+ printf("%s: link down (status: 0x%04x)\n",
+ netdev->name, status);
+ return 0;
+ }
+
+ /* First check for GMAC */
+ if (macb_is_gem(macb)) {
+ lpa = macb_mdio_read(macb, MII_STAT1000);
+ if (lpa & (1 << 11)) {
+ speed = 1000;
+ duplex = 1;
+ } else {
+ if (lpa & (1 << 10)) {
+ speed = 1000;
+ duplex = 1;
+ } else {
+ speed = 0;
+ }
+ }
+
+ if (speed == 1000) {
+ printf("%s: link up, %dMbps %s-duplex (lpa: 0x%04x)\n",
+ netdev->name,
+ speed,
+ duplex ? "full" : "half",
+ lpa);
+
+ ncfgr = macb_readl(macb, NCFGR);
+ ncfgr &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD));
+ if (speed)
+ ncfgr |= GEM_BIT(GBE);
+ if (duplex)
+ ncfgr |= MACB_BIT(FD);
+ macb_writel(macb, NCFGR, ncfgr);
+
+ return 1;
+ }
+ }
+
+ /* fall back for EMAC checking */
+ adv = macb_mdio_read(macb, MII_ADVERTISE);
+ lpa = macb_mdio_read(macb, MII_LPA);
+ media = mii_nway_result(lpa & adv);
+ speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+ ? 1 : 0);
+ duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+ printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
+ netdev->name,
+ speed ? "100" : "10",
+ duplex ? "full" : "half",
+ lpa);
+
+ ncfgr = macb_readl(macb, NCFGR);
+ ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
+ if (speed)
+ ncfgr |= MACB_BIT(SPD);
+ if (duplex)
+ ncfgr |= MACB_BIT(FD);
+ macb_writel(macb, NCFGR, ncfgr);
+
+ return 1;
+}
+
+static int macb_init(struct eth_device *netdev, bd_t *bd)
+{
+ struct macb_device *macb = to_macb(netdev);
+ unsigned long paddr;
+ int i;
+
+ /*
+ * macb_halt should have been called at some point before now,
+ * so we'll assume the controller is idle.
+ */
+
+ /* initialize DMA descriptors */
+ paddr = macb->rx_buffer_dma;
+ for (i = 0; i < CONFIG_SYS_MACB_RX_RING_SIZE; i++) {
+ if (i == (CONFIG_SYS_MACB_RX_RING_SIZE - 1))
+ paddr |= RXADDR_WRAP;
+ macb->rx_ring[i].addr = paddr;
+ macb->rx_ring[i].ctrl = 0;
+ paddr += 128;
+ }
+ for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) {
+ macb->tx_ring[i].addr = 0;
+ if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1))
+ macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
+ else
+ macb->tx_ring[i].ctrl = TXBUF_USED;
+ }
+ macb->rx_tail = macb->tx_head = macb->tx_tail = 0;
+
+ macb_writel(macb, RBQP, macb->rx_ring_dma);
+ macb_writel(macb, TBQP, macb->tx_ring_dma);
+
+ if (macb_is_gem(macb)) {
+#ifdef CONFIG_RGMII
+ gem_writel(macb, UR, GEM_BIT(RGMII));
+#else
+ gem_writel(macb, UR, 0);
+#endif
+ } else {
+ /* choose RMII or MII mode. This depends on the board */
+#ifdef CONFIG_RMII
+#ifdef CONFIG_AT91FAMILY
+ macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN));
+#else
+ macb_writel(macb, USRIO, 0);
+#endif
+#else
+#ifdef CONFIG_AT91FAMILY
+ macb_writel(macb, USRIO, MACB_BIT(CLKEN));
+#else
+ macb_writel(macb, USRIO, MACB_BIT(MII));
+#endif
+#endif /* CONFIG_RMII */
+ }
+
+ if (!macb_phy_init(macb))
+ return -1;
+
+ /* Enable TX and RX */
+ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE));
+
+ return 0;
+}
+
+static void macb_halt(struct eth_device *netdev)
+{
+ struct macb_device *macb = to_macb(netdev);
+ u32 ncr, tsr;
+
+ /* Halt the controller and wait for any ongoing transmission to end. */
+ ncr = macb_readl(macb, NCR);
+ ncr |= MACB_BIT(THALT);
+ macb_writel(macb, NCR, ncr);
+
+ do {
+ tsr = macb_readl(macb, TSR);
+ } while (tsr & MACB_BIT(TGO));
+
+ /* Disable TX and RX, and clear statistics */
+ macb_writel(macb, NCR, MACB_BIT(CLRSTAT));
+}
+
+static int macb_write_hwaddr(struct eth_device *dev)
+{
+ struct macb_device *macb = to_macb(dev);
+ u32 hwaddr_bottom;
+ u16 hwaddr_top;
+
+ /* set hardware address */
+ hwaddr_bottom = dev->enetaddr[0] | dev->enetaddr[1] << 8 |
+ dev->enetaddr[2] << 16 | dev->enetaddr[3] << 24;
+ macb_writel(macb, SA1B, hwaddr_bottom);
+ hwaddr_top = dev->enetaddr[4] | dev->enetaddr[5] << 8;
+ macb_writel(macb, SA1T, hwaddr_top);
+ return 0;
+}
+
+static u32 macb_mdc_clk_div(int id, struct macb_device *macb)
+{
+ u32 config;
+ unsigned long macb_hz = get_macb_pclk_rate(id);
+
+ if (macb_hz < 20000000)
+ config = MACB_BF(CLK, MACB_CLK_DIV8);
+ else if (macb_hz < 40000000)
+ config = MACB_BF(CLK, MACB_CLK_DIV16);
+ else if (macb_hz < 80000000)
+ config = MACB_BF(CLK, MACB_CLK_DIV32);
+ else
+ config = MACB_BF(CLK, MACB_CLK_DIV64);
+
+ return config;
+}
+
+static u32 gem_mdc_clk_div(int id, struct macb_device *macb)
+{
+ u32 config;
+ unsigned long macb_hz = get_macb_pclk_rate(id);
+
+ if (macb_hz < 20000000)
+ config = GEM_BF(CLK, GEM_CLK_DIV8);
+ else if (macb_hz < 40000000)
+ config = GEM_BF(CLK, GEM_CLK_DIV16);
+ else if (macb_hz < 80000000)
+ config = GEM_BF(CLK, GEM_CLK_DIV32);
+ else if (macb_hz < 120000000)
+ config = GEM_BF(CLK, GEM_CLK_DIV48);
+ else if (macb_hz < 160000000)
+ config = GEM_BF(CLK, GEM_CLK_DIV64);
+ else
+ config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+ return config;
+}
+
+/*
+ * Get the DMA bus width field of the network configuration register that we
+ * should program. We find the width from decoding the design configuration
+ * register to find the maximum supported data bus width.
+ */
+static u32 macb_dbw(struct macb_device *macb)
+{
+ switch (GEM_BFEXT(DBWDEF, gem_readl(macb, DCFG1))) {
+ case 4:
+ return GEM_BF(DBW, GEM_DBW128);
+ case 2:
+ return GEM_BF(DBW, GEM_DBW64);
+ case 1:
+ default:
+ return GEM_BF(DBW, GEM_DBW32);
+ }
+}
+
+int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
+{
+ struct macb_device *macb;
+ struct eth_device *netdev;
+ u32 ncfgr;
+
+ macb = malloc(sizeof(struct macb_device));
+ if (!macb) {
+ printf("Error: Failed to allocate memory for MACB%d\n", id);
+ return -1;
+ }
+ memset(macb, 0, sizeof(struct macb_device));
+
+ netdev = &macb->netdev;
+
+ macb->rx_buffer = dma_alloc_coherent(CONFIG_SYS_MACB_RX_BUFFER_SIZE,
+ &macb->rx_buffer_dma);
+ macb->rx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_RX_RING_SIZE
+ * sizeof(struct macb_dma_desc),
+ &macb->rx_ring_dma);
+ macb->tx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_TX_RING_SIZE
+ * sizeof(struct macb_dma_desc),
+ &macb->tx_ring_dma);
+
+ macb->regs = regs;
+ macb->phy_addr = phy_addr;
+
+ if (macb_is_gem(macb))
+ sprintf(netdev->name, "gmac%d", id);
+ else
+ sprintf(netdev->name, "macb%d", id);
+
+ netdev->init = macb_init;
+ netdev->halt = macb_halt;
+ netdev->send = macb_send;
+ netdev->recv = macb_recv;
+ netdev->write_hwaddr = macb_write_hwaddr;
+
+ /*
+ * Do some basic initialization so that we at least can talk
+ * to the PHY
+ */
+ if (macb_is_gem(macb)) {
+ ncfgr = gem_mdc_clk_div(id, macb);
+ ncfgr |= macb_dbw(macb);
+ } else {
+ ncfgr = macb_mdc_clk_div(id, macb);
+ }
+
+ macb_writel(macb, NCFGR, ncfgr);
+
+ eth_register(netdev);
+
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
+ miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write);
+ macb->bus = miiphy_get_dev_by_name(netdev->name);
+#endif
+ return 0;
+}
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/macb.h b/qemu/roms/u-boot/drivers/net/macb.h
new file mode 100644
index 000000000..06f7c66df
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/macb.h
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef __DRIVERS_MACB_H__
+#define __DRIVERS_MACB_H__
+
+/* MACB register offsets */
+#define MACB_NCR 0x0000
+#define MACB_NCFGR 0x0004
+#define MACB_NSR 0x0008
+#define GEM_UR 0x000c
+#define MACB_TSR 0x0014
+#define MACB_RBQP 0x0018
+#define MACB_TBQP 0x001c
+#define MACB_RSR 0x0020
+#define MACB_ISR 0x0024
+#define MACB_IER 0x0028
+#define MACB_IDR 0x002c
+#define MACB_IMR 0x0030
+#define MACB_MAN 0x0034
+#define MACB_PTR 0x0038
+#define MACB_PFR 0x003c
+#define MACB_FTO 0x0040
+#define MACB_SCF 0x0044
+#define MACB_MCF 0x0048
+#define MACB_FRO 0x004c
+#define MACB_FCSE 0x0050
+#define MACB_ALE 0x0054
+#define MACB_DTF 0x0058
+#define MACB_LCOL 0x005c
+#define MACB_EXCOL 0x0060
+#define MACB_TUND 0x0064
+#define MACB_CSE 0x0068
+#define MACB_RRE 0x006c
+#define MACB_ROVR 0x0070
+#define MACB_RSE 0x0074
+#define MACB_ELE 0x0078
+#define MACB_RJA 0x007c
+#define MACB_USF 0x0080
+#define MACB_STE 0x0084
+#define MACB_RLE 0x0088
+#define MACB_TPF 0x008c
+#define MACB_HRB 0x0090
+#define MACB_HRT 0x0094
+#define MACB_SA1B 0x0098
+#define MACB_SA1T 0x009c
+#define MACB_SA2B 0x00a0
+#define MACB_SA2T 0x00a4
+#define MACB_SA3B 0x00a8
+#define MACB_SA3T 0x00ac
+#define MACB_SA4B 0x00b0
+#define MACB_SA4T 0x00b4
+#define MACB_TID 0x00b8
+#define MACB_TPQ 0x00bc
+#define MACB_USRIO 0x00c0
+#define MACB_WOL 0x00c4
+#define MACB_MID 0x00fc
+
+/* GEM specific register offsets */
+#define GEM_DCFG1 0x0280
+
+/* Bitfields in NCR */
+#define MACB_LB_OFFSET 0
+#define MACB_LB_SIZE 1
+#define MACB_LLB_OFFSET 1
+#define MACB_LLB_SIZE 1
+#define MACB_RE_OFFSET 2
+#define MACB_RE_SIZE 1
+#define MACB_TE_OFFSET 3
+#define MACB_TE_SIZE 1
+#define MACB_MPE_OFFSET 4
+#define MACB_MPE_SIZE 1
+#define MACB_CLRSTAT_OFFSET 5
+#define MACB_CLRSTAT_SIZE 1
+#define MACB_INCSTAT_OFFSET 6
+#define MACB_INCSTAT_SIZE 1
+#define MACB_WESTAT_OFFSET 7
+#define MACB_WESTAT_SIZE 1
+#define MACB_BP_OFFSET 8
+#define MACB_BP_SIZE 1
+#define MACB_TSTART_OFFSET 9
+#define MACB_TSTART_SIZE 1
+#define MACB_THALT_OFFSET 10
+#define MACB_THALT_SIZE 1
+#define MACB_NCR_TPF_OFFSET 11
+#define MACB_NCR_TPF_SIZE 1
+#define MACB_TZQ_OFFSET 12
+#define MACB_TZQ_SIZE 1
+
+/* Bitfields in NCFGR */
+#define MACB_SPD_OFFSET 0
+#define MACB_SPD_SIZE 1
+#define MACB_FD_OFFSET 1
+#define MACB_FD_SIZE 1
+#define MACB_BIT_RATE_OFFSET 2
+#define MACB_BIT_RATE_SIZE 1
+#define MACB_JFRAME_OFFSET 3
+#define MACB_JFRAME_SIZE 1
+#define MACB_CAF_OFFSET 4
+#define MACB_CAF_SIZE 1
+#define MACB_NBC_OFFSET 5
+#define MACB_NBC_SIZE 1
+#define MACB_NCFGR_MTI_OFFSET 6
+#define MACB_NCFGR_MTI_SIZE 1
+#define MACB_UNI_OFFSET 7
+#define MACB_UNI_SIZE 1
+#define MACB_BIG_OFFSET 8
+#define MACB_BIG_SIZE 1
+#define MACB_EAE_OFFSET 9
+#define MACB_EAE_SIZE 1
+#define MACB_CLK_OFFSET 10
+#define MACB_CLK_SIZE 2
+#define MACB_RTY_OFFSET 12
+#define MACB_RTY_SIZE 1
+#define MACB_PAE_OFFSET 13
+#define MACB_PAE_SIZE 1
+#define MACB_RBOF_OFFSET 14
+#define MACB_RBOF_SIZE 2
+#define MACB_RLCE_OFFSET 16
+#define MACB_RLCE_SIZE 1
+#define MACB_DRFCS_OFFSET 17
+#define MACB_DRFCS_SIZE 1
+#define MACB_EFRHD_OFFSET 18
+#define MACB_EFRHD_SIZE 1
+#define MACB_IRXFCS_OFFSET 19
+#define MACB_IRXFCS_SIZE 1
+
+#define GEM_GBE_OFFSET 10
+#define GEM_GBE_SIZE 1
+#define GEM_CLK_OFFSET 18
+#define GEM_CLK_SIZE 3
+#define GEM_DBW_OFFSET 21
+#define GEM_DBW_SIZE 2
+
+/* Bitfields in NSR */
+#define MACB_NSR_LINK_OFFSET 0
+#define MACB_NSR_LINK_SIZE 1
+#define MACB_MDIO_OFFSET 1
+#define MACB_MDIO_SIZE 1
+#define MACB_IDLE_OFFSET 2
+#define MACB_IDLE_SIZE 1
+
+/* Bitfields in UR */
+#define GEM_RGMII_OFFSET 0
+#define GEM_RGMII_SIZE 1
+
+/* Bitfields in TSR */
+#define MACB_UBR_OFFSET 0
+#define MACB_UBR_SIZE 1
+#define MACB_COL_OFFSET 1
+#define MACB_COL_SIZE 1
+#define MACB_TSR_RLE_OFFSET 2
+#define MACB_TSR_RLE_SIZE 1
+#define MACB_TGO_OFFSET 3
+#define MACB_TGO_SIZE 1
+#define MACB_BEX_OFFSET 4
+#define MACB_BEX_SIZE 1
+#define MACB_COMP_OFFSET 5
+#define MACB_COMP_SIZE 1
+#define MACB_UND_OFFSET 6
+#define MACB_UND_SIZE 1
+
+/* Bitfields in RSR */
+#define MACB_BNA_OFFSET 0
+#define MACB_BNA_SIZE 1
+#define MACB_REC_OFFSET 1
+#define MACB_REC_SIZE 1
+#define MACB_OVR_OFFSET 2
+#define MACB_OVR_SIZE 1
+
+/* Bitfields in ISR/IER/IDR/IMR */
+#define MACB_MFD_OFFSET 0
+#define MACB_MFD_SIZE 1
+#define MACB_RCOMP_OFFSET 1
+#define MACB_RCOMP_SIZE 1
+#define MACB_RXUBR_OFFSET 2
+#define MACB_RXUBR_SIZE 1
+#define MACB_TXUBR_OFFSET 3
+#define MACB_TXUBR_SIZE 1
+#define MACB_ISR_TUND_OFFSET 4
+#define MACB_ISR_TUND_SIZE 1
+#define MACB_ISR_RLE_OFFSET 5
+#define MACB_ISR_RLE_SIZE 1
+#define MACB_TXERR_OFFSET 6
+#define MACB_TXERR_SIZE 1
+#define MACB_TCOMP_OFFSET 7
+#define MACB_TCOMP_SIZE 1
+#define MACB_ISR_LINK_OFFSET 9
+#define MACB_ISR_LINK_SIZE 1
+#define MACB_ISR_ROVR_OFFSET 10
+#define MACB_ISR_ROVR_SIZE 1
+#define MACB_HRESP_OFFSET 11
+#define MACB_HRESP_SIZE 1
+#define MACB_PFR_OFFSET 12
+#define MACB_PFR_SIZE 1
+#define MACB_PTZ_OFFSET 13
+#define MACB_PTZ_SIZE 1
+
+/* Bitfields in MAN */
+#define MACB_DATA_OFFSET 0
+#define MACB_DATA_SIZE 16
+#define MACB_CODE_OFFSET 16
+#define MACB_CODE_SIZE 2
+#define MACB_REGA_OFFSET 18
+#define MACB_REGA_SIZE 5
+#define MACB_PHYA_OFFSET 23
+#define MACB_PHYA_SIZE 5
+#define MACB_RW_OFFSET 28
+#define MACB_RW_SIZE 2
+#define MACB_SOF_OFFSET 30
+#define MACB_SOF_SIZE 2
+
+/* Bitfields in USRIO */
+#define MACB_MII_OFFSET 0
+#define MACB_MII_SIZE 1
+#define MACB_EAM_OFFSET 1
+#define MACB_EAM_SIZE 1
+#define MACB_TX_PAUSE_OFFSET 2
+#define MACB_TX_PAUSE_SIZE 1
+#define MACB_TX_PAUSE_ZERO_OFFSET 3
+#define MACB_TX_PAUSE_ZERO_SIZE 1
+
+/* Bitfields in USRIO (AT91) */
+#define MACB_RMII_OFFSET 0
+#define MACB_RMII_SIZE 1
+#define MACB_CLKEN_OFFSET 1
+#define MACB_CLKEN_SIZE 1
+
+/* Bitfields in WOL */
+#define MACB_IP_OFFSET 0
+#define MACB_IP_SIZE 16
+#define MACB_MAG_OFFSET 16
+#define MACB_MAG_SIZE 1
+#define MACB_ARP_OFFSET 17
+#define MACB_ARP_SIZE 1
+#define MACB_SA1_OFFSET 18
+#define MACB_SA1_SIZE 1
+#define MACB_WOL_MTI_OFFSET 19
+#define MACB_WOL_MTI_SIZE 1
+
+/* Bitfields in MID */
+#define MACB_IDNUM_OFFSET 16
+#define MACB_IDNUM_SIZE 16
+
+/* Bitfields in DCFG1 */
+#define GEM_DBWDEF_OFFSET 25
+#define GEM_DBWDEF_SIZE 3
+
+/* constants for data bus width */
+#define GEM_DBW32 0
+#define GEM_DBW64 1
+#define GEM_DBW128 2
+
+/* Constants for CLK */
+#define MACB_CLK_DIV8 0
+#define MACB_CLK_DIV16 1
+#define MACB_CLK_DIV32 2
+#define MACB_CLK_DIV64 3
+
+/* GEM specific constants for CLK */
+#define GEM_CLK_DIV8 0
+#define GEM_CLK_DIV16 1
+#define GEM_CLK_DIV32 2
+#define GEM_CLK_DIV48 3
+#define GEM_CLK_DIV64 4
+#define GEM_CLK_DIV96 5
+
+/* Constants for MAN register */
+#define MACB_MAN_SOF 1
+#define MACB_MAN_WRITE 1
+#define MACB_MAN_READ 2
+#define MACB_MAN_CODE 2
+
+/* Bit manipulation macros */
+#define MACB_BIT(name) \
+ (1 << MACB_##name##_OFFSET)
+#define MACB_BF(name, value) \
+ (((value) & ((1 << MACB_##name##_SIZE) - 1)) \
+ << MACB_##name##_OFFSET)
+#define MACB_BFEXT(name, value)\
+ (((value) >> MACB_##name##_OFFSET) \
+ & ((1 << MACB_##name##_SIZE) - 1))
+#define MACB_BFINS(name, value, old) \
+ (((old) & ~(((1 << MACB_##name##_SIZE) - 1) \
+ << MACB_##name##_OFFSET)) \
+ | MACB_BF(name, value))
+
+#define GEM_BIT(name) \
+ (1 << GEM_##name##_OFFSET)
+#define GEM_BF(name, value) \
+ (((value) & ((1 << GEM_##name##_SIZE) - 1)) \
+ << GEM_##name##_OFFSET)
+#define GEM_BFEXT(name, value)\
+ (((value) >> GEM_##name##_OFFSET) \
+ & ((1 << GEM_##name##_SIZE) - 1))
+#define GEM_BFINS(name, value, old) \
+ (((old) & ~(((1 << GEM_##name##_SIZE) - 1) \
+ << GEM_##name##_OFFSET)) \
+ | GEM_BF(name, value))
+
+/* Register access macros */
+#define macb_readl(port, reg) \
+ readl((port)->regs + MACB_##reg)
+#define macb_writel(port, reg, value) \
+ writel((value), (port)->regs + MACB_##reg)
+#define gem_readl(port, reg) \
+ readl((port)->regs + GEM_##reg)
+#define gem_writel(port, reg, value) \
+ writel((value), (port)->regs + GEM_##reg)
+
+#endif /* __DRIVERS_MACB_H__ */
diff --git a/qemu/roms/u-boot/drivers/net/mcffec.c b/qemu/roms/u-boot/drivers/net/mcffec.c
new file mode 100644
index 000000000..7c4b210b0
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/mcffec.c
@@ -0,0 +1,609 @@
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2007 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+
+#include <command.h>
+#include <net.h>
+#include <netdev.h>
+#include <miiphy.h>
+
+#include <asm/fec.h>
+#include <asm/immap.h>
+
+#undef ET_DEBUG
+#undef MII_DEBUG
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+#define TX_BUF_CNT 2
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+#define PKT_MAXBLR_SIZE 1520
+#define LAST_PKTBUFSRX PKTBUFSRX - 1
+#define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY)
+#define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct fec_info_s fec_info[] = {
+#ifdef CONFIG_SYS_FEC0_IOBASE
+ {
+ 0, /* index */
+ CONFIG_SYS_FEC0_IOBASE, /* io base */
+ CONFIG_SYS_FEC0_PINMUX, /* gpio pin muxing */
+ CONFIG_SYS_FEC0_MIIBASE, /* mii base */
+ -1, /* phy_addr */
+ 0, /* duplex and speed */
+ 0, /* phy name */
+ 0, /* phyname init */
+ 0, /* RX BD */
+ 0, /* TX BD */
+ 0, /* rx Index */
+ 0, /* tx Index */
+ 0, /* tx buffer */
+ 0, /* initialized flag */
+ (struct fec_info_s *)-1,
+ },
+#endif
+#ifdef CONFIG_SYS_FEC1_IOBASE
+ {
+ 1, /* index */
+ CONFIG_SYS_FEC1_IOBASE, /* io base */
+ CONFIG_SYS_FEC1_PINMUX, /* gpio pin muxing */
+ CONFIG_SYS_FEC1_MIIBASE, /* mii base */
+ -1, /* phy_addr */
+ 0, /* duplex and speed */
+ 0, /* phy name */
+ 0, /* phy name init */
+#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
+ (cbd_t *)DBUF_LENGTH, /* RX BD */
+#else
+ 0, /* RX BD */
+#endif
+ 0, /* TX BD */
+ 0, /* rx Index */
+ 0, /* tx Index */
+ 0, /* tx buffer */
+ 0, /* initialized flag */
+ (struct fec_info_s *)-1,
+ }
+#endif
+};
+
+int fec_recv(struct eth_device *dev);
+int fec_init(struct eth_device *dev, bd_t * bd);
+void fec_halt(struct eth_device *dev);
+void fec_reset(struct eth_device *dev);
+
+void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd)
+{
+ if ((dup_spd >> 16) == FULL) {
+ /* Set maximum frame length */
+ fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE |
+ FEC_RCR_PROM | 0x100;
+ fecp->tcr = FEC_TCR_FDEN;
+ } else {
+ /* Half duplex mode */
+ fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) |
+ FEC_RCR_MII_MODE | FEC_RCR_DRT;
+ fecp->tcr &= ~FEC_TCR_FDEN;
+ }
+
+ if ((dup_spd & 0xFFFF) == _100BASET) {
+#ifdef CONFIG_MCF5445x
+ fecp->rcr &= ~0x200; /* disabled 10T base */
+#endif
+#ifdef MII_DEBUG
+ printf("100Mbps\n");
+#endif
+ bd->bi_ethspeed = 100;
+ } else {
+#ifdef CONFIG_MCF5445x
+ fecp->rcr |= 0x200; /* enabled 10T base */
+#endif
+#ifdef MII_DEBUG
+ printf("10Mbps\n");
+#endif
+ bd->bi_ethspeed = 10;
+ }
+}
+
+static int fec_send(struct eth_device *dev, void *packet, int length)
+{
+ struct fec_info_s *info = dev->priv;
+ volatile fec_t *fecp = (fec_t *) (info->iobase);
+ int j, rc;
+ u16 phyStatus;
+
+ miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phyStatus);
+
+ /* section 16.9.23.3
+ * Wait for ready
+ */
+ j = 0;
+ while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) &&
+ (j < MCFFEC_TOUT_LOOP)) {
+ udelay(1);
+ j++;
+ }
+ if (j >= MCFFEC_TOUT_LOOP) {
+ printf("TX not ready\n");
+ }
+
+ info->txbd[info->txIdx].cbd_bufaddr = (uint) packet;
+ info->txbd[info->txIdx].cbd_datlen = length;
+ info->txbd[info->txIdx].cbd_sc |= BD_ENET_TX_RDY_LST;
+
+ /* Activate transmit Buffer Descriptor polling */
+ fecp->tdar = 0x01000000; /* Descriptor polling active */
+
+#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM
+ /*
+ * FEC unable to initial transmit data packet.
+ * A nop will ensure the descriptor polling active completed.
+ * CF Internal RAM has shorter cycle access than DRAM. If use
+ * DRAM as Buffer descriptor and data, a nop is a must.
+ * Affect only V2 and V3.
+ */
+ __asm__ ("nop");
+
+#endif
+
+#ifdef CONFIG_SYS_UNIFY_CACHE
+ icache_invalid();
+#endif
+
+ j = 0;
+ while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) &&
+ (j < MCFFEC_TOUT_LOOP)) {
+ udelay(1);
+ j++;
+ }
+ if (j >= MCFFEC_TOUT_LOOP) {
+ printf("TX timeout\n");
+ }
+
+#ifdef ET_DEBUG
+ printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n",
+ __FILE__, __LINE__, __FUNCTION__, j,
+ info->txbd[info->txIdx].cbd_sc,
+ (info->txbd[info->txIdx].cbd_sc & 0x003C) >> 2);
+#endif
+
+ /* return only status bits */
+ rc = (info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_STATS);
+ info->txIdx = (info->txIdx + 1) % TX_BUF_CNT;
+
+ return rc;
+}
+
+int fec_recv(struct eth_device *dev)
+{
+ struct fec_info_s *info = dev->priv;
+ volatile fec_t *fecp = (fec_t *) (info->iobase);
+ int length;
+
+ for (;;) {
+#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM
+#endif
+#ifdef CONFIG_SYS_UNIFY_CACHE
+ icache_invalid();
+#endif
+ /* section 16.9.23.2 */
+ if (info->rxbd[info->rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ length = info->rxbd[info->rxIdx].cbd_datlen;
+
+ if (info->rxbd[info->rxIdx].cbd_sc & 0x003f) {
+ printf("%s[%d] err: %x\n",
+ __FUNCTION__, __LINE__,
+ info->rxbd[info->rxIdx].cbd_sc);
+#ifdef ET_DEBUG
+ printf("%s[%d] err: %x\n",
+ __FUNCTION__, __LINE__,
+ info->rxbd[info->rxIdx].cbd_sc);
+#endif
+ } else {
+
+ length -= 4;
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[info->rxIdx], length);
+
+ fecp->eir |= FEC_EIR_RXF;
+ }
+
+ /* Give the buffer back to the FEC. */
+ info->rxbd[info->rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if (info->rxIdx == LAST_PKTBUFSRX) {
+ info->rxbd[PKTBUFSRX - 1].cbd_sc = BD_ENET_RX_W_E;
+ info->rxIdx = 0;
+ } else {
+ info->rxbd[info->rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ info->rxIdx++;
+ }
+
+ /* Try to fill Buffer Descriptors */
+ fecp->rdar = 0x01000000; /* Descriptor polling active */
+ }
+
+ return length;
+}
+
+#ifdef ET_DEBUG
+void dbgFecRegs(struct eth_device *dev)
+{
+ struct fec_info_s *info = dev->priv;
+ volatile fec_t *fecp = (fec_t *) (info->iobase);
+
+ printf("=====\n");
+ printf("ievent %x - %x\n", (int)&fecp->eir, fecp->eir);
+ printf("imask %x - %x\n", (int)&fecp->eimr, fecp->eimr);
+ printf("r_des_active %x - %x\n", (int)&fecp->rdar, fecp->rdar);
+ printf("x_des_active %x - %x\n", (int)&fecp->tdar, fecp->tdar);
+ printf("ecntrl %x - %x\n", (int)&fecp->ecr, fecp->ecr);
+ printf("mii_mframe %x - %x\n", (int)&fecp->mmfr, fecp->mmfr);
+ printf("mii_speed %x - %x\n", (int)&fecp->mscr, fecp->mscr);
+ printf("mii_ctrlstat %x - %x\n", (int)&fecp->mibc, fecp->mibc);
+ printf("r_cntrl %x - %x\n", (int)&fecp->rcr, fecp->rcr);
+ printf("x_cntrl %x - %x\n", (int)&fecp->tcr, fecp->tcr);
+ printf("padr_l %x - %x\n", (int)&fecp->palr, fecp->palr);
+ printf("padr_u %x - %x\n", (int)&fecp->paur, fecp->paur);
+ printf("op_pause %x - %x\n", (int)&fecp->opd, fecp->opd);
+ printf("iadr_u %x - %x\n", (int)&fecp->iaur, fecp->iaur);
+ printf("iadr_l %x - %x\n", (int)&fecp->ialr, fecp->ialr);
+ printf("gadr_u %x - %x\n", (int)&fecp->gaur, fecp->gaur);
+ printf("gadr_l %x - %x\n", (int)&fecp->galr, fecp->galr);
+ printf("x_wmrk %x - %x\n", (int)&fecp->tfwr, fecp->tfwr);
+ printf("r_bound %x - %x\n", (int)&fecp->frbr, fecp->frbr);
+ printf("r_fstart %x - %x\n", (int)&fecp->frsr, fecp->frsr);
+ printf("r_drng %x - %x\n", (int)&fecp->erdsr, fecp->erdsr);
+ printf("x_drng %x - %x\n", (int)&fecp->etdsr, fecp->etdsr);
+ printf("r_bufsz %x - %x\n", (int)&fecp->emrbr, fecp->emrbr);
+
+ printf("\n");
+ printf("rmon_t_drop %x - %x\n", (int)&fecp->rmon_t_drop,
+ fecp->rmon_t_drop);
+ printf("rmon_t_packets %x - %x\n", (int)&fecp->rmon_t_packets,
+ fecp->rmon_t_packets);
+ printf("rmon_t_bc_pkt %x - %x\n", (int)&fecp->rmon_t_bc_pkt,
+ fecp->rmon_t_bc_pkt);
+ printf("rmon_t_mc_pkt %x - %x\n", (int)&fecp->rmon_t_mc_pkt,
+ fecp->rmon_t_mc_pkt);
+ printf("rmon_t_crc_align %x - %x\n", (int)&fecp->rmon_t_crc_align,
+ fecp->rmon_t_crc_align);
+ printf("rmon_t_undersize %x - %x\n", (int)&fecp->rmon_t_undersize,
+ fecp->rmon_t_undersize);
+ printf("rmon_t_oversize %x - %x\n", (int)&fecp->rmon_t_oversize,
+ fecp->rmon_t_oversize);
+ printf("rmon_t_frag %x - %x\n", (int)&fecp->rmon_t_frag,
+ fecp->rmon_t_frag);
+ printf("rmon_t_jab %x - %x\n", (int)&fecp->rmon_t_jab,
+ fecp->rmon_t_jab);
+ printf("rmon_t_col %x - %x\n", (int)&fecp->rmon_t_col,
+ fecp->rmon_t_col);
+ printf("rmon_t_p64 %x - %x\n", (int)&fecp->rmon_t_p64,
+ fecp->rmon_t_p64);
+ printf("rmon_t_p65to127 %x - %x\n", (int)&fecp->rmon_t_p65to127,
+ fecp->rmon_t_p65to127);
+ printf("rmon_t_p128to255 %x - %x\n", (int)&fecp->rmon_t_p128to255,
+ fecp->rmon_t_p128to255);
+ printf("rmon_t_p256to511 %x - %x\n", (int)&fecp->rmon_t_p256to511,
+ fecp->rmon_t_p256to511);
+ printf("rmon_t_p512to1023 %x - %x\n", (int)&fecp->rmon_t_p512to1023,
+ fecp->rmon_t_p512to1023);
+ printf("rmon_t_p1024to2047 %x - %x\n", (int)&fecp->rmon_t_p1024to2047,
+ fecp->rmon_t_p1024to2047);
+ printf("rmon_t_p_gte2048 %x - %x\n", (int)&fecp->rmon_t_p_gte2048,
+ fecp->rmon_t_p_gte2048);
+ printf("rmon_t_octets %x - %x\n", (int)&fecp->rmon_t_octets,
+ fecp->rmon_t_octets);
+
+ printf("\n");
+ printf("ieee_t_drop %x - %x\n", (int)&fecp->ieee_t_drop,
+ fecp->ieee_t_drop);
+ printf("ieee_t_frame_ok %x - %x\n", (int)&fecp->ieee_t_frame_ok,
+ fecp->ieee_t_frame_ok);
+ printf("ieee_t_1col %x - %x\n", (int)&fecp->ieee_t_1col,
+ fecp->ieee_t_1col);
+ printf("ieee_t_mcol %x - %x\n", (int)&fecp->ieee_t_mcol,
+ fecp->ieee_t_mcol);
+ printf("ieee_t_def %x - %x\n", (int)&fecp->ieee_t_def,
+ fecp->ieee_t_def);
+ printf("ieee_t_lcol %x - %x\n", (int)&fecp->ieee_t_lcol,
+ fecp->ieee_t_lcol);
+ printf("ieee_t_excol %x - %x\n", (int)&fecp->ieee_t_excol,
+ fecp->ieee_t_excol);
+ printf("ieee_t_macerr %x - %x\n", (int)&fecp->ieee_t_macerr,
+ fecp->ieee_t_macerr);
+ printf("ieee_t_cserr %x - %x\n", (int)&fecp->ieee_t_cserr,
+ fecp->ieee_t_cserr);
+ printf("ieee_t_sqe %x - %x\n", (int)&fecp->ieee_t_sqe,
+ fecp->ieee_t_sqe);
+ printf("ieee_t_fdxfc %x - %x\n", (int)&fecp->ieee_t_fdxfc,
+ fecp->ieee_t_fdxfc);
+ printf("ieee_t_octets_ok %x - %x\n", (int)&fecp->ieee_t_octets_ok,
+ fecp->ieee_t_octets_ok);
+
+ printf("\n");
+ printf("rmon_r_drop %x - %x\n", (int)&fecp->rmon_r_drop,
+ fecp->rmon_r_drop);
+ printf("rmon_r_packets %x - %x\n", (int)&fecp->rmon_r_packets,
+ fecp->rmon_r_packets);
+ printf("rmon_r_bc_pkt %x - %x\n", (int)&fecp->rmon_r_bc_pkt,
+ fecp->rmon_r_bc_pkt);
+ printf("rmon_r_mc_pkt %x - %x\n", (int)&fecp->rmon_r_mc_pkt,
+ fecp->rmon_r_mc_pkt);
+ printf("rmon_r_crc_align %x - %x\n", (int)&fecp->rmon_r_crc_align,
+ fecp->rmon_r_crc_align);
+ printf("rmon_r_undersize %x - %x\n", (int)&fecp->rmon_r_undersize,
+ fecp->rmon_r_undersize);
+ printf("rmon_r_oversize %x - %x\n", (int)&fecp->rmon_r_oversize,
+ fecp->rmon_r_oversize);
+ printf("rmon_r_frag %x - %x\n", (int)&fecp->rmon_r_frag,
+ fecp->rmon_r_frag);
+ printf("rmon_r_jab %x - %x\n", (int)&fecp->rmon_r_jab,
+ fecp->rmon_r_jab);
+ printf("rmon_r_p64 %x - %x\n", (int)&fecp->rmon_r_p64,
+ fecp->rmon_r_p64);
+ printf("rmon_r_p65to127 %x - %x\n", (int)&fecp->rmon_r_p65to127,
+ fecp->rmon_r_p65to127);
+ printf("rmon_r_p128to255 %x - %x\n", (int)&fecp->rmon_r_p128to255,
+ fecp->rmon_r_p128to255);
+ printf("rmon_r_p256to511 %x - %x\n", (int)&fecp->rmon_r_p256to511,
+ fecp->rmon_r_p256to511);
+ printf("rmon_r_p512to1023 %x - %x\n", (int)&fecp->rmon_r_p512to1023,
+ fecp->rmon_r_p512to1023);
+ printf("rmon_r_p1024to2047 %x - %x\n", (int)&fecp->rmon_r_p1024to2047,
+ fecp->rmon_r_p1024to2047);
+ printf("rmon_r_p_gte2048 %x - %x\n", (int)&fecp->rmon_r_p_gte2048,
+ fecp->rmon_r_p_gte2048);
+ printf("rmon_r_octets %x - %x\n", (int)&fecp->rmon_r_octets,
+ fecp->rmon_r_octets);
+
+ printf("\n");
+ printf("ieee_r_drop %x - %x\n", (int)&fecp->ieee_r_drop,
+ fecp->ieee_r_drop);
+ printf("ieee_r_frame_ok %x - %x\n", (int)&fecp->ieee_r_frame_ok,
+ fecp->ieee_r_frame_ok);
+ printf("ieee_r_crc %x - %x\n", (int)&fecp->ieee_r_crc,
+ fecp->ieee_r_crc);
+ printf("ieee_r_align %x - %x\n", (int)&fecp->ieee_r_align,
+ fecp->ieee_r_align);
+ printf("ieee_r_macerr %x - %x\n", (int)&fecp->ieee_r_macerr,
+ fecp->ieee_r_macerr);
+ printf("ieee_r_fdxfc %x - %x\n", (int)&fecp->ieee_r_fdxfc,
+ fecp->ieee_r_fdxfc);
+ printf("ieee_r_octets_ok %x - %x\n", (int)&fecp->ieee_r_octets_ok,
+ fecp->ieee_r_octets_ok);
+
+ printf("\n\n\n");
+}
+#endif
+
+int fec_init(struct eth_device *dev, bd_t * bd)
+{
+ struct fec_info_s *info = dev->priv;
+ volatile fec_t *fecp = (fec_t *) (info->iobase);
+ int i;
+ uchar ea[6];
+
+ fecpin_setclear(dev, 1);
+
+ fec_reset(dev);
+
+#if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \
+ defined (CONFIG_SYS_DISCOVER_PHY)
+
+ mii_init();
+
+ setFecDuplexSpeed(fecp, bd, info->dup_spd);
+#else
+#ifndef CONFIG_SYS_DISCOVER_PHY
+ setFecDuplexSpeed(fecp, bd, (FECDUPLEX << 16) | FECSPEED);
+#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */
+#endif /* CONFIG_CMD_MII || CONFIG_MII */
+
+ /* We use strictly polling mode only */
+ fecp->eimr = 0;
+
+ /* Clear any pending interrupt */
+ fecp->eir = 0xffffffff;
+
+ /* Set station address */
+ if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) {
+#ifdef CONFIG_SYS_FEC1_IOBASE
+ volatile fec_t *fecp1 = (fec_t *) (CONFIG_SYS_FEC1_IOBASE);
+ eth_getenv_enetaddr("eth1addr", ea);
+ fecp1->palr =
+ (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+ fecp1->paur = (ea[4] << 24) | (ea[5] << 16);
+#endif
+ eth_getenv_enetaddr("ethaddr", ea);
+ fecp->palr =
+ (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+ fecp->paur = (ea[4] << 24) | (ea[5] << 16);
+ } else {
+#ifdef CONFIG_SYS_FEC0_IOBASE
+ volatile fec_t *fecp0 = (fec_t *) (CONFIG_SYS_FEC0_IOBASE);
+ eth_getenv_enetaddr("ethaddr", ea);
+ fecp0->palr =
+ (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+ fecp0->paur = (ea[4] << 24) | (ea[5] << 16);
+#endif
+#ifdef CONFIG_SYS_FEC1_IOBASE
+ eth_getenv_enetaddr("eth1addr", ea);
+ fecp->palr =
+ (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+ fecp->paur = (ea[4] << 24) | (ea[5] << 16);
+#endif
+ }
+
+ /* Clear unicast address hash table */
+ fecp->iaur = 0;
+ fecp->ialr = 0;
+
+ /* Clear multicast address hash table */
+ fecp->gaur = 0;
+ fecp->galr = 0;
+
+ /* Set maximum receive buffer size. */
+ fecp->emrbr = PKT_MAXBLR_SIZE;
+
+ /*
+ * Setup Buffers and Buffer Desriptors
+ */
+ info->rxIdx = 0;
+ info->txIdx = 0;
+
+ /*
+ * Setup Receiver Buffer Descriptors (13.14.24.18)
+ * Settings:
+ * Empty, Wrap
+ */
+ for (i = 0; i < PKTBUFSRX; i++) {
+ info->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ info->rxbd[i].cbd_datlen = 0; /* Reset */
+ info->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
+ }
+ info->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /*
+ * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+ * Settings:
+ * Last, Tx CRC
+ */
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ info->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC;
+ info->txbd[i].cbd_datlen = 0; /* Reset */
+ info->txbd[i].cbd_bufaddr = (uint) (&info->txbuf[0]);
+ }
+ info->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* Set receive and transmit descriptor base */
+ fecp->erdsr = (unsigned int)(&info->rxbd[0]);
+ fecp->etdsr = (unsigned int)(&info->txbd[0]);
+
+ /* Now enable the transmit and receive processing */
+ fecp->ecr |= FEC_ECR_ETHER_EN;
+
+ /* And last, try to fill Rx Buffer Descriptors */
+ fecp->rdar = 0x01000000; /* Descriptor polling active */
+
+ return 1;
+}
+
+void fec_reset(struct eth_device *dev)
+{
+ struct fec_info_s *info = dev->priv;
+ volatile fec_t *fecp = (fec_t *) (info->iobase);
+ int i;
+
+ fecp->ecr = FEC_ECR_RESET;
+ for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) {
+ udelay(1);
+ }
+ if (i == FEC_RESET_DELAY) {
+ printf("FEC_RESET_DELAY timeout\n");
+ }
+}
+
+void fec_halt(struct eth_device *dev)
+{
+ struct fec_info_s *info = dev->priv;
+
+ fec_reset(dev);
+
+ fecpin_setclear(dev, 0);
+
+ info->rxIdx = info->txIdx = 0;
+ memset(info->rxbd, 0, PKTBUFSRX * sizeof(cbd_t));
+ memset(info->txbd, 0, TX_BUF_CNT * sizeof(cbd_t));
+ memset(info->txbuf, 0, DBUF_LENGTH);
+}
+
+int mcffec_initialize(bd_t * bis)
+{
+ struct eth_device *dev;
+ int i;
+#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
+ u32 tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000;
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(fec_info); i++) {
+
+ dev =
+ (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE,
+ sizeof *dev);
+ if (dev == NULL)
+ hang();
+
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf(dev->name, "FEC%d", fec_info[i].index);
+
+ dev->priv = &fec_info[i];
+ dev->init = fec_init;
+ dev->halt = fec_halt;
+ dev->send = fec_send;
+ dev->recv = fec_recv;
+
+ /* setup Receive and Transmit buffer descriptor */
+#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
+ fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp);
+ tmp = (u32)fec_info[i].rxbd;
+ fec_info[i].txbd =
+ (cbd_t *)((u32)fec_info[i].txbd + tmp +
+ (PKTBUFSRX * sizeof(cbd_t)));
+ tmp = (u32)fec_info[i].txbd;
+ fec_info[i].txbuf =
+ (char *)((u32)fec_info[i].txbuf + tmp +
+ (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
+ tmp = (u32)fec_info[i].txbuf;
+#else
+ fec_info[i].rxbd =
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ (PKTBUFSRX * sizeof(cbd_t)));
+ fec_info[i].txbd =
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ (TX_BUF_CNT * sizeof(cbd_t)));
+ fec_info[i].txbuf =
+ (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH);
+#endif
+
+#ifdef ET_DEBUG
+ printf("rxbd %x txbd %x\n",
+ (int)fec_info[i].rxbd, (int)fec_info[i].txbd);
+#endif
+
+ fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name,
+ mcffec_miiphy_read, mcffec_miiphy_write);
+#endif
+ if (i > 0)
+ fec_info[i - 1].next = &fec_info[i];
+ }
+ fec_info[i - 1].next = &fec_info[0];
+
+ /* default speed */
+ bis->bi_ethspeed = 10;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/mcfmii.c b/qemu/roms/u-boot/drivers/net/mcfmii.c
new file mode 100644
index 000000000..17a780c85
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/mcfmii.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <config.h>
+#include <net.h>
+#include <netdev.h>
+
+#ifdef CONFIG_MCF547x_8x
+#include <asm/fsl_mcdmafec.h>
+#else
+#include <asm/fec.h>
+#endif
+#include <asm/immap.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CMD_NET)
+#undef MII_DEBUG
+#undef ET_DEBUG
+
+/*extern int fecpin_setclear(struct eth_device *dev, int setclear);*/
+
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+
+/* Make MII read/write commands for the FEC. */
+#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | \
+ (REG & 0x1f) << 18))
+#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | \
+ (REG & 0x1f) << 18) | (VAL & 0xffff))
+
+#ifndef CONFIG_SYS_UNSPEC_PHYID
+# define CONFIG_SYS_UNSPEC_PHYID 0
+#endif
+#ifndef CONFIG_SYS_UNSPEC_STRID
+# define CONFIG_SYS_UNSPEC_STRID 0
+#endif
+
+#ifdef CONFIG_MCF547x_8x
+typedef struct fec_info_dma FEC_INFO_T;
+#define FEC_T fecdma_t
+#else
+typedef struct fec_info_s FEC_INFO_T;
+#define FEC_T fec_t
+#endif
+
+typedef struct phy_info_struct {
+ u32 phyid;
+ char *strid;
+} phy_info_t;
+
+phy_info_t phyinfo[] = {
+ {0x0022561B, "AMD79C784VC"}, /* AMD 79C784VC */
+ {0x00406322, "BCM5222"}, /* Broadcom 5222 */
+ {0x02a80150, "Intel82555"}, /* Intel 82555 */
+ {0x0016f870, "LSI80225"}, /* LSI 80225 */
+ {0x0016f880, "LSI80225/B"}, /* LSI 80225/B */
+ {0x78100000, "LXT970"}, /* LXT970 */
+ {0x001378e0, "LXT971"}, /* LXT971 and 972 */
+ {0x00221619, "KS8721BL"}, /* Micrel KS8721BL/SL */
+ {0x00221512, "KSZ8041NL"}, /* Micrel KSZ8041NL */
+ {0x20005CE1, "N83640"}, /* National 83640 */
+ {0x20005C90, "N83848"}, /* National 83848 */
+ {0x20005CA2, "N83849"}, /* National 83849 */
+ {0x01814400, "QS6612"}, /* QS6612 */
+#if defined(CONFIG_SYS_UNSPEC_PHYID) && defined(CONFIG_SYS_UNSPEC_STRID)
+ {CONFIG_SYS_UNSPEC_PHYID, CONFIG_SYS_UNSPEC_STRID},
+#endif
+ {0, 0}
+};
+
+/*
+ * mii_init -- Initialize the MII for MII command without ethernet
+ * This function is a subset of eth_init
+ */
+void mii_reset(FEC_INFO_T *info)
+{
+ volatile FEC_T *fecp = (FEC_T *) (info->miibase);
+ int i;
+
+ fecp->ecr = FEC_ECR_RESET;
+
+ for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) {
+ udelay(1);
+ }
+ if (i == FEC_RESET_DELAY)
+ printf("FEC_RESET_DELAY timeout\n");
+}
+
+/* send command to phy using mii, wait for result */
+uint mii_send(uint mii_cmd)
+{
+ FEC_INFO_T *info;
+ volatile FEC_T *ep;
+ struct eth_device *dev;
+ uint mii_reply;
+ int j = 0;
+
+ /* retrieve from register structure */
+ dev = eth_get_dev();
+ info = dev->priv;
+
+ ep = (FEC_T *) info->miibase;
+
+ ep->mmfr = mii_cmd; /* command to phy */
+
+ /* wait for mii complete */
+ while (!(ep->eir & FEC_EIR_MII) && (j < MCFFEC_TOUT_LOOP)) {
+ udelay(1);
+ j++;
+ }
+ if (j >= MCFFEC_TOUT_LOOP) {
+ printf("MII not complete\n");
+ return -1;
+ }
+
+ mii_reply = ep->mmfr; /* result from phy */
+ ep->eir = FEC_EIR_MII; /* clear MII complete */
+#ifdef ET_DEBUG
+ printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n",
+ __FILE__, __LINE__, __FUNCTION__, mii_cmd, mii_reply);
+#endif
+
+ return (mii_reply & 0xffff); /* data read from phy */
+}
+#endif /* CONFIG_SYS_DISCOVER_PHY || (CONFIG_MII) */
+
+#if defined(CONFIG_SYS_DISCOVER_PHY)
+int mii_discover_phy(struct eth_device *dev)
+{
+#define MAX_PHY_PASSES 11
+ FEC_INFO_T *info = dev->priv;
+ int phyaddr, pass;
+ uint phyno, phytype;
+ int i, found = 0;
+
+ if (info->phyname_init)
+ return info->phy_addr;
+
+ phyaddr = -1; /* didn't find a PHY yet */
+ for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
+ if (pass > 1) {
+ /* PHY may need more time to recover from reset.
+ * The LXT970 needs 50ms typical, no maximum is
+ * specified, so wait 10ms before try again.
+ * With 11 passes this gives it 100ms to wake up.
+ */
+ udelay(10000); /* wait 10ms */
+ }
+
+ for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
+
+ phytype = mii_send(mk_mii_read(phyno, MII_PHYSID1));
+#ifdef ET_DEBUG
+ printf("PHY type 0x%x pass %d type\n", phytype, pass);
+#endif
+ if (phytype == 0xffff)
+ continue;
+ phyaddr = phyno;
+ phytype <<= 16;
+ phytype |=
+ mii_send(mk_mii_read(phyno, MII_PHYSID2));
+
+#ifdef ET_DEBUG
+ printf("PHY @ 0x%x pass %d\n", phyno, pass);
+#endif
+
+ for (i = 0; (i < ARRAY_SIZE(phyinfo))
+ && (phyinfo[i].phyid != 0); i++) {
+ if (phyinfo[i].phyid == phytype) {
+#ifdef ET_DEBUG
+ printf("phyid %x - %s\n",
+ phyinfo[i].phyid,
+ phyinfo[i].strid);
+#endif
+ strcpy(info->phy_name, phyinfo[i].strid);
+ info->phyname_init = 1;
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+#ifdef ET_DEBUG
+ printf("0x%08x\n", phytype);
+#endif
+ strcpy(info->phy_name, "unknown");
+ info->phyname_init = 1;
+ break;
+ }
+ }
+ }
+
+ if (phyaddr < 0)
+ printf("No PHY device found.\n");
+
+ return phyaddr;
+}
+#endif /* CONFIG_SYS_DISCOVER_PHY */
+
+void mii_init(void) __attribute__((weak,alias("__mii_init")));
+
+void __mii_init(void)
+{
+ FEC_INFO_T *info;
+ volatile FEC_T *fecp;
+ struct eth_device *dev;
+ int miispd = 0, i = 0;
+ u16 status = 0;
+ u16 linkgood = 0;
+
+ /* retrieve from register structure */
+ dev = eth_get_dev();
+ info = dev->priv;
+
+ fecp = (FEC_T *) info->miibase;
+
+ fecpin_setclear(dev, 1);
+
+ mii_reset(info);
+
+ /* We use strictly polling mode only */
+ fecp->eimr = 0;
+
+ /* Clear any pending interrupt */
+ fecp->eir = 0xffffffff;
+
+ /* Set MII speed */
+ miispd = (gd->bus_clk / 1000000) / 5;
+ fecp->mscr = miispd << 1;
+
+ info->phy_addr = mii_discover_phy(dev);
+
+ while (i < MCFFEC_TOUT_LOOP) {
+ status = 0;
+ i++;
+ /* Read PHY control register */
+ miiphy_read(dev->name, info->phy_addr, MII_BMCR, &status);
+
+ /* If phy set to autonegotiate, wait for autonegotiation done,
+ * if phy is not autonegotiating, just wait for link up.
+ */
+ if ((status & BMCR_ANENABLE) == BMCR_ANENABLE) {
+ linkgood = (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
+ } else {
+ linkgood = BMSR_LSTATUS;
+ }
+ /* Read PHY status register */
+ miiphy_read(dev->name, info->phy_addr, MII_BMSR, &status);
+ if ((status & linkgood) == linkgood)
+ break;
+
+ udelay(1);
+ }
+ if (i >= MCFFEC_TOUT_LOOP) {
+ printf("Link UP timeout\n");
+ }
+
+ /* adapt to the duplex and speed settings of the phy */
+ info->dup_spd = miiphy_duplex(dev->name, info->phy_addr) << 16;
+ info->dup_spd |= miiphy_speed(dev->name, info->phy_addr);
+}
+
+/*
+ * Read and write a MII PHY register, routines used by MII Utilities
+ *
+ * FIXME: These routines are expected to return 0 on success, but mii_send
+ * does _not_ return an error code. Maybe 0xFFFF means error, i.e.
+ * no PHY connected...
+ * For now always return 0.
+ * FIXME: These routines only work after calling eth_init() at least once!
+ * Otherwise they hang in mii_send() !!! Sorry!
+ */
+
+int mcffec_miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
+ unsigned short *value)
+{
+ short rdreg; /* register working value */
+
+#ifdef MII_DEBUG
+ printf("miiphy_read(0x%x) @ 0x%x = ", reg, addr);
+#endif
+ rdreg = mii_send(mk_mii_read(addr, reg));
+
+ *value = rdreg;
+
+#ifdef MII_DEBUG
+ printf("0x%04x\n", *value);
+#endif
+
+ return 0;
+}
+
+int mcffec_miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
+ unsigned short value)
+{
+#ifdef MII_DEBUG
+ printf("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
+#endif
+
+ mii_send(mk_mii_write(addr, reg, value));
+
+#ifdef MII_DEBUG
+ printf("0x%04x\n", value);
+#endif
+
+ return 0;
+}
+
+#endif /* CONFIG_CMD_NET */
diff --git a/qemu/roms/u-boot/drivers/net/mpc512x_fec.c b/qemu/roms/u-boot/drivers/net/mpc512x_fec.c
new file mode 100644
index 000000000..427e0b8b4
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/mpc512x_fec.c
@@ -0,0 +1,754 @@
+/*
+ * (C) Copyright 2003-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Derived from the MPC8xx FEC driver.
+ * Adapted for MPC512x by Grzegorz Bernacki <gjb@semihalf.com>
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include <asm/io.h>
+#include "mpc512x_fec.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DEBUG 0
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+int fec512x_miiphy_read(const char *devname, u8 phyAddr, u8 regAddr, u16 * retVal);
+int fec512x_miiphy_write(const char *devname, u8 phyAddr, u8 regAddr, u16 data);
+int mpc512x_fec_init_phy(struct eth_device *dev, bd_t * bis);
+
+static uchar rx_buff[FEC_BUFFER_SIZE];
+static int rx_buff_idx = 0;
+
+/********************************************************************/
+#if (DEBUG & 0x2)
+static void mpc512x_fec_phydump (char *devname)
+{
+ u16 phyStatus, i;
+ u8 phyAddr = CONFIG_PHY_ADDR;
+ u8 reg_mask[] = {
+ /* regs to print: 0...8, 21,27,31 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
+ };
+
+ for (i = 0; i < 32; i++) {
+ if (reg_mask[i]) {
+ miiphy_read (devname, phyAddr, i, &phyStatus);
+ printf ("Mii reg %d: 0x%04x\n", i, phyStatus);
+ }
+ }
+}
+#endif
+
+/********************************************************************/
+static int mpc512x_fec_bd_init (mpc512x_fec_priv *fec)
+{
+ int ix;
+
+ /*
+ * Receive BDs init
+ */
+ for (ix = 0; ix < FEC_RBD_NUM; ix++) {
+ fec->bdBase->rbd[ix].dataPointer =
+ (u32)&fec->bdBase->recv_frames[ix];
+ fec->bdBase->rbd[ix].status = FEC_RBD_EMPTY;
+ fec->bdBase->rbd[ix].dataLength = 0;
+ }
+
+ /*
+ * have the last RBD to close the ring
+ */
+ fec->bdBase->rbd[ix - 1].status |= FEC_RBD_WRAP;
+ fec->rbdIndex = 0;
+
+ /*
+ * Trasmit BDs init
+ */
+ for (ix = 0; ix < FEC_TBD_NUM; ix++) {
+ fec->bdBase->tbd[ix].status = 0;
+ }
+
+ /*
+ * Have the last TBD to close the ring
+ */
+ fec->bdBase->tbd[ix - 1].status |= FEC_TBD_WRAP;
+
+ /*
+ * Initialize some indices
+ */
+ fec->tbdIndex = 0;
+ fec->usedTbdIndex = 0;
+ fec->cleanTbdNum = FEC_TBD_NUM;
+
+ return 0;
+}
+
+/********************************************************************/
+static void mpc512x_fec_rbd_clean (mpc512x_fec_priv *fec, volatile FEC_RBD * pRbd)
+{
+ /*
+ * Reset buffer descriptor as empty
+ */
+ if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
+ pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
+ else
+ pRbd->status = FEC_RBD_EMPTY;
+
+ pRbd->dataLength = 0;
+
+ /*
+ * Increment BD count
+ */
+ fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
+
+ /*
+ * Now, we have an empty RxBD, notify FEC
+ * Set Descriptor polling active
+ */
+ out_be32(&fec->eth->r_des_active, 0x01000000);
+}
+
+/********************************************************************/
+static void mpc512x_fec_tbd_scrub (mpc512x_fec_priv *fec)
+{
+ volatile FEC_TBD *pUsedTbd;
+
+#if (DEBUG & 0x1)
+ printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
+ fec->cleanTbdNum, fec->usedTbdIndex);
+#endif
+
+ /*
+ * process all the consumed TBDs
+ */
+ while (fec->cleanTbdNum < FEC_TBD_NUM) {
+ pUsedTbd = &fec->bdBase->tbd[fec->usedTbdIndex];
+ if (pUsedTbd->status & FEC_TBD_READY) {
+#if (DEBUG & 0x20)
+ printf ("Cannot clean TBD %d, in use\n", fec->usedTbdIndex);
+#endif
+ return;
+ }
+
+ /*
+ * clean this buffer descriptor
+ */
+ if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
+ pUsedTbd->status = FEC_TBD_WRAP;
+ else
+ pUsedTbd->status = 0;
+
+ /*
+ * update some indeces for a correct handling of the TBD ring
+ */
+ fec->cleanTbdNum++;
+ fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
+ }
+}
+
+/********************************************************************/
+static void mpc512x_fec_set_hwaddr (mpc512x_fec_priv *fec, unsigned char *mac)
+{
+ u8 currByte; /* byte for which to compute the CRC */
+ int byte; /* loop - counter */
+ int bit; /* loop - counter */
+ u32 crc = 0xffffffff; /* initial value */
+
+ /*
+ * The algorithm used is the following:
+ * we loop on each of the six bytes of the provided address,
+ * and we compute the CRC by left-shifting the previous
+ * value by one position, so that each bit in the current
+ * byte of the address may contribute the calculation. If
+ * the latter and the MSB in the CRC are different, then
+ * the CRC value so computed is also ex-ored with the
+ * "polynomium generator". The current byte of the address
+ * is also shifted right by one bit at each iteration.
+ * This is because the CRC generatore in hardware is implemented
+ * as a shift-register with as many ex-ores as the radixes
+ * in the polynomium. This suggests that we represent the
+ * polynomiumm itself as a 32-bit constant.
+ */
+ for (byte = 0; byte < 6; byte++) {
+ currByte = mac[byte];
+ for (bit = 0; bit < 8; bit++) {
+ if ((currByte & 0x01) ^ (crc & 0x01)) {
+ crc >>= 1;
+ crc = crc ^ 0xedb88320;
+ } else {
+ crc >>= 1;
+ }
+ currByte >>= 1;
+ }
+ }
+
+ crc = crc >> 26;
+
+ /*
+ * Set individual hash table register
+ */
+ if (crc >= 32) {
+ out_be32(&fec->eth->iaddr1, (1 << (crc - 32)));
+ out_be32(&fec->eth->iaddr2, 0);
+ } else {
+ out_be32(&fec->eth->iaddr1, 0);
+ out_be32(&fec->eth->iaddr2, (1 << crc));
+ }
+
+ /*
+ * Set physical address
+ */
+ out_be32(&fec->eth->paddr1, (mac[0] << 24) + (mac[1] << 16) +
+ (mac[2] << 8) + mac[3]);
+ out_be32(&fec->eth->paddr2, (mac[4] << 24) + (mac[5] << 16) +
+ 0x8808);
+}
+
+/********************************************************************/
+static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis)
+{
+ mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
+
+#if (DEBUG & 0x1)
+ printf ("mpc512x_fec_init... Begin\n");
+#endif
+
+ mpc512x_fec_set_hwaddr (fec, dev->enetaddr);
+ out_be32(&fec->eth->gaddr1, 0x00000000);
+ out_be32(&fec->eth->gaddr2, 0x00000000);
+
+ mpc512x_fec_init_phy (dev, bis);
+
+ /* Set interrupt mask register */
+ out_be32(&fec->eth->imask, 0x00000000);
+
+ /* Clear FEC-Lite interrupt event register(IEVENT) */
+ out_be32(&fec->eth->ievent, 0xffffffff);
+
+ /* Set transmit fifo watermark register(X_WMRK), default = 64 */
+ out_be32(&fec->eth->x_wmrk, 0x0);
+
+ /* Set Opcode/Pause Duration Register */
+ out_be32(&fec->eth->op_pause, 0x00010020);
+
+ /* Frame length=1522; MII mode */
+ out_be32(&fec->eth->r_cntrl, (FEC_MAX_FRAME_LEN << 16) | 0x24);
+
+ /* Half-duplex, heartbeat disabled */
+ out_be32(&fec->eth->x_cntrl, 0x00000000);
+
+ /* Enable MIB counters */
+ out_be32(&fec->eth->mib_control, 0x0);
+
+ /* Setup recv fifo start and buff size */
+ out_be32(&fec->eth->r_fstart, 0x500);
+ out_be32(&fec->eth->r_buff_size, FEC_BUFFER_SIZE);
+
+ /* Setup BD base addresses */
+ out_be32(&fec->eth->r_des_start, (u32)fec->bdBase->rbd);
+ out_be32(&fec->eth->x_des_start, (u32)fec->bdBase->tbd);
+
+ /* DMA Control */
+ out_be32(&fec->eth->dma_control, 0xc0000000);
+
+ /* Enable FEC */
+ setbits_be32(&fec->eth->ecntrl, 0x00000006);
+
+ /* Initilize addresses and status words of BDs */
+ mpc512x_fec_bd_init (fec);
+
+ /* Descriptor polling active */
+ out_be32(&fec->eth->r_des_active, 0x01000000);
+
+#if (DEBUG & 0x1)
+ printf("mpc512x_fec_init... Done \n");
+#endif
+ return 1;
+}
+
+/********************************************************************/
+int mpc512x_fec_init_phy (struct eth_device *dev, bd_t * bis)
+{
+ mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
+ const u8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */
+ int timeout = 1;
+ u16 phyStatus;
+
+#if (DEBUG & 0x1)
+ printf ("mpc512x_fec_init_phy... Begin\n");
+#endif
+
+ /*
+ * Clear FEC-Lite interrupt event register(IEVENT)
+ */
+ out_be32(&fec->eth->ievent, 0xffffffff);
+
+ /*
+ * Set interrupt mask register
+ */
+ out_be32(&fec->eth->imask, 0x00000000);
+
+ if (fec->xcv_type != SEVENWIRE) {
+ /*
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+ * and do not drop the Preamble.
+ */
+ out_be32(&fec->eth->mii_speed,
+ (((gd->arch.ips_clk / 1000000) / 5) + 1) << 1);
+
+ /*
+ * Reset PHY, then delay 300ns
+ */
+ miiphy_write (dev->name, phyAddr, 0x0, 0x8000);
+ udelay (1000);
+
+ if (fec->xcv_type == MII10) {
+ /*
+ * Force 10Base-T, FDX operation
+ */
+#if (DEBUG & 0x2)
+ printf ("Forcing 10 Mbps ethernet link... ");
+#endif
+ miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+
+ miiphy_write (dev->name, phyAddr, 0x0, 0x0180);
+
+ timeout = 20;
+ do { /* wait for link status to go down */
+ udelay (10000);
+ if ((timeout--) == 0) {
+#if (DEBUG & 0x2)
+ printf ("hmmm, should not have waited...");
+#endif
+ break;
+ }
+ miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+#if (DEBUG & 0x2)
+ printf ("=");
+#endif
+ } while ((phyStatus & 0x0004)); /* !link up */
+
+ timeout = 1000;
+ do { /* wait for link status to come back up */
+ udelay (10000);
+ if ((timeout--) == 0) {
+ printf ("failed. Link is down.\n");
+ break;
+ }
+ miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+#if (DEBUG & 0x2)
+ printf ("+");
+#endif
+ } while (!(phyStatus & 0x0004)); /* !link up */
+
+#if (DEBUG & 0x2)
+ printf ("done.\n");
+#endif
+ } else { /* MII100 */
+ /*
+ * Set the auto-negotiation advertisement register bits
+ */
+ miiphy_write (dev->name, phyAddr, 0x4, 0x01e1);
+
+ /*
+ * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
+ */
+ miiphy_write (dev->name, phyAddr, 0x0, 0x1200);
+
+ /*
+ * Wait for AN completion
+ */
+ timeout = 2500;
+ do {
+ udelay (1000);
+
+ if ((timeout--) == 0) {
+#if (DEBUG & 0x2)
+ printf ("PHY auto neg 0 failed...\n");
+#endif
+ return -1;
+ }
+
+ if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) != 0) {
+#if (DEBUG & 0x2)
+ printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
+#endif
+ return -1;
+ }
+ } while (!(phyStatus & 0x0004));
+
+#if (DEBUG & 0x2)
+ printf ("PHY auto neg complete! \n");
+#endif
+ }
+ }
+
+#if (DEBUG & 0x2)
+ if (fec->xcv_type != SEVENWIRE)
+ mpc512x_fec_phydump (dev->name);
+#endif
+
+#if (DEBUG & 0x1)
+ printf ("mpc512x_fec_init_phy... Done \n");
+#endif
+ return 1;
+}
+
+/********************************************************************/
+static void mpc512x_fec_halt (struct eth_device *dev)
+{
+ mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
+ int counter = 0xffff;
+
+#if (DEBUG & 0x2)
+ if (fec->xcv_type != SEVENWIRE)
+ mpc512x_fec_phydump (dev->name);
+#endif
+
+ /*
+ * mask FEC chip interrupts
+ */
+ out_be32(&fec->eth->imask, 0);
+
+ /*
+ * issue graceful stop command to the FEC transmitter if necessary
+ */
+ setbits_be32(&fec->eth->x_cntrl, 0x00000001);
+
+ /*
+ * wait for graceful stop to register
+ */
+ while ((counter--) && (!(in_be32(&fec->eth->ievent) & 0x10000000)))
+ ;
+
+ /*
+ * Disable the Ethernet Controller
+ */
+ clrbits_be32(&fec->eth->ecntrl, 0x00000002);
+
+ /*
+ * Issue a reset command to the FEC chip
+ */
+ setbits_be32(&fec->eth->ecntrl, 0x1);
+
+ /*
+ * wait at least 16 clock cycles
+ */
+ udelay (10);
+#if (DEBUG & 0x3)
+ printf ("Ethernet task stopped\n");
+#endif
+}
+
+/********************************************************************/
+
+static int mpc512x_fec_send(struct eth_device *dev, void *eth_data,
+ int data_length)
+{
+ /*
+ * This routine transmits one frame. This routine only accepts
+ * 6-byte Ethernet addresses.
+ */
+ mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
+ volatile FEC_TBD *pTbd;
+
+#if (DEBUG & 0x20)
+ printf("tbd status: 0x%04x\n", fec->tbdBase[fec->tbdIndex].status);
+#endif
+
+ /*
+ * Clear Tx BD ring at first
+ */
+ mpc512x_fec_tbd_scrub (fec);
+
+ /*
+ * Check for valid length of data.
+ */
+ if ((data_length > 1500) || (data_length <= 0)) {
+ return -1;
+ }
+
+ /*
+ * Check the number of vacant TxBDs.
+ */
+ if (fec->cleanTbdNum < 1) {
+#if (DEBUG & 0x20)
+ printf ("No available TxBDs ...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * Get the first TxBD to send the mac header
+ */
+ pTbd = &fec->bdBase->tbd[fec->tbdIndex];
+ pTbd->dataLength = data_length;
+ pTbd->dataPointer = (u32)eth_data;
+ pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+ fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
+
+ /* Activate transmit Buffer Descriptor polling */
+ out_be32(&fec->eth->x_des_active, 0x01000000);
+
+#if (DEBUG & 0x8)
+ printf ( "+" );
+#endif
+
+ fec->cleanTbdNum -= 1;
+
+ /*
+ * wait until frame is sent .
+ */
+ while (pTbd->status & FEC_TBD_READY) {
+ udelay (10);
+#if (DEBUG & 0x8)
+ printf ("TDB status = %04x\n", pTbd->status);
+#endif
+ }
+
+ return 0;
+}
+
+
+/********************************************************************/
+static int mpc512x_fec_recv (struct eth_device *dev)
+{
+ /*
+ * This command pulls one frame from the card
+ */
+ mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
+ volatile FEC_RBD *pRbd = &fec->bdBase->rbd[fec->rbdIndex];
+ unsigned long ievent;
+ int frame_length = 0;
+
+#if (DEBUG & 0x1)
+ printf ("mpc512x_fec_recv %d Start...\n", fec->rbdIndex);
+#endif
+#if (DEBUG & 0x8)
+ printf( "-" );
+#endif
+
+ /*
+ * Check if any critical events have happened
+ */
+ ievent = in_be32(&fec->eth->ievent);
+ out_be32(&fec->eth->ievent, ievent);
+ if (ievent & 0x20060000) {
+ /* BABT, Rx/Tx FIFO errors */
+ mpc512x_fec_halt (dev);
+ mpc512x_fec_init (dev, NULL);
+ return 0;
+ }
+ if (ievent & 0x80000000) {
+ /* Heartbeat error */
+ setbits_be32(&fec->eth->x_cntrl, 0x00000001);
+ }
+ if (ievent & 0x10000000) {
+ /* Graceful stop complete */
+ if (in_be32(&fec->eth->x_cntrl) & 0x00000001) {
+ mpc512x_fec_halt (dev);
+ clrbits_be32(&fec->eth->x_cntrl, 0x00000001);;
+ mpc512x_fec_init (dev, NULL);
+ }
+ }
+
+ if (!(pRbd->status & FEC_RBD_EMPTY)) {
+ if (!(pRbd->status & FEC_RBD_ERR) &&
+ ((pRbd->dataLength - 4) > 14)) {
+
+ /*
+ * Get buffer size
+ */
+ if (pRbd->status & FEC_RBD_LAST)
+ frame_length = pRbd->dataLength - 4;
+ else
+ frame_length = pRbd->dataLength;
+#if (DEBUG & 0x20)
+ {
+ int i;
+ printf ("recv data length 0x%08x data hdr: ",
+ pRbd->dataLength);
+ for (i = 0; i < 14; i++)
+ printf ("%x ", *((u8*)pRbd->dataPointer + i));
+ printf("\n");
+ }
+#endif
+ /*
+ * Fill the buffer and pass it to upper layers
+ */
+ memcpy (&rx_buff[rx_buff_idx], (void*)pRbd->dataPointer,
+ frame_length - rx_buff_idx);
+ rx_buff_idx = frame_length;
+
+ if (pRbd->status & FEC_RBD_LAST) {
+ NetReceive ((uchar*)rx_buff, frame_length);
+ rx_buff_idx = 0;
+ }
+ }
+
+ /*
+ * Reset buffer descriptor as empty
+ */
+ mpc512x_fec_rbd_clean (fec, pRbd);
+ }
+
+ /* Try to fill Buffer Descriptors */
+ out_be32(&fec->eth->r_des_active, 0x01000000);
+
+ return frame_length;
+}
+
+/********************************************************************/
+int mpc512x_fec_initialize (bd_t * bis)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ mpc512x_fec_priv *fec;
+ struct eth_device *dev;
+ void * bd;
+
+ fec = (mpc512x_fec_priv *) malloc (sizeof(*fec));
+ dev = (struct eth_device *) malloc (sizeof(*dev));
+ memset (dev, 0, sizeof *dev);
+
+ fec->eth = &im->fec;
+
+# ifndef CONFIG_FEC_10MBIT
+ fec->xcv_type = MII100;
+# else
+ fec->xcv_type = MII10;
+# endif
+ dev->priv = (void *)fec;
+ dev->iobase = (int)&im->fec;
+ dev->init = mpc512x_fec_init;
+ dev->halt = mpc512x_fec_halt;
+ dev->send = mpc512x_fec_send;
+ dev->recv = mpc512x_fec_recv;
+
+ sprintf (dev->name, "FEC");
+ eth_register (dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register (dev->name,
+ fec512x_miiphy_read, fec512x_miiphy_write);
+#endif
+
+ /* Clean up space FEC's MIB and FIFO RAM ...*/
+ memset ((void *)&im->fec.mib, 0x00, sizeof(im->fec.mib));
+ memset ((void *)&im->fec.fifo, 0x00, sizeof(im->fec.fifo));
+
+ /*
+ * Malloc space for BDs (must be quad word-aligned)
+ * this pointer is lost, so cannot be freed
+ */
+ bd = malloc (sizeof(mpc512x_buff_descs) + 0x1f);
+ fec->bdBase = (mpc512x_buff_descs*)((u32)bd & 0xfffffff0);
+ memset ((void *) bd, 0x00, sizeof(mpc512x_buff_descs) + 0x1f);
+
+ /*
+ * Set interrupt mask register
+ */
+ out_be32(&fec->eth->imask, 0x00000000);
+
+ /*
+ * Clear FEC-Lite interrupt event register(IEVENT)
+ */
+ out_be32(&fec->eth->ievent, 0xffffffff);
+
+ return 1;
+}
+
+/* MII-interface related functions */
+/********************************************************************/
+int fec512x_miiphy_read(const char *devname, u8 phyAddr, u8 regAddr, u16 *retVal)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile fec512x_t *eth = &im->fec;
+ u32 reg; /* convenient holder for the PHY register */
+ u32 phy; /* convenient holder for the PHY */
+ int timeout = 0xffff;
+
+ /*
+ * reading from any PHY's register is done by properly
+ * programming the FEC's MII data register.
+ */
+ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+ out_be32(&eth->mii_data, FEC_MII_DATA_ST |
+ FEC_MII_DATA_OP_RD |
+ FEC_MII_DATA_TA |
+ phy | reg);
+
+ /*
+ * wait for the related interrupt
+ */
+ while ((timeout--) && (!(in_be32(&eth->ievent) & 0x00800000)))
+ ;
+
+ if (timeout == 0) {
+#if (DEBUG & 0x2)
+ printf ("Read MDIO failed...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * clear mii interrupt bit
+ */
+ out_be32(&eth->ievent, 0x00800000);
+
+ /*
+ * it's now safe to read the PHY's register
+ */
+ *retVal = (u16) in_be32(&eth->mii_data);
+
+ return 0;
+}
+
+/********************************************************************/
+int fec512x_miiphy_write(const char *devname, u8 phyAddr, u8 regAddr, u16 data)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile fec512x_t *eth = &im->fec;
+ u32 reg; /* convenient holder for the PHY register */
+ u32 phy; /* convenient holder for the PHY */
+ int timeout = 0xffff;
+
+ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+ out_be32(&eth->mii_data, FEC_MII_DATA_ST |
+ FEC_MII_DATA_OP_WR |
+ FEC_MII_DATA_TA |
+ phy | reg | data);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while ((timeout--) && (!(in_be32(&eth->ievent) & 0x00800000)))
+ ;
+
+ if (timeout == 0) {
+#if (DEBUG & 0x2)
+ printf ("Write MDIO failed...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * clear MII interrupt bit
+ */
+ out_be32(&eth->ievent, 0x00800000);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/mpc512x_fec.h b/qemu/roms/u-boot/drivers/net/mpc512x_fec.h
new file mode 100644
index 000000000..a083cca2f
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/mpc512x_fec.h
@@ -0,0 +1,98 @@
+/*
+ * (C) Copyright 2003 - 2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Derived from the MPC8xx driver's header file.
+ */
+
+#ifndef __MPC512X_FEC_H
+#define __MPC512X_FEC_H
+
+#include <common.h>
+
+/* Receive & Transmit Buffer Descriptor definitions */
+typedef struct BufferDescriptor {
+ u16 status;
+ u16 dataLength;
+ u32 dataPointer;
+} FEC_RBD;
+
+typedef struct {
+ u16 status;
+ u16 dataLength;
+ u32 dataPointer;
+} FEC_TBD;
+
+/* private structure */
+typedef enum {
+ SEVENWIRE, /* 7-wire */
+ MII10, /* MII 10Mbps */
+ MII100 /* MII 100Mbps */
+} xceiver_type;
+
+/* BD Numer definitions */
+#define FEC_TBD_NUM 48 /* The user can adjust this value */
+#define FEC_RBD_NUM 32 /* The user can adjust this value */
+
+/* packet size limit */
+#define FEC_MAX_FRAME_LEN 1522 /* recommended default value */
+
+/* Buffer size must be evenly divisible by 16 */
+#define FEC_BUFFER_SIZE ((FEC_MAX_FRAME_LEN + 0x10) & (~0xf))
+
+typedef struct {
+ u8 frame[FEC_BUFFER_SIZE];
+} mpc512x_frame;
+
+typedef struct {
+ FEC_RBD rbd[FEC_RBD_NUM]; /* RBD ring */
+ FEC_TBD tbd[FEC_TBD_NUM]; /* TBD ring */
+ mpc512x_frame recv_frames[FEC_RBD_NUM]; /* receive buff */
+} mpc512x_buff_descs;
+
+typedef struct {
+ volatile fec512x_t *eth;
+ xceiver_type xcv_type; /* transceiver type */
+ mpc512x_buff_descs *bdBase; /* BD rings and recv buffer */
+ u16 rbdIndex; /* next receive BD to read */
+ u16 tbdIndex; /* next transmit BD to send */
+ u16 usedTbdIndex; /* next transmit BD to clean */
+ u16 cleanTbdNum; /* the number of available transmit BDs */
+} mpc512x_fec_priv;
+
+/* RBD bits definitions */
+#define FEC_RBD_EMPTY 0x8000 /* Buffer is empty */
+#define FEC_RBD_WRAP 0x2000 /* Last BD in ring */
+#define FEC_RBD_LAST 0x0800 /* Buffer is last in frame(useless) */
+#define FEC_RBD_MISS 0x0100 /* Miss bit for prom mode */
+#define FEC_RBD_BC 0x0080 /* The received frame is broadcast frame */
+#define FEC_RBD_MC 0x0040 /* The received frame is multicast frame */
+#define FEC_RBD_LG 0x0020 /* Frame length violation */
+#define FEC_RBD_NO 0x0010 /* Nonoctet align frame */
+#define FEC_RBD_SH 0x0008 /* Short frame */
+#define FEC_RBD_CR 0x0004 /* CRC error */
+#define FEC_RBD_OV 0x0002 /* Receive FIFO overrun */
+#define FEC_RBD_TR 0x0001 /* Frame is truncated */
+#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+ FEC_RBD_OV | FEC_RBD_TR)
+
+/* TBD bits definitions */
+#define FEC_TBD_READY 0x8000 /* Buffer is ready */
+#define FEC_TBD_WRAP 0x2000 /* Last BD in ring */
+#define FEC_TBD_LAST 0x0800 /* Buffer is last in frame */
+#define FEC_TBD_TC 0x0400 /* Transmit the CRC */
+#define FEC_TBD_ABC 0x0200 /* Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST 0x40000000 /* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform a read operation */
+#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register field mask */
+#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
+#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */
+
+#endif /* __MPC512X_FEC_H */
diff --git a/qemu/roms/u-boot/drivers/net/mpc5xxx_fec.c b/qemu/roms/u-boot/drivers/net/mpc5xxx_fec.c
new file mode 100644
index 000000000..1093ba59d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/mpc5xxx_fec.c
@@ -0,0 +1,1027 @@
+/*
+ * (C) Copyright 2003-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.c,
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+#include <mpc5xxx_sdma.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include "mpc5xxx_fec.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* #define DEBUG 0x28 */
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#if (DEBUG & 0x60)
+static void tfifo_print(char *devname, mpc5xxx_fec_priv *fec);
+static void rfifo_print(char *devname, mpc5xxx_fec_priv *fec);
+#endif /* DEBUG */
+
+typedef struct {
+ uint8 data[1500]; /* actual data */
+ int length; /* actual length */
+ int used; /* buffer in use or not */
+ uint8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */
+} NBUF;
+
+int fec5xxx_miiphy_read(const char *devname, uint8 phyAddr, uint8 regAddr, uint16 *retVal);
+int fec5xxx_miiphy_write(const char *devname, uint8 phyAddr, uint8 regAddr, uint16 data);
+
+static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis);
+
+/********************************************************************/
+#if (DEBUG & 0x2)
+static void mpc5xxx_fec_phydump (char *devname)
+{
+ uint16 phyStatus, i;
+ uint8 phyAddr = CONFIG_PHY_ADDR;
+ uint8 reg_mask[] = {
+#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */
+ /* regs to print: 0...7, 16...19, 21, 23, 24 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+#else
+ /* regs to print: 0...8, 16...20 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+ };
+
+ for (i = 0; i < 32; i++) {
+ if (reg_mask[i]) {
+ miiphy_read(devname, phyAddr, i, &phyStatus);
+ printf("Mii reg %d: 0x%04x\n", i, phyStatus);
+ }
+ }
+}
+#endif
+
+/********************************************************************/
+static int mpc5xxx_fec_rbd_init(mpc5xxx_fec_priv *fec)
+{
+ int ix;
+ char *data;
+ static int once = 0;
+
+ for (ix = 0; ix < FEC_RBD_NUM; ix++) {
+ if (!once) {
+ data = (char *)malloc(FEC_MAX_PKT_SIZE);
+ if (data == NULL) {
+ printf ("RBD INIT FAILED\n");
+ return -1;
+ }
+ fec->rbdBase[ix].dataPointer = (uint32)data;
+ }
+ fec->rbdBase[ix].status = FEC_RBD_EMPTY;
+ fec->rbdBase[ix].dataLength = 0;
+ }
+ once ++;
+
+ /*
+ * have the last RBD to close the ring
+ */
+ fec->rbdBase[ix - 1].status |= FEC_RBD_WRAP;
+ fec->rbdIndex = 0;
+
+ return 0;
+}
+
+/********************************************************************/
+static void mpc5xxx_fec_tbd_init(mpc5xxx_fec_priv *fec)
+{
+ int ix;
+
+ for (ix = 0; ix < FEC_TBD_NUM; ix++) {
+ fec->tbdBase[ix].status = 0;
+ }
+
+ /*
+ * Have the last TBD to close the ring
+ */
+ fec->tbdBase[ix - 1].status |= FEC_TBD_WRAP;
+
+ /*
+ * Initialize some indices
+ */
+ fec->tbdIndex = 0;
+ fec->usedTbdIndex = 0;
+ fec->cleanTbdNum = FEC_TBD_NUM;
+}
+
+/********************************************************************/
+static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, volatile FEC_RBD * pRbd)
+{
+ /*
+ * Reset buffer descriptor as empty
+ */
+ if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
+ pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
+ else
+ pRbd->status = FEC_RBD_EMPTY;
+
+ pRbd->dataLength = 0;
+
+ /*
+ * Now, we have an empty RxBD, restart the SmartDMA receive task
+ */
+ SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
+
+ /*
+ * Increment BD count
+ */
+ fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
+}
+
+/********************************************************************/
+static void mpc5xxx_fec_tbd_scrub(mpc5xxx_fec_priv *fec)
+{
+ volatile FEC_TBD *pUsedTbd;
+
+#if (DEBUG & 0x1)
+ printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
+ fec->cleanTbdNum, fec->usedTbdIndex);
+#endif
+
+ /*
+ * process all the consumed TBDs
+ */
+ while (fec->cleanTbdNum < FEC_TBD_NUM) {
+ pUsedTbd = &fec->tbdBase[fec->usedTbdIndex];
+ if (pUsedTbd->status & FEC_TBD_READY) {
+#if (DEBUG & 0x20)
+ printf("Cannot clean TBD %d, in use\n", fec->cleanTbdNum);
+#endif
+ return;
+ }
+
+ /*
+ * clean this buffer descriptor
+ */
+ if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
+ pUsedTbd->status = FEC_TBD_WRAP;
+ else
+ pUsedTbd->status = 0;
+
+ /*
+ * update some indeces for a correct handling of the TBD ring
+ */
+ fec->cleanTbdNum++;
+ fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
+ }
+}
+
+/********************************************************************/
+static void mpc5xxx_fec_set_hwaddr(mpc5xxx_fec_priv *fec, char *mac)
+{
+ uint8 currByte; /* byte for which to compute the CRC */
+ int byte; /* loop - counter */
+ int bit; /* loop - counter */
+ uint32 crc = 0xffffffff; /* initial value */
+
+ /*
+ * The algorithm used is the following:
+ * we loop on each of the six bytes of the provided address,
+ * and we compute the CRC by left-shifting the previous
+ * value by one position, so that each bit in the current
+ * byte of the address may contribute the calculation. If
+ * the latter and the MSB in the CRC are different, then
+ * the CRC value so computed is also ex-ored with the
+ * "polynomium generator". The current byte of the address
+ * is also shifted right by one bit at each iteration.
+ * This is because the CRC generatore in hardware is implemented
+ * as a shift-register with as many ex-ores as the radixes
+ * in the polynomium. This suggests that we represent the
+ * polynomiumm itself as a 32-bit constant.
+ */
+ for (byte = 0; byte < 6; byte++) {
+ currByte = mac[byte];
+ for (bit = 0; bit < 8; bit++) {
+ if ((currByte & 0x01) ^ (crc & 0x01)) {
+ crc >>= 1;
+ crc = crc ^ 0xedb88320;
+ } else {
+ crc >>= 1;
+ }
+ currByte >>= 1;
+ }
+ }
+
+ crc = crc >> 26;
+
+ /*
+ * Set individual hash table register
+ */
+ if (crc >= 32) {
+ fec->eth->iaddr1 = (1 << (crc - 32));
+ fec->eth->iaddr2 = 0;
+ } else {
+ fec->eth->iaddr1 = 0;
+ fec->eth->iaddr2 = (1 << crc);
+ }
+
+ /*
+ * Set physical address
+ */
+ fec->eth->paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
+ fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
+}
+
+/********************************************************************/
+static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
+{
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
+ struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
+
+#if (DEBUG & 0x1)
+ printf ("mpc5xxx_fec_init... Begin\n");
+#endif
+
+ mpc5xxx_fec_init_phy(dev, bis);
+
+ /*
+ * Call board-specific PHY fixups (if any)
+ */
+#ifdef CONFIG_RESET_PHY_R
+ reset_phy();
+#endif
+
+ /*
+ * Initialize RxBD/TxBD rings
+ */
+ mpc5xxx_fec_rbd_init(fec);
+ mpc5xxx_fec_tbd_init(fec);
+
+ /*
+ * Clear FEC-Lite interrupt event register(IEVENT)
+ */
+ fec->eth->ievent = 0xffffffff;
+
+ /*
+ * Set interrupt mask register
+ */
+ fec->eth->imask = 0x00000000;
+
+ /*
+ * Set FEC-Lite receive control register(R_CNTRL):
+ */
+ if (fec->xcv_type == SEVENWIRE) {
+ /*
+ * Frame length=1518; 7-wire mode
+ */
+ fec->eth->r_cntrl = 0x05ee0020; /*0x05ee0000;FIXME */
+ } else {
+ /*
+ * Frame length=1518; MII mode;
+ */
+ fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */
+ }
+
+ fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */
+
+ /*
+ * Set Opcode/Pause Duration Register
+ */
+ fec->eth->op_pause = 0x00010020; /*FIXME 0xffff0020; */
+
+ /*
+ * Set Rx FIFO alarm and granularity value
+ */
+ fec->eth->rfifo_cntrl = 0x0c000000
+ | (fec->eth->rfifo_cntrl & ~0x0f000000);
+ fec->eth->rfifo_alarm = 0x0000030c;
+#if (DEBUG & 0x22)
+ if (fec->eth->rfifo_status & 0x00700000 ) {
+ printf("mpc5xxx_fec_init() RFIFO error\n");
+ }
+#endif
+
+ /*
+ * Set Tx FIFO granularity value
+ */
+ fec->eth->tfifo_cntrl = 0x0c000000
+ | (fec->eth->tfifo_cntrl & ~0x0f000000);
+#if (DEBUG & 0x2)
+ printf("tfifo_status: 0x%08x\n", fec->eth->tfifo_status);
+ printf("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm);
+#endif
+
+ /*
+ * Set transmit fifo watermark register(X_WMRK), default = 64
+ */
+ fec->eth->tfifo_alarm = 0x00000080;
+ fec->eth->x_wmrk = 0x2;
+
+ /*
+ * Set individual address filter for unicast address
+ * and set physical address registers.
+ */
+ mpc5xxx_fec_set_hwaddr(fec, (char *)dev->enetaddr);
+
+ /*
+ * Set multicast address filter
+ */
+ fec->eth->gaddr1 = 0x00000000;
+ fec->eth->gaddr2 = 0x00000000;
+
+ /*
+ * Turn ON cheater FSM: ????
+ */
+ fec->eth->xmit_fsm = 0x03000000;
+
+ /*
+ * Turn off COMM bus prefetch in the MPC5200 BestComm. It doesn't
+ * work w/ the current receive task.
+ */
+ sdma->PtdCntrl |= 0x00000001;
+
+ /*
+ * Set priority of different initiators
+ */
+ sdma->IPR0 = 7; /* always */
+ sdma->IPR3 = 6; /* Eth RX */
+ sdma->IPR4 = 5; /* Eth Tx */
+
+ /*
+ * Clear SmartDMA task interrupt pending bits
+ */
+ SDMA_CLEAR_IEVENT(FEC_RECV_TASK_NO);
+
+ /*
+ * Initialize SmartDMA parameters stored in SRAM
+ */
+ *(volatile int *)FEC_TBD_BASE = (int)fec->tbdBase;
+ *(volatile int *)FEC_RBD_BASE = (int)fec->rbdBase;
+ *(volatile int *)FEC_TBD_NEXT = (int)fec->tbdBase;
+ *(volatile int *)FEC_RBD_NEXT = (int)fec->rbdBase;
+
+ /*
+ * Enable FEC-Lite controller
+ */
+ fec->eth->ecntrl |= 0x00000006;
+
+#if (DEBUG & 0x2)
+ if (fec->xcv_type != SEVENWIRE)
+ mpc5xxx_fec_phydump (dev->name);
+#endif
+
+ /*
+ * Enable SmartDMA receive task
+ */
+ SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
+
+#if (DEBUG & 0x1)
+ printf("mpc5xxx_fec_init... Done \n");
+#endif
+
+ return 1;
+}
+
+/********************************************************************/
+static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis)
+{
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
+ const uint8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */
+ static int initialized = 0;
+
+ if(initialized)
+ return 0;
+ initialized = 1;
+
+#if (DEBUG & 0x1)
+ printf ("mpc5xxx_fec_init_phy... Begin\n");
+#endif
+
+ /*
+ * Initialize GPIO pins
+ */
+ if (fec->xcv_type == SEVENWIRE) {
+ /* 10MBit with 7-wire operation */
+#if defined(CONFIG_TOTAL5200)
+ /* 7-wire and USB2 on Ethernet */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00030000;
+#else /* !CONFIG_TOTAL5200 */
+ /* 7-wire only */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00020000;
+#endif /* CONFIG_TOTAL5200 */
+ } else {
+ /* 100MBit with MD operation */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00050000;
+ }
+
+ /*
+ * Clear FEC-Lite interrupt event register(IEVENT)
+ */
+ fec->eth->ievent = 0xffffffff;
+
+ /*
+ * Set interrupt mask register
+ */
+ fec->eth->imask = 0x00000000;
+
+/*
+ * In original Promess-provided code PHY initialization is disabled with the
+ * following comment: "Phy initialization is DISABLED for now. There was a
+ * problem with running 100 Mbps on PRO board". Thus we temporarily disable
+ * PHY initialization for the Motion-PRO board, until a proper fix is found.
+ */
+
+ if (fec->xcv_type != SEVENWIRE) {
+ /*
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+ * and do not drop the Preamble.
+ * No MII for 7-wire mode
+ */
+ fec->eth->mii_speed = (((gd->arch.ipb_clk >> 20) / 5) << 1);
+ }
+
+ if (fec->xcv_type != SEVENWIRE) {
+ /*
+ * Initialize PHY(LXT971A):
+ *
+ * Generally, on power up, the LXT971A reads its configuration
+ * pins to check for forced operation, If not cofigured for
+ * forced operation, it uses auto-negotiation/parallel detection
+ * to automatically determine line operating conditions.
+ * If the PHY device on the other side of the link supports
+ * auto-negotiation, the LXT971A auto-negotiates with it
+ * using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
+ * support auto-negotiation, the LXT971A automatically detects
+ * the presence of either link pulses(10Mbps PHY) or Idle
+ * symbols(100Mbps) and sets its operating conditions accordingly.
+ *
+ * When auto-negotiation is controlled by software, the following
+ * steps are recommended.
+ *
+ * Note:
+ * The physical address is dependent on hardware configuration.
+ *
+ */
+ int timeout = 1;
+ uint16 phyStatus;
+
+ /*
+ * Reset PHY, then delay 300ns
+ */
+ miiphy_write(dev->name, phyAddr, 0x0, 0x8000);
+ udelay(1000);
+
+#if defined(CONFIG_UC101) || defined(CONFIG_MUCMC52)
+ /* Set the LED configuration Register for the UC101
+ and MUCMC52 Board */
+ miiphy_write(dev->name, phyAddr, 0x14, 0x4122);
+#endif
+ if (fec->xcv_type == MII10) {
+ /*
+ * Force 10Base-T, FDX operation
+ */
+#if (DEBUG & 0x2)
+ printf("Forcing 10 Mbps ethernet link... ");
+#endif
+ miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
+ /*
+ miiphy_write(dev->name, fec, phyAddr, 0x0, 0x0100);
+ */
+ miiphy_write(dev->name, phyAddr, 0x0, 0x0180);
+
+ timeout = 20;
+ do { /* wait for link status to go down */
+ udelay(10000);
+ if ((timeout--) == 0) {
+#if (DEBUG & 0x2)
+ printf("hmmm, should not have waited...");
+#endif
+ break;
+ }
+ miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
+#if (DEBUG & 0x2)
+ printf("=");
+#endif
+ } while ((phyStatus & 0x0004)); /* !link up */
+
+ timeout = 1000;
+ do { /* wait for link status to come back up */
+ udelay(10000);
+ if ((timeout--) == 0) {
+ printf("failed. Link is down.\n");
+ break;
+ }
+ miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
+#if (DEBUG & 0x2)
+ printf("+");
+#endif
+ } while (!(phyStatus & 0x0004)); /* !link up */
+
+#if (DEBUG & 0x2)
+ printf ("done.\n");
+#endif
+ } else { /* MII100 */
+ /*
+ * Set the auto-negotiation advertisement register bits
+ */
+ miiphy_write(dev->name, phyAddr, 0x4, 0x01e1);
+
+ /*
+ * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
+ */
+ miiphy_write(dev->name, phyAddr, 0x0, 0x1200);
+
+ /*
+ * Wait for AN completion
+ */
+ timeout = 5000;
+ do {
+ udelay(1000);
+
+ if ((timeout--) == 0) {
+#if (DEBUG & 0x2)
+ printf("PHY auto neg 0 failed...\n");
+#endif
+ return -1;
+ }
+
+ if (miiphy_read(dev->name, phyAddr, 0x1, &phyStatus) != 0) {
+#if (DEBUG & 0x2)
+ printf("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
+#endif
+ return -1;
+ }
+ } while (!(phyStatus & 0x0004));
+
+#if (DEBUG & 0x2)
+ printf("PHY auto neg complete! \n");
+#endif
+ }
+
+ }
+
+#if (DEBUG & 0x2)
+ if (fec->xcv_type != SEVENWIRE)
+ mpc5xxx_fec_phydump (dev->name);
+#endif
+
+
+#if (DEBUG & 0x1)
+ printf("mpc5xxx_fec_init_phy... Done \n");
+#endif
+
+ return 1;
+}
+
+/********************************************************************/
+static void mpc5xxx_fec_halt(struct eth_device *dev)
+{
+ struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
+ int counter = 0xffff;
+
+#if (DEBUG & 0x2)
+ if (fec->xcv_type != SEVENWIRE)
+ mpc5xxx_fec_phydump (dev->name);
+#endif
+
+ /*
+ * mask FEC chip interrupts
+ */
+ fec->eth->imask = 0;
+
+ /*
+ * issue graceful stop command to the FEC transmitter if necessary
+ */
+ fec->eth->x_cntrl |= 0x00000001;
+
+ /*
+ * wait for graceful stop to register
+ */
+ while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ;
+
+ /*
+ * Disable SmartDMA tasks
+ */
+ SDMA_TASK_DISABLE (FEC_XMIT_TASK_NO);
+ SDMA_TASK_DISABLE (FEC_RECV_TASK_NO);
+
+ /*
+ * Turn on COMM bus prefetch in the MPC5200 BestComm after we're
+ * done. It doesn't work w/ the current receive task.
+ */
+ sdma->PtdCntrl &= ~0x00000001;
+
+ /*
+ * Disable the Ethernet Controller
+ */
+ fec->eth->ecntrl &= 0xfffffffd;
+
+ /*
+ * Clear FIFO status registers
+ */
+ fec->eth->rfifo_status &= 0x00700000;
+ fec->eth->tfifo_status &= 0x00700000;
+
+ fec->eth->reset_cntrl = 0x01000000;
+
+ /*
+ * Issue a reset command to the FEC chip
+ */
+ fec->eth->ecntrl |= 0x1;
+
+ /*
+ * wait at least 16 clock cycles
+ */
+ udelay(10);
+
+ /* don't leave the MII speed set to zero */
+ if (fec->xcv_type != SEVENWIRE) {
+ /*
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+ * and do not drop the Preamble.
+ * No MII for 7-wire mode
+ */
+ fec->eth->mii_speed = (((gd->arch.ipb_clk >> 20) / 5) << 1);
+ }
+
+#if (DEBUG & 0x3)
+ printf("Ethernet task stopped\n");
+#endif
+}
+
+#if (DEBUG & 0x60)
+/********************************************************************/
+
+static void tfifo_print(char *devname, mpc5xxx_fec_priv *fec)
+{
+ uint16 phyAddr = CONFIG_PHY_ADDR;
+ uint16 phyStatus;
+
+ if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr)
+ || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) {
+
+ miiphy_read(devname, phyAddr, 0x1, &phyStatus);
+ printf("\nphyStatus: 0x%04x\n", phyStatus);
+ printf("ecntrl: 0x%08x\n", fec->eth->ecntrl);
+ printf("ievent: 0x%08x\n", fec->eth->ievent);
+ printf("x_status: 0x%08x\n", fec->eth->x_status);
+ printf("tfifo: status 0x%08x\n", fec->eth->tfifo_status);
+
+ printf(" control 0x%08x\n", fec->eth->tfifo_cntrl);
+ printf(" lrfp 0x%08x\n", fec->eth->tfifo_lrf_ptr);
+ printf(" lwfp 0x%08x\n", fec->eth->tfifo_lwf_ptr);
+ printf(" alarm 0x%08x\n", fec->eth->tfifo_alarm);
+ printf(" readptr 0x%08x\n", fec->eth->tfifo_rdptr);
+ printf(" writptr 0x%08x\n", fec->eth->tfifo_wrptr);
+ }
+}
+
+static void rfifo_print(char *devname, mpc5xxx_fec_priv *fec)
+{
+ uint16 phyAddr = CONFIG_PHY_ADDR;
+ uint16 phyStatus;
+
+ if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr)
+ || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) {
+
+ miiphy_read(devname, phyAddr, 0x1, &phyStatus);
+ printf("\nphyStatus: 0x%04x\n", phyStatus);
+ printf("ecntrl: 0x%08x\n", fec->eth->ecntrl);
+ printf("ievent: 0x%08x\n", fec->eth->ievent);
+ printf("x_status: 0x%08x\n", fec->eth->x_status);
+ printf("rfifo: status 0x%08x\n", fec->eth->rfifo_status);
+
+ printf(" control 0x%08x\n", fec->eth->rfifo_cntrl);
+ printf(" lrfp 0x%08x\n", fec->eth->rfifo_lrf_ptr);
+ printf(" lwfp 0x%08x\n", fec->eth->rfifo_lwf_ptr);
+ printf(" alarm 0x%08x\n", fec->eth->rfifo_alarm);
+ printf(" readptr 0x%08x\n", fec->eth->rfifo_rdptr);
+ printf(" writptr 0x%08x\n", fec->eth->rfifo_wrptr);
+ }
+}
+#endif /* DEBUG */
+
+/********************************************************************/
+
+static int mpc5xxx_fec_send(struct eth_device *dev, void *eth_data,
+ int data_length)
+{
+ /*
+ * This routine transmits one frame. This routine only accepts
+ * 6-byte Ethernet addresses.
+ */
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
+ volatile FEC_TBD *pTbd;
+
+#if (DEBUG & 0x20)
+ printf("tbd status: 0x%04x\n", fec->tbdBase[0].status);
+ tfifo_print(dev->name, fec);
+#endif
+
+ /*
+ * Clear Tx BD ring at first
+ */
+ mpc5xxx_fec_tbd_scrub(fec);
+
+ /*
+ * Check for valid length of data.
+ */
+ if ((data_length > 1500) || (data_length <= 0)) {
+ return -1;
+ }
+
+ /*
+ * Check the number of vacant TxBDs.
+ */
+ if (fec->cleanTbdNum < 1) {
+#if (DEBUG & 0x20)
+ printf("No available TxBDs ...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * Get the first TxBD to send the mac header
+ */
+ pTbd = &fec->tbdBase[fec->tbdIndex];
+ pTbd->dataLength = data_length;
+ pTbd->dataPointer = (uint32)eth_data;
+ pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+ fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
+
+#if (DEBUG & 0x100)
+ printf("SDMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex);
+#endif
+
+ /*
+ * Kick the MII i/f
+ */
+ if (fec->xcv_type != SEVENWIRE) {
+ uint16 phyStatus;
+ miiphy_read(dev->name, 0, 0x1, &phyStatus);
+ }
+
+ /*
+ * Enable SmartDMA transmit task
+ */
+
+#if (DEBUG & 0x20)
+ tfifo_print(dev->name, fec);
+#endif
+ SDMA_TASK_ENABLE (FEC_XMIT_TASK_NO);
+#if (DEBUG & 0x20)
+ tfifo_print(dev->name, fec);
+#endif
+#if (DEBUG & 0x8)
+ printf( "+" );
+#endif
+
+ fec->cleanTbdNum -= 1;
+
+#if (DEBUG & 0x129) && (DEBUG & 0x80000000)
+ printf ("smartDMA ethernet Tx task enabled\n");
+#endif
+ /*
+ * wait until frame is sent .
+ */
+ while (pTbd->status & FEC_TBD_READY) {
+ udelay(10);
+#if (DEBUG & 0x8)
+ printf ("TDB status = %04x\n", pTbd->status);
+#endif
+ }
+
+ return 0;
+}
+
+
+/********************************************************************/
+static int mpc5xxx_fec_recv(struct eth_device *dev)
+{
+ /*
+ * This command pulls one frame from the card
+ */
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
+ volatile FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
+ unsigned long ievent;
+ int frame_length, len = 0;
+ NBUF *frame;
+ uchar buff[FEC_MAX_PKT_SIZE];
+
+#if (DEBUG & 0x1)
+ printf ("mpc5xxx_fec_recv %d Start...\n", fec->rbdIndex);
+#endif
+#if (DEBUG & 0x8)
+ printf( "-" );
+#endif
+
+ /*
+ * Check if any critical events have happened
+ */
+ ievent = fec->eth->ievent;
+ fec->eth->ievent = ievent;
+ if (ievent & 0x20060000) {
+ /* BABT, Rx/Tx FIFO errors */
+ mpc5xxx_fec_halt(dev);
+ mpc5xxx_fec_init(dev, NULL);
+ return 0;
+ }
+ if (ievent & 0x80000000) {
+ /* Heartbeat error */
+ fec->eth->x_cntrl |= 0x00000001;
+ }
+ if (ievent & 0x10000000) {
+ /* Graceful stop complete */
+ if (fec->eth->x_cntrl & 0x00000001) {
+ mpc5xxx_fec_halt(dev);
+ fec->eth->x_cntrl &= ~0x00000001;
+ mpc5xxx_fec_init(dev, NULL);
+ }
+ }
+
+ if (!(pRbd->status & FEC_RBD_EMPTY)) {
+ if ((pRbd->status & FEC_RBD_LAST) && !(pRbd->status & FEC_RBD_ERR) &&
+ ((pRbd->dataLength - 4) > 14)) {
+
+ /*
+ * Get buffer address and size
+ */
+ frame = (NBUF *)pRbd->dataPointer;
+ frame_length = pRbd->dataLength - 4;
+
+#if (DEBUG & 0x20)
+ {
+ int i;
+ printf("recv data hdr:");
+ for (i = 0; i < 14; i++)
+ printf("%x ", *(frame->head + i));
+ printf("\n");
+ }
+#endif
+ /*
+ * Fill the buffer and pass it to upper layers
+ */
+ memcpy(buff, frame->head, 14);
+ memcpy(buff + 14, frame->data, frame_length);
+ NetReceive(buff, frame_length);
+ len = frame_length;
+ }
+ /*
+ * Reset buffer descriptor as empty
+ */
+ mpc5xxx_fec_rbd_clean(fec, pRbd);
+ }
+ SDMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
+ return len;
+}
+
+
+/********************************************************************/
+int mpc5xxx_fec_initialize(bd_t * bis)
+{
+ mpc5xxx_fec_priv *fec;
+ struct eth_device *dev;
+ char *tmp, *end;
+ char env_enetaddr[6];
+ int i;
+
+ fec = (mpc5xxx_fec_priv *)malloc(sizeof(*fec));
+ dev = (struct eth_device *)malloc(sizeof(*dev));
+ memset(dev, 0, sizeof *dev);
+
+ fec->eth = (ethernet_regs *)MPC5XXX_FEC;
+ fec->tbdBase = (FEC_TBD *)FEC_BD_BASE;
+ fec->rbdBase = (FEC_RBD *)(FEC_BD_BASE + FEC_TBD_NUM * sizeof(FEC_TBD));
+#if defined(CONFIG_MPC5xxx_FEC_MII100)
+ fec->xcv_type = MII100;
+#elif defined(CONFIG_MPC5xxx_FEC_MII10)
+ fec->xcv_type = MII10;
+#elif defined(CONFIG_MPC5xxx_FEC_SEVENWIRE)
+ fec->xcv_type = SEVENWIRE;
+#else
+#error fec->xcv_type not initialized.
+#endif
+ if (fec->xcv_type != SEVENWIRE) {
+ /*
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+ * and do not drop the Preamble.
+ * No MII for 7-wire mode
+ */
+ fec->eth->mii_speed = (((gd->arch.ipb_clk >> 20) / 5) << 1);
+ }
+
+ dev->priv = (void *)fec;
+ dev->iobase = MPC5XXX_FEC;
+ dev->init = mpc5xxx_fec_init;
+ dev->halt = mpc5xxx_fec_halt;
+ dev->send = mpc5xxx_fec_send;
+ dev->recv = mpc5xxx_fec_recv;
+
+ sprintf(dev->name, "FEC");
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register (dev->name,
+ fec5xxx_miiphy_read, fec5xxx_miiphy_write);
+#endif
+
+ /*
+ * Try to set the mac address now. The fec mac address is
+ * a garbage after reset. When not using fec for booting
+ * the Linux fec driver will try to work with this garbage.
+ */
+ tmp = getenv("ethaddr");
+ if (tmp) {
+ for (i=0; i<6; i++) {
+ env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+ if (tmp)
+ tmp = (*end) ? end+1 : end;
+ }
+ mpc5xxx_fec_set_hwaddr(fec, env_enetaddr);
+ }
+
+ return 1;
+}
+
+/* MII-interface related functions */
+/********************************************************************/
+int fec5xxx_miiphy_read(const char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal)
+{
+ ethernet_regs *eth = (ethernet_regs *)MPC5XXX_FEC;
+ uint32 reg; /* convenient holder for the PHY register */
+ uint32 phy; /* convenient holder for the PHY */
+ int timeout = 0xffff;
+
+ /*
+ * reading from any PHY's register is done by properly
+ * programming the FEC's MII data register.
+ */
+ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+ eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | reg);
+
+ /*
+ * wait for the related interrupt
+ */
+ while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
+
+ if (timeout == 0) {
+#if (DEBUG & 0x2)
+ printf ("Read MDIO failed...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * clear mii interrupt bit
+ */
+ eth->ievent = 0x00800000;
+
+ /*
+ * it's now safe to read the PHY's register
+ */
+ *retVal = (uint16) eth->mii_data;
+
+ return 0;
+}
+
+/********************************************************************/
+int fec5xxx_miiphy_write(const char *devname, uint8 phyAddr, uint8 regAddr, uint16 data)
+{
+ ethernet_regs *eth = (ethernet_regs *)MPC5XXX_FEC;
+ uint32 reg; /* convenient holder for the PHY register */
+ uint32 phy; /* convenient holder for the PHY */
+ int timeout = 0xffff;
+
+ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+ eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
+ FEC_MII_DATA_TA | phy | reg | data);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
+
+ if (timeout == 0) {
+#if (DEBUG & 0x2)
+ printf ("Write MDIO failed...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * clear MII interrupt bit
+ */
+ eth->ievent = 0x00800000;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/mpc5xxx_fec.h b/qemu/roms/u-boot/drivers/net/mpc5xxx_fec.h
new file mode 100644
index 000000000..16c3e8e91
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/mpc5xxx_fec.h
@@ -0,0 +1,282 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.h
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * odin ethernet header file
+ */
+
+#ifndef __MPC5XXX_FEC_H
+#define __MPC5XXX_FEC_H
+
+typedef unsigned long uint32;
+typedef unsigned short uint16;
+typedef unsigned char uint8;
+
+typedef struct ethernet_register_set {
+
+/* [10:2]addr = 00 */
+
+/* Control and status Registers (offset 000-1FF) */
+
+ volatile uint32 fec_id; /* MBAR_ETH + 0x000 */
+ volatile uint32 ievent; /* MBAR_ETH + 0x004 */
+ volatile uint32 imask; /* MBAR_ETH + 0x008 */
+
+ volatile uint32 RES0[1]; /* MBAR_ETH + 0x00C */
+ volatile uint32 r_des_active; /* MBAR_ETH + 0x010 */
+ volatile uint32 x_des_active; /* MBAR_ETH + 0x014 */
+ volatile uint32 r_des_active_cl; /* MBAR_ETH + 0x018 */
+ volatile uint32 x_des_active_cl; /* MBAR_ETH + 0x01C */
+ volatile uint32 ivent_set; /* MBAR_ETH + 0x020 */
+ volatile uint32 ecntrl; /* MBAR_ETH + 0x024 */
+
+ volatile uint32 RES1[6]; /* MBAR_ETH + 0x028-03C */
+ volatile uint32 mii_data; /* MBAR_ETH + 0x040 */
+ volatile uint32 mii_speed; /* MBAR_ETH + 0x044 */
+ volatile uint32 mii_status; /* MBAR_ETH + 0x048 */
+
+ volatile uint32 RES2[5]; /* MBAR_ETH + 0x04C-05C */
+ volatile uint32 mib_data; /* MBAR_ETH + 0x060 */
+ volatile uint32 mib_control; /* MBAR_ETH + 0x064 */
+
+ volatile uint32 RES3[6]; /* MBAR_ETH + 0x068-7C */
+ volatile uint32 r_activate; /* MBAR_ETH + 0x080 */
+ volatile uint32 r_cntrl; /* MBAR_ETH + 0x084 */
+ volatile uint32 r_hash; /* MBAR_ETH + 0x088 */
+ volatile uint32 r_data; /* MBAR_ETH + 0x08C */
+ volatile uint32 ar_done; /* MBAR_ETH + 0x090 */
+ volatile uint32 r_test; /* MBAR_ETH + 0x094 */
+ volatile uint32 r_mib; /* MBAR_ETH + 0x098 */
+ volatile uint32 r_da_low; /* MBAR_ETH + 0x09C */
+ volatile uint32 r_da_high; /* MBAR_ETH + 0x0A0 */
+
+ volatile uint32 RES4[7]; /* MBAR_ETH + 0x0A4-0BC */
+ volatile uint32 x_activate; /* MBAR_ETH + 0x0C0 */
+ volatile uint32 x_cntrl; /* MBAR_ETH + 0x0C4 */
+ volatile uint32 backoff; /* MBAR_ETH + 0x0C8 */
+ volatile uint32 x_data; /* MBAR_ETH + 0x0CC */
+ volatile uint32 x_status; /* MBAR_ETH + 0x0D0 */
+ volatile uint32 x_mib; /* MBAR_ETH + 0x0D4 */
+ volatile uint32 x_test; /* MBAR_ETH + 0x0D8 */
+ volatile uint32 fdxfc_da1; /* MBAR_ETH + 0x0DC */
+ volatile uint32 fdxfc_da2; /* MBAR_ETH + 0x0E0 */
+ volatile uint32 paddr1; /* MBAR_ETH + 0x0E4 */
+ volatile uint32 paddr2; /* MBAR_ETH + 0x0E8 */
+ volatile uint32 op_pause; /* MBAR_ETH + 0x0EC */
+
+ volatile uint32 RES5[4]; /* MBAR_ETH + 0x0F0-0FC */
+ volatile uint32 instr_reg; /* MBAR_ETH + 0x100 */
+ volatile uint32 context_reg; /* MBAR_ETH + 0x104 */
+ volatile uint32 test_cntrl; /* MBAR_ETH + 0x108 */
+ volatile uint32 acc_reg; /* MBAR_ETH + 0x10C */
+ volatile uint32 ones; /* MBAR_ETH + 0x110 */
+ volatile uint32 zeros; /* MBAR_ETH + 0x114 */
+ volatile uint32 iaddr1; /* MBAR_ETH + 0x118 */
+ volatile uint32 iaddr2; /* MBAR_ETH + 0x11C */
+ volatile uint32 gaddr1; /* MBAR_ETH + 0x120 */
+ volatile uint32 gaddr2; /* MBAR_ETH + 0x124 */
+ volatile uint32 random; /* MBAR_ETH + 0x128 */
+ volatile uint32 rand1; /* MBAR_ETH + 0x12C */
+ volatile uint32 tmp; /* MBAR_ETH + 0x130 */
+
+ volatile uint32 RES6[3]; /* MBAR_ETH + 0x134-13C */
+ volatile uint32 fifo_id; /* MBAR_ETH + 0x140 */
+ volatile uint32 x_wmrk; /* MBAR_ETH + 0x144 */
+ volatile uint32 fcntrl; /* MBAR_ETH + 0x148 */
+ volatile uint32 r_bound; /* MBAR_ETH + 0x14C */
+ volatile uint32 r_fstart; /* MBAR_ETH + 0x150 */
+ volatile uint32 r_count; /* MBAR_ETH + 0x154 */
+ volatile uint32 r_lag; /* MBAR_ETH + 0x158 */
+ volatile uint32 r_read; /* MBAR_ETH + 0x15C */
+ volatile uint32 r_write; /* MBAR_ETH + 0x160 */
+ volatile uint32 x_count; /* MBAR_ETH + 0x164 */
+ volatile uint32 x_lag; /* MBAR_ETH + 0x168 */
+ volatile uint32 x_retry; /* MBAR_ETH + 0x16C */
+ volatile uint32 x_write; /* MBAR_ETH + 0x170 */
+ volatile uint32 x_read; /* MBAR_ETH + 0x174 */
+
+ volatile uint32 RES7[2]; /* MBAR_ETH + 0x178-17C */
+ volatile uint32 fm_cntrl; /* MBAR_ETH + 0x180 */
+ volatile uint32 rfifo_data; /* MBAR_ETH + 0x184 */
+ volatile uint32 rfifo_status; /* MBAR_ETH + 0x188 */
+ volatile uint32 rfifo_cntrl; /* MBAR_ETH + 0x18C */
+ volatile uint32 rfifo_lrf_ptr; /* MBAR_ETH + 0x190 */
+ volatile uint32 rfifo_lwf_ptr; /* MBAR_ETH + 0x194 */
+ volatile uint32 rfifo_alarm; /* MBAR_ETH + 0x198 */
+ volatile uint32 rfifo_rdptr; /* MBAR_ETH + 0x19C */
+ volatile uint32 rfifo_wrptr; /* MBAR_ETH + 0x1A0 */
+ volatile uint32 tfifo_data; /* MBAR_ETH + 0x1A4 */
+ volatile uint32 tfifo_status; /* MBAR_ETH + 0x1A8 */
+ volatile uint32 tfifo_cntrl; /* MBAR_ETH + 0x1AC */
+ volatile uint32 tfifo_lrf_ptr; /* MBAR_ETH + 0x1B0 */
+ volatile uint32 tfifo_lwf_ptr; /* MBAR_ETH + 0x1B4 */
+ volatile uint32 tfifo_alarm; /* MBAR_ETH + 0x1B8 */
+ volatile uint32 tfifo_rdptr; /* MBAR_ETH + 0x1BC */
+ volatile uint32 tfifo_wrptr; /* MBAR_ETH + 0x1C0 */
+
+ volatile uint32 reset_cntrl; /* MBAR_ETH + 0x1C4 */
+ volatile uint32 xmit_fsm; /* MBAR_ETH + 0x1C8 */
+
+ volatile uint32 RES8[3]; /* MBAR_ETH + 0x1CC-1D4 */
+ volatile uint32 rdes_data0; /* MBAR_ETH + 0x1D8 */
+ volatile uint32 rdes_data1; /* MBAR_ETH + 0x1DC */
+ volatile uint32 r_length; /* MBAR_ETH + 0x1E0 */
+ volatile uint32 x_length; /* MBAR_ETH + 0x1E4 */
+ volatile uint32 x_addr; /* MBAR_ETH + 0x1E8 */
+ volatile uint32 cdes_data; /* MBAR_ETH + 0x1EC */
+ volatile uint32 status; /* MBAR_ETH + 0x1F0 */
+ volatile uint32 dma_control; /* MBAR_ETH + 0x1F4 */
+ volatile uint32 des_cmnd; /* MBAR_ETH + 0x1F8 */
+ volatile uint32 data; /* MBAR_ETH + 0x1FC */
+
+/* MIB COUNTERS (Offset 200-2FF) */
+
+ volatile uint32 rmon_t_drop; /* MBAR_ETH + 0x200 */
+ volatile uint32 rmon_t_packets; /* MBAR_ETH + 0x204 */
+ volatile uint32 rmon_t_bc_pkt; /* MBAR_ETH + 0x208 */
+ volatile uint32 rmon_t_mc_pkt; /* MBAR_ETH + 0x20C */
+ volatile uint32 rmon_t_crc_align; /* MBAR_ETH + 0x210 */
+ volatile uint32 rmon_t_undersize; /* MBAR_ETH + 0x214 */
+ volatile uint32 rmon_t_oversize; /* MBAR_ETH + 0x218 */
+ volatile uint32 rmon_t_frag; /* MBAR_ETH + 0x21C */
+ volatile uint32 rmon_t_jab; /* MBAR_ETH + 0x220 */
+ volatile uint32 rmon_t_col; /* MBAR_ETH + 0x224 */
+ volatile uint32 rmon_t_p64; /* MBAR_ETH + 0x228 */
+ volatile uint32 rmon_t_p65to127; /* MBAR_ETH + 0x22C */
+ volatile uint32 rmon_t_p128to255; /* MBAR_ETH + 0x230 */
+ volatile uint32 rmon_t_p256to511; /* MBAR_ETH + 0x234 */
+ volatile uint32 rmon_t_p512to1023; /* MBAR_ETH + 0x238 */
+ volatile uint32 rmon_t_p1024to2047; /* MBAR_ETH + 0x23C */
+ volatile uint32 rmon_t_p_gte2048; /* MBAR_ETH + 0x240 */
+ volatile uint32 rmon_t_octets; /* MBAR_ETH + 0x244 */
+ volatile uint32 ieee_t_drop; /* MBAR_ETH + 0x248 */
+ volatile uint32 ieee_t_frame_ok; /* MBAR_ETH + 0x24C */
+ volatile uint32 ieee_t_1col; /* MBAR_ETH + 0x250 */
+ volatile uint32 ieee_t_mcol; /* MBAR_ETH + 0x254 */
+ volatile uint32 ieee_t_def; /* MBAR_ETH + 0x258 */
+ volatile uint32 ieee_t_lcol; /* MBAR_ETH + 0x25C */
+ volatile uint32 ieee_t_excol; /* MBAR_ETH + 0x260 */
+ volatile uint32 ieee_t_macerr; /* MBAR_ETH + 0x264 */
+ volatile uint32 ieee_t_cserr; /* MBAR_ETH + 0x268 */
+ volatile uint32 ieee_t_sqe; /* MBAR_ETH + 0x26C */
+ volatile uint32 t_fdxfc; /* MBAR_ETH + 0x270 */
+ volatile uint32 ieee_t_octets_ok; /* MBAR_ETH + 0x274 */
+
+ volatile uint32 RES9[2]; /* MBAR_ETH + 0x278-27C */
+ volatile uint32 rmon_r_drop; /* MBAR_ETH + 0x280 */
+ volatile uint32 rmon_r_packets; /* MBAR_ETH + 0x284 */
+ volatile uint32 rmon_r_bc_pkt; /* MBAR_ETH + 0x288 */
+ volatile uint32 rmon_r_mc_pkt; /* MBAR_ETH + 0x28C */
+ volatile uint32 rmon_r_crc_align; /* MBAR_ETH + 0x290 */
+ volatile uint32 rmon_r_undersize; /* MBAR_ETH + 0x294 */
+ volatile uint32 rmon_r_oversize; /* MBAR_ETH + 0x298 */
+ volatile uint32 rmon_r_frag; /* MBAR_ETH + 0x29C */
+ volatile uint32 rmon_r_jab; /* MBAR_ETH + 0x2A0 */
+
+ volatile uint32 rmon_r_resvd_0; /* MBAR_ETH + 0x2A4 */
+
+ volatile uint32 rmon_r_p64; /* MBAR_ETH + 0x2A8 */
+ volatile uint32 rmon_r_p65to127; /* MBAR_ETH + 0x2AC */
+ volatile uint32 rmon_r_p128to255; /* MBAR_ETH + 0x2B0 */
+ volatile uint32 rmon_r_p256to511; /* MBAR_ETH + 0x2B4 */
+ volatile uint32 rmon_r_p512to1023; /* MBAR_ETH + 0x2B8 */
+ volatile uint32 rmon_r_p1024to2047; /* MBAR_ETH + 0x2BC */
+ volatile uint32 rmon_r_p_gte2048; /* MBAR_ETH + 0x2C0 */
+ volatile uint32 rmon_r_octets; /* MBAR_ETH + 0x2C4 */
+ volatile uint32 ieee_r_drop; /* MBAR_ETH + 0x2C8 */
+ volatile uint32 ieee_r_frame_ok; /* MBAR_ETH + 0x2CC */
+ volatile uint32 ieee_r_crc; /* MBAR_ETH + 0x2D0 */
+ volatile uint32 ieee_r_align; /* MBAR_ETH + 0x2D4 */
+ volatile uint32 r_macerr; /* MBAR_ETH + 0x2D8 */
+ volatile uint32 r_fdxfc; /* MBAR_ETH + 0x2DC */
+ volatile uint32 ieee_r_octets_ok; /* MBAR_ETH + 0x2E0 */
+
+ volatile uint32 RES10[6]; /* MBAR_ETH + 0x2E4-2FC */
+
+ volatile uint32 RES11[64]; /* MBAR_ETH + 0x300-3FF */
+} ethernet_regs;
+
+/* Receive & Transmit Buffer Descriptor definitions */
+typedef struct BufferDescriptor {
+ uint16 status;
+ uint16 dataLength;
+ uint32 dataPointer;
+} FEC_RBD;
+typedef struct {
+ uint16 status;
+ uint16 dataLength;
+ uint32 dataPointer;
+} FEC_TBD;
+
+/* private structure */
+typedef enum {
+ SEVENWIRE, /* 7-wire */
+ MII10, /* MII 10Mbps */
+ MII100 /* MII 100Mbps */
+} xceiver_type;
+
+typedef struct {
+ ethernet_regs *eth;
+ xceiver_type xcv_type; /* transceiver type */
+ FEC_RBD *rbdBase; /* RBD ring */
+ FEC_TBD *tbdBase; /* TBD ring */
+ uint16 rbdIndex; /* next receive BD to read */
+ uint16 tbdIndex; /* next transmit BD to send */
+ uint16 usedTbdIndex; /* next transmit BD to clean */
+ uint16 cleanTbdNum; /* the number of available transmit BDs */
+} mpc5xxx_fec_priv;
+
+/* Ethernet parameter area */
+#define FEC_TBD_BASE (FEC_PARAM_BASE + 0x00)
+#define FEC_TBD_NEXT (FEC_PARAM_BASE + 0x04)
+#define FEC_RBD_BASE (FEC_PARAM_BASE + 0x08)
+#define FEC_RBD_NEXT (FEC_PARAM_BASE + 0x0c)
+
+/* BD Numer definitions */
+#define FEC_TBD_NUM 48 /* The user can adjust this value */
+#define FEC_RBD_NUM 32 /* The user can adjust this value */
+
+/* packet size limit */
+#define FEC_MAX_PKT_SIZE 1536
+
+/* RBD bits definitions */
+#define FEC_RBD_EMPTY 0x8000 /* Buffer is empty */
+#define FEC_RBD_WRAP 0x2000 /* Last BD in ring */
+#define FEC_RBD_INT 0x1000 /* Interrupt */
+#define FEC_RBD_LAST 0x0800 /* Buffer is last in frame(useless) */
+#define FEC_RBD_MISS 0x0100 /* Miss bit for prom mode */
+#define FEC_RBD_BC 0x0080 /* The received frame is broadcast frame */
+#define FEC_RBD_MC 0x0040 /* The received frame is multicast frame */
+#define FEC_RBD_LG 0x0020 /* Frame length violation */
+#define FEC_RBD_NO 0x0010 /* Nonoctet align frame */
+#define FEC_RBD_SH 0x0008 /* Short frame */
+#define FEC_RBD_CR 0x0004 /* CRC error */
+#define FEC_RBD_OV 0x0002 /* Receive FIFO overrun */
+#define FEC_RBD_TR 0x0001 /* Frame is truncated */
+#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+ FEC_RBD_OV | FEC_RBD_TR)
+
+/* TBD bits definitions */
+#define FEC_TBD_READY 0x8000 /* Buffer is ready */
+#define FEC_TBD_WRAP 0x2000 /* Last BD in ring */
+#define FEC_TBD_INT 0x1000 /* Interrupt */
+#define FEC_TBD_LAST 0x0800 /* Buffer is last in frame */
+#define FEC_TBD_TC 0x0400 /* Transmit the CRC */
+#define FEC_TBD_ABC 0x0200 /* Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST 0x40000000 /* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform a read operation */
+#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register field mask */
+#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
+#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */
+
+#endif /* __MPC5XXX_FEC_H */
diff --git a/qemu/roms/u-boot/drivers/net/mvgbe.c b/qemu/roms/u-boot/drivers/net/mvgbe.c
new file mode 100644
index 000000000..0cd06b6a6
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/mvgbe.c
@@ -0,0 +1,788 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * (C) Copyright 2003
+ * Ingo Assmus <ingo.assmus@keymile.com>
+ *
+ * based on - Driver for MV64360X ethernet ports
+ * Copyright (C) 2002 rabeeh@galileo.co.il
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/types.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include <asm/arch/cpu.h>
+
+#if defined(CONFIG_KIRKWOOD)
+#include <asm/arch/kirkwood.h>
+#elif defined(CONFIG_ORION5X)
+#include <asm/arch/orion5x.h>
+#elif defined(CONFIG_DOVE)
+#include <asm/arch/dove.h>
+#endif
+
+#include "mvgbe.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MV_PHY_ADR_REQUEST 0xee
+#define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi)
+
+#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+/*
+ * smi_reg_read - miiphy_read callback function.
+ *
+ * Returns 16bit phy register value, or 0xffff on error
+ */
+static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+ struct mvgbe_registers *regs = dmvgbe->regs;
+ u32 smi_reg;
+ u32 timeout;
+
+ /* Phyadr read request */
+ if (phy_adr == MV_PHY_ADR_REQUEST &&
+ reg_ofs == MV_PHY_ADR_REQUEST) {
+ /* */
+ *data = (u16) (MVGBE_REG_RD(regs->phyadr) & PHYADR_MASK);
+ return 0;
+ }
+ /* check parameters */
+ if (phy_adr > PHYADR_MASK) {
+ printf("Err..(%s) Invalid PHY address %d\n",
+ __FUNCTION__, phy_adr);
+ return -EFAULT;
+ }
+ if (reg_ofs > PHYREG_MASK) {
+ printf("Err..(%s) Invalid register offset %d\n",
+ __FUNCTION__, reg_ofs);
+ return -EFAULT;
+ }
+
+ timeout = MVGBE_PHY_SMI_TIMEOUT;
+ /* wait till the SMI is not busy */
+ do {
+ /* read smi register */
+ smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
+ if (timeout-- == 0) {
+ printf("Err..(%s) SMI busy timeout\n", __FUNCTION__);
+ return -EFAULT;
+ }
+ } while (smi_reg & MVGBE_PHY_SMI_BUSY_MASK);
+
+ /* fill the phy address and regiser offset and read opcode */
+ smi_reg = (phy_adr << MVGBE_PHY_SMI_DEV_ADDR_OFFS)
+ | (reg_ofs << MVGBE_SMI_REG_ADDR_OFFS)
+ | MVGBE_PHY_SMI_OPCODE_READ;
+
+ /* write the smi register */
+ MVGBE_REG_WR(MVGBE_SMI_REG, smi_reg);
+
+ /*wait till read value is ready */
+ timeout = MVGBE_PHY_SMI_TIMEOUT;
+
+ do {
+ /* read smi register */
+ smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
+ if (timeout-- == 0) {
+ printf("Err..(%s) SMI read ready timeout\n",
+ __FUNCTION__);
+ return -EFAULT;
+ }
+ } while (!(smi_reg & MVGBE_PHY_SMI_READ_VALID_MASK));
+
+ /* Wait for the data to update in the SMI register */
+ for (timeout = 0; timeout < MVGBE_PHY_SMI_TIMEOUT; timeout++)
+ ;
+
+ *data = (u16) (MVGBE_REG_RD(MVGBE_SMI_REG) & MVGBE_PHY_SMI_DATA_MASK);
+
+ debug("%s:(adr %d, off %d) value= %04x\n", __FUNCTION__, phy_adr,
+ reg_ofs, *data);
+
+ return 0;
+}
+
+/*
+ * smi_reg_write - imiiphy_write callback function.
+ *
+ * Returns 0 if write succeed, -EINVAL on bad parameters
+ * -ETIME on timeout
+ */
+static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+ struct mvgbe_registers *regs = dmvgbe->regs;
+ u32 smi_reg;
+ u32 timeout;
+
+ /* Phyadr write request*/
+ if (phy_adr == MV_PHY_ADR_REQUEST &&
+ reg_ofs == MV_PHY_ADR_REQUEST) {
+ MVGBE_REG_WR(regs->phyadr, data);
+ return 0;
+ }
+
+ /* check parameters */
+ if (phy_adr > PHYADR_MASK) {
+ printf("Err..(%s) Invalid phy address\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (reg_ofs > PHYREG_MASK) {
+ printf("Err..(%s) Invalid register offset\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* wait till the SMI is not busy */
+ timeout = MVGBE_PHY_SMI_TIMEOUT;
+ do {
+ /* read smi register */
+ smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
+ if (timeout-- == 0) {
+ printf("Err..(%s) SMI busy timeout\n", __FUNCTION__);
+ return -ETIME;
+ }
+ } while (smi_reg & MVGBE_PHY_SMI_BUSY_MASK);
+
+ /* fill the phy addr and reg offset and write opcode and data */
+ smi_reg = (data << MVGBE_PHY_SMI_DATA_OFFS);
+ smi_reg |= (phy_adr << MVGBE_PHY_SMI_DEV_ADDR_OFFS)
+ | (reg_ofs << MVGBE_SMI_REG_ADDR_OFFS);
+ smi_reg &= ~MVGBE_PHY_SMI_OPCODE_READ;
+
+ /* write the smi register */
+ MVGBE_REG_WR(MVGBE_SMI_REG, smi_reg);
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_PHYLIB)
+int mvgbe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr)
+{
+ u16 data;
+ int ret;
+ ret = smi_reg_read(bus->name, phy_addr, reg_addr, &data);
+ if (ret)
+ return ret;
+ return data;
+}
+
+int mvgbe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr, u16 data)
+{
+ return smi_reg_write(bus->name, phy_addr, reg_addr, data);
+}
+#endif
+
+/* Stop and checks all queues */
+static void stop_queue(u32 * qreg)
+{
+ u32 reg_data;
+
+ reg_data = readl(qreg);
+
+ if (reg_data & 0xFF) {
+ /* Issue stop command for active channels only */
+ writel((reg_data << 8), qreg);
+
+ /* Wait for all queue activity to terminate. */
+ do {
+ /*
+ * Check port cause register that all queues
+ * are stopped
+ */
+ reg_data = readl(qreg);
+ }
+ while (reg_data & 0xFF);
+ }
+}
+
+/*
+ * set_access_control - Config address decode parameters for Ethernet unit
+ *
+ * This function configures the address decode parameters for the Gigabit
+ * Ethernet Controller according the given parameters struct.
+ *
+ * @regs Register struct pointer.
+ * @param Address decode parameter struct.
+ */
+static void set_access_control(struct mvgbe_registers *regs,
+ struct mvgbe_winparam *param)
+{
+ u32 access_prot_reg;
+
+ /* Set access control register */
+ access_prot_reg = MVGBE_REG_RD(regs->epap);
+ /* clear window permission */
+ access_prot_reg &= (~(3 << (param->win * 2)));
+ access_prot_reg |= (param->access_ctrl << (param->win * 2));
+ MVGBE_REG_WR(regs->epap, access_prot_reg);
+
+ /* Set window Size reg (SR) */
+ MVGBE_REG_WR(regs->barsz[param->win].size,
+ (((param->size / 0x10000) - 1) << 16));
+
+ /* Set window Base address reg (BA) */
+ MVGBE_REG_WR(regs->barsz[param->win].bar,
+ (param->target | param->attrib | param->base_addr));
+ /* High address remap reg (HARR) */
+ if (param->win < 4)
+ MVGBE_REG_WR(regs->ha_remap[param->win], param->high_addr);
+
+ /* Base address enable reg (BARER) */
+ if (param->enable == 1)
+ MVGBE_REG_BITS_RESET(regs->bare, (1 << param->win));
+ else
+ MVGBE_REG_BITS_SET(regs->bare, (1 << param->win));
+}
+
+static void set_dram_access(struct mvgbe_registers *regs)
+{
+ struct mvgbe_winparam win_param;
+ int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ /* Set access parameters for DRAM bank i */
+ win_param.win = i; /* Use Ethernet window i */
+ /* Window target - DDR */
+ win_param.target = MVGBE_TARGET_DRAM;
+ /* Enable full access */
+ win_param.access_ctrl = EWIN_ACCESS_FULL;
+ win_param.high_addr = 0;
+ /* Get bank base and size */
+ win_param.base_addr = gd->bd->bi_dram[i].start;
+ win_param.size = gd->bd->bi_dram[i].size;
+ if (win_param.size == 0)
+ win_param.enable = 0;
+ else
+ win_param.enable = 1; /* Enable the access */
+
+ /* Enable DRAM bank */
+ switch (i) {
+ case 0:
+ win_param.attrib = EBAR_DRAM_CS0;
+ break;
+ case 1:
+ win_param.attrib = EBAR_DRAM_CS1;
+ break;
+ case 2:
+ win_param.attrib = EBAR_DRAM_CS2;
+ break;
+ case 3:
+ win_param.attrib = EBAR_DRAM_CS3;
+ break;
+ default:
+ /* invalid bank, disable access */
+ win_param.enable = 0;
+ win_param.attrib = 0;
+ break;
+ }
+ /* Set the access control for address window(EPAPR) RD/WR */
+ set_access_control(regs, &win_param);
+ }
+}
+
+/*
+ * port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables
+ *
+ * Go through all the DA filter tables (Unicast, Special Multicast & Other
+ * Multicast) and set each entry to 0.
+ */
+static void port_init_mac_tables(struct mvgbe_registers *regs)
+{
+ int table_index;
+
+ /* Clear DA filter unicast table (Ex_dFUT) */
+ for (table_index = 0; table_index < 4; ++table_index)
+ MVGBE_REG_WR(regs->dfut[table_index], 0);
+
+ for (table_index = 0; table_index < 64; ++table_index) {
+ /* Clear DA filter special multicast table (Ex_dFSMT) */
+ MVGBE_REG_WR(regs->dfsmt[table_index], 0);
+ /* Clear DA filter other multicast table (Ex_dFOMT) */
+ MVGBE_REG_WR(regs->dfomt[table_index], 0);
+ }
+}
+
+/*
+ * port_uc_addr - This function Set the port unicast address table
+ *
+ * This function locates the proper entry in the Unicast table for the
+ * specified MAC nibble and sets its properties according to function
+ * parameters.
+ * This function add/removes MAC addresses from the port unicast address
+ * table.
+ *
+ * @uc_nibble Unicast MAC Address last nibble.
+ * @option 0 = Add, 1 = remove address.
+ *
+ * RETURN: 1 if output succeeded. 0 if option parameter is invalid.
+ */
+static int port_uc_addr(struct mvgbe_registers *regs, u8 uc_nibble,
+ int option)
+{
+ u32 unicast_reg;
+ u32 tbl_offset;
+ u32 reg_offset;
+
+ /* Locate the Unicast table entry */
+ uc_nibble = (0xf & uc_nibble);
+ /* Register offset from unicast table base */
+ tbl_offset = (uc_nibble / 4);
+ /* Entry offset within the above register */
+ reg_offset = uc_nibble % 4;
+
+ switch (option) {
+ case REJECT_MAC_ADDR:
+ /*
+ * Clear accepts frame bit at specified unicast
+ * DA table entry
+ */
+ unicast_reg = MVGBE_REG_RD(regs->dfut[tbl_offset]);
+ unicast_reg &= (0xFF << (8 * reg_offset));
+ MVGBE_REG_WR(regs->dfut[tbl_offset], unicast_reg);
+ break;
+ case ACCEPT_MAC_ADDR:
+ /* Set accepts frame bit at unicast DA filter table entry */
+ unicast_reg = MVGBE_REG_RD(regs->dfut[tbl_offset]);
+ unicast_reg &= (0xFF << (8 * reg_offset));
+ unicast_reg |= ((0x01 | (RXUQ << 1)) << (8 * reg_offset));
+ MVGBE_REG_WR(regs->dfut[tbl_offset], unicast_reg);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * port_uc_addr_set - This function Set the port Unicast address.
+ */
+static void port_uc_addr_set(struct mvgbe_registers *regs, u8 * p_addr)
+{
+ u32 mac_h;
+ u32 mac_l;
+
+ mac_l = (p_addr[4] << 8) | (p_addr[5]);
+ mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
+ (p_addr[3] << 0);
+
+ MVGBE_REG_WR(regs->macal, mac_l);
+ MVGBE_REG_WR(regs->macah, mac_h);
+
+ /* Accept frames of this address */
+ port_uc_addr(regs, p_addr[5], ACCEPT_MAC_ADDR);
+}
+
+/*
+ * mvgbe_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory.
+ */
+static void mvgbe_init_rx_desc_ring(struct mvgbe_device *dmvgbe)
+{
+ struct mvgbe_rxdesc *p_rx_desc;
+ int i;
+
+ /* initialize the Rx descriptors ring */
+ p_rx_desc = dmvgbe->p_rxdesc;
+ for (i = 0; i < RINGSZ; i++) {
+ p_rx_desc->cmd_sts =
+ MVGBE_BUFFER_OWNED_BY_DMA | MVGBE_RX_EN_INTERRUPT;
+ p_rx_desc->buf_size = PKTSIZE_ALIGN;
+ p_rx_desc->byte_cnt = 0;
+ p_rx_desc->buf_ptr = dmvgbe->p_rxbuf + i * PKTSIZE_ALIGN;
+ if (i == (RINGSZ - 1))
+ p_rx_desc->nxtdesc_p = dmvgbe->p_rxdesc;
+ else {
+ p_rx_desc->nxtdesc_p = (struct mvgbe_rxdesc *)
+ ((u32) p_rx_desc + MV_RXQ_DESC_ALIGNED_SIZE);
+ p_rx_desc = p_rx_desc->nxtdesc_p;
+ }
+ }
+ dmvgbe->p_rxdesc_curr = dmvgbe->p_rxdesc;
+}
+
+static int mvgbe_init(struct eth_device *dev)
+{
+ struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+ struct mvgbe_registers *regs = dmvgbe->regs;
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
+ !defined(CONFIG_PHYLIB) && \
+ defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
+ int i;
+#endif
+ /* setup RX rings */
+ mvgbe_init_rx_desc_ring(dmvgbe);
+
+ /* Clear the ethernet port interrupts */
+ MVGBE_REG_WR(regs->ic, 0);
+ MVGBE_REG_WR(regs->ice, 0);
+ /* Unmask RX buffer and TX end interrupt */
+ MVGBE_REG_WR(regs->pim, INT_CAUSE_UNMASK_ALL);
+ /* Unmask phy and link status changes interrupts */
+ MVGBE_REG_WR(regs->peim, INT_CAUSE_UNMASK_ALL_EXT);
+
+ set_dram_access(regs);
+ port_init_mac_tables(regs);
+ port_uc_addr_set(regs, dmvgbe->dev.enetaddr);
+
+ /* Assign port configuration and command. */
+ MVGBE_REG_WR(regs->pxc, PRT_CFG_VAL);
+ MVGBE_REG_WR(regs->pxcx, PORT_CFG_EXTEND_VALUE);
+ MVGBE_REG_WR(regs->psc0, PORT_SERIAL_CONTROL_VALUE);
+
+ /* Assign port SDMA configuration */
+ MVGBE_REG_WR(regs->sdc, PORT_SDMA_CFG_VALUE);
+ MVGBE_REG_WR(regs->tqx[0].qxttbc, QTKNBKT_DEF_VAL);
+ MVGBE_REG_WR(regs->tqx[0].tqxtbc,
+ (QMTBS_DEF_VAL << 16) | QTKNRT_DEF_VAL);
+ /* Turn off the port/RXUQ bandwidth limitation */
+ MVGBE_REG_WR(regs->pmtu, 0);
+
+ /* Set maximum receive buffer to 9700 bytes */
+ MVGBE_REG_WR(regs->psc0, MVGBE_MAX_RX_PACKET_9700BYTE
+ | (MVGBE_REG_RD(regs->psc0) & MRU_MASK));
+
+ /* Enable port initially */
+ MVGBE_REG_BITS_SET(regs->psc0, MVGBE_SERIAL_PORT_EN);
+
+ /*
+ * Set ethernet MTU for leaky bucket mechanism to 0 - this will
+ * disable the leaky bucket mechanism .
+ */
+ MVGBE_REG_WR(regs->pmtu, 0);
+
+ /* Assignment of Rx CRDB of given RXUQ */
+ MVGBE_REG_WR(regs->rxcdp[RXUQ], (u32) dmvgbe->p_rxdesc_curr);
+ /* ensure previous write is done before enabling Rx DMA */
+ isb();
+ /* Enable port Rx. */
+ MVGBE_REG_WR(regs->rqc, (1 << RXUQ));
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
+ !defined(CONFIG_PHYLIB) && \
+ defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
+ /* Wait up to 5s for the link status */
+ for (i = 0; i < 5; i++) {
+ u16 phyadr;
+
+ miiphy_read(dev->name, MV_PHY_ADR_REQUEST,
+ MV_PHY_ADR_REQUEST, &phyadr);
+ /* Return if we get link up */
+ if (miiphy_link(dev->name, phyadr))
+ return 0;
+ udelay(1000000);
+ }
+
+ printf("No link on %s\n", dev->name);
+ return -1;
+#endif
+ return 0;
+}
+
+static int mvgbe_halt(struct eth_device *dev)
+{
+ struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+ struct mvgbe_registers *regs = dmvgbe->regs;
+
+ /* Disable all gigE address decoder */
+ MVGBE_REG_WR(regs->bare, 0x3f);
+
+ stop_queue(&regs->tqc);
+ stop_queue(&regs->rqc);
+
+ /* Disable port */
+ MVGBE_REG_BITS_RESET(regs->psc0, MVGBE_SERIAL_PORT_EN);
+ /* Set port is not reset */
+ MVGBE_REG_BITS_RESET(regs->psc1, 1 << 4);
+#ifdef CONFIG_SYS_MII_MODE
+ /* Set MMI interface up */
+ MVGBE_REG_BITS_RESET(regs->psc1, 1 << 3);
+#endif
+ /* Disable & mask ethernet port interrupts */
+ MVGBE_REG_WR(regs->ic, 0);
+ MVGBE_REG_WR(regs->ice, 0);
+ MVGBE_REG_WR(regs->pim, 0);
+ MVGBE_REG_WR(regs->peim, 0);
+
+ return 0;
+}
+
+static int mvgbe_write_hwaddr(struct eth_device *dev)
+{
+ struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+ struct mvgbe_registers *regs = dmvgbe->regs;
+
+ /* Programs net device MAC address after initialization */
+ port_uc_addr_set(regs, dmvgbe->dev.enetaddr);
+ return 0;
+}
+
+static int mvgbe_send(struct eth_device *dev, void *dataptr, int datasize)
+{
+ struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+ struct mvgbe_registers *regs = dmvgbe->regs;
+ struct mvgbe_txdesc *p_txdesc = dmvgbe->p_txdesc;
+ void *p = (void *)dataptr;
+ u32 cmd_sts;
+ u32 txuq0_reg_addr;
+
+ /* Copy buffer if it's misaligned */
+ if ((u32) dataptr & 0x07) {
+ if (datasize > PKTSIZE_ALIGN) {
+ printf("Non-aligned data too large (%d)\n",
+ datasize);
+ return -1;
+ }
+
+ memcpy(dmvgbe->p_aligned_txbuf, p, datasize);
+ p = dmvgbe->p_aligned_txbuf;
+ }
+
+ p_txdesc->cmd_sts = MVGBE_ZERO_PADDING | MVGBE_GEN_CRC;
+ p_txdesc->cmd_sts |= MVGBE_TX_FIRST_DESC | MVGBE_TX_LAST_DESC;
+ p_txdesc->cmd_sts |= MVGBE_BUFFER_OWNED_BY_DMA;
+ p_txdesc->cmd_sts |= MVGBE_TX_EN_INTERRUPT;
+ p_txdesc->buf_ptr = (u8 *) p;
+ p_txdesc->byte_cnt = datasize;
+
+ /* Set this tc desc as zeroth TXUQ */
+ txuq0_reg_addr = (u32)&regs->tcqdp[TXUQ];
+ writel((u32) p_txdesc, txuq0_reg_addr);
+
+ /* ensure tx desc writes above are performed before we start Tx DMA */
+ isb();
+
+ /* Apply send command using zeroth TXUQ */
+ MVGBE_REG_WR(regs->tqc, (1 << TXUQ));
+
+ /*
+ * wait for packet xmit completion
+ */
+ cmd_sts = readl(&p_txdesc->cmd_sts);
+ while (cmd_sts & MVGBE_BUFFER_OWNED_BY_DMA) {
+ /* return fail if error is detected */
+ if ((cmd_sts & (MVGBE_ERROR_SUMMARY | MVGBE_TX_LAST_FRAME)) ==
+ (MVGBE_ERROR_SUMMARY | MVGBE_TX_LAST_FRAME) &&
+ cmd_sts & (MVGBE_UR_ERROR | MVGBE_RL_ERROR)) {
+ printf("Err..(%s) in xmit packet\n", __FUNCTION__);
+ return -1;
+ }
+ cmd_sts = readl(&p_txdesc->cmd_sts);
+ };
+ return 0;
+}
+
+static int mvgbe_recv(struct eth_device *dev)
+{
+ struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+ struct mvgbe_rxdesc *p_rxdesc_curr = dmvgbe->p_rxdesc_curr;
+ u32 cmd_sts;
+ u32 timeout = 0;
+ u32 rxdesc_curr_addr;
+
+ /* wait untill rx packet available or timeout */
+ do {
+ if (timeout < MVGBE_PHY_SMI_TIMEOUT)
+ timeout++;
+ else {
+ debug("%s time out...\n", __FUNCTION__);
+ return -1;
+ }
+ } while (readl(&p_rxdesc_curr->cmd_sts) & MVGBE_BUFFER_OWNED_BY_DMA);
+
+ if (p_rxdesc_curr->byte_cnt != 0) {
+ debug("%s: Received %d byte Packet @ 0x%x (cmd_sts= %08x)\n",
+ __FUNCTION__, (u32) p_rxdesc_curr->byte_cnt,
+ (u32) p_rxdesc_curr->buf_ptr,
+ (u32) p_rxdesc_curr->cmd_sts);
+ }
+
+ /*
+ * In case received a packet without first/last bits on
+ * OR the error summary bit is on,
+ * the packets needs to be dropeed.
+ */
+ cmd_sts = readl(&p_rxdesc_curr->cmd_sts);
+
+ if ((cmd_sts &
+ (MVGBE_RX_FIRST_DESC | MVGBE_RX_LAST_DESC))
+ != (MVGBE_RX_FIRST_DESC | MVGBE_RX_LAST_DESC)) {
+
+ printf("Err..(%s) Dropping packet spread on"
+ " multiple descriptors\n", __FUNCTION__);
+
+ } else if (cmd_sts & MVGBE_ERROR_SUMMARY) {
+
+ printf("Err..(%s) Dropping packet with errors\n",
+ __FUNCTION__);
+
+ } else {
+ /* !!! call higher layer processing */
+ debug("%s: Sending Received packet to"
+ " upper layer (NetReceive)\n", __FUNCTION__);
+
+ /* let the upper layer handle the packet */
+ NetReceive((p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET),
+ (int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET));
+ }
+ /*
+ * free these descriptors and point next in the ring
+ */
+ p_rxdesc_curr->cmd_sts =
+ MVGBE_BUFFER_OWNED_BY_DMA | MVGBE_RX_EN_INTERRUPT;
+ p_rxdesc_curr->buf_size = PKTSIZE_ALIGN;
+ p_rxdesc_curr->byte_cnt = 0;
+
+ rxdesc_curr_addr = (u32)&dmvgbe->p_rxdesc_curr;
+ writel((unsigned)p_rxdesc_curr->nxtdesc_p, rxdesc_curr_addr);
+
+ return 0;
+}
+
+#if defined(CONFIG_PHYLIB)
+int mvgbe_phylib_init(struct eth_device *dev, int phyid)
+{
+ struct mii_dev *bus;
+ struct phy_device *phydev;
+ int ret;
+
+ bus = mdio_alloc();
+ if (!bus) {
+ printf("mdio_alloc failed\n");
+ return -ENOMEM;
+ }
+ bus->read = mvgbe_phy_read;
+ bus->write = mvgbe_phy_write;
+ sprintf(bus->name, dev->name);
+
+ ret = mdio_register(bus);
+ if (ret) {
+ printf("mdio_register failed\n");
+ free(bus);
+ return -ENOMEM;
+ }
+
+ /* Set phy address of the port */
+ mvgbe_phy_write(bus, MV_PHY_ADR_REQUEST, 0, MV_PHY_ADR_REQUEST, phyid);
+
+ phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_RGMII);
+ if (!phydev) {
+ printf("phy_connect failed\n");
+ return -ENODEV;
+ }
+
+ phy_config(phydev);
+ phy_startup(phydev);
+
+ return 0;
+}
+#endif
+
+int mvgbe_initialize(bd_t *bis)
+{
+ struct mvgbe_device *dmvgbe;
+ struct eth_device *dev;
+ int devnum;
+ u8 used_ports[MAX_MVGBE_DEVS] = CONFIG_MVGBE_PORTS;
+
+ for (devnum = 0; devnum < MAX_MVGBE_DEVS; devnum++) {
+ /*skip if port is configured not to use */
+ if (used_ports[devnum] == 0)
+ continue;
+
+ dmvgbe = malloc(sizeof(struct mvgbe_device));
+
+ if (!dmvgbe)
+ goto error1;
+
+ memset(dmvgbe, 0, sizeof(struct mvgbe_device));
+
+ dmvgbe->p_rxdesc =
+ (struct mvgbe_rxdesc *)memalign(PKTALIGN,
+ MV_RXQ_DESC_ALIGNED_SIZE*RINGSZ + 1);
+
+ if (!dmvgbe->p_rxdesc)
+ goto error2;
+
+ dmvgbe->p_rxbuf = (u8 *) memalign(PKTALIGN,
+ RINGSZ*PKTSIZE_ALIGN + 1);
+
+ if (!dmvgbe->p_rxbuf)
+ goto error3;
+
+ dmvgbe->p_aligned_txbuf = memalign(8, PKTSIZE_ALIGN);
+
+ if (!dmvgbe->p_aligned_txbuf)
+ goto error4;
+
+ dmvgbe->p_txdesc = (struct mvgbe_txdesc *) memalign(
+ PKTALIGN, sizeof(struct mvgbe_txdesc) + 1);
+
+ if (!dmvgbe->p_txdesc) {
+ free(dmvgbe->p_aligned_txbuf);
+error4:
+ free(dmvgbe->p_rxbuf);
+error3:
+ free(dmvgbe->p_rxdesc);
+error2:
+ free(dmvgbe);
+error1:
+ printf("Err.. %s Failed to allocate memory\n",
+ __FUNCTION__);
+ return -1;
+ }
+
+ dev = &dmvgbe->dev;
+
+ /* must be less than sizeof(dev->name) */
+ sprintf(dev->name, "egiga%d", devnum);
+
+ switch (devnum) {
+ case 0:
+ dmvgbe->regs = (void *)MVGBE0_BASE;
+ break;
+#if defined(MVGBE1_BASE)
+ case 1:
+ dmvgbe->regs = (void *)MVGBE1_BASE;
+ break;
+#endif
+ default: /* this should never happen */
+ printf("Err..(%s) Invalid device number %d\n",
+ __FUNCTION__, devnum);
+ return -1;
+ }
+
+ dev->init = (void *)mvgbe_init;
+ dev->halt = (void *)mvgbe_halt;
+ dev->send = (void *)mvgbe_send;
+ dev->recv = (void *)mvgbe_recv;
+ dev->write_hwaddr = (void *)mvgbe_write_hwaddr;
+
+ eth_register(dev);
+
+#if defined(CONFIG_PHYLIB)
+ mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum);
+#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, smi_reg_read, smi_reg_write);
+ /* Set phy address of the port */
+ miiphy_write(dev->name, MV_PHY_ADR_REQUEST,
+ MV_PHY_ADR_REQUEST, PHY_BASE_ADR + devnum);
+#endif
+ }
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/mvgbe.h b/qemu/roms/u-boot/drivers/net/mvgbe.h
new file mode 100644
index 000000000..27a3f41e8
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/mvgbe.h
@@ -0,0 +1,498 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * based on - Driver for MV64360X ethernet ports
+ * Copyright (C) 2002 rabeeh@galileo.co.il
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MVGBE_H__
+#define __MVGBE_H__
+
+/* PHY_BASE_ADR is board specific and can be configured */
+#if defined (CONFIG_PHY_BASE_ADR)
+#define PHY_BASE_ADR CONFIG_PHY_BASE_ADR
+#else
+#define PHY_BASE_ADR 0x08 /* default phy base addr */
+#endif
+
+/* Constants */
+#define INT_CAUSE_UNMASK_ALL 0x0007ffff
+#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff
+#define MRU_MASK 0xfff1ffff
+#define PHYADR_MASK 0x0000001f
+#define PHYREG_MASK 0x0000001f
+#define QTKNBKT_DEF_VAL 0x3fffffff
+#define QMTBS_DEF_VAL 0x000003ff
+#define QTKNRT_DEF_VAL 0x0000fcff
+#define RXUQ 0 /* Used Rx queue */
+#define TXUQ 0 /* Used Rx queue */
+
+#define to_mvgbe(_d) container_of(_d, struct mvgbe_device, dev)
+#define MVGBE_REG_WR(adr, val) writel(val, &adr)
+#define MVGBE_REG_RD(adr) readl(&adr)
+#define MVGBE_REG_BITS_RESET(adr, val) writel(readl(&adr) & ~(val), &adr)
+#define MVGBE_REG_BITS_SET(adr, val) writel(readl(&adr) | val, &adr)
+
+/* Default port configuration value */
+#define PRT_CFG_VAL ( \
+ MVGBE_UCAST_MOD_NRML | \
+ MVGBE_DFLT_RXQ(RXUQ) | \
+ MVGBE_DFLT_RX_ARPQ(RXUQ) | \
+ MVGBE_RX_BC_IF_NOT_IP_OR_ARP | \
+ MVGBE_RX_BC_IF_IP | \
+ MVGBE_RX_BC_IF_ARP | \
+ MVGBE_CPTR_TCP_FRMS_DIS | \
+ MVGBE_CPTR_UDP_FRMS_DIS | \
+ MVGBE_DFLT_RX_TCPQ(RXUQ) | \
+ MVGBE_DFLT_RX_UDPQ(RXUQ) | \
+ MVGBE_DFLT_RX_BPDUQ(RXUQ))
+
+/* Default port extend configuration value */
+#define PORT_CFG_EXTEND_VALUE \
+ MVGBE_SPAN_BPDU_PACKETS_AS_NORMAL | \
+ MVGBE_PARTITION_DIS | \
+ MVGBE_TX_CRC_GENERATION_EN
+
+#define GT_MVGBE_IPG_INT_RX(value) ((value & 0x3fff) << 8)
+
+/* Default sdma control value */
+#define PORT_SDMA_CFG_VALUE ( \
+ MVGBE_RX_BURST_SIZE_16_64BIT | \
+ MVGBE_BLM_RX_NO_SWAP | \
+ MVGBE_BLM_TX_NO_SWAP | \
+ GT_MVGBE_IPG_INT_RX(RXUQ) | \
+ MVGBE_TX_BURST_SIZE_16_64BIT)
+
+/* Default port serial control value */
+#ifndef PORT_SERIAL_CONTROL_VALUE
+#define PORT_SERIAL_CONTROL_VALUE ( \
+ MVGBE_FORCE_LINK_PASS | \
+ MVGBE_DIS_AUTO_NEG_FOR_DUPLX | \
+ MVGBE_DIS_AUTO_NEG_FOR_FLOW_CTRL | \
+ MVGBE_ADV_NO_FLOW_CTRL | \
+ MVGBE_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \
+ MVGBE_FORCE_BP_MODE_NO_JAM | \
+ (1 << 9) /* Reserved bit has to be 1 */ | \
+ MVGBE_DO_NOT_FORCE_LINK_FAIL | \
+ MVGBE_EN_AUTO_NEG_SPEED_GMII | \
+ MVGBE_DTE_ADV_0 | \
+ MVGBE_MIIPHY_MAC_MODE | \
+ MVGBE_AUTO_NEG_NO_CHANGE | \
+ MVGBE_MAX_RX_PACKET_1552BYTE | \
+ MVGBE_CLR_EXT_LOOPBACK | \
+ MVGBE_SET_FULL_DUPLEX_MODE | \
+ MVGBE_DIS_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX)
+#endif
+
+/* Tx WRR confoguration macros */
+#define PORT_MAX_TRAN_UNIT 0x24 /* MTU register (default) 9KByte */
+#define PORT_MAX_TOKEN_BUCKET_SIZE 0x_FFFF /* PMTBS reg (default) */
+#define PORT_TOKEN_RATE 1023 /* PTTBRC reg (default) */
+/* MAC accepet/reject macros */
+#define ACCEPT_MAC_ADDR 0
+#define REJECT_MAC_ADDR 1
+/* Size of a Tx/Rx descriptor used in chain list data structure */
+#define MV_RXQ_DESC_ALIGNED_SIZE \
+ (((sizeof(struct mvgbe_rxdesc) / PKTALIGN) + 1) * PKTALIGN)
+/* Buffer offset from buffer pointer */
+#define RX_BUF_OFFSET 0x2
+
+/* Port serial status reg (PSR) */
+#define MVGBE_INTERFACE_GMII_MII 0
+#define MVGBE_INTERFACE_PCM 1
+#define MVGBE_LINK_IS_DOWN 0
+#define MVGBE_LINK_IS_UP (1 << 1)
+#define MVGBE_PORT_AT_HALF_DUPLEX 0
+#define MVGBE_PORT_AT_FULL_DUPLEX (1 << 2)
+#define MVGBE_RX_FLOW_CTRL_DISD 0
+#define MVGBE_RX_FLOW_CTRL_ENBALED (1 << 3)
+#define MVGBE_GMII_SPEED_100_10 0
+#define MVGBE_GMII_SPEED_1000 (1 << 4)
+#define MVGBE_MII_SPEED_10 0
+#define MVGBE_MII_SPEED_100 (1 << 5)
+#define MVGBE_NO_TX 0
+#define MVGBE_TX_IN_PROGRESS (1 << 7)
+#define MVGBE_BYPASS_NO_ACTIVE 0
+#define MVGBE_BYPASS_ACTIVE (1 << 8)
+#define MVGBE_PORT_NOT_AT_PARTN_STT 0
+#define MVGBE_PORT_AT_PARTN_STT (1 << 9)
+#define MVGBE_PORT_TX_FIFO_NOT_EMPTY 0
+#define MVGBE_PORT_TX_FIFO_EMPTY (1 << 10)
+
+/* These macros describes the Port configuration reg (Px_cR) bits */
+#define MVGBE_UCAST_MOD_NRML 0
+#define MVGBE_UNICAST_PROMISCUOUS_MODE 1
+#define MVGBE_DFLT_RXQ(_x) (_x << 1)
+#define MVGBE_DFLT_RX_ARPQ(_x) (_x << 4)
+#define MVGBE_RX_BC_IF_NOT_IP_OR_ARP 0
+#define MVGBE_REJECT_BC_IF_NOT_IP_OR_ARP (1 << 7)
+#define MVGBE_RX_BC_IF_IP 0
+#define MVGBE_REJECT_BC_IF_IP (1 << 8)
+#define MVGBE_RX_BC_IF_ARP 0
+#define MVGBE_REJECT_BC_IF_ARP (1 << 9)
+#define MVGBE_TX_AM_NO_UPDATE_ERR_SMRY (1 << 12)
+#define MVGBE_CPTR_TCP_FRMS_DIS 0
+#define MVGBE_CPTR_TCP_FRMS_EN (1 << 14)
+#define MVGBE_CPTR_UDP_FRMS_DIS 0
+#define MVGBE_CPTR_UDP_FRMS_EN (1 << 15)
+#define MVGBE_DFLT_RX_TCPQ(_x) (_x << 16)
+#define MVGBE_DFLT_RX_UDPQ(_x) (_x << 19)
+#define MVGBE_DFLT_RX_BPDUQ(_x) (_x << 22)
+#define MVGBE_DFLT_RX_TCP_CHKSUM_MODE (1 << 25)
+
+/* These macros describes the Port configuration extend reg (Px_cXR) bits*/
+#define MVGBE_CLASSIFY_EN 1
+#define MVGBE_SPAN_BPDU_PACKETS_AS_NORMAL 0
+#define MVGBE_SPAN_BPDU_PACKETS_TO_RX_Q7 (1 << 1)
+#define MVGBE_PARTITION_DIS 0
+#define MVGBE_PARTITION_EN (1 << 2)
+#define MVGBE_TX_CRC_GENERATION_EN 0
+#define MVGBE_TX_CRC_GENERATION_DIS (1 << 3)
+
+/* These macros describes the Port Sdma configuration reg (SDCR) bits */
+#define MVGBE_RIFB 1
+#define MVGBE_RX_BURST_SIZE_1_64BIT 0
+#define MVGBE_RX_BURST_SIZE_2_64BIT (1 << 1)
+#define MVGBE_RX_BURST_SIZE_4_64BIT (1 << 2)
+#define MVGBE_RX_BURST_SIZE_8_64BIT ((1 << 2) | (1 << 1))
+#define MVGBE_RX_BURST_SIZE_16_64BIT (1 << 3)
+#define MVGBE_BLM_RX_NO_SWAP (1 << 4)
+#define MVGBE_BLM_RX_BYTE_SWAP 0
+#define MVGBE_BLM_TX_NO_SWAP (1 << 5)
+#define MVGBE_BLM_TX_BYTE_SWAP 0
+#define MVGBE_DESCRIPTORS_BYTE_SWAP (1 << 6)
+#define MVGBE_DESCRIPTORS_NO_SWAP 0
+#define MVGBE_TX_BURST_SIZE_1_64BIT 0
+#define MVGBE_TX_BURST_SIZE_2_64BIT (1 << 22)
+#define MVGBE_TX_BURST_SIZE_4_64BIT (1 << 23)
+#define MVGBE_TX_BURST_SIZE_8_64BIT ((1 << 23) | (1 << 22))
+#define MVGBE_TX_BURST_SIZE_16_64BIT (1 << 24)
+
+/* These macros describes the Port serial control reg (PSCR) bits */
+#define MVGBE_SERIAL_PORT_DIS 0
+#define MVGBE_SERIAL_PORT_EN 1
+#define MVGBE_FORCE_LINK_PASS (1 << 1)
+#define MVGBE_DO_NOT_FORCE_LINK_PASS 0
+#define MVGBE_EN_AUTO_NEG_FOR_DUPLX 0
+#define MVGBE_DIS_AUTO_NEG_FOR_DUPLX (1 << 2)
+#define MVGBE_EN_AUTO_NEG_FOR_FLOW_CTRL 0
+#define MVGBE_DIS_AUTO_NEG_FOR_FLOW_CTRL (1 << 3)
+#define MVGBE_ADV_NO_FLOW_CTRL 0
+#define MVGBE_ADV_SYMMETRIC_FLOW_CTRL (1 << 4)
+#define MVGBE_FORCE_FC_MODE_NO_PAUSE_DIS_TX 0
+#define MVGBE_FORCE_FC_MODE_TX_PAUSE_DIS (1 << 5)
+#define MVGBE_FORCE_BP_MODE_NO_JAM 0
+#define MVGBE_FORCE_BP_MODE_JAM_TX (1 << 7)
+#define MVGBE_FORCE_BP_MODE_JAM_TX_ON_RX_ERR (1 << 8)
+#define MVGBE_FORCE_LINK_FAIL 0
+#define MVGBE_DO_NOT_FORCE_LINK_FAIL (1 << 10)
+#define MVGBE_DIS_AUTO_NEG_SPEED_GMII (1 << 13)
+#define MVGBE_EN_AUTO_NEG_SPEED_GMII 0
+#define MVGBE_DTE_ADV_0 0
+#define MVGBE_DTE_ADV_1 (1 << 14)
+#define MVGBE_MIIPHY_MAC_MODE 0
+#define MVGBE_MIIPHY_PHY_MODE (1 << 15)
+#define MVGBE_AUTO_NEG_NO_CHANGE 0
+#define MVGBE_RESTART_AUTO_NEG (1 << 16)
+#define MVGBE_MAX_RX_PACKET_1518BYTE 0
+#define MVGBE_MAX_RX_PACKET_1522BYTE (1 << 17)
+#define MVGBE_MAX_RX_PACKET_1552BYTE (1 << 18)
+#define MVGBE_MAX_RX_PACKET_9022BYTE ((1 << 18) | (1 << 17))
+#define MVGBE_MAX_RX_PACKET_9192BYTE (1 << 19)
+#define MVGBE_MAX_RX_PACKET_9700BYTE ((1 << 19) | (1 << 17))
+#define MVGBE_SET_EXT_LOOPBACK (1 << 20)
+#define MVGBE_CLR_EXT_LOOPBACK 0
+#define MVGBE_SET_FULL_DUPLEX_MODE (1 << 21)
+#define MVGBE_SET_HALF_DUPLEX_MODE 0
+#define MVGBE_EN_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX (1 << 22)
+#define MVGBE_DIS_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0
+#define MVGBE_SET_GMII_SPEED_TO_10_100 0
+#define MVGBE_SET_GMII_SPEED_TO_1000 (1 << 23)
+#define MVGBE_SET_MII_SPEED_TO_10 0
+#define MVGBE_SET_MII_SPEED_TO_100 (1 << 24)
+
+/* SMI register fields */
+#define MVGBE_PHY_SMI_TIMEOUT 10000
+#define MVGBE_PHY_SMI_DATA_OFFS 0 /* Data */
+#define MVGBE_PHY_SMI_DATA_MASK (0xffff << MVGBE_PHY_SMI_DATA_OFFS)
+#define MVGBE_PHY_SMI_DEV_ADDR_OFFS 16 /* PHY device address */
+#define MVGBE_PHY_SMI_DEV_ADDR_MASK \
+ (PHYADR_MASK << MVGBE_PHY_SMI_DEV_ADDR_OFFS)
+#define MVGBE_SMI_REG_ADDR_OFFS 21 /* PHY device reg addr */
+#define MVGBE_SMI_REG_ADDR_MASK \
+ (PHYADR_MASK << MVGBE_SMI_REG_ADDR_OFFS)
+#define MVGBE_PHY_SMI_OPCODE_OFFS 26 /* Write/Read opcode */
+#define MVGBE_PHY_SMI_OPCODE_MASK (3 << MVGBE_PHY_SMI_OPCODE_OFFS)
+#define MVGBE_PHY_SMI_OPCODE_WRITE (0 << MVGBE_PHY_SMI_OPCODE_OFFS)
+#define MVGBE_PHY_SMI_OPCODE_READ (1 << MVGBE_PHY_SMI_OPCODE_OFFS)
+#define MVGBE_PHY_SMI_READ_VALID_MASK (1 << 27) /* Read Valid */
+#define MVGBE_PHY_SMI_BUSY_MASK (1 << 28) /* Busy */
+
+/* SDMA command status fields macros */
+/* Tx & Rx descriptors status */
+#define MVGBE_ERROR_SUMMARY 1
+/* Tx & Rx descriptors command */
+#define MVGBE_BUFFER_OWNED_BY_DMA (1 << 31)
+/* Tx descriptors status */
+#define MVGBE_LC_ERROR 0
+#define MVGBE_UR_ERROR (1 << 1)
+#define MVGBE_RL_ERROR (1 << 2)
+#define MVGBE_LLC_SNAP_FORMAT (1 << 9)
+#define MVGBE_TX_LAST_FRAME (1 << 20)
+
+/* Rx descriptors status */
+#define MVGBE_CRC_ERROR 0
+#define MVGBE_OVERRUN_ERROR (1 << 1)
+#define MVGBE_MAX_FRAME_LENGTH_ERROR (1 << 2)
+#define MVGBE_RESOURCE_ERROR ((1 << 2) | (1 << 1))
+#define MVGBE_VLAN_TAGGED (1 << 19)
+#define MVGBE_BPDU_FRAME (1 << 20)
+#define MVGBE_TCP_FRAME_OVER_IP_V_4 0
+#define MVGBE_UDP_FRAME_OVER_IP_V_4 (1 << 21)
+#define MVGBE_OTHER_FRAME_TYPE (1 << 22)
+#define MVGBE_LAYER_2_IS_MVGBE_V_2 (1 << 23)
+#define MVGBE_FRAME_TYPE_IP_V_4 (1 << 24)
+#define MVGBE_FRAME_HEADER_OK (1 << 25)
+#define MVGBE_RX_LAST_DESC (1 << 26)
+#define MVGBE_RX_FIRST_DESC (1 << 27)
+#define MVGBE_UNKNOWN_DESTINATION_ADDR (1 << 28)
+#define MVGBE_RX_EN_INTERRUPT (1 << 29)
+#define MVGBE_LAYER_4_CHECKSUM_OK (1 << 30)
+
+/* Rx descriptors byte count */
+#define MVGBE_FRAME_FRAGMENTED (1 << 2)
+
+/* Tx descriptors command */
+#define MVGBE_LAYER_4_CHECKSUM_FIRST_DESC (1 << 10)
+#define MVGBE_FRAME_SET_TO_VLAN (1 << 15)
+#define MVGBE_TCP_FRAME 0
+#define MVGBE_UDP_FRAME (1 << 16)
+#define MVGBE_GEN_TCP_UDP_CHECKSUM (1 << 17)
+#define MVGBE_GEN_IP_V_4_CHECKSUM (1 << 18)
+#define MVGBE_ZERO_PADDING (1 << 19)
+#define MVGBE_TX_LAST_DESC (1 << 20)
+#define MVGBE_TX_FIRST_DESC (1 << 21)
+#define MVGBE_GEN_CRC (1 << 22)
+#define MVGBE_TX_EN_INTERRUPT (1 << 23)
+#define MVGBE_AUTO_MODE (1 << 30)
+
+/* Address decode parameters */
+/* Ethernet Base Address Register bits */
+#define EBAR_TARGET_DRAM 0x00000000
+#define EBAR_TARGET_DEVICE 0x00000001
+#define EBAR_TARGET_CBS 0x00000002
+#define EBAR_TARGET_PCI0 0x00000003
+#define EBAR_TARGET_PCI1 0x00000004
+#define EBAR_TARGET_CUNIT 0x00000005
+#define EBAR_TARGET_AUNIT 0x00000006
+#define EBAR_TARGET_GUNIT 0x00000007
+
+/* Window attrib */
+#if defined(CONFIG_DOVE)
+#define EBAR_DRAM_CS0 0x00000000
+#define EBAR_DRAM_CS1 0x00000000
+#define EBAR_DRAM_CS2 0x00000000
+#define EBAR_DRAM_CS3 0x00000000
+#else
+#define EBAR_DRAM_CS0 0x00000E00
+#define EBAR_DRAM_CS1 0x00000D00
+#define EBAR_DRAM_CS2 0x00000B00
+#define EBAR_DRAM_CS3 0x00000700
+#endif
+
+/* DRAM Target interface */
+#define EBAR_DRAM_NO_CACHE_COHERENCY 0x00000000
+#define EBAR_DRAM_CACHE_COHERENCY_WT 0x00001000
+#define EBAR_DRAM_CACHE_COHERENCY_WB 0x00002000
+
+/* Device Bus Target interface */
+#define EBAR_DEVICE_DEVCS0 0x00001E00
+#define EBAR_DEVICE_DEVCS1 0x00001D00
+#define EBAR_DEVICE_DEVCS2 0x00001B00
+#define EBAR_DEVICE_DEVCS3 0x00001700
+#define EBAR_DEVICE_BOOTCS3 0x00000F00
+
+/* PCI Target interface */
+#define EBAR_PCI_BYTE_SWAP 0x00000000
+#define EBAR_PCI_NO_SWAP 0x00000100
+#define EBAR_PCI_BYTE_WORD_SWAP 0x00000200
+#define EBAR_PCI_WORD_SWAP 0x00000300
+#define EBAR_PCI_NO_SNOOP_NOT_ASSERT 0x00000000
+#define EBAR_PCI_NO_SNOOP_ASSERT 0x00000400
+#define EBAR_PCI_IO_SPACE 0x00000000
+#define EBAR_PCI_MEMORY_SPACE 0x00000800
+#define EBAR_PCI_REQ64_FORCE 0x00000000
+#define EBAR_PCI_REQ64_SIZE 0x00001000
+
+/* Window access control */
+#define EWIN_ACCESS_NOT_ALLOWED 0
+#define EWIN_ACCESS_READ_ONLY 1
+#define EWIN_ACCESS_FULL ((1 << 1) | 1)
+
+/* structures represents Controller registers */
+struct mvgbe_barsz {
+ u32 bar;
+ u32 size;
+};
+
+struct mvgbe_rxcdp {
+ struct mvgbe_rxdesc *rxcdp;
+ u32 rxcdp_pad[3];
+};
+
+struct mvgbe_tqx {
+ u32 qxttbc;
+ u32 tqxtbc;
+ u32 tqxac;
+ u32 tqxpad;
+};
+
+struct mvgbe_registers {
+ u32 phyadr;
+ u32 smi;
+ u32 euda;
+ u32 eudid;
+ u8 pad1[0x080 - 0x00c - 4];
+ u32 euic;
+ u32 euim;
+ u8 pad2[0x094 - 0x084 - 4];
+ u32 euea;
+ u32 euiae;
+ u8 pad3[0x0b0 - 0x098 - 4];
+ u32 euc;
+ u8 pad3a[0x200 - 0x0b0 - 4];
+ struct mvgbe_barsz barsz[6];
+ u8 pad4[0x280 - 0x22c - 4];
+ u32 ha_remap[4];
+ u32 bare;
+ u32 epap;
+ u8 pad5[0x400 - 0x294 - 4];
+ u32 pxc;
+ u32 pxcx;
+ u32 mii_ser_params;
+ u8 pad6[0x410 - 0x408 - 4];
+ u32 evlane;
+ u32 macal;
+ u32 macah;
+ u32 sdc;
+ u32 dscp[7];
+ u32 psc0;
+ u32 vpt2p;
+ u32 ps0;
+ u32 tqc;
+ u32 psc1;
+ u32 ps1;
+ u32 mrvl_header;
+ u8 pad7[0x460 - 0x454 - 4];
+ u32 ic;
+ u32 ice;
+ u32 pim;
+ u32 peim;
+ u8 pad8[0x474 - 0x46c - 4];
+ u32 pxtfut;
+ u32 pad9;
+ u32 pxmfs;
+ u32 pad10;
+ u32 pxdfc;
+ u32 pxofc;
+ u8 pad11[0x494 - 0x488 - 4];
+ u32 peuiae;
+ u8 pad12[0x4bc - 0x494 - 4];
+ u32 eth_type_prio;
+ u8 pad13[0x4dc - 0x4bc - 4];
+ u32 tqfpc;
+ u32 pttbrc;
+ u32 tqc1;
+ u32 pmtu;
+ u32 pmtbs;
+ u8 pad14[0x60c - 0x4ec - 4];
+ struct mvgbe_rxcdp rxcdp[7];
+ struct mvgbe_rxdesc *rxcdp7;
+ u32 rqc;
+ struct mvgbe_txdesc *tcsdp;
+ u8 pad15[0x6c0 - 0x684 - 4];
+ struct mvgbe_txdesc *tcqdp[8];
+ u8 pad16[0x700 - 0x6dc - 4];
+ struct mvgbe_tqx tqx[8];
+ u32 pttbc;
+ u8 pad17[0x7a8 - 0x780 - 4];
+ u32 tqxipg0;
+ u32 pad18[3];
+ u32 tqxipg1;
+ u8 pad19[0x7c0 - 0x7b8 - 4];
+ u32 hitkninlopkt;
+ u32 hitkninasyncpkt;
+ u32 lotkninasyncpkt;
+ u32 pad20;
+ u32 ts;
+ u8 pad21[0x3000 - 0x27d0 - 4];
+ u32 pad20_1[32]; /* mib counter registes */
+ u8 pad22[0x3400 - 0x3000 - sizeof(u32) * 32];
+ u32 dfsmt[64];
+ u32 dfomt[64];
+ u32 dfut[4];
+ u8 pad23[0xe20c0 - 0x7360c - 4];
+ u32 pmbus_top_arbiter;
+};
+
+/* structures/enums needed by driver */
+enum mvgbe_adrwin {
+ MVGBE_WIN0,
+ MVGBE_WIN1,
+ MVGBE_WIN2,
+ MVGBE_WIN3,
+ MVGBE_WIN4,
+ MVGBE_WIN5
+};
+
+enum mvgbe_target {
+ MVGBE_TARGET_DRAM,
+ MVGBE_TARGET_DEV,
+ MVGBE_TARGET_CBS,
+ MVGBE_TARGET_PCI0,
+ MVGBE_TARGET_PCI1
+};
+
+struct mvgbe_winparam {
+ enum mvgbe_adrwin win; /* Window number */
+ enum mvgbe_target target; /* System targets */
+ u16 attrib; /* BAR attrib. See above macros */
+ u32 base_addr; /* Window base address in u32 form */
+ u32 high_addr; /* Window high address in u32 form */
+ u32 size; /* Size in MBytes. Must be % 64Kbyte. */
+ int enable; /* Enable/disable access to the window. */
+ u16 access_ctrl; /*Access ctrl register. see above macros */
+};
+
+struct mvgbe_rxdesc {
+ u32 cmd_sts; /* Descriptor command status */
+ u16 buf_size; /* Buffer size */
+ u16 byte_cnt; /* Descriptor buffer byte count */
+ u8 *buf_ptr; /* Descriptor buffer pointer */
+ struct mvgbe_rxdesc *nxtdesc_p; /* Next descriptor pointer */
+};
+
+struct mvgbe_txdesc {
+ u32 cmd_sts; /* Descriptor command status */
+ u16 l4i_chk; /* CPU provided TCP Checksum */
+ u16 byte_cnt; /* Descriptor buffer byte count */
+ u8 *buf_ptr; /* Descriptor buffer ptr */
+ struct mvgbe_txdesc *nxtdesc_p; /* Next descriptor ptr */
+};
+
+/* port device data struct */
+struct mvgbe_device {
+ struct eth_device dev;
+ struct mvgbe_registers *regs;
+ struct mvgbe_txdesc *p_txdesc;
+ struct mvgbe_rxdesc *p_rxdesc;
+ struct mvgbe_rxdesc *p_rxdesc_curr;
+ u8 *p_rxbuf;
+ u8 *p_aligned_txbuf;
+};
+
+#endif /* __MVGBE_H__ */
diff --git a/qemu/roms/u-boot/drivers/net/natsemi.c b/qemu/roms/u-boot/drivers/net/natsemi.c
new file mode 100644
index 000000000..04743bd2b
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/natsemi.c
@@ -0,0 +1,882 @@
+/*
+ natsemi.c: A U-Boot driver for the NatSemi DP8381x series.
+ Author: Mark A. Rakes (mark_rakes@vivato.net)
+
+ Adapted from an Etherboot driver written by:
+
+ Copyright (C) 2001 Entity Cyber, Inc.
+
+ This development of this Etherboot driver was funded by
+
+ Sicom Systems: http://www.sicompos.com/
+
+ Author: Marty Connor (mdc@thinguin.org)
+ Adapted from a Linux driver which was written by Donald Becker
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License (GPL), incorporated herein by reference.
+
+ Original Copyright Notice:
+
+ Written/copyright 1999-2001 by Donald Becker.
+
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+ a complete program and may only be used when the entire operating
+ system is licensed under the GPL. License for under other terms may be
+ available. Contact the original author for details.
+
+ The original author may be reached as becker@scyld.com, or at
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ Support information and updates available at
+ http://www.scyld.com/network/netsemi.html
+
+ References:
+ http://www.scyld.com/expert/100mbps.html
+ http://www.scyld.com/expert/NWay.html
+ Datasheet is available from:
+ http://www.national.com/pf/DP/DP83815.html
+*/
+
+/* Revision History
+ * October 2002 mar 1.0
+ * Initial U-Boot Release. Tested with Netgear FA311 board
+ * and dp83815 chipset on custom board
+*/
+
+/* Includes */
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <pci.h>
+
+/* defines */
+#define EEPROM_SIZE 0xb /*12 16-bit chunks, or 24 bytes*/
+
+#define DSIZE 0x00000FFF
+#define ETH_ALEN 6
+#define CRC_SIZE 4
+#define TOUT_LOOP 500000
+#define TX_BUF_SIZE 1536
+#define RX_BUF_SIZE 1536
+#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
+
+/* Offsets to the device registers.
+ Unlike software-only systems, device drivers interact with complex hardware.
+ It's not useful to define symbolic names for every register bit in the
+ device. */
+enum register_offsets {
+ ChipCmd = 0x00,
+ ChipConfig = 0x04,
+ EECtrl = 0x08,
+ IntrMask = 0x14,
+ IntrEnable = 0x18,
+ TxRingPtr = 0x20,
+ TxConfig = 0x24,
+ RxRingPtr = 0x30,
+ RxConfig = 0x34,
+ ClkRun = 0x3C,
+ RxFilterAddr = 0x48,
+ RxFilterData = 0x4C,
+ SiliconRev = 0x58,
+ PCIPM = 0x44,
+ BasicControl = 0x80,
+ BasicStatus = 0x84,
+ /* These are from the spec, around page 78... on a separate table. */
+ PGSEL = 0xCC,
+ PMDCSR = 0xE4,
+ TSTDAT = 0xFC,
+ DSPCFG = 0xF4,
+ SDCFG = 0x8C
+};
+
+/* Bit in ChipCmd. */
+enum ChipCmdBits {
+ ChipReset = 0x100,
+ RxReset = 0x20,
+ TxReset = 0x10,
+ RxOff = 0x08,
+ RxOn = 0x04,
+ TxOff = 0x02,
+ TxOn = 0x01
+};
+
+enum ChipConfigBits {
+ LinkSts = 0x80000000,
+ HundSpeed = 0x40000000,
+ FullDuplex = 0x20000000,
+ TenPolarity = 0x10000000,
+ AnegDone = 0x08000000,
+ AnegEnBothBoth = 0x0000E000,
+ AnegDis100Full = 0x0000C000,
+ AnegEn100Both = 0x0000A000,
+ AnegDis100Half = 0x00008000,
+ AnegEnBothHalf = 0x00006000,
+ AnegDis10Full = 0x00004000,
+ AnegEn10Both = 0x00002000,
+ DuplexMask = 0x00008000,
+ SpeedMask = 0x00004000,
+ AnegMask = 0x00002000,
+ AnegDis10Half = 0x00000000,
+ ExtPhy = 0x00001000,
+ PhyRst = 0x00000400,
+ PhyDis = 0x00000200,
+ BootRomDisable = 0x00000004,
+ BEMode = 0x00000001,
+};
+
+enum TxConfig_bits {
+ TxDrthMask = 0x3f,
+ TxFlthMask = 0x3f00,
+ TxMxdmaMask = 0x700000,
+ TxMxdma_512 = 0x0,
+ TxMxdma_4 = 0x100000,
+ TxMxdma_8 = 0x200000,
+ TxMxdma_16 = 0x300000,
+ TxMxdma_32 = 0x400000,
+ TxMxdma_64 = 0x500000,
+ TxMxdma_128 = 0x600000,
+ TxMxdma_256 = 0x700000,
+ TxCollRetry = 0x800000,
+ TxAutoPad = 0x10000000,
+ TxMacLoop = 0x20000000,
+ TxHeartIgn = 0x40000000,
+ TxCarrierIgn = 0x80000000
+};
+
+enum RxConfig_bits {
+ RxDrthMask = 0x3e,
+ RxMxdmaMask = 0x700000,
+ RxMxdma_512 = 0x0,
+ RxMxdma_4 = 0x100000,
+ RxMxdma_8 = 0x200000,
+ RxMxdma_16 = 0x300000,
+ RxMxdma_32 = 0x400000,
+ RxMxdma_64 = 0x500000,
+ RxMxdma_128 = 0x600000,
+ RxMxdma_256 = 0x700000,
+ RxAcceptLong = 0x8000000,
+ RxAcceptTx = 0x10000000,
+ RxAcceptRunt = 0x40000000,
+ RxAcceptErr = 0x80000000
+};
+
+/* Bits in the RxMode register. */
+enum rx_mode_bits {
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0xC0000000,
+ AcceptMulticast = 0x00200000,
+ AcceptAllMulticast = 0x20000000,
+ AcceptAllPhys = 0x10000000,
+ AcceptMyPhys = 0x08000000
+};
+
+typedef struct _BufferDesc {
+ u32 link;
+ vu_long cmdsts;
+ u32 bufptr;
+ u32 software_use;
+} BufferDesc;
+
+/* Bits in network_desc.status */
+enum desc_status_bits {
+ DescOwn = 0x80000000, DescMore = 0x40000000, DescIntr = 0x20000000,
+ DescNoCRC = 0x10000000, DescPktOK = 0x08000000,
+ DescSizeMask = 0xfff,
+
+ DescTxAbort = 0x04000000, DescTxFIFO = 0x02000000,
+ DescTxCarrier = 0x01000000, DescTxDefer = 0x00800000,
+ DescTxExcDefer = 0x00400000, DescTxOOWCol = 0x00200000,
+ DescTxExcColl = 0x00100000, DescTxCollCount = 0x000f0000,
+
+ DescRxAbort = 0x04000000, DescRxOver = 0x02000000,
+ DescRxDest = 0x01800000, DescRxLong = 0x00400000,
+ DescRxRunt = 0x00200000, DescRxInvalid = 0x00100000,
+ DescRxCRC = 0x00080000, DescRxAlign = 0x00040000,
+ DescRxLoop = 0x00020000, DesRxColl = 0x00010000,
+};
+
+/* Globals */
+#ifdef NATSEMI_DEBUG
+static int natsemi_debug = 0; /* 1 verbose debugging, 0 normal */
+#endif
+static u32 SavedClkRun;
+static unsigned int cur_rx;
+static unsigned int advertising;
+static unsigned int rx_config;
+static unsigned int tx_config;
+
+/* Note: transmit and receive buffers and descriptors must be
+ longword aligned */
+static BufferDesc txd __attribute__ ((aligned(4)));
+static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(4)));
+
+static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4)));
+static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]
+ __attribute__ ((aligned(4)));
+
+/* Function Prototypes */
+#if 0
+static void write_eeprom(struct eth_device *dev, long addr, int location,
+ short value);
+#endif
+static int read_eeprom(struct eth_device *dev, long addr, int location);
+static int mdio_read(struct eth_device *dev, int phy_id, int location);
+static int natsemi_init(struct eth_device *dev, bd_t * bis);
+static void natsemi_reset(struct eth_device *dev);
+static void natsemi_init_rxfilter(struct eth_device *dev);
+static void natsemi_init_txd(struct eth_device *dev);
+static void natsemi_init_rxd(struct eth_device *dev);
+static void natsemi_set_rx_mode(struct eth_device *dev);
+static void natsemi_check_duplex(struct eth_device *dev);
+static int natsemi_send(struct eth_device *dev, void *packet, int length);
+static int natsemi_poll(struct eth_device *dev);
+static void natsemi_disable(struct eth_device *dev);
+
+static struct pci_device_id supported[] = {
+ {PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815},
+ {}
+};
+
+#define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
+
+static inline int
+INW(struct eth_device *dev, u_long addr)
+{
+ return le16_to_cpu(*(vu_short *) (addr + dev->iobase));
+}
+
+static int
+INL(struct eth_device *dev, u_long addr)
+{
+ return le32_to_cpu(*(vu_long *) (addr + dev->iobase));
+}
+
+static inline void
+OUTW(struct eth_device *dev, int command, u_long addr)
+{
+ *(vu_short *) ((addr + dev->iobase)) = cpu_to_le16(command);
+}
+
+static inline void
+OUTL(struct eth_device *dev, int command, u_long addr)
+{
+ *(vu_long *) ((addr + dev->iobase)) = cpu_to_le32(command);
+}
+
+/*
+ * Function: natsemi_initialize
+ *
+ * Description: Retrieves the MAC address of the card, and sets up some
+ * globals required by other routines, and initializes the NIC, making it
+ * ready to send and receive packets.
+ *
+ * Side effects:
+ * leaves the natsemi initialized, and ready to receive packets.
+ *
+ * Returns: struct eth_device *: pointer to NIC data structure
+ */
+
+int
+natsemi_initialize(bd_t * bis)
+{
+ pci_dev_t devno;
+ int card_number = 0;
+ struct eth_device *dev;
+ u32 iobase, status, chip_config;
+ int i, idx = 0;
+ int prev_eedata;
+ u32 tmp;
+
+ while (1) {
+ /* Find PCI device(s) */
+ if ((devno = pci_find_devices(supported, idx++)) < 0) {
+ break;
+ }
+
+ pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &iobase);
+ iobase &= ~0x3; /* bit 1: unused and bit 0: I/O Space Indicator */
+
+ pci_write_config_dword(devno, PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ /* Check if I/O accesses and Bus Mastering are enabled. */
+ pci_read_config_dword(devno, PCI_COMMAND, &status);
+ if (!(status & PCI_COMMAND_MEMORY)) {
+ printf("Error: Can not enable MEM access.\n");
+ continue;
+ } else if (!(status & PCI_COMMAND_MASTER)) {
+ printf("Error: Can not enable Bus Mastering.\n");
+ continue;
+ }
+
+ dev = (struct eth_device *) malloc(sizeof *dev);
+ if (!dev) {
+ printf("natsemi: Can not allocate memory\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf(dev->name, "dp83815#%d", card_number);
+ dev->iobase = bus_to_phys(iobase);
+#ifdef NATSEMI_DEBUG
+ printf("natsemi: NatSemi ns8381[56] @ %#x\n", dev->iobase);
+#endif
+ dev->priv = (void *) devno;
+ dev->init = natsemi_init;
+ dev->halt = natsemi_disable;
+ dev->send = natsemi_send;
+ dev->recv = natsemi_poll;
+
+ eth_register(dev);
+
+ card_number++;
+
+ /* Set the latency timer for value. */
+ pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x20);
+
+ udelay(10 * 1000);
+
+ /* natsemi has a non-standard PM control register
+ * in PCI config space. Some boards apparently need
+ * to be brought to D0 in this manner. */
+ pci_read_config_dword(devno, PCIPM, &tmp);
+ if (tmp & (0x03 | 0x100)) {
+ /* D0 state, disable PME assertion */
+ u32 newtmp = tmp & ~(0x03 | 0x100);
+ pci_write_config_dword(devno, PCIPM, newtmp);
+ }
+
+ printf("natsemi: EEPROM contents:\n");
+ for (i = 0; i <= EEPROM_SIZE; i++) {
+ short eedata = read_eeprom(dev, EECtrl, i);
+ printf(" %04hx", eedata);
+ }
+ printf("\n");
+
+ /* get MAC address */
+ prev_eedata = read_eeprom(dev, EECtrl, 6);
+ for (i = 0; i < 3; i++) {
+ int eedata = read_eeprom(dev, EECtrl, i + 7);
+ dev->enetaddr[i*2] = (eedata << 1) + (prev_eedata >> 15);
+ dev->enetaddr[i*2+1] = eedata >> 7;
+ prev_eedata = eedata;
+ }
+
+ /* Reset the chip to erase any previous misconfiguration. */
+ OUTL(dev, ChipReset, ChipCmd);
+
+ advertising = mdio_read(dev, 1, 4);
+ chip_config = INL(dev, ChipConfig);
+#ifdef NATSEMI_DEBUG
+ printf("%s: Transceiver status %#08X advertising %#08X\n",
+ dev->name, (int) INL(dev, BasicStatus), advertising);
+ printf("%s: Transceiver default autoneg. %s 10%s %s duplex.\n",
+ dev->name, chip_config & AnegMask ? "enabled, advertise" :
+ "disabled, force", chip_config & SpeedMask ? "0" : "",
+ chip_config & DuplexMask ? "full" : "half");
+#endif
+ chip_config |= AnegEnBothBoth;
+#ifdef NATSEMI_DEBUG
+ printf("%s: changed to autoneg. %s 10%s %s duplex.\n",
+ dev->name, chip_config & AnegMask ? "enabled, advertise" :
+ "disabled, force", chip_config & SpeedMask ? "0" : "",
+ chip_config & DuplexMask ? "full" : "half");
+#endif
+ /*write new autoneg bits, reset phy*/
+ OUTL(dev, (chip_config | PhyRst), ChipConfig);
+ /*un-reset phy*/
+ OUTL(dev, chip_config, ChipConfig);
+
+ /* Disable PME:
+ * The PME bit is initialized from the EEPROM contents.
+ * PCI cards probably have PME disabled, but motherboard
+ * implementations may have PME set to enable WakeOnLan.
+ * With PME set the chip will scan incoming packets but
+ * nothing will be written to memory. */
+ SavedClkRun = INL(dev, ClkRun);
+ OUTL(dev, SavedClkRun & ~0x100, ClkRun);
+ }
+ return card_number;
+}
+
+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
+ The EEPROM code is for common 93c06/46 EEPROMs w/ 6bit addresses. */
+
+/* Delay between EEPROM clock transitions.
+ No extra delay is needed with 33MHz PCI, but future 66MHz
+ access may need a delay. */
+#define eeprom_delay(ee_addr) INL(dev, ee_addr)
+
+enum EEPROM_Ctrl_Bits {
+ EE_ShiftClk = 0x04,
+ EE_DataIn = 0x01,
+ EE_ChipSelect = 0x08,
+ EE_DataOut = 0x02
+};
+
+#define EE_Write0 (EE_ChipSelect)
+#define EE_Write1 (EE_ChipSelect | EE_DataIn)
+/* The EEPROM commands include the alway-set leading bit. */
+enum EEPROM_Cmds {
+ EE_WrEnCmd = (4 << 6), EE_WriteCmd = (5 << 6),
+ EE_ReadCmd = (6 << 6), EE_EraseCmd = (7 << 6),
+};
+
+#if 0
+static void
+write_eeprom(struct eth_device *dev, long addr, int location, short value)
+{
+ int i;
+ int ee_addr = (typeof(ee_addr))addr;
+ short wren_cmd = EE_WrEnCmd | 0x30; /*wren is 100 + 11XXXX*/
+ short write_cmd = location | EE_WriteCmd;
+
+#ifdef NATSEMI_DEBUG
+ printf("write_eeprom: %08x, %04hx, %04hx\n",
+ dev->iobase + ee_addr, write_cmd, value);
+#endif
+ /* Shift the write enable command bits out. */
+ for (i = 9; i >= 0; i--) {
+ short cmdval = (wren_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
+ OUTL(dev, cmdval, ee_addr);
+ eeprom_delay(ee_addr);
+ OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
+ eeprom_delay(ee_addr);
+ }
+
+ OUTL(dev, 0, ee_addr); /*bring chip select low*/
+ OUTL(dev, EE_ShiftClk, ee_addr);
+ eeprom_delay(ee_addr);
+
+ /* Shift the write command bits out. */
+ for (i = 9; i >= 0; i--) {
+ short cmdval = (write_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
+ OUTL(dev, cmdval, ee_addr);
+ eeprom_delay(ee_addr);
+ OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
+ eeprom_delay(ee_addr);
+ }
+
+ for (i = 0; i < 16; i++) {
+ short cmdval = (value & (1 << i)) ? EE_Write1 : EE_Write0;
+ OUTL(dev, cmdval, ee_addr);
+ eeprom_delay(ee_addr);
+ OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
+ eeprom_delay(ee_addr);
+ }
+
+ OUTL(dev, 0, ee_addr); /*bring chip select low*/
+ OUTL(dev, EE_ShiftClk, ee_addr);
+ for (i = 0; i < 200000; i++) {
+ OUTL(dev, EE_Write0, ee_addr); /*poll for done*/
+ if (INL(dev, ee_addr) & EE_DataOut) {
+ break; /*finished*/
+ }
+ }
+ eeprom_delay(ee_addr);
+
+ /* Terminate the EEPROM access. */
+ OUTL(dev, EE_Write0, ee_addr);
+ OUTL(dev, 0, ee_addr);
+ return;
+}
+#endif
+
+static int
+read_eeprom(struct eth_device *dev, long addr, int location)
+{
+ int i;
+ int retval = 0;
+ int ee_addr = (typeof(ee_addr))addr;
+ int read_cmd = location | EE_ReadCmd;
+
+ OUTL(dev, EE_Write0, ee_addr);
+
+ /* Shift the read command bits out. */
+ for (i = 10; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
+ OUTL(dev, dataval, ee_addr);
+ eeprom_delay(ee_addr);
+ OUTL(dev, dataval | EE_ShiftClk, ee_addr);
+ eeprom_delay(ee_addr);
+ }
+ OUTL(dev, EE_ChipSelect, ee_addr);
+ eeprom_delay(ee_addr);
+
+ for (i = 0; i < 16; i++) {
+ OUTL(dev, EE_ChipSelect | EE_ShiftClk, ee_addr);
+ eeprom_delay(ee_addr);
+ retval |= (INL(dev, ee_addr) & EE_DataOut) ? 1 << i : 0;
+ OUTL(dev, EE_ChipSelect, ee_addr);
+ eeprom_delay(ee_addr);
+ }
+
+ /* Terminate the EEPROM access. */
+ OUTL(dev, EE_Write0, ee_addr);
+ OUTL(dev, 0, ee_addr);
+#ifdef NATSEMI_DEBUG
+ if (natsemi_debug)
+ printf("read_eeprom: %08x, %08x, retval %08x\n",
+ dev->iobase + ee_addr, read_cmd, retval);
+#endif
+ return retval;
+}
+
+/* MII transceiver control section.
+ The 83815 series has an internal transceiver, and we present the
+ management registers as if they were MII connected. */
+
+static int
+mdio_read(struct eth_device *dev, int phy_id, int location)
+{
+ if (phy_id == 1 && location < 32)
+ return INL(dev, BasicControl+(location<<2))&0xffff;
+ else
+ return 0xffff;
+}
+
+/* Function: natsemi_init
+ *
+ * Description: resets the ethernet controller chip and configures
+ * registers and data structures required for sending and receiving packets.
+ *
+ * Arguments: struct eth_device *dev: NIC data structure
+ *
+ * returns: int.
+ */
+
+static int
+natsemi_init(struct eth_device *dev, bd_t * bis)
+{
+
+ natsemi_reset(dev);
+
+ /* Disable PME:
+ * The PME bit is initialized from the EEPROM contents.
+ * PCI cards probably have PME disabled, but motherboard
+ * implementations may have PME set to enable WakeOnLan.
+ * With PME set the chip will scan incoming packets but
+ * nothing will be written to memory. */
+ OUTL(dev, SavedClkRun & ~0x100, ClkRun);
+
+ natsemi_init_rxfilter(dev);
+ natsemi_init_txd(dev);
+ natsemi_init_rxd(dev);
+
+ /* Configure the PCI bus bursts and FIFO thresholds. */
+ tx_config = TxAutoPad | TxCollRetry | TxMxdma_256 | (0x1002);
+ rx_config = RxMxdma_256 | 0x20;
+
+#ifdef NATSEMI_DEBUG
+ printf("%s: Setting TxConfig Register %#08X\n", dev->name, tx_config);
+ printf("%s: Setting RxConfig Register %#08X\n", dev->name, rx_config);
+#endif
+ OUTL(dev, tx_config, TxConfig);
+ OUTL(dev, rx_config, RxConfig);
+
+ natsemi_check_duplex(dev);
+ natsemi_set_rx_mode(dev);
+
+ OUTL(dev, (RxOn | TxOn), ChipCmd);
+ return 1;
+}
+
+/*
+ * Function: natsemi_reset
+ *
+ * Description: soft resets the controller chip
+ *
+ * Arguments: struct eth_device *dev: NIC data structure
+ *
+ * Returns: void.
+ */
+static void
+natsemi_reset(struct eth_device *dev)
+{
+ OUTL(dev, ChipReset, ChipCmd);
+
+ /* On page 78 of the spec, they recommend some settings for "optimum
+ performance" to be done in sequence. These settings optimize some
+ of the 100Mbit autodetection circuitry. Also, we only want to do
+ this for rev C of the chip. */
+ if (INL(dev, SiliconRev) == 0x302) {
+ OUTW(dev, 0x0001, PGSEL);
+ OUTW(dev, 0x189C, PMDCSR);
+ OUTW(dev, 0x0000, TSTDAT);
+ OUTW(dev, 0x5040, DSPCFG);
+ OUTW(dev, 0x008C, SDCFG);
+ }
+ /* Disable interrupts using the mask. */
+ OUTL(dev, 0, IntrMask);
+ OUTL(dev, 0, IntrEnable);
+}
+
+/* Function: natsemi_init_rxfilter
+ *
+ * Description: sets receive filter address to our MAC address
+ *
+ * Arguments: struct eth_device *dev: NIC data structure
+ *
+ * returns: void.
+ */
+
+static void
+natsemi_init_rxfilter(struct eth_device *dev)
+{
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i += 2) {
+ OUTL(dev, i, RxFilterAddr);
+ OUTW(dev, dev->enetaddr[i] + (dev->enetaddr[i + 1] << 8),
+ RxFilterData);
+ }
+}
+
+/*
+ * Function: natsemi_init_txd
+ *
+ * Description: initializes the Tx descriptor
+ *
+ * Arguments: struct eth_device *dev: NIC data structure
+ *
+ * returns: void.
+ */
+
+static void
+natsemi_init_txd(struct eth_device *dev)
+{
+ txd.link = (u32) 0;
+ txd.cmdsts = (u32) 0;
+ txd.bufptr = (u32) & txb[0];
+
+ /* load Transmit Descriptor Register */
+ OUTL(dev, (u32) & txd, TxRingPtr);
+#ifdef NATSEMI_DEBUG
+ printf("natsemi_init_txd: TX descriptor reg loaded with: %#08X\n",
+ INL(dev, TxRingPtr));
+#endif
+}
+
+/* Function: natsemi_init_rxd
+ *
+ * Description: initializes the Rx descriptor ring
+ *
+ * Arguments: struct eth_device *dev: NIC data structure
+ *
+ * Returns: void.
+ */
+
+static void
+natsemi_init_rxd(struct eth_device *dev)
+{
+ int i;
+
+ cur_rx = 0;
+
+ /* init RX descriptor */
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ rxd[i].link =
+ cpu_to_le32((i + 1 <
+ NUM_RX_DESC) ? (u32) & rxd[i +
+ 1] : (u32) &
+ rxd[0]);
+ rxd[i].cmdsts = cpu_to_le32((u32) RX_BUF_SIZE);
+ rxd[i].bufptr = cpu_to_le32((u32) & rxb[i * RX_BUF_SIZE]);
+#ifdef NATSEMI_DEBUG
+ printf
+ ("natsemi_init_rxd: rxd[%d]=%p link=%X cmdsts=%lX bufptr=%X\n",
+ i, &rxd[i], le32_to_cpu(rxd[i].link),
+ rxd[i].cmdsts, rxd[i].bufptr);
+#endif
+ }
+
+ /* load Receive Descriptor Register */
+ OUTL(dev, (u32) & rxd[0], RxRingPtr);
+
+#ifdef NATSEMI_DEBUG
+ printf("natsemi_init_rxd: RX descriptor register loaded with: %X\n",
+ INL(dev, RxRingPtr));
+#endif
+}
+
+/* Function: natsemi_set_rx_mode
+ *
+ * Description:
+ * sets the receive mode to accept all broadcast packets and packets
+ * with our MAC address, and reject all multicast packets.
+ *
+ * Arguments: struct eth_device *dev: NIC data structure
+ *
+ * Returns: void.
+ */
+
+static void
+natsemi_set_rx_mode(struct eth_device *dev)
+{
+ u32 rx_mode = AcceptBroadcast | AcceptMyPhys;
+
+ OUTL(dev, rx_mode, RxFilterAddr);
+}
+
+static void
+natsemi_check_duplex(struct eth_device *dev)
+{
+ int duplex = INL(dev, ChipConfig) & FullDuplex ? 1 : 0;
+
+#ifdef NATSEMI_DEBUG
+ printf("%s: Setting %s-duplex based on negotiated link"
+ " capability.\n", dev->name, duplex ? "full" : "half");
+#endif
+ if (duplex) {
+ rx_config |= RxAcceptTx;
+ tx_config |= (TxCarrierIgn | TxHeartIgn);
+ } else {
+ rx_config &= ~RxAcceptTx;
+ tx_config &= ~(TxCarrierIgn | TxHeartIgn);
+ }
+ OUTL(dev, tx_config, TxConfig);
+ OUTL(dev, rx_config, RxConfig);
+}
+
+/* Function: natsemi_send
+ *
+ * Description: transmits a packet and waits for completion or timeout.
+ *
+ * Returns: void. */
+static int natsemi_send(struct eth_device *dev, void *packet, int length)
+{
+ u32 i, status = 0;
+ u32 tx_status = 0;
+ u32 *tx_ptr = &tx_status;
+ vu_long *res = (vu_long *)tx_ptr;
+
+ /* Stop the transmitter */
+ OUTL(dev, TxOff, ChipCmd);
+
+#ifdef NATSEMI_DEBUG
+ if (natsemi_debug)
+ printf("natsemi_send: sending %d bytes\n", (int) length);
+#endif
+
+ /* set the transmit buffer descriptor and enable Transmit State Machine */
+ txd.link = cpu_to_le32(0);
+ txd.bufptr = cpu_to_le32(phys_to_bus((u32) packet));
+ txd.cmdsts = cpu_to_le32(DescOwn | length);
+
+ /* load Transmit Descriptor Register */
+ OUTL(dev, phys_to_bus((u32) & txd), TxRingPtr);
+#ifdef NATSEMI_DEBUG
+ if (natsemi_debug)
+ printf("natsemi_send: TX descriptor register loaded with: %#08X\n",
+ INL(dev, TxRingPtr));
+#endif
+ /* restart the transmitter */
+ OUTL(dev, TxOn, ChipCmd);
+
+ for (i = 0;
+ (*res = le32_to_cpu(txd.cmdsts)) & DescOwn;
+ i++) {
+ if (i >= TOUT_LOOP) {
+ printf
+ ("%s: tx error buffer not ready: txd.cmdsts == %#X\n",
+ dev->name, tx_status);
+ goto Done;
+ }
+ }
+
+ if (!(tx_status & DescPktOK)) {
+ printf("natsemi_send: Transmit error, Tx status %X.\n",
+ tx_status);
+ goto Done;
+ }
+
+ status = 1;
+ Done:
+ return status;
+}
+
+/* Function: natsemi_poll
+ *
+ * Description: checks for a received packet and returns it if found.
+ *
+ * Arguments: struct eth_device *dev: NIC data structure
+ *
+ * Returns: 1 if packet was received.
+ * 0 if no packet was received.
+ *
+ * Side effects:
+ * Returns (copies) the packet to the array dev->packet.
+ * Returns the length of the packet.
+ */
+
+static int
+natsemi_poll(struct eth_device *dev)
+{
+ int retstat = 0;
+ int length = 0;
+ u32 rx_status = le32_to_cpu(rxd[cur_rx].cmdsts);
+
+ if (!(rx_status & (u32) DescOwn))
+ return retstat;
+#ifdef NATSEMI_DEBUG
+ if (natsemi_debug)
+ printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n",
+ cur_rx, rx_status);
+#endif
+ length = (rx_status & DSIZE) - CRC_SIZE;
+
+ if ((rx_status & (DescMore | DescPktOK | DescRxLong)) != DescPktOK) {
+ printf
+ ("natsemi_poll: Corrupted packet received, buffer status = %X\n",
+ rx_status);
+ retstat = 0;
+ } else { /* give packet to higher level routine */
+ NetReceive((rxb + cur_rx * RX_BUF_SIZE), length);
+ retstat = 1;
+ }
+
+ /* return the descriptor and buffer to receive ring */
+ rxd[cur_rx].cmdsts = cpu_to_le32(RX_BUF_SIZE);
+ rxd[cur_rx].bufptr = cpu_to_le32((u32) & rxb[cur_rx * RX_BUF_SIZE]);
+
+ if (++cur_rx == NUM_RX_DESC)
+ cur_rx = 0;
+
+ /* re-enable the potentially idle receive state machine */
+ OUTL(dev, RxOn, ChipCmd);
+
+ return retstat;
+}
+
+/* Function: natsemi_disable
+ *
+ * Description: Turns off interrupts and stops Tx and Rx engines
+ *
+ * Arguments: struct eth_device *dev: NIC data structure
+ *
+ * Returns: void.
+ */
+
+static void
+natsemi_disable(struct eth_device *dev)
+{
+ /* Disable interrupts using the mask. */
+ OUTL(dev, 0, IntrMask);
+ OUTL(dev, 0, IntrEnable);
+
+ /* Stop the chip's Tx and Rx processes. */
+ OUTL(dev, RxOff | TxOff, ChipCmd);
+
+ /* Restore PME enable bit */
+ OUTL(dev, SavedClkRun, ClkRun);
+}
diff --git a/qemu/roms/u-boot/drivers/net/ne2000.c b/qemu/roms/u-boot/drivers/net/ne2000.c
new file mode 100644
index 000000000..e6cd3e9ba
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ne2000.c
@@ -0,0 +1,259 @@
+/*
+Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+==========================================================================
+
+dev/if_dp83902a.c
+
+Ethernet device driver for NS DP83902a ethernet controller
+
+==========================================================================
+####ECOSGPLCOPYRIGHTBEGIN####
+-------------------------------------------
+This file is part of eCos, the Embedded Configurable Operating System.
+Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+eCos is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 or (at your option) any later version.
+
+eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with eCos; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file does not
+by itself cause the resulting work to be covered by the GNU General Public
+License. However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based on
+this file might be covered by the GNU General Public License.
+
+Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+at http://sources.redhat.com/ecos/ecos-license/
+-------------------------------------------
+####ECOSGPLCOPYRIGHTEND####
+####BSDCOPYRIGHTBEGIN####
+
+-------------------------------------------
+
+Portions of this software may have been derived from OpenBSD or other sources,
+and are covered by the appropriate copyright disclaimers included herein.
+
+-------------------------------------------
+
+####BSDCOPYRIGHTEND####
+==========================================================================
+#####DESCRIPTIONBEGIN####
+
+Author(s): gthomas
+Contributors: gthomas, jskov, rsandifo
+Date: 2001-06-13
+Purpose:
+Description:
+
+FIXME: Will fail if pinged with large packets (1520 bytes)
+Add promisc config
+Add SNMP
+
+####DESCRIPTIONEND####
+
+==========================================================================
+*/
+
+#include <common.h>
+#include <command.h>
+
+/* NE2000 base header file */
+#include "ne2000_base.h"
+
+/* find prom (taken from pc_net_cs.c from Linux) */
+
+#include "8390.h"
+/*
+typedef struct hw_info_t {
+ u_int offset;
+ u_char a0, a1, a2;
+ u_int flags;
+} hw_info_t;
+*/
+#define DELAY_OUTPUT 0x01
+#define HAS_MISC_REG 0x02
+#define USE_BIG_BUF 0x04
+#define HAS_IBM_MISC 0x08
+#define IS_DL10019 0x10
+#define IS_DL10022 0x20
+#define HAS_MII 0x40
+#define USE_SHMEM 0x80 /* autodetected */
+
+#define AM79C9XX_HOME_PHY 0x00006B90 /* HomePNA PHY */
+#define AM79C9XX_ETH_PHY 0x00006B70 /* 10baseT PHY */
+#define MII_PHYID_REV_MASK 0xfffffff0
+#define MII_PHYID_REG1 0x02
+#define MII_PHYID_REG2 0x03
+
+static hw_info_t hw_info[] = {
+ { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
+ { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
+ { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
+ { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
+ DELAY_OUTPUT | HAS_IBM_MISC },
+ { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
+ { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
+ { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
+ { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
+ { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
+ { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
+ { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
+ { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
+ { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
+ { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
+ { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
+ { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
+ { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
+ { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
+ { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
+ HAS_MISC_REG | HAS_IBM_MISC },
+ { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
+ { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
+ { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
+ { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
+ DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
+ { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
+ { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
+ { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
+ { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
+ { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 },
+ { /* Qemu */ 0x0, 0x52, 0x54, 0x00, 0 },
+ { /* RTL8019AS */ 0x0, 0x0, 0x18, 0x5f, 0 }
+};
+
+#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
+
+#define PCNET_CMD 0x00
+#define PCNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */
+#define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */
+#define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */
+
+static void pcnet_reset_8390(u8* addr)
+{
+ int i, r;
+
+ n2k_outb(E8390_NODMA + E8390_PAGE0+E8390_STOP, E8390_CMD);
+ PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD));
+ n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD);
+ PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD));
+ n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
+ PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD));
+ n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
+
+ n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET);
+
+ for (i = 0; i < 100; i++) {
+ if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0)
+ break;
+ PRINTK("got %x in reset\n", r);
+ udelay(100);
+ }
+ n2k_outb(ENISR_RESET, EN0_ISR); /* Ack intr. */
+
+ if (i == 100)
+ printf("pcnet_reset_8390() did not complete.\n");
+} /* pcnet_reset_8390 */
+
+int get_prom(u8* mac_addr, u8* base_addr)
+{
+ u8 prom[32];
+ int i, j;
+ struct {
+ u_char value, offset;
+ } program_seq[] = {
+ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+ {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */
+ {0x00, EN0_RCNTLO}, /* Clear the count regs. */
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_IMR}, /* Mask completion irq. */
+ {0xFF, EN0_ISR},
+ {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
+ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
+ {32, EN0_RCNTLO},
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
+ {0x00, EN0_RSARHI},
+ {E8390_RREAD+E8390_START, E8390_CMD},
+ };
+
+ PRINTK ("trying to get MAC via prom reading\n");
+
+ pcnet_reset_8390 (base_addr);
+
+ mdelay (10);
+
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
+ n2k_outb (program_seq[i].value, program_seq[i].offset);
+
+ PRINTK ("PROM:");
+ for (i = 0; i < 32; i++) {
+ prom[i] = n2k_inb (PCNET_DATAPORT);
+ PRINTK (" %02x", prom[i]);
+ }
+ PRINTK ("\n");
+ for (i = 0; i < NR_INFO; i++) {
+ if ((prom[0] == hw_info[i].a0) &&
+ (prom[2] == hw_info[i].a1) &&
+ (prom[4] == hw_info[i].a2)) {
+ PRINTK ("matched board %d\n", i);
+ break;
+ }
+ }
+ if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
+ PRINTK ("on exit i is %d/%ld\n", i, NR_INFO);
+ PRINTK ("MAC address is ");
+ for (j = 0; j < 6; j++) {
+ mac_addr[j] = prom[j << 1];
+ PRINTK ("%02x:", mac_addr[i]);
+ }
+ PRINTK ("\n");
+ return (i < NR_INFO) ? i : 0;
+ }
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ne2000.h b/qemu/roms/u-boot/drivers/net/ne2000.h
new file mode 100644
index 000000000..2cde6be43
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ne2000.h
@@ -0,0 +1,94 @@
+/*
+Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+==========================================================================
+
+ dev/dp83902a.h
+
+ National Semiconductor DP83902a ethernet chip
+
+==========================================================================
+####ECOSGPLCOPYRIGHTBEGIN####
+ -------------------------------------------
+ This file is part of eCos, the Embedded Configurable Operating System.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ eCos is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 or (at your option) any later version.
+
+ eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with eCos; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file does not
+ by itself cause the resulting work to be covered by the GNU General Public
+ License. However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based on
+ this file might be covered by the GNU General Public License.
+
+ Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+ at http://sources.redhat.com/ecos/ecos-license/
+ -------------------------------------------
+####ECOSGPLCOPYRIGHTEND####
+####BSDCOPYRIGHTBEGIN####
+
+ -------------------------------------------
+
+ Portions of this software may have been derived from OpenBSD or other sources,
+ and are covered by the appropriate copyright disclaimers included herein.
+
+ -------------------------------------------
+
+####BSDCOPYRIGHTEND####
+==========================================================================
+#####DESCRIPTIONBEGIN####
+
+ Author(s): gthomas
+ Contributors: gthomas, jskov
+ Date: 2001-06-13
+ Purpose:
+ Description:
+
+####DESCRIPTIONEND####
+
+==========================================================================
+*/
+
+/*
+ * NE2000 support header file.
+ * Created by Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ */
+
+#ifndef __DRIVERS_NE2000_H__
+#define __DRIVERS_NE2000_H__
+
+/* Enable NE2000 basic init function */
+#define NE2000_BASIC_INIT
+
+#define DP_DATA 0x10
+#define START_PG 0x50 /* First page of TX buffer */
+#define START_PG2 0x48
+#define STOP_PG 0x80 /* Last page +1 of RX ring */
+
+#define RX_START 0x50
+#define RX_END 0x80
+
+#define DP_IN(_b_, _o_, _d_) (_d_) = *( (vu_char *) ((_b_)+(_o_)))
+#define DP_OUT(_b_, _o_, _d_) *( (vu_char *) ((_b_)+(_o_))) = (_d_)
+#define DP_IN_DATA(_b_, _d_) (_d_) = *( (vu_char *) ((_b_)))
+#define DP_OUT_DATA(_b_, _d_) *( (vu_char *) ((_b_))) = (_d_)
+#endif /* __DRIVERS_NE2000_H__ */
diff --git a/qemu/roms/u-boot/drivers/net/ne2000_base.c b/qemu/roms/u-boot/drivers/net/ne2000_base.c
new file mode 100644
index 000000000..ef3592204
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ne2000_base.c
@@ -0,0 +1,800 @@
+/*
+Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+==========================================================================
+
+dev/if_dp83902a.c
+
+Ethernet device driver for NS DP83902a ethernet controller
+
+==========================================================================
+####ECOSGPLCOPYRIGHTBEGIN####
+-------------------------------------------
+This file is part of eCos, the Embedded Configurable Operating System.
+Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+eCos is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 or (at your option) any later version.
+
+eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with eCos; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file does not
+by itself cause the resulting work to be covered by the GNU General Public
+License. However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based on
+this file might be covered by the GNU General Public License.
+
+Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+at http://sources.redhat.com/ecos/ecos-license/
+-------------------------------------------
+####ECOSGPLCOPYRIGHTEND####
+####BSDCOPYRIGHTBEGIN####
+
+-------------------------------------------
+
+Portions of this software may have been derived from OpenBSD or other sources,
+and are covered by the appropriate copyright disclaimers included herein.
+
+-------------------------------------------
+
+####BSDCOPYRIGHTEND####
+==========================================================================
+#####DESCRIPTIONBEGIN####
+
+Author(s): gthomas
+Contributors: gthomas, jskov, rsandifo
+Date: 2001-06-13
+Purpose:
+Description:
+
+FIXME: Will fail if pinged with large packets (1520 bytes)
+Add promisc config
+Add SNMP
+
+####DESCRIPTIONEND####
+
+==========================================================================
+*/
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <malloc.h>
+#include <linux/compiler.h>
+
+/* forward definition of function used for the uboot interface */
+void uboot_push_packet_len(int len);
+void uboot_push_tx_done(int key, int val);
+
+/* NE2000 base header file */
+#include "ne2000_base.h"
+
+#if defined(CONFIG_DRIVER_AX88796L)
+/* AX88796L support */
+#include "ax88796.h"
+#else
+/* Basic NE2000 chip support */
+#include "ne2000.h"
+#endif
+
+static dp83902a_priv_data_t nic; /* just one instance of the card supported */
+
+/**
+ * This function reads the MAC address from the serial EEPROM,
+ * used if PROM read fails. Does nothing for ax88796 chips (sh boards)
+ */
+static bool
+dp83902a_init(unsigned char *enetaddr)
+{
+ dp83902a_priv_data_t *dp = &nic;
+ u8* base;
+#if defined(NE2000_BASIC_INIT)
+ int i;
+#endif
+
+ DEBUG_FUNCTION();
+
+ base = dp->base;
+ if (!base)
+ return false; /* No device found */
+
+ DEBUG_LINE();
+
+#if defined(NE2000_BASIC_INIT)
+ /* AX88796L doesn't need */
+ /* Prepare ESA */
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */
+ /* Use the address from the serial EEPROM */
+ for (i = 0; i < 6; i++)
+ DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */
+
+ printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ "eeprom",
+ dp->esa[0],
+ dp->esa[1],
+ dp->esa[2],
+ dp->esa[3],
+ dp->esa[4],
+ dp->esa[5] );
+
+ memcpy(enetaddr, dp->esa, 6); /* Use MAC from serial EEPROM */
+#endif /* NE2000_BASIC_INIT */
+ return true;
+}
+
+static void
+dp83902a_stop(void)
+{
+ dp83902a_priv_data_t *dp = &nic;
+ u8 *base = dp->base;
+
+ DEBUG_FUNCTION();
+
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
+ DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
+ DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */
+
+ dp->running = false;
+}
+
+/*
+ * This function is called to "start up" the interface. It may be called
+ * multiple times, even when the hardware is already running. It will be
+ * called whenever something "hardware oriented" changes and should leave
+ * the hardware ready to send/receive packets.
+ */
+static void
+dp83902a_start(u8 * enaddr)
+{
+ dp83902a_priv_data_t *dp = &nic;
+ u8 *base = dp->base;
+ int i;
+
+ debug("The MAC is %pM\n", enaddr);
+
+ DEBUG_FUNCTION();
+
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
+ DP_OUT(base, DP_DCR, DP_DCR_INIT);
+ DP_OUT(base, DP_RBCH, 0); /* Remote byte count */
+ DP_OUT(base, DP_RBCL, 0);
+ DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */
+ DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */
+ DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */
+ dp->tx1 = dp->tx2 = 0;
+ dp->tx_next = dp->tx_buf1;
+ dp->tx_started = false;
+ dp->running = true;
+ DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
+ DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */
+ DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */
+ dp->rx_next = dp->rx_buf_start - 1;
+ dp->running = true;
+ DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
+ DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */
+ DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */
+ dp->running = true;
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ /* FIXME */
+ /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
+ * 0x1400)) = enaddr[i];*/
+ DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
+ }
+ /* Enable and start device */
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+ DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
+ DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
+ dp->running = true;
+}
+
+/*
+ * This routine is called to start the transmitter. It is split out from the
+ * data handling routine so it may be called either when data becomes first
+ * available or when an Tx interrupt occurs
+ */
+
+static void
+dp83902a_start_xmit(int start_page, int len)
+{
+ dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
+ u8 *base = dp->base;
+
+ DEBUG_FUNCTION();
+
+#if DEBUG & 1
+ printf("Tx pkt %d len %d\n", start_page, len);
+ if (dp->tx_started)
+ printf("TX already started?!?\n");
+#endif
+
+ DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+ DP_OUT(base, DP_TBCL, len & 0xFF);
+ DP_OUT(base, DP_TBCH, len >> 8);
+ DP_OUT(base, DP_TPSR, start_page);
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
+
+ dp->tx_started = true;
+}
+
+/*
+ * This routine is called to send data to the hardware. It is known a-priori
+ * that there is free buffer space (dp->tx_next).
+ */
+static void
+dp83902a_send(u8 *data, int total_len, u32 key)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ int len, start_page, pkt_len, i, isr;
+#if DEBUG & 4
+ int dx;
+#endif
+
+ DEBUG_FUNCTION();
+
+ len = pkt_len = total_len;
+ if (pkt_len < IEEE_8023_MIN_FRAME)
+ pkt_len = IEEE_8023_MIN_FRAME;
+
+ start_page = dp->tx_next;
+ if (dp->tx_next == dp->tx_buf1) {
+ dp->tx1 = start_page;
+ dp->tx1_len = pkt_len;
+ dp->tx1_key = key;
+ dp->tx_next = dp->tx_buf2;
+ } else {
+ dp->tx2 = start_page;
+ dp->tx2_len = pkt_len;
+ dp->tx2_key = key;
+ dp->tx_next = dp->tx_buf1;
+ }
+
+#if DEBUG & 5
+ printf("TX prep page %d len %d\n", start_page, pkt_len);
+#endif
+
+ DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
+ {
+ /*
+ * Dummy read. The manual sez something slightly different,
+ * but the code is extended a bit to do what Hitachi's monitor
+ * does (i.e., also read data).
+ */
+
+ __maybe_unused u16 tmp;
+ int len = 1;
+
+ DP_OUT(base, DP_RSAL, 0x100 - len);
+ DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff);
+ DP_OUT(base, DP_RBCL, len);
+ DP_OUT(base, DP_RBCH, 0);
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
+ DP_IN_DATA(dp->data, tmp);
+ }
+
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
+ /*
+ * Stall for a bit before continuing to work around random data
+ * corruption problems on some platforms.
+ */
+ CYGACC_CALL_IF_DELAY_US(1);
+#endif
+
+ /* Send data to device buffer(s) */
+ DP_OUT(base, DP_RSAL, 0);
+ DP_OUT(base, DP_RSAH, start_page);
+ DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
+ DP_OUT(base, DP_RBCH, pkt_len >> 8);
+ DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
+
+ /* Put data into buffer */
+#if DEBUG & 4
+ printf(" sg buf %08lx len %08x\n ", (u32)data, len);
+ dx = 0;
+#endif
+ while (len > 0) {
+#if DEBUG & 4
+ printf(" %02x", *data);
+ if (0 == (++dx % 16)) printf("\n ");
+#endif
+
+ DP_OUT_DATA(dp->data, *data++);
+ len--;
+ }
+#if DEBUG & 4
+ printf("\n");
+#endif
+ if (total_len < pkt_len) {
+#if DEBUG & 4
+ printf(" + %d bytes of padding\n", pkt_len - total_len);
+#endif
+ /* Padding to 802.3 length was required */
+ for (i = total_len; i < pkt_len;) {
+ i++;
+ DP_OUT_DATA(dp->data, 0);
+ }
+ }
+
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
+ /*
+ * After last data write, delay for a bit before accessing the
+ * device again, or we may get random data corruption in the last
+ * datum (on some platforms).
+ */
+ CYGACC_CALL_IF_DELAY_US(1);
+#endif
+
+ /* Wait for DMA to complete */
+ do {
+ DP_IN(base, DP_ISR, isr);
+ } while ((isr & DP_ISR_RDC) == 0);
+
+ /* Then disable DMA */
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+
+ /* Start transmit if not already going */
+ if (!dp->tx_started) {
+ if (start_page == dp->tx1) {
+ dp->tx_int = 1; /* Expecting interrupt from BUF1 */
+ } else {
+ dp->tx_int = 2; /* Expecting interrupt from BUF2 */
+ }
+ dp83902a_start_xmit(start_page, pkt_len);
+ }
+}
+
+/*
+ * This function is called when a packet has been received. It's job is
+ * to prepare to unload the packet from the hardware. Once the length of
+ * the packet is known, the upper layer of the driver can be told. When
+ * the upper layer is ready to unload the packet, the internal function
+ * 'dp83902a_recv' will be called to actually fetch it from the hardware.
+ */
+static void
+dp83902a_RxEvent(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ __maybe_unused u8 rsr;
+ u8 rcv_hdr[4];
+ int i, len, pkt, cur;
+
+ DEBUG_FUNCTION();
+
+ DP_IN(base, DP_RSR, rsr);
+ while (true) {
+ /* Read incoming packet header */
+ DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
+ DP_IN(base, DP_P1_CURP, cur);
+ DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+ DP_IN(base, DP_BNDRY, pkt);
+
+ pkt += 1;
+ if (pkt == dp->rx_buf_end)
+ pkt = dp->rx_buf_start;
+
+ if (pkt == cur) {
+ break;
+ }
+ DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
+ DP_OUT(base, DP_RBCH, 0);
+ DP_OUT(base, DP_RSAL, 0);
+ DP_OUT(base, DP_RSAH, pkt);
+ if (dp->rx_next == pkt) {
+ if (cur == dp->rx_buf_start)
+ DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
+ else
+ DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */
+ return;
+ }
+ dp->rx_next = pkt;
+ DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
+ DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
+ CYGACC_CALL_IF_DELAY_US(10);
+#endif
+
+ /* read header (get data size)*/
+ for (i = 0; i < sizeof(rcv_hdr);) {
+ DP_IN_DATA(dp->data, rcv_hdr[i++]);
+ }
+
+#if DEBUG & 5
+ printf("rx hdr %02x %02x %02x %02x\n",
+ rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
+#endif
+ len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
+
+ /* data read */
+ uboot_push_packet_len(len);
+
+ if (rcv_hdr[1] == dp->rx_buf_start)
+ DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
+ else
+ DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
+ }
+}
+
+/*
+ * This function is called as a result of the "eth_drv_recv()" call above.
+ * It's job is to actually fetch data for a packet from the hardware once
+ * memory buffers have been allocated for the packet. Note that the buffers
+ * may come in pieces, using a scatter-gather list. This allows for more
+ * efficient processing in the upper layers of the stack.
+ */
+static void
+dp83902a_recv(u8 *data, int len)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ int i, mlen;
+ u8 saved_char = 0;
+ bool saved;
+#if DEBUG & 4
+ int dx;
+#endif
+
+ DEBUG_FUNCTION();
+
+#if DEBUG & 5
+ printf("Rx packet %d length %d\n", dp->rx_next, len);
+#endif
+
+ /* Read incoming packet data */
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+ DP_OUT(base, DP_RBCL, len & 0xFF);
+ DP_OUT(base, DP_RBCH, len >> 8);
+ DP_OUT(base, DP_RSAL, 4); /* Past header */
+ DP_OUT(base, DP_RSAH, dp->rx_next);
+ DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
+ DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
+ CYGACC_CALL_IF_DELAY_US(10);
+#endif
+
+ saved = false;
+ for (i = 0; i < 1; i++) {
+ if (data) {
+ mlen = len;
+#if DEBUG & 4
+ printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
+ dx = 0;
+#endif
+ while (0 < mlen) {
+ /* Saved byte from previous loop? */
+ if (saved) {
+ *data++ = saved_char;
+ mlen--;
+ saved = false;
+ continue;
+ }
+
+ {
+ u8 tmp;
+ DP_IN_DATA(dp->data, tmp);
+#if DEBUG & 4
+ printf(" %02x", tmp);
+ if (0 == (++dx % 16)) printf("\n ");
+#endif
+ *data++ = tmp;;
+ mlen--;
+ }
+ }
+#if DEBUG & 4
+ printf("\n");
+#endif
+ }
+ }
+}
+
+static void
+dp83902a_TxEvent(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ __maybe_unused u8 tsr;
+ u32 key;
+
+ DEBUG_FUNCTION();
+
+ DP_IN(base, DP_TSR, tsr);
+ if (dp->tx_int == 1) {
+ key = dp->tx1_key;
+ dp->tx1 = 0;
+ } else {
+ key = dp->tx2_key;
+ dp->tx2 = 0;
+ }
+ /* Start next packet if one is ready */
+ dp->tx_started = false;
+ if (dp->tx1) {
+ dp83902a_start_xmit(dp->tx1, dp->tx1_len);
+ dp->tx_int = 1;
+ } else if (dp->tx2) {
+ dp83902a_start_xmit(dp->tx2, dp->tx2_len);
+ dp->tx_int = 2;
+ } else {
+ dp->tx_int = 0;
+ }
+ /* Tell higher level we sent this packet */
+ uboot_push_tx_done(key, 0);
+}
+
+/*
+ * Read the tally counters to clear them. Called in response to a CNT
+ * interrupt.
+ */
+static void
+dp83902a_ClearCounters(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ __maybe_unused u8 cnt1, cnt2, cnt3;
+
+ DP_IN(base, DP_FER, cnt1);
+ DP_IN(base, DP_CER, cnt2);
+ DP_IN(base, DP_MISSED, cnt3);
+ DP_OUT(base, DP_ISR, DP_ISR_CNT);
+}
+
+/*
+ * Deal with an overflow condition. This code follows the procedure set
+ * out in section 7.0 of the datasheet.
+ */
+static void
+dp83902a_Overflow(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
+ u8 *base = dp->base;
+ u8 isr;
+
+ /* Issue a stop command and wait 1.6ms for it to complete. */
+ DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
+ CYGACC_CALL_IF_DELAY_US(1600);
+
+ /* Clear the remote byte counter registers. */
+ DP_OUT(base, DP_RBCL, 0);
+ DP_OUT(base, DP_RBCH, 0);
+
+ /* Enter loopback mode while we clear the buffer. */
+ DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
+ DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
+
+ /*
+ * Read in as many packets as we can and acknowledge any and receive
+ * interrupts. Since the buffer has overflowed, a receive event of
+ * some kind will have occured.
+ */
+ dp83902a_RxEvent();
+ DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
+
+ /* Clear the overflow condition and leave loopback mode. */
+ DP_OUT(base, DP_ISR, DP_ISR_OFLW);
+ DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
+
+ /*
+ * If a transmit command was issued, but no transmit event has occured,
+ * restart it here.
+ */
+ DP_IN(base, DP_ISR, isr);
+ if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
+ }
+}
+
+static void
+dp83902a_poll(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ u8 isr;
+
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
+ DP_IN(base, DP_ISR, isr);
+ while (0 != isr) {
+ /*
+ * The CNT interrupt triggers when the MSB of one of the error
+ * counters is set. We don't much care about these counters, but
+ * we should read their values to reset them.
+ */
+ if (isr & DP_ISR_CNT) {
+ dp83902a_ClearCounters();
+ }
+ /*
+ * Check for overflow. It's a special case, since there's a
+ * particular procedure that must be followed to get back into
+ * a running state.a
+ */
+ if (isr & DP_ISR_OFLW) {
+ dp83902a_Overflow();
+ } else {
+ /*
+ * Other kinds of interrupts can be acknowledged simply by
+ * clearing the relevant bits of the ISR. Do that now, then
+ * handle the interrupts we care about.
+ */
+ DP_OUT(base, DP_ISR, isr); /* Clear set bits */
+ if (!dp->running) break; /* Is this necessary? */
+ /*
+ * Check for tx_started on TX event since these may happen
+ * spuriously it seems.
+ */
+ if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
+ dp83902a_TxEvent();
+ }
+ if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
+ dp83902a_RxEvent();
+ }
+ }
+ DP_IN(base, DP_ISR, isr);
+ }
+}
+
+
+/* U-boot specific routines */
+static u8 *pbuf = NULL;
+
+static int pkey = -1;
+static int initialized = 0;
+
+void uboot_push_packet_len(int len) {
+ PRINTK("pushed len = %d\n", len);
+ if (len >= 2000) {
+ printf("NE2000: packet too big\n");
+ return;
+ }
+ dp83902a_recv(&pbuf[0], len);
+
+ /*Just pass it to the upper layer*/
+ NetReceive(&pbuf[0], len);
+}
+
+void uboot_push_tx_done(int key, int val) {
+ PRINTK("pushed key = %d\n", key);
+ pkey = key;
+}
+
+/**
+ * Setup the driver and init MAC address according to doc/README.enetaddr
+ * Called by ne2k_register() before registering the driver @eth layer
+ *
+ * @param struct ethdevice of this instance of the driver for dev->enetaddr
+ * @return 0 on success, -1 on error (causing caller to print error msg)
+ */
+static int ne2k_setup_driver(struct eth_device *dev)
+{
+ PRINTK("### ne2k_setup_driver\n");
+
+ if (!pbuf) {
+ pbuf = malloc(2000);
+ if (!pbuf) {
+ printf("Cannot allocate rx buffer\n");
+ return -1;
+ }
+ }
+
+#ifdef CONFIG_DRIVER_NE2000_CCR
+ {
+ vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR;
+
+ PRINTK("CCR before is %x\n", *p);
+ *p = CONFIG_DRIVER_NE2000_VAL;
+ PRINTK("CCR after is %x\n", *p);
+ }
+#endif
+
+ nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
+
+ nic.data = nic.base + DP_DATA;
+ nic.tx_buf1 = START_PG;
+ nic.tx_buf2 = START_PG2;
+ nic.rx_buf_start = RX_START;
+ nic.rx_buf_end = RX_END;
+
+ /*
+ * According to doc/README.enetaddr, drivers shall give priority
+ * to the MAC address value in the environment, so we do not read
+ * it from the prom or eeprom if it is specified in the environment.
+ */
+ if (!eth_getenv_enetaddr("ethaddr", dev->enetaddr)) {
+ /* If the MAC address is not in the environment, get it: */
+ if (!get_prom(dev->enetaddr, nic.base)) /* get MAC from prom */
+ dp83902a_init(dev->enetaddr); /* fallback: seeprom */
+ /* And write it into the environment otherwise eth_write_hwaddr
+ * returns -1 due to eth_getenv_enetaddr_by_index() failing,
+ * and this causes "Warning: failed to set MAC address", and
+ * cmd_bdinfo has no ethaddr value which it can show: */
+ eth_setenv_enetaddr("ethaddr", dev->enetaddr);
+ }
+ return 0;
+}
+
+static int ne2k_init(struct eth_device *dev, bd_t *bd)
+{
+ dp83902a_start(dev->enetaddr);
+ initialized = 1;
+ return 0;
+}
+
+static void ne2k_halt(struct eth_device *dev)
+{
+ debug("### ne2k_halt\n");
+ if(initialized)
+ dp83902a_stop();
+ initialized = 0;
+}
+
+static int ne2k_recv(struct eth_device *dev)
+{
+ dp83902a_poll();
+ return 1;
+}
+
+static int ne2k_send(struct eth_device *dev, void *packet, int length)
+{
+ int tmo;
+
+ debug("### ne2k_send\n");
+
+ pkey = -1;
+
+ dp83902a_send((u8 *) packet, length, 666);
+ tmo = get_timer (0) + TOUT * CONFIG_SYS_HZ;
+ while(1) {
+ dp83902a_poll();
+ if (pkey != -1) {
+ PRINTK("Packet sucesfully sent\n");
+ return 0;
+ }
+ if (get_timer (0) >= tmo) {
+ printf("transmission error (timoeut)\n");
+ return 0;
+ }
+
+ }
+ return 0;
+}
+
+/**
+ * Setup the driver for use and register it with the eth layer
+ * @return 0 on success, -1 on error (causing caller to print error msg)
+ */
+int ne2k_register(void)
+{
+ struct eth_device *dev;
+
+ dev = calloc(sizeof(*dev), 1);
+ if (dev == NULL)
+ return -1;
+
+ if (ne2k_setup_driver(dev))
+ return -1;
+
+ dev->init = ne2k_init;
+ dev->halt = ne2k_halt;
+ dev->send = ne2k_send;
+ dev->recv = ne2k_recv;
+
+ sprintf(dev->name, "NE2000");
+
+ return eth_register(dev);
+}
diff --git a/qemu/roms/u-boot/drivers/net/ne2000_base.h b/qemu/roms/u-boot/drivers/net/ne2000_base.h
new file mode 100644
index 000000000..eee0956fd
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ne2000_base.h
@@ -0,0 +1,304 @@
+/*
+Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+
+==========================================================================
+
+ dev/dp83902a.h
+
+ National Semiconductor DP83902a ethernet chip
+
+==========================================================================
+####ECOSGPLCOPYRIGHTBEGIN####
+ -------------------------------------------
+ This file is part of eCos, the Embedded Configurable Operating System.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ eCos is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 or (at your option) any later version.
+
+ eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with eCos; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file does not
+ by itself cause the resulting work to be covered by the GNU General Public
+ License. However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based on
+ this file might be covered by the GNU General Public License.
+
+ Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+ at http://sources.redhat.com/ecos/ecos-license/
+ -------------------------------------------
+####ECOSGPLCOPYRIGHTEND####
+####BSDCOPYRIGHTBEGIN####
+
+ -------------------------------------------
+
+ Portions of this software may have been derived from OpenBSD or other sources,
+ and are covered by the appropriate copyright disclaimers included herein.
+
+ -------------------------------------------
+
+####BSDCOPYRIGHTEND####
+==========================================================================
+#####DESCRIPTIONBEGIN####
+
+ Author(s): gthomas
+ Contributors: gthomas, jskov
+ Date: 2001-06-13
+ Purpose:
+ Description:
+
+####DESCRIPTIONEND####
+
+==========================================================================
+
+*/
+
+/*
+ ------------------------------------------------------------------------
+ Macros for accessing DP registers
+ These can be overridden by the platform header
+*/
+
+#ifndef __NE2000_BASE_H__
+#define __NE2000_BASE_H__
+
+/*
+ * Debugging details
+ *
+ * Set to perms of:
+ * 0 disables all debug output
+ * 1 for process debug output
+ * 2 for added data IO output: get_reg, put_reg
+ * 4 for packet allocation/free output
+ * 8 for only startup status, so we can tell we're installed OK
+ */
+#if 0
+#define DEBUG 0xf
+#else
+#define DEBUG 0
+#endif
+
+#if DEBUG & 1
+#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
+#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
+#define PRINTK(args...) printf(args)
+#else
+#define DEBUG_FUNCTION() do {} while(0)
+#define DEBUG_LINE() do {} while(0)
+#define PRINTK(args...)
+#endif
+
+/* timeout for tx/rx in s */
+#define TOUT 5
+/* Ether MAC address size */
+#define ETHER_ADDR_LEN 6
+
+
+#define CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 1
+#define CYGACC_CALL_IF_DELAY_US(X) udelay(X)
+
+/* H/W infomation struct */
+typedef struct hw_info_t {
+ u32 offset;
+ u8 a0, a1, a2;
+ u32 flags;
+} hw_info_t;
+
+typedef struct dp83902a_priv_data {
+ u8* base;
+ u8* data;
+ u8* reset;
+ int tx_next; /* First free Tx page */
+ int tx_int; /* Expecting interrupt from this buffer */
+ int rx_next; /* First free Rx page */
+ int tx1, tx2; /* Page numbers for Tx buffers */
+ u32 tx1_key, tx2_key; /* Used to ack when packet sent */
+ int tx1_len, tx2_len;
+ bool tx_started, running, hardwired_esa;
+ u8 esa[6];
+ void* plf_priv;
+
+ /* Buffer allocation */
+ int tx_buf1, tx_buf2;
+ int rx_buf_start, rx_buf_end;
+} dp83902a_priv_data_t;
+
+/* ------------------------------------------------------------------------ */
+/* Register offsets */
+
+#define DP_CR 0x00
+#define DP_CLDA0 0x01
+#define DP_PSTART 0x01 /* write */
+#define DP_CLDA1 0x02
+#define DP_PSTOP 0x02 /* write */
+#define DP_BNDRY 0x03
+#define DP_TSR 0x04
+#define DP_TPSR 0x04 /* write */
+#define DP_NCR 0x05
+#define DP_TBCL 0x05 /* write */
+#define DP_FIFO 0x06
+#define DP_TBCH 0x06 /* write */
+#define DP_ISR 0x07
+#define DP_CRDA0 0x08
+#define DP_RSAL 0x08 /* write */
+#define DP_CRDA1 0x09
+#define DP_RSAH 0x09 /* write */
+#define DP_RBCL 0x0a /* write */
+#define DP_RBCH 0x0b /* write */
+#define DP_RSR 0x0c
+#define DP_RCR 0x0c /* write */
+#define DP_FER 0x0d
+#define DP_TCR 0x0d /* write */
+#define DP_CER 0x0e
+#define DP_DCR 0x0e /* write */
+#define DP_MISSED 0x0f
+#define DP_IMR 0x0f /* write */
+#define DP_DATAPORT 0x10 /* "eprom" data port */
+
+#define DP_P1_CR 0x00
+#define DP_P1_PAR0 0x01
+#define DP_P1_PAR1 0x02
+#define DP_P1_PAR2 0x03
+#define DP_P1_PAR3 0x04
+#define DP_P1_PAR4 0x05
+#define DP_P1_PAR5 0x06
+#define DP_P1_CURP 0x07
+#define DP_P1_MAR0 0x08
+#define DP_P1_MAR1 0x09
+#define DP_P1_MAR2 0x0a
+#define DP_P1_MAR3 0x0b
+#define DP_P1_MAR4 0x0c
+#define DP_P1_MAR5 0x0d
+#define DP_P1_MAR6 0x0e
+#define DP_P1_MAR7 0x0f
+
+#define DP_P2_CR 0x00
+#define DP_P2_PSTART 0x01
+#define DP_P2_CLDA0 0x01 /* write */
+#define DP_P2_PSTOP 0x02
+#define DP_P2_CLDA1 0x02 /* write */
+#define DP_P2_RNPP 0x03
+#define DP_P2_TPSR 0x04
+#define DP_P2_LNPP 0x05
+#define DP_P2_ACH 0x06
+#define DP_P2_ACL 0x07
+#define DP_P2_RCR 0x0c
+#define DP_P2_TCR 0x0d
+#define DP_P2_DCR 0x0e
+#define DP_P2_IMR 0x0f
+
+/* Command register - common to all pages */
+
+#define DP_CR_STOP 0x01 /* Stop: software reset */
+#define DP_CR_START 0x02 /* Start: initialize device */
+#define DP_CR_TXPKT 0x04 /* Transmit packet */
+#define DP_CR_RDMA 0x08 /* Read DMA (recv data from device) */
+#define DP_CR_WDMA 0x10 /* Write DMA (send data to device) */
+#define DP_CR_SEND 0x18 /* Send packet */
+#define DP_CR_NODMA 0x20 /* Remote (or no) DMA */
+#define DP_CR_PAGE0 0x00 /* Page select */
+#define DP_CR_PAGE1 0x40
+#define DP_CR_PAGE2 0x80
+#define DP_CR_PAGEMSK 0x3F /* Used to mask out page bits */
+
+/* Data configuration register */
+
+#define DP_DCR_WTS 0x01 /* 1=16 bit word transfers */
+#define DP_DCR_BOS 0x02 /* 1=Little Endian */
+#define DP_DCR_LAS 0x04 /* 1=Single 32 bit DMA mode */
+#define DP_DCR_LS 0x08 /* 1=normal mode, 0=loopback */
+#define DP_DCR_ARM 0x10 /* 0=no send command (program I/O) */
+#define DP_DCR_FIFO_1 0x00 /* FIFO threshold */
+#define DP_DCR_FIFO_2 0x20
+#define DP_DCR_FIFO_4 0x40
+#define DP_DCR_FIFO_6 0x60
+
+#define DP_DCR_INIT (DP_DCR_LS|DP_DCR_FIFO_4)
+
+/* Interrupt status register */
+
+#define DP_ISR_RxP 0x01 /* Packet received */
+#define DP_ISR_TxP 0x02 /* Packet transmitted */
+#define DP_ISR_RxE 0x04 /* Receive error */
+#define DP_ISR_TxE 0x08 /* Transmit error */
+#define DP_ISR_OFLW 0x10 /* Receive overflow */
+#define DP_ISR_CNT 0x20 /* Tally counters need emptying */
+#define DP_ISR_RDC 0x40 /* Remote DMA complete */
+#define DP_ISR_RESET 0x80 /* Device has reset (shutdown, error) */
+
+/* Interrupt mask register */
+
+#define DP_IMR_RxP 0x01 /* Packet received */
+#define DP_IMR_TxP 0x02 /* Packet transmitted */
+#define DP_IMR_RxE 0x04 /* Receive error */
+#define DP_IMR_TxE 0x08 /* Transmit error */
+#define DP_IMR_OFLW 0x10 /* Receive overflow */
+#define DP_IMR_CNT 0x20 /* Tall counters need emptying */
+#define DP_IMR_RDC 0x40 /* Remote DMA complete */
+
+#define DP_IMR_All 0x3F /* Everything but remote DMA */
+
+/* Receiver control register */
+
+#define DP_RCR_SEP 0x01 /* Save bad(error) packets */
+#define DP_RCR_AR 0x02 /* Accept runt packets */
+#define DP_RCR_AB 0x04 /* Accept broadcast packets */
+#define DP_RCR_AM 0x08 /* Accept multicast packets */
+#define DP_RCR_PROM 0x10 /* Promiscuous mode */
+#define DP_RCR_MON 0x20 /* Monitor mode - 1=accept no packets */
+
+/* Receiver status register */
+
+#define DP_RSR_RxP 0x01 /* Packet received */
+#define DP_RSR_CRC 0x02 /* CRC error */
+#define DP_RSR_FRAME 0x04 /* Framing error */
+#define DP_RSR_FO 0x08 /* FIFO overrun */
+#define DP_RSR_MISS 0x10 /* Missed packet */
+#define DP_RSR_PHY 0x20 /* 0=pad match, 1=mad match */
+#define DP_RSR_DIS 0x40 /* Receiver disabled */
+#define DP_RSR_DFR 0x80 /* Receiver processing deferred */
+
+/* Transmitter control register */
+
+#define DP_TCR_NOCRC 0x01 /* 1=inhibit CRC */
+#define DP_TCR_NORMAL 0x00 /* Normal transmitter operation */
+#define DP_TCR_LOCAL 0x02 /* Internal NIC loopback */
+#define DP_TCR_INLOOP 0x04 /* Full internal loopback */
+#define DP_TCR_OUTLOOP 0x08 /* External loopback */
+#define DP_TCR_ATD 0x10 /* Auto transmit disable */
+#define DP_TCR_OFFSET 0x20 /* Collision offset adjust */
+
+/* Transmit status register */
+
+#define DP_TSR_TxP 0x01 /* Packet transmitted */
+#define DP_TSR_COL 0x04 /* Collision (at least one) */
+#define DP_TSR_ABT 0x08 /* Aborted because of too many collisions */
+#define DP_TSR_CRS 0x10 /* Lost carrier */
+#define DP_TSR_FU 0x20 /* FIFO underrun */
+#define DP_TSR_CDH 0x40 /* Collision Detect Heartbeat */
+#define DP_TSR_OWC 0x80 /* Collision outside normal window */
+
+#define IEEE_8023_MAX_FRAME 1518 /* Largest possible ethernet frame */
+#define IEEE_8023_MIN_FRAME 64 /* Smallest possible ethernet frame */
+
+/* Functions */
+int get_prom(u8* mac_addr, u8* base_addr);
+
+#endif /* __NE2000_BASE_H__ */
diff --git a/qemu/roms/u-boot/drivers/net/netconsole.c b/qemu/roms/u-boot/drivers/net/netconsole.c
new file mode 100644
index 000000000..65c747e14
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/netconsole.c
@@ -0,0 +1,331 @@
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <stdio_dev.h>
+#include <net.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_NETCONSOLE_BUFFER_SIZE
+#define CONFIG_NETCONSOLE_BUFFER_SIZE 512
+#endif
+
+static char input_buffer[CONFIG_NETCONSOLE_BUFFER_SIZE];
+static int input_size; /* char count in input buffer */
+static int input_offset; /* offset to valid chars in input buffer */
+static int input_recursion;
+static int output_recursion;
+static int net_timeout;
+static uchar nc_ether[6]; /* server enet address */
+static IPaddr_t nc_ip; /* server ip */
+static short nc_out_port; /* target output port */
+static short nc_in_port; /* source input port */
+static const char *output_packet; /* used by first send udp */
+static int output_packet_len;
+/*
+ * Start with a default last protocol.
+ * We are only interested in NETCONS or not.
+ */
+enum proto_t net_loop_last_protocol = BOOTP;
+
+static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
+ IPaddr_t sip, unsigned src,
+ unsigned len)
+{
+ net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */
+}
+
+static void nc_handler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+ unsigned len)
+{
+ if (input_size)
+ net_set_state(NETLOOP_SUCCESS); /* got input - quit net loop */
+}
+
+static void nc_timeout(void)
+{
+ net_set_state(NETLOOP_SUCCESS);
+}
+
+static int is_broadcast(IPaddr_t ip)
+{
+ static IPaddr_t netmask;
+ static IPaddr_t our_ip;
+ static int env_changed_id;
+ int env_id = get_env_id();
+
+ /* update only when the environment has changed */
+ if (env_changed_id != env_id) {
+ netmask = getenv_IPaddr("netmask");
+ our_ip = getenv_IPaddr("ipaddr");
+
+ env_changed_id = env_id;
+ }
+
+ return (ip == ~0 || /* 255.255.255.255 */
+ ((netmask & our_ip) == (netmask & ip) && /* on the same net */
+ (netmask | ip) == ~0)); /* broadcast to our net */
+}
+
+static int refresh_settings_from_env(void)
+{
+ const char *p;
+ static int env_changed_id;
+ int env_id = get_env_id();
+
+ /* update only when the environment has changed */
+ if (env_changed_id != env_id) {
+ if (getenv("ncip")) {
+ nc_ip = getenv_IPaddr("ncip");
+ if (!nc_ip)
+ return -1; /* ncip is 0.0.0.0 */
+ p = strchr(getenv("ncip"), ':');
+ if (p != NULL) {
+ nc_out_port = simple_strtoul(p + 1, NULL, 10);
+ nc_in_port = nc_out_port;
+ }
+ } else
+ nc_ip = ~0; /* ncip is not set, so broadcast */
+
+ p = getenv("ncoutport");
+ if (p != NULL)
+ nc_out_port = simple_strtoul(p, NULL, 10);
+ p = getenv("ncinport");
+ if (p != NULL)
+ nc_in_port = simple_strtoul(p, NULL, 10);
+
+ if (is_broadcast(nc_ip))
+ /* broadcast MAC address */
+ memset(nc_ether, 0xff, sizeof(nc_ether));
+ else
+ /* force arp request */
+ memset(nc_ether, 0, sizeof(nc_ether));
+ }
+ return 0;
+}
+
+/**
+ * Called from NetLoop in net/net.c before each packet
+ */
+void NcStart(void)
+{
+ refresh_settings_from_env();
+ if (!output_packet_len || memcmp(nc_ether, NetEtherNullAddr, 6)) {
+ /* going to check for input packet */
+ net_set_udp_handler(nc_handler);
+ NetSetTimeout(net_timeout, nc_timeout);
+ } else {
+ /* send arp request */
+ uchar *pkt;
+ net_set_arp_handler(nc_wait_arp_handler);
+ pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
+ memcpy(pkt, output_packet, output_packet_len);
+ NetSendUDPPacket(nc_ether, nc_ip, nc_out_port, nc_in_port,
+ output_packet_len);
+ }
+}
+
+int nc_input_packet(uchar *pkt, IPaddr_t src_ip, unsigned dest_port,
+ unsigned src_port, unsigned len)
+{
+ int end, chunk;
+
+ if (dest_port != nc_in_port || !len)
+ return 0; /* not for us */
+
+ if (src_ip != nc_ip && !is_broadcast(nc_ip))
+ return 0; /* not from our client */
+
+ debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt);
+
+ if (input_size == sizeof(input_buffer))
+ return 1; /* no space */
+ if (len > sizeof(input_buffer) - input_size)
+ len = sizeof(input_buffer) - input_size;
+
+ end = input_offset + input_size;
+ if (end > sizeof(input_buffer))
+ end -= sizeof(input_buffer);
+
+ chunk = len;
+ if (end + len > sizeof(input_buffer)) {
+ chunk = sizeof(input_buffer) - end;
+ memcpy(input_buffer, pkt + chunk, len - chunk);
+ }
+ memcpy(input_buffer + end, pkt, chunk);
+
+ input_size += len;
+
+ return 1;
+}
+
+static void nc_send_packet(const char *buf, int len)
+{
+ struct eth_device *eth;
+ int inited = 0;
+ uchar *pkt;
+ uchar *ether;
+ IPaddr_t ip;
+
+ debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf);
+
+ eth = eth_get_dev();
+ if (eth == NULL)
+ return;
+
+ if (!memcmp(nc_ether, NetEtherNullAddr, 6)) {
+ if (eth->state == ETH_STATE_ACTIVE)
+ return; /* inside net loop */
+ output_packet = buf;
+ output_packet_len = len;
+ input_recursion = 1;
+ NetLoop(NETCONS); /* wait for arp reply and send packet */
+ input_recursion = 0;
+ output_packet_len = 0;
+ return;
+ }
+
+ if (eth->state != ETH_STATE_ACTIVE) {
+ if (eth_is_on_demand_init()) {
+ if (eth_init(gd->bd) < 0)
+ return;
+ eth_set_last_protocol(NETCONS);
+ } else
+ eth_init_state_only(gd->bd);
+
+ inited = 1;
+ }
+ pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
+ memcpy(pkt, buf, len);
+ ether = nc_ether;
+ ip = nc_ip;
+ NetSendUDPPacket(ether, ip, nc_out_port, nc_in_port, len);
+
+ if (inited) {
+ if (eth_is_on_demand_init())
+ eth_halt();
+ else
+ eth_halt_state_only();
+ }
+}
+
+static int nc_start(void)
+{
+ int retval;
+
+ nc_out_port = 6666; /* default port */
+ nc_in_port = nc_out_port;
+
+ retval = refresh_settings_from_env();
+ if (retval != 0)
+ return retval;
+
+ /*
+ * Initialize the static IP settings and buffer pointers
+ * incase we call NetSendUDPPacket before NetLoop
+ */
+ net_init();
+
+ return 0;
+}
+
+static void nc_putc(char c)
+{
+ if (output_recursion)
+ return;
+ output_recursion = 1;
+
+ nc_send_packet(&c, 1);
+
+ output_recursion = 0;
+}
+
+static void nc_puts(const char *s)
+{
+ int len;
+
+ if (output_recursion)
+ return;
+ output_recursion = 1;
+
+ len = strlen(s);
+ while (len) {
+ int send_len = min(len, sizeof(input_buffer));
+ nc_send_packet(s, send_len);
+ len -= send_len;
+ s += send_len;
+ }
+
+ output_recursion = 0;
+}
+
+static int nc_getc(void)
+{
+ uchar c;
+
+ input_recursion = 1;
+
+ net_timeout = 0; /* no timeout */
+ while (!input_size)
+ NetLoop(NETCONS);
+
+ input_recursion = 0;
+
+ c = input_buffer[input_offset++];
+
+ if (input_offset >= sizeof(input_buffer))
+ input_offset -= sizeof(input_buffer);
+ input_size--;
+
+ return c;
+}
+
+static int nc_tstc(void)
+{
+ struct eth_device *eth;
+
+ if (input_recursion)
+ return 0;
+
+ if (input_size)
+ return 1;
+
+ eth = eth_get_dev();
+ if (eth && eth->state == ETH_STATE_ACTIVE)
+ return 0; /* inside net loop */
+
+ input_recursion = 1;
+
+ net_timeout = 1;
+ NetLoop(NETCONS); /* kind of poll */
+
+ input_recursion = 0;
+
+ return input_size != 0;
+}
+
+int drv_nc_init(void)
+{
+ struct stdio_dev dev;
+ int rc;
+
+ memset(&dev, 0, sizeof(dev));
+
+ strcpy(dev.name, "nc");
+ dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ dev.start = nc_start;
+ dev.putc = nc_putc;
+ dev.puts = nc_puts;
+ dev.getc = nc_getc;
+ dev.tstc = nc_tstc;
+
+ rc = stdio_register(&dev);
+
+ return (rc == 0) ? 1 : rc;
+}
diff --git a/qemu/roms/u-boot/drivers/net/ns8382x.c b/qemu/roms/u-boot/drivers/net/ns8382x.c
new file mode 100644
index 000000000..cfe1f349d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/ns8382x.c
@@ -0,0 +1,851 @@
+/*
+ ns8382x.c: A U-Boot driver for the NatSemi DP8382[01].
+ ported by: Mark A. Rakes (mark_rakes@vivato.net)
+
+ Adapted from:
+ 1. an Etherboot driver for DP8381[56] written by:
+ Copyright (C) 2001 Entity Cyber, Inc.
+
+ This development of this Etherboot driver was funded by
+ Sicom Systems: http://www.sicompos.com/
+
+ Author: Marty Connor (mdc@thinguin.org)
+ Adapted from a Linux driver which was written by Donald Becker
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License (GPL), incorporated herein by reference.
+
+ 2. A Linux driver by Donald Becker, ns820.c:
+ Written/copyright 1999-2002 by Donald Becker.
+
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+ a complete program and may only be used when the entire operating
+ system is licensed under the GPL. License for under other terms may be
+ available. Contact the original author for details.
+
+ The original author may be reached as becker@scyld.com, or at
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ Support information and updates available at
+ http://www.scyld.com/network/netsemi.html
+
+ Datasheets available from:
+ http://www.national.com/pf/DP/DP83820.html
+ http://www.national.com/pf/DP/DP83821.html
+*/
+
+/* Revision History
+ * October 2002 mar 1.0
+ * Initial U-Boot Release.
+ * Tested with Netgear GA622T (83820)
+ * and SMC9452TX (83821)
+ * NOTE: custom boards with these chips may (likely) require
+ * a programmed EEPROM device (if present) in order to work
+ * correctly.
+*/
+
+/* Includes */
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <pci.h>
+
+/* defines */
+#define DSIZE 0x00000FFF
+#define ETH_ALEN 6
+#define CRC_SIZE 4
+#define TOUT_LOOP 500000
+#define TX_BUF_SIZE 1536
+#define RX_BUF_SIZE 1536
+#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
+
+enum register_offsets {
+ ChipCmd = 0x00,
+ ChipConfig = 0x04,
+ EECtrl = 0x08,
+ IntrMask = 0x14,
+ IntrEnable = 0x18,
+ TxRingPtr = 0x20,
+ TxRingPtrHi = 0x24,
+ TxConfig = 0x28,
+ RxRingPtr = 0x30,
+ RxRingPtrHi = 0x34,
+ RxConfig = 0x38,
+ PriQueue = 0x3C,
+ RxFilterAddr = 0x48,
+ RxFilterData = 0x4C,
+ ClkRun = 0xCC,
+ PCIPM = 0x44,
+};
+
+enum ChipCmdBits {
+ ChipReset = 0x100,
+ RxReset = 0x20,
+ TxReset = 0x10,
+ RxOff = 0x08,
+ RxOn = 0x04,
+ TxOff = 0x02,
+ TxOn = 0x01
+};
+
+enum ChipConfigBits {
+ LinkSts = 0x80000000,
+ GigSpeed = 0x40000000,
+ HundSpeed = 0x20000000,
+ FullDuplex = 0x10000000,
+ TBIEn = 0x01000000,
+ Mode1000 = 0x00400000,
+ T64En = 0x00004000,
+ D64En = 0x00001000,
+ M64En = 0x00000800,
+ PhyRst = 0x00000400,
+ PhyDis = 0x00000200,
+ ExtStEn = 0x00000100,
+ BEMode = 0x00000001,
+};
+#define SpeedStatus_Polarity ( GigSpeed | HundSpeed | FullDuplex)
+
+enum TxConfig_bits {
+ TxDrthMask = 0x000000ff,
+ TxFlthMask = 0x0000ff00,
+ TxMxdmaMask = 0x00700000,
+ TxMxdma_8 = 0x00100000,
+ TxMxdma_16 = 0x00200000,
+ TxMxdma_32 = 0x00300000,
+ TxMxdma_64 = 0x00400000,
+ TxMxdma_128 = 0x00500000,
+ TxMxdma_256 = 0x00600000,
+ TxMxdma_512 = 0x00700000,
+ TxMxdma_1024 = 0x00000000,
+ TxCollRetry = 0x00800000,
+ TxAutoPad = 0x10000000,
+ TxMacLoop = 0x20000000,
+ TxHeartIgn = 0x40000000,
+ TxCarrierIgn = 0x80000000
+};
+
+enum RxConfig_bits {
+ RxDrthMask = 0x0000003e,
+ RxMxdmaMask = 0x00700000,
+ RxMxdma_8 = 0x00100000,
+ RxMxdma_16 = 0x00200000,
+ RxMxdma_32 = 0x00300000,
+ RxMxdma_64 = 0x00400000,
+ RxMxdma_128 = 0x00500000,
+ RxMxdma_256 = 0x00600000,
+ RxMxdma_512 = 0x00700000,
+ RxMxdma_1024 = 0x00000000,
+ RxAcceptLenErr = 0x04000000,
+ RxAcceptLong = 0x08000000,
+ RxAcceptTx = 0x10000000,
+ RxStripCRC = 0x20000000,
+ RxAcceptRunt = 0x40000000,
+ RxAcceptErr = 0x80000000,
+};
+
+/* Bits in the RxMode register. */
+enum rx_mode_bits {
+ RxFilterEnable = 0x80000000,
+ AcceptAllBroadcast = 0x40000000,
+ AcceptAllMulticast = 0x20000000,
+ AcceptAllUnicast = 0x10000000,
+ AcceptPerfectMatch = 0x08000000,
+};
+
+typedef struct _BufferDesc {
+ u32 link;
+ u32 bufptr;
+ vu_long cmdsts;
+ u32 extsts; /*not used here */
+} BufferDesc;
+
+/* Bits in network_desc.status */
+enum desc_status_bits {
+ DescOwn = 0x80000000, DescMore = 0x40000000, DescIntr = 0x20000000,
+ DescNoCRC = 0x10000000, DescPktOK = 0x08000000,
+ DescSizeMask = 0xfff,
+
+ DescTxAbort = 0x04000000, DescTxFIFO = 0x02000000,
+ DescTxCarrier = 0x01000000, DescTxDefer = 0x00800000,
+ DescTxExcDefer = 0x00400000, DescTxOOWCol = 0x00200000,
+ DescTxExcColl = 0x00100000, DescTxCollCount = 0x000f0000,
+
+ DescRxAbort = 0x04000000, DescRxOver = 0x02000000,
+ DescRxDest = 0x01800000, DescRxLong = 0x00400000,
+ DescRxRunt = 0x00200000, DescRxInvalid = 0x00100000,
+ DescRxCRC = 0x00080000, DescRxAlign = 0x00040000,
+ DescRxLoop = 0x00020000, DesRxColl = 0x00010000,
+};
+
+/* Bits in MEAR */
+enum mii_reg_bits {
+ MDIO_ShiftClk = 0x0040,
+ MDIO_EnbOutput = 0x0020,
+ MDIO_Data = 0x0010,
+};
+
+/* PHY Register offsets. */
+enum phy_reg_offsets {
+ BMCR = 0x00,
+ BMSR = 0x01,
+ PHYIDR1 = 0x02,
+ PHYIDR2 = 0x03,
+ ANAR = 0x04,
+ KTCR = 0x09,
+};
+
+/* basic mode control register bits */
+enum bmcr_bits {
+ Bmcr_Reset = 0x8000,
+ Bmcr_Loop = 0x4000,
+ Bmcr_Speed0 = 0x2000,
+ Bmcr_AutoNegEn = 0x1000, /*if set ignores Duplex, Speed[01] */
+ Bmcr_RstAutoNeg = 0x0200,
+ Bmcr_Duplex = 0x0100,
+ Bmcr_Speed1 = 0x0040,
+ Bmcr_Force10H = 0x0000,
+ Bmcr_Force10F = 0x0100,
+ Bmcr_Force100H = 0x2000,
+ Bmcr_Force100F = 0x2100,
+ Bmcr_Force1000H = 0x0040,
+ Bmcr_Force1000F = 0x0140,
+};
+
+/* auto negotiation advertisement register */
+enum anar_bits {
+ anar_adv_100F = 0x0100,
+ anar_adv_100H = 0x0080,
+ anar_adv_10F = 0x0040,
+ anar_adv_10H = 0x0020,
+ anar_ieee_8023 = 0x0001,
+};
+
+/* 1K-base T control register */
+enum ktcr_bits {
+ ktcr_adv_1000H = 0x0100,
+ ktcr_adv_1000F = 0x0200,
+};
+
+/* Globals */
+static u32 SavedClkRun;
+static unsigned int cur_rx;
+static unsigned int rx_config;
+static unsigned int tx_config;
+
+/* Note: transmit and receive buffers and descriptors must be
+ long long word aligned */
+static BufferDesc txd __attribute__ ((aligned(8)));
+static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(8)));
+static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(8)));
+static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]
+ __attribute__ ((aligned(8)));
+
+/* Function Prototypes */
+static int mdio_read(struct eth_device *dev, int phy_id, int addr);
+static void mdio_write(struct eth_device *dev, int phy_id, int addr, int value);
+static void mdio_sync(struct eth_device *dev, u32 offset);
+static int ns8382x_init(struct eth_device *dev, bd_t * bis);
+static void ns8382x_reset(struct eth_device *dev);
+static void ns8382x_init_rxfilter(struct eth_device *dev);
+static void ns8382x_init_txd(struct eth_device *dev);
+static void ns8382x_init_rxd(struct eth_device *dev);
+static void ns8382x_set_rx_mode(struct eth_device *dev);
+static void ns8382x_check_duplex(struct eth_device *dev);
+static int ns8382x_send(struct eth_device *dev, void *packet, int length);
+static int ns8382x_poll(struct eth_device *dev);
+static void ns8382x_disable(struct eth_device *dev);
+
+static struct pci_device_id supported[] = {
+ {PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83820},
+ {}
+};
+
+#define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
+
+static inline int
+INW(struct eth_device *dev, u_long addr)
+{
+ return le16_to_cpu(*(vu_short *) (addr + dev->iobase));
+}
+
+static int
+INL(struct eth_device *dev, u_long addr)
+{
+ return le32_to_cpu(*(vu_long *) (addr + dev->iobase));
+}
+
+static inline void
+OUTW(struct eth_device *dev, int command, u_long addr)
+{
+ *(vu_short *) ((addr + dev->iobase)) = cpu_to_le16(command);
+}
+
+static inline void
+OUTL(struct eth_device *dev, int command, u_long addr)
+{
+ *(vu_long *) ((addr + dev->iobase)) = cpu_to_le32(command);
+}
+
+/* Function: ns8382x_initialize
+ * Description: Retrieves the MAC address of the card, and sets up some
+ * globals required by other routines, and initializes the NIC, making it
+ * ready to send and receive packets.
+ * Side effects: initializes ns8382xs, ready to receive packets.
+ * Returns: int: number of cards found
+ */
+
+int
+ns8382x_initialize(bd_t * bis)
+{
+ pci_dev_t devno;
+ int card_number = 0;
+ struct eth_device *dev;
+ u32 iobase, status;
+ int i, idx = 0;
+ u32 phyAddress;
+ u32 tmp;
+ u32 chip_config;
+
+ while (1) { /* Find PCI device(s) */
+ if ((devno = pci_find_devices(supported, idx++)) < 0)
+ break;
+
+ pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+ iobase &= ~0x3; /* 1: unused and 0:I/O Space Indicator */
+
+ debug("ns8382x: NatSemi dp8382x @ 0x%x\n", iobase);
+
+ pci_write_config_dword(devno, PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ /* Check if I/O accesses and Bus Mastering are enabled. */
+ pci_read_config_dword(devno, PCI_COMMAND, &status);
+ if (!(status & PCI_COMMAND_MEMORY)) {
+ printf("Error: Can not enable MEM access.\n");
+ continue;
+ } else if (!(status & PCI_COMMAND_MASTER)) {
+ printf("Error: Can not enable Bus Mastering.\n");
+ continue;
+ }
+
+ dev = (struct eth_device *) malloc(sizeof *dev);
+ if (!dev) {
+ printf("ns8382x: Can not allocate memory\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf(dev->name, "dp8382x#%d", card_number);
+ dev->iobase = bus_to_phys(iobase);
+ dev->priv = (void *) devno;
+ dev->init = ns8382x_init;
+ dev->halt = ns8382x_disable;
+ dev->send = ns8382x_send;
+ dev->recv = ns8382x_poll;
+
+ /* ns8382x has a non-standard PM control register
+ * in PCI config space. Some boards apparently need
+ * to be brought to D0 in this manner. */
+ pci_read_config_dword(devno, PCIPM, &tmp);
+ if (tmp & (0x03 | 0x100)) { /* D0 state, disable PME assertion */
+ u32 newtmp = tmp & ~(0x03 | 0x100);
+ pci_write_config_dword(devno, PCIPM, newtmp);
+ }
+
+ /* get MAC address */
+ for (i = 0; i < 3; i++) {
+ u32 data;
+ char *mac = (char *)&dev->enetaddr[i * 2];
+
+ OUTL(dev, i * 2, RxFilterAddr);
+ data = INL(dev, RxFilterData);
+ *mac++ = data;
+ *mac++ = data >> 8;
+ }
+ /* get PHY address, can't be zero */
+ for (phyAddress = 1; phyAddress < 32; phyAddress++) {
+ u32 rev, phy1;
+
+ phy1 = mdio_read(dev, phyAddress, PHYIDR1);
+ if (phy1 == 0x2000) { /*check for 83861/91 */
+ rev = mdio_read(dev, phyAddress, PHYIDR2);
+ if ((rev & ~(0x000f)) == 0x00005c50 ||
+ (rev & ~(0x000f)) == 0x00005c60) {
+ debug("phy rev is %x\n", rev);
+ debug("phy address is %x\n",
+ phyAddress);
+ break;
+ }
+ }
+ }
+
+ /* set phy to autonegotiate && advertise everything */
+ mdio_write(dev, phyAddress, KTCR,
+ (ktcr_adv_1000H | ktcr_adv_1000F));
+ mdio_write(dev, phyAddress, ANAR,
+ (anar_adv_100F | anar_adv_100H | anar_adv_10H |
+ anar_adv_10F | anar_ieee_8023));
+ mdio_write(dev, phyAddress, BMCR, 0x0); /*restore */
+ mdio_write(dev, phyAddress, BMCR,
+ (Bmcr_AutoNegEn | Bmcr_RstAutoNeg));
+ /* Reset the chip to erase any previous misconfiguration. */
+ OUTL(dev, (ChipReset), ChipCmd);
+
+ chip_config = INL(dev, ChipConfig);
+ /* reset the phy */
+ OUTL(dev, (chip_config | PhyRst), ChipConfig);
+ /* power up and initialize transceiver */
+ OUTL(dev, (chip_config & ~(PhyDis)), ChipConfig);
+
+ mdio_sync(dev, EECtrl);
+
+ {
+ u32 chpcfg =
+ INL(dev, ChipConfig) ^ SpeedStatus_Polarity;
+
+ debug("%s: Transceiver 10%s %s duplex.\n", dev->name,
+ (chpcfg & GigSpeed) ? "00" : (chpcfg & HundSpeed)
+ ? "0" : "",
+ chpcfg & FullDuplex ? "full" : "half");
+ debug("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+ dev->enetaddr[0], dev->enetaddr[1],
+ dev->enetaddr[2], dev->enetaddr[3],
+ dev->enetaddr[4], dev->enetaddr[5]);
+ }
+
+ /* Disable PME:
+ * The PME bit is initialized from the EEPROM contents.
+ * PCI cards probably have PME disabled, but motherboard
+ * implementations may have PME set to enable WakeOnLan.
+ * With PME set the chip will scan incoming packets but
+ * nothing will be written to memory. */
+ SavedClkRun = INL(dev, ClkRun);
+ OUTL(dev, SavedClkRun & ~0x100, ClkRun);
+
+ eth_register(dev);
+
+ card_number++;
+
+ pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x60);
+
+ udelay(10 * 1000);
+ }
+ return card_number;
+}
+
+/* MII transceiver control section.
+ Read and write MII registers using software-generated serial MDIO
+ protocol. See the MII specifications or DP83840A data sheet for details.
+
+ The maximum data clock rate is 2.5 MHz. To meet minimum timing we
+ must flush writes to the PCI bus with a PCI read. */
+#define mdio_delay(mdio_addr) INL(dev, mdio_addr)
+
+#define MDIO_EnbIn (0)
+#define MDIO_WRITE0 (MDIO_EnbOutput)
+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
+
+/* Generate the preamble required for initial synchronization and
+ a few older transceivers. */
+static void
+mdio_sync(struct eth_device *dev, u32 offset)
+{
+ int bits = 32;
+
+ /* Establish sync by sending at least 32 logic ones. */
+ while (--bits >= 0) {
+ OUTL(dev, MDIO_WRITE1, offset);
+ mdio_delay(offset);
+ OUTL(dev, MDIO_WRITE1 | MDIO_ShiftClk, offset);
+ mdio_delay(offset);
+ }
+}
+
+static int
+mdio_read(struct eth_device *dev, int phy_id, int addr)
+{
+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | addr;
+ int i, retval = 0;
+
+ /* Shift the read command bits out. */
+ for (i = 15; i >= 0; i--) {
+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+ OUTL(dev, dataval, EECtrl);
+ mdio_delay(EECtrl);
+ OUTL(dev, dataval | MDIO_ShiftClk, EECtrl);
+ mdio_delay(EECtrl);
+ }
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ OUTL(dev, MDIO_EnbIn, EECtrl);
+ mdio_delay(EECtrl);
+ retval =
+ (retval << 1) | ((INL(dev, EECtrl) & MDIO_Data) ? 1 : 0);
+ OUTL(dev, MDIO_EnbIn | MDIO_ShiftClk, EECtrl);
+ mdio_delay(EECtrl);
+ }
+ return (retval >> 1) & 0xffff;
+}
+
+static void
+mdio_write(struct eth_device *dev, int phy_id, int addr, int value)
+{
+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (addr << 18) | value;
+ int i;
+
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+ OUTL(dev, dataval, EECtrl);
+ mdio_delay(EECtrl);
+ OUTL(dev, dataval | MDIO_ShiftClk, EECtrl);
+ mdio_delay(EECtrl);
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ OUTL(dev, MDIO_EnbIn, EECtrl);
+ mdio_delay(EECtrl);
+ OUTL(dev, MDIO_EnbIn | MDIO_ShiftClk, EECtrl);
+ mdio_delay(EECtrl);
+ }
+ return;
+}
+
+/* Function: ns8382x_init
+ * Description: resets the ethernet controller chip and configures
+ * registers and data structures required for sending and receiving packets.
+ * Arguments: struct eth_device *dev: NIC data structure
+ * returns: int.
+ */
+
+static int
+ns8382x_init(struct eth_device *dev, bd_t * bis)
+{
+ u32 config;
+
+ ns8382x_reset(dev);
+
+ /* Disable PME:
+ * The PME bit is initialized from the EEPROM contents.
+ * PCI cards probably have PME disabled, but motherboard
+ * implementations may have PME set to enable WakeOnLan.
+ * With PME set the chip will scan incoming packets but
+ * nothing will be written to memory. */
+ OUTL(dev, SavedClkRun & ~0x100, ClkRun);
+
+ ns8382x_init_rxfilter(dev);
+ ns8382x_init_txd(dev);
+ ns8382x_init_rxd(dev);
+
+ /*set up ChipConfig */
+ config = INL(dev, ChipConfig);
+ /*turn off 64 bit ops && Ten-bit interface
+ * && big-endian mode && extended status */
+ config &= ~(TBIEn | Mode1000 | T64En | D64En | M64En | BEMode | PhyDis | ExtStEn);
+ OUTL(dev, config, ChipConfig);
+
+ /* Configure the PCI bus bursts and FIFO thresholds. */
+ tx_config = TxCarrierIgn | TxHeartIgn | TxAutoPad
+ | TxCollRetry | TxMxdma_1024 | (0x1002);
+ rx_config = RxMxdma_1024 | 0x20;
+
+ debug("%s: Setting TxConfig Register %#08X\n", dev->name, tx_config);
+ debug("%s: Setting RxConfig Register %#08X\n", dev->name, rx_config);
+
+ OUTL(dev, tx_config, TxConfig);
+ OUTL(dev, rx_config, RxConfig);
+
+ /*turn off priority queueing */
+ OUTL(dev, 0x0, PriQueue);
+
+ ns8382x_check_duplex(dev);
+ ns8382x_set_rx_mode(dev);
+
+ OUTL(dev, (RxOn | TxOn), ChipCmd);
+ return 1;
+}
+
+/* Function: ns8382x_reset
+ * Description: soft resets the controller chip
+ * Arguments: struct eth_device *dev: NIC data structure
+ * Returns: void.
+ */
+static void
+ns8382x_reset(struct eth_device *dev)
+{
+ OUTL(dev, ChipReset, ChipCmd);
+ while (INL(dev, ChipCmd))
+ /*wait until done */ ;
+ OUTL(dev, 0, IntrMask);
+ OUTL(dev, 0, IntrEnable);
+}
+
+/* Function: ns8382x_init_rxfilter
+ * Description: sets receive filter address to our MAC address
+ * Arguments: struct eth_device *dev: NIC data structure
+ * returns: void.
+ */
+
+static void
+ns8382x_init_rxfilter(struct eth_device *dev)
+{
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i += 2) {
+ OUTL(dev, i, RxFilterAddr);
+ OUTW(dev, dev->enetaddr[i] + (dev->enetaddr[i + 1] << 8),
+ RxFilterData);
+ }
+}
+
+/* Function: ns8382x_init_txd
+ * Description: initializes the Tx descriptor
+ * Arguments: struct eth_device *dev: NIC data structure
+ * returns: void.
+ */
+
+static void
+ns8382x_init_txd(struct eth_device *dev)
+{
+ txd.link = (u32) 0;
+ txd.bufptr = cpu_to_le32((u32) & txb[0]);
+ txd.cmdsts = (u32) 0;
+ txd.extsts = (u32) 0;
+
+ OUTL(dev, 0x0, TxRingPtrHi);
+ OUTL(dev, phys_to_bus((u32)&txd), TxRingPtr);
+
+ debug("ns8382x_init_txd: TX descriptor register loaded with: %#08X (&txd: %p)\n",
+ INL(dev, TxRingPtr), &txd);
+}
+
+/* Function: ns8382x_init_rxd
+ * Description: initializes the Rx descriptor ring
+ * Arguments: struct eth_device *dev: NIC data structure
+ * Returns: void.
+ */
+
+static void
+ns8382x_init_rxd(struct eth_device *dev)
+{
+ int i;
+
+ OUTL(dev, 0x0, RxRingPtrHi);
+
+ cur_rx = 0;
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ rxd[i].link =
+ cpu_to_le32((i + 1 <
+ NUM_RX_DESC) ? (u32) & rxd[i +
+ 1] : (u32) &
+ rxd[0]);
+ rxd[i].extsts = cpu_to_le32((u32) 0x0);
+ rxd[i].cmdsts = cpu_to_le32((u32) RX_BUF_SIZE);
+ rxd[i].bufptr = cpu_to_le32((u32) & rxb[i * RX_BUF_SIZE]);
+
+ debug
+ ("ns8382x_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%X\n",
+ i, &rxd[i], le32_to_cpu(rxd[i].link),
+ le32_to_cpu(rxd[i].cmdsts), le32_to_cpu(rxd[i].bufptr));
+ }
+ OUTL(dev, phys_to_bus((u32) & rxd), RxRingPtr);
+
+ debug("ns8382x_init_rxd: RX descriptor register loaded with: %X\n",
+ INL(dev, RxRingPtr));
+}
+
+/* Function: ns8382x_set_rx_mode
+ * Description:
+ * sets the receive mode to accept all broadcast packets and packets
+ * with our MAC address, and reject all multicast packets.
+ * Arguments: struct eth_device *dev: NIC data structure
+ * Returns: void.
+ */
+
+static void
+ns8382x_set_rx_mode(struct eth_device *dev)
+{
+ u32 rx_mode = 0x0;
+ /*spec says RxFilterEnable has to be 0 for rest of
+ * this stuff to be properly configured. Linux driver
+ * seems to support this*/
+/* OUTL(dev, rx_mode, RxFilterAddr);*/
+ rx_mode = (RxFilterEnable | AcceptAllBroadcast | AcceptPerfectMatch);
+ OUTL(dev, rx_mode, RxFilterAddr);
+ printf("ns8382x_set_rx_mode: set to %X\n", rx_mode);
+ /*now we turn RxFilterEnable back on */
+ /*rx_mode |= RxFilterEnable;
+ OUTL(dev, rx_mode, RxFilterAddr);*/
+}
+
+static void
+ns8382x_check_duplex(struct eth_device *dev)
+{
+ int gig = 0;
+ int hun = 0;
+ int duplex = 0;
+ int config = (INL(dev, ChipConfig) ^ SpeedStatus_Polarity);
+
+ duplex = (config & FullDuplex) ? 1 : 0;
+ gig = (config & GigSpeed) ? 1 : 0;
+ hun = (config & HundSpeed) ? 1 : 0;
+
+ debug("%s: Setting 10%s %s-duplex based on negotiated link"
+ " capability.\n", dev->name, (gig) ? "00" : (hun) ? "0" : "",
+ duplex ? "full" : "half");
+
+ if (duplex) {
+ rx_config |= RxAcceptTx;
+ tx_config |= (TxCarrierIgn | TxHeartIgn);
+ } else {
+ rx_config &= ~RxAcceptTx;
+ tx_config &= ~(TxCarrierIgn | TxHeartIgn);
+ }
+
+ debug("%s: Resetting TxConfig Register %#08X\n", dev->name, tx_config);
+ debug("%s: Resetting RxConfig Register %#08X\n", dev->name, rx_config);
+
+ OUTL(dev, tx_config, TxConfig);
+ OUTL(dev, rx_config, RxConfig);
+
+ /*if speed is 10 or 100, remove MODE1000,
+ * if it's 1000, then set it */
+ config = INL(dev, ChipConfig);
+ if (gig)
+ config |= Mode1000;
+ else
+ config &= ~Mode1000;
+
+ debug("%s: %setting Mode1000\n", dev->name, (gig) ? "S" : "Uns");
+
+ OUTL(dev, config, ChipConfig);
+}
+
+/* Function: ns8382x_send
+ * Description: transmits a packet and waits for completion or timeout.
+ * Returns: void. */
+static int ns8382x_send(struct eth_device *dev, void *packet, int length)
+{
+ u32 i, status = 0;
+ vu_long tx_stat = 0;
+
+ /* Stop the transmitter */
+ OUTL(dev, TxOff, ChipCmd);
+
+ debug("ns8382x_send: sending %d bytes\n", (int)length);
+
+ /* set the transmit buffer descriptor and enable Transmit State Machine */
+ txd.link = cpu_to_le32(0x0);
+ txd.bufptr = cpu_to_le32(phys_to_bus((u32)packet));
+ txd.extsts = cpu_to_le32(0x0);
+ txd.cmdsts = cpu_to_le32(DescOwn | length);
+
+ /* load Transmit Descriptor Register */
+ OUTL(dev, phys_to_bus((u32) & txd), TxRingPtr);
+
+ debug("ns8382x_send: TX descriptor register loaded with: %#08X\n",
+ INL(dev, TxRingPtr));
+ debug("\ttxd.link:%X\tbufp:%X\texsts:%X\tcmdsts:%X\n",
+ le32_to_cpu(txd.link), le32_to_cpu(txd.bufptr),
+ le32_to_cpu(txd.extsts), le32_to_cpu(txd.cmdsts));
+
+ /* restart the transmitter */
+ OUTL(dev, TxOn, ChipCmd);
+
+ for (i = 0; (tx_stat = le32_to_cpu(txd.cmdsts)) & DescOwn; i++) {
+ if (i >= TOUT_LOOP) {
+ printf ("%s: tx error buffer not ready: txd.cmdsts %#lX\n",
+ dev->name, tx_stat);
+ goto Done;
+ }
+ }
+
+ if (!(tx_stat & DescPktOK)) {
+ printf("ns8382x_send: Transmit error, Tx status %lX.\n", tx_stat);
+ goto Done;
+ }
+
+ debug("ns8382x_send: tx_stat: %#08lX\n", tx_stat);
+
+ status = 1;
+Done:
+ return status;
+}
+
+/* Function: ns8382x_poll
+ * Description: checks for a received packet and returns it if found.
+ * Arguments: struct eth_device *dev: NIC data structure
+ * Returns: 1 if packet was received.
+ * 0 if no packet was received.
+ * Side effects:
+ * Returns (copies) the packet to the array dev->packet.
+ * Returns the length of the packet.
+ */
+
+static int
+ns8382x_poll(struct eth_device *dev)
+{
+ int retstat = 0;
+ int length = 0;
+ vu_long rx_status = le32_to_cpu(rxd[cur_rx].cmdsts);
+
+ if (!(rx_status & (u32) DescOwn))
+ return retstat;
+
+ debug("ns8382x_poll: got a packet: cur_rx:%u, status:%lx\n",
+ cur_rx, rx_status);
+
+ length = (rx_status & DSIZE) - CRC_SIZE;
+
+ if ((rx_status & (DescMore | DescPktOK | DescRxLong)) != DescPktOK) {
+ /* corrupted packet received */
+ printf("ns8382x_poll: Corrupted packet, status:%lx\n", rx_status);
+ retstat = 0;
+ } else {
+ /* give packet to higher level routine */
+ NetReceive((rxb + cur_rx * RX_BUF_SIZE), length);
+ retstat = 1;
+ }
+
+ /* return the descriptor and buffer to receive ring */
+ rxd[cur_rx].cmdsts = cpu_to_le32(RX_BUF_SIZE);
+ rxd[cur_rx].bufptr = cpu_to_le32((u32) & rxb[cur_rx * RX_BUF_SIZE]);
+
+ if (++cur_rx == NUM_RX_DESC)
+ cur_rx = 0;
+
+ /* re-enable the potentially idle receive state machine */
+ OUTL(dev, RxOn, ChipCmd);
+
+ return retstat;
+}
+
+/* Function: ns8382x_disable
+ * Description: Turns off interrupts and stops Tx and Rx engines
+ * Arguments: struct eth_device *dev: NIC data structure
+ * Returns: void.
+ */
+
+static void
+ns8382x_disable(struct eth_device *dev)
+{
+ /* Disable interrupts using the mask. */
+ OUTL(dev, 0, IntrMask);
+ OUTL(dev, 0, IntrEnable);
+
+ /* Stop the chip's Tx and Rx processes. */
+ OUTL(dev, (RxOff | TxOff), ChipCmd);
+
+ /* Restore PME enable bit */
+ OUTL(dev, SavedClkRun, ClkRun);
+}
diff --git a/qemu/roms/u-boot/drivers/net/pcnet.c b/qemu/roms/u-boot/drivers/net/pcnet.c
new file mode 100644
index 000000000..237fbba51
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/pcnet.c
@@ -0,0 +1,542 @@
+/*
+ * (C) Copyright 2002 Wolfgang Grandegger, wg@denx.de.
+ *
+ * This driver for AMD PCnet network controllers is derived from the
+ * Linux driver pcnet32.c written 1996-1999 by Thomas Bogendoerfer.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define PCNET_DEBUG_LEVEL 0 /* 0=off, 1=init, 2=rx/tx */
+
+#define PCNET_DEBUG1(fmt,args...) \
+ debug_cond(PCNET_DEBUG_LEVEL > 0, fmt ,##args)
+#define PCNET_DEBUG2(fmt,args...) \
+ debug_cond(PCNET_DEBUG_LEVEL > 1, fmt ,##args)
+
+#if !defined(CONF_PCNET_79C973) && defined(CONF_PCNET_79C975)
+#error "Macro for PCnet chip version is not defined!"
+#endif
+
+/*
+ * Set the number of Tx and Rx buffers, using Log_2(# buffers).
+ * Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
+ * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4).
+ */
+#define PCNET_LOG_TX_BUFFERS 0
+#define PCNET_LOG_RX_BUFFERS 2
+
+#define TX_RING_SIZE (1 << (PCNET_LOG_TX_BUFFERS))
+#define TX_RING_LEN_BITS ((PCNET_LOG_TX_BUFFERS) << 12)
+
+#define RX_RING_SIZE (1 << (PCNET_LOG_RX_BUFFERS))
+#define RX_RING_LEN_BITS ((PCNET_LOG_RX_BUFFERS) << 4)
+
+#define PKT_BUF_SZ 1544
+
+/* The PCNET Rx and Tx ring descriptors. */
+struct pcnet_rx_head {
+ u32 base;
+ s16 buf_length;
+ s16 status;
+ u32 msg_length;
+ u32 reserved;
+};
+
+struct pcnet_tx_head {
+ u32 base;
+ s16 length;
+ s16 status;
+ u32 misc;
+ u32 reserved;
+};
+
+/* The PCNET 32-Bit initialization block, described in databook. */
+struct pcnet_init_block {
+ u16 mode;
+ u16 tlen_rlen;
+ u8 phys_addr[6];
+ u16 reserved;
+ u32 filter[2];
+ /* Receive and transmit ring base, along with extra bits. */
+ u32 rx_ring;
+ u32 tx_ring;
+ u32 reserved2;
+};
+
+struct pcnet_uncached_priv {
+ struct pcnet_rx_head rx_ring[RX_RING_SIZE];
+ struct pcnet_tx_head tx_ring[TX_RING_SIZE];
+ struct pcnet_init_block init_block;
+};
+
+typedef struct pcnet_priv {
+ struct pcnet_uncached_priv *uc;
+ /* Receive Buffer space */
+ unsigned char (*rx_buf)[RX_RING_SIZE][PKT_BUF_SZ + 4];
+ int cur_rx;
+ int cur_tx;
+} pcnet_priv_t;
+
+static pcnet_priv_t *lp;
+
+/* Offsets from base I/O address for WIO mode */
+#define PCNET_RDP 0x10
+#define PCNET_RAP 0x12
+#define PCNET_RESET 0x14
+#define PCNET_BDP 0x16
+
+static u16 pcnet_read_csr(struct eth_device *dev, int index)
+{
+ outw(index, dev->iobase + PCNET_RAP);
+ return inw(dev->iobase + PCNET_RDP);
+}
+
+static void pcnet_write_csr(struct eth_device *dev, int index, u16 val)
+{
+ outw(index, dev->iobase + PCNET_RAP);
+ outw(val, dev->iobase + PCNET_RDP);
+}
+
+static u16 pcnet_read_bcr(struct eth_device *dev, int index)
+{
+ outw(index, dev->iobase + PCNET_RAP);
+ return inw(dev->iobase + PCNET_BDP);
+}
+
+static void pcnet_write_bcr(struct eth_device *dev, int index, u16 val)
+{
+ outw(index, dev->iobase + PCNET_RAP);
+ outw(val, dev->iobase + PCNET_BDP);
+}
+
+static void pcnet_reset(struct eth_device *dev)
+{
+ inw(dev->iobase + PCNET_RESET);
+}
+
+static int pcnet_check(struct eth_device *dev)
+{
+ outw(88, dev->iobase + PCNET_RAP);
+ return inw(dev->iobase + PCNET_RAP) == 88;
+}
+
+static int pcnet_init (struct eth_device *dev, bd_t * bis);
+static int pcnet_send(struct eth_device *dev, void *packet, int length);
+static int pcnet_recv (struct eth_device *dev);
+static void pcnet_halt (struct eth_device *dev);
+static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_num);
+
+#define PCI_TO_MEM(d, a) pci_virt_to_mem((pci_dev_t)d->priv, (a))
+#define PCI_TO_MEM_LE(d,a) (u32)(cpu_to_le32(PCI_TO_MEM(d,a)))
+
+static struct pci_device_id supported[] = {
+ {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE},
+ {}
+};
+
+
+int pcnet_initialize(bd_t *bis)
+{
+ pci_dev_t devbusfn;
+ struct eth_device *dev;
+ u16 command, status;
+ int dev_nr = 0;
+
+ PCNET_DEBUG1("\npcnet_initialize...\n");
+
+ for (dev_nr = 0;; dev_nr++) {
+
+ /*
+ * Find the PCnet PCI device(s).
+ */
+ devbusfn = pci_find_devices(supported, dev_nr);
+ if (devbusfn < 0)
+ break;
+
+ /*
+ * Allocate and pre-fill the device structure.
+ */
+ dev = (struct eth_device *)malloc(sizeof(*dev));
+ if (!dev) {
+ printf("pcnet: Can not allocate memory\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+ dev->priv = (void *)devbusfn;
+ sprintf(dev->name, "pcnet#%d", dev_nr);
+
+ /*
+ * Setup the PCI device.
+ */
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0,
+ (unsigned int *)&dev->iobase);
+ dev->iobase = pci_io_to_phys(devbusfn, dev->iobase);
+ dev->iobase &= ~0xf;
+
+ PCNET_DEBUG1("%s: devbusfn=0x%x iobase=0x%x: ",
+ dev->name, devbusfn, dev->iobase);
+
+ command = PCI_COMMAND_IO | PCI_COMMAND_MASTER;
+ pci_write_config_word(devbusfn, PCI_COMMAND, command);
+ pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+ if ((status & command) != command) {
+ printf("%s: Couldn't enable IO access or Bus Mastering\n",
+ dev->name);
+ free(dev);
+ continue;
+ }
+
+ pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, 0x40);
+
+ /*
+ * Probe the PCnet chip.
+ */
+ if (pcnet_probe(dev, bis, dev_nr) < 0) {
+ free(dev);
+ continue;
+ }
+
+ /*
+ * Setup device structure and register the driver.
+ */
+ dev->init = pcnet_init;
+ dev->halt = pcnet_halt;
+ dev->send = pcnet_send;
+ dev->recv = pcnet_recv;
+
+ eth_register(dev);
+ }
+
+ udelay(10 * 1000);
+
+ return dev_nr;
+}
+
+static int pcnet_probe(struct eth_device *dev, bd_t *bis, int dev_nr)
+{
+ int chip_version;
+ char *chipname;
+
+#ifdef PCNET_HAS_PROM
+ int i;
+#endif
+
+ /* Reset the PCnet controller */
+ pcnet_reset(dev);
+
+ /* Check if register access is working */
+ if (pcnet_read_csr(dev, 0) != 4 || !pcnet_check(dev)) {
+ printf("%s: CSR register access check failed\n", dev->name);
+ return -1;
+ }
+
+ /* Identify the chip */
+ chip_version =
+ pcnet_read_csr(dev, 88) | (pcnet_read_csr(dev, 89) << 16);
+ if ((chip_version & 0xfff) != 0x003)
+ return -1;
+ chip_version = (chip_version >> 12) & 0xffff;
+ switch (chip_version) {
+ case 0x2621:
+ chipname = "PCnet/PCI II 79C970A"; /* PCI */
+ break;
+#ifdef CONFIG_PCNET_79C973
+ case 0x2625:
+ chipname = "PCnet/FAST III 79C973"; /* PCI */
+ break;
+#endif
+#ifdef CONFIG_PCNET_79C975
+ case 0x2627:
+ chipname = "PCnet/FAST III 79C975"; /* PCI */
+ break;
+#endif
+ default:
+ printf("%s: PCnet version %#x not supported\n",
+ dev->name, chip_version);
+ return -1;
+ }
+
+ PCNET_DEBUG1("AMD %s\n", chipname);
+
+#ifdef PCNET_HAS_PROM
+ /*
+ * In most chips, after a chip reset, the ethernet address is read from
+ * the station address PROM at the base address and programmed into the
+ * "Physical Address Registers" CSR12-14.
+ */
+ for (i = 0; i < 3; i++) {
+ unsigned int val;
+
+ val = pcnet_read_csr(dev, i + 12) & 0x0ffff;
+ /* There may be endianness issues here. */
+ dev->enetaddr[2 * i] = val & 0x0ff;
+ dev->enetaddr[2 * i + 1] = (val >> 8) & 0x0ff;
+ }
+#endif /* PCNET_HAS_PROM */
+
+ return 0;
+}
+
+static int pcnet_init(struct eth_device *dev, bd_t *bis)
+{
+ struct pcnet_uncached_priv *uc;
+ int i, val;
+ u32 addr;
+
+ PCNET_DEBUG1("%s: pcnet_init...\n", dev->name);
+
+ /* Switch pcnet to 32bit mode */
+ pcnet_write_bcr(dev, 20, 2);
+
+ /* Set/reset autoselect bit */
+ val = pcnet_read_bcr(dev, 2) & ~2;
+ val |= 2;
+ pcnet_write_bcr(dev, 2, val);
+
+ /* Enable auto negotiate, setup, disable fd */
+ val = pcnet_read_bcr(dev, 32) & ~0x98;
+ val |= 0x20;
+ pcnet_write_bcr(dev, 32, val);
+
+ /*
+ * Enable NOUFLO on supported controllers, with the transmit
+ * start point set to the full packet. This will cause entire
+ * packets to be buffered by the ethernet controller before
+ * transmission, eliminating underflows which are common on
+ * slower devices. Controllers which do not support NOUFLO will
+ * simply be left with a larger transmit FIFO threshold.
+ */
+ val = pcnet_read_bcr(dev, 18);
+ val |= 1 << 11;
+ pcnet_write_bcr(dev, 18, val);
+ val = pcnet_read_csr(dev, 80);
+ val |= 0x3 << 10;
+ pcnet_write_csr(dev, 80, val);
+
+ /*
+ * We only maintain one structure because the drivers will never
+ * be used concurrently. In 32bit mode the RX and TX ring entries
+ * must be aligned on 16-byte boundaries.
+ */
+ if (lp == NULL) {
+ addr = (u32)malloc(sizeof(pcnet_priv_t) + 0x10);
+ addr = (addr + 0xf) & ~0xf;
+ lp = (pcnet_priv_t *)addr;
+
+ addr = (u32)memalign(ARCH_DMA_MINALIGN, sizeof(*lp->uc));
+ flush_dcache_range(addr, addr + sizeof(*lp->uc));
+ addr = UNCACHED_SDRAM(addr);
+ lp->uc = (struct pcnet_uncached_priv *)addr;
+
+ addr = (u32)memalign(ARCH_DMA_MINALIGN, sizeof(*lp->rx_buf));
+ flush_dcache_range(addr, addr + sizeof(*lp->rx_buf));
+ lp->rx_buf = (void *)addr;
+ }
+
+ uc = lp->uc;
+
+ uc->init_block.mode = cpu_to_le16(0x0000);
+ uc->init_block.filter[0] = 0x00000000;
+ uc->init_block.filter[1] = 0x00000000;
+
+ /*
+ * Initialize the Rx ring.
+ */
+ lp->cur_rx = 0;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ uc->rx_ring[i].base = PCI_TO_MEM_LE(dev, (*lp->rx_buf)[i]);
+ uc->rx_ring[i].buf_length = cpu_to_le16(-PKT_BUF_SZ);
+ uc->rx_ring[i].status = cpu_to_le16(0x8000);
+ PCNET_DEBUG1
+ ("Rx%d: base=0x%x buf_length=0x%hx status=0x%hx\n", i,
+ uc->rx_ring[i].base, uc->rx_ring[i].buf_length,
+ uc->rx_ring[i].status);
+ }
+
+ /*
+ * Initialize the Tx ring. The Tx buffer address is filled in as
+ * needed, but we do need to clear the upper ownership bit.
+ */
+ lp->cur_tx = 0;
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ uc->tx_ring[i].base = 0;
+ uc->tx_ring[i].status = 0;
+ }
+
+ /*
+ * Setup Init Block.
+ */
+ PCNET_DEBUG1("Init block at 0x%p: MAC", &lp->uc->init_block);
+
+ for (i = 0; i < 6; i++) {
+ lp->uc->init_block.phys_addr[i] = dev->enetaddr[i];
+ PCNET_DEBUG1(" %02x", lp->uc->init_block.phys_addr[i]);
+ }
+
+ uc->init_block.tlen_rlen = cpu_to_le16(TX_RING_LEN_BITS |
+ RX_RING_LEN_BITS);
+ uc->init_block.rx_ring = PCI_TO_MEM_LE(dev, uc->rx_ring);
+ uc->init_block.tx_ring = PCI_TO_MEM_LE(dev, uc->tx_ring);
+
+ PCNET_DEBUG1("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n",
+ uc->init_block.tlen_rlen,
+ uc->init_block.rx_ring, uc->init_block.tx_ring);
+
+ /*
+ * Tell the controller where the Init Block is located.
+ */
+ barrier();
+ addr = PCI_TO_MEM(dev, &lp->uc->init_block);
+ pcnet_write_csr(dev, 1, addr & 0xffff);
+ pcnet_write_csr(dev, 2, (addr >> 16) & 0xffff);
+
+ pcnet_write_csr(dev, 4, 0x0915);
+ pcnet_write_csr(dev, 0, 0x0001); /* start */
+
+ /* Wait for Init Done bit */
+ for (i = 10000; i > 0; i--) {
+ if (pcnet_read_csr(dev, 0) & 0x0100)
+ break;
+ udelay(10);
+ }
+ if (i <= 0) {
+ printf("%s: TIMEOUT: controller init failed\n", dev->name);
+ pcnet_reset(dev);
+ return -1;
+ }
+
+ /*
+ * Finally start network controller operation.
+ */
+ pcnet_write_csr(dev, 0, 0x0002);
+
+ return 0;
+}
+
+static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len)
+{
+ int i, status;
+ struct pcnet_tx_head *entry = &lp->uc->tx_ring[lp->cur_tx];
+
+ PCNET_DEBUG2("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len,
+ packet);
+
+ flush_dcache_range((unsigned long)packet,
+ (unsigned long)packet + pkt_len);
+
+ /* Wait for completion by testing the OWN bit */
+ for (i = 1000; i > 0; i--) {
+ status = readw(&entry->status);
+ if ((status & 0x8000) == 0)
+ break;
+ udelay(100);
+ PCNET_DEBUG2(".");
+ }
+ if (i <= 0) {
+ printf("%s: TIMEOUT: Tx%d failed (status = 0x%x)\n",
+ dev->name, lp->cur_tx, status);
+ pkt_len = 0;
+ goto failure;
+ }
+
+ /*
+ * Setup Tx ring. Caution: the write order is important here,
+ * set the status with the "ownership" bits last.
+ */
+ writew(-pkt_len, &entry->length);
+ writel(0, &entry->misc);
+ writel(PCI_TO_MEM(dev, packet), &entry->base);
+ writew(0x8300, &entry->status);
+
+ /* Trigger an immediate send poll. */
+ pcnet_write_csr(dev, 0, 0x0008);
+
+ failure:
+ if (++lp->cur_tx >= TX_RING_SIZE)
+ lp->cur_tx = 0;
+
+ PCNET_DEBUG2("done\n");
+ return pkt_len;
+}
+
+static int pcnet_recv (struct eth_device *dev)
+{
+ struct pcnet_rx_head *entry;
+ unsigned char *buf;
+ int pkt_len = 0;
+ u16 status, err_status;
+
+ while (1) {
+ entry = &lp->uc->rx_ring[lp->cur_rx];
+ /*
+ * If we own the next entry, it's a new packet. Send it up.
+ */
+ status = readw(&entry->status);
+ if ((status & 0x8000) != 0)
+ break;
+ err_status = status >> 8;
+
+ if (err_status != 0x03) { /* There was an error. */
+ printf("%s: Rx%d", dev->name, lp->cur_rx);
+ PCNET_DEBUG1(" (status=0x%x)", err_status);
+ if (err_status & 0x20)
+ printf(" Frame");
+ if (err_status & 0x10)
+ printf(" Overflow");
+ if (err_status & 0x08)
+ printf(" CRC");
+ if (err_status & 0x04)
+ printf(" Fifo");
+ printf(" Error\n");
+ status &= 0x03ff;
+
+ } else {
+ pkt_len = (readl(&entry->msg_length) & 0xfff) - 4;
+ if (pkt_len < 60) {
+ printf("%s: Rx%d: invalid packet length %d\n",
+ dev->name, lp->cur_rx, pkt_len);
+ } else {
+ buf = (*lp->rx_buf)[lp->cur_rx];
+ invalidate_dcache_range((unsigned long)buf,
+ (unsigned long)buf + pkt_len);
+ NetReceive(buf, pkt_len);
+ PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n",
+ lp->cur_rx, pkt_len, buf);
+ }
+ }
+
+ status |= 0x8000;
+ writew(status, &entry->status);
+
+ if (++lp->cur_rx >= RX_RING_SIZE)
+ lp->cur_rx = 0;
+ }
+ return pkt_len;
+}
+
+static void pcnet_halt(struct eth_device *dev)
+{
+ int i;
+
+ PCNET_DEBUG1("%s: pcnet_halt...\n", dev->name);
+
+ /* Reset the PCnet controller */
+ pcnet_reset(dev);
+
+ /* Wait for Stop bit */
+ for (i = 1000; i > 0; i--) {
+ if (pcnet_read_csr(dev, 0) & 0x4)
+ break;
+ udelay(10);
+ }
+ if (i <= 0)
+ printf("%s: TIMEOUT: controller reset failed\n", dev->name);
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/Makefile b/qemu/roms/u-boot/drivers/net/phy/Makefile
new file mode 100644
index 000000000..dbf7bf705
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/Makefile
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_BITBANGMII) += miiphybb.o
+obj-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o
+obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o
+
+obj-$(CONFIG_PHYLIB) += phy.o
+obj-$(CONFIG_PHYLIB_10G) += generic_10g.o
+obj-$(CONFIG_PHY_ATHEROS) += atheros.o
+obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
+obj-$(CONFIG_PHY_DAVICOM) += davicom.o
+obj-$(CONFIG_PHY_ET1011C) += et1011c.o
+obj-$(CONFIG_PHY_ICPLUS) += icplus.o
+obj-$(CONFIG_PHY_LXT) += lxt.o
+obj-$(CONFIG_PHY_MARVELL) += marvell.o
+obj-$(CONFIG_PHY_MICREL) += micrel.o
+obj-$(CONFIG_PHY_NATSEMI) += natsemi.o
+obj-$(CONFIG_PHY_REALTEK) += realtek.o
+obj-$(CONFIG_PHY_SMSC) += smsc.o
+obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
+obj-$(CONFIG_PHY_VITESSE) += vitesse.o
diff --git a/qemu/roms/u-boot/drivers/net/phy/atheros.c b/qemu/roms/u-boot/drivers/net/phy/atheros.c
new file mode 100644
index 000000000..d509e30d3
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/atheros.c
@@ -0,0 +1,76 @@
+/*
+ * Atheros PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2011, 2013 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ */
+#include <phy.h>
+
+static int ar8021_config(struct phy_device *phydev)
+{
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x3D47);
+
+ phydev->supported = phydev->drv->features;
+ return 0;
+}
+
+static int ar8035_config(struct phy_device *phydev)
+{
+ int regval;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007);
+ regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018));
+
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
+ regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100));
+
+ phydev->supported = phydev->drv->features;
+
+ return 0;
+}
+
+static struct phy_driver AR8021_driver = {
+ .name = "AR8021",
+ .uid = 0x4dd040,
+ .mask = 0x4ffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = ar8021_config,
+ .startup = genphy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+static struct phy_driver AR8031_driver = {
+ .name = "AR8031/AR8033",
+ .uid = 0x4dd074,
+ .mask = 0xffffffef,
+ .features = PHY_GBIT_FEATURES,
+ .config = ar8021_config,
+ .startup = genphy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+static struct phy_driver AR8035_driver = {
+ .name = "AR8035",
+ .uid = 0x4dd072,
+ .mask = 0xffffffef,
+ .features = PHY_GBIT_FEATURES,
+ .config = ar8035_config,
+ .startup = genphy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+int phy_atheros_init(void)
+{
+ phy_register(&AR8021_driver);
+ phy_register(&AR8031_driver);
+ phy_register(&AR8035_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/broadcom.c b/qemu/roms/u-boot/drivers/net/phy/broadcom.c
new file mode 100644
index 000000000..4512763b5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/broadcom.c
@@ -0,0 +1,274 @@
+/*
+ * Broadcom PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ */
+#include <config.h>
+#include <common.h>
+#include <phy.h>
+
+/* Broadcom BCM54xx -- taken from linux sungem_phy */
+#define MIIM_BCM54xx_AUXCNTL 0x18
+#define MIIM_BCM54xx_AUXCNTL_ENCODE(val) (((val & 0x7) << 12)|(val & 0x7))
+#define MIIM_BCM54xx_AUXSTATUS 0x19
+#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700
+#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8
+
+#define MIIM_BCM54XX_SHD 0x1c
+#define MIIM_BCM54XX_SHD_WRITE 0x8000
+#define MIIM_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10)
+#define MIIM_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0)
+#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data) \
+ (MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \
+ MIIM_BCM54XX_SHD_DATA(data))
+
+#define MIIM_BCM54XX_EXP_DATA 0x15 /* Expansion register data */
+#define MIIM_BCM54XX_EXP_SEL 0x17 /* Expansion register select */
+#define MIIM_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */
+#define MIIM_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */
+
+/* Broadcom BCM5461S */
+static int bcm5461_config(struct phy_device *phydev)
+{
+ genphy_config_aneg(phydev);
+
+ phy_reset(phydev);
+
+ return 0;
+}
+
+static int bcm54xx_parse_status(struct phy_device *phydev)
+{
+ unsigned int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXSTATUS);
+
+ switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >>
+ MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) {
+ case 1:
+ phydev->duplex = DUPLEX_HALF;
+ phydev->speed = SPEED_10;
+ break;
+ case 2:
+ phydev->duplex = DUPLEX_FULL;
+ phydev->speed = SPEED_10;
+ break;
+ case 3:
+ phydev->duplex = DUPLEX_HALF;
+ phydev->speed = SPEED_100;
+ break;
+ case 5:
+ phydev->duplex = DUPLEX_FULL;
+ phydev->speed = SPEED_100;
+ break;
+ case 6:
+ phydev->duplex = DUPLEX_HALF;
+ phydev->speed = SPEED_1000;
+ break;
+ case 7:
+ phydev->duplex = DUPLEX_FULL;
+ phydev->speed = SPEED_1000;
+ break;
+ default:
+ printf("Auto-neg error, defaulting to 10BT/HD\n");
+ phydev->duplex = DUPLEX_HALF;
+ phydev->speed = SPEED_10;
+ break;
+ }
+
+ return 0;
+}
+
+static int bcm54xx_startup(struct phy_device *phydev)
+{
+ /* Read the Status (2x to make sure link is right) */
+ genphy_update_link(phydev);
+ bcm54xx_parse_status(phydev);
+
+ return 0;
+}
+
+/* Broadcom BCM5482S */
+/*
+ * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain
+ * circumstances. eg a gigabit TSEC connected to a gigabit switch with
+ * a 4-wire ethernet cable. Both ends advertise gigabit, but can't
+ * link. "Ethernet@Wirespeed" reduces advertised speed until link
+ * can be achieved.
+ */
+static u32 bcm5482_read_wirespeed(struct phy_device *phydev, u32 reg)
+{
+ return (phy_read(phydev, MDIO_DEVAD_NONE, reg) & 0x8FFF) | 0x8010;
+}
+
+static int bcm5482_config(struct phy_device *phydev)
+{
+ unsigned int reg;
+
+ /* reset the PHY */
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+ reg |= BMCR_RESET;
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg);
+
+ /* Setup read from auxilary control shadow register 7 */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL,
+ MIIM_BCM54xx_AUXCNTL_ENCODE(7));
+ /* Read Misc Control register and or in Ethernet@Wirespeed */
+ reg = bcm5482_read_wirespeed(phydev, MIIM_BCM54xx_AUXCNTL);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, reg);
+
+ /* Initial config/enable of secondary SerDes interface */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD,
+ MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf));
+ /* Write intial value to secondary SerDes Contol */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL,
+ MIIM_BCM54XX_EXP_SEL_SSD | 0);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA,
+ BMCR_ANRESTART);
+ /* Enable copper/fiber auto-detect */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD,
+ MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201));
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+/*
+ * Find out if PHY is in copper or serdes mode by looking at Expansion Reg
+ * 0x42 - "Operating Mode Status Register"
+ */
+static int bcm5482_is_serdes(struct phy_device *phydev)
+{
+ u16 val;
+ int serdes = 0;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL,
+ MIIM_BCM54XX_EXP_SEL_ER | 0x42);
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA);
+
+ switch (val & 0x1f) {
+ case 0x0d: /* RGMII-to-100Base-FX */
+ case 0x0e: /* RGMII-to-SGMII */
+ case 0x0f: /* RGMII-to-SerDes */
+ case 0x12: /* SGMII-to-SerDes */
+ case 0x13: /* SGMII-to-100Base-FX */
+ case 0x16: /* SerDes-to-Serdes */
+ serdes = 1;
+ break;
+ case 0x6: /* RGMII-to-Copper */
+ case 0x14: /* SGMII-to-Copper */
+ case 0x17: /* SerDes-to-Copper */
+ break;
+ default:
+ printf("ERROR, invalid PHY mode (0x%x\n)", val);
+ break;
+ }
+
+ return serdes;
+}
+
+/*
+ * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating
+ * Mode Status Register"
+ */
+static u32 bcm5482_parse_serdes_sr(struct phy_device *phydev)
+{
+ u16 val;
+ int i = 0;
+
+ /* Wait 1s for link - Clause 37 autonegotiation happens very fast */
+ while (1) {
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL,
+ MIIM_BCM54XX_EXP_SEL_ER | 0x42);
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA);
+
+ if (val & 0x8000)
+ break;
+
+ if (i++ > 1000) {
+ phydev->link = 0;
+ return 1;
+ }
+
+ udelay(1000); /* 1 ms */
+ }
+
+ phydev->link = 1;
+ switch ((val >> 13) & 0x3) {
+ case (0x00):
+ phydev->speed = 10;
+ break;
+ case (0x01):
+ phydev->speed = 100;
+ break;
+ case (0x02):
+ phydev->speed = 1000;
+ break;
+ }
+
+ phydev->duplex = (val & 0x1000) == 0x1000;
+
+ return 0;
+}
+
+/*
+ * Figure out if BCM5482 is in serdes or copper mode and determine link
+ * configuration accordingly
+ */
+static int bcm5482_startup(struct phy_device *phydev)
+{
+ if (bcm5482_is_serdes(phydev)) {
+ bcm5482_parse_serdes_sr(phydev);
+ phydev->port = PORT_FIBRE;
+ } else {
+ /* Wait for auto-negotiation to complete or fail */
+ genphy_update_link(phydev);
+ /* Parse BCM54xx copper aux status register */
+ bcm54xx_parse_status(phydev);
+ }
+
+ return 0;
+}
+
+static struct phy_driver BCM5461S_driver = {
+ .name = "Broadcom BCM5461S",
+ .uid = 0x2060c0,
+ .mask = 0xfffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &bcm5461_config,
+ .startup = &bcm54xx_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver BCM5464S_driver = {
+ .name = "Broadcom BCM5464S",
+ .uid = 0x2060b0,
+ .mask = 0xfffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &bcm5461_config,
+ .startup = &bcm54xx_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver BCM5482S_driver = {
+ .name = "Broadcom BCM5482S",
+ .uid = 0x143bcb0,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &bcm5482_config,
+ .startup = &bcm5482_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_broadcom_init(void)
+{
+ phy_register(&BCM5482S_driver);
+ phy_register(&BCM5464S_driver);
+ phy_register(&BCM5461S_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/davicom.c b/qemu/roms/u-boot/drivers/net/phy/davicom.c
new file mode 100644
index 000000000..0c039fe79
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/davicom.c
@@ -0,0 +1,84 @@
+/*
+ * Davicom PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ */
+#include <phy.h>
+
+#define MIIM_DM9161_SCR 0x10
+#define MIIM_DM9161_SCR_INIT 0x0610
+
+/* DM9161 Specified Configuration and Status Register */
+#define MIIM_DM9161_SCSR 0x11
+#define MIIM_DM9161_SCSR_100F 0x8000
+#define MIIM_DM9161_SCSR_100H 0x4000
+#define MIIM_DM9161_SCSR_10F 0x2000
+#define MIIM_DM9161_SCSR_10H 0x1000
+
+/* DM9161 10BT Configuration/Status */
+#define MIIM_DM9161_10BTCSR 0x12
+#define MIIM_DM9161_10BTCSR_INIT 0x7800
+
+
+/* Davicom DM9161E */
+static int dm9161_config(struct phy_device *phydev)
+{
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_ISOLATE);
+ /* Do not bypass the scrambler/descrambler */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_SCR,
+ MIIM_DM9161_SCR_INIT);
+ /* Clear 10BTCSR to default */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_10BTCSR,
+ MIIM_DM9161_10BTCSR_INIT);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static int dm9161_parse_status(struct phy_device *phydev)
+{
+ int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_SCSR);
+
+ if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
+ phydev->speed = SPEED_100;
+ else
+ phydev->speed = SPEED_10;
+
+ if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ return 0;
+}
+
+static int dm9161_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ dm9161_parse_status(phydev);
+
+ return 0;
+}
+
+static struct phy_driver DM9161_driver = {
+ .name = "Davicom DM9161E",
+ .uid = 0x181b880,
+ .mask = 0xffffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &dm9161_config,
+ .startup = &dm9161_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_davicom_init(void)
+{
+ phy_register(&DM9161_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/et1011c.c b/qemu/roms/u-boot/drivers/net/phy/et1011c.c
new file mode 100644
index 000000000..70c15e2f2
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/et1011c.c
@@ -0,0 +1,101 @@
+/*
+ * ET1011C PHY driver
+ *
+ * Derived from Linux kernel driver by Chaithrika U S
+ * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <config.h>
+#include <phy.h>
+
+#define ET1011C_CONFIG_REG (0x16)
+#define ET1011C_TX_FIFO_MASK (0x3 << 12)
+#define ET1011C_TX_FIFO_DEPTH_8 (0x0 << 12)
+#define ET1011C_TX_FIFO_DEPTH_16 (0x1 << 12)
+#define ET1011C_INTERFACE_MASK (0x7 << 0)
+#define ET1011C_GMII_INTERFACE (0x2 << 0)
+#define ET1011C_SYS_CLK_EN (0x1 << 4)
+#define ET1011C_TX_CLK_EN (0x1 << 5)
+
+#define ET1011C_STATUS_REG (0x1A)
+#define ET1011C_DUPLEX_STATUS (0x1 << 7)
+#define ET1011C_SPEED_MASK (0x3 << 8)
+#define ET1011C_SPEED_1000 (0x2 << 8)
+#define ET1011C_SPEED_100 (0x1 << 8)
+#define ET1011C_SPEED_10 (0x0 << 8)
+
+static int et1011c_config(struct phy_device *phydev)
+{
+ int ctl = 0;
+ ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+ if (ctl < 0)
+ return ctl;
+ ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
+ BMCR_ANENABLE);
+ /* First clear the PHY */
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl | BMCR_RESET);
+
+ return genphy_config_aneg(phydev);
+}
+
+static int et1011c_parse_status(struct phy_device *phydev)
+{
+ int mii_reg;
+ int speed;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_STATUS_REG);
+
+ if (mii_reg & ET1011C_DUPLEX_STATUS)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ speed = mii_reg & ET1011C_SPEED_MASK;
+ switch (speed) {
+ case ET1011C_SPEED_1000:
+ phydev->speed = SPEED_1000;
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG);
+ mii_reg &= ~ET1011C_TX_FIFO_MASK;
+ phy_write(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG,
+ mii_reg |
+ ET1011C_GMII_INTERFACE |
+ ET1011C_SYS_CLK_EN |
+#ifdef CONFIG_PHY_ET1011C_TX_CLK_FIX
+ ET1011C_TX_CLK_EN |
+#endif
+ ET1011C_TX_FIFO_DEPTH_16);
+ break;
+ case ET1011C_SPEED_100:
+ phydev->speed = SPEED_100;
+ break;
+ case ET1011C_SPEED_10:
+ phydev->speed = SPEED_10;
+ break;
+ }
+
+ return 0;
+}
+
+static int et1011c_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ et1011c_parse_status(phydev);
+ return 0;
+}
+
+static struct phy_driver et1011c_driver = {
+ .name = "ET1011C",
+ .uid = 0x0282f014,
+ .mask = 0xfffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &et1011c_config,
+ .startup = &et1011c_startup,
+};
+
+int phy_et1011c_init(void)
+{
+ phy_register(&et1011c_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/generic_10g.c b/qemu/roms/u-boot/drivers/net/phy/generic_10g.c
new file mode 100644
index 000000000..ed3dcd91d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/generic_10g.c
@@ -0,0 +1,94 @@
+/*
+ * Generic PHY Management code
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ *
+ * Based loosely off of Linux's PHY Lib
+ */
+
+#include <config.h>
+#include <common.h>
+#include <miiphy.h>
+#include <phy.h>
+
+int gen10g_shutdown(struct phy_device *phydev)
+{
+ return 0;
+}
+
+int gen10g_startup(struct phy_device *phydev)
+{
+ int devad, reg;
+ u32 mmd_mask = phydev->mmds & MDIO_DEVS_LINK;
+
+ phydev->link = 1;
+
+ /* For now just lie and say it's 10G all the time */
+ phydev->speed = SPEED_10000;
+ phydev->duplex = DUPLEX_FULL;
+
+ /*
+ * Go through all the link-reporting devices, and make sure
+ * they're all up and happy
+ */
+ for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) {
+ if (!(mmd_mask & 1))
+ continue;
+
+ /* Read twice because link state is latched and a
+ * read moves the current state into the register */
+ phy_read(phydev, devad, MDIO_STAT1);
+ reg = phy_read(phydev, devad, MDIO_STAT1);
+ if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
+ phydev->link = 0;
+ }
+
+ return 0;
+}
+
+int gen10g_discover_mmds(struct phy_device *phydev)
+{
+ int mmd, stat2, devs1, devs2;
+
+ /* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY
+ * XS or DTE XS; give up if none is present. */
+ for (mmd = 1; mmd <= 5; mmd++) {
+ /* Is this MMD present? */
+ stat2 = phy_read(phydev, mmd, MDIO_STAT2);
+ if (stat2 < 0 ||
+ (stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL)
+ continue;
+
+ /* It should tell us about all the other MMDs */
+ devs1 = phy_read(phydev, mmd, MDIO_DEVS1);
+ devs2 = phy_read(phydev, mmd, MDIO_DEVS2);
+ if (devs1 < 0 || devs2 < 0)
+ continue;
+
+ phydev->mmds = devs1 | (devs2 << 16);
+ return 0;
+ }
+
+ return 0;
+}
+
+int gen10g_config(struct phy_device *phydev)
+{
+ /* For now, assume 10000baseT. Fill in later */
+ phydev->supported = phydev->advertising = SUPPORTED_10000baseT_Full;
+
+ return gen10g_discover_mmds(phydev);
+}
+
+struct phy_driver gen10g_driver = {
+ .uid = 0xffffffff,
+ .mask = 0xffffffff,
+ .name = "Generic 10G PHY",
+ .features = 0,
+ .config = gen10g_config,
+ .startup = gen10g_startup,
+ .shutdown = gen10g_shutdown,
+};
diff --git a/qemu/roms/u-boot/drivers/net/phy/icplus.c b/qemu/roms/u-boot/drivers/net/phy/icplus.c
new file mode 100644
index 000000000..597195580
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/icplus.c
@@ -0,0 +1,80 @@
+/*
+ * ICPlus PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ */
+#include <phy.h>
+
+/* IP101A/G - IP1001 */
+#define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */
+#define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */
+#define IP1001_PHASE_SEL_MASK 3 /* IP1001 RX/TXPHASE_SEL */
+#define IP1001_APS_ON 11 /* IP1001 APS Mode bit */
+#define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */
+#define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */
+#define IP101A_G_IRQ_PIN_USED (1<<15) /* INTR pin used */
+#define IP101A_G_IRQ_DEFAULT IP101A_G_IRQ_PIN_USED
+
+static int ip1001_config(struct phy_device *phydev)
+{
+ int c;
+
+ /* Enable Auto Power Saving mode */
+ c = phy_read(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2);
+ if (c < 0)
+ return c;
+ c |= IP1001_APS_ON;
+ c = phy_write(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2, c);
+ if (c < 0)
+ return c;
+
+ /* INTR pin used: speed/link/duplex will cause an interrupt */
+ c = phy_write(phydev, MDIO_DEVAD_NONE, IP101A_G_IRQ_CONF_STATUS,
+ IP101A_G_IRQ_DEFAULT);
+ if (c < 0)
+ return c;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+ /*
+ * Additional delay (2ns) used to adjust RX clock phase
+ * at RGMII interface
+ */
+ c = phy_read(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS);
+ if (c < 0)
+ return c;
+
+ c |= IP1001_PHASE_SEL_MASK;
+ c = phy_write(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS,
+ c);
+ if (c < 0)
+ return c;
+ }
+
+ return 0;
+}
+
+static int ip1001_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ genphy_parse_link(phydev);
+
+ return 0;
+}
+static struct phy_driver IP1001_driver = {
+ .name = "ICPlus IP1001",
+ .uid = 0x02430d90,
+ .mask = 0x0ffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &ip1001_config,
+ .startup = &ip1001_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_icplus_init(void)
+{
+ phy_register(&IP1001_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/lxt.c b/qemu/roms/u-boot/drivers/net/phy/lxt.c
new file mode 100644
index 000000000..91838ce5e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/lxt.c
@@ -0,0 +1,73 @@
+/*
+ * LXT PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ */
+#include <phy.h>
+
+/* LXT971 Status 2 registers */
+#define MIIM_LXT971_SR2 0x11 /* Status Register 2 */
+#define MIIM_LXT971_SR2_SPEED_MASK 0x4200
+#define MIIM_LXT971_SR2_10HDX 0x0000 /* 10 Mbit half duplex selected */
+#define MIIM_LXT971_SR2_10FDX 0x0200 /* 10 Mbit full duplex selected */
+#define MIIM_LXT971_SR2_100HDX 0x4000 /* 100 Mbit half duplex selected */
+#define MIIM_LXT971_SR2_100FDX 0x4200 /* 100 Mbit full duplex selected */
+
+
+/* LXT971 */
+static int lxt971_parse_status(struct phy_device *phydev)
+{
+ int mii_reg;
+ int speed;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_LXT971_SR2);
+ speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK;
+
+ switch (speed) {
+ case MIIM_LXT971_SR2_10HDX:
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+ break;
+ case MIIM_LXT971_SR2_10FDX:
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_FULL;
+ break;
+ case MIIM_LXT971_SR2_100HDX:
+ phydev->speed = SPEED_100;
+ phydev->duplex = DUPLEX_HALF;
+ break;
+ default:
+ phydev->speed = SPEED_100;
+ phydev->duplex = DUPLEX_FULL;
+ }
+
+ return 0;
+}
+
+static int lxt971_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ lxt971_parse_status(phydev);
+
+ return 0;
+}
+
+static struct phy_driver LXT971_driver = {
+ .name = "LXT971",
+ .uid = 0x1378e0,
+ .mask = 0xfffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &lxt971_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_lxt_init(void)
+{
+ phy_register(&LXT971_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/marvell.c b/qemu/roms/u-boot/drivers/net/phy/marvell.c
new file mode 100644
index 000000000..d2ecadc89
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/marvell.c
@@ -0,0 +1,524 @@
+/*
+ * Marvell PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ */
+#include <config.h>
+#include <common.h>
+#include <phy.h>
+
+#define PHY_AUTONEGOTIATE_TIMEOUT 5000
+
+/* 88E1011 PHY Status Register */
+#define MIIM_88E1xxx_PHY_STATUS 0x11
+#define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000
+#define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000
+#define MIIM_88E1xxx_PHYSTAT_100 0x4000
+#define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000
+#define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800
+#define MIIM_88E1xxx_PHYSTAT_LINK 0x0400
+
+#define MIIM_88E1xxx_PHY_SCR 0x10
+#define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060
+
+/* 88E1111 PHY LED Control Register */
+#define MIIM_88E1111_PHY_LED_CONTROL 24
+#define MIIM_88E1111_PHY_LED_DIRECT 0x4100
+#define MIIM_88E1111_PHY_LED_COMBINE 0x411C
+
+/* 88E1111 Extended PHY Specific Control Register */
+#define MIIM_88E1111_PHY_EXT_CR 0x14
+#define MIIM_88E1111_RX_DELAY 0x80
+#define MIIM_88E1111_TX_DELAY 0x2
+
+/* 88E1111 Extended PHY Specific Status Register */
+#define MIIM_88E1111_PHY_EXT_SR 0x1b
+#define MIIM_88E1111_HWCFG_MODE_MASK 0xf
+#define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb
+#define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3
+#define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4
+#define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9
+#define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000
+#define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000
+
+#define MIIM_88E1111_COPPER 0
+#define MIIM_88E1111_FIBER 1
+
+/* 88E1118 PHY defines */
+#define MIIM_88E1118_PHY_PAGE 22
+#define MIIM_88E1118_PHY_LED_PAGE 3
+
+/* 88E1121 PHY LED Control Register */
+#define MIIM_88E1121_PHY_LED_CTRL 16
+#define MIIM_88E1121_PHY_LED_PAGE 3
+#define MIIM_88E1121_PHY_LED_DEF 0x0030
+
+/* 88E1121 PHY IRQ Enable/Status Register */
+#define MIIM_88E1121_PHY_IRQ_EN 18
+#define MIIM_88E1121_PHY_IRQ_STATUS 19
+
+#define MIIM_88E1121_PHY_PAGE 22
+
+/* 88E1145 Extended PHY Specific Control Register */
+#define MIIM_88E1145_PHY_EXT_CR 20
+#define MIIM_M88E1145_RGMII_RX_DELAY 0x0080
+#define MIIM_M88E1145_RGMII_TX_DELAY 0x0002
+
+#define MIIM_88E1145_PHY_LED_CONTROL 24
+#define MIIM_88E1145_PHY_LED_DIRECT 0x4100
+
+#define MIIM_88E1145_PHY_PAGE 29
+#define MIIM_88E1145_PHY_CAL_OV 30
+
+#define MIIM_88E1149_PHY_PAGE 29
+
+/* 88E1310 PHY defines */
+#define MIIM_88E1310_PHY_LED_CTRL 16
+#define MIIM_88E1310_PHY_IRQ_EN 18
+#define MIIM_88E1310_PHY_RGMII_CTRL 21
+#define MIIM_88E1310_PHY_PAGE 22
+
+/* Marvell 88E1011S */
+static int m88e1011s_config(struct phy_device *phydev)
+{
+ /* Reset and configure the PHY */
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+/* Parse the 88E1011's status register for speed and duplex
+ * information
+ */
+static uint m88e1xxx_parse_status(struct phy_device *phydev)
+{
+ unsigned int speed;
+ unsigned int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS);
+
+ if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) &&
+ !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
+ int i = 0;
+
+ puts("Waiting for PHY realtime link");
+ while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
+ /* Timeout reached ? */
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts(" TIMEOUT !\n");
+ phydev->link = 0;
+ break;
+ }
+
+ if ((i++ % 1000) == 0)
+ putc('.');
+ udelay(1000);
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
+ MIIM_88E1xxx_PHY_STATUS);
+ }
+ puts(" done\n");
+ udelay(500000); /* another 500 ms (results in faster booting) */
+ } else {
+ if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK)
+ phydev->link = 1;
+ else
+ phydev->link = 0;
+ }
+
+ if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED;
+
+ switch (speed) {
+ case MIIM_88E1xxx_PHYSTAT_GBIT:
+ phydev->speed = SPEED_1000;
+ break;
+ case MIIM_88E1xxx_PHYSTAT_100:
+ phydev->speed = SPEED_100;
+ break;
+ default:
+ phydev->speed = SPEED_10;
+ break;
+ }
+
+ return 0;
+}
+
+static int m88e1011s_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ m88e1xxx_parse_status(phydev);
+
+ return 0;
+}
+
+/* Marvell 88E1111S */
+static int m88e1111s_config(struct phy_device *phydev)
+{
+ int reg;
+ int timeout;
+
+ if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
+ reg = phy_read(phydev,
+ MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR);
+ if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) {
+ reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
+ } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+ reg &= ~MIIM_88E1111_TX_DELAY;
+ reg |= MIIM_88E1111_RX_DELAY;
+ } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+ reg &= ~MIIM_88E1111_RX_DELAY;
+ reg |= MIIM_88E1111_TX_DELAY;
+ }
+
+ phy_write(phydev,
+ MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg);
+
+ reg = phy_read(phydev,
+ MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR);
+
+ reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
+
+ if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES)
+ reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII;
+ else
+ reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII;
+
+ phy_write(phydev,
+ MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg);
+ }
+
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ reg = phy_read(phydev,
+ MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR);
+
+ reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
+ reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK;
+ reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
+
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_88E1111_PHY_EXT_SR, reg);
+ }
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
+ reg = phy_read(phydev,
+ MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR);
+ reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
+ phy_write(phydev,
+ MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg);
+
+ reg = phy_read(phydev, MDIO_DEVAD_NONE,
+ MIIM_88E1111_PHY_EXT_SR);
+ reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
+ MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
+ reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_88E1111_PHY_EXT_SR, reg);
+
+ /* soft reset */
+ timeout = 1000;
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+ udelay(1000);
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+ while ((reg & BMCR_RESET) && --timeout) {
+ udelay(1000);
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+ }
+ if (!timeout)
+ printf("%s: phy soft reset timeout\n", __func__);
+
+ reg = phy_read(phydev, MDIO_DEVAD_NONE,
+ MIIM_88E1111_PHY_EXT_SR);
+ reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
+ MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
+ reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI |
+ MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_88E1111_PHY_EXT_SR, reg);
+ }
+
+ /* soft reset */
+ timeout = 1000;
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+ udelay(1000);
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+ while ((reg & BMCR_RESET) && --timeout) {
+ udelay(1000);
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+ }
+ if (!timeout)
+ printf("%s: phy soft reset timeout\n", __func__);
+
+ genphy_config_aneg(phydev);
+
+ phy_reset(phydev);
+
+ return 0;
+}
+
+/* Marvell 88E1118 */
+static int m88e1118_config(struct phy_device *phydev)
+{
+ /* Change Page Number */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002);
+ /* Delay RGMII TX and RX */
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070);
+ /* Change Page Number */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003);
+ /* Adjust LED control */
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e);
+ /* Change Page Number */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
+
+ genphy_config_aneg(phydev);
+
+ phy_reset(phydev);
+
+ return 0;
+}
+
+static int m88e1118_startup(struct phy_device *phydev)
+{
+ /* Change Page Number */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
+
+ genphy_update_link(phydev);
+ m88e1xxx_parse_status(phydev);
+
+ return 0;
+}
+
+/* Marvell 88E1121R */
+static int m88e1121_config(struct phy_device *phydev)
+{
+ int pg;
+
+ /* Configure the PHY */
+ genphy_config_aneg(phydev);
+
+ /* Switch the page to access the led register */
+ pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE,
+ MIIM_88E1121_PHY_LED_PAGE);
+ /* Configure leds */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL,
+ MIIM_88E1121_PHY_LED_DEF);
+ /* Restore the page pointer */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg);
+
+ /* Disable IRQs and de-assert interrupt */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0);
+ phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS);
+
+ return 0;
+}
+
+/* Marvell 88E1145 */
+static int m88e1145_config(struct phy_device *phydev)
+{
+ int reg;
+
+ /* Errata E0, E1 */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR,
+ MIIM_88E1xxx_PHY_MDI_X_AUTO);
+
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR);
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ reg |= MIIM_M88E1145_RGMII_RX_DELAY |
+ MIIM_M88E1145_RGMII_TX_DELAY;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg);
+
+ genphy_config_aneg(phydev);
+
+ phy_reset(phydev);
+
+ return 0;
+}
+
+static int m88e1145_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL,
+ MIIM_88E1145_PHY_LED_DIRECT);
+ m88e1xxx_parse_status(phydev);
+
+ return 0;
+}
+
+/* Marvell 88E1149S */
+static int m88e1149_config(struct phy_device *phydev)
+{
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0);
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
+
+ genphy_config_aneg(phydev);
+
+ phy_reset(phydev);
+
+ return 0;
+}
+
+/* Marvell 88E1310 */
+static int m88e1310_config(struct phy_device *phydev)
+{
+ u16 reg;
+
+ /* LED link and activity */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL);
+ reg = (reg & ~0xf) | 0x1;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg);
+
+ /* Set LED2/INT to INT mode, low active */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN);
+ reg = (reg & 0x77ff) | 0x0880;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg);
+
+ /* Set RGMII delay */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002);
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL);
+ reg |= 0x0030;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg);
+
+ /* Ensure to return to page 0 */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000);
+
+ genphy_config_aneg(phydev);
+ phy_reset(phydev);
+
+ return 0;
+}
+
+static struct phy_driver M88E1011S_driver = {
+ .name = "Marvell 88E1011S",
+ .uid = 0x1410c60,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1011s_config,
+ .startup = &m88e1011s_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1111S_driver = {
+ .name = "Marvell 88E1111S",
+ .uid = 0x1410cc0,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1111s_config,
+ .startup = &m88e1011s_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1118_driver = {
+ .name = "Marvell 88E1118",
+ .uid = 0x1410e10,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1118_config,
+ .startup = &m88e1118_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1118R_driver = {
+ .name = "Marvell 88E1118R",
+ .uid = 0x1410e40,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1118_config,
+ .startup = &m88e1118_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1121R_driver = {
+ .name = "Marvell 88E1121R",
+ .uid = 0x1410cb0,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1121_config,
+ .startup = &genphy_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1145_driver = {
+ .name = "Marvell 88E1145",
+ .uid = 0x1410cd0,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1145_config,
+ .startup = &m88e1145_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1149S_driver = {
+ .name = "Marvell 88E1149S",
+ .uid = 0x1410ca0,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1149_config,
+ .startup = &m88e1011s_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1518_driver = {
+ .name = "Marvell 88E1518",
+ .uid = 0x1410dd1,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1111s_config,
+ .startup = &m88e1011s_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1310_driver = {
+ .name = "Marvell 88E1310",
+ .uid = 0x01410e90,
+ .mask = 0xffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &m88e1310_config,
+ .startup = &m88e1011s_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_marvell_init(void)
+{
+ phy_register(&M88E1310_driver);
+ phy_register(&M88E1149S_driver);
+ phy_register(&M88E1145_driver);
+ phy_register(&M88E1121R_driver);
+ phy_register(&M88E1118_driver);
+ phy_register(&M88E1118R_driver);
+ phy_register(&M88E1111S_driver);
+ phy_register(&M88E1011S_driver);
+ phy_register(&M88E1518_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/micrel.c b/qemu/roms/u-boot/drivers/net/phy/micrel.c
new file mode 100644
index 000000000..5d7e3be52
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/micrel.c
@@ -0,0 +1,226 @@
+/*
+ * Micrel PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ * (C) 2012 NetModule AG, David Andrey, added KSZ9031
+ */
+#include <config.h>
+#include <common.h>
+#include <micrel.h>
+#include <phy.h>
+
+static struct phy_driver KSZ804_driver = {
+ .name = "Micrel KSZ804",
+ .uid = 0x221510,
+ .mask = 0xfffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &genphy_config,
+ .startup = &genphy_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+#ifndef CONFIG_PHY_MICREL_KSZ9021
+/*
+ * I can't believe Micrel used the exact same part number
+ * for the KSZ9021
+ * Shame Micrel, Shame!!!!!
+ */
+static struct phy_driver KS8721_driver = {
+ .name = "Micrel KS8721BL",
+ .uid = 0x221610,
+ .mask = 0xfffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &genphy_config,
+ .startup = &genphy_startup,
+ .shutdown = &genphy_shutdown,
+};
+#endif
+
+
+/**
+ * KSZ9021 - KSZ9031 common
+ */
+
+#define MII_KSZ90xx_PHY_CTL 0x1f
+#define MIIM_KSZ90xx_PHYCTL_1000 (1 << 6)
+#define MIIM_KSZ90xx_PHYCTL_100 (1 << 5)
+#define MIIM_KSZ90xx_PHYCTL_10 (1 << 4)
+#define MIIM_KSZ90xx_PHYCTL_DUPLEX (1 << 3)
+
+static int ksz90xx_startup(struct phy_device *phydev)
+{
+ unsigned phy_ctl;
+ genphy_update_link(phydev);
+ phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL);
+
+ if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000)
+ phydev->speed = SPEED_1000;
+ else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100)
+ phydev->speed = SPEED_100;
+ else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10)
+ phydev->speed = SPEED_10;
+ return 0;
+}
+#ifdef CONFIG_PHY_MICREL_KSZ9021
+
+/*
+ * KSZ9021
+ */
+
+/* PHY Registers */
+#define MII_KSZ9021_EXTENDED_CTRL 0x0b
+#define MII_KSZ9021_EXTENDED_DATAW 0x0c
+#define MII_KSZ9021_EXTENDED_DATAR 0x0d
+
+#define CTRL1000_PREFER_MASTER (1 << 10)
+#define CTRL1000_CONFIG_MASTER (1 << 11)
+#define CTRL1000_MANUAL_CONFIG (1 << 12)
+
+int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val)
+{
+ /* extended registers */
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9021_EXTENDED_CTRL, regnum | 0x8000);
+ return phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9021_EXTENDED_DATAW, val);
+}
+
+int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum)
+{
+ /* extended registers */
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_CTRL, regnum);
+ return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAR);
+}
+
+
+static int ksz9021_phy_extread(struct phy_device *phydev, int addr, int devaddr,
+ int regnum)
+{
+ return ksz9021_phy_extended_read(phydev, regnum);
+}
+
+static int ksz9021_phy_extwrite(struct phy_device *phydev, int addr,
+ int devaddr, int regnum, u16 val)
+{
+ return ksz9021_phy_extended_write(phydev, regnum, val);
+}
+
+/* Micrel ksz9021 */
+static int ksz9021_config(struct phy_device *phydev)
+{
+ unsigned ctrl1000 = 0;
+ const unsigned master = CTRL1000_PREFER_MASTER |
+ CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG;
+ unsigned features = phydev->drv->features;
+
+ if (getenv("disable_giga"))
+ features &= ~(SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full);
+ /* force master mode for 1000BaseT due to chip errata */
+ if (features & SUPPORTED_1000baseT_Half)
+ ctrl1000 |= ADVERTISE_1000HALF | master;
+ if (features & SUPPORTED_1000baseT_Full)
+ ctrl1000 |= ADVERTISE_1000FULL | master;
+ phydev->advertising = phydev->supported = features;
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, ctrl1000);
+ genphy_config_aneg(phydev);
+ genphy_restart_aneg(phydev);
+ return 0;
+}
+
+static struct phy_driver ksz9021_driver = {
+ .name = "Micrel ksz9021",
+ .uid = 0x221610,
+ .mask = 0xfffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &ksz9021_config,
+ .startup = &ksz90xx_startup,
+ .shutdown = &genphy_shutdown,
+ .writeext = &ksz9021_phy_extwrite,
+ .readext = &ksz9021_phy_extread,
+};
+#endif
+
+/**
+ * KSZ9031
+ */
+/* PHY Registers */
+#define MII_KSZ9031_MMD_ACCES_CTRL 0x0d
+#define MII_KSZ9031_MMD_REG_DATA 0x0e
+
+/* Accessors to extended registers*/
+int ksz9031_phy_extended_write(struct phy_device *phydev,
+ int devaddr, int regnum, u16 mode, u16 val)
+{
+ /*select register addr for mmd*/
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
+ /*select register for mmd*/
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9031_MMD_REG_DATA, regnum);
+ /*setup mode*/
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr));
+ /*write the value*/
+ return phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9031_MMD_REG_DATA, val);
+}
+
+int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
+ int regnum, u16 mode)
+{
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9031_MMD_REG_DATA, regnum);
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode));
+ return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA);
+}
+
+static int ksz9031_phy_extread(struct phy_device *phydev, int addr, int devaddr,
+ int regnum)
+{
+ return ksz9031_phy_extended_read(phydev, devaddr, regnum,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC);
+};
+
+static int ksz9031_phy_extwrite(struct phy_device *phydev, int addr,
+ int devaddr, int regnum, u16 val)
+{
+ return ksz9031_phy_extended_write(phydev, devaddr, regnum,
+ MII_KSZ9031_MOD_DATA_POST_INC_RW, val);
+};
+
+
+static struct phy_driver ksz9031_driver = {
+ .name = "Micrel ksz9031",
+ .uid = 0x221620,
+ .mask = 0xfffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &genphy_config,
+ .startup = &ksz90xx_startup,
+ .shutdown = &genphy_shutdown,
+ .writeext = &ksz9031_phy_extwrite,
+ .readext = &ksz9031_phy_extread,
+};
+
+int phy_micrel_init(void)
+{
+ phy_register(&KSZ804_driver);
+#ifdef CONFIG_PHY_MICREL_KSZ9021
+ phy_register(&ksz9021_driver);
+#else
+ phy_register(&KS8721_driver);
+#endif
+ phy_register(&ksz9031_driver);
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/miiphybb.c b/qemu/roms/u-boot/drivers/net/phy/miiphybb.c
new file mode 100644
index 000000000..5cda0b846
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/miiphybb.c
@@ -0,0 +1,364 @@
+/*
+ * (C) Copyright 2009 Industrie Dial Face S.p.A.
+ * Luigi 'Comio' Mantellini <luigi.mantellini@idf-hit.com>
+ *
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * This provides a bit-banged interface to the ethernet MII management
+ * channel.
+ */
+
+#include <common.h>
+#include <ioports.h>
+#include <ppc_asm.tmpl>
+#include <miiphy.h>
+
+#define BB_MII_RELOCATE(v,off) (v += (v?off:0))
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_BITBANGMII_MULTI
+
+/*
+ * If CONFIG_BITBANGMII_MULTI is not defined we use a
+ * compatibility layer with the previous miiphybb implementation
+ * based on macros usage.
+ *
+ */
+static int bb_mii_init_wrap(struct bb_miiphy_bus *bus)
+{
+#ifdef MII_INIT
+ MII_INIT;
+#endif
+ return 0;
+}
+
+static int bb_mdio_active_wrap(struct bb_miiphy_bus *bus)
+{
+#ifdef MDIO_DECLARE
+ MDIO_DECLARE;
+#endif
+ MDIO_ACTIVE;
+ return 0;
+}
+
+static int bb_mdio_tristate_wrap(struct bb_miiphy_bus *bus)
+{
+#ifdef MDIO_DECLARE
+ MDIO_DECLARE;
+#endif
+ MDIO_TRISTATE;
+ return 0;
+}
+
+static int bb_set_mdio_wrap(struct bb_miiphy_bus *bus, int v)
+{
+#ifdef MDIO_DECLARE
+ MDIO_DECLARE;
+#endif
+ MDIO(v);
+ return 0;
+}
+
+static int bb_get_mdio_wrap(struct bb_miiphy_bus *bus, int *v)
+{
+#ifdef MDIO_DECLARE
+ MDIO_DECLARE;
+#endif
+ *v = MDIO_READ;
+ return 0;
+}
+
+static int bb_set_mdc_wrap(struct bb_miiphy_bus *bus, int v)
+{
+#ifdef MDC_DECLARE
+ MDC_DECLARE;
+#endif
+ MDC(v);
+ return 0;
+}
+
+static int bb_delay_wrap(struct bb_miiphy_bus *bus)
+{
+ MIIDELAY;
+ return 0;
+}
+
+struct bb_miiphy_bus bb_miiphy_buses[] = {
+ {
+ .name = BB_MII_DEVNAME,
+ .init = bb_mii_init_wrap,
+ .mdio_active = bb_mdio_active_wrap,
+ .mdio_tristate = bb_mdio_tristate_wrap,
+ .set_mdio = bb_set_mdio_wrap,
+ .get_mdio = bb_get_mdio_wrap,
+ .set_mdc = bb_set_mdc_wrap,
+ .delay = bb_delay_wrap,
+ }
+};
+
+int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /
+ sizeof(bb_miiphy_buses[0]);
+#endif
+
+void bb_miiphy_init(void)
+{
+ int i;
+
+ for (i = 0; i < bb_miiphy_buses_num; i++) {
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ /* Relocate the hook pointers*/
+ BB_MII_RELOCATE(bb_miiphy_buses[i].init, gd->reloc_off);
+ BB_MII_RELOCATE(bb_miiphy_buses[i].mdio_active, gd->reloc_off);
+ BB_MII_RELOCATE(bb_miiphy_buses[i].mdio_tristate, gd->reloc_off);
+ BB_MII_RELOCATE(bb_miiphy_buses[i].set_mdio, gd->reloc_off);
+ BB_MII_RELOCATE(bb_miiphy_buses[i].get_mdio, gd->reloc_off);
+ BB_MII_RELOCATE(bb_miiphy_buses[i].set_mdc, gd->reloc_off);
+ BB_MII_RELOCATE(bb_miiphy_buses[i].delay, gd->reloc_off);
+#endif
+ if (bb_miiphy_buses[i].init != NULL) {
+ bb_miiphy_buses[i].init(&bb_miiphy_buses[i]);
+ }
+ }
+}
+
+static inline struct bb_miiphy_bus *bb_miiphy_getbus(const char *devname)
+{
+#ifdef CONFIG_BITBANGMII_MULTI
+ int i;
+
+ /* Search the correct bus */
+ for (i = 0; i < bb_miiphy_buses_num; i++) {
+ if (!strcmp(bb_miiphy_buses[i].name, devname)) {
+ return &bb_miiphy_buses[i];
+ }
+ }
+ return NULL;
+#else
+ /* We have just one bitbanging bus */
+ return &bb_miiphy_buses[0];
+#endif
+}
+
+/*****************************************************************************
+ *
+ * Utility to send the preamble, address, and register (common to read
+ * and write).
+ */
+static void miiphy_pre(struct bb_miiphy_bus *bus, char read,
+ unsigned char addr, unsigned char reg)
+{
+ int j;
+
+ /*
+ * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
+ * The IEEE spec says this is a PHY optional requirement. The AMD
+ * 79C874 requires one after power up and one after a MII communications
+ * error. This means that we are doing more preambles than we need,
+ * but it is safer and will be much more robust.
+ */
+
+ bus->mdio_active(bus);
+ bus->set_mdio(bus, 1);
+ for (j = 0; j < 32; j++) {
+ bus->set_mdc(bus, 0);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ }
+
+ /* send the start bit (01) and the read opcode (10) or write (10) */
+ bus->set_mdc(bus, 0);
+ bus->set_mdio(bus, 0);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ bus->set_mdc(bus, 0);
+ bus->set_mdio(bus, 1);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ bus->set_mdc(bus, 0);
+ bus->set_mdio(bus, read);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ bus->set_mdc(bus, 0);
+ bus->set_mdio(bus, !read);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+
+ /* send the PHY address */
+ for (j = 0; j < 5; j++) {
+ bus->set_mdc(bus, 0);
+ if ((addr & 0x10) == 0) {
+ bus->set_mdio(bus, 0);
+ } else {
+ bus->set_mdio(bus, 1);
+ }
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ addr <<= 1;
+ }
+
+ /* send the register address */
+ for (j = 0; j < 5; j++) {
+ bus->set_mdc(bus, 0);
+ if ((reg & 0x10) == 0) {
+ bus->set_mdio(bus, 0);
+ } else {
+ bus->set_mdio(bus, 1);
+ }
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ reg <<= 1;
+ }
+}
+
+/*****************************************************************************
+ *
+ * Read a MII PHY register.
+ *
+ * Returns:
+ * 0 on success
+ */
+int bb_miiphy_read(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ short rdreg; /* register working value */
+ int v;
+ int j; /* counter */
+ struct bb_miiphy_bus *bus;
+
+ bus = bb_miiphy_getbus(devname);
+ if (bus == NULL) {
+ return -1;
+ }
+
+ if (value == NULL) {
+ puts("NULL value pointer\n");
+ return -1;
+ }
+
+ miiphy_pre (bus, 1, addr, reg);
+
+ /* tri-state our MDIO I/O pin so we can read */
+ bus->set_mdc(bus, 0);
+ bus->mdio_tristate(bus);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+
+ /* check the turnaround bit: the PHY should be driving it to zero */
+ bus->get_mdio(bus, &v);
+ if (v != 0) {
+ /* puts ("PHY didn't drive TA low\n"); */
+ for (j = 0; j < 32; j++) {
+ bus->set_mdc(bus, 0);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ }
+ /* There is no PHY, set value to 0xFFFF and return */
+ *value = 0xFFFF;
+ return -1;
+ }
+
+ bus->set_mdc(bus, 0);
+ bus->delay(bus);
+
+ /* read 16 bits of register data, MSB first */
+ rdreg = 0;
+ for (j = 0; j < 16; j++) {
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ rdreg <<= 1;
+ bus->get_mdio(bus, &v);
+ rdreg |= (v & 0x1);
+ bus->set_mdc(bus, 0);
+ bus->delay(bus);
+ }
+
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ bus->set_mdc(bus, 0);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+
+ *value = rdreg;
+
+#ifdef DEBUG
+ printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
+#endif
+
+ return 0;
+}
+
+
+/*****************************************************************************
+ *
+ * Write a MII PHY register.
+ *
+ * Returns:
+ * 0 on success
+ */
+int bb_miiphy_write (const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ struct bb_miiphy_bus *bus;
+ int j; /* counter */
+
+ bus = bb_miiphy_getbus(devname);
+ if (bus == NULL) {
+ /* Bus not found! */
+ return -1;
+ }
+
+ miiphy_pre (bus, 0, addr, reg);
+
+ /* send the turnaround (10) */
+ bus->set_mdc(bus, 0);
+ bus->set_mdio(bus, 1);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ bus->set_mdc(bus, 0);
+ bus->set_mdio(bus, 0);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+
+ /* write 16 bits of register data, MSB first */
+ for (j = 0; j < 16; j++) {
+ bus->set_mdc(bus, 0);
+ if ((value & 0x00008000) == 0) {
+ bus->set_mdio(bus, 0);
+ } else {
+ bus->set_mdio(bus, 1);
+ }
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+ value <<= 1;
+ }
+
+ /*
+ * Tri-state the MDIO line.
+ */
+ bus->mdio_tristate(bus);
+ bus->set_mdc(bus, 0);
+ bus->delay(bus);
+ bus->set_mdc(bus, 1);
+ bus->delay(bus);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/mv88e61xx.c b/qemu/roms/u-boot/drivers/net/phy/mv88e61xx.c
new file mode 100644
index 000000000..302abe86c
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/mv88e61xx.c
@@ -0,0 +1,537 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <netdev.h>
+#include "mv88e61xx.h"
+
+/*
+ * Uncomment either of the following line for local debug control;
+ * otherwise global debug control will apply.
+ */
+
+/* #undef DEBUG */
+/* #define DEBUG */
+
+#ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE
+/* Chip Address mode
+ * The Switch support two modes of operation
+ * 1. single chip mode and
+ * 2. Multi-chip mode
+ * Refer section 9.2 &9.3 in chip datasheet-02 for more details
+ *
+ * By default single chip mode is configured
+ * multichip mode operation can be configured in board header
+ */
+static int mv88e61xx_busychk_multic(char *name, u32 devaddr)
+{
+ u16 reg = 0;
+ u32 timeout = MV88E61XX_PHY_TIMEOUT;
+
+ /* Poll till SMIBusy bit is clear */
+ do {
+ miiphy_read(name, devaddr, 0x0, &reg);
+ if (timeout-- == 0) {
+ printf("SMI busy timeout\n");
+ return -1;
+ }
+ } while (reg & (1 << 15));
+ return 0;
+}
+
+static void mv88e61xx_switch_write(char *name, u32 phy_adr,
+ u32 reg_ofs, u16 data)
+{
+ u16 mii_dev_addr;
+
+ /* command to read PHY dev address */
+ if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
+ printf("Error..could not read PHY dev address\n");
+ return;
+ }
+ mv88e61xx_busychk_multic(name, mii_dev_addr);
+ /* Write data to Switch indirect data register */
+ miiphy_write(name, mii_dev_addr, 0x1, data);
+ /* Write command to Switch indirect command register (write) */
+ miiphy_write(name, mii_dev_addr, 0x0,
+ reg_ofs | (phy_adr << 5) | (1 << 10) | (1 << 12) | (1 <<
+ 15));
+}
+
+static void mv88e61xx_switch_read(char *name, u32 phy_adr,
+ u32 reg_ofs, u16 *data)
+{
+ u16 mii_dev_addr;
+
+ /* command to read PHY dev address */
+ if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
+ printf("Error..could not read PHY dev address\n");
+ return;
+ }
+ mv88e61xx_busychk_multic(name, mii_dev_addr);
+ /* Write command to Switch indirect command register (read) */
+ miiphy_write(name, mii_dev_addr, 0x0,
+ reg_ofs | (phy_adr << 5) | (1 << 11) | (1 << 12) | (1 <<
+ 15));
+ mv88e61xx_busychk_multic(name, mii_dev_addr);
+ /* Read data from Switch indirect data register */
+ miiphy_read(name, mii_dev_addr, 0x1, data);
+}
+#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
+
+/*
+ * Convenience macros for switch device/port reads/writes
+ * These macros output valid 'mv88e61xx' U_BOOT_CMDs
+ */
+
+#ifndef DEBUG
+#define WR_SWITCH_REG wr_switch_reg
+#define RD_SWITCH_REG rd_switch_reg
+#define WR_SWITCH_PORT_REG(n, p, r, d) \
+ WR_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d)
+#define RD_SWITCH_PORT_REG(n, p, r, d) \
+ RD_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d)
+#else
+static void WR_SWITCH_REG(char *name, u32 dev_adr, u32 reg_ofs, u16 data)
+{
+ printf("mv88e61xx %s dev %02x reg %02x write %04x\n",
+ name, dev_adr, reg_ofs, data);
+ wr_switch_reg(name, dev_adr, reg_ofs, data);
+}
+static void RD_SWITCH_REG(char *name, u32 dev_adr, u32 reg_ofs, u16 *data)
+{
+ rd_switch_reg(name, dev_adr, reg_ofs, data);
+ printf("mv88e61xx %s dev %02x reg %02x read %04x\n",
+ name, dev_adr, reg_ofs, *data);
+}
+static void WR_SWITCH_PORT_REG(char *name, u32 prt_adr, u32 reg_ofs,
+ u16 data)
+{
+ printf("mv88e61xx %s port %02x reg %02x write %04x\n",
+ name, prt_adr, reg_ofs, data);
+ wr_switch_reg(name, (MV88E61XX_PRT_OFST+prt_adr), reg_ofs, data);
+}
+static void RD_SWITCH_PORT_REG(char *name, u32 prt_adr, u32 reg_ofs,
+ u16 *data)
+{
+ rd_switch_reg(name, (MV88E61XX_PRT_OFST+prt_adr), reg_ofs, data);
+ printf("mv88e61xx %s port %02x reg %02x read %04x\n",
+ name, prt_adr, reg_ofs, *data);
+}
+#endif
+
+/*
+ * Local functions to read/write registers on the switch PHYs.
+ * NOTE! This goes through switch, not direct miiphy, writes and reads!
+ */
+
+/*
+ * Make sure SMIBusy bit cleared before another
+ * SMI operation can take place
+ */
+static int mv88e61xx_busychk(char *name)
+{
+ u16 reg = 0;
+ u32 timeout = MV88E61XX_PHY_TIMEOUT;
+ do {
+ rd_switch_reg(name, MV88E61XX_GLB2REG_DEVADR,
+ MV88E61XX_PHY_CMD, &reg);
+ if (timeout-- == 0) {
+ printf("SMI busy timeout\n");
+ return -1;
+ }
+ } while (reg & 1 << 15); /* busy mask */
+ return 0;
+}
+
+static inline int mv88e61xx_switch_miiphy_write(char *name, u32 phy,
+ u32 reg, u16 data)
+{
+ /* write switch data reg then cmd reg then check completion */
+ wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA,
+ data);
+ wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD,
+ (MV88E61XX_PHY_WRITE_CMD | (phy << 5) | reg));
+ return mv88e61xx_busychk(name);
+}
+
+static inline int mv88e61xx_switch_miiphy_read(char *name, u32 phy,
+ u32 reg, u16 *data)
+{
+ /* write switch cmd reg, check for completion */
+ wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD,
+ (MV88E61XX_PHY_READ_CMD | (phy << 5) | reg));
+ if (mv88e61xx_busychk(name))
+ return -1;
+ /* read switch data reg and return success */
+ rd_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, data);
+ return 0;
+}
+
+/*
+ * Convenience macros for switch PHY reads/writes
+ */
+
+#ifndef DEBUG
+#define WR_SWITCH_PHY_REG mv88e61xx_switch_miiphy_write
+#define RD_SWITCH_PHY_REG mv88e61xx_switch_miiphy_read
+#else
+static inline int WR_SWITCH_PHY_REG(char *name, u32 phy_adr,
+ u32 reg_ofs, u16 data)
+{
+ int r = mv88e61xx_switch_miiphy_write(name, phy_adr, reg_ofs, data);
+ if (r)
+ printf("** ERROR writing mv88e61xx %s phy %02x reg %02x\n",
+ name, phy_adr, reg_ofs);
+ else
+ printf("mv88e61xx %s phy %02x reg %02x write %04x\n",
+ name, phy_adr, reg_ofs, data);
+ return r;
+}
+static inline int RD_SWITCH_PHY_REG(char *name, u32 phy_adr,
+ u32 reg_ofs, u16 *data)
+{
+ int r = mv88e61xx_switch_miiphy_read(name, phy_adr, reg_ofs, data);
+ if (r)
+ printf("** ERROR reading mv88e61xx %s phy %02x reg %02x\n",
+ name, phy_adr, reg_ofs);
+ else
+ printf("mv88e61xx %s phy %02x reg %02x read %04x\n",
+ name, phy_adr, reg_ofs, *data);
+ return r;
+}
+#endif
+
+static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig)
+{
+ u32 prt;
+ u16 reg;
+ char *name = swconfig->name;
+ u32 port_mask = swconfig->ports_enabled;
+
+ /* apply internal vlan config */
+ for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) {
+ /* only for enabled ports */
+ if ((1 << prt) & port_mask) {
+ /* take vlan map from swconfig */
+ u8 vlanmap = swconfig->vlancfg[prt];
+ /* remove disabled ports from vlan map */
+ vlanmap &= swconfig->ports_enabled;
+ /* apply vlan map to port */
+ RD_SWITCH_PORT_REG(name, prt,
+ MV88E61XX_PRT_VMAP_REG, &reg);
+ reg &= ~((1 << MV88E61XX_MAX_PORTS_NUM) - 1);
+ reg |= vlanmap;
+ WR_SWITCH_PORT_REG(name, prt,
+ MV88E61XX_PRT_VMAP_REG, reg);
+ }
+ }
+}
+
+/*
+ * Power up the specified port and reset PHY
+ */
+static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 phy)
+{
+ char *name = swconfig->name;
+
+ /* Write Copper Specific control reg1 (0x10) for-
+ * Enable Phy power up
+ * Energy Detect on (sense&Xmit NLP Periodically
+ * reset other settings default
+ */
+ if (WR_SWITCH_PHY_REG(name, phy, 0x10, 0x3360))
+ return -1;
+
+ /* Write PHY ctrl reg (0x0) to apply
+ * Phy reset (set bit 15 low)
+ * reset other default values
+ */
+ if (WR_SWITCH_PHY_REG(name, phy, 0x00, 0x9140))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Default Setup for LED[0]_Control (ref: Table 46 Datasheet-3)
+ * is set to "On-1000Mb/s Link, Off Else"
+ * This function sets it to "On-Link, Blink-Activity, Off-NoLink"
+ *
+ * This is optional settings may be needed on some boards
+ * to setup PHY LEDs default configuration to detect 10/100/1000Mb/s
+ * Link status
+ */
+static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 phy)
+{
+ char *name = swconfig->name;
+
+ if (swconfig->led_init != MV88E61XX_LED_INIT_EN)
+ return 0;
+
+ /* set page address to 3 */
+ if (WR_SWITCH_PHY_REG(name, phy, 0x16, 0x0003))
+ return -1;
+
+ /*
+ * set LED Func Ctrl reg
+ * value 0x0001 = LED[0] On-Link, Blink-Activity, Off-NoLink
+ */
+ if (WR_SWITCH_PHY_REG(name, phy, 0x10, 0x0001))
+ return -1;
+
+ /* set page address to 0 */
+ if (WR_SWITCH_PHY_REG(name, phy, 0x16, 0x0000))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Reverse Transmit polarity for Media Dependent Interface
+ * Pins (MDIP) bits in Copper Specific Control Register 3
+ * (Page 0, Reg 20 for each phy (except cpu port)
+ * Reference: Section 1.1 Switch datasheet-3
+ *
+ * This is optional settings may be needed on some boards
+ * for PHY<->magnetics h/w tuning
+ */
+static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, u32 phy)
+{
+ char *name = swconfig->name;
+
+ if (swconfig->mdip != MV88E61XX_MDIP_REVERSE)
+ return 0;
+
+ /*Reverse MDIP/N[3:0] bits */
+ if (WR_SWITCH_PHY_REG(name, phy, 0x14, 0x000f))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Marvell 88E61XX Switch initialization
+ */
+int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig)
+{
+ u32 prt;
+ u16 reg;
+ char *idstr;
+ char *name = swconfig->name;
+ int time;
+
+ if (miiphy_set_current_dev(name)) {
+ printf("%s failed\n", __FUNCTION__);
+ return -1;
+ }
+
+ if (!(swconfig->cpuport & ((1 << 4) | (1 << 5)))) {
+ swconfig->cpuport = (1 << 5);
+ printf("Invalid cpu port config, using default port5\n");
+ }
+
+ RD_SWITCH_PORT_REG(name, 0, MII_PHYSID2, &reg);
+ switch (reg &= 0xfff0) {
+ case 0x1610:
+ idstr = "88E6161";
+ break;
+ case 0x1650:
+ idstr = "88E6165";
+ break;
+ case 0x1210:
+ idstr = "88E6123";
+ /* ports 2,3,4 not available */
+ swconfig->ports_enabled &= 0x023;
+ break;
+ default:
+ /* Could not detect switch id */
+ idstr = "88E61??";
+ break;
+ }
+
+ /* be sure all ports are disabled */
+ for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) {
+ RD_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, &reg);
+ reg &= ~0x3;
+ WR_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, reg);
+ }
+
+ /* wait 2 ms for queues to drain */
+ udelay(2000);
+
+ /* reset switch */
+ RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, &reg);
+ reg |= 0x8000;
+ WR_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, reg);
+
+ /* wait up to 1 second for switch reset complete */
+ for (time = 1000; time; time--) {
+ RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGSR,
+ &reg);
+ if ((reg & 0xc800) == 0xc800)
+ break;
+ udelay(1000);
+ }
+ if (!time)
+ return -1;
+
+ /* Port based VLANs configuration */
+ mv88e61xx_port_vlan_config(swconfig);
+
+ if (swconfig->rgmii_delay == MV88E61XX_RGMII_DELAY_EN) {
+ /*
+ * Enable RGMII delay on Tx and Rx for CPU port
+ * Ref: sec 9.5 of chip datasheet-02
+ */
+ /*Force port link down */
+ WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x10);
+ /* configure port RGMII delay */
+ WR_SWITCH_PORT_REG(name, 4,
+ MV88E61XX_RGMII_TIMECTRL_REG, 0x81e7);
+ RD_SWITCH_PORT_REG(name, 5,
+ MV88E61XX_RGMII_TIMECTRL_REG, &reg);
+ WR_SWITCH_PORT_REG(name, 5,
+ MV88E61XX_RGMII_TIMECTRL_REG, reg | 0x18);
+ WR_SWITCH_PORT_REG(name, 4,
+ MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7);
+ /* Force port to RGMII FDX 1000Base then up */
+ WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x1e);
+ WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x3e);
+ }
+
+ for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) {
+
+ /* configure port's PHY */
+ if (!((1 << prt) & swconfig->cpuport)) {
+ /* port 4 has phy 6, not 4 */
+ int phy = (prt == 4) ? 6 : prt;
+ if (mv88361xx_powerup(swconfig, phy))
+ return -1;
+ if (mv88361xx_reverse_mdipn(swconfig, phy))
+ return -1;
+ if (mv88361xx_led_init(swconfig, phy))
+ return -1;
+ }
+
+ /* set port VID to port+1 except for cpu port */
+ if (!((1 << prt) & swconfig->cpuport)) {
+ RD_SWITCH_PORT_REG(name, prt,
+ MV88E61XX_PRT_VID_REG, &reg);
+ WR_SWITCH_PORT_REG(name, prt,
+ MV88E61XX_PRT_VID_REG,
+ (reg & ~1023) | (prt+1));
+ }
+
+ /*Program port state */
+ RD_SWITCH_PORT_REG(name, prt,
+ MV88E61XX_PRT_CTRL_REG, &reg);
+ WR_SWITCH_PORT_REG(name, prt,
+ MV88E61XX_PRT_CTRL_REG,
+ reg | (swconfig->portstate & 0x03));
+
+ }
+
+ printf("%s Initialized on %s\n", idstr, name);
+ return 0;
+}
+
+#ifdef CONFIG_MV88E61XX_CMD
+static int
+do_switch(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *name, *endp;
+ int write = 0;
+ enum { dev, prt, phy } target = dev;
+ u32 addrlo, addrhi, addr;
+ u32 reglo, reghi, reg;
+ u16 data, rdata;
+
+ if (argc < 7)
+ return -1;
+
+ name = argv[1];
+
+ if (strcmp(argv[2], "phy") == 0)
+ target = phy;
+ else if (strcmp(argv[2], "port") == 0)
+ target = prt;
+ else if (strcmp(argv[2], "dev") != 0)
+ return 1;
+
+ addrlo = simple_strtoul(argv[3], &endp, 16);
+
+ if (!*endp) {
+ addrhi = addrlo;
+ } else {
+ while (*endp < '0' || *endp > '9')
+ endp++;
+ addrhi = simple_strtoul(endp, NULL, 16);
+ }
+
+ reglo = simple_strtoul(argv[5], &endp, 16);
+ if (!*endp) {
+ reghi = reglo;
+ } else {
+ while (*endp < '0' || *endp > '9')
+ endp++;
+ reghi = simple_strtoul(endp, NULL, 16);
+ }
+
+ if (strcmp(argv[6], "write") == 0)
+ write = 1;
+ else if (strcmp(argv[6], "read") != 0)
+ return 1;
+
+ data = simple_strtoul(argv[7], NULL, 16);
+
+ for (addr = addrlo; addr <= addrhi; addr++) {
+ for (reg = reglo; reg <= reghi; reg++) {
+ if (write) {
+ if (target == phy)
+ mv88e61xx_switch_miiphy_write(
+ name, addr, reg, data);
+ else if (target == prt)
+ wr_switch_reg(name,
+ addr+MV88E61XX_PRT_OFST,
+ reg, data);
+ else
+ wr_switch_reg(name, addr, reg, data);
+ } else {
+ if (target == phy)
+ mv88e61xx_switch_miiphy_read(
+ name, addr, reg, &rdata);
+ else if (target == prt)
+ rd_switch_reg(name,
+ addr+MV88E61XX_PRT_OFST,
+ reg, &rdata);
+ else
+ rd_switch_reg(name, addr, reg, &rdata);
+ printf("%s %s %s %02x %s %02x %s %04x\n",
+ argv[0], argv[1], argv[2], addr,
+ argv[4], reg, argv[6], rdata);
+ if (write && argc == 7 && rdata != data)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+U_BOOT_CMD(mv88e61xx, 8, 0, do_switch,
+ "Read or write mv88e61xx switch registers",
+ "<ethdevice> dev|port|phy <addr> reg <reg> write <data>\n"
+ "<ethdevice> dev|port|phy <addr> reg <reg> read [<data>]\n"
+ " - read/write switch device, port or phy at (addr,reg)\n"
+ " addr=0..0x1C for dev, 0..5 for port or phy.\n"
+ " reg=0..0x1F.\n"
+ " data=0..0xFFFF (tested if present against actual read).\n"
+ " All numeric parameters are assumed to be hex.\n"
+ " <addr> and <<reg> arguments can be ranges (x..y)"
+);
+#endif /* CONFIG_MV88E61XX_CMD */
diff --git a/qemu/roms/u-boot/drivers/net/phy/mv88e61xx.h b/qemu/roms/u-boot/drivers/net/phy/mv88e61xx.h
new file mode 100644
index 000000000..9c62e4a77
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/mv88e61xx.h
@@ -0,0 +1,61 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _MV88E61XX_H
+#define _MV88E61XX_H
+
+#include <miiphy.h>
+
+#define MV88E61XX_CPU_PORT 0x5
+
+#define MV88E61XX_PHY_TIMEOUT 100000
+
+/* port dev-addr (= port + 0x10) */
+#define MV88E61XX_PRT_OFST 0x10
+/* port registers */
+#define MV88E61XX_PCS_CTRL_REG 0x1
+#define MV88E61XX_PRT_CTRL_REG 0x4
+#define MV88E61XX_PRT_VMAP_REG 0x6
+#define MV88E61XX_PRT_VID_REG 0x7
+#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A
+
+/* global registers dev-addr */
+#define MV88E61XX_GLBREG_DEVADR 0x1B
+/* global registers */
+#define MV88E61XX_SGSR 0x00
+#define MV88E61XX_SGCR 0x04
+
+/* global 2 registers dev-addr */
+#define MV88E61XX_GLB2REG_DEVADR 0x1C
+/* global 2 registers */
+#define MV88E61XX_PHY_CMD 0x18
+#define MV88E61XX_PHY_DATA 0x19
+/* global 2 phy commands */
+#define MV88E61XX_PHY_WRITE_CMD 0x9400
+#define MV88E61XX_PHY_READ_CMD 0x9800
+
+#define MV88E61XX_BUSY_OFST 15
+#define MV88E61XX_MODE_OFST 12
+#define MV88E61XX_OP_OFST 10
+#define MV88E61XX_ADDR_OFST 5
+
+#ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE
+static int mv88e61xx_busychk_multic(char *name, u32 devaddr);
+static void mv88e61xx_switch_write(char *name, u32 phy_adr,
+ u32 reg_ofs, u16 data);
+static void mv88e61xx_switch_read(char *name, u32 phy_adr,
+ u32 reg_ofs, u16 *data);
+#define wr_switch_reg mv88e61xx_switch_write
+#define rd_switch_reg mv88e61xx_switch_read
+#else
+/* switch appears a s simple PHY and can thus use miiphy */
+#define wr_switch_reg miiphy_write
+#define rd_switch_reg miiphy_read
+#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
+
+#endif /* _MV88E61XX_H */
diff --git a/qemu/roms/u-boot/drivers/net/phy/mv88e6352.c b/qemu/roms/u-boot/drivers/net/phy/mv88e6352.c
new file mode 100644
index 000000000..f639a42fa
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/mv88e6352.c
@@ -0,0 +1,302 @@
+/*
+ * (C) Copyright 2012
+ * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <miiphy.h>
+#include <asm/errno.h>
+#include <mv88e6352.h>
+
+#define SMI_HDR ((0x8 | 0x1) << 12)
+#define SMI_BUSY_MASK (0x8000)
+#define SMIRD_OP (0x2 << 10)
+#define SMIWR_OP (0x1 << 10)
+#define SMI_MASK 0x1f
+#define PORT_SHIFT 5
+
+#define COMMAND_REG 0
+#define DATA_REG 1
+
+/* global registers */
+#define GLOBAL 0x1b
+
+#define GLOBAL_STATUS 0x00
+#define PPU_STATE 0x8000
+
+#define GLOBAL_CTRL 0x04
+#define SW_RESET 0x8000
+#define PPU_ENABLE 0x4000
+
+static int sw_wait_rdy(const char *devname, u8 phy_addr)
+{
+ u16 command;
+ u32 timeout = 100;
+ int ret;
+
+ /* wait till the SMI is not busy */
+ do {
+ /* read command register */
+ ret = miiphy_read(devname, phy_addr, COMMAND_REG, &command);
+ if (ret < 0) {
+ printf("%s: Error reading command register\n",
+ __func__);
+ return ret;
+ }
+ if (timeout-- == 0) {
+ printf("Err..(%s) SMI busy timeout\n", __func__);
+ return -EFAULT;
+ }
+ } while (command & SMI_BUSY_MASK);
+
+ return 0;
+}
+
+static int sw_reg_read(const char *devname, u8 phy_addr, u8 port,
+ u8 reg, u16 *data)
+{
+ int ret;
+ u16 command;
+
+ ret = sw_wait_rdy(devname, phy_addr);
+ if (ret)
+ return ret;
+
+ command = SMI_HDR | SMIRD_OP | ((port&SMI_MASK) << PORT_SHIFT) |
+ (reg & SMI_MASK);
+ debug("%s: write to command: %#x\n", __func__, command);
+ ret = miiphy_write(devname, phy_addr, COMMAND_REG, command);
+ if (ret)
+ return ret;
+
+ ret = sw_wait_rdy(devname, phy_addr);
+ if (ret)
+ return ret;
+
+ ret = miiphy_read(devname, phy_addr, DATA_REG, data);
+
+ return ret;
+}
+
+static int sw_reg_write(const char *devname, u8 phy_addr, u8 port,
+ u8 reg, u16 data)
+{
+ int ret;
+ u16 value;
+
+ ret = sw_wait_rdy(devname, phy_addr);
+ if (ret)
+ return ret;
+
+ debug("%s: write to data: %#x\n", __func__, data);
+ ret = miiphy_write(devname, phy_addr, DATA_REG, data);
+ if (ret)
+ return ret;
+
+ value = SMI_HDR | SMIWR_OP | ((port & SMI_MASK) << PORT_SHIFT) |
+ (reg & SMI_MASK);
+ debug("%s: write to command: %#x\n", __func__, value);
+ ret = miiphy_write(devname, phy_addr, COMMAND_REG, value);
+ if (ret)
+ return ret;
+
+ ret = sw_wait_rdy(devname, phy_addr);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ppu_enable(const char *devname, u8 phy_addr)
+{
+ int i, ret = 0;
+ u16 reg;
+
+ ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
+ if (ret) {
+ printf("%s: Error reading global ctrl reg\n", __func__);
+ return ret;
+ }
+
+ reg |= PPU_ENABLE;
+
+ ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
+ if (ret) {
+ printf("%s: Error writing global ctrl reg\n", __func__);
+ return ret;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
+ &reg);
+ if ((reg & 0xc000) == 0xc000)
+ return 0;
+ udelay(1000);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int ppu_disable(const char *devname, u8 phy_addr)
+{
+ int i, ret = 0;
+ u16 reg;
+
+ ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
+ if (ret) {
+ printf("%s: Error reading global ctrl reg\n", __func__);
+ return ret;
+ }
+
+ reg &= ~PPU_ENABLE;
+
+ ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
+ if (ret) {
+ printf("%s: Error writing global ctrl reg\n", __func__);
+ return ret;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
+ &reg);
+ if ((reg & 0xc000) != 0xc000)
+ return 0;
+ udelay(1000);
+ }
+
+ return -ETIMEDOUT;
+}
+
+int mv88e_sw_program(const char *devname, u8 phy_addr,
+ struct mv88e_sw_reg *regs, int regs_nb)
+{
+ int i, ret = 0;
+
+ /* first we need to disable the PPU */
+ ret = ppu_disable(devname, phy_addr);
+ if (ret) {
+ printf("%s: Error disabling PPU\n", __func__);
+ return ret;
+ }
+
+ for (i = 0; i < regs_nb; i++) {
+ ret = sw_reg_write(devname, phy_addr, regs[i].port,
+ regs[i].reg, regs[i].value);
+ if (ret) {
+ printf("%s: Error configuring switch\n", __func__);
+ ppu_enable(devname, phy_addr);
+ return ret;
+ }
+ }
+
+ /* re-enable the PPU */
+ ret = ppu_enable(devname, phy_addr);
+ if (ret) {
+ printf("%s: Error enabling PPU\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+int mv88e_sw_reset(const char *devname, u8 phy_addr)
+{
+ int i, ret = 0;
+ u16 reg;
+
+ ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
+ if (ret) {
+ printf("%s: Error reading global ctrl reg\n", __func__);
+ return ret;
+ }
+
+ reg = SW_RESET | PPU_ENABLE | 0x0400;
+
+ ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
+ if (ret) {
+ printf("%s: Error writing global ctrl reg\n", __func__);
+ return ret;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
+ &reg);
+ if ((reg & 0xc800) != 0xc800)
+ return 0;
+ udelay(1000);
+ }
+
+ return -ETIMEDOUT;
+}
+
+int do_mvsw_reg_read(const char *name, int argc, char * const argv[])
+{
+ u16 value = 0, phyaddr, reg, port;
+ int ret;
+
+ phyaddr = simple_strtoul(argv[1], NULL, 10);
+ port = simple_strtoul(argv[2], NULL, 10);
+ reg = simple_strtoul(argv[3], NULL, 10);
+
+ ret = sw_reg_read(name, phyaddr, port, reg, &value);
+ printf("%#x\n", value);
+
+ return ret;
+}
+
+int do_mvsw_reg_write(const char *name, int argc, char * const argv[])
+{
+ u16 value = 0, phyaddr, reg, port;
+ int ret;
+
+ phyaddr = simple_strtoul(argv[1], NULL, 10);
+ port = simple_strtoul(argv[2], NULL, 10);
+ reg = simple_strtoul(argv[3], NULL, 10);
+ value = simple_strtoul(argv[4], NULL, 16);
+
+ ret = sw_reg_write(name, phyaddr, port, reg, value);
+
+ return ret;
+}
+
+
+int do_mvsw_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int ret;
+ const char *cmd, *ethname;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ cmd = argv[1];
+ --argc;
+ ++argv;
+
+ if (strcmp(cmd, "read") == 0) {
+ if (argc < 5)
+ return cmd_usage(cmdtp);
+ ethname = argv[1];
+ --argc;
+ ++argv;
+ ret = do_mvsw_reg_read(ethname, argc, argv);
+ } else if (strcmp(cmd, "write") == 0) {
+ if (argc < 6)
+ return cmd_usage(cmdtp);
+ ethname = argv[1];
+ --argc;
+ ++argv;
+ ret = do_mvsw_reg_write(ethname, argc, argv);
+ } else
+ return cmd_usage(cmdtp);
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ mvsw_reg, 7, 1, do_mvsw_reg,
+ "marvell 88e6352 switch register access",
+ "write ethname phyaddr port reg value\n"
+ "mvsw_reg read ethname phyaddr port reg\n"
+ );
diff --git a/qemu/roms/u-boot/drivers/net/phy/natsemi.c b/qemu/roms/u-boot/drivers/net/phy/natsemi.c
new file mode 100644
index 000000000..ea9fe833e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/natsemi.c
@@ -0,0 +1,119 @@
+/*
+ * National Semiconductor PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ */
+#include <phy.h>
+
+/* NatSemi DP83630 */
+
+#define DP83630_PHY_PAGESEL_REG 0x13
+#define DP83630_PHY_PTP_COC_REG 0x14
+#define DP83630_PHY_PTP_CLKOUT_EN (1<<15)
+#define DP83630_PHY_RBR_REG 0x17
+
+static int dp83630_config(struct phy_device *phydev)
+{
+ int ptp_coc_reg;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+ phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0x6);
+ ptp_coc_reg = phy_read(phydev, MDIO_DEVAD_NONE,
+ DP83630_PHY_PTP_COC_REG);
+ ptp_coc_reg &= ~DP83630_PHY_PTP_CLKOUT_EN;
+ phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PTP_COC_REG,
+ ptp_coc_reg);
+ phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static struct phy_driver DP83630_driver = {
+ .name = "NatSemi DP83630",
+ .uid = 0x20005ce1,
+ .mask = 0xfffffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &dp83630_config,
+ .startup = &genphy_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+
+/* DP83865 Link and Auto-Neg Status Register */
+#define MIIM_DP83865_LANR 0x11
+#define MIIM_DP83865_SPD_MASK 0x0018
+#define MIIM_DP83865_SPD_1000 0x0010
+#define MIIM_DP83865_SPD_100 0x0008
+#define MIIM_DP83865_DPX_FULL 0x0002
+
+
+/* NatSemi DP83865 */
+static int dp83865_config(struct phy_device *phydev)
+{
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static int dp83865_parse_status(struct phy_device *phydev)
+{
+ int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_DP83865_LANR);
+
+ switch (mii_reg & MIIM_DP83865_SPD_MASK) {
+
+ case MIIM_DP83865_SPD_1000:
+ phydev->speed = SPEED_1000;
+ break;
+
+ case MIIM_DP83865_SPD_100:
+ phydev->speed = SPEED_100;
+ break;
+
+ default:
+ phydev->speed = SPEED_10;
+ break;
+
+ }
+
+ if (mii_reg & MIIM_DP83865_DPX_FULL)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ return 0;
+}
+
+static int dp83865_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ dp83865_parse_status(phydev);
+
+ return 0;
+}
+
+
+static struct phy_driver DP83865_driver = {
+ .name = "NatSemi DP83865",
+ .uid = 0x20005c70,
+ .mask = 0xfffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &dp83865_config,
+ .startup = &dp83865_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_natsemi_init(void)
+{
+ phy_register(&DP83630_driver);
+ phy_register(&DP83865_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/phy.c b/qemu/roms/u-boot/drivers/net/phy/phy.c
new file mode 100644
index 000000000..230ed97dd
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/phy.c
@@ -0,0 +1,817 @@
+/*
+ * Generic PHY Management code
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ *
+ * Based loosely off of Linux's PHY Lib
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <command.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <errno.h>
+#include <linux/err.h>
+#include <linux/compiler.h>
+
+/* Generic PHY support and helper functions */
+
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotation parameters
+ * @phydev: target phy_device struct
+ *
+ * Description: Writes MII_ADVERTISE with the appropriate values,
+ * after sanitizing the values to make sure we only advertise
+ * what is supported. Returns < 0 on error, 0 if the PHY's advertisement
+ * hasn't changed, and > 0 if it has changed.
+ */
+static int genphy_config_advert(struct phy_device *phydev)
+{
+ u32 advertise;
+ int oldadv, adv;
+ int err, changed = 0;
+
+ /* Only allow advertising what
+ * this PHY supports */
+ phydev->advertising &= phydev->supported;
+ advertise = phydev->advertising;
+
+ /* Setup standard advertisement */
+ oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+
+ if (adv < 0)
+ return adv;
+
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+ if (advertise & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ if (advertise & ADVERTISED_Pause)
+ adv |= ADVERTISE_PAUSE_CAP;
+ if (advertise & ADVERTISED_Asym_Pause)
+ adv |= ADVERTISE_PAUSE_ASYM;
+ if (advertise & ADVERTISED_1000baseX_Half)
+ adv |= ADVERTISE_1000XHALF;
+ if (advertise & ADVERTISED_1000baseX_Full)
+ adv |= ADVERTISE_1000XFULL;
+
+ if (adv != oldadv) {
+ err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv);
+
+ if (err < 0)
+ return err;
+ changed = 1;
+ }
+
+ /* Configure gigabit if it's supported */
+ if (phydev->supported & (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full)) {
+ oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+
+ if (adv < 0)
+ return adv;
+
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ if (advertise & SUPPORTED_1000baseT_Half)
+ adv |= ADVERTISE_1000HALF;
+ if (advertise & SUPPORTED_1000baseT_Full)
+ adv |= ADVERTISE_1000FULL;
+
+ if (adv != oldadv) {
+ err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
+ adv);
+
+ if (err < 0)
+ return err;
+ changed = 1;
+ }
+ }
+
+ return changed;
+}
+
+
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Configures MII_BMCR to force speed/duplex
+ * to the values in phydev. Assumes that the values are valid.
+ */
+static int genphy_setup_forced(struct phy_device *phydev)
+{
+ int err;
+ int ctl = 0;
+
+ phydev->pause = phydev->asym_pause = 0;
+
+ if (SPEED_1000 == phydev->speed)
+ ctl |= BMCR_SPEED1000;
+ else if (SPEED_100 == phydev->speed)
+ ctl |= BMCR_SPEED100;
+
+ if (DUPLEX_FULL == phydev->duplex)
+ ctl |= BMCR_FULLDPLX;
+
+ err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
+
+ return err;
+}
+
+
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
+int genphy_restart_aneg(struct phy_device *phydev)
+{
+ int ctl;
+
+ ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+ if (ctl < 0)
+ return ctl;
+
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+ /* Don't isolate the PHY if we're negotiating */
+ ctl &= ~(BMCR_ISOLATE);
+
+ ctl = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
+
+ return ctl;
+}
+
+
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
+ *
+ * Description: If auto-negotiation is enabled, we configure the
+ * advertising, and then restart auto-negotiation. If it is not
+ * enabled, then we write the BMCR.
+ */
+int genphy_config_aneg(struct phy_device *phydev)
+{
+ int result;
+
+ if (AUTONEG_ENABLE != phydev->autoneg)
+ return genphy_setup_forced(phydev);
+
+ result = genphy_config_advert(phydev);
+
+ if (result < 0) /* error */
+ return result;
+
+ if (result == 0) {
+ /* Advertisment hasn't changed, but maybe aneg was never on to
+ * begin with? Or maybe phy was isolated? */
+ int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+ if (ctl < 0)
+ return ctl;
+
+ if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
+ result = 1; /* do restart aneg */
+ }
+
+ /* Only restart aneg if we are advertising something different
+ * than we were before. */
+ if (result > 0)
+ result = genphy_restart_aneg(phydev);
+
+ return result;
+}
+
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Update the value in phydev->link to reflect the
+ * current link value. In order to do this, we need to read
+ * the status register twice, keeping the second value.
+ */
+int genphy_update_link(struct phy_device *phydev)
+{
+ unsigned int mii_reg;
+
+ /*
+ * Wait if the link is up, and autonegotiation is in progress
+ * (ie - we're capable and it's not done)
+ */
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+ /*
+ * If we already saw the link up, and it hasn't gone down, then
+ * we don't need to wait for autoneg again
+ */
+ if (phydev->link && mii_reg & BMSR_LSTATUS)
+ return 0;
+
+ if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+ int i = 0;
+
+ printf("%s Waiting for PHY auto negotiation to complete",
+ phydev->dev->name);
+ while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
+ /*
+ * Timeout reached ?
+ */
+ if (i > PHY_ANEG_TIMEOUT) {
+ printf(" TIMEOUT !\n");
+ phydev->link = 0;
+ return 0;
+ }
+
+ if (ctrlc()) {
+ puts("user interrupt!\n");
+ phydev->link = 0;
+ return -EINTR;
+ }
+
+ if ((i++ % 500) == 0)
+ printf(".");
+
+ udelay(1000); /* 1 ms */
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ }
+ printf(" done\n");
+ phydev->link = 1;
+ } else {
+ /* Read the link a second time to clear the latched state */
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+ if (mii_reg & BMSR_LSTATUS)
+ phydev->link = 1;
+ else
+ phydev->link = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Generic function which updates the speed and duplex. If
+ * autonegotiation is enabled, it uses the AND of the link
+ * partner's advertised capabilities and our advertised
+ * capabilities. If autonegotiation is disabled, we use the
+ * appropriate bits in the control register.
+ *
+ * Stolen from Linux's mii.c and phy_device.c
+ */
+int genphy_parse_link(struct phy_device *phydev)
+{
+ int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+ /* We're using autonegotiation */
+ if (phydev->supported & SUPPORTED_Autoneg) {
+ u32 lpa = 0;
+ int gblpa = 0;
+ u32 estatus = 0;
+
+ /* Check for gigabit capability */
+ if (phydev->supported & (SUPPORTED_1000baseT_Full |
+ SUPPORTED_1000baseT_Half)) {
+ /* We want a list of states supported by
+ * both PHYs in the link
+ */
+ gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
+ if (gblpa < 0) {
+ debug("Could not read MII_STAT1000. Ignoring gigabit capability\n");
+ gblpa = 0;
+ }
+ gblpa &= phy_read(phydev,
+ MDIO_DEVAD_NONE, MII_CTRL1000) << 2;
+ }
+
+ /* Set the baseline so we only have to set them
+ * if they're different
+ */
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+
+ /* Check the gigabit fields */
+ if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
+ phydev->speed = SPEED_1000;
+
+ if (gblpa & PHY_1000BTSR_1000FD)
+ phydev->duplex = DUPLEX_FULL;
+
+ /* We're done! */
+ return 0;
+ }
+
+ lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
+
+ if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ phydev->speed = SPEED_100;
+
+ if (lpa & LPA_100FULL)
+ phydev->duplex = DUPLEX_FULL;
+
+ } else if (lpa & LPA_10FULL)
+ phydev->duplex = DUPLEX_FULL;
+
+ /*
+ * Extended status may indicate that the PHY supports
+ * 1000BASE-T/X even though the 1000BASE-T registers
+ * are missing. In this case we can't tell whether the
+ * peer also supports it, so we only check extended
+ * status if the 1000BASE-T registers are actually
+ * missing.
+ */
+ if ((mii_reg & BMSR_ESTATEN) && !(mii_reg & BMSR_ERCAP))
+ estatus = phy_read(phydev, MDIO_DEVAD_NONE,
+ MII_ESTATUS);
+
+ if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF |
+ ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
+ phydev->speed = SPEED_1000;
+ if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_TFULL))
+ phydev->duplex = DUPLEX_FULL;
+ }
+
+ } else {
+ u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+
+ if (bmcr & BMCR_FULLDPLX)
+ phydev->duplex = DUPLEX_FULL;
+
+ if (bmcr & BMCR_SPEED1000)
+ phydev->speed = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ phydev->speed = SPEED_100;
+ }
+
+ return 0;
+}
+
+int genphy_config(struct phy_device *phydev)
+{
+ int val;
+ u32 features;
+
+ /* For now, I'll claim that the generic driver supports
+ * all possible port types */
+ features = (SUPPORTED_TP | SUPPORTED_MII
+ | SUPPORTED_AUI | SUPPORTED_FIBRE |
+ SUPPORTED_BNC);
+
+ /* Do we support autonegotiation? */
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+ if (val < 0)
+ return val;
+
+ if (val & BMSR_ANEGCAPABLE)
+ features |= SUPPORTED_Autoneg;
+
+ if (val & BMSR_100FULL)
+ features |= SUPPORTED_100baseT_Full;
+ if (val & BMSR_100HALF)
+ features |= SUPPORTED_100baseT_Half;
+ if (val & BMSR_10FULL)
+ features |= SUPPORTED_10baseT_Full;
+ if (val & BMSR_10HALF)
+ features |= SUPPORTED_10baseT_Half;
+
+ if (val & BMSR_ESTATEN) {
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS);
+
+ if (val < 0)
+ return val;
+
+ if (val & ESTATUS_1000_TFULL)
+ features |= SUPPORTED_1000baseT_Full;
+ if (val & ESTATUS_1000_THALF)
+ features |= SUPPORTED_1000baseT_Half;
+ if (val & ESTATUS_1000_XFULL)
+ features |= SUPPORTED_1000baseX_Full;
+ if (val & ESTATUS_1000_XHALF)
+ features |= SUPPORTED_1000baseX_Half;
+ }
+
+ phydev->supported = features;
+ phydev->advertising = features;
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+int genphy_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ genphy_parse_link(phydev);
+
+ return 0;
+}
+
+int genphy_shutdown(struct phy_device *phydev)
+{
+ return 0;
+}
+
+static struct phy_driver genphy_driver = {
+ .uid = 0xffffffff,
+ .mask = 0xffffffff,
+ .name = "Generic PHY",
+ .features = 0,
+ .config = genphy_config,
+ .startup = genphy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+static LIST_HEAD(phy_drivers);
+
+int phy_init(void)
+{
+#ifdef CONFIG_PHY_ATHEROS
+ phy_atheros_init();
+#endif
+#ifdef CONFIG_PHY_BROADCOM
+ phy_broadcom_init();
+#endif
+#ifdef CONFIG_PHY_DAVICOM
+ phy_davicom_init();
+#endif
+#ifdef CONFIG_PHY_ET1011C
+ phy_et1011c_init();
+#endif
+#ifdef CONFIG_PHY_ICPLUS
+ phy_icplus_init();
+#endif
+#ifdef CONFIG_PHY_LXT
+ phy_lxt_init();
+#endif
+#ifdef CONFIG_PHY_MARVELL
+ phy_marvell_init();
+#endif
+#ifdef CONFIG_PHY_MICREL
+ phy_micrel_init();
+#endif
+#ifdef CONFIG_PHY_NATSEMI
+ phy_natsemi_init();
+#endif
+#ifdef CONFIG_PHY_REALTEK
+ phy_realtek_init();
+#endif
+#ifdef CONFIG_PHY_SMSC
+ phy_smsc_init();
+#endif
+#ifdef CONFIG_PHY_TERANETICS
+ phy_teranetics_init();
+#endif
+#ifdef CONFIG_PHY_VITESSE
+ phy_vitesse_init();
+#endif
+
+ return 0;
+}
+
+int phy_register(struct phy_driver *drv)
+{
+ INIT_LIST_HEAD(&drv->list);
+ list_add_tail(&drv->list, &phy_drivers);
+
+ return 0;
+}
+
+static int phy_probe(struct phy_device *phydev)
+{
+ int err = 0;
+
+ phydev->advertising = phydev->supported = phydev->drv->features;
+ phydev->mmds = phydev->drv->mmds;
+
+ if (phydev->drv->probe)
+ err = phydev->drv->probe(phydev);
+
+ return err;
+}
+
+static struct phy_driver *generic_for_interface(phy_interface_t interface)
+{
+#ifdef CONFIG_PHYLIB_10G
+ if (is_10g_interface(interface))
+ return &gen10g_driver;
+#endif
+
+ return &genphy_driver;
+}
+
+static struct phy_driver *get_phy_driver(struct phy_device *phydev,
+ phy_interface_t interface)
+{
+ struct list_head *entry;
+ int phy_id = phydev->phy_id;
+ struct phy_driver *drv = NULL;
+
+ list_for_each(entry, &phy_drivers) {
+ drv = list_entry(entry, struct phy_driver, list);
+ if ((drv->uid & drv->mask) == (phy_id & drv->mask))
+ return drv;
+ }
+
+ /* If we made it here, there's no driver for this PHY */
+ return generic_for_interface(interface);
+}
+
+static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
+ int phy_id,
+ phy_interface_t interface)
+{
+ struct phy_device *dev;
+
+ /* We allocate the device, and initialize the
+ * default values */
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ printf("Failed to allocate PHY device for %s:%d\n",
+ bus->name, addr);
+ return NULL;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+
+ dev->duplex = -1;
+ dev->link = 1;
+ dev->interface = interface;
+
+ dev->autoneg = AUTONEG_ENABLE;
+
+ dev->addr = addr;
+ dev->phy_id = phy_id;
+ dev->bus = bus;
+
+ dev->drv = get_phy_driver(dev, interface);
+
+ phy_probe(dev);
+
+ bus->phymap[addr] = dev;
+
+ return dev;
+}
+
+/**
+ * get_phy_id - reads the specified addr for its ID.
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ * @phy_id: where to store the ID retrieved.
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, stores it in @phy_id and returns zero on success.
+ */
+int __weak get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
+{
+ int phy_reg;
+
+ /* Grab the bits from PHYIR1, and put them
+ * in the upper half */
+ phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id = (phy_reg & 0xffff) << 16;
+
+ /* Grab the bits from PHYIR2, and put them in the lower half */
+ phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id |= (phy_reg & 0xffff);
+
+ return 0;
+}
+
+static struct phy_device *create_phy_by_mask(struct mii_dev *bus,
+ unsigned phy_mask, int devad, phy_interface_t interface)
+{
+ u32 phy_id = 0xffffffff;
+ while (phy_mask) {
+ int addr = ffs(phy_mask) - 1;
+ int r = get_phy_id(bus, addr, devad, &phy_id);
+ if (r < 0)
+ return ERR_PTR(r);
+ /* If the PHY ID is mostly f's, we didn't find anything */
+ if ((phy_id & 0x1fffffff) != 0x1fffffff)
+ return phy_device_create(bus, addr, phy_id, interface);
+ phy_mask &= ~(1 << addr);
+ }
+ return NULL;
+}
+
+static struct phy_device *search_for_existing_phy(struct mii_dev *bus,
+ unsigned phy_mask, phy_interface_t interface)
+{
+ /* If we have one, return the existing device, with new interface */
+ while (phy_mask) {
+ int addr = ffs(phy_mask) - 1;
+ if (bus->phymap[addr]) {
+ bus->phymap[addr]->interface = interface;
+ return bus->phymap[addr];
+ }
+ phy_mask &= ~(1 << addr);
+ }
+ return NULL;
+}
+
+static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus,
+ unsigned phy_mask, phy_interface_t interface)
+{
+ int i;
+ struct phy_device *phydev;
+
+ phydev = search_for_existing_phy(bus, phy_mask, interface);
+ if (phydev)
+ return phydev;
+ /* Try Standard (ie Clause 22) access */
+ /* Otherwise we have to try Clause 45 */
+ for (i = 0; i < 5; i++) {
+ phydev = create_phy_by_mask(bus, phy_mask,
+ i ? i : MDIO_DEVAD_NONE, interface);
+ if (IS_ERR(phydev))
+ return NULL;
+ if (phydev)
+ return phydev;
+ }
+ printf("Phy not found\n");
+ return phy_device_create(bus, ffs(phy_mask) - 1, 0xffffffff, interface);
+}
+
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, then allocates and returns the phy_device to represent it.
+ */
+static struct phy_device *get_phy_device(struct mii_dev *bus, int addr,
+ phy_interface_t interface)
+{
+ return get_phy_device_by_mask(bus, 1 << addr, interface);
+}
+
+int phy_reset(struct phy_device *phydev)
+{
+ int reg;
+ int timeout = 500;
+ int devad = MDIO_DEVAD_NONE;
+
+#ifdef CONFIG_PHYLIB_10G
+ /* If it's 10G, we need to issue reset through one of the MMDs */
+ if (is_10g_interface(phydev->interface)) {
+ if (!phydev->mmds)
+ gen10g_discover_mmds(phydev);
+
+ devad = ffs(phydev->mmds) - 1;
+ }
+#endif
+
+ reg = phy_read(phydev, devad, MII_BMCR);
+ if (reg < 0) {
+ debug("PHY status read failed\n");
+ return -1;
+ }
+
+ reg |= BMCR_RESET;
+
+ if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
+ debug("PHY reset failed\n");
+ return -1;
+ }
+
+#ifdef CONFIG_PHY_RESET_DELAY
+ udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
+#endif
+ /*
+ * Poll the control register for the reset bit to go to 0 (it is
+ * auto-clearing). This should happen within 0.5 seconds per the
+ * IEEE spec.
+ */
+ while ((reg & BMCR_RESET) && timeout--) {
+ reg = phy_read(phydev, devad, MII_BMCR);
+
+ if (reg < 0) {
+ debug("PHY status read failed\n");
+ return -1;
+ }
+ udelay(1000);
+ }
+
+ if (reg & BMCR_RESET) {
+ puts("PHY reset timed out\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int miiphy_reset(const char *devname, unsigned char addr)
+{
+ struct mii_dev *bus = miiphy_get_dev_by_name(devname);
+ struct phy_device *phydev;
+
+ /*
+ * miiphy_reset was only used on standard PHYs, so we'll fake it here.
+ * If later code tries to connect with the right interface, this will
+ * be corrected by get_phy_device in phy_connect()
+ */
+ phydev = get_phy_device(bus, addr, PHY_INTERFACE_MODE_MII);
+
+ return phy_reset(phydev);
+}
+
+struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask,
+ phy_interface_t interface)
+{
+ /* Reset the bus */
+ if (bus->reset)
+ bus->reset(bus);
+
+ /* Wait 15ms to make sure the PHY has come out of hard reset */
+ udelay(15000);
+ return get_phy_device_by_mask(bus, phy_mask, interface);
+}
+
+void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
+{
+ /* Soft Reset the PHY */
+ phy_reset(phydev);
+ if (phydev->dev) {
+ printf("%s:%d is connected to %s. Reconnecting to %s\n",
+ phydev->bus->name, phydev->addr,
+ phydev->dev->name, dev->name);
+ }
+ phydev->dev = dev;
+ debug("%s connected to %s\n", dev->name, phydev->drv->name);
+}
+
+struct phy_device *phy_connect(struct mii_dev *bus, int addr,
+ struct eth_device *dev, phy_interface_t interface)
+{
+ struct phy_device *phydev;
+
+ phydev = phy_find_by_mask(bus, 1 << addr, interface);
+ if (phydev)
+ phy_connect_dev(phydev, dev);
+ else
+ printf("Could not get PHY for %s: addr %d\n", bus->name, addr);
+ return phydev;
+}
+
+/*
+ * Start the PHY. Returns 0 on success, or a negative error code.
+ */
+int phy_startup(struct phy_device *phydev)
+{
+ if (phydev->drv->startup)
+ return phydev->drv->startup(phydev);
+
+ return 0;
+}
+
+static int __board_phy_config(struct phy_device *phydev)
+{
+ if (phydev->drv->config)
+ return phydev->drv->config(phydev);
+ return 0;
+}
+
+int board_phy_config(struct phy_device *phydev)
+ __attribute__((weak, alias("__board_phy_config")));
+
+int phy_config(struct phy_device *phydev)
+{
+ /* Invoke an optional board-specific helper */
+ board_phy_config(phydev);
+
+ return 0;
+}
+
+int phy_shutdown(struct phy_device *phydev)
+{
+ if (phydev->drv->shutdown)
+ phydev->drv->shutdown(phydev);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/realtek.c b/qemu/roms/u-boot/drivers/net/phy/realtek.c
new file mode 100644
index 000000000..a3ace6852
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/realtek.c
@@ -0,0 +1,141 @@
+/*
+ * RealTek PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ */
+#include <config.h>
+#include <common.h>
+#include <phy.h>
+
+#define PHY_AUTONEGOTIATE_TIMEOUT 5000
+
+/* RTL8211x PHY Status Register */
+#define MIIM_RTL8211x_PHY_STATUS 0x11
+#define MIIM_RTL8211x_PHYSTAT_SPEED 0xc000
+#define MIIM_RTL8211x_PHYSTAT_GBIT 0x8000
+#define MIIM_RTL8211x_PHYSTAT_100 0x4000
+#define MIIM_RTL8211x_PHYSTAT_DUPLEX 0x2000
+#define MIIM_RTL8211x_PHYSTAT_SPDDONE 0x0800
+#define MIIM_RTL8211x_PHYSTAT_LINK 0x0400
+
+
+/* RealTek RTL8211x */
+static int rtl8211x_config(struct phy_device *phydev)
+{
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static int rtl8211x_parse_status(struct phy_device *phydev)
+{
+ unsigned int speed;
+ unsigned int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
+
+ if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
+ int i = 0;
+
+ /* in case of timeout ->link is cleared */
+ phydev->link = 1;
+ puts("Waiting for PHY realtime link");
+ while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
+ /* Timeout reached ? */
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts(" TIMEOUT !\n");
+ phydev->link = 0;
+ break;
+ }
+
+ if ((i++ % 1000) == 0)
+ putc('.');
+ udelay(1000); /* 1 ms */
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
+ MIIM_RTL8211x_PHY_STATUS);
+ }
+ puts(" done\n");
+ udelay(500000); /* another 500 ms (results in faster booting) */
+ } else {
+ if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
+ phydev->link = 1;
+ else
+ phydev->link = 0;
+ }
+
+ if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
+
+ switch (speed) {
+ case MIIM_RTL8211x_PHYSTAT_GBIT:
+ phydev->speed = SPEED_1000;
+ break;
+ case MIIM_RTL8211x_PHYSTAT_100:
+ phydev->speed = SPEED_100;
+ break;
+ default:
+ phydev->speed = SPEED_10;
+ }
+
+ return 0;
+}
+
+static int rtl8211x_startup(struct phy_device *phydev)
+{
+ /* Read the Status (2x to make sure link is right) */
+ genphy_update_link(phydev);
+ rtl8211x_parse_status(phydev);
+
+ return 0;
+}
+
+/* Support for RTL8211B PHY */
+static struct phy_driver RTL8211B_driver = {
+ .name = "RealTek RTL8211B",
+ .uid = 0x1cc910,
+ .mask = 0xffffff,
+ .features = PHY_GBIT_FEATURES,
+ .config = &rtl8211x_config,
+ .startup = &rtl8211x_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+/* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */
+static struct phy_driver RTL8211E_driver = {
+ .name = "RealTek RTL8211E",
+ .uid = 0x1cc915,
+ .mask = 0xffffff,
+ .features = PHY_GBIT_FEATURES,
+ .config = &rtl8211x_config,
+ .startup = &rtl8211x_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+/* Support for RTL8211DN PHY */
+static struct phy_driver RTL8211DN_driver = {
+ .name = "RealTek RTL8211DN",
+ .uid = 0x1cc914,
+ .mask = 0xffffff,
+ .features = PHY_GBIT_FEATURES,
+ .config = &rtl8211x_config,
+ .startup = &rtl8211x_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_realtek_init(void)
+{
+ phy_register(&RTL8211B_driver);
+ phy_register(&RTL8211E_driver);
+ phy_register(&RTL8211DN_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/smsc.c b/qemu/roms/u-boot/drivers/net/phy/smsc.c
new file mode 100644
index 000000000..bfd9815ab
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/smsc.c
@@ -0,0 +1,79 @@
+/*
+ * SMSC PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Base code from drivers/net/phy/davicom.c
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ *
+ * Some code copied from linux kernel
+ * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
+ */
+#include <miiphy.h>
+
+/* This code does not check the partner abilities. */
+static int smsc_parse_status(struct phy_device *phydev)
+{
+ int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+ if (mii_reg & (BMSR_100FULL | BMSR_100HALF))
+ phydev->speed = SPEED_100;
+ else
+ phydev->speed = SPEED_10;
+
+ if (mii_reg & (BMSR_10FULL | BMSR_100FULL))
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ return 0;
+}
+
+static int smsc_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ smsc_parse_status(phydev);
+ return 0;
+}
+
+static struct phy_driver lan8700_driver = {
+ .name = "SMSC LAN8700",
+ .uid = 0x0007c0c0,
+ .mask = 0xffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &smsc_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver lan911x_driver = {
+ .name = "SMSC LAN911x Internal PHY",
+ .uid = 0x0007c0d0,
+ .mask = 0xffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &smsc_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver lan8710_driver = {
+ .name = "SMSC LAN8710/LAN8720",
+ .uid = 0x0007c0f0,
+ .mask = 0xffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &genphy_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_smsc_init(void)
+{
+ phy_register(&lan8710_driver);
+ phy_register(&lan911x_driver);
+ phy_register(&lan8700_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/teranetics.c b/qemu/roms/u-boot/drivers/net/phy/teranetics.c
new file mode 100644
index 000000000..93d5ac3d1
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/teranetics.c
@@ -0,0 +1,112 @@
+/*
+ * Teranetics PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ */
+#include <config.h>
+#include <common.h>
+#include <phy.h>
+
+#ifndef CONFIG_PHYLIB_10G
+#error The Teranetics PHY needs 10G support
+#endif
+
+int tn2020_config(struct phy_device *phydev)
+{
+ if (phydev->port == PORT_FIBRE) {
+ unsigned short restart_an = (MDIO_AN_CTRL1_RESTART |
+ MDIO_AN_CTRL1_ENABLE |
+ MDIO_AN_CTRL1_XNP);
+ u8 phy_hwversion;
+
+ /*
+ * bit 15:12 of register 30.32 indicates PHY hardware
+ * version. It can be used to distinguish TN80xx from
+ * TN2020. TN2020 needs write 0x2 to 30.93, but TN80xx
+ * needs 0x1.
+ */
+ phy_hwversion = (phy_read(phydev, 30, 32) >> 12) & 0xf;
+ if (phy_hwversion <= 3) {
+ phy_write(phydev, 30, 93, 2);
+ phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an);
+ } else {
+ phy_write(phydev, 30, 93, 1);
+ }
+ }
+
+ return 0;
+}
+
+int tn2020_startup(struct phy_device *phydev)
+{
+ unsigned int timeout = 5 * 1000; /* 5 second timeout */
+
+#define MDIO_PHYXS_LANE_READY (MDIO_PHYXS_LNSTAT_SYNC0 | \
+ MDIO_PHYXS_LNSTAT_SYNC1 | \
+ MDIO_PHYXS_LNSTAT_SYNC2 | \
+ MDIO_PHYXS_LNSTAT_SYNC3 | \
+ MDIO_PHYXS_LNSTAT_ALIGN)
+
+ /*
+ * Wait for the XAUI-SERDES lanes to align first. Under normal
+ * circumstances, this can take up to three seconds.
+ */
+ while (--timeout) {
+ int reg = phy_read(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT);
+ if (reg < 0) {
+ printf("TN2020: Error reading from PHY at "
+ "address %u\n", phydev->addr);
+ break;
+ }
+ if ((reg & MDIO_PHYXS_LANE_READY) == MDIO_PHYXS_LANE_READY)
+ break;
+ udelay(1000);
+ }
+ if (!timeout) {
+ /*
+ * A timeout is bad, but it may not be fatal, so don't
+ * return an error. Display a warning instead.
+ */
+ printf("TN2020: Timeout waiting for PHY at address %u to "
+ "align.\n", phydev->addr);
+ }
+
+ if (phydev->port != PORT_FIBRE)
+ return gen10g_startup(phydev);
+
+ /*
+ * The TN2020 only pretends to support fiber.
+ * It works, but it doesn't look like it works,
+ * so the link status reports no link.
+ */
+ phydev->link = 1;
+
+ /* For now just lie and say it's 10G all the time */
+ phydev->speed = SPEED_10000;
+ phydev->duplex = DUPLEX_FULL;
+
+ return 0;
+}
+
+struct phy_driver tn2020_driver = {
+ .name = "Teranetics TN2020",
+ .uid = PHY_UID_TN2020,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |
+ MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
+ MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
+ .config = &tn2020_config,
+ .startup = &tn2020_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
+int phy_teranetics_init(void)
+{
+ phy_register(&tn2020_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/phy/vitesse.c b/qemu/roms/u-boot/drivers/net/phy/vitesse.c
new file mode 100644
index 000000000..3a55d271a
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/phy/vitesse.c
@@ -0,0 +1,373 @@
+/*
+ * Vitesse PHY drivers
+ *
+ * Copyright 2010-2012 Freescale Semiconductor, Inc.
+ * Author: Andy Fleming
+ * Add vsc8662 phy support - Priyanka Jain
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <miiphy.h>
+
+/* Cicada Auxiliary Control/Status Register */
+#define MIIM_CIS82xx_AUX_CONSTAT 0x1c
+#define MIIM_CIS82xx_AUXCONSTAT_INIT 0x0004
+#define MIIM_CIS82xx_AUXCONSTAT_DUPLEX 0x0020
+#define MIIM_CIS82xx_AUXCONSTAT_SPEED 0x0018
+#define MIIM_CIS82xx_AUXCONSTAT_GBIT 0x0010
+#define MIIM_CIS82xx_AUXCONSTAT_100 0x0008
+
+/* Cicada Extended Control Register 1 */
+#define MIIM_CIS82xx_EXT_CON1 0x17
+#define MIIM_CIS8201_EXTCON1_INIT 0x0000
+
+/* Cicada 8204 Extended PHY Control Register 1 */
+#define MIIM_CIS8204_EPHY_CON 0x17
+#define MIIM_CIS8204_EPHYCON_INIT 0x0006
+#define MIIM_CIS8204_EPHYCON_RGMII 0x1100
+
+/* Cicada 8204 Serial LED Control Register */
+#define MIIM_CIS8204_SLED_CON 0x1b
+#define MIIM_CIS8204_SLEDCON_INIT 0x1115
+
+/* Vitesse VSC8601 Extended PHY Control Register 1 */
+#define MIIM_VSC8601_EPHY_CON 0x17
+#define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120
+#define MIIM_VSC8601_SKEW_CTRL 0x1c
+
+#define PHY_EXT_PAGE_ACCESS 0x1f
+#define PHY_EXT_PAGE_ACCESS_GENERAL 0x10
+#define PHY_EXT_PAGE_ACCESS_EXTENDED3 0x3
+
+/* Vitesse VSC8574 control register */
+#define MIIM_VSC8574_MAC_SERDES_CON 0x10
+#define MIIM_VSC8574_MAC_SERDES_ANEG 0x80
+#define MIIM_VSC8574_GENERAL18 0x12
+#define MIIM_VSC8574_GENERAL19 0x13
+
+/* Vitesse VSC8574 gerenal purpose register 18 */
+#define MIIM_VSC8574_18G_SGMII 0x80f0
+#define MIIM_VSC8574_18G_QSGMII 0x80e0
+#define MIIM_VSC8574_18G_CMDSTAT 0x8000
+
+/* Vitesse VSC8514 control register */
+#define MIIM_VSC8514_GENERAL18 0x12
+#define MIIM_VSC8514_GENERAL19 0x13
+#define MIIM_VSC8514_GENERAL23 0x17
+
+/* Vitesse VSC8514 gerenal purpose register 18 */
+#define MIIM_VSC8514_18G_QSGMII 0x80e0
+#define MIIM_VSC8514_18G_CMDSTAT 0x8000
+
+/* CIS8201 */
+static int vitesse_config(struct phy_device *phydev)
+{
+ /* Override PHY config settings */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT,
+ MIIM_CIS82xx_AUXCONSTAT_INIT);
+ /* Set up the interface mode */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1,
+ MIIM_CIS8201_EXTCON1_INIT);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static int vitesse_parse_status(struct phy_device *phydev)
+{
+ int speed;
+ int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT);
+
+ if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED;
+ switch (speed) {
+ case MIIM_CIS82xx_AUXCONSTAT_GBIT:
+ phydev->speed = SPEED_1000;
+ break;
+ case MIIM_CIS82xx_AUXCONSTAT_100:
+ phydev->speed = SPEED_100;
+ break;
+ default:
+ phydev->speed = SPEED_10;
+ break;
+ }
+
+ return 0;
+}
+
+static int vitesse_startup(struct phy_device *phydev)
+{
+ genphy_update_link(phydev);
+ vitesse_parse_status(phydev);
+
+ return 0;
+}
+
+static int cis8204_config(struct phy_device *phydev)
+{
+ /* Override PHY config settings */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT,
+ MIIM_CIS82xx_AUXCONSTAT_INIT);
+
+ genphy_config_aneg(phydev);
+
+ if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID))
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON,
+ MIIM_CIS8204_EPHYCON_INIT |
+ MIIM_CIS8204_EPHYCON_RGMII);
+ else
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON,
+ MIIM_CIS8204_EPHYCON_INIT);
+
+ return 0;
+}
+
+/* Vitesse VSC8601 */
+static int vsc8601_config(struct phy_device *phydev)
+{
+ /* Configure some basic stuff */
+#ifdef CONFIG_SYS_VSC8601_SKEWFIX
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_EPHY_CON,
+ MIIM_VSC8601_EPHY_CON_INIT_SKEW);
+#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX)
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 1);
+#define VSC8101_SKEW \
+ ((CONFIG_SYS_VSC8601_SKEW_TX << 14) \
+ | (CONFIG_SYS_VSC8601_SKEW_RX << 12))
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_SKEW_CTRL,
+ VSC8101_SKEW);
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
+#endif
+#endif
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static int vsc8574_config(struct phy_device *phydev)
+{
+ u32 val;
+ /* configure register 19G for MAC */
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
+ PHY_EXT_PAGE_ACCESS_GENERAL);
+
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19);
+ if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
+ /* set bit 15:14 to '01' for QSGMII mode */
+ val = (val & 0x3fff) | (1 << 14);
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_VSC8574_GENERAL19, val);
+ /* Enable 4 ports MAC QSGMII */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
+ MIIM_VSC8574_18G_QSGMII);
+ } else {
+ /* set bit 15:14 to '00' for SGMII mode */
+ val = val & 0x3fff;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val);
+ /* Enable 4 ports MAC SGMII */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
+ MIIM_VSC8574_18G_SGMII);
+ }
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
+ /* When bit 15 is cleared the command has completed */
+ while (val & MIIM_VSC8574_18G_CMDSTAT)
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
+
+ /* Enable Serdes Auto-negotiation */
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
+ PHY_EXT_PAGE_ACCESS_EXTENDED3);
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON);
+ val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static int vsc8514_config(struct phy_device *phydev)
+{
+ u32 val;
+ int timeout = 1000000;
+
+ /* configure register to access 19G */
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
+ PHY_EXT_PAGE_ACCESS_GENERAL);
+
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19);
+ if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
+ /* set bit 15:14 to '01' for QSGMII mode */
+ val = (val & 0x3fff) | (1 << 14);
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_VSC8514_GENERAL19, val);
+ /* Enable 4 ports MAC QSGMII */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18,
+ MIIM_VSC8514_18G_QSGMII);
+ } else {
+ /*TODO Add SGMII functionality once spec sheet
+ * for VSC8514 defines complete functionality
+ */
+ }
+
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18);
+ /* When bit 15 is cleared the command has completed */
+ while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--)
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18);
+
+ if (0 == timeout) {
+ printf("PHY 8514 config failed\n");
+ return -1;
+ }
+
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
+
+ /* configure register to access 23 */
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23);
+ /* set bits 10:8 to '000' */
+ val = (val & 0xf8ff);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static struct phy_driver VSC8211_driver = {
+ .name = "Vitesse VSC8211",
+ .uid = 0xfc4b0,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &vitesse_config,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8221_driver = {
+ .name = "Vitesse VSC8221",
+ .uid = 0xfc550,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8244_driver = {
+ .name = "Vitesse VSC8244",
+ .uid = 0xfc6c0,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8234_driver = {
+ .name = "Vitesse VSC8234",
+ .uid = 0xfc620,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8574_driver = {
+ .name = "Vitesse VSC8574",
+ .uid = 0x704a0,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &vsc8574_config,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8514_driver = {
+ .name = "Vitesse VSC8514",
+ .uid = 0x70670,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &vsc8514_config,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8601_driver = {
+ .name = "Vitesse VSC8601",
+ .uid = 0x70420,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &vsc8601_config,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8641_driver = {
+ .name = "Vitesse VSC8641",
+ .uid = 0x70430,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8662_driver = {
+ .name = "Vitesse VSC8662",
+ .uid = 0x70660,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+/* Vitesse bought Cicada, so we'll put these here */
+static struct phy_driver cis8201_driver = {
+ .name = "CIS8201",
+ .uid = 0xfc410,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &vitesse_config,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver cis8204_driver = {
+ .name = "Cicada Cis8204",
+ .uid = 0xfc440,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &cis8204_config,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
+int phy_vitesse_init(void)
+{
+ phy_register(&VSC8641_driver);
+ phy_register(&VSC8601_driver);
+ phy_register(&VSC8234_driver);
+ phy_register(&VSC8244_driver);
+ phy_register(&VSC8211_driver);
+ phy_register(&VSC8221_driver);
+ phy_register(&VSC8574_driver);
+ phy_register(&VSC8514_driver);
+ phy_register(&VSC8662_driver);
+ phy_register(&cis8201_driver);
+ phy_register(&cis8204_driver);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/plb2800_eth.c b/qemu/roms/u-boot/drivers/net/plb2800_eth.c
new file mode 100644
index 000000000..f869514f2
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/plb2800_eth.c
@@ -0,0 +1,373 @@
+/*
+ * PLB2800 internal switch ethernet driver.
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/addrspace.h>
+
+
+#define NUM_RX_DESC PKTBUFSRX
+#define TOUT_LOOP 1000000
+
+#define LONG_REF(addr) (*((volatile unsigned long*)addr))
+
+#define CMAC_CRX_CTRL LONG_REF(0xb800c870)
+#define CMAC_CTX_CTRL LONG_REF(0xb800c874)
+#define SYS_MAC_ADDR_0 LONG_REF(0xb800c878)
+#define SYS_MAC_ADDR_1 LONG_REF(0xb800c87c)
+#define MIPS_H_MASK LONG_REF(0xB800C810)
+
+#define MA_LEARN LONG_REF(0xb8008004)
+#define DA_LOOKUP LONG_REF(0xb8008008)
+
+#define CMAC_CRX_CTRL_PD 0x00000001
+#define CMAC_CRX_CTRL_CG 0x00000002
+#define CMAC_CRX_CTRL_PL_SHIFT 2
+#define CMAC_CRIT 0x0
+#define CMAC_NON_CRIT 0x1
+#define MBOX_STAT_ID_SHF 28
+#define MBOX_STAT_CP 0x80000000
+#define MBOX_STAT_MB 0x00000001
+#define EN_MA_LEARN 0x02000000
+#define EN_DA_LKUP 0x01000000
+#define MA_DEST_SHF 11
+#define DA_DEST_SHF 11
+#define DA_STATE_SHF 19
+#define TSTAMP_MS 0x00000000
+#define SW_H_MBOX4_MASK 0x08000000
+#define SW_H_MBOX3_MASK 0x04000000
+#define SW_H_MBOX2_MASK 0x02000000
+#define SW_H_MBOX1_MASK 0x01000000
+
+typedef volatile struct {
+ unsigned int stat;
+ unsigned int cmd;
+ unsigned int cnt;
+ unsigned int adr;
+} mailbox_t;
+
+#define MBOX_REG(mb) ((mailbox_t*)(0xb800c830+(mb<<4)))
+
+typedef volatile struct {
+ unsigned int word0;
+ unsigned int word1;
+ unsigned int word2;
+} mbhdr_t;
+
+#define MBOX_MEM(mb) ((void*)(0xb800a000+((3-mb)<<11)))
+
+
+static int plb2800_eth_init(struct eth_device *dev, bd_t * bis);
+static int plb2800_eth_send(struct eth_device *dev, void *packet, int length);
+static int plb2800_eth_recv(struct eth_device *dev);
+static void plb2800_eth_halt(struct eth_device *dev);
+
+static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr);
+static unsigned char * plb2800_get_mac_addr(void);
+
+static int rx_new;
+static int mac_addr_set = 0;
+
+
+int plb2800_eth_initialize(bd_t * bis)
+{
+ struct eth_device *dev;
+ ulong temp;
+
+#ifdef DEBUG
+ printf("Entered plb2800_eth_initialize()\n");
+#endif
+
+ if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
+ {
+ printf("Failed to allocate memory\n");
+ return -1;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf(dev->name, "PLB2800 Switch");
+ dev->init = plb2800_eth_init;
+ dev->halt = plb2800_eth_halt;
+ dev->send = plb2800_eth_send;
+ dev->recv = plb2800_eth_recv;
+
+ eth_register(dev);
+
+ /* bug fix */
+ *(ulong *)0xb800e800 = 0x838;
+
+ /* Set MBOX ownership */
+ temp = CMAC_CRIT << MBOX_STAT_ID_SHF;
+ MBOX_REG(0)->stat = temp;
+ MBOX_REG(1)->stat = temp;
+
+ temp = CMAC_NON_CRIT << MBOX_STAT_ID_SHF;
+ MBOX_REG(2)->stat = temp;
+ MBOX_REG(3)->stat = temp;
+
+ plb2800_set_mac_addr(dev, plb2800_get_mac_addr());
+
+ /* Disable all Mbox interrupt */
+ temp = MIPS_H_MASK;
+ temp &= ~ (SW_H_MBOX1_MASK | SW_H_MBOX2_MASK | SW_H_MBOX3_MASK | SW_H_MBOX4_MASK) ;
+ MIPS_H_MASK = temp;
+
+#ifdef DEBUG
+ printf("Leaving plb2800_eth_initialize()\n");
+#endif
+
+ return 0;
+}
+
+static int plb2800_eth_init(struct eth_device *dev, bd_t * bis)
+{
+#ifdef DEBUG
+ printf("Entering plb2800_eth_init()\n");
+#endif
+
+ plb2800_set_mac_addr(dev, dev->enetaddr);
+
+ rx_new = 0;
+
+#ifdef DEBUG
+ printf("Leaving plb2800_eth_init()\n");
+#endif
+
+ return 0;
+}
+
+
+static int plb2800_eth_send(struct eth_device *dev, void *packet, int length)
+{
+ int i;
+ int res = -1;
+ u32 temp;
+ mailbox_t * mb = MBOX_REG(0);
+ char * mem = MBOX_MEM(0);
+
+#ifdef DEBUG
+ printf("Entered plb2800_eth_send()\n");
+#endif
+
+ if (length <= 0)
+ {
+ printf ("%s: bad packet size: %d\n", dev->name, length);
+ goto Done;
+ }
+
+ if (length < 64)
+ {
+ length = 64;
+ }
+
+ temp = CMAC_CRX_CTRL_CG | ((length + 4) << CMAC_CRX_CTRL_PL_SHIFT);
+
+#ifdef DEBUG
+ printf("0 mb->stat = 0x%x\n", mb->stat);
+#endif
+
+ for(i = 0; mb->stat & (MBOX_STAT_CP | MBOX_STAT_MB); i++)
+ {
+ if (i >= TOUT_LOOP)
+ {
+ printf("%s: tx buffer not ready\n", dev->name);
+ printf("1 mb->stat = 0x%x\n", mb->stat);
+ goto Done;
+ }
+ }
+
+ /* For some strange reason, memcpy doesn't work, here!
+ */
+ do
+ {
+ int words = (length >> 2) + 1;
+ unsigned int* dst = (unsigned int*)(mem);
+ unsigned int* src = (unsigned int*)(packet);
+ for (i = 0; i < words; i++)
+ {
+ *dst = *src;
+ dst++;
+ src++;
+ };
+ } while(0);
+
+ CMAC_CRX_CTRL = temp;
+ mb->cmd = MBOX_STAT_CP;
+
+#ifdef DEBUG
+ printf("2 mb->stat = 0x%x\n", mb->stat);
+#endif
+
+ res = length;
+Done:
+
+#ifdef DEBUG
+ printf("Leaving plb2800_eth_send()\n");
+#endif
+
+ return res;
+}
+
+
+static int plb2800_eth_recv(struct eth_device *dev)
+{
+ int length = 0;
+ mailbox_t * mbox = MBOX_REG(3);
+ unsigned char * hdr = MBOX_MEM(3);
+ unsigned int stat;
+
+#ifdef DEBUG
+ printf("Entered plb2800_eth_recv()\n");
+#endif
+
+ for (;;)
+ {
+ stat = mbox->stat;
+
+ if (!(stat & MBOX_STAT_CP))
+ {
+ break;
+ }
+
+ length = ((*(hdr + 6) & 0x3f) << 8) + *(hdr + 7);
+ memcpy((void *)NetRxPackets[rx_new], hdr + 12, length);
+
+ stat &= ~MBOX_STAT_CP;
+ mbox->stat = stat;
+#ifdef DEBUG
+ {
+ int i;
+ for (i=0;i<length - 4;i++)
+ {
+ if (i % 16 == 0) printf("\n%04x: ", i);
+ printf("%02X ", NetRxPackets[rx_new][i]);
+ }
+ printf("\n");
+ }
+#endif
+
+ if (length)
+ {
+#ifdef DEBUG
+ printf("Received %d bytes\n", length);
+#endif
+ NetReceive((void*)(NetRxPackets[rx_new]),
+ length - 4);
+ }
+ else
+ {
+#if 1
+ printf("Zero length!!!\n");
+#endif
+ }
+
+ rx_new = (rx_new + 1) % NUM_RX_DESC;
+ }
+
+#ifdef DEBUG
+ printf("Leaving plb2800_eth_recv()\n");
+#endif
+
+ return length;
+}
+
+
+static void plb2800_eth_halt(struct eth_device *dev)
+{
+#ifdef DEBUG
+ printf("Entered plb2800_eth_halt()\n");
+#endif
+
+#ifdef DEBUG
+ printf("Leaving plb2800_eth_halt()\n");
+#endif
+}
+
+static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr)
+{
+ char packet[60];
+ ulong temp;
+ int ix;
+
+ if (mac_addr_set ||
+ NULL == addr || memcmp(addr, "\0\0\0\0\0\0", 6) == 0)
+ {
+ return;
+ }
+
+ /* send one packet through CPU port
+ * in order to learn system MAC address
+ */
+
+ /* Set DA_LOOKUP register */
+ temp = EN_MA_LEARN | (0 << DA_STATE_SHF) | (63 << DA_DEST_SHF);
+ DA_LOOKUP = temp;
+
+ /* Set MA_LEARN register */
+ temp = 50 << MA_DEST_SHF; /* static entry */
+ MA_LEARN = temp;
+
+ /* set destination address */
+ for (ix=0;ix<6;ix++)
+ packet[ix] = 0xff;
+
+ /* set source address = system MAC address */
+ for (ix=0;ix<6;ix++)
+ packet[6+ix] = addr[ix];
+
+ /* set type field */
+ packet[12]=0xaa;
+ packet[13]=0x55;
+
+ /* set data field */
+ for(ix=14;ix<60;ix++)
+ packet[ix] = 0x00;
+
+#ifdef DEBUG
+ for (ix=0;ix<6;ix++)
+ printf("mac_addr[%d]=%02X\n", ix, (unsigned char)packet[6+ix]);
+#endif
+
+ /* set one packet */
+ plb2800_eth_send(dev, packet, sizeof(packet));
+
+ /* delay for a while */
+ for(ix=0;ix<65535;ix++)
+ temp = ~temp;
+
+ /* Set CMAC_CTX_CTRL register */
+ temp = TSTAMP_MS; /* no autocast */
+ CMAC_CTX_CTRL = temp;
+
+ /* Set DA_LOOKUP register */
+ temp = EN_DA_LKUP;
+ DA_LOOKUP = temp;
+
+ mac_addr_set = 1;
+}
+
+static unsigned char * plb2800_get_mac_addr(void)
+{
+ static unsigned char addr[6];
+ char *tmp, *end;
+ int i;
+
+ tmp = getenv ("ethaddr");
+ if (NULL == tmp) return NULL;
+
+ for (i=0; i<6; i++) {
+ addr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+ if (tmp)
+ tmp = (*end) ? end+1 : end;
+ }
+
+ return addr;
+}
diff --git a/qemu/roms/u-boot/drivers/net/rtl8139.c b/qemu/roms/u-boot/drivers/net/rtl8139.c
new file mode 100644
index 000000000..208ce5ccc
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/rtl8139.c
@@ -0,0 +1,539 @@
+/*
+ * rtl8139.c : U-Boot driver for the RealTek RTL8139
+ *
+ * Masami Komiya (mkomiya@sonare.it)
+ *
+ * Most part is taken from rtl8139.c of etherboot
+ *
+ */
+
+/* rtl8139.c - etherboot driver for the Realtek 8139 chipset
+
+ ported from the linux driver written by Donald Becker
+ by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ changes to the original driver:
+ - removed support for interrupts, switching to polling mode (yuck!)
+ - removed support for the 8129 chip (external MII)
+
+*/
+
+/*********************************************************************/
+/* Revision History */
+/*********************************************************************/
+
+/*
+ 28 Dec 2002 ken_yap@users.sourceforge.net (Ken Yap)
+ Put in virt_to_bus calls to allow Etherboot relocation.
+
+ 06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap)
+ Following email from Hyun-Joon Cha, added a disable routine, otherwise
+ NIC remains live and can crash the kernel later.
+
+ 4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub)
+ Shuffled things around, removed the leftovers from the 8129 support
+ that was in the Linux driver and added a bit more 8139 definitions.
+ Moved the 8K receive buffer to a fixed, available address outside the
+ 0x98000-0x9ffff range. This is a bit of a hack, but currently the only
+ way to make room for the Etherboot features that need substantial amounts
+ of code like the ANSI console support. Currently the buffer is just below
+ 0x10000, so this even conforms to the tagged boot image specification,
+ which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My
+ interpretation of this "reserved" is that Etherboot may do whatever it
+ likes, as long as its environment is kept intact (like the BIOS
+ variables). Hopefully fixed rtl_poll() once and for all. The symptoms
+ were that if Etherboot was left at the boot menu for several minutes, the
+ first eth_poll failed. Seems like I am the only person who does this.
+ First of all I fixed the debugging code and then set out for a long bug
+ hunting session. It took me about a week full time work - poking around
+ various places in the driver, reading Don Becker's and Jeff Garzik's Linux
+ driver and even the FreeBSD driver (what a piece of crap!) - and
+ eventually spotted the nasty thing: the transmit routine was acknowledging
+ each and every interrupt pending, including the RxOverrun and RxFIFIOver
+ interrupts. This confused the RTL8139 thoroughly. It destroyed the
+ Rx ring contents by dumping the 2K FIFO contents right where we wanted to
+ get the next packet. Oh well, what fun.
+
+ 18 Jan 2000 mdc@thinguin.org (Marty Connor)
+ Drastically simplified error handling. Basically, if any error
+ in transmission or reception occurs, the card is reset.
+ Also, pointed all transmit descriptors to the same buffer to
+ save buffer space. This should decrease driver size and avoid
+ corruption because of exceeding 32K during runtime.
+
+ 28 Jul 1999 (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de)
+ rtl_poll was quite broken: it used the RxOK interrupt flag instead
+ of the RxBufferEmpty flag which often resulted in very bad
+ transmission performace - below 1kBytes/s.
+
+*/
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define RTL_TIMEOUT 100000
+
+#define ETH_FRAME_LEN 1514
+#define ETH_ALEN 6
+#define ETH_ZLEN 60
+
+/* PCI Tuning Parameters
+ Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
+#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST 4 /* Calculate as 16<<val. */
+#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */
+#define TX_BUF_SIZE ETH_FRAME_LEN /* FCS is added by the chip */
+#define RX_BUF_LEN_IDX 0 /* 0, 1, 2 is allowed - 8,16,32K rx buffer */
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+
+#define DEBUG_TX 0 /* set to 1 to enable debug code */
+#define DEBUG_RX 0 /* set to 1 to enable debug code */
+
+#define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+ MAC0=0, /* Ethernet hardware address. */
+ MAR0=8, /* Multicast filter. */
+ TxStatus0=0x10, /* Transmit status (four 32bit registers). */
+ TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
+ RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
+ ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
+ IntrMask=0x3C, IntrStatus=0x3E,
+ TxConfig=0x40, RxConfig=0x44,
+ Timer=0x48, /* general-purpose counter. */
+ RxMissed=0x4C, /* 24 bits valid, write clears. */
+ Cfg9346=0x50, Config0=0x51, Config1=0x52,
+ TimerIntrReg=0x54, /* intr if gp counter reaches this value */
+ MediaStatus=0x58,
+ Config3=0x59,
+ MultiIntr=0x5C,
+ RevisionID=0x5E, /* revision of the RTL8139 chip */
+ TxSummary=0x60,
+ MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
+ NWayExpansion=0x6A,
+ DisconnectCnt=0x6C, FalseCarrierCnt=0x6E,
+ NWayTestReg=0x70,
+ RxCnt=0x72, /* packet received counter */
+ CSCR=0x74, /* chip status and configuration register */
+ PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80, /* undocumented */
+ /* from 0x84 onwards are a number of power management/wakeup frame
+ * definitions we will probably never need to know about. */
+};
+
+enum ChipCmdBits {
+ CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+ PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000,
+ RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
+ TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
+};
+enum TxStatusBits {
+ TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
+ TxOutOfWindow=0x20000000, TxAborted=0x40000000,
+ TxCarrierLost=0x80000000,
+};
+enum RxStatusBits {
+ RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
+ RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
+ RxBadAlign=0x0002, RxStatusOK=0x0001,
+};
+
+enum MediaStatusBits {
+ MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08,
+ MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01,
+};
+
+enum MIIBMCRBits {
+ BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000,
+ BMCRRestartNWay=0x0200, BMCRDuplex=0x0100,
+};
+
+enum CSCRBits {
+ CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
+ CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
+ CSCR_LinkDownCmd=0x0f3c0,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+ RxCfgWrap=0x80,
+ AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
+ AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
+};
+
+static int ioaddr;
+static unsigned int cur_rx,cur_tx;
+
+/* The RTL8139 can only transmit from a contiguous, aligned memory block. */
+static unsigned char tx_buffer[TX_BUF_SIZE] __attribute__((aligned(4)));
+static unsigned char rx_ring[RX_BUF_LEN+16] __attribute__((aligned(4)));
+
+static int rtl8139_probe(struct eth_device *dev, bd_t *bis);
+static int read_eeprom(int location, int addr_len);
+static void rtl_reset(struct eth_device *dev);
+static int rtl_transmit(struct eth_device *dev, void *packet, int length);
+static int rtl_poll(struct eth_device *dev);
+static void rtl_disable(struct eth_device *dev);
+#ifdef CONFIG_MCAST_TFTP/* This driver already accepts all b/mcast */
+static int rtl_bcast_addr(struct eth_device *dev, const u8 *bcast_mac, u8 set)
+{
+ return (0);
+}
+#endif
+
+static struct pci_device_id supported[] = {
+ {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139},
+ {PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139},
+ {}
+};
+
+int rtl8139_initialize(bd_t *bis)
+{
+ pci_dev_t devno;
+ int card_number = 0;
+ struct eth_device *dev;
+ u32 iobase;
+ int idx=0;
+
+ while(1){
+ /* Find RTL8139 */
+ if ((devno = pci_find_devices(supported, idx++)) < 0)
+ break;
+
+ pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+ iobase &= ~0xf;
+
+ debug ("rtl8139: REALTEK RTL8139 @0x%x\n", iobase);
+
+ dev = (struct eth_device *)malloc(sizeof *dev);
+ if (!dev) {
+ printf("Can not allocate memory of rtl8139\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf (dev->name, "RTL8139#%d", card_number);
+
+ dev->priv = (void *) devno;
+ dev->iobase = (int)bus_to_phys(iobase);
+ dev->init = rtl8139_probe;
+ dev->halt = rtl_disable;
+ dev->send = rtl_transmit;
+ dev->recv = rtl_poll;
+#ifdef CONFIG_MCAST_TFTP
+ dev->mcast = rtl_bcast_addr;
+#endif
+
+ eth_register (dev);
+
+ card_number++;
+
+ pci_write_config_byte (devno, PCI_LATENCY_TIMER, 0x20);
+
+ udelay (10 * 1000);
+ }
+
+ return card_number;
+}
+
+static int rtl8139_probe(struct eth_device *dev, bd_t *bis)
+{
+ int i;
+ int addr_len;
+ unsigned short *ap = (unsigned short *)dev->enetaddr;
+
+ ioaddr = dev->iobase;
+
+ /* Bring the chip out of low-power mode. */
+ outb(0x00, ioaddr + Config1);
+
+ addr_len = read_eeprom(0,8) == 0x8129 ? 8 : 6;
+ for (i = 0; i < 3; i++)
+ *ap++ = le16_to_cpu (read_eeprom(i + 7, addr_len));
+
+ rtl_reset(dev);
+
+ if (inb(ioaddr + MediaStatus) & MSRLinkFail) {
+ printf("Cable not connected or other link failure\n");
+ return -1 ;
+ }
+
+ return 0;
+}
+
+/* Serial EEPROM section. */
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
+#define EE_CS 0x08 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x00
+#define EE_WRITE_1 0x02
+#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
+#define EE_ENB (0x80 | EE_CS)
+
+/*
+ Delay between EEPROM clock transitions.
+ No extra delay is needed with 33MHz PCI, but 66MHz may change this.
+*/
+
+#define eeprom_delay() inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5)
+#define EE_READ_CMD (6)
+#define EE_ERASE_CMD (7)
+
+static int read_eeprom(int location, int addr_len)
+{
+ int i;
+ unsigned int retval = 0;
+ long ee_addr = ioaddr + Cfg9346;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ outb(EE_ENB & ~EE_CS, ee_addr);
+ outb(EE_ENB, ee_addr);
+ eeprom_delay();
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ outb(EE_ENB | dataval, ee_addr);
+ eeprom_delay();
+ outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ }
+ outb(EE_ENB, ee_addr);
+ eeprom_delay();
+
+ for (i = 16; i > 0; i--) {
+ outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ outb(EE_ENB, ee_addr);
+ eeprom_delay();
+ }
+
+ /* Terminate the EEPROM access. */
+ outb(~EE_CS, ee_addr);
+ eeprom_delay();
+ return retval;
+}
+
+static const unsigned int rtl8139_rx_config =
+ (RX_BUF_LEN_IDX << 11) |
+ (RX_FIFO_THRESH << 13) |
+ (RX_DMA_BURST << 8);
+
+static void set_rx_mode(struct eth_device *dev) {
+ unsigned int mc_filter[2];
+ int rx_mode;
+ /* !IFF_PROMISC */
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+
+ outl(rtl8139_rx_config | rx_mode, ioaddr + RxConfig);
+
+ outl(mc_filter[0], ioaddr + MAR0 + 0);
+ outl(mc_filter[1], ioaddr + MAR0 + 4);
+}
+
+static void rtl_reset(struct eth_device *dev)
+{
+ int i;
+
+ outb(CmdReset, ioaddr + ChipCmd);
+
+ cur_rx = 0;
+ cur_tx = 0;
+
+ /* Give the chip 10ms to finish the reset. */
+ for (i=0; i<100; ++i){
+ if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;
+ udelay (100); /* wait 100us */
+ }
+
+
+ for (i = 0; i < ETH_ALEN; i++)
+ outb(dev->enetaddr[i], ioaddr + MAC0 + i);
+
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+ outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8),
+ ioaddr + RxConfig); /* accept no frames yet! */
+ outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
+
+ /* The Linux driver changes Config1 here to use a different LED pattern
+ * for half duplex or full/autodetect duplex (for full/autodetect, the
+ * outputs are TX/RX, Link10/100, FULL, while for half duplex it uses
+ * TX/RX, Link100, Link10). This is messy, because it doesn't match
+ * the inscription on the mounting bracket. It should not be changed
+ * from the configuration EEPROM default, because the card manufacturer
+ * should have set that to match the card. */
+
+ debug_cond(DEBUG_RX,
+ "rx ring address is %lX\n",(unsigned long)rx_ring);
+ flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
+ outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);
+
+ /* If we add multicast support, the MAR0 register would have to be
+ * initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot
+ * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast. */
+
+ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+
+ outl(rtl8139_rx_config, ioaddr + RxConfig);
+
+ /* Start the chip's Tx and Rx process. */
+ outl(0, ioaddr + RxMissed);
+
+ /* set_rx_mode */
+ set_rx_mode(dev);
+
+ /* Disable all known interrupts by setting the interrupt mask. */
+ outw(0, ioaddr + IntrMask);
+}
+
+static int rtl_transmit(struct eth_device *dev, void *packet, int length)
+{
+ unsigned int status;
+ unsigned long txstatus;
+ unsigned int len = length;
+ int i = 0;
+
+ ioaddr = dev->iobase;
+
+ memcpy((char *)tx_buffer, (char *)packet, (int)length);
+
+ debug_cond(DEBUG_TX, "sending %d bytes\n", len);
+
+ /* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
+ * bytes are sent automatically for the FCS, totalling to 64 bytes). */
+ while (len < ETH_ZLEN) {
+ tx_buffer[len++] = '\0';
+ }
+
+ flush_cache((unsigned long)tx_buffer, length);
+ outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4);
+ outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
+ ioaddr + TxStatus0 + cur_tx*4);
+
+ do {
+ status = inw(ioaddr + IntrStatus);
+ /* Only acknlowledge interrupt sources we can properly handle
+ * here - the RxOverflow/RxFIFOOver MUST be handled in the
+ * rtl_poll() function. */
+ outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);
+ if ((status & (TxOK | TxErr | PCIErr)) != 0) break;
+ udelay(10);
+ } while (i++ < RTL_TIMEOUT);
+
+ txstatus = inl(ioaddr + TxStatus0 + cur_tx*4);
+
+ if (status & TxOK) {
+ cur_tx = (cur_tx + 1) % NUM_TX_DESC;
+
+ debug_cond(DEBUG_TX,
+ "tx done, status %hX txstatus %lX\n",
+ status, txstatus);
+
+ return length;
+ } else {
+
+ debug_cond(DEBUG_TX,
+ "tx timeout/error (%d usecs), status %hX txstatus %lX\n",
+ 10*i, status, txstatus);
+
+ rtl_reset(dev);
+
+ return 0;
+ }
+}
+
+static int rtl_poll(struct eth_device *dev)
+{
+ unsigned int status;
+ unsigned int ring_offs;
+ unsigned int rx_size, rx_status;
+ int length=0;
+
+ ioaddr = dev->iobase;
+
+ if (inb(ioaddr + ChipCmd) & RxBufEmpty) {
+ return 0;
+ }
+
+ status = inw(ioaddr + IntrStatus);
+ /* See below for the rest of the interrupt acknowledges. */
+ outw(status & ~(RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);
+
+ debug_cond(DEBUG_RX, "rtl_poll: int %hX ", status);
+
+ ring_offs = cur_rx % RX_BUF_LEN;
+ /* ring_offs is guaranteed being 4-byte aligned */
+ rx_status = le32_to_cpu(*(unsigned int *)(rx_ring + ring_offs));
+ rx_size = rx_status >> 16;
+ rx_status &= 0xffff;
+
+ if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) ||
+ (rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) {
+ printf("rx error %hX\n", rx_status);
+ rtl_reset(dev); /* this clears all interrupts still pending */
+ return 0;
+ }
+
+ /* Received a good packet */
+ length = rx_size - 4; /* no one cares about the FCS */
+ if (ring_offs+4+rx_size-4 > RX_BUF_LEN) {
+ int semi_count = RX_BUF_LEN - ring_offs - 4;
+ unsigned char rxdata[RX_BUF_LEN];
+
+ memcpy(rxdata, rx_ring + ring_offs + 4, semi_count);
+ memcpy(&(rxdata[semi_count]), rx_ring, rx_size-4-semi_count);
+
+ NetReceive(rxdata, length);
+ debug_cond(DEBUG_RX, "rx packet %d+%d bytes",
+ semi_count, rx_size-4-semi_count);
+ } else {
+ NetReceive(rx_ring + ring_offs + 4, length);
+ debug_cond(DEBUG_RX, "rx packet %d bytes", rx_size-4);
+ }
+ flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
+
+ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+ outw(cur_rx - 16, ioaddr + RxBufPtr);
+ /* See RTL8139 Programming Guide V0.1 for the official handling of
+ * Rx overflow situations. The document itself contains basically no
+ * usable information, except for a few exception handling rules. */
+ outw(status & (RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);
+ return length;
+}
+
+static void rtl_disable(struct eth_device *dev)
+{
+ int i;
+
+ ioaddr = dev->iobase;
+
+ /* reset the chip */
+ outb(CmdReset, ioaddr + ChipCmd);
+
+ /* Give the chip 10ms to finish the reset. */
+ for (i=0; i<100; ++i){
+ if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;
+ udelay (100); /* wait 100us */
+ }
+}
diff --git a/qemu/roms/u-boot/drivers/net/rtl8169.c b/qemu/roms/u-boot/drivers/net/rtl8169.c
new file mode 100644
index 000000000..d040ab171
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/rtl8169.c
@@ -0,0 +1,967 @@
+/*
+ * rtl8169.c : U-Boot driver for the RealTek RTL8169
+ *
+ * Masami Komiya (mkomiya@sonare.it)
+ *
+ * Most part is taken from r8169.c of etherboot
+ *
+ */
+
+/**************************************************************************
+* r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit
+* Written 2003 by Timothy Legge <tlegge@rogers.com>
+*
+ * SPDX-License-Identifier: GPL-2.0+
+*
+* Portions of this code based on:
+* r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver
+* for Linux kernel 2.4.x.
+*
+* Written 2002 ShuChen <shuchen@realtek.com.tw>
+* See Linux Driver for full information
+*
+* Linux Driver Version 1.27a, 10.02.2002
+*
+* Thanks to:
+* Jean Chen of RealTek Semiconductor Corp. for
+* providing the evaluation NIC used to develop
+* this driver. RealTek's support for Etherboot
+* is appreciated.
+*
+* REVISION HISTORY:
+* ================
+*
+* v1.0 11-26-2003 timlegge Initial port of Linux driver
+* v1.5 01-17-2004 timlegge Initial driver output cleanup
+*
+* Indent Options: indent -kr -i8
+***************************************************************************/
+/*
+ * 26 August 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
+ * Modified to use le32_to_cpu and cpu_to_le32 properly
+ */
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#undef DEBUG_RTL8169
+#undef DEBUG_RTL8169_TX
+#undef DEBUG_RTL8169_RX
+
+#define drv_version "v1.5"
+#define drv_date "01-17-2004"
+
+static u32 ioaddr;
+
+/* Condensed operations for readability. */
+#define currticks() get_timer(0)
+
+/* media options */
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+
+/* MAC address length*/
+#define MAC_ADDR_LEN 6
+
+/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE 1536
+
+#define TX_FIFO_THRESH 256 /* In bytes */
+
+#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
+#define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */
+#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
+
+#define NUM_TX_DESC 1 /* Number of Tx descriptor registers */
+#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
+#define RX_BUF_SIZE 1536 /* Rx Buffer size */
+#define RX_BUF_LEN 8192
+
+#define RTL_MIN_IO_SIZE 0x80
+#define TX_TIMEOUT (6*HZ)
+
+/* write/read MMIO register. Notice: {read,write}[wl] do the necessary swapping */
+#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
+#define RTL_R8(reg) readb (ioaddr + (reg))
+#define RTL_R16(reg) readw (ioaddr + (reg))
+#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
+
+#define ETH_FRAME_LEN MAX_ETH_FRAME_SIZE
+#define ETH_ALEN MAC_ADDR_LEN
+#define ETH_ZLEN 60
+
+#define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)dev->priv, (pci_addr_t)a)
+#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, (phys_addr_t)a)
+
+enum RTL8169_registers {
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAR0 = 8, /* Multicast filter. */
+ TxDescStartAddrLow = 0x20,
+ TxDescStartAddrHigh = 0x24,
+ TxHDescStartAddrLow = 0x28,
+ TxHDescStartAddrHigh = 0x2c,
+ FLASH = 0x30,
+ ERSR = 0x36,
+ ChipCmd = 0x37,
+ TxPoll = 0x38,
+ IntrMask = 0x3C,
+ IntrStatus = 0x3E,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ RxMissed = 0x4C,
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ Config2 = 0x53,
+ Config3 = 0x54,
+ Config4 = 0x55,
+ Config5 = 0x56,
+ MultiIntr = 0x5C,
+ PHYAR = 0x60,
+ TBICSR = 0x64,
+ TBI_ANAR = 0x68,
+ TBI_LPAR = 0x6A,
+ PHYstatus = 0x6C,
+ RxMaxSize = 0xDA,
+ CPlusCmd = 0xE0,
+ RxDescStartAddrLow = 0xE4,
+ RxDescStartAddrHigh = 0xE8,
+ EarlyTxThres = 0xEC,
+ FuncEvent = 0xF0,
+ FuncEventMask = 0xF4,
+ FuncPresetState = 0xF8,
+ FuncForceEvent = 0xFC,
+};
+
+enum RTL8169_register_content {
+ /*InterruptStatusBits */
+ SYSErr = 0x8000,
+ PCSTimeout = 0x4000,
+ SWInt = 0x0100,
+ TxDescUnavail = 0x80,
+ RxFIFOOver = 0x40,
+ RxUnderrun = 0x20,
+ RxOverflow = 0x10,
+ TxErr = 0x08,
+ TxOK = 0x04,
+ RxErr = 0x02,
+ RxOK = 0x01,
+
+ /*RxStatusDesc */
+ RxRES = 0x00200000,
+ RxCRC = 0x00080000,
+ RxRUNT = 0x00100000,
+ RxRWT = 0x00400000,
+
+ /*ChipCmdBits */
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
+
+ /*Cfg9346Bits */
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xC0,
+
+ /*rx_mode_bits */
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
+
+ /*RxConfigBits */
+ RxCfgFIFOShift = 13,
+ RxCfgDMAShift = 8,
+
+ /*TxConfigBits */
+ TxInterFrameGapShift = 24,
+ TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
+
+ /*rtl8169_PHYstatus */
+ TBI_Enable = 0x80,
+ TxFlowCtrl = 0x40,
+ RxFlowCtrl = 0x20,
+ _1000bpsF = 0x10,
+ _100bps = 0x08,
+ _10bps = 0x04,
+ LinkStatus = 0x02,
+ FullDup = 0x01,
+
+ /*GIGABIT_PHY_registers */
+ PHY_CTRL_REG = 0,
+ PHY_STAT_REG = 1,
+ PHY_AUTO_NEGO_REG = 4,
+ PHY_1000_CTRL_REG = 9,
+
+ /*GIGABIT_PHY_REG_BIT */
+ PHY_Restart_Auto_Nego = 0x0200,
+ PHY_Enable_Auto_Nego = 0x1000,
+
+ /* PHY_STAT_REG = 1; */
+ PHY_Auto_Nego_Comp = 0x0020,
+
+ /* PHY_AUTO_NEGO_REG = 4; */
+ PHY_Cap_10_Half = 0x0020,
+ PHY_Cap_10_Full = 0x0040,
+ PHY_Cap_100_Half = 0x0080,
+ PHY_Cap_100_Full = 0x0100,
+
+ /* PHY_1000_CTRL_REG = 9; */
+ PHY_Cap_1000_Full = 0x0200,
+
+ PHY_Cap_Null = 0x0,
+
+ /*_MediaType*/
+ _10_Half = 0x01,
+ _10_Full = 0x02,
+ _100_Half = 0x04,
+ _100_Full = 0x08,
+ _1000_Full = 0x10,
+
+ /*_TBICSRBit*/
+ TBILinkOK = 0x02000000,
+};
+
+static struct {
+ const char *name;
+ u8 version; /* depend on RTL8169 docs */
+ u32 RxConfigMask; /* should clear the bits supported by this chip */
+} rtl_chip_info[] = {
+ {"RTL-8169", 0x00, 0xff7e1880,},
+ {"RTL-8169", 0x04, 0xff7e1880,},
+ {"RTL-8169", 0x00, 0xff7e1880,},
+ {"RTL-8169s/8110s", 0x02, 0xff7e1880,},
+ {"RTL-8169s/8110s", 0x04, 0xff7e1880,},
+ {"RTL-8169sb/8110sb", 0x10, 0xff7e1880,},
+ {"RTL-8169sc/8110sc", 0x18, 0xff7e1880,},
+ {"RTL-8168b/8111sb", 0x30, 0xff7e1880,},
+ {"RTL-8168b/8111sb", 0x38, 0xff7e1880,},
+ {"RTL-8168d/8111d", 0x28, 0xff7e1880,},
+ {"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,},
+ {"RTL-8101e", 0x34, 0xff7e1880,},
+ {"RTL-8100e", 0x32, 0xff7e1880,},
+};
+
+enum _DescStatusBit {
+ OWNbit = 0x80000000,
+ EORbit = 0x40000000,
+ FSbit = 0x20000000,
+ LSbit = 0x10000000,
+};
+
+struct TxDesc {
+ u32 status;
+ u32 vlan_tag;
+ u32 buf_addr;
+ u32 buf_Haddr;
+};
+
+struct RxDesc {
+ u32 status;
+ u32 vlan_tag;
+ u32 buf_addr;
+ u32 buf_Haddr;
+};
+
+/* Define the TX Descriptor */
+static u8 tx_ring[NUM_TX_DESC * sizeof(struct TxDesc) + 256];
+/* __attribute__ ((aligned(256))); */
+
+/* Create a static buffer of size RX_BUF_SZ for each
+TX Descriptor. All descriptors point to a
+part of this buffer */
+static unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
+
+/* Define the RX Descriptor */
+static u8 rx_ring[NUM_RX_DESC * sizeof(struct TxDesc) + 256];
+ /* __attribute__ ((aligned(256))); */
+
+/* Create a static buffer of size RX_BUF_SZ for each
+RX Descriptor All descriptors point to a
+part of this buffer */
+static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
+
+struct rtl8169_private {
+ void *mmio_addr; /* memory map physical address */
+ int chipset;
+ unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
+ unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
+ unsigned long dirty_tx;
+ unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */
+ unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */
+ struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
+ struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
+ unsigned char *RxBufferRings; /* Index of Rx Buffer */
+ unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */
+ unsigned char *Tx_skbuff[NUM_TX_DESC];
+} tpx;
+
+static struct rtl8169_private *tpc;
+
+static const u16 rtl8169_intr_mask =
+ SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr |
+ TxOK | RxErr | RxOK;
+static const unsigned int rtl8169_rx_config =
+ (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+static struct pci_device_id supported[] = {
+ {PCI_VENDOR_ID_REALTEK, 0x8167},
+ {PCI_VENDOR_ID_REALTEK, 0x8168},
+ {PCI_VENDOR_ID_REALTEK, 0x8169},
+ {}
+};
+
+void mdio_write(int RegAddr, int value)
+{
+ int i;
+
+ RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
+ udelay(1000);
+
+ for (i = 2000; i > 0; i--) {
+ /* Check if the RTL8169 has completed writing to the specified MII register */
+ if (!(RTL_R32(PHYAR) & 0x80000000)) {
+ break;
+ } else {
+ udelay(100);
+ }
+ }
+}
+
+int mdio_read(int RegAddr)
+{
+ int i, value = -1;
+
+ RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
+ udelay(1000);
+
+ for (i = 2000; i > 0; i--) {
+ /* Check if the RTL8169 has completed retrieving data from the specified MII register */
+ if (RTL_R32(PHYAR) & 0x80000000) {
+ value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+ break;
+ } else {
+ udelay(100);
+ }
+ }
+ return value;
+}
+
+static int rtl8169_init_board(struct eth_device *dev)
+{
+ int i;
+ u32 tmp;
+
+#ifdef DEBUG_RTL8169
+ printf ("%s\n", __FUNCTION__);
+#endif
+ ioaddr = dev->iobase;
+
+ /* Soft reset the chip. */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+ for (i = 1000; i > 0; i--)
+ if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+ break;
+ else
+ udelay(10);
+
+ /* identify chip attached to board */
+ tmp = RTL_R32(TxConfig);
+ tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24;
+
+ for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--){
+ if (tmp == rtl_chip_info[i].version) {
+ tpc->chipset = i;
+ goto match;
+ }
+ }
+
+ /* if unknown chip, assume array element #0, original RTL-8169 in this case */
+ printf("PCI device %s: unknown chip version, assuming RTL-8169\n", dev->name);
+ printf("PCI device: TxConfig = 0x%lX\n", (unsigned long) RTL_R32(TxConfig));
+ tpc->chipset = 0;
+
+match:
+ return 0;
+}
+
+/*
+ * Cache maintenance functions. These are simple wrappers around the more
+ * general purpose flush_cache() and invalidate_dcache_range() functions.
+ */
+
+static void rtl_inval_rx_desc(struct RxDesc *desc)
+{
+ unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
+ unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN);
+
+ invalidate_dcache_range(start, end);
+}
+
+static void rtl_flush_rx_desc(struct RxDesc *desc)
+{
+ flush_cache((unsigned long)desc, sizeof(*desc));
+}
+
+static void rtl_inval_tx_desc(struct TxDesc *desc)
+{
+ unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
+ unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN);
+
+ invalidate_dcache_range(start, end);
+}
+
+static void rtl_flush_tx_desc(struct TxDesc *desc)
+{
+ flush_cache((unsigned long)desc, sizeof(*desc));
+}
+
+static void rtl_inval_buffer(void *buf, size_t size)
+{
+ unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1);
+ unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN);
+
+ invalidate_dcache_range(start, end);
+}
+
+static void rtl_flush_buffer(void *buf, size_t size)
+{
+ flush_cache((unsigned long)buf, size);
+}
+
+/**************************************************************************
+RECV - Receive a frame
+***************************************************************************/
+static int rtl_recv(struct eth_device *dev)
+{
+ /* return true if there's an ethernet packet ready to read */
+ /* nic->packet should contain data on return */
+ /* nic->packetlen should contain length of data */
+ int cur_rx;
+ int length = 0;
+
+#ifdef DEBUG_RTL8169_RX
+ printf ("%s\n", __FUNCTION__);
+#endif
+ ioaddr = dev->iobase;
+
+ cur_rx = tpc->cur_rx;
+
+ rtl_inval_rx_desc(&tpc->RxDescArray[cur_rx]);
+
+ if ((le32_to_cpu(tpc->RxDescArray[cur_rx].status) & OWNbit) == 0) {
+ if (!(le32_to_cpu(tpc->RxDescArray[cur_rx].status) & RxRES)) {
+ unsigned char rxdata[RX_BUF_LEN];
+ length = (int) (le32_to_cpu(tpc->RxDescArray[cur_rx].
+ status) & 0x00001FFF) - 4;
+
+ rtl_inval_buffer(tpc->RxBufferRing[cur_rx], length);
+ memcpy(rxdata, tpc->RxBufferRing[cur_rx], length);
+ NetReceive(rxdata, length);
+
+ if (cur_rx == NUM_RX_DESC - 1)
+ tpc->RxDescArray[cur_rx].status =
+ cpu_to_le32((OWNbit | EORbit) + RX_BUF_SIZE);
+ else
+ tpc->RxDescArray[cur_rx].status =
+ cpu_to_le32(OWNbit + RX_BUF_SIZE);
+ tpc->RxDescArray[cur_rx].buf_addr =
+ cpu_to_le32(bus_to_phys(tpc->RxBufferRing[cur_rx]));
+ rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]);
+ } else {
+ puts("Error Rx");
+ }
+ cur_rx = (cur_rx + 1) % NUM_RX_DESC;
+ tpc->cur_rx = cur_rx;
+ return 1;
+
+ } else {
+ ushort sts = RTL_R8(IntrStatus);
+ RTL_W8(IntrStatus, sts & ~(TxErr | RxErr | SYSErr));
+ udelay(100); /* wait */
+ }
+ tpc->cur_rx = cur_rx;
+ return (0); /* initially as this is called to flush the input */
+}
+
+#define HZ 1000
+/**************************************************************************
+SEND - Transmit a frame
+***************************************************************************/
+static int rtl_send(struct eth_device *dev, void *packet, int length)
+{
+ /* send the packet to destination */
+
+ u32 to;
+ u8 *ptxb;
+ int entry = tpc->cur_tx % NUM_TX_DESC;
+ u32 len = length;
+ int ret;
+
+#ifdef DEBUG_RTL8169_TX
+ int stime = currticks();
+ printf ("%s\n", __FUNCTION__);
+ printf("sending %d bytes\n", len);
+#endif
+
+ ioaddr = dev->iobase;
+
+ /* point to the current txb incase multiple tx_rings are used */
+ ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
+ memcpy(ptxb, (char *)packet, (int)length);
+ rtl_flush_buffer(ptxb, length);
+
+ while (len < ETH_ZLEN)
+ ptxb[len++] = '\0';
+
+ tpc->TxDescArray[entry].buf_Haddr = 0;
+ tpc->TxDescArray[entry].buf_addr = cpu_to_le32(bus_to_phys(ptxb));
+ if (entry != (NUM_TX_DESC - 1)) {
+ tpc->TxDescArray[entry].status =
+ cpu_to_le32((OWNbit | FSbit | LSbit) |
+ ((len > ETH_ZLEN) ? len : ETH_ZLEN));
+ } else {
+ tpc->TxDescArray[entry].status =
+ cpu_to_le32((OWNbit | EORbit | FSbit | LSbit) |
+ ((len > ETH_ZLEN) ? len : ETH_ZLEN));
+ }
+ rtl_flush_tx_desc(&tpc->TxDescArray[entry]);
+ RTL_W8(TxPoll, 0x40); /* set polling bit */
+
+ tpc->cur_tx++;
+ to = currticks() + TX_TIMEOUT;
+ do {
+ rtl_inval_tx_desc(&tpc->TxDescArray[entry]);
+ } while ((le32_to_cpu(tpc->TxDescArray[entry].status) & OWNbit)
+ && (currticks() < to)); /* wait */
+
+ if (currticks() >= to) {
+#ifdef DEBUG_RTL8169_TX
+ puts("tx timeout/error\n");
+ printf("%s elapsed time : %lu\n", __func__, currticks()-stime);
+#endif
+ ret = 0;
+ } else {
+#ifdef DEBUG_RTL8169_TX
+ puts("tx done\n");
+#endif
+ ret = length;
+ }
+ /* Delay to make net console (nc) work properly */
+ udelay(20);
+ return ret;
+}
+
+static void rtl8169_set_rx_mode(struct eth_device *dev)
+{
+ u32 mc_filter[2]; /* Multicast hash filter */
+ int rx_mode;
+ u32 tmp = 0;
+
+#ifdef DEBUG_RTL8169
+ printf ("%s\n", __FUNCTION__);
+#endif
+
+ /* IFF_ALLMULTI */
+ /* Too many to filter perfectly -- accept all multicasts. */
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+
+ tmp = rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
+ rtl_chip_info[tpc->chipset].RxConfigMask);
+
+ RTL_W32(RxConfig, tmp);
+ RTL_W32(MAR0 + 0, mc_filter[0]);
+ RTL_W32(MAR0 + 4, mc_filter[1]);
+}
+
+static void rtl8169_hw_start(struct eth_device *dev)
+{
+ u32 i;
+
+#ifdef DEBUG_RTL8169
+ int stime = currticks();
+ printf ("%s\n", __FUNCTION__);
+#endif
+
+#if 0
+ /* Soft reset the chip. */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+ for (i = 1000; i > 0; i--) {
+ if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+ break;
+ else
+ udelay(10);
+ }
+#endif
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ /* RTL-8169sb/8110sb or previous version */
+ if (tpc->chipset <= 5)
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ /* For gigabit rtl8169 */
+ RTL_W16(RxMaxSize, RxPacketMaxSize);
+
+ /* Set Rx Config register */
+ i = rtl8169_rx_config | (RTL_R32(RxConfig) &
+ rtl_chip_info[tpc->chipset].RxConfigMask);
+ RTL_W32(RxConfig, i);
+
+ /* Set DMA burst size and Interframe Gap Time */
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
+
+
+ tpc->cur_rx = 0;
+
+ RTL_W32(TxDescStartAddrLow, bus_to_phys(tpc->TxDescArray));
+ RTL_W32(TxDescStartAddrHigh, (unsigned long)0);
+ RTL_W32(RxDescStartAddrLow, bus_to_phys(tpc->RxDescArray));
+ RTL_W32(RxDescStartAddrHigh, (unsigned long)0);
+
+ /* RTL-8169sc/8110sc or later version */
+ if (tpc->chipset > 5)
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+ udelay(10);
+
+ RTL_W32(RxMissed, 0);
+
+ rtl8169_set_rx_mode(dev);
+
+ /* no early-rx interrupts */
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+#ifdef DEBUG_RTL8169
+ printf("%s elapsed time : %lu\n", __func__, currticks()-stime);
+#endif
+}
+
+static void rtl8169_init_ring(struct eth_device *dev)
+{
+ int i;
+
+#ifdef DEBUG_RTL8169
+ int stime = currticks();
+ printf ("%s\n", __FUNCTION__);
+#endif
+
+ tpc->cur_rx = 0;
+ tpc->cur_tx = 0;
+ tpc->dirty_tx = 0;
+ memset(tpc->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc));
+ memset(tpc->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc));
+
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ tpc->Tx_skbuff[i] = &txb[i];
+ }
+
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ if (i == (NUM_RX_DESC - 1))
+ tpc->RxDescArray[i].status =
+ cpu_to_le32((OWNbit | EORbit) + RX_BUF_SIZE);
+ else
+ tpc->RxDescArray[i].status =
+ cpu_to_le32(OWNbit + RX_BUF_SIZE);
+
+ tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
+ tpc->RxDescArray[i].buf_addr =
+ cpu_to_le32(bus_to_phys(tpc->RxBufferRing[i]));
+ rtl_flush_rx_desc(&tpc->RxDescArray[i]);
+ }
+
+#ifdef DEBUG_RTL8169
+ printf("%s elapsed time : %lu\n", __func__, currticks()-stime);
+#endif
+}
+
+/**************************************************************************
+RESET - Finish setting up the ethernet interface
+***************************************************************************/
+static int rtl_reset(struct eth_device *dev, bd_t *bis)
+{
+ int i;
+
+#ifdef DEBUG_RTL8169
+ int stime = currticks();
+ printf ("%s\n", __FUNCTION__);
+#endif
+
+ tpc->TxDescArrays = tx_ring;
+ /* Tx Desscriptor needs 256 bytes alignment; */
+ tpc->TxDescArray = (struct TxDesc *) ((unsigned long)(tpc->TxDescArrays +
+ 255) & ~255);
+
+ tpc->RxDescArrays = rx_ring;
+ /* Rx Desscriptor needs 256 bytes alignment; */
+ tpc->RxDescArray = (struct RxDesc *) ((unsigned long)(tpc->RxDescArrays +
+ 255) & ~255);
+
+ rtl8169_init_ring(dev);
+ rtl8169_hw_start(dev);
+ /* Construct a perfect filter frame with the mac address as first match
+ * and broadcast for all others */
+ for (i = 0; i < 192; i++)
+ txb[i] = 0xFF;
+
+ txb[0] = dev->enetaddr[0];
+ txb[1] = dev->enetaddr[1];
+ txb[2] = dev->enetaddr[2];
+ txb[3] = dev->enetaddr[3];
+ txb[4] = dev->enetaddr[4];
+ txb[5] = dev->enetaddr[5];
+
+#ifdef DEBUG_RTL8169
+ printf("%s elapsed time : %lu\n", __func__, currticks()-stime);
+#endif
+ return 0;
+}
+
+/**************************************************************************
+HALT - Turn off ethernet interface
+***************************************************************************/
+static void rtl_halt(struct eth_device *dev)
+{
+ int i;
+
+#ifdef DEBUG_RTL8169
+ printf ("%s\n", __FUNCTION__);
+#endif
+
+ ioaddr = dev->iobase;
+
+ /* Stop the chip's Tx and Rx DMA processes. */
+ RTL_W8(ChipCmd, 0x00);
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ RTL_W16(IntrMask, 0x0000);
+
+ RTL_W32(RxMissed, 0);
+
+ tpc->TxDescArrays = NULL;
+ tpc->RxDescArrays = NULL;
+ tpc->TxDescArray = NULL;
+ tpc->RxDescArray = NULL;
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ tpc->RxBufferRing[i] = NULL;
+ }
+}
+
+/**************************************************************************
+INIT - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+#define board_found 1
+#define valid_link 0
+static int rtl_init(struct eth_device *dev, bd_t *bis)
+{
+ static int board_idx = -1;
+ int i, rc;
+ int option = -1, Cap10_100 = 0, Cap1000 = 0;
+
+#ifdef DEBUG_RTL8169
+ printf ("%s\n", __FUNCTION__);
+#endif
+
+ ioaddr = dev->iobase;
+
+ board_idx++;
+
+ /* point to private storage */
+ tpc = &tpx;
+
+ rc = rtl8169_init_board(dev);
+ if (rc)
+ return rc;
+
+ /* Get MAC address. FIXME: read EEPROM */
+ for (i = 0; i < MAC_ADDR_LEN; i++)
+ dev->enetaddr[i] = RTL_R8(MAC0 + i);
+
+#ifdef DEBUG_RTL8169
+ printf("chipset = %d\n", tpc->chipset);
+ printf("MAC Address");
+ for (i = 0; i < MAC_ADDR_LEN; i++)
+ printf(":%02x", dev->enetaddr[i]);
+ putc('\n');
+#endif
+
+#ifdef DEBUG_RTL8169
+ /* Print out some hardware info */
+ printf("%s: at ioaddr 0x%x\n", dev->name, ioaddr);
+#endif
+
+ /* if TBI is not endbled */
+ if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
+ int val = mdio_read(PHY_AUTO_NEGO_REG);
+
+ option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
+ /* Force RTL8169 in 10/100/1000 Full/Half mode. */
+ if (option > 0) {
+#ifdef DEBUG_RTL8169
+ printf("%s: Force-mode Enabled.\n", dev->name);
+#endif
+ Cap10_100 = 0, Cap1000 = 0;
+ switch (option) {
+ case _10_Half:
+ Cap10_100 = PHY_Cap_10_Half;
+ Cap1000 = PHY_Cap_Null;
+ break;
+ case _10_Full:
+ Cap10_100 = PHY_Cap_10_Full;
+ Cap1000 = PHY_Cap_Null;
+ break;
+ case _100_Half:
+ Cap10_100 = PHY_Cap_100_Half;
+ Cap1000 = PHY_Cap_Null;
+ break;
+ case _100_Full:
+ Cap10_100 = PHY_Cap_100_Full;
+ Cap1000 = PHY_Cap_Null;
+ break;
+ case _1000_Full:
+ Cap10_100 = PHY_Cap_Null;
+ Cap1000 = PHY_Cap_1000_Full;
+ break;
+ default:
+ break;
+ }
+ mdio_write(PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F)); /* leave PHY_AUTO_NEGO_REG bit4:0 unchanged */
+ mdio_write(PHY_1000_CTRL_REG, Cap1000);
+ } else {
+#ifdef DEBUG_RTL8169
+ printf("%s: Auto-negotiation Enabled.\n",
+ dev->name);
+#endif
+ /* enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged */
+ mdio_write(PHY_AUTO_NEGO_REG,
+ PHY_Cap_10_Half | PHY_Cap_10_Full |
+ PHY_Cap_100_Half | PHY_Cap_100_Full |
+ (val & 0x1F));
+
+ /* enable 1000 Full Mode */
+ mdio_write(PHY_1000_CTRL_REG, PHY_Cap_1000_Full);
+
+ }
+
+ /* Enable auto-negotiation and restart auto-nigotiation */
+ mdio_write(PHY_CTRL_REG,
+ PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
+ udelay(100);
+
+ /* wait for auto-negotiation process */
+ for (i = 10000; i > 0; i--) {
+ /* check if auto-negotiation complete */
+ if (mdio_read(PHY_STAT_REG) & PHY_Auto_Nego_Comp) {
+ udelay(100);
+ option = RTL_R8(PHYstatus);
+ if (option & _1000bpsF) {
+#ifdef DEBUG_RTL8169
+ printf("%s: 1000Mbps Full-duplex operation.\n",
+ dev->name);
+#endif
+ } else {
+#ifdef DEBUG_RTL8169
+ printf("%s: %sMbps %s-duplex operation.\n",
+ dev->name,
+ (option & _100bps) ? "100" :
+ "10",
+ (option & FullDup) ? "Full" :
+ "Half");
+#endif
+ }
+ break;
+ } else {
+ udelay(100);
+ }
+ } /* end for-loop to wait for auto-negotiation process */
+
+ } else {
+ udelay(100);
+#ifdef DEBUG_RTL8169
+ printf
+ ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
+ dev->name,
+ (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
+#endif
+ }
+
+ return 1;
+}
+
+int rtl8169_initialize(bd_t *bis)
+{
+ pci_dev_t devno;
+ int card_number = 0;
+ struct eth_device *dev;
+ u32 iobase;
+ int idx=0;
+
+ while(1){
+ unsigned int region;
+ u16 device;
+
+ /* Find RTL8169 */
+ if ((devno = pci_find_devices(supported, idx++)) < 0)
+ break;
+
+ pci_read_config_word(devno, PCI_DEVICE_ID, &device);
+ switch (device) {
+ case 0x8168:
+ region = 2;
+ break;
+
+ default:
+ region = 1;
+ break;
+ }
+
+ pci_read_config_dword(devno, PCI_BASE_ADDRESS_0 + (region * 4), &iobase);
+ iobase &= ~0xf;
+
+ debug ("rtl8169: REALTEK RTL8169 @0x%x\n", iobase);
+
+ dev = (struct eth_device *)malloc(sizeof *dev);
+ if (!dev) {
+ printf("Can not allocate memory of rtl8169\n");
+ break;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ sprintf (dev->name, "RTL8169#%d", card_number);
+
+ dev->priv = (void *) devno;
+ dev->iobase = (int)pci_mem_to_phys(devno, iobase);
+
+ dev->init = rtl_reset;
+ dev->halt = rtl_halt;
+ dev->send = rtl_send;
+ dev->recv = rtl_recv;
+
+ eth_register (dev);
+
+ rtl_init(dev, bis);
+
+ card_number++;
+ }
+ return card_number;
+}
diff --git a/qemu/roms/u-boot/drivers/net/sh_eth.c b/qemu/roms/u-boot/drivers/net/sh_eth.c
new file mode 100644
index 000000000..5e132f2b5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/sh_eth.c
@@ -0,0 +1,655 @@
+/*
+ * sh_eth.c - Driver for Renesas ethernet controler.
+ *
+ * Copyright (C) 2008, 2011 Renesas Solutions Corp.
+ * Copyright (c) 2008, 2011 Nobuhiro Iwamatsu
+ * Copyright (c) 2007 Carlos Munoz <carlos@kenati.com>
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include "sh_eth.h"
+
+#ifndef CONFIG_SH_ETHER_USE_PORT
+# error "Please define CONFIG_SH_ETHER_USE_PORT"
+#endif
+#ifndef CONFIG_SH_ETHER_PHY_ADDR
+# error "Please define CONFIG_SH_ETHER_PHY_ADDR"
+#endif
+
+#if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && !defined(CONFIG_SYS_DCACHE_OFF)
+#define flush_cache_wback(addr, len) \
+ flush_dcache_range((u32)addr, (u32)(addr + len - 1))
+#else
+#define flush_cache_wback(...)
+#endif
+
+#if defined(CONFIG_SH_ETHER_CACHE_INVALIDATE) && defined(CONFIG_ARM)
+#define invalidate_cache(addr, len) \
+ { \
+ u32 line_size = CONFIG_SH_ETHER_ALIGNE_SIZE; \
+ u32 start, end; \
+ \
+ start = (u32)addr; \
+ end = start + len; \
+ start &= ~(line_size - 1); \
+ end = ((end + line_size - 1) & ~(line_size - 1)); \
+ \
+ invalidate_dcache_range(start, end); \
+ }
+#else
+#define invalidate_cache(...)
+#endif
+
+#define TIMEOUT_CNT 1000
+
+int sh_eth_send(struct eth_device *dev, void *packet, int len)
+{
+ struct sh_eth_dev *eth = dev->priv;
+ int port = eth->port, ret = 0, timeout;
+ struct sh_eth_info *port_info = &eth->port_info[port];
+
+ if (!packet || len > 0xffff) {
+ printf(SHETHER_NAME ": %s: Invalid argument\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* packet must be a 4 byte boundary */
+ if ((int)packet & 3) {
+ printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n", __func__);
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Update tx descriptor */
+ flush_cache_wback(packet, len);
+ port_info->tx_desc_cur->td2 = ADDR_TO_PHY(packet);
+ port_info->tx_desc_cur->td1 = len << 16;
+ /* Must preserve the end of descriptor list indication */
+ if (port_info->tx_desc_cur->td0 & TD_TDLE)
+ port_info->tx_desc_cur->td0 = TD_TACT | TD_TFP | TD_TDLE;
+ else
+ port_info->tx_desc_cur->td0 = TD_TACT | TD_TFP;
+
+ /* Restart the transmitter if disabled */
+ if (!(sh_eth_read(eth, EDTRR) & EDTRR_TRNS))
+ sh_eth_write(eth, EDTRR_TRNS, EDTRR);
+
+ /* Wait until packet is transmitted */
+ timeout = TIMEOUT_CNT;
+ do {
+ invalidate_cache(port_info->tx_desc_cur,
+ sizeof(struct tx_desc_s));
+ udelay(100);
+ } while (port_info->tx_desc_cur->td0 & TD_TACT && timeout--);
+
+ if (timeout < 0) {
+ printf(SHETHER_NAME ": transmit timeout\n");
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ port_info->tx_desc_cur++;
+ if (port_info->tx_desc_cur >= port_info->tx_desc_base + NUM_TX_DESC)
+ port_info->tx_desc_cur = port_info->tx_desc_base;
+
+err:
+ return ret;
+}
+
+int sh_eth_recv(struct eth_device *dev)
+{
+ struct sh_eth_dev *eth = dev->priv;
+ int port = eth->port, len = 0;
+ struct sh_eth_info *port_info = &eth->port_info[port];
+ uchar *packet;
+
+ /* Check if the rx descriptor is ready */
+ invalidate_cache(port_info->rx_desc_cur, sizeof(struct rx_desc_s));
+ if (!(port_info->rx_desc_cur->rd0 & RD_RACT)) {
+ /* Check for errors */
+ if (!(port_info->rx_desc_cur->rd0 & RD_RFE)) {
+ len = port_info->rx_desc_cur->rd1 & 0xffff;
+ packet = (uchar *)
+ ADDR_TO_P2(port_info->rx_desc_cur->rd2);
+ invalidate_cache(packet, len);
+ NetReceive(packet, len);
+ }
+
+ /* Make current descriptor available again */
+ if (port_info->rx_desc_cur->rd0 & RD_RDLE)
+ port_info->rx_desc_cur->rd0 = RD_RACT | RD_RDLE;
+ else
+ port_info->rx_desc_cur->rd0 = RD_RACT;
+ /* Point to the next descriptor */
+ port_info->rx_desc_cur++;
+ if (port_info->rx_desc_cur >=
+ port_info->rx_desc_base + NUM_RX_DESC)
+ port_info->rx_desc_cur = port_info->rx_desc_base;
+ }
+
+ /* Restart the receiver if disabled */
+ if (!(sh_eth_read(eth, EDRRR) & EDRRR_R))
+ sh_eth_write(eth, EDRRR_R, EDRRR);
+
+ return len;
+}
+
+static int sh_eth_reset(struct sh_eth_dev *eth)
+{
+#if defined(SH_ETH_TYPE_GETHER)
+ int ret = 0, i;
+
+ /* Start e-dmac transmitter and receiver */
+ sh_eth_write(eth, EDSR_ENALL, EDSR);
+
+ /* Perform a software reset and wait for it to complete */
+ sh_eth_write(eth, EDMR_SRST, EDMR);
+ for (i = 0; i < TIMEOUT_CNT ; i++) {
+ if (!(sh_eth_read(eth, EDMR) & EDMR_SRST))
+ break;
+ udelay(1000);
+ }
+
+ if (i == TIMEOUT_CNT) {
+ printf(SHETHER_NAME ": Software reset timeout\n");
+ ret = -EIO;
+ }
+
+ return ret;
+#else
+ sh_eth_write(eth, sh_eth_read(eth, EDMR) | EDMR_SRST, EDMR);
+ udelay(3000);
+ sh_eth_write(eth, sh_eth_read(eth, EDMR) & ~EDMR_SRST, EDMR);
+
+ return 0;
+#endif
+}
+
+static int sh_eth_tx_desc_init(struct sh_eth_dev *eth)
+{
+ int port = eth->port, i, ret = 0;
+ u32 tmp_addr;
+ struct sh_eth_info *port_info = &eth->port_info[port];
+ struct tx_desc_s *cur_tx_desc;
+
+ /*
+ * Allocate tx descriptors. They must be TX_DESC_SIZE bytes aligned
+ */
+ port_info->tx_desc_malloc = malloc(NUM_TX_DESC *
+ sizeof(struct tx_desc_s) +
+ TX_DESC_SIZE - 1);
+ if (!port_info->tx_desc_malloc) {
+ printf(SHETHER_NAME ": malloc failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ tmp_addr = (u32) (((int)port_info->tx_desc_malloc + TX_DESC_SIZE - 1) &
+ ~(TX_DESC_SIZE - 1));
+ flush_cache_wback(tmp_addr, NUM_TX_DESC * sizeof(struct tx_desc_s));
+ /* Make sure we use a P2 address (non-cacheable) */
+ port_info->tx_desc_base = (struct tx_desc_s *)ADDR_TO_P2(tmp_addr);
+ port_info->tx_desc_cur = port_info->tx_desc_base;
+
+ /* Initialize all descriptors */
+ for (cur_tx_desc = port_info->tx_desc_base, i = 0; i < NUM_TX_DESC;
+ cur_tx_desc++, i++) {
+ cur_tx_desc->td0 = 0x00;
+ cur_tx_desc->td1 = 0x00;
+ cur_tx_desc->td2 = 0x00;
+ }
+
+ /* Mark the end of the descriptors */
+ cur_tx_desc--;
+ cur_tx_desc->td0 |= TD_TDLE;
+
+ /* Point the controller to the tx descriptor list. Must use physical
+ addresses */
+ sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDLAR);
+#if defined(SH_ETH_TYPE_GETHER)
+ sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDFAR);
+ sh_eth_write(eth, ADDR_TO_PHY(cur_tx_desc), TDFXR);
+ sh_eth_write(eth, 0x01, TDFFR);/* Last discriptor bit */
+#endif
+
+err:
+ return ret;
+}
+
+static int sh_eth_rx_desc_init(struct sh_eth_dev *eth)
+{
+ int port = eth->port, i , ret = 0;
+ struct sh_eth_info *port_info = &eth->port_info[port];
+ struct rx_desc_s *cur_rx_desc;
+ u32 tmp_addr;
+ u8 *rx_buf;
+
+ /*
+ * Allocate rx descriptors. They must be RX_DESC_SIZE bytes aligned
+ */
+ port_info->rx_desc_malloc = malloc(NUM_RX_DESC *
+ sizeof(struct rx_desc_s) +
+ RX_DESC_SIZE - 1);
+ if (!port_info->rx_desc_malloc) {
+ printf(SHETHER_NAME ": malloc failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ tmp_addr = (u32) (((int)port_info->rx_desc_malloc + RX_DESC_SIZE - 1) &
+ ~(RX_DESC_SIZE - 1));
+ flush_cache_wback(tmp_addr, NUM_RX_DESC * sizeof(struct rx_desc_s));
+ /* Make sure we use a P2 address (non-cacheable) */
+ port_info->rx_desc_base = (struct rx_desc_s *)ADDR_TO_P2(tmp_addr);
+
+ port_info->rx_desc_cur = port_info->rx_desc_base;
+
+ /*
+ * Allocate rx data buffers. They must be 32 bytes aligned and in
+ * P2 area
+ */
+ port_info->rx_buf_malloc = malloc(
+ NUM_RX_DESC * MAX_BUF_SIZE + RX_BUF_ALIGNE_SIZE - 1);
+ if (!port_info->rx_buf_malloc) {
+ printf(SHETHER_NAME ": malloc failed\n");
+ ret = -ENOMEM;
+ goto err_buf_malloc;
+ }
+
+ tmp_addr = (u32)(((int)port_info->rx_buf_malloc
+ + (RX_BUF_ALIGNE_SIZE - 1)) &
+ ~(RX_BUF_ALIGNE_SIZE - 1));
+ port_info->rx_buf_base = (u8 *)ADDR_TO_P2(tmp_addr);
+
+ /* Initialize all descriptors */
+ for (cur_rx_desc = port_info->rx_desc_base,
+ rx_buf = port_info->rx_buf_base, i = 0;
+ i < NUM_RX_DESC; cur_rx_desc++, rx_buf += MAX_BUF_SIZE, i++) {
+ cur_rx_desc->rd0 = RD_RACT;
+ cur_rx_desc->rd1 = MAX_BUF_SIZE << 16;
+ cur_rx_desc->rd2 = (u32) ADDR_TO_PHY(rx_buf);
+ }
+
+ /* Mark the end of the descriptors */
+ cur_rx_desc--;
+ cur_rx_desc->rd0 |= RD_RDLE;
+
+ /* Point the controller to the rx descriptor list */
+ sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR);
+#if defined(SH_ETH_TYPE_GETHER)
+ sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDFAR);
+ sh_eth_write(eth, ADDR_TO_PHY(cur_rx_desc), RDFXR);
+ sh_eth_write(eth, RDFFR_RDLF, RDFFR);
+#endif
+
+ return ret;
+
+err_buf_malloc:
+ free(port_info->rx_desc_malloc);
+ port_info->rx_desc_malloc = NULL;
+
+err:
+ return ret;
+}
+
+static void sh_eth_tx_desc_free(struct sh_eth_dev *eth)
+{
+ int port = eth->port;
+ struct sh_eth_info *port_info = &eth->port_info[port];
+
+ if (port_info->tx_desc_malloc) {
+ free(port_info->tx_desc_malloc);
+ port_info->tx_desc_malloc = NULL;
+ }
+}
+
+static void sh_eth_rx_desc_free(struct sh_eth_dev *eth)
+{
+ int port = eth->port;
+ struct sh_eth_info *port_info = &eth->port_info[port];
+
+ if (port_info->rx_desc_malloc) {
+ free(port_info->rx_desc_malloc);
+ port_info->rx_desc_malloc = NULL;
+ }
+
+ if (port_info->rx_buf_malloc) {
+ free(port_info->rx_buf_malloc);
+ port_info->rx_buf_malloc = NULL;
+ }
+}
+
+static int sh_eth_desc_init(struct sh_eth_dev *eth)
+{
+ int ret = 0;
+
+ ret = sh_eth_tx_desc_init(eth);
+ if (ret)
+ goto err_tx_init;
+
+ ret = sh_eth_rx_desc_init(eth);
+ if (ret)
+ goto err_rx_init;
+
+ return ret;
+err_rx_init:
+ sh_eth_tx_desc_free(eth);
+
+err_tx_init:
+ return ret;
+}
+
+static int sh_eth_phy_config(struct sh_eth_dev *eth)
+{
+ int port = eth->port, ret = 0;
+ struct sh_eth_info *port_info = &eth->port_info[port];
+ struct eth_device *dev = port_info->dev;
+ struct phy_device *phydev;
+
+ phydev = phy_connect(
+ miiphy_get_dev_by_name(dev->name),
+ port_info->phy_addr, dev, CONFIG_SH_ETHER_PHY_MODE);
+ port_info->phydev = phydev;
+ phy_config(phydev);
+
+ return ret;
+}
+
+static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
+{
+ int port = eth->port, ret = 0;
+ u32 val;
+ struct sh_eth_info *port_info = &eth->port_info[port];
+ struct eth_device *dev = port_info->dev;
+ struct phy_device *phy;
+
+ /* Configure e-dmac registers */
+ sh_eth_write(eth, (sh_eth_read(eth, EDMR) & ~EMDR_DESC_R) |
+ (EMDR_DESC | EDMR_EL), EDMR);
+
+ sh_eth_write(eth, 0, EESIPR);
+ sh_eth_write(eth, 0, TRSCER);
+ sh_eth_write(eth, 0, TFTR);
+ sh_eth_write(eth, (FIFO_SIZE_T | FIFO_SIZE_R), FDR);
+ sh_eth_write(eth, RMCR_RST, RMCR);
+#if defined(SH_ETH_TYPE_GETHER)
+ sh_eth_write(eth, 0, RPADIR);
+#endif
+ sh_eth_write(eth, (FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR);
+
+ /* Configure e-mac registers */
+ sh_eth_write(eth, 0, ECSIPR);
+
+ /* Set Mac address */
+ val = dev->enetaddr[0] << 24 | dev->enetaddr[1] << 16 |
+ dev->enetaddr[2] << 8 | dev->enetaddr[3];
+ sh_eth_write(eth, val, MAHR);
+
+ val = dev->enetaddr[4] << 8 | dev->enetaddr[5];
+ sh_eth_write(eth, val, MALR);
+
+ sh_eth_write(eth, RFLR_RFL_MIN, RFLR);
+#if defined(SH_ETH_TYPE_GETHER)
+ sh_eth_write(eth, 0, PIPR);
+ sh_eth_write(eth, APR_AP, APR);
+ sh_eth_write(eth, MPR_MP, MPR);
+ sh_eth_write(eth, TPAUSER_TPAUSE, TPAUSER);
+#endif
+
+#if defined(CONFIG_CPU_SH7734) || defined(CONFIG_R8A7740)
+ sh_eth_write(eth, CONFIG_SH_ETHER_SH7734_MII, RMII_MII);
+#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791)
+ sh_eth_write(eth, sh_eth_read(eth, RMIIMR) | 0x1, RMIIMR);
+#endif
+ /* Configure phy */
+ ret = sh_eth_phy_config(eth);
+ if (ret) {
+ printf(SHETHER_NAME ": phy config timeout\n");
+ goto err_phy_cfg;
+ }
+ phy = port_info->phydev;
+ ret = phy_startup(phy);
+ if (ret) {
+ printf(SHETHER_NAME ": phy startup failure\n");
+ return ret;
+ }
+
+ val = 0;
+
+ /* Set the transfer speed */
+ if (phy->speed == 100) {
+ printf(SHETHER_NAME ": 100Base/");
+#if defined(SH_ETH_TYPE_GETHER)
+ sh_eth_write(eth, GECMR_100B, GECMR);
+#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)
+ sh_eth_write(eth, 1, RTRATE);
+#elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_R8A7790) || \
+ defined(CONFIG_R8A7791)
+ val = ECMR_RTM;
+#endif
+ } else if (phy->speed == 10) {
+ printf(SHETHER_NAME ": 10Base/");
+#if defined(SH_ETH_TYPE_GETHER)
+ sh_eth_write(eth, GECMR_10B, GECMR);
+#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)
+ sh_eth_write(eth, 0, RTRATE);
+#endif
+ }
+#if defined(SH_ETH_TYPE_GETHER)
+ else if (phy->speed == 1000) {
+ printf(SHETHER_NAME ": 1000Base/");
+ sh_eth_write(eth, GECMR_1000B, GECMR);
+ }
+#endif
+
+ /* Check if full duplex mode is supported by the phy */
+ if (phy->duplex) {
+ printf("Full\n");
+ sh_eth_write(eth, val | (ECMR_CHG_DM|ECMR_RE|ECMR_TE|ECMR_DM),
+ ECMR);
+ } else {
+ printf("Half\n");
+ sh_eth_write(eth, val | (ECMR_CHG_DM|ECMR_RE|ECMR_TE), ECMR);
+ }
+
+ return ret;
+
+err_phy_cfg:
+ return ret;
+}
+
+static void sh_eth_start(struct sh_eth_dev *eth)
+{
+ /*
+ * Enable the e-dmac receiver only. The transmitter will be enabled when
+ * we have something to transmit
+ */
+ sh_eth_write(eth, EDRRR_R, EDRRR);
+}
+
+static void sh_eth_stop(struct sh_eth_dev *eth)
+{
+ sh_eth_write(eth, ~EDRRR_R, EDRRR);
+}
+
+int sh_eth_init(struct eth_device *dev, bd_t *bd)
+{
+ int ret = 0;
+ struct sh_eth_dev *eth = dev->priv;
+
+ ret = sh_eth_reset(eth);
+ if (ret)
+ goto err;
+
+ ret = sh_eth_desc_init(eth);
+ if (ret)
+ goto err;
+
+ ret = sh_eth_config(eth, bd);
+ if (ret)
+ goto err_config;
+
+ sh_eth_start(eth);
+
+ return ret;
+
+err_config:
+ sh_eth_tx_desc_free(eth);
+ sh_eth_rx_desc_free(eth);
+
+err:
+ return ret;
+}
+
+void sh_eth_halt(struct eth_device *dev)
+{
+ struct sh_eth_dev *eth = dev->priv;
+ sh_eth_stop(eth);
+}
+
+int sh_eth_initialize(bd_t *bd)
+{
+ int ret = 0;
+ struct sh_eth_dev *eth = NULL;
+ struct eth_device *dev = NULL;
+
+ eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev));
+ if (!eth) {
+ printf(SHETHER_NAME ": %s: malloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ if (!dev) {
+ printf(SHETHER_NAME ": %s: malloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+ memset(dev, 0, sizeof(struct eth_device));
+ memset(eth, 0, sizeof(struct sh_eth_dev));
+
+ eth->port = CONFIG_SH_ETHER_USE_PORT;
+ eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR;
+
+ dev->priv = (void *)eth;
+ dev->iobase = 0;
+ dev->init = sh_eth_init;
+ dev->halt = sh_eth_halt;
+ dev->send = sh_eth_send;
+ dev->recv = sh_eth_recv;
+ eth->port_info[eth->port].dev = dev;
+
+ sprintf(dev->name, SHETHER_NAME);
+
+ /* Register Device to EtherNet subsystem */
+ eth_register(dev);
+
+ bb_miiphy_buses[0].priv = eth;
+ miiphy_register(dev->name, bb_miiphy_read, bb_miiphy_write);
+
+ if (!eth_getenv_enetaddr("ethaddr", dev->enetaddr))
+ puts("Please set MAC address\n");
+
+ return ret;
+
+err:
+ if (dev)
+ free(dev);
+
+ if (eth)
+ free(eth);
+
+ printf(SHETHER_NAME ": Failed\n");
+ return ret;
+}
+
+/******* for bb_miiphy *******/
+static int sh_eth_bb_init(struct bb_miiphy_bus *bus)
+{
+ return 0;
+}
+
+static int sh_eth_bb_mdio_active(struct bb_miiphy_bus *bus)
+{
+ struct sh_eth_dev *eth = bus->priv;
+
+ sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MMD, PIR);
+
+ return 0;
+}
+
+static int sh_eth_bb_mdio_tristate(struct bb_miiphy_bus *bus)
+{
+ struct sh_eth_dev *eth = bus->priv;
+
+ sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MMD, PIR);
+
+ return 0;
+}
+
+static int sh_eth_bb_set_mdio(struct bb_miiphy_bus *bus, int v)
+{
+ struct sh_eth_dev *eth = bus->priv;
+
+ if (v)
+ sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MDO, PIR);
+ else
+ sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MDO, PIR);
+
+ return 0;
+}
+
+static int sh_eth_bb_get_mdio(struct bb_miiphy_bus *bus, int *v)
+{
+ struct sh_eth_dev *eth = bus->priv;
+
+ *v = (sh_eth_read(eth, PIR) & PIR_MDI) >> 3;
+
+ return 0;
+}
+
+static int sh_eth_bb_set_mdc(struct bb_miiphy_bus *bus, int v)
+{
+ struct sh_eth_dev *eth = bus->priv;
+
+ if (v)
+ sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MDC, PIR);
+ else
+ sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MDC, PIR);
+
+ return 0;
+}
+
+static int sh_eth_bb_delay(struct bb_miiphy_bus *bus)
+{
+ udelay(10);
+
+ return 0;
+}
+
+struct bb_miiphy_bus bb_miiphy_buses[] = {
+ {
+ .name = "sh_eth",
+ .init = sh_eth_bb_init,
+ .mdio_active = sh_eth_bb_mdio_active,
+ .mdio_tristate = sh_eth_bb_mdio_tristate,
+ .set_mdio = sh_eth_bb_set_mdio,
+ .get_mdio = sh_eth_bb_get_mdio,
+ .set_mdc = sh_eth_bb_set_mdc,
+ .delay = sh_eth_bb_delay,
+ }
+};
+int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);
diff --git a/qemu/roms/u-boot/drivers/net/sh_eth.h b/qemu/roms/u-boot/drivers/net/sh_eth.h
new file mode 100644
index 000000000..331c07cb5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/sh_eth.h
@@ -0,0 +1,624 @@
+/*
+ * sh_eth.h - Driver for Renesas SuperH ethernet controler.
+ *
+ * Copyright (C) 2008 - 2012 Renesas Solutions Corp.
+ * Copyright (c) 2008 - 2012 Nobuhiro Iwamatsu
+ * Copyright (c) 2007 Carlos Munoz <carlos@kenati.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <netdev.h>
+#include <asm/types.h>
+
+#define SHETHER_NAME "sh_eth"
+
+#if defined(CONFIG_SH)
+/* Malloc returns addresses in the P1 area (cacheable). However we need to
+ use area P2 (non-cacheable) */
+#define ADDR_TO_P2(addr) ((((int)(addr) & ~0xe0000000) | 0xa0000000))
+
+/* The ethernet controller needs to use physical addresses */
+#if defined(CONFIG_SH_32BIT)
+#define ADDR_TO_PHY(addr) ((((int)(addr) & ~0xe0000000) | 0x40000000))
+#else
+#define ADDR_TO_PHY(addr) ((int)(addr) & ~0xe0000000)
+#endif
+#elif defined(CONFIG_ARM)
+#define inl readl
+#define outl writel
+#define ADDR_TO_PHY(addr) ((int)(addr))
+#define ADDR_TO_P2(addr) (addr)
+#endif /* defined(CONFIG_SH) */
+
+/* base padding size is 16 */
+#ifndef CONFIG_SH_ETHER_ALIGNE_SIZE
+#define CONFIG_SH_ETHER_ALIGNE_SIZE 16
+#endif
+
+/* Number of supported ports */
+#define MAX_PORT_NUM 2
+
+/* Buffers must be big enough to hold the largest ethernet frame. Also, rx
+ buffers must be a multiple of 32 bytes */
+#define MAX_BUF_SIZE (48 * 32)
+
+/* The number of tx descriptors must be large enough to point to 5 or more
+ frames. If each frame uses 2 descriptors, at least 10 descriptors are needed.
+ We use one descriptor per frame */
+#define NUM_TX_DESC 8
+
+/* The size of the tx descriptor is determined by how much padding is used.
+ 4, 20, or 52 bytes of padding can be used */
+#define TX_DESC_PADDING (CONFIG_SH_ETHER_ALIGNE_SIZE - 12)
+/* same as CONFIG_SH_ETHER_ALIGNE_SIZE */
+#define TX_DESC_SIZE (12 + TX_DESC_PADDING)
+
+/* Tx descriptor. We always use 3 bytes of padding */
+struct tx_desc_s {
+ volatile u32 td0;
+ u32 td1;
+ u32 td2; /* Buffer start */
+ u8 padding[TX_DESC_PADDING]; /* aligned cache line size */
+};
+
+/* There is no limitation in the number of rx descriptors */
+#define NUM_RX_DESC 8
+
+/* The size of the rx descriptor is determined by how much padding is used.
+ 4, 20, or 52 bytes of padding can be used */
+#define RX_DESC_PADDING (CONFIG_SH_ETHER_ALIGNE_SIZE - 12)
+/* same as CONFIG_SH_ETHER_ALIGNE_SIZE */
+#define RX_DESC_SIZE (12 + RX_DESC_PADDING)
+/* aligned cache line size */
+#define RX_BUF_ALIGNE_SIZE (CONFIG_SH_ETHER_ALIGNE_SIZE > 32 ? 64 : 32)
+
+/* Rx descriptor. We always use 4 bytes of padding */
+struct rx_desc_s {
+ volatile u32 rd0;
+ volatile u32 rd1;
+ u32 rd2; /* Buffer start */
+ u8 padding[TX_DESC_PADDING]; /* aligned cache line size */
+};
+
+struct sh_eth_info {
+ struct tx_desc_s *tx_desc_malloc;
+ struct tx_desc_s *tx_desc_base;
+ struct tx_desc_s *tx_desc_cur;
+ struct rx_desc_s *rx_desc_malloc;
+ struct rx_desc_s *rx_desc_base;
+ struct rx_desc_s *rx_desc_cur;
+ u8 *rx_buf_malloc;
+ u8 *rx_buf_base;
+ u8 mac_addr[6];
+ u8 phy_addr;
+ struct eth_device *dev;
+ struct phy_device *phydev;
+};
+
+struct sh_eth_dev {
+ int port;
+ struct sh_eth_info port_info[MAX_PORT_NUM];
+};
+
+/* from linux/drivers/net/ethernet/renesas/sh_eth.h */
+enum {
+ /* E-DMAC registers */
+ EDSR = 0,
+ EDMR,
+ EDTRR,
+ EDRRR,
+ EESR,
+ EESIPR,
+ TDLAR,
+ TDFAR,
+ TDFXR,
+ TDFFR,
+ RDLAR,
+ RDFAR,
+ RDFXR,
+ RDFFR,
+ TRSCER,
+ RMFCR,
+ TFTR,
+ FDR,
+ RMCR,
+ EDOCR,
+ TFUCR,
+ RFOCR,
+ FCFTR,
+ RPADIR,
+ TRIMD,
+ RBWAR,
+ TBRAR,
+
+ /* Ether registers */
+ ECMR,
+ ECSR,
+ ECSIPR,
+ PIR,
+ PSR,
+ RDMLR,
+ PIPR,
+ RFLR,
+ IPGR,
+ APR,
+ MPR,
+ PFTCR,
+ PFRCR,
+ RFCR,
+ RFCF,
+ TPAUSER,
+ TPAUSECR,
+ BCFR,
+ BCFRR,
+ GECMR,
+ BCULR,
+ MAHR,
+ MALR,
+ TROCR,
+ CDCR,
+ LCCR,
+ CNDCR,
+ CEFCR,
+ FRECR,
+ TSFRCR,
+ TLFRCR,
+ CERCR,
+ CEECR,
+ RMIIMR, /* R8A7790 */
+ MAFCR,
+ RTRATE,
+ CSMR,
+ RMII_MII,
+
+ /* This value must be written at last. */
+ SH_ETH_MAX_REGISTER_OFFSET,
+};
+
+static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [EDSR] = 0x0000,
+ [EDMR] = 0x0400,
+ [EDTRR] = 0x0408,
+ [EDRRR] = 0x0410,
+ [EESR] = 0x0428,
+ [EESIPR] = 0x0430,
+ [TDLAR] = 0x0010,
+ [TDFAR] = 0x0014,
+ [TDFXR] = 0x0018,
+ [TDFFR] = 0x001c,
+ [RDLAR] = 0x0030,
+ [RDFAR] = 0x0034,
+ [RDFXR] = 0x0038,
+ [RDFFR] = 0x003c,
+ [TRSCER] = 0x0438,
+ [RMFCR] = 0x0440,
+ [TFTR] = 0x0448,
+ [FDR] = 0x0450,
+ [RMCR] = 0x0458,
+ [RPADIR] = 0x0460,
+ [FCFTR] = 0x0468,
+ [CSMR] = 0x04E4,
+
+ [ECMR] = 0x0500,
+ [ECSR] = 0x0510,
+ [ECSIPR] = 0x0518,
+ [PIR] = 0x0520,
+ [PSR] = 0x0528,
+ [PIPR] = 0x052c,
+ [RFLR] = 0x0508,
+ [APR] = 0x0554,
+ [MPR] = 0x0558,
+ [PFTCR] = 0x055c,
+ [PFRCR] = 0x0560,
+ [TPAUSER] = 0x0564,
+ [GECMR] = 0x05b0,
+ [BCULR] = 0x05b4,
+ [MAHR] = 0x05c0,
+ [MALR] = 0x05c8,
+ [TROCR] = 0x0700,
+ [CDCR] = 0x0708,
+ [LCCR] = 0x0710,
+ [CEFCR] = 0x0740,
+ [FRECR] = 0x0748,
+ [TSFRCR] = 0x0750,
+ [TLFRCR] = 0x0758,
+ [RFCR] = 0x0760,
+ [CERCR] = 0x0768,
+ [CEECR] = 0x0770,
+ [MAFCR] = 0x0778,
+ [RMII_MII] = 0x0790,
+};
+
+static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [ECMR] = 0x0100,
+ [RFLR] = 0x0108,
+ [ECSR] = 0x0110,
+ [ECSIPR] = 0x0118,
+ [PIR] = 0x0120,
+ [PSR] = 0x0128,
+ [RDMLR] = 0x0140,
+ [IPGR] = 0x0150,
+ [APR] = 0x0154,
+ [MPR] = 0x0158,
+ [TPAUSER] = 0x0164,
+ [RFCF] = 0x0160,
+ [TPAUSECR] = 0x0168,
+ [BCFRR] = 0x016c,
+ [MAHR] = 0x01c0,
+ [MALR] = 0x01c8,
+ [TROCR] = 0x01d0,
+ [CDCR] = 0x01d4,
+ [LCCR] = 0x01d8,
+ [CNDCR] = 0x01dc,
+ [CEFCR] = 0x01e4,
+ [FRECR] = 0x01e8,
+ [TSFRCR] = 0x01ec,
+ [TLFRCR] = 0x01f0,
+ [RFCR] = 0x01f4,
+ [MAFCR] = 0x01f8,
+ [RTRATE] = 0x01fc,
+
+ [EDMR] = 0x0000,
+ [EDTRR] = 0x0008,
+ [EDRRR] = 0x0010,
+ [TDLAR] = 0x0018,
+ [RDLAR] = 0x0020,
+ [EESR] = 0x0028,
+ [EESIPR] = 0x0030,
+ [TRSCER] = 0x0038,
+ [RMFCR] = 0x0040,
+ [TFTR] = 0x0048,
+ [FDR] = 0x0050,
+ [RMCR] = 0x0058,
+ [TFUCR] = 0x0064,
+ [RFOCR] = 0x0068,
+ [RMIIMR] = 0x006C,
+ [FCFTR] = 0x0070,
+ [RPADIR] = 0x0078,
+ [TRIMD] = 0x007c,
+ [RBWAR] = 0x00c8,
+ [RDFAR] = 0x00cc,
+ [TBRAR] = 0x00d4,
+ [TDFAR] = 0x00d8,
+};
+
+/* Register Address */
+#if defined(CONFIG_CPU_SH7763) || defined(CONFIG_CPU_SH7734)
+#define SH_ETH_TYPE_GETHER
+#define BASE_IO_ADDR 0xfee00000
+#elif defined(CONFIG_CPU_SH7757) || \
+ defined(CONFIG_CPU_SH7752) || \
+ defined(CONFIG_CPU_SH7753)
+#if defined(CONFIG_SH_ETHER_USE_GETHER)
+#define SH_ETH_TYPE_GETHER
+#define BASE_IO_ADDR 0xfee00000
+#else
+#define SH_ETH_TYPE_ETHER
+#define BASE_IO_ADDR 0xfef00000
+#endif
+#elif defined(CONFIG_CPU_SH7724)
+#define SH_ETH_TYPE_ETHER
+#define BASE_IO_ADDR 0xA4600000
+#elif defined(CONFIG_R8A7740)
+#define SH_ETH_TYPE_GETHER
+#define BASE_IO_ADDR 0xE9A00000
+#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791)
+#define SH_ETH_TYPE_ETHER
+#define BASE_IO_ADDR 0xEE700200
+#endif
+
+/*
+ * Register's bits
+ * Copy from Linux driver source code
+ */
+#if defined(SH_ETH_TYPE_GETHER)
+/* EDSR */
+enum EDSR_BIT {
+ EDSR_ENT = 0x01, EDSR_ENR = 0x02,
+};
+#define EDSR_ENALL (EDSR_ENT|EDSR_ENR)
+#endif
+
+/* EDMR */
+enum DMAC_M_BIT {
+ EDMR_DL1 = 0x20, EDMR_DL0 = 0x10,
+#if defined(SH_ETH_TYPE_GETHER)
+ EDMR_SRST = 0x03, /* Receive/Send reset */
+ EMDR_DESC_R = 0x30, /* Descriptor reserve size */
+ EDMR_EL = 0x40, /* Litte endian */
+#elif defined(SH_ETH_TYPE_ETHER)
+ EDMR_SRST = 0x01,
+ EMDR_DESC_R = 0x30, /* Descriptor reserve size */
+ EDMR_EL = 0x40, /* Litte endian */
+#else
+ EDMR_SRST = 0x01,
+#endif
+};
+
+#if CONFIG_SH_ETHER_ALIGNE_SIZE == 64
+# define EMDR_DESC EDMR_DL1
+#elif CONFIG_SH_ETHER_ALIGNE_SIZE == 32
+# define EMDR_DESC EDMR_DL0
+#elif CONFIG_SH_ETHER_ALIGNE_SIZE == 16 /* Default */
+# define EMDR_DESC 0
+#endif
+
+/* RFLR */
+#define RFLR_RFL_MIN 0x05EE /* Recv Frame length 1518 byte */
+
+/* EDTRR */
+enum DMAC_T_BIT {
+#if defined(SH_ETH_TYPE_GETHER)
+ EDTRR_TRNS = 0x03,
+#else
+ EDTRR_TRNS = 0x01,
+#endif
+};
+
+/* GECMR */
+enum GECMR_BIT {
+#if defined(CONFIG_CPU_SH7757) || \
+ defined(CONFIG_CPU_SH7752) || \
+ defined(CONFIG_CPU_SH7753)
+ GECMR_1000B = 0x20, GECMR_100B = 0x01, GECMR_10B = 0x00,
+#else
+ GECMR_1000B = 0x01, GECMR_100B = 0x04, GECMR_10B = 0x00,
+#endif
+};
+
+/* EDRRR*/
+enum EDRRR_R_BIT {
+ EDRRR_R = 0x01,
+};
+
+/* TPAUSER */
+enum TPAUSER_BIT {
+ TPAUSER_TPAUSE = 0x0000ffff,
+ TPAUSER_UNLIMITED = 0,
+};
+
+/* BCFR */
+enum BCFR_BIT {
+ BCFR_RPAUSE = 0x0000ffff,
+ BCFR_UNLIMITED = 0,
+};
+
+/* PIR */
+enum PIR_BIT {
+ PIR_MDI = 0x08, PIR_MDO = 0x04, PIR_MMD = 0x02, PIR_MDC = 0x01,
+};
+
+/* PSR */
+enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, };
+
+/* EESR */
+enum EESR_BIT {
+
+#if defined(SH_ETH_TYPE_ETHER)
+ EESR_TWB = 0x40000000,
+#else
+ EESR_TWB = 0xC0000000,
+ EESR_TC1 = 0x20000000,
+ EESR_TUC = 0x10000000,
+ EESR_ROC = 0x80000000,
+#endif
+ EESR_TABT = 0x04000000,
+ EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000,
+#if defined(SH_ETH_TYPE_ETHER)
+ EESR_ADE = 0x00800000,
+#endif
+ EESR_ECI = 0x00400000,
+ EESR_FTC = 0x00200000, EESR_TDE = 0x00100000,
+ EESR_TFE = 0x00080000, EESR_FRC = 0x00040000,
+ EESR_RDE = 0x00020000, EESR_RFE = 0x00010000,
+#if defined(SH_ETH_TYPE_ETHER)
+ EESR_CND = 0x00000800,
+#endif
+ EESR_DLC = 0x00000400,
+ EESR_CD = 0x00000200, EESR_RTO = 0x00000100,
+ EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040,
+ EESR_CELF = 0x00000020, EESR_RRF = 0x00000010,
+ rESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004,
+ EESR_PRE = 0x00000002, EESR_CERF = 0x00000001,
+};
+
+
+#if defined(SH_ETH_TYPE_GETHER)
+# define TX_CHECK (EESR_TC1 | EESR_FTC)
+# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \
+ | EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI)
+# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE)
+
+#else
+# define TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO)
+# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \
+ | EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI)
+# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE)
+#endif
+
+/* EESIPR */
+enum DMAC_IM_BIT {
+ DMAC_M_TWB = 0x40000000, DMAC_M_TABT = 0x04000000,
+ DMAC_M_RABT = 0x02000000,
+ DMAC_M_RFRMER = 0x01000000, DMAC_M_ADF = 0x00800000,
+ DMAC_M_ECI = 0x00400000, DMAC_M_FTC = 0x00200000,
+ DMAC_M_TDE = 0x00100000, DMAC_M_TFE = 0x00080000,
+ DMAC_M_FRC = 0x00040000, DMAC_M_RDE = 0x00020000,
+ DMAC_M_RFE = 0x00010000, DMAC_M_TINT4 = 0x00000800,
+ DMAC_M_TINT3 = 0x00000400, DMAC_M_TINT2 = 0x00000200,
+ DMAC_M_TINT1 = 0x00000100, DMAC_M_RINT8 = 0x00000080,
+ DMAC_M_RINT5 = 0x00000010, DMAC_M_RINT4 = 0x00000008,
+ DMAC_M_RINT3 = 0x00000004, DMAC_M_RINT2 = 0x00000002,
+ DMAC_M_RINT1 = 0x00000001,
+};
+
+/* Receive descriptor bit */
+enum RD_STS_BIT {
+ RD_RACT = 0x80000000, RD_RDLE = 0x40000000,
+ RD_RFP1 = 0x20000000, RD_RFP0 = 0x10000000,
+ RD_RFE = 0x08000000, RD_RFS10 = 0x00000200,
+ RD_RFS9 = 0x00000100, RD_RFS8 = 0x00000080,
+ RD_RFS7 = 0x00000040, RD_RFS6 = 0x00000020,
+ RD_RFS5 = 0x00000010, RD_RFS4 = 0x00000008,
+ RD_RFS3 = 0x00000004, RD_RFS2 = 0x00000002,
+ RD_RFS1 = 0x00000001,
+};
+#define RDF1ST RD_RFP1
+#define RDFEND RD_RFP0
+#define RD_RFP (RD_RFP1|RD_RFP0)
+
+/* RDFFR*/
+enum RDFFR_BIT {
+ RDFFR_RDLF = 0x01,
+};
+
+/* FCFTR */
+enum FCFTR_BIT {
+ FCFTR_RFF2 = 0x00040000, FCFTR_RFF1 = 0x00020000,
+ FCFTR_RFF0 = 0x00010000, FCFTR_RFD2 = 0x00000004,
+ FCFTR_RFD1 = 0x00000002, FCFTR_RFD0 = 0x00000001,
+};
+#define FIFO_F_D_RFF (FCFTR_RFF2|FCFTR_RFF1|FCFTR_RFF0)
+#define FIFO_F_D_RFD (FCFTR_RFD2|FCFTR_RFD1|FCFTR_RFD0)
+
+/* Transfer descriptor bit */
+enum TD_STS_BIT {
+#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_ETHER)
+ TD_TACT = 0x80000000,
+#else
+ TD_TACT = 0x7fffffff,
+#endif
+ TD_TDLE = 0x40000000, TD_TFP1 = 0x20000000,
+ TD_TFP0 = 0x10000000,
+};
+#define TDF1ST TD_TFP1
+#define TDFEND TD_TFP0
+#define TD_TFP (TD_TFP1|TD_TFP0)
+
+/* RMCR */
+enum RECV_RST_BIT { RMCR_RST = 0x01, };
+/* ECMR */
+enum FELIC_MODE_BIT {
+#if defined(SH_ETH_TYPE_GETHER)
+ ECMR_TRCCM=0x04000000, ECMR_RCSC= 0x00800000, ECMR_DPAD= 0x00200000,
+ ECMR_RZPF = 0x00100000,
+#endif
+ ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000,
+ ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000,
+ ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020,
+ ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002,
+ ECMR_PRM = 0x00000001,
+#ifdef CONFIG_CPU_SH7724
+ ECMR_RTM = 0x00000010,
+#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791)
+ ECMR_RTM = 0x00000004,
+#endif
+
+};
+
+#if defined(SH_ETH_TYPE_GETHER)
+#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF | ECMR_PFR | ECMR_RXF | \
+ ECMR_TXF | ECMR_MCT)
+#elif defined(SH_ETH_TYPE_ETHER)
+#define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF)
+#else
+#define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF | ECMR_MCT)
+#endif
+
+/* ECSR */
+enum ECSR_STATUS_BIT {
+#if defined(SH_ETH_TYPE_ETHER)
+ ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10,
+#endif
+ ECSR_LCHNG = 0x04,
+ ECSR_MPD = 0x02, ECSR_ICD = 0x01,
+};
+
+#if defined(SH_ETH_TYPE_GETHER)
+# define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP)
+#else
+# define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \
+ ECSR_LCHNG | ECSR_ICD | ECSIPR_MPDIP)
+#endif
+
+/* ECSIPR */
+enum ECSIPR_STATUS_MASK_BIT {
+#if defined(SH_ETH_TYPE_ETHER)
+ ECSIPR_BRCRXIP = 0x20,
+ ECSIPR_PSRTOIP = 0x10,
+#elif defined(SH_ETY_TYPE_GETHER)
+ ECSIPR_PSRTOIP = 0x10,
+ ECSIPR_PHYIP = 0x08,
+#endif
+ ECSIPR_LCHNGIP = 0x04,
+ ECSIPR_MPDIP = 0x02,
+ ECSIPR_ICDIP = 0x01,
+};
+
+#if defined(SH_ETH_TYPE_GETHER)
+# define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP)
+#else
+# define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \
+ ECSIPR_ICDIP | ECSIPR_MPDIP)
+#endif
+
+/* APR */
+enum APR_BIT {
+ APR_AP = 0x00000004,
+};
+
+/* MPR */
+enum MPR_BIT {
+ MPR_MP = 0x00000006,
+};
+
+/* TRSCER */
+enum DESC_I_BIT {
+ DESC_I_TINT4 = 0x0800, DESC_I_TINT3 = 0x0400, DESC_I_TINT2 = 0x0200,
+ DESC_I_TINT1 = 0x0100, DESC_I_RINT8 = 0x0080, DESC_I_RINT5 = 0x0010,
+ DESC_I_RINT4 = 0x0008, DESC_I_RINT3 = 0x0004, DESC_I_RINT2 = 0x0002,
+ DESC_I_RINT1 = 0x0001,
+};
+
+/* RPADIR */
+enum RPADIR_BIT {
+ RPADIR_PADS1 = 0x20000, RPADIR_PADS0 = 0x10000,
+ RPADIR_PADR = 0x0003f,
+};
+
+#if defined(SH_ETH_TYPE_GETHER)
+# define RPADIR_INIT (0x00)
+#else
+# define RPADIR_INIT (RPADIR_PADS1)
+#endif
+
+/* FDR */
+enum FIFO_SIZE_BIT {
+ FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007,
+};
+
+static inline unsigned long sh_eth_reg_addr(struct sh_eth_dev *eth,
+ int enum_index)
+{
+#if defined(SH_ETH_TYPE_GETHER)
+ const u16 *reg_offset = sh_eth_offset_gigabit;
+#elif defined(SH_ETH_TYPE_ETHER)
+ const u16 *reg_offset = sh_eth_offset_fast_sh4;
+#else
+#error
+#endif
+ return BASE_IO_ADDR + reg_offset[enum_index] + 0x800 * eth->port;
+}
+
+static inline void sh_eth_write(struct sh_eth_dev *eth, unsigned long data,
+ int enum_index)
+{
+ outl(data, sh_eth_reg_addr(eth, enum_index));
+}
+
+static inline unsigned long sh_eth_read(struct sh_eth_dev *eth,
+ int enum_index)
+{
+ return inl(sh_eth_reg_addr(eth, enum_index));
+}
diff --git a/qemu/roms/u-boot/drivers/net/smc91111.c b/qemu/roms/u-boot/drivers/net/smc91111.c
new file mode 100644
index 000000000..57c667a58
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/smc91111.c
@@ -0,0 +1,1355 @@
+/*------------------------------------------------------------------------
+ . smc91111.c
+ . This is a driver for SMSC's 91C111 single-chip Ethernet device.
+ .
+ . (C) Copyright 2002
+ . Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ . Rolf Offermanns <rof@sysgo.de>
+ .
+ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ . Developed by Simple Network Magic Corporation (SNMC)
+ . Copyright (C) 1996 by Erik Stahlman (ES)
+ .
+ * SPDX-License-Identifier: GPL-2.0+
+ .
+ . Information contained in this file was obtained from the LAN91C111
+ . manual from SMC. To get a copy, if you really want one, you can find
+ . information under www.smsc.com.
+ .
+ .
+ . "Features" of the SMC chip:
+ . Integrated PHY/MAC for 10/100BaseT Operation
+ . Supports internal and external MII
+ . Integrated 8K packet memory
+ . EEPROM interface for configuration
+ .
+ . Arguments:
+ . io = for the base address
+ . irq = for the IRQ
+ .
+ . author:
+ . Erik Stahlman ( erik@vt.edu )
+ . Daris A Nevil ( dnevil@snmc.com )
+ .
+ .
+ . Hardware multicast code from Peter Cammaert ( pc@denkart.be )
+ .
+ . Sources:
+ . o SMSC LAN91C111 databook (www.smsc.com)
+ . o smc9194.c by Erik Stahlman
+ . o skeleton.c by Donald Becker ( becker@cesdis.gsfc.nasa.gov )
+ .
+ . History:
+ . 06/19/03 Richard Woodruff Made u-boot environment aware and added mac addr checks.
+ . 10/17/01 Marco Hasewinkel Modify for DNP/1110
+ . 07/25/01 Woojung Huh Modify for ADS Bitsy
+ . 04/25/01 Daris A Nevil Initial public release through SMSC
+ . 03/16/01 Daris A Nevil Modified smc9194.c for use with LAN91C111
+ ----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <malloc.h>
+#include "smc91111.h"
+#include <net.h>
+
+/* Use power-down feature of the chip */
+#define POWER_DOWN 0
+
+#define NO_AUTOPROBE
+
+#define SMC_DEBUG 0
+
+#if SMC_DEBUG > 1
+static const char version[] =
+ "smc91111.c:v1.0 04/25/01 by Daris A Nevil (dnevil@snmc.com)\n";
+#endif
+
+/* Autonegotiation timeout in seconds */
+#ifndef CONFIG_SMC_AUTONEG_TIMEOUT
+#define CONFIG_SMC_AUTONEG_TIMEOUT 10
+#endif
+
+/*------------------------------------------------------------------------
+ .
+ . Configuration options, for the experienced user to change.
+ .
+ -------------------------------------------------------------------------*/
+
+/*
+ . Wait time for memory to be free. This probably shouldn't be
+ . tuned that much, as waiting for this means nothing else happens
+ . in the system
+*/
+#define MEMORY_WAIT_TIME 16
+
+
+#if (SMC_DEBUG > 2 )
+#define PRINTK3(args...) printf(args)
+#else
+#define PRINTK3(args...)
+#endif
+
+#if SMC_DEBUG > 1
+#define PRINTK2(args...) printf(args)
+#else
+#define PRINTK2(args...)
+#endif
+
+#ifdef SMC_DEBUG
+#define PRINTK(args...) printf(args)
+#else
+#define PRINTK(args...)
+#endif
+
+
+/*------------------------------------------------------------------------
+ .
+ . The internal workings of the driver. If you are changing anything
+ . here with the SMC stuff, you should have the datasheet and know
+ . what you are doing.
+ .
+ -------------------------------------------------------------------------*/
+
+/* Memory sizing constant */
+#define LAN91C111_MEMORY_MULTIPLIER (1024*2)
+
+#ifndef CONFIG_SMC91111_BASE
+#error "SMC91111 Base address must be passed to initialization funciton"
+/* #define CONFIG_SMC91111_BASE 0x20000300 */
+#endif
+
+#define SMC_DEV_NAME "SMC91111"
+#define SMC_PHY_ADDR 0x0000
+#define SMC_ALLOC_MAX_TRY 5
+#define SMC_TX_TIMEOUT 30
+
+#define SMC_PHY_CLOCK_DELAY 1000
+
+#define ETH_ZLEN 60
+
+#ifdef CONFIG_SMC_USE_32_BIT
+#define USE_32_BIT 1
+#else
+#undef USE_32_BIT
+#endif
+
+#ifdef SHARED_RESOURCES
+extern void swap_to(int device_id);
+#else
+# define swap_to(x)
+#endif
+
+#ifndef CONFIG_SMC91111_EXT_PHY
+static void smc_phy_configure(struct eth_device *dev);
+#endif /* !CONFIG_SMC91111_EXT_PHY */
+
+/*
+ ------------------------------------------------------------
+ .
+ . Internal routines
+ .
+ ------------------------------------------------------------
+*/
+
+#ifdef CONFIG_SMC_USE_IOFUNCS
+/*
+ * input and output functions
+ *
+ * Implemented due to inx,outx macros accessing the device improperly
+ * and putting the device into an unkown state.
+ *
+ * For instance, on Sharp LPD7A400 SDK, affects were chip memory
+ * could not be free'd (hence the alloc failures), duplicate packets,
+ * packets being corrupt (shifted) on the wire, etc. Switching to the
+ * inx,outx functions fixed this problem.
+ */
+
+static inline word SMC_inw(struct eth_device *dev, dword offset)
+{
+ word v;
+ v = *((volatile word*)(dev->iobase + offset));
+ barrier(); *(volatile u32*)(0xc0000000);
+ return v;
+}
+
+static inline void SMC_outw(struct eth_device *dev, word value, dword offset)
+{
+ *((volatile word*)(dev->iobase + offset)) = value;
+ barrier(); *(volatile u32*)(0xc0000000);
+}
+
+static inline byte SMC_inb(struct eth_device *dev, dword offset)
+{
+ word _w;
+
+ _w = SMC_inw(dev, offset & ~((dword)1));
+ return (offset & 1) ? (byte)(_w >> 8) : (byte)(_w);
+}
+
+static inline void SMC_outb(struct eth_device *dev, byte value, dword offset)
+{
+ word _w;
+
+ _w = SMC_inw(dev, offset & ~((dword)1));
+ if (offset & 1)
+ *((volatile word*)(dev->iobase + (offset & ~((dword)1)))) =
+ (value<<8) | (_w & 0x00ff);
+ else
+ *((volatile word*)(dev->iobase + offset)) =
+ value | (_w & 0xff00);
+}
+
+static inline void SMC_insw(struct eth_device *dev, dword offset,
+ volatile uchar* buf, dword len)
+{
+ volatile word *p = (volatile word *)buf;
+
+ while (len-- > 0) {
+ *p++ = SMC_inw(dev, offset);
+ barrier();
+ *((volatile u32*)(0xc0000000));
+ }
+}
+
+static inline void SMC_outsw(struct eth_device *dev, dword offset,
+ uchar* buf, dword len)
+{
+ volatile word *p = (volatile word *)buf;
+
+ while (len-- > 0) {
+ SMC_outw(dev, *p++, offset);
+ barrier();
+ *(volatile u32*)(0xc0000000);
+ }
+}
+#endif /* CONFIG_SMC_USE_IOFUNCS */
+
+/*
+ . A rather simple routine to print out a packet for debugging purposes.
+*/
+#if SMC_DEBUG > 2
+static void print_packet( byte *, int );
+#endif
+
+#define tx_done(dev) 1
+
+static int poll4int (struct eth_device *dev, byte mask, int timeout)
+{
+ int tmo = get_timer (0) + timeout * CONFIG_SYS_HZ;
+ int is_timeout = 0;
+ word old_bank = SMC_inw (dev, BSR_REG);
+
+ PRINTK2 ("Polling...\n");
+ SMC_SELECT_BANK (dev, 2);
+ while ((SMC_inw (dev, SMC91111_INT_REG) & mask) == 0) {
+ if (get_timer (0) >= tmo) {
+ is_timeout = 1;
+ break;
+ }
+ }
+
+ /* restore old bank selection */
+ SMC_SELECT_BANK (dev, old_bank);
+
+ if (is_timeout)
+ return 1;
+ else
+ return 0;
+}
+
+/* Only one release command at a time, please */
+static inline void smc_wait_mmu_release_complete (struct eth_device *dev)
+{
+ int count = 0;
+
+ /* assume bank 2 selected */
+ while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY) {
+ udelay (1); /* Wait until not busy */
+ if (++count > 200)
+ break;
+ }
+}
+
+/*
+ . Function: smc_reset( void )
+ . Purpose:
+ . This sets the SMC91111 chip to its normal state, hopefully from whatever
+ . mess that any other DOS driver has put it in.
+ .
+ . Maybe I should reset more registers to defaults in here? SOFTRST should
+ . do that for me.
+ .
+ . Method:
+ . 1. send a SOFT RESET
+ . 2. wait for it to finish
+ . 3. enable autorelease mode
+ . 4. reset the memory management unit
+ . 5. clear all interrupts
+ .
+*/
+static void smc_reset (struct eth_device *dev)
+{
+ PRINTK2 ("%s: smc_reset\n", SMC_DEV_NAME);
+
+ /* This resets the registers mostly to defaults, but doesn't
+ affect EEPROM. That seems unnecessary */
+ SMC_SELECT_BANK (dev, 0);
+ SMC_outw (dev, RCR_SOFTRST, RCR_REG);
+
+ /* Setup the Configuration Register */
+ /* This is necessary because the CONFIG_REG is not affected */
+ /* by a soft reset */
+
+ SMC_SELECT_BANK (dev, 1);
+#if defined(CONFIG_SMC91111_EXT_PHY)
+ SMC_outw (dev, CONFIG_DEFAULT | CONFIG_EXT_PHY, CONFIG_REG);
+#else
+ SMC_outw (dev, CONFIG_DEFAULT, CONFIG_REG);
+#endif
+
+
+ /* Release from possible power-down state */
+ /* Configuration register is not affected by Soft Reset */
+ SMC_outw (dev, SMC_inw (dev, CONFIG_REG) | CONFIG_EPH_POWER_EN,
+ CONFIG_REG);
+
+ SMC_SELECT_BANK (dev, 0);
+
+ /* this should pause enough for the chip to be happy */
+ udelay (10);
+
+ /* Disable transmit and receive functionality */
+ SMC_outw (dev, RCR_CLEAR, RCR_REG);
+ SMC_outw (dev, TCR_CLEAR, TCR_REG);
+
+ /* set the control register */
+ SMC_SELECT_BANK (dev, 1);
+ SMC_outw (dev, CTL_DEFAULT, CTL_REG);
+
+ /* Reset the MMU */
+ SMC_SELECT_BANK (dev, 2);
+ smc_wait_mmu_release_complete (dev);
+ SMC_outw (dev, MC_RESET, MMU_CMD_REG);
+ while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY)
+ udelay (1); /* Wait until not busy */
+
+ /* Note: It doesn't seem that waiting for the MMU busy is needed here,
+ but this is a place where future chipsets _COULD_ break. Be wary
+ of issuing another MMU command right after this */
+
+ /* Disable all interrupts */
+ SMC_outb (dev, 0, IM_REG);
+}
+
+/*
+ . Function: smc_enable
+ . Purpose: let the chip talk to the outside work
+ . Method:
+ . 1. Enable the transmitter
+ . 2. Enable the receiver
+ . 3. Enable interrupts
+*/
+static void smc_enable(struct eth_device *dev)
+{
+ PRINTK2("%s: smc_enable\n", SMC_DEV_NAME);
+ SMC_SELECT_BANK( dev, 0 );
+ /* see the header file for options in TCR/RCR DEFAULT*/
+ SMC_outw( dev, TCR_DEFAULT, TCR_REG );
+ SMC_outw( dev, RCR_DEFAULT, RCR_REG );
+
+ /* clear MII_DIS */
+/* smc_write_phy_register(PHY_CNTL_REG, 0x0000); */
+}
+
+/*
+ . Function: smc_halt
+ . Purpose: closes down the SMC91xxx chip.
+ . Method:
+ . 1. zero the interrupt mask
+ . 2. clear the enable receive flag
+ . 3. clear the enable xmit flags
+ .
+ . TODO:
+ . (1) maybe utilize power down mode.
+ . Why not yet? Because while the chip will go into power down mode,
+ . the manual says that it will wake up in response to any I/O requests
+ . in the register space. Empirical results do not show this working.
+*/
+static void smc_halt(struct eth_device *dev)
+{
+ PRINTK2("%s: smc_halt\n", SMC_DEV_NAME);
+
+ /* no more interrupts for me */
+ SMC_SELECT_BANK( dev, 2 );
+ SMC_outb( dev, 0, IM_REG );
+
+ /* and tell the card to stay away from that nasty outside world */
+ SMC_SELECT_BANK( dev, 0 );
+ SMC_outb( dev, RCR_CLEAR, RCR_REG );
+ SMC_outb( dev, TCR_CLEAR, TCR_REG );
+
+ swap_to(FLASH);
+}
+
+
+/*
+ . Function: smc_send(struct net_device * )
+ . Purpose:
+ . This sends the actual packet to the SMC9xxx chip.
+ .
+ . Algorithm:
+ . First, see if a saved_skb is available.
+ . ( this should NOT be called if there is no 'saved_skb'
+ . Now, find the packet number that the chip allocated
+ . Point the data pointers at it in memory
+ . Set the length word in the chip's memory
+ . Dump the packet to chip memory
+ . Check if a last byte is needed ( odd length packet )
+ . if so, set the control flag right
+ . Tell the card to send it
+ . Enable the transmit interrupt, so I know if it failed
+ . Free the kernel data if I actually sent it.
+*/
+static int smc_send(struct eth_device *dev, void *packet, int packet_length)
+{
+ byte packet_no;
+ byte *buf;
+ int length;
+ int numPages;
+ int try = 0;
+ int time_out;
+ byte status;
+ byte saved_pnr;
+ word saved_ptr;
+
+ /* save PTR and PNR registers before manipulation */
+ SMC_SELECT_BANK (dev, 2);
+ saved_pnr = SMC_inb( dev, PN_REG );
+ saved_ptr = SMC_inw( dev, PTR_REG );
+
+ PRINTK3 ("%s: smc_hardware_send_packet\n", SMC_DEV_NAME);
+
+ length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
+
+ /* allocate memory
+ ** The MMU wants the number of pages to be the number of 256 bytes
+ ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+ **
+ ** The 91C111 ignores the size bits, but the code is left intact
+ ** for backwards and future compatibility.
+ **
+ ** Pkt size for allocating is data length +6 (for additional status
+ ** words, length and ctl!)
+ **
+ ** If odd size then last byte is included in this header.
+ */
+ numPages = ((length & 0xfffe) + 6);
+ numPages >>= 8; /* Divide by 256 */
+
+ if (numPages > 7) {
+ printf ("%s: Far too big packet error. \n", SMC_DEV_NAME);
+ return 0;
+ }
+
+ /* now, try to allocate the memory */
+ SMC_SELECT_BANK (dev, 2);
+ SMC_outw (dev, MC_ALLOC | numPages, MMU_CMD_REG);
+
+ /* FIXME: the ALLOC_INT bit never gets set *
+ * so the following will always give a *
+ * memory allocation error. *
+ * same code works in armboot though *
+ * -ro
+ */
+
+again:
+ try++;
+ time_out = MEMORY_WAIT_TIME;
+ do {
+ status = SMC_inb (dev, SMC91111_INT_REG);
+ if (status & IM_ALLOC_INT) {
+ /* acknowledge the interrupt */
+ SMC_outb (dev, IM_ALLOC_INT, SMC91111_INT_REG);
+ break;
+ }
+ } while (--time_out);
+
+ if (!time_out) {
+ PRINTK2 ("%s: memory allocation, try %d failed ...\n",
+ SMC_DEV_NAME, try);
+ if (try < SMC_ALLOC_MAX_TRY)
+ goto again;
+ else
+ return 0;
+ }
+
+ PRINTK2 ("%s: memory allocation, try %d succeeded ...\n",
+ SMC_DEV_NAME, try);
+
+ buf = (byte *) packet;
+
+ /* If I get here, I _know_ there is a packet slot waiting for me */
+ packet_no = SMC_inb (dev, AR_REG);
+ if (packet_no & AR_FAILED) {
+ /* or isn't there? BAD CHIP! */
+ printf ("%s: Memory allocation failed. \n", SMC_DEV_NAME);
+ return 0;
+ }
+
+ /* we have a packet address, so tell the card to use it */
+#ifndef CONFIG_XAENIAX
+ SMC_outb (dev, packet_no, PN_REG);
+#else
+ /* On Xaeniax board, we can't use SMC_outb here because that way
+ * the Allocate MMU command will end up written to the command register
+ * as well, which will lead to a problem.
+ */
+ SMC_outl (dev, packet_no << 16, 0);
+#endif
+ /* do not write new ptr value if Write data fifo not empty */
+ while ( saved_ptr & PTR_NOTEMPTY )
+ printf ("Write data fifo not empty!\n");
+
+ /* point to the beginning of the packet */
+ SMC_outw (dev, PTR_AUTOINC, PTR_REG);
+
+ PRINTK3 ("%s: Trying to xmit packet of length %x\n",
+ SMC_DEV_NAME, length);
+
+#if SMC_DEBUG > 2
+ printf ("Transmitting Packet\n");
+ print_packet (buf, length);
+#endif
+
+ /* send the packet length ( +6 for status, length and ctl byte )
+ and the status word ( set to zeros ) */
+#ifdef USE_32_BIT
+ SMC_outl (dev, (length + 6) << 16, SMC91111_DATA_REG);
+#else
+ SMC_outw (dev, 0, SMC91111_DATA_REG);
+ /* send the packet length ( +6 for status words, length, and ctl */
+ SMC_outw (dev, (length + 6), SMC91111_DATA_REG);
+#endif
+
+ /* send the actual data
+ . I _think_ it's faster to send the longs first, and then
+ . mop up by sending the last word. It depends heavily
+ . on alignment, at least on the 486. Maybe it would be
+ . a good idea to check which is optimal? But that could take
+ . almost as much time as is saved?
+ */
+#ifdef USE_32_BIT
+ SMC_outsl (dev, SMC91111_DATA_REG, buf, length >> 2);
+#ifndef CONFIG_XAENIAX
+ if (length & 0x2)
+ SMC_outw (dev, *((word *) (buf + (length & 0xFFFFFFFC))),
+ SMC91111_DATA_REG);
+#else
+ /* On XANEIAX, we can only use 32-bit writes, so we need to handle
+ * unaligned tail part specially. The standard code doesn't work.
+ */
+ if ((length & 3) == 3) {
+ u16 * ptr = (u16*) &buf[length-3];
+ SMC_outl(dev, (*ptr) | ((0x2000 | buf[length-1]) << 16),
+ SMC91111_DATA_REG);
+ } else if ((length & 2) == 2) {
+ u16 * ptr = (u16*) &buf[length-2];
+ SMC_outl(dev, *ptr, SMC91111_DATA_REG);
+ } else if (length & 1) {
+ SMC_outl(dev, (0x2000 | buf[length-1]), SMC91111_DATA_REG);
+ } else {
+ SMC_outl(dev, 0, SMC91111_DATA_REG);
+ }
+#endif
+#else
+ SMC_outsw (dev, SMC91111_DATA_REG, buf, (length) >> 1);
+#endif /* USE_32_BIT */
+
+#ifndef CONFIG_XAENIAX
+ /* Send the last byte, if there is one. */
+ if ((length & 1) == 0) {
+ SMC_outw (dev, 0, SMC91111_DATA_REG);
+ } else {
+ SMC_outw (dev, buf[length - 1] | 0x2000, SMC91111_DATA_REG);
+ }
+#endif
+
+ /* and let the chipset deal with it */
+ SMC_outw (dev, MC_ENQUEUE, MMU_CMD_REG);
+
+ /* poll for TX INT */
+ /* if (poll4int (dev, IM_TX_INT, SMC_TX_TIMEOUT)) { */
+ /* poll for TX_EMPTY INT - autorelease enabled */
+ if (poll4int(dev, IM_TX_EMPTY_INT, SMC_TX_TIMEOUT)) {
+ /* sending failed */
+ PRINTK2 ("%s: TX timeout, sending failed...\n", SMC_DEV_NAME);
+
+ /* release packet */
+ /* no need to release, MMU does that now */
+#ifdef CONFIG_XAENIAX
+ SMC_outw (dev, MC_FREEPKT, MMU_CMD_REG);
+#endif
+
+ /* wait for MMU getting ready (low) */
+ while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY) {
+ udelay (10);
+ }
+
+ PRINTK2 ("MMU ready\n");
+
+
+ return 0;
+ } else {
+ /* ack. int */
+ SMC_outb (dev, IM_TX_EMPTY_INT, SMC91111_INT_REG);
+ /* SMC_outb (IM_TX_INT, SMC91111_INT_REG); */
+ PRINTK2 ("%s: Sent packet of length %d \n", SMC_DEV_NAME,
+ length);
+
+ /* release packet */
+ /* no need to release, MMU does that now */
+#ifdef CONFIG_XAENIAX
+ SMC_outw (dev, MC_FREEPKT, MMU_CMD_REG);
+#endif
+
+ /* wait for MMU getting ready (low) */
+ while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY) {
+ udelay (10);
+ }
+
+ PRINTK2 ("MMU ready\n");
+
+
+ }
+
+ /* restore previously saved registers */
+#ifndef CONFIG_XAENIAX
+ SMC_outb( dev, saved_pnr, PN_REG );
+#else
+ /* On Xaeniax board, we can't use SMC_outb here because that way
+ * the Allocate MMU command will end up written to the command register
+ * as well, which will lead to a problem.
+ */
+ SMC_outl(dev, saved_pnr << 16, 0);
+#endif
+ SMC_outw( dev, saved_ptr, PTR_REG );
+
+ return length;
+}
+
+static int smc_write_hwaddr(struct eth_device *dev)
+{
+ int i;
+
+ swap_to(ETHERNET);
+ SMC_SELECT_BANK (dev, 1);
+#ifdef USE_32_BIT
+ for (i = 0; i < 6; i += 2) {
+ word address;
+
+ address = dev->enetaddr[i + 1] << 8;
+ address |= dev->enetaddr[i];
+ SMC_outw(dev, address, (ADDR0_REG + i));
+ }
+#else
+ for (i = 0; i < 6; i++)
+ SMC_outb(dev, dev->enetaddr[i], (ADDR0_REG + i));
+#endif
+ swap_to(FLASH);
+ return 0;
+}
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ *
+ */
+static int smc_init(struct eth_device *dev, bd_t *bd)
+{
+ swap_to(ETHERNET);
+
+ PRINTK2 ("%s: smc_init\n", SMC_DEV_NAME);
+
+ /* reset the hardware */
+ smc_reset (dev);
+ smc_enable (dev);
+
+ /* Configure the PHY */
+#ifndef CONFIG_SMC91111_EXT_PHY
+ smc_phy_configure (dev);
+#endif
+
+ /* conservative setting (10Mbps, HalfDuplex, no AutoNeg.) */
+/* SMC_SELECT_BANK(dev, 0); */
+/* SMC_outw(dev, 0, RPC_REG); */
+
+ printf(SMC_DEV_NAME ": MAC %pM\n", dev->enetaddr);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------
+ .
+ . smc_rcv - receive a packet from the card
+ .
+ . There is ( at least ) a packet waiting to be read from
+ . chip-memory.
+ .
+ . o Read the status
+ . o If an error, record it
+ . o otherwise, read in the packet
+ --------------------------------------------------------------
+*/
+static int smc_rcv(struct eth_device *dev)
+{
+ int packet_number;
+ word status;
+ word packet_length;
+ int is_error = 0;
+#ifdef USE_32_BIT
+ dword stat_len;
+#endif
+ byte saved_pnr;
+ word saved_ptr;
+
+ SMC_SELECT_BANK(dev, 2);
+ /* save PTR and PTR registers */
+ saved_pnr = SMC_inb( dev, PN_REG );
+ saved_ptr = SMC_inw( dev, PTR_REG );
+
+ packet_number = SMC_inw( dev, RXFIFO_REG );
+
+ if ( packet_number & RXFIFO_REMPTY ) {
+
+ return 0;
+ }
+
+ PRINTK3("%s: smc_rcv\n", SMC_DEV_NAME);
+ /* start reading from the start of the packet */
+ SMC_outw( dev, PTR_READ | PTR_RCV | PTR_AUTOINC, PTR_REG );
+
+ /* First two words are status and packet_length */
+#ifdef USE_32_BIT
+ stat_len = SMC_inl(dev, SMC91111_DATA_REG);
+ status = stat_len & 0xffff;
+ packet_length = stat_len >> 16;
+#else
+ status = SMC_inw( dev, SMC91111_DATA_REG );
+ packet_length = SMC_inw( dev, SMC91111_DATA_REG );
+#endif
+
+ packet_length &= 0x07ff; /* mask off top bits */
+
+ PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length );
+
+ if ( !(status & RS_ERRORS ) ){
+ /* Adjust for having already read the first two words */
+ packet_length -= 4; /*4; */
+
+
+ /* set odd length for bug in LAN91C111, */
+ /* which never sets RS_ODDFRAME */
+ /* TODO ? */
+
+
+#ifdef USE_32_BIT
+ PRINTK3(" Reading %d dwords (and %d bytes) \n",
+ packet_length >> 2, packet_length & 3 );
+ /* QUESTION: Like in the TX routine, do I want
+ to send the DWORDs or the bytes first, or some
+ mixture. A mixture might improve already slow PIO
+ performance */
+ SMC_insl( dev, SMC91111_DATA_REG, NetRxPackets[0],
+ packet_length >> 2 );
+ /* read the left over bytes */
+ if (packet_length & 3) {
+ int i;
+
+ byte *tail = (byte *)(NetRxPackets[0] +
+ (packet_length & ~3));
+ dword leftover = SMC_inl(dev, SMC91111_DATA_REG);
+ for (i=0; i<(packet_length & 3); i++)
+ *tail++ = (byte) (leftover >> (8*i)) & 0xff;
+ }
+#else
+ PRINTK3(" Reading %d words and %d byte(s) \n",
+ (packet_length >> 1 ), packet_length & 1 );
+ SMC_insw(dev, SMC91111_DATA_REG , NetRxPackets[0],
+ packet_length >> 1);
+
+#endif /* USE_32_BIT */
+
+#if SMC_DEBUG > 2
+ printf("Receiving Packet\n");
+ print_packet( NetRxPackets[0], packet_length );
+#endif
+ } else {
+ /* error ... */
+ /* TODO ? */
+ is_error = 1;
+ }
+
+ while ( SMC_inw( dev, MMU_CMD_REG ) & MC_BUSY )
+ udelay(1); /* Wait until not busy */
+
+ /* error or good, tell the card to get rid of this packet */
+ SMC_outw( dev, MC_RELEASE, MMU_CMD_REG );
+
+ while ( SMC_inw( dev, MMU_CMD_REG ) & MC_BUSY )
+ udelay(1); /* Wait until not busy */
+
+ /* restore saved registers */
+#ifndef CONFIG_XAENIAX
+ SMC_outb( dev, saved_pnr, PN_REG );
+#else
+ /* On Xaeniax board, we can't use SMC_outb here because that way
+ * the Allocate MMU command will end up written to the command register
+ * as well, which will lead to a problem.
+ */
+ SMC_outl( dev, saved_pnr << 16, 0);
+#endif
+ SMC_outw( dev, saved_ptr, PTR_REG );
+
+ if (!is_error) {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[0], packet_length);
+ return packet_length;
+ } else {
+ return 0;
+ }
+
+}
+
+
+#if 0
+/*------------------------------------------------------------
+ . Modify a bit in the LAN91C111 register set
+ .-------------------------------------------------------------*/
+static word smc_modify_regbit(struct eth_device *dev, int bank, int ioaddr, int reg,
+ unsigned int bit, int val)
+{
+ word regval;
+
+ SMC_SELECT_BANK( dev, bank );
+
+ regval = SMC_inw( dev, reg );
+ if (val)
+ regval |= bit;
+ else
+ regval &= ~bit;
+
+ SMC_outw( dev, regval, 0 );
+ return(regval);
+}
+
+
+/*------------------------------------------------------------
+ . Retrieve a bit in the LAN91C111 register set
+ .-------------------------------------------------------------*/
+static int smc_get_regbit(struct eth_device *dev, int bank, int ioaddr, int reg, unsigned int bit)
+{
+ SMC_SELECT_BANK( dev, bank );
+ if ( SMC_inw( dev, reg ) & bit)
+ return(1);
+ else
+ return(0);
+}
+
+
+/*------------------------------------------------------------
+ . Modify a LAN91C111 register (word access only)
+ .-------------------------------------------------------------*/
+static void smc_modify_reg(struct eth_device *dev, int bank, int ioaddr, int reg, word val)
+{
+ SMC_SELECT_BANK( dev, bank );
+ SMC_outw( dev, val, reg );
+}
+
+
+/*------------------------------------------------------------
+ . Retrieve a LAN91C111 register (word access only)
+ .-------------------------------------------------------------*/
+static int smc_get_reg(struct eth_device *dev, int bank, int ioaddr, int reg)
+{
+ SMC_SELECT_BANK( dev, bank );
+ return(SMC_inw( dev, reg ));
+}
+
+#endif /* 0 */
+
+/*---PHY CONTROL AND CONFIGURATION----------------------------------------- */
+
+#if (SMC_DEBUG > 2 )
+
+/*------------------------------------------------------------
+ . Debugging function for viewing MII Management serial bitstream
+ .-------------------------------------------------------------*/
+static void smc_dump_mii_stream (byte * bits, int size)
+{
+ int i;
+
+ printf ("BIT#:");
+ for (i = 0; i < size; ++i) {
+ printf ("%d", i % 10);
+ }
+
+ printf ("\nMDOE:");
+ for (i = 0; i < size; ++i) {
+ if (bits[i] & MII_MDOE)
+ printf ("1");
+ else
+ printf ("0");
+ }
+
+ printf ("\nMDO :");
+ for (i = 0; i < size; ++i) {
+ if (bits[i] & MII_MDO)
+ printf ("1");
+ else
+ printf ("0");
+ }
+
+ printf ("\nMDI :");
+ for (i = 0; i < size; ++i) {
+ if (bits[i] & MII_MDI)
+ printf ("1");
+ else
+ printf ("0");
+ }
+
+ printf ("\n");
+}
+#endif
+
+/*------------------------------------------------------------
+ . Reads a register from the MII Management serial interface
+ .-------------------------------------------------------------*/
+#ifndef CONFIG_SMC91111_EXT_PHY
+static word smc_read_phy_register (struct eth_device *dev, byte phyreg)
+{
+ int oldBank;
+ int i;
+ byte mask;
+ word mii_reg;
+ byte bits[64];
+ int clk_idx = 0;
+ int input_idx;
+ word phydata;
+ byte phyaddr = SMC_PHY_ADDR;
+
+ /* 32 consecutive ones on MDO to establish sync */
+ for (i = 0; i < 32; ++i)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ /* Start code <01> */
+ bits[clk_idx++] = MII_MDOE;
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ /* Read command <10> */
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ bits[clk_idx++] = MII_MDOE;
+
+ /* Output the PHY address, msb first */
+ mask = (byte) 0x10;
+ for (i = 0; i < 5; ++i) {
+ if (phyaddr & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ /* Shift to next lowest bit */
+ mask >>= 1;
+ }
+
+ /* Output the phy register number, msb first */
+ mask = (byte) 0x10;
+ for (i = 0; i < 5; ++i) {
+ if (phyreg & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ /* Shift to next lowest bit */
+ mask >>= 1;
+ }
+
+ /* Tristate and turnaround (2 bit times) */
+ bits[clk_idx++] = 0;
+ /*bits[clk_idx++] = 0; */
+
+ /* Input starts at this bit time */
+ input_idx = clk_idx;
+
+ /* Will input 16 bits */
+ for (i = 0; i < 16; ++i)
+ bits[clk_idx++] = 0;
+
+ /* Final clock bit */
+ bits[clk_idx++] = 0;
+
+ /* Save the current bank */
+ oldBank = SMC_inw (dev, BANK_SELECT);
+
+ /* Select bank 3 */
+ SMC_SELECT_BANK (dev, 3);
+
+ /* Get the current MII register value */
+ mii_reg = SMC_inw (dev, MII_REG);
+
+ /* Turn off all MII Interface bits */
+ mii_reg &= ~(MII_MDOE | MII_MCLK | MII_MDI | MII_MDO);
+
+ /* Clock all 64 cycles */
+ for (i = 0; i < sizeof bits; ++i) {
+ /* Clock Low - output data */
+ SMC_outw (dev, mii_reg | bits[i], MII_REG);
+ udelay (SMC_PHY_CLOCK_DELAY);
+
+
+ /* Clock Hi - input data */
+ SMC_outw (dev, mii_reg | bits[i] | MII_MCLK, MII_REG);
+ udelay (SMC_PHY_CLOCK_DELAY);
+ bits[i] |= SMC_inw (dev, MII_REG) & MII_MDI;
+ }
+
+ /* Return to idle state */
+ /* Set clock to low, data to low, and output tristated */
+ SMC_outw (dev, mii_reg, MII_REG);
+ udelay (SMC_PHY_CLOCK_DELAY);
+
+ /* Restore original bank select */
+ SMC_SELECT_BANK (dev, oldBank);
+
+ /* Recover input data */
+ phydata = 0;
+ for (i = 0; i < 16; ++i) {
+ phydata <<= 1;
+
+ if (bits[input_idx++] & MII_MDI)
+ phydata |= 0x0001;
+ }
+
+#if (SMC_DEBUG > 2 )
+ printf ("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+ phyaddr, phyreg, phydata);
+ smc_dump_mii_stream (bits, sizeof bits);
+#endif
+
+ return (phydata);
+}
+
+
+/*------------------------------------------------------------
+ . Writes a register to the MII Management serial interface
+ .-------------------------------------------------------------*/
+static void smc_write_phy_register (struct eth_device *dev, byte phyreg,
+ word phydata)
+{
+ int oldBank;
+ int i;
+ word mask;
+ word mii_reg;
+ byte bits[65];
+ int clk_idx = 0;
+ byte phyaddr = SMC_PHY_ADDR;
+
+ /* 32 consecutive ones on MDO to establish sync */
+ for (i = 0; i < 32; ++i)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ /* Start code <01> */
+ bits[clk_idx++] = MII_MDOE;
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ /* Write command <01> */
+ bits[clk_idx++] = MII_MDOE;
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ /* Output the PHY address, msb first */
+ mask = (byte) 0x10;
+ for (i = 0; i < 5; ++i) {
+ if (phyaddr & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ /* Shift to next lowest bit */
+ mask >>= 1;
+ }
+
+ /* Output the phy register number, msb first */
+ mask = (byte) 0x10;
+ for (i = 0; i < 5; ++i) {
+ if (phyreg & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ /* Shift to next lowest bit */
+ mask >>= 1;
+ }
+
+ /* Tristate and turnaround (2 bit times) */
+ bits[clk_idx++] = 0;
+ bits[clk_idx++] = 0;
+
+ /* Write out 16 bits of data, msb first */
+ mask = 0x8000;
+ for (i = 0; i < 16; ++i) {
+ if (phydata & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ /* Shift to next lowest bit */
+ mask >>= 1;
+ }
+
+ /* Final clock bit (tristate) */
+ bits[clk_idx++] = 0;
+
+ /* Save the current bank */
+ oldBank = SMC_inw (dev, BANK_SELECT);
+
+ /* Select bank 3 */
+ SMC_SELECT_BANK (dev, 3);
+
+ /* Get the current MII register value */
+ mii_reg = SMC_inw (dev, MII_REG);
+
+ /* Turn off all MII Interface bits */
+ mii_reg &= ~(MII_MDOE | MII_MCLK | MII_MDI | MII_MDO);
+
+ /* Clock all cycles */
+ for (i = 0; i < sizeof bits; ++i) {
+ /* Clock Low - output data */
+ SMC_outw (dev, mii_reg | bits[i], MII_REG);
+ udelay (SMC_PHY_CLOCK_DELAY);
+
+
+ /* Clock Hi - input data */
+ SMC_outw (dev, mii_reg | bits[i] | MII_MCLK, MII_REG);
+ udelay (SMC_PHY_CLOCK_DELAY);
+ bits[i] |= SMC_inw (dev, MII_REG) & MII_MDI;
+ }
+
+ /* Return to idle state */
+ /* Set clock to low, data to low, and output tristated */
+ SMC_outw (dev, mii_reg, MII_REG);
+ udelay (SMC_PHY_CLOCK_DELAY);
+
+ /* Restore original bank select */
+ SMC_SELECT_BANK (dev, oldBank);
+
+#if (SMC_DEBUG > 2 )
+ printf ("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+ phyaddr, phyreg, phydata);
+ smc_dump_mii_stream (bits, sizeof bits);
+#endif
+}
+#endif /* !CONFIG_SMC91111_EXT_PHY */
+
+
+/*------------------------------------------------------------
+ . Configures the specified PHY using Autonegotiation. Calls
+ . smc_phy_fixed() if the user has requested a certain config.
+ .-------------------------------------------------------------*/
+#ifndef CONFIG_SMC91111_EXT_PHY
+static void smc_phy_configure (struct eth_device *dev)
+{
+ int timeout;
+ word my_phy_caps; /* My PHY capabilities */
+ word my_ad_caps; /* My Advertised capabilities */
+ word status = 0; /*;my status = 0 */
+
+ PRINTK3 ("%s: smc_program_phy()\n", SMC_DEV_NAME);
+
+ /* Reset the PHY, setting all other bits to zero */
+ smc_write_phy_register (dev, PHY_CNTL_REG, PHY_CNTL_RST);
+
+ /* Wait for the reset to complete, or time out */
+ timeout = 6; /* Wait up to 3 seconds */
+ while (timeout--) {
+ if (!(smc_read_phy_register (dev, PHY_CNTL_REG)
+ & PHY_CNTL_RST)) {
+ /* reset complete */
+ break;
+ }
+
+ mdelay(500); /* wait 500 millisecs */
+ }
+
+ if (timeout < 1) {
+ printf ("%s:PHY reset timed out\n", SMC_DEV_NAME);
+ goto smc_phy_configure_exit;
+ }
+
+ /* Read PHY Register 18, Status Output */
+ /* lp->lastPhy18 = smc_read_phy_register(PHY_INT_REG); */
+
+ /* Enable PHY Interrupts (for register 18) */
+ /* Interrupts listed here are disabled */
+ smc_write_phy_register (dev, PHY_MASK_REG, 0xffff);
+
+ /* Configure the Receive/Phy Control register */
+ SMC_SELECT_BANK (dev, 0);
+ SMC_outw (dev, RPC_DEFAULT, RPC_REG);
+
+ /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
+ my_phy_caps = smc_read_phy_register (dev, PHY_STAT_REG);
+ my_ad_caps = PHY_AD_CSMA; /* I am CSMA capable */
+
+ if (my_phy_caps & PHY_STAT_CAP_T4)
+ my_ad_caps |= PHY_AD_T4;
+
+ if (my_phy_caps & PHY_STAT_CAP_TXF)
+ my_ad_caps |= PHY_AD_TX_FDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TXH)
+ my_ad_caps |= PHY_AD_TX_HDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TF)
+ my_ad_caps |= PHY_AD_10_FDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TH)
+ my_ad_caps |= PHY_AD_10_HDX;
+
+ /* Update our Auto-Neg Advertisement Register */
+ smc_write_phy_register (dev, PHY_AD_REG, my_ad_caps);
+
+ /* Read the register back. Without this, it appears that when */
+ /* auto-negotiation is restarted, sometimes it isn't ready and */
+ /* the link does not come up. */
+ smc_read_phy_register(dev, PHY_AD_REG);
+
+ PRINTK2 ("%s: phy caps=%x\n", SMC_DEV_NAME, my_phy_caps);
+ PRINTK2 ("%s: phy advertised caps=%x\n", SMC_DEV_NAME, my_ad_caps);
+
+ /* Restart auto-negotiation process in order to advertise my caps */
+ smc_write_phy_register (dev, PHY_CNTL_REG,
+ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
+
+ /* Wait for the auto-negotiation to complete. This may take from */
+ /* 2 to 3 seconds. */
+ /* Wait for the reset to complete, or time out */
+ timeout = CONFIG_SMC_AUTONEG_TIMEOUT * 2;
+ while (timeout--) {
+
+ status = smc_read_phy_register (dev, PHY_STAT_REG);
+ if (status & PHY_STAT_ANEG_ACK) {
+ /* auto-negotiate complete */
+ break;
+ }
+
+ mdelay(500); /* wait 500 millisecs */
+
+ /* Restart auto-negotiation if remote fault */
+ if (status & PHY_STAT_REM_FLT) {
+ printf ("%s: PHY remote fault detected\n",
+ SMC_DEV_NAME);
+
+ /* Restart auto-negotiation */
+ printf ("%s: PHY restarting auto-negotiation\n",
+ SMC_DEV_NAME);
+ smc_write_phy_register (dev, PHY_CNTL_REG,
+ PHY_CNTL_ANEG_EN |
+ PHY_CNTL_ANEG_RST |
+ PHY_CNTL_SPEED |
+ PHY_CNTL_DPLX);
+ }
+ }
+
+ if (timeout < 1) {
+ printf ("%s: PHY auto-negotiate timed out\n", SMC_DEV_NAME);
+ }
+
+ /* Fail if we detected an auto-negotiate remote fault */
+ if (status & PHY_STAT_REM_FLT) {
+ printf ("%s: PHY remote fault detected\n", SMC_DEV_NAME);
+ }
+
+ /* Re-Configure the Receive/Phy Control register */
+ SMC_outw (dev, RPC_DEFAULT, RPC_REG);
+
+smc_phy_configure_exit: ;
+
+}
+#endif /* !CONFIG_SMC91111_EXT_PHY */
+
+
+#if SMC_DEBUG > 2
+static void print_packet( byte * buf, int length )
+{
+ int i;
+ int remainder;
+ int lines;
+
+ printf("Packet of length %d \n", length );
+
+#if SMC_DEBUG > 3
+ lines = length / 16;
+ remainder = length % 16;
+
+ for ( i = 0; i < lines ; i ++ ) {
+ int cur;
+
+ for ( cur = 0; cur < 8; cur ++ ) {
+ byte a, b;
+
+ a = *(buf ++ );
+ b = *(buf ++ );
+ printf("%02x%02x ", a, b );
+ }
+ printf("\n");
+ }
+ for ( i = 0; i < remainder/2 ; i++ ) {
+ byte a, b;
+
+ a = *(buf ++ );
+ b = *(buf ++ );
+ printf("%02x%02x ", a, b );
+ }
+ printf("\n");
+#endif
+}
+#endif
+
+int smc91111_initialize(u8 dev_num, int base_addr)
+{
+ struct smc91111_priv *priv;
+ struct eth_device *dev;
+ int i;
+
+ priv = malloc(sizeof(*priv));
+ if (!priv)
+ return 0;
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ free(priv);
+ return 0;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ priv->dev_num = dev_num;
+ dev->priv = priv;
+ dev->iobase = base_addr;
+
+ swap_to(ETHERNET);
+ SMC_SELECT_BANK(dev, 1);
+ for (i = 0; i < 6; ++i)
+ dev->enetaddr[i] = SMC_inb(dev, (ADDR0_REG + i));
+ swap_to(FLASH);
+
+ dev->init = smc_init;
+ dev->halt = smc_halt;
+ dev->send = smc_send;
+ dev->recv = smc_rcv;
+ dev->write_hwaddr = smc_write_hwaddr;
+ sprintf(dev->name, "%s-%hu", SMC_DEV_NAME, dev_num);
+
+ eth_register(dev);
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/smc91111.h b/qemu/roms/u-boot/drivers/net/smc91111.h
new file mode 100644
index 000000000..d9135cb57
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/smc91111.h
@@ -0,0 +1,789 @@
+/*------------------------------------------------------------------------
+ . smc91111.h - macros for the LAN91C111 Ethernet Driver
+ .
+ . (C) Copyright 2002
+ . Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ . Rolf Offermanns <rof@sysgo.de>
+ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ . Developed by Simple Network Magic Corporation (SNMC)
+ . Copyright (C) 1996 by Erik Stahlman (ES)
+ .
+ * SPDX-License-Identifier: GPL-2.0+
+ .
+ . This file contains register information and access macros for
+ . the LAN91C111 single chip ethernet controller. It is a modified
+ . version of the smc9194.h file.
+ .
+ . Information contained in this file was obtained from the LAN91C111
+ . manual from SMC. To get a copy, if you really want one, you can find
+ . information under www.smsc.com.
+ .
+ . Authors
+ . Erik Stahlman ( erik@vt.edu )
+ . Daris A Nevil ( dnevil@snmc.com )
+ .
+ . History
+ . 03/16/01 Daris A Nevil Modified for use with LAN91C111 device
+ .
+ ---------------------------------------------------------------------------*/
+#ifndef _SMC91111_H_
+#define _SMC91111_H_
+
+#include <asm/types.h>
+#include <config.h>
+
+/*
+ * This function may be called by the board specific initialisation code
+ * in order to override the default mac address.
+ */
+
+void smc_set_mac_addr (const unsigned char *addr);
+
+
+/* I want some simple types */
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long int dword;
+
+struct smc91111_priv{
+ u8 dev_num;
+};
+
+/*
+ . DEBUGGING LEVELS
+ .
+ . 0 for normal operation
+ . 1 for slightly more details
+ . >2 for various levels of increasingly useless information
+ . 2 for interrupt tracking, status flags
+ . 3 for packet info
+ . 4 for complete packet dumps
+*/
+/*#define SMC_DEBUG 0 */
+
+/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
+
+#define SMC_IO_EXTENT 16
+
+#ifdef CONFIG_CPU_PXA25X
+
+#ifdef CONFIG_XSENGINE
+#define SMC_inl(a,r) (*((volatile dword *)((a)->iobase+((r)<<1))))
+#define SMC_inw(a,r) (*((volatile word *)((a)->iobase+((r)<<1))))
+#define SMC_inb(a,p) ({ \
+ unsigned int __p = (unsigned int)((a)->iobase + ((p)<<1)); \
+ unsigned int __v = *(volatile unsigned short *)((__p) & ~2); \
+ if (__p & 2) __v >>= 8; \
+ else __v &= 0xff; \
+ __v; })
+#elif defined(CONFIG_XAENIAX)
+#define SMC_inl(a,r) (*((volatile dword *)((a)->iobase+(r))))
+#define SMC_inw(a,z) ({ \
+ unsigned int __p = (unsigned int)((a)->iobase + (z)); \
+ unsigned int __v = *(volatile unsigned int *)((__p) & ~3); \
+ if (__p & 3) __v >>= 16; \
+ else __v &= 0xffff; \
+ __v; })
+#define SMC_inb(a,p) ({ \
+ unsigned int ___v = SMC_inw((a),(p) & ~1); \
+ if ((p) & 1) ___v >>= 8; \
+ else ___v &= 0xff; \
+ ___v; })
+#else
+#define SMC_inl(a,r) (*((volatile dword *)((a)->iobase+(r))))
+#define SMC_inw(a,r) (*((volatile word *)((a)->iobase+(r))))
+#define SMC_inb(a,p) ({ \
+ unsigned int __p = (unsigned int)((a)->iobase + (p)); \
+ unsigned int __v = *(volatile unsigned short *)((__p) & ~1); \
+ if (__p & 1) __v >>= 8; \
+ else __v &= 0xff; \
+ __v; })
+#endif
+
+#ifdef CONFIG_XSENGINE
+#define SMC_outl(a,d,r) (*((volatile dword *)((a)->iobase+(r<<1))) = d)
+#define SMC_outw(a,d,r) (*((volatile word *)((a)->iobase+(r<<1))) = d)
+#elif defined (CONFIG_XAENIAX)
+#define SMC_outl(a,d,r) (*((volatile dword *)((a)->iobase+(r))) = d)
+#define SMC_outw(a,d,p) ({ \
+ dword __dwo = SMC_inl((a),(p) & ~3); \
+ dword __dwn = (word)(d); \
+ __dwo &= ((p) & 3) ? 0x0000ffff : 0xffff0000; \
+ __dwo |= ((p) & 3) ? __dwn << 16 : __dwn; \
+ SMC_outl((a), __dwo, (p) & ~3); \
+})
+#else
+#define SMC_outl(a,d,r) (*((volatile dword *)((a)->iobase+(r))) = d)
+#define SMC_outw(a,d,r) (*((volatile word *)((a)->iobase+(r))) = d)
+#endif
+
+#define SMC_outb(a,d,r) ({ word __d = (byte)(d); \
+ word __w = SMC_inw((a),(r)&~1); \
+ __w &= ((r)&1) ? 0x00FF : 0xFF00; \
+ __w |= ((r)&1) ? __d<<8 : __d; \
+ SMC_outw((a),__w,(r)&~1); \
+ })
+
+#define SMC_outsl(a,r,b,l) ({ int __i; \
+ dword *__b2; \
+ __b2 = (dword *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outl((a), *(__b2 + __i), r); \
+ } \
+ })
+
+#define SMC_outsw(a,r,b,l) ({ int __i; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outw((a), *(__b2 + __i), r); \
+ } \
+ })
+
+#define SMC_insl(a,r,b,l) ({ int __i ; \
+ dword *__b2; \
+ __b2 = (dword *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inl((a),(r)); \
+ SMC_inl((a),0); \
+ }; \
+ })
+
+#define SMC_insw(a,r,b,l) ({ int __i ; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inw((a),(r)); \
+ SMC_inw((a),0); \
+ }; \
+ })
+
+#define SMC_insb(a,r,b,l) ({ int __i ; \
+ byte *__b2; \
+ __b2 = (byte *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inb((a),(r)); \
+ SMC_inb((a),0); \
+ }; \
+ })
+
+#elif defined(CONFIG_LEON) /* if not CONFIG_CPU_PXA25X */
+
+#define SMC_LEON_SWAP16(_x_) ({ word _x = (_x_); ((_x << 8) | (_x >> 8)); })
+
+#define SMC_LEON_SWAP32(_x_) \
+ ({ dword _x = (_x_); \
+ ((_x << 24) | \
+ ((0x0000FF00UL & _x) << 8) | \
+ ((0x00FF0000UL & _x) >> 8) | \
+ (_x >> 24)); })
+
+#define SMC_inl(a,r) (SMC_LEON_SWAP32((*(volatile dword *)((a)->iobase+((r)<<0)))))
+#define SMC_inl_nosw(a,r) ((*(volatile dword *)((a)->iobase+((r)<<0))))
+#define SMC_inw(a,r) (SMC_LEON_SWAP16((*(volatile word *)((a)->iobase+((r)<<0)))))
+#define SMC_inw_nosw(a,r) ((*(volatile word *)((a)->iobase+((r)<<0))))
+#define SMC_inb(a,p) ({ \
+ word ___v = SMC_inw((a),(p) & ~1); \
+ if ((p) & 1) ___v >>= 8; \
+ else ___v &= 0xff; \
+ ___v; })
+
+#define SMC_outl(a,d,r) (*(volatile dword *)((a)->iobase+((r)<<0))=SMC_LEON_SWAP32(d))
+#define SMC_outl_nosw(a,d,r) (*(volatile dword *)((a)->iobase+((r)<<0))=(d))
+#define SMC_outw(a,d,r) (*(volatile word *)((a)->iobase+((r)<<0))=SMC_LEON_SWAP16(d))
+#define SMC_outw_nosw(a,d,r) (*(volatile word *)((a)->iobase+((r)<<0))=(d))
+#define SMC_outb(a,d,r) do{ word __d = (byte)(d); \
+ word __w = SMC_inw((a),(r)&~1); \
+ __w &= ((r)&1) ? 0x00FF : 0xFF00; \
+ __w |= ((r)&1) ? __d<<8 : __d; \
+ SMC_outw((a),__w,(r)&~1); \
+ }while(0)
+#define SMC_outsl(a,r,b,l) do{ int __i; \
+ dword *__b2; \
+ __b2 = (dword *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outl_nosw((a), *(__b2 + __i), r); \
+ } \
+ }while(0)
+#define SMC_outsw(a,r,b,l) do{ int __i; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outw_nosw((a), *(__b2 + __i), r); \
+ } \
+ }while(0)
+#define SMC_insl(a,r,b,l) do{ int __i ; \
+ dword *__b2; \
+ __b2 = (dword *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inl_nosw((a),(r)); \
+ }; \
+ }while(0)
+
+#define SMC_insw(a,r,b,l) do{ int __i ; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inw_nosw((a),(r)); \
+ }; \
+ }while(0)
+
+#define SMC_insb(a,r,b,l) do{ int __i ; \
+ byte *__b2; \
+ __b2 = (byte *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inb((a),(r)); \
+ }; \
+ }while(0)
+
+#else /* if not CONFIG_CPU_PXA25X and not CONFIG_LEON */
+
+#ifndef CONFIG_SMC_USE_IOFUNCS /* these macros don't work on some boards */
+/*
+ * We have only 16 Bit PCMCIA access on Socket 0
+ */
+
+#ifdef CONFIG_ADNPESC1
+#define SMC_inw(a,r) (*((volatile word *)((a)->iobase+((r)<<1))))
+#elif CONFIG_BLACKFIN
+#define SMC_inw(a,r) ({ word __v = (*((volatile word *)((a)->iobase+(r)))); SSYNC(); __v;})
+#elif CONFIG_ARM64
+#define SMC_inw(a, r) (*((volatile word*)((a)->iobase+((dword)(r)))))
+#else
+#define SMC_inw(a, r) (*((volatile word*)((a)->iobase+(r))))
+#endif
+#define SMC_inb(a,r) (((r)&1) ? SMC_inw((a),(r)&~1)>>8 : SMC_inw((a),(r)&0xFF))
+
+#ifdef CONFIG_ADNPESC1
+#define SMC_outw(a,d,r) (*((volatile word *)((a)->iobase+((r)<<1))) = d)
+#elif CONFIG_BLACKFIN
+#define SMC_outw(a, d, r) \
+ ({ (*((volatile word*)((a)->iobase+((r)))) = d); \
+ SSYNC(); \
+ })
+#elif CONFIG_ARM64
+#define SMC_outw(a, d, r) \
+ (*((volatile word*)((a)->iobase+((dword)(r)))) = d)
+#else
+#define SMC_outw(a, d, r) \
+ (*((volatile word*)((a)->iobase+(r))) = d)
+#endif
+#define SMC_outb(a,d,r) ({ word __d = (byte)(d); \
+ word __w = SMC_inw((a),(r)&~1); \
+ __w &= ((r)&1) ? 0x00FF : 0xFF00; \
+ __w |= ((r)&1) ? __d<<8 : __d; \
+ SMC_outw((a),__w,(r)&~1); \
+ })
+#if 0
+#define SMC_outsw(a,r,b,l) outsw((a)->iobase+(r), (b), (l))
+#else
+#define SMC_outsw(a,r,b,l) ({ int __i; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outw((a), *(__b2 + __i), r); \
+ } \
+ })
+#endif
+
+#if 0
+#define SMC_insw(a,r,b,l) insw((a)->iobase+(r), (b), (l))
+#else
+#define SMC_insw(a,r,b,l) ({ int __i ; \
+ word *__b2; \
+ __b2 = (word *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inw((a),(r)); \
+ SMC_inw((a),0); \
+ }; \
+ })
+#endif
+
+#endif /* CONFIG_SMC_USE_IOFUNCS */
+
+#if defined(CONFIG_SMC_USE_32_BIT)
+
+#ifdef CONFIG_XSENGINE
+#define SMC_inl(a,r) (*((volatile dword *)((a)->iobase+(r<<1))))
+#else
+#define SMC_inl(a,r) (*((volatile dword *)((a)->iobase+(r))))
+#endif
+
+#define SMC_insl(a,r,b,l) ({ int __i ; \
+ dword *__b2; \
+ __b2 = (dword *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = SMC_inl((a),(r)); \
+ SMC_inl((a),0); \
+ }; \
+ })
+
+#ifdef CONFIG_XSENGINE
+#define SMC_outl(a,d,r) (*((volatile dword *)((a)->iobase+(r<<1))) = d)
+#else
+#define SMC_outl(a,d,r) (*((volatile dword *)((a)->iobase+(r))) = d)
+#endif
+#define SMC_outsl(a,r,b,l) ({ int __i; \
+ dword *__b2; \
+ __b2 = (dword *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ SMC_outl((a), *(__b2 + __i), r); \
+ } \
+ })
+
+#endif /* CONFIG_SMC_USE_32_BIT */
+
+#endif
+
+/*---------------------------------------------------------------
+ .
+ . A description of the SMSC registers is probably in order here,
+ . although for details, the SMC datasheet is invaluable.
+ .
+ . Basically, the chip has 4 banks of registers ( 0 to 3 ), which
+ . are accessed by writing a number into the BANK_SELECT register
+ . ( I also use a SMC_SELECT_BANK macro for this ).
+ .
+ . The banks are configured so that for most purposes, bank 2 is all
+ . that is needed for simple run time tasks.
+ -----------------------------------------------------------------------*/
+
+/*
+ . Bank Select Register:
+ .
+ . yyyy yyyy 0000 00xx
+ . xx = bank number
+ . yyyy yyyy = 0x33, for identification purposes.
+*/
+#define BANK_SELECT 14
+
+/* Transmit Control Register */
+/* BANK 0 */
+#define TCR_REG 0x0000 /* transmit control register */
+#define TCR_ENABLE 0x0001 /* When 1 we can transmit */
+#define TCR_LOOP 0x0002 /* Controls output pin LBK */
+#define TCR_FORCOL 0x0004 /* When 1 will force a collision */
+#define TCR_PAD_EN 0x0080 /* When 1 will pad tx frames < 64 bytes w/0 */
+#define TCR_NOCRC 0x0100 /* When 1 will not append CRC to tx frames */
+#define TCR_MON_CSN 0x0400 /* When 1 tx monitors carrier */
+#define TCR_FDUPLX 0x0800 /* When 1 enables full duplex operation */
+#define TCR_STP_SQET 0x1000 /* When 1 stops tx if Signal Quality Error */
+#define TCR_EPH_LOOP 0x2000 /* When 1 enables EPH block loopback */
+#define TCR_SWFDUP 0x8000 /* When 1 enables Switched Full Duplex mode */
+
+#define TCR_CLEAR 0 /* do NOTHING */
+/* the default settings for the TCR register : */
+/* QUESTION: do I want to enable padding of short packets ? */
+#define TCR_DEFAULT TCR_ENABLE
+
+
+/* EPH Status Register */
+/* BANK 0 */
+#define EPH_STATUS_REG 0x0002
+#define ES_TX_SUC 0x0001 /* Last TX was successful */
+#define ES_SNGL_COL 0x0002 /* Single collision detected for last tx */
+#define ES_MUL_COL 0x0004 /* Multiple collisions detected for last tx */
+#define ES_LTX_MULT 0x0008 /* Last tx was a multicast */
+#define ES_16COL 0x0010 /* 16 Collisions Reached */
+#define ES_SQET 0x0020 /* Signal Quality Error Test */
+#define ES_LTXBRD 0x0040 /* Last tx was a broadcast */
+#define ES_TXDEFR 0x0080 /* Transmit Deferred */
+#define ES_LATCOL 0x0200 /* Late collision detected on last tx */
+#define ES_LOSTCARR 0x0400 /* Lost Carrier Sense */
+#define ES_EXC_DEF 0x0800 /* Excessive Deferral */
+#define ES_CTR_ROL 0x1000 /* Counter Roll Over indication */
+#define ES_LINK_OK 0x4000 /* Driven by inverted value of nLNK pin */
+#define ES_TXUNRN 0x8000 /* Tx Underrun */
+
+
+/* Receive Control Register */
+/* BANK 0 */
+#define RCR_REG 0x0004
+#define RCR_RX_ABORT 0x0001 /* Set if a rx frame was aborted */
+#define RCR_PRMS 0x0002 /* Enable promiscuous mode */
+#define RCR_ALMUL 0x0004 /* When set accepts all multicast frames */
+#define RCR_RXEN 0x0100 /* IFF this is set, we can receive packets */
+#define RCR_STRIP_CRC 0x0200 /* When set strips CRC from rx packets */
+#define RCR_ABORT_ENB 0x0200 /* When set will abort rx on collision */
+#define RCR_FILT_CAR 0x0400 /* When set filters leading 12 bit s of carrier */
+#define RCR_SOFTRST 0x8000 /* resets the chip */
+
+/* the normal settings for the RCR register : */
+#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN)
+#define RCR_CLEAR 0x0 /* set it to a base state */
+
+/* Counter Register */
+/* BANK 0 */
+#define COUNTER_REG 0x0006
+
+/* Memory Information Register */
+/* BANK 0 */
+#define MIR_REG 0x0008
+
+/* Receive/Phy Control Register */
+/* BANK 0 */
+#define RPC_REG 0x000A
+#define RPC_SPEED 0x2000 /* When 1 PHY is in 100Mbps mode. */
+#define RPC_DPLX 0x1000 /* When 1 PHY is in Full-Duplex Mode */
+#define RPC_ANEG 0x0800 /* When 1 PHY is in Auto-Negotiate Mode */
+#define RPC_LSXA_SHFT 5 /* Bits to shift LS2A,LS1A,LS0A to lsb */
+#define RPC_LSXB_SHFT 2 /* Bits to get LS2B,LS1B,LS0B to lsb */
+#define RPC_LED_100_10 (0x00) /* LED = 100Mbps OR's with 10Mbps link detect */
+#define RPC_LED_RES (0x01) /* LED = Reserved */
+#define RPC_LED_10 (0x02) /* LED = 10Mbps link detect */
+#define RPC_LED_FD (0x03) /* LED = Full Duplex Mode */
+#define RPC_LED_TX_RX (0x04) /* LED = TX or RX packet occurred */
+#define RPC_LED_100 (0x05) /* LED = 100Mbps link dectect */
+#define RPC_LED_TX (0x06) /* LED = TX packet occurred */
+#define RPC_LED_RX (0x07) /* LED = RX packet occurred */
+#if defined(CONFIG_DK1C20) || defined(CONFIG_DK1S10)
+/* buggy schematic: LEDa -> yellow, LEDb --> green */
+#define RPC_DEFAULT ( RPC_SPEED | RPC_DPLX | RPC_ANEG \
+ | (RPC_LED_TX_RX << RPC_LSXA_SHFT) \
+ | (RPC_LED_100_10 << RPC_LSXB_SHFT) )
+#elif defined(CONFIG_ADNPESC1)
+/* SSV ADNP/ESC1 has only one LED: LEDa -> Rx/Tx indicator */
+#define RPC_DEFAULT ( RPC_SPEED | RPC_DPLX | RPC_ANEG \
+ | (RPC_LED_TX_RX << RPC_LSXA_SHFT) \
+ | (RPC_LED_100_10 << RPC_LSXB_SHFT) )
+#else
+/* SMSC reference design: LEDa --> green, LEDb --> yellow */
+#define RPC_DEFAULT ( RPC_SPEED | RPC_DPLX | RPC_ANEG \
+ | (RPC_LED_100_10 << RPC_LSXA_SHFT) \
+ | (RPC_LED_TX_RX << RPC_LSXB_SHFT) )
+#endif
+
+/* Bank 0 0x000C is reserved */
+
+/* Bank Select Register */
+/* All Banks */
+#define BSR_REG 0x000E
+
+
+/* Configuration Reg */
+/* BANK 1 */
+#define CONFIG_REG 0x0000
+#define CONFIG_EXT_PHY 0x0200 /* 1=external MII, 0=internal Phy */
+#define CONFIG_GPCNTRL 0x0400 /* Inverse value drives pin nCNTRL */
+#define CONFIG_NO_WAIT 0x1000 /* When 1 no extra wait states on ISA bus */
+#define CONFIG_EPH_POWER_EN 0x8000 /* When 0 EPH is placed into low power mode. */
+
+/* Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low */
+#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN)
+
+
+/* Base Address Register */
+/* BANK 1 */
+#define BASE_REG 0x0002
+
+
+/* Individual Address Registers */
+/* BANK 1 */
+#define ADDR0_REG 0x0004
+#define ADDR1_REG 0x0006
+#define ADDR2_REG 0x0008
+
+
+/* General Purpose Register */
+/* BANK 1 */
+#define GP_REG 0x000A
+
+
+/* Control Register */
+/* BANK 1 */
+#define CTL_REG 0x000C
+#define CTL_RCV_BAD 0x4000 /* When 1 bad CRC packets are received */
+#define CTL_AUTO_RELEASE 0x0800 /* When 1 tx pages are released automatically */
+#define CTL_LE_ENABLE 0x0080 /* When 1 enables Link Error interrupt */
+#define CTL_CR_ENABLE 0x0040 /* When 1 enables Counter Rollover interrupt */
+#define CTL_TE_ENABLE 0x0020 /* When 1 enables Transmit Error interrupt */
+#define CTL_EEPROM_SELECT 0x0004 /* Controls EEPROM reload & store */
+#define CTL_RELOAD 0x0002 /* When set reads EEPROM into registers */
+#define CTL_STORE 0x0001 /* When set stores registers into EEPROM */
+#define CTL_DEFAULT (0x1A10) /* Autorelease enabled*/
+
+/* MMU Command Register */
+/* BANK 2 */
+#define MMU_CMD_REG 0x0000
+#define MC_BUSY 1 /* When 1 the last release has not completed */
+#define MC_NOP (0<<5) /* No Op */
+#define MC_ALLOC (1<<5) /* OR with number of 256 byte packets */
+#define MC_RESET (2<<5) /* Reset MMU to initial state */
+#define MC_REMOVE (3<<5) /* Remove the current rx packet */
+#define MC_RELEASE (4<<5) /* Remove and release the current rx packet */
+#define MC_FREEPKT (5<<5) /* Release packet in PNR register */
+#define MC_ENQUEUE (6<<5) /* Enqueue the packet for transmit */
+#define MC_RSTTXFIFO (7<<5) /* Reset the TX FIFOs */
+
+
+/* Packet Number Register */
+/* BANK 2 */
+#define PN_REG 0x0002
+
+
+/* Allocation Result Register */
+/* BANK 2 */
+#define AR_REG 0x0003
+#define AR_FAILED 0x80 /* Alocation Failed */
+
+
+/* RX FIFO Ports Register */
+/* BANK 2 */
+#define RXFIFO_REG 0x0004 /* Must be read as a word */
+#define RXFIFO_REMPTY 0x8000 /* RX FIFO Empty */
+
+
+/* TX FIFO Ports Register */
+/* BANK 2 */
+#define TXFIFO_REG RXFIFO_REG /* Must be read as a word */
+#define TXFIFO_TEMPTY 0x80 /* TX FIFO Empty */
+
+
+/* Pointer Register */
+/* BANK 2 */
+#define PTR_REG 0x0006
+#define PTR_RCV 0x8000 /* 1=Receive area, 0=Transmit area */
+#define PTR_AUTOINC 0x4000 /* Auto increment the pointer on each access */
+#define PTR_READ 0x2000 /* When 1 the operation is a read */
+#define PTR_NOTEMPTY 0x0800 /* When 1 _do not_ write fifo DATA REG */
+
+
+/* Data Register */
+/* BANK 2 */
+#define SMC91111_DATA_REG 0x0008
+
+
+/* Interrupt Status/Acknowledge Register */
+/* BANK 2 */
+#define SMC91111_INT_REG 0x000C
+
+
+/* Interrupt Mask Register */
+/* BANK 2 */
+#define IM_REG 0x000D
+#define IM_MDINT 0x80 /* PHY MI Register 18 Interrupt */
+#define IM_ERCV_INT 0x40 /* Early Receive Interrupt */
+#define IM_EPH_INT 0x20 /* Set by Etheret Protocol Handler section */
+#define IM_RX_OVRN_INT 0x10 /* Set by Receiver Overruns */
+#define IM_ALLOC_INT 0x08 /* Set when allocation request is completed */
+#define IM_TX_EMPTY_INT 0x04 /* Set if the TX FIFO goes empty */
+#define IM_TX_INT 0x02 /* Transmit Interrrupt */
+#define IM_RCV_INT 0x01 /* Receive Interrupt */
+
+
+/* Multicast Table Registers */
+/* BANK 3 */
+#define MCAST_REG1 0x0000
+#define MCAST_REG2 0x0002
+#define MCAST_REG3 0x0004
+#define MCAST_REG4 0x0006
+
+
+/* Management Interface Register (MII) */
+/* BANK 3 */
+#define MII_REG 0x0008
+#define MII_MSK_CRS100 0x4000 /* Disables CRS100 detection during tx half dup */
+#define MII_MDOE 0x0008 /* MII Output Enable */
+#define MII_MCLK 0x0004 /* MII Clock, pin MDCLK */
+#define MII_MDI 0x0002 /* MII Input, pin MDI */
+#define MII_MDO 0x0001 /* MII Output, pin MDO */
+
+
+/* Revision Register */
+/* BANK 3 */
+#define REV_REG 0x000A /* ( hi: chip id low: rev # ) */
+
+
+/* Early RCV Register */
+/* BANK 3 */
+/* this is NOT on SMC9192 */
+#define ERCV_REG 0x000C
+#define ERCV_RCV_DISCRD 0x0080 /* When 1 discards a packet being received */
+#define ERCV_THRESHOLD 0x001F /* ERCV Threshold Mask */
+
+/* External Register */
+/* BANK 7 */
+#define EXT_REG 0x0000
+
+
+#define CHIP_9192 3
+#define CHIP_9194 4
+#define CHIP_9195 5
+#define CHIP_9196 6
+#define CHIP_91100 7
+#define CHIP_91100FD 8
+#define CHIP_91111FD 9
+
+#if 0
+static const char * chip_ids[ 15 ] = {
+ NULL, NULL, NULL,
+ /* 3 */ "SMC91C90/91C92",
+ /* 4 */ "SMC91C94",
+ /* 5 */ "SMC91C95",
+ /* 6 */ "SMC91C96",
+ /* 7 */ "SMC91C100",
+ /* 8 */ "SMC91C100FD",
+ /* 9 */ "SMC91C111",
+ NULL, NULL,
+ NULL, NULL, NULL};
+#endif
+
+/*
+ . Transmit status bits
+*/
+#define TS_SUCCESS 0x0001
+#define TS_LOSTCAR 0x0400
+#define TS_LATCOL 0x0200
+#define TS_16COL 0x0010
+
+/*
+ . Receive status bits
+*/
+#define RS_ALGNERR 0x8000
+#define RS_BRODCAST 0x4000
+#define RS_BADCRC 0x2000
+#define RS_ODDFRAME 0x1000 /* bug: the LAN91C111 never sets this on receive */
+#define RS_TOOLONG 0x0800
+#define RS_TOOSHORT 0x0400
+#define RS_MULTICAST 0x0001
+#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+
+/* PHY Types */
+enum {
+ PHY_LAN83C183 = 1, /* LAN91C111 Internal PHY */
+ PHY_LAN83C180
+};
+
+
+/* PHY Register Addresses (LAN91C111 Internal PHY) */
+
+/* PHY Control Register */
+#define PHY_CNTL_REG 0x00
+#define PHY_CNTL_RST 0x8000 /* 1=PHY Reset */
+#define PHY_CNTL_LPBK 0x4000 /* 1=PHY Loopback */
+#define PHY_CNTL_SPEED 0x2000 /* 1=100Mbps, 0=10Mpbs */
+#define PHY_CNTL_ANEG_EN 0x1000 /* 1=Enable Auto negotiation */
+#define PHY_CNTL_PDN 0x0800 /* 1=PHY Power Down mode */
+#define PHY_CNTL_MII_DIS 0x0400 /* 1=MII 4 bit interface disabled */
+#define PHY_CNTL_ANEG_RST 0x0200 /* 1=Reset Auto negotiate */
+#define PHY_CNTL_DPLX 0x0100 /* 1=Full Duplex, 0=Half Duplex */
+#define PHY_CNTL_COLTST 0x0080 /* 1= MII Colision Test */
+
+/* PHY Status Register */
+#define PHY_STAT_REG 0x01
+#define PHY_STAT_CAP_T4 0x8000 /* 1=100Base-T4 capable */
+#define PHY_STAT_CAP_TXF 0x4000 /* 1=100Base-X full duplex capable */
+#define PHY_STAT_CAP_TXH 0x2000 /* 1=100Base-X half duplex capable */
+#define PHY_STAT_CAP_TF 0x1000 /* 1=10Mbps full duplex capable */
+#define PHY_STAT_CAP_TH 0x0800 /* 1=10Mbps half duplex capable */
+#define PHY_STAT_CAP_SUPR 0x0040 /* 1=recv mgmt frames with not preamble */
+#define PHY_STAT_ANEG_ACK 0x0020 /* 1=ANEG has completed */
+#define PHY_STAT_REM_FLT 0x0010 /* 1=Remote Fault detected */
+#define PHY_STAT_CAP_ANEG 0x0008 /* 1=Auto negotiate capable */
+#define PHY_STAT_LINK 0x0004 /* 1=valid link */
+#define PHY_STAT_JAB 0x0002 /* 1=10Mbps jabber condition */
+#define PHY_STAT_EXREG 0x0001 /* 1=extended registers implemented */
+
+/* PHY Identifier Registers */
+#define PHY_ID1_REG 0x02 /* PHY Identifier 1 */
+#define PHY_ID2_REG 0x03 /* PHY Identifier 2 */
+
+/* PHY Auto-Negotiation Advertisement Register */
+#define PHY_AD_REG 0x04
+#define PHY_AD_NP 0x8000 /* 1=PHY requests exchange of Next Page */
+#define PHY_AD_ACK 0x4000 /* 1=got link code word from remote */
+#define PHY_AD_RF 0x2000 /* 1=advertise remote fault */
+#define PHY_AD_T4 0x0200 /* 1=PHY is capable of 100Base-T4 */
+#define PHY_AD_TX_FDX 0x0100 /* 1=PHY is capable of 100Base-TX FDPLX */
+#define PHY_AD_TX_HDX 0x0080 /* 1=PHY is capable of 100Base-TX HDPLX */
+#define PHY_AD_10_FDX 0x0040 /* 1=PHY is capable of 10Base-T FDPLX */
+#define PHY_AD_10_HDX 0x0020 /* 1=PHY is capable of 10Base-T HDPLX */
+#define PHY_AD_CSMA 0x0001 /* 1=PHY is capable of 802.3 CMSA */
+
+/* PHY Auto-negotiation Remote End Capability Register */
+#define PHY_RMT_REG 0x05
+/* Uses same bit definitions as PHY_AD_REG */
+
+/* PHY Configuration Register 1 */
+#define PHY_CFG1_REG 0x10
+#define PHY_CFG1_LNKDIS 0x8000 /* 1=Rx Link Detect Function disabled */
+#define PHY_CFG1_XMTDIS 0x4000 /* 1=TP Transmitter Disabled */
+#define PHY_CFG1_XMTPDN 0x2000 /* 1=TP Transmitter Powered Down */
+#define PHY_CFG1_BYPSCR 0x0400 /* 1=Bypass scrambler/descrambler */
+#define PHY_CFG1_UNSCDS 0x0200 /* 1=Unscramble Idle Reception Disable */
+#define PHY_CFG1_EQLZR 0x0100 /* 1=Rx Equalizer Disabled */
+#define PHY_CFG1_CABLE 0x0080 /* 1=STP(150ohm), 0=UTP(100ohm) */
+#define PHY_CFG1_RLVL0 0x0040 /* 1=Rx Squelch level reduced by 4.5db */
+#define PHY_CFG1_TLVL_SHIFT 2 /* Transmit Output Level Adjust */
+#define PHY_CFG1_TLVL_MASK 0x003C
+#define PHY_CFG1_TRF_MASK 0x0003 /* Transmitter Rise/Fall time */
+
+
+/* PHY Configuration Register 2 */
+#define PHY_CFG2_REG 0x11
+#define PHY_CFG2_APOLDIS 0x0020 /* 1=Auto Polarity Correction disabled */
+#define PHY_CFG2_JABDIS 0x0010 /* 1=Jabber disabled */
+#define PHY_CFG2_MREG 0x0008 /* 1=Multiple register access (MII mgt) */
+#define PHY_CFG2_INTMDIO 0x0004 /* 1=Interrupt signaled with MDIO pulseo */
+
+/* PHY Status Output (and Interrupt status) Register */
+#define PHY_INT_REG 0x12 /* Status Output (Interrupt Status) */
+#define PHY_INT_INT 0x8000 /* 1=bits have changed since last read */
+#define PHY_INT_LNKFAIL 0x4000 /* 1=Link Not detected */
+#define PHY_INT_LOSSSYNC 0x2000 /* 1=Descrambler has lost sync */
+#define PHY_INT_CWRD 0x1000 /* 1=Invalid 4B5B code detected on rx */
+#define PHY_INT_SSD 0x0800 /* 1=No Start Of Stream detected on rx */
+#define PHY_INT_ESD 0x0400 /* 1=No End Of Stream detected on rx */
+#define PHY_INT_RPOL 0x0200 /* 1=Reverse Polarity detected */
+#define PHY_INT_JAB 0x0100 /* 1=Jabber detected */
+#define PHY_INT_SPDDET 0x0080 /* 1=100Base-TX mode, 0=10Base-T mode */
+#define PHY_INT_DPLXDET 0x0040 /* 1=Device in Full Duplex */
+
+/* PHY Interrupt/Status Mask Register */
+#define PHY_MASK_REG 0x13 /* Interrupt Mask */
+/* Uses the same bit definitions as PHY_INT_REG */
+
+
+/*-------------------------------------------------------------------------
+ . I define some macros to make it easier to do somewhat common
+ . or slightly complicated, repeated tasks.
+ --------------------------------------------------------------------------*/
+
+/* select a register bank, 0 to 3 */
+
+#define SMC_SELECT_BANK(a,x) { SMC_outw((a), (x), BANK_SELECT ); }
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(a,x) {\
+ unsigned char mask;\
+ SMC_SELECT_BANK((a),2);\
+ mask = SMC_inb((a), IM_REG );\
+ mask |= (x);\
+ SMC_outb( (a), mask, IM_REG ); \
+}
+
+/* this disables an interrupt from the interrupt mask register */
+
+#define SMC_DISABLE_INT(a,x) {\
+ unsigned char mask;\
+ SMC_SELECT_BANK(2);\
+ mask = SMC_inb( (a), IM_REG );\
+ mask &= ~(x);\
+ SMC_outb( (a), mask, IM_REG ); \
+}
+
+/*----------------------------------------------------------------------
+ . Define the interrupts that I want to receive from the card
+ .
+ . I want:
+ . IM_EPH_INT, for nasty errors
+ . IM_RCV_INT, for happy received packets
+ . IM_RX_OVRN_INT, because I have to kick the receiver
+ . IM_MDINT, for PHY Register 18 Status Changes
+ --------------------------------------------------------------------------*/
+#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | \
+ IM_MDINT)
+
+#endif /* _SMC_91111_H_ */
diff --git a/qemu/roms/u-boot/drivers/net/smc911x.c b/qemu/roms/u-boot/drivers/net/smc911x.c
new file mode 100644
index 000000000..b097c1a56
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/smc911x.c
@@ -0,0 +1,282 @@
+/*
+ * SMSC LAN9[12]1[567] Network driver
+ *
+ * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+
+#include "smc911x.h"
+
+u32 pkt_data_pull(struct eth_device *dev, u32 addr) \
+ __attribute__ ((weak, alias ("smc911x_reg_read")));
+void pkt_data_push(struct eth_device *dev, u32 addr, u32 val) \
+ __attribute__ ((weak, alias ("smc911x_reg_write")));
+
+static void smc911x_handle_mac_address(struct eth_device *dev)
+{
+ unsigned long addrh, addrl;
+ uchar *m = dev->enetaddr;
+
+ addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
+ addrh = m[4] | (m[5] << 8);
+ smc911x_set_mac_csr(dev, ADDRL, addrl);
+ smc911x_set_mac_csr(dev, ADDRH, addrh);
+
+ printf(DRIVERNAME ": MAC %pM\n", m);
+}
+
+static int smc911x_eth_phy_read(struct eth_device *dev,
+ u8 phy, u8 reg, u16 *val)
+{
+ while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
+ ;
+
+ smc911x_set_mac_csr(dev, MII_ACC, phy << 11 | reg << 6 |
+ MII_ACC_MII_BUSY);
+
+ while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
+ ;
+
+ *val = smc911x_get_mac_csr(dev, MII_DATA);
+
+ return 0;
+}
+
+static int smc911x_eth_phy_write(struct eth_device *dev,
+ u8 phy, u8 reg, u16 val)
+{
+ while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
+ ;
+
+ smc911x_set_mac_csr(dev, MII_DATA, val);
+ smc911x_set_mac_csr(dev, MII_ACC,
+ phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE);
+
+ while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
+ ;
+ return 0;
+}
+
+static int smc911x_phy_reset(struct eth_device *dev)
+{
+ u32 reg;
+
+ reg = smc911x_reg_read(dev, PMT_CTRL);
+ reg &= ~0xfffff030;
+ reg |= PMT_CTRL_PHY_RST;
+ smc911x_reg_write(dev, PMT_CTRL, reg);
+
+ mdelay(100);
+
+ return 0;
+}
+
+static void smc911x_phy_configure(struct eth_device *dev)
+{
+ int timeout;
+ u16 status;
+
+ smc911x_phy_reset(dev);
+
+ smc911x_eth_phy_write(dev, 1, MII_BMCR, BMCR_RESET);
+ mdelay(1);
+ smc911x_eth_phy_write(dev, 1, MII_ADVERTISE, 0x01e1);
+ smc911x_eth_phy_write(dev, 1, MII_BMCR, BMCR_ANENABLE |
+ BMCR_ANRESTART);
+
+ timeout = 5000;
+ do {
+ mdelay(1);
+ if ((timeout--) == 0)
+ goto err_out;
+
+ if (smc911x_eth_phy_read(dev, 1, MII_BMSR, &status) != 0)
+ goto err_out;
+ } while (!(status & BMSR_LSTATUS));
+
+ printf(DRIVERNAME ": phy initialized\n");
+
+ return;
+
+err_out:
+ printf(DRIVERNAME ": autonegotiation timed out\n");
+}
+
+static void smc911x_enable(struct eth_device *dev)
+{
+ /* Enable TX */
+ smc911x_reg_write(dev, HW_CFG, 8 << 16 | HW_CFG_SF);
+
+ smc911x_reg_write(dev, GPT_CFG, GPT_CFG_TIMER_EN | 10000);
+
+ smc911x_reg_write(dev, TX_CFG, TX_CFG_TX_ON);
+
+ /* no padding to start of packets */
+ smc911x_reg_write(dev, RX_CFG, 0);
+
+ smc911x_set_mac_csr(dev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
+ MAC_CR_HBDIS);
+
+}
+
+static int smc911x_init(struct eth_device *dev, bd_t * bd)
+{
+ struct chip_id *id = dev->priv;
+
+ printf(DRIVERNAME ": detected %s controller\n", id->name);
+
+ smc911x_reset(dev);
+
+ /* Configure the PHY, initialize the link state */
+ smc911x_phy_configure(dev);
+
+ smc911x_handle_mac_address(dev);
+
+ /* Turn on Tx + Rx */
+ smc911x_enable(dev);
+
+ return 0;
+}
+
+static int smc911x_send(struct eth_device *dev, void *packet, int length)
+{
+ u32 *data = (u32*)packet;
+ u32 tmplen;
+ u32 status;
+
+ smc911x_reg_write(dev, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG |
+ TX_CMD_A_INT_LAST_SEG | length);
+ smc911x_reg_write(dev, TX_DATA_FIFO, length);
+
+ tmplen = (length + 3) / 4;
+
+ while (tmplen--)
+ pkt_data_push(dev, TX_DATA_FIFO, *data++);
+
+ /* wait for transmission */
+ while (!((smc911x_reg_read(dev, TX_FIFO_INF) &
+ TX_FIFO_INF_TSUSED) >> 16));
+
+ /* get status. Ignore 'no carrier' error, it has no meaning for
+ * full duplex operation
+ */
+ status = smc911x_reg_read(dev, TX_STATUS_FIFO) &
+ (TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL |
+ TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
+
+ if (!status)
+ return 0;
+
+ printf(DRIVERNAME ": failed to send packet: %s%s%s%s%s\n",
+ status & TX_STS_LOC ? "TX_STS_LOC " : "",
+ status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "",
+ status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "",
+ status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "",
+ status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : "");
+
+ return -1;
+}
+
+static void smc911x_halt(struct eth_device *dev)
+{
+ smc911x_reset(dev);
+}
+
+static int smc911x_rx(struct eth_device *dev)
+{
+ u32 *data = (u32 *)NetRxPackets[0];
+ u32 pktlen, tmplen;
+ u32 status;
+
+ if ((smc911x_reg_read(dev, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
+ status = smc911x_reg_read(dev, RX_STATUS_FIFO);
+ pktlen = (status & RX_STS_PKT_LEN) >> 16;
+
+ smc911x_reg_write(dev, RX_CFG, 0);
+
+ tmplen = (pktlen + 3) / 4;
+ while (tmplen--)
+ *data++ = pkt_data_pull(dev, RX_DATA_FIFO);
+
+ if (status & RX_STS_ES)
+ printf(DRIVERNAME
+ ": dropped bad packet. Status: 0x%08x\n",
+ status);
+ else
+ NetReceive(NetRxPackets[0], pktlen);
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+/* wrapper for smc911x_eth_phy_read */
+static int smc911x_miiphy_read(const char *devname, u8 phy, u8 reg, u16 *val)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ if (dev)
+ return smc911x_eth_phy_read(dev, phy, reg, val);
+ return -1;
+}
+/* wrapper for smc911x_eth_phy_write */
+static int smc911x_miiphy_write(const char *devname, u8 phy, u8 reg, u16 val)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ if (dev)
+ return smc911x_eth_phy_write(dev, phy, reg, val);
+ return -1;
+}
+#endif
+
+int smc911x_initialize(u8 dev_num, int base_addr)
+{
+ unsigned long addrl, addrh;
+ struct eth_device *dev;
+
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ return -1;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ dev->iobase = base_addr;
+
+ /* Try to detect chip. Will fail if not present. */
+ if (smc911x_detect_chip(dev)) {
+ free(dev);
+ return 0;
+ }
+
+ addrh = smc911x_get_mac_csr(dev, ADDRH);
+ addrl = smc911x_get_mac_csr(dev, ADDRL);
+ if (!(addrl == 0xffffffff && addrh == 0x0000ffff)) {
+ /* address is obtained from optional eeprom */
+ dev->enetaddr[0] = addrl;
+ dev->enetaddr[1] = addrl >> 8;
+ dev->enetaddr[2] = addrl >> 16;
+ dev->enetaddr[3] = addrl >> 24;
+ dev->enetaddr[4] = addrh;
+ dev->enetaddr[5] = addrh >> 8;
+ }
+
+ dev->init = smc911x_init;
+ dev->halt = smc911x_halt;
+ dev->send = smc911x_send;
+ dev->recv = smc911x_rx;
+ sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num);
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, smc911x_miiphy_read, smc911x_miiphy_write);
+#endif
+
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/smc911x.h b/qemu/roms/u-boot/drivers/net/smc911x.h
new file mode 100644
index 000000000..acae0cfb8
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/smc911x.h
@@ -0,0 +1,500 @@
+/*
+ * SMSC LAN9[12]1[567] Network driver
+ *
+ * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _SMC911X_H_
+#define _SMC911X_H_
+
+#include <linux/types.h>
+
+#define DRIVERNAME "smc911x"
+
+#if defined (CONFIG_SMC911X_32_BIT) && \
+ defined (CONFIG_SMC911X_16_BIT)
+#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \
+ CONFIG_SMC911X_16_BIT shall be set"
+#endif
+
+#if defined (CONFIG_SMC911X_32_BIT)
+static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset)
+{
+ return *(volatile u32*)(dev->iobase + offset);
+}
+u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
+ __attribute__((weak, alias("__smc911x_reg_read")));
+
+static inline void __smc911x_reg_write(struct eth_device *dev,
+ u32 offset, u32 val)
+{
+ *(volatile u32*)(dev->iobase + offset) = val;
+}
+void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val)
+ __attribute__((weak, alias("__smc911x_reg_write")));
+#elif defined (CONFIG_SMC911X_16_BIT)
+static inline u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
+{
+ volatile u16 *addr_16 = (u16 *)(dev->iobase + offset);
+ return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16));
+}
+static inline void smc911x_reg_write(struct eth_device *dev,
+ u32 offset, u32 val)
+{
+ *(volatile u16 *)(dev->iobase + offset) = (u16)val;
+ *(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16);
+}
+#else
+#error "SMC911X: undefined bus width"
+#endif /* CONFIG_SMC911X_16_BIT */
+
+/* Below are the register offsets and bit definitions
+ * of the Lan911x memory space
+ */
+#define RX_DATA_FIFO 0x00
+
+#define TX_DATA_FIFO 0x20
+#define TX_CMD_A_INT_ON_COMP 0x80000000
+#define TX_CMD_A_INT_BUF_END_ALGN 0x03000000
+#define TX_CMD_A_INT_4_BYTE_ALGN 0x00000000
+#define TX_CMD_A_INT_16_BYTE_ALGN 0x01000000
+#define TX_CMD_A_INT_32_BYTE_ALGN 0x02000000
+#define TX_CMD_A_INT_DATA_OFFSET 0x001F0000
+#define TX_CMD_A_INT_FIRST_SEG 0x00002000
+#define TX_CMD_A_INT_LAST_SEG 0x00001000
+#define TX_CMD_A_BUF_SIZE 0x000007FF
+#define TX_CMD_B_PKT_TAG 0xFFFF0000
+#define TX_CMD_B_ADD_CRC_DISABLE 0x00002000
+#define TX_CMD_B_DISABLE_PADDING 0x00001000
+#define TX_CMD_B_PKT_BYTE_LENGTH 0x000007FF
+
+#define RX_STATUS_FIFO 0x40
+#define RX_STS_PKT_LEN 0x3FFF0000
+#define RX_STS_ES 0x00008000
+#define RX_STS_BCST 0x00002000
+#define RX_STS_LEN_ERR 0x00001000
+#define RX_STS_RUNT_ERR 0x00000800
+#define RX_STS_MCAST 0x00000400
+#define RX_STS_TOO_LONG 0x00000080
+#define RX_STS_COLL 0x00000040
+#define RX_STS_ETH_TYPE 0x00000020
+#define RX_STS_WDOG_TMT 0x00000010
+#define RX_STS_MII_ERR 0x00000008
+#define RX_STS_DRIBBLING 0x00000004
+#define RX_STS_CRC_ERR 0x00000002
+#define RX_STATUS_FIFO_PEEK 0x44
+#define TX_STATUS_FIFO 0x48
+#define TX_STS_TAG 0xFFFF0000
+#define TX_STS_ES 0x00008000
+#define TX_STS_LOC 0x00000800
+#define TX_STS_NO_CARR 0x00000400
+#define TX_STS_LATE_COLL 0x00000200
+#define TX_STS_MANY_COLL 0x00000100
+#define TX_STS_COLL_CNT 0x00000078
+#define TX_STS_MANY_DEFER 0x00000004
+#define TX_STS_UNDERRUN 0x00000002
+#define TX_STS_DEFERRED 0x00000001
+#define TX_STATUS_FIFO_PEEK 0x4C
+#define ID_REV 0x50
+#define ID_REV_CHIP_ID 0xFFFF0000 /* RO */
+#define ID_REV_REV_ID 0x0000FFFF /* RO */
+
+#define INT_CFG 0x54
+#define INT_CFG_INT_DEAS 0xFF000000 /* R/W */
+#define INT_CFG_INT_DEAS_CLR 0x00004000
+#define INT_CFG_INT_DEAS_STS 0x00002000
+#define INT_CFG_IRQ_INT 0x00001000 /* RO */
+#define INT_CFG_IRQ_EN 0x00000100 /* R/W */
+ /* R/W Not Affected by SW Reset */
+#define INT_CFG_IRQ_POL 0x00000010
+ /* R/W Not Affected by SW Reset */
+#define INT_CFG_IRQ_TYPE 0x00000001
+
+#define INT_STS 0x58
+#define INT_STS_SW_INT 0x80000000 /* R/WC */
+#define INT_STS_TXSTOP_INT 0x02000000 /* R/WC */
+#define INT_STS_RXSTOP_INT 0x01000000 /* R/WC */
+#define INT_STS_RXDFH_INT 0x00800000 /* R/WC */
+#define INT_STS_RXDF_INT 0x00400000 /* R/WC */
+#define INT_STS_TX_IOC 0x00200000 /* R/WC */
+#define INT_STS_RXD_INT 0x00100000 /* R/WC */
+#define INT_STS_GPT_INT 0x00080000 /* R/WC */
+#define INT_STS_PHY_INT 0x00040000 /* RO */
+#define INT_STS_PME_INT 0x00020000 /* R/WC */
+#define INT_STS_TXSO 0x00010000 /* R/WC */
+#define INT_STS_RWT 0x00008000 /* R/WC */
+#define INT_STS_RXE 0x00004000 /* R/WC */
+#define INT_STS_TXE 0x00002000 /* R/WC */
+/*#define INT_STS_ERX 0x00001000*/ /* R/WC */
+#define INT_STS_TDFU 0x00000800 /* R/WC */
+#define INT_STS_TDFO 0x00000400 /* R/WC */
+#define INT_STS_TDFA 0x00000200 /* R/WC */
+#define INT_STS_TSFF 0x00000100 /* R/WC */
+#define INT_STS_TSFL 0x00000080 /* R/WC */
+/*#define INT_STS_RXDF 0x00000040*/ /* R/WC */
+#define INT_STS_RDFO 0x00000040 /* R/WC */
+#define INT_STS_RDFL 0x00000020 /* R/WC */
+#define INT_STS_RSFF 0x00000010 /* R/WC */
+#define INT_STS_RSFL 0x00000008 /* R/WC */
+#define INT_STS_GPIO2_INT 0x00000004 /* R/WC */
+#define INT_STS_GPIO1_INT 0x00000002 /* R/WC */
+#define INT_STS_GPIO0_INT 0x00000001 /* R/WC */
+#define INT_EN 0x5C
+#define INT_EN_SW_INT_EN 0x80000000 /* R/W */
+#define INT_EN_TXSTOP_INT_EN 0x02000000 /* R/W */
+#define INT_EN_RXSTOP_INT_EN 0x01000000 /* R/W */
+#define INT_EN_RXDFH_INT_EN 0x00800000 /* R/W */
+/*#define INT_EN_RXDF_INT_EN 0x00400000*/ /* R/W */
+#define INT_EN_TIOC_INT_EN 0x00200000 /* R/W */
+#define INT_EN_RXD_INT_EN 0x00100000 /* R/W */
+#define INT_EN_GPT_INT_EN 0x00080000 /* R/W */
+#define INT_EN_PHY_INT_EN 0x00040000 /* R/W */
+#define INT_EN_PME_INT_EN 0x00020000 /* R/W */
+#define INT_EN_TXSO_EN 0x00010000 /* R/W */
+#define INT_EN_RWT_EN 0x00008000 /* R/W */
+#define INT_EN_RXE_EN 0x00004000 /* R/W */
+#define INT_EN_TXE_EN 0x00002000 /* R/W */
+/*#define INT_EN_ERX_EN 0x00001000*/ /* R/W */
+#define INT_EN_TDFU_EN 0x00000800 /* R/W */
+#define INT_EN_TDFO_EN 0x00000400 /* R/W */
+#define INT_EN_TDFA_EN 0x00000200 /* R/W */
+#define INT_EN_TSFF_EN 0x00000100 /* R/W */
+#define INT_EN_TSFL_EN 0x00000080 /* R/W */
+/*#define INT_EN_RXDF_EN 0x00000040*/ /* R/W */
+#define INT_EN_RDFO_EN 0x00000040 /* R/W */
+#define INT_EN_RDFL_EN 0x00000020 /* R/W */
+#define INT_EN_RSFF_EN 0x00000010 /* R/W */
+#define INT_EN_RSFL_EN 0x00000008 /* R/W */
+#define INT_EN_GPIO2_INT 0x00000004 /* R/W */
+#define INT_EN_GPIO1_INT 0x00000002 /* R/W */
+#define INT_EN_GPIO0_INT 0x00000001 /* R/W */
+
+#define BYTE_TEST 0x64
+#define FIFO_INT 0x68
+#define FIFO_INT_TX_AVAIL_LEVEL 0xFF000000 /* R/W */
+#define FIFO_INT_TX_STS_LEVEL 0x00FF0000 /* R/W */
+#define FIFO_INT_RX_AVAIL_LEVEL 0x0000FF00 /* R/W */
+#define FIFO_INT_RX_STS_LEVEL 0x000000FF /* R/W */
+
+#define RX_CFG 0x6C
+#define RX_CFG_RX_END_ALGN 0xC0000000 /* R/W */
+#define RX_CFG_RX_END_ALGN4 0x00000000 /* R/W */
+#define RX_CFG_RX_END_ALGN16 0x40000000 /* R/W */
+#define RX_CFG_RX_END_ALGN32 0x80000000 /* R/W */
+#define RX_CFG_RX_DMA_CNT 0x0FFF0000 /* R/W */
+#define RX_CFG_RX_DUMP 0x00008000 /* R/W */
+#define RX_CFG_RXDOFF 0x00001F00 /* R/W */
+/*#define RX_CFG_RXBAD 0x00000001*/ /* R/W */
+
+#define TX_CFG 0x70
+/*#define TX_CFG_TX_DMA_LVL 0xE0000000*/ /* R/W */
+ /* R/W Self Clearing */
+/*#define TX_CFG_TX_DMA_CNT 0x0FFF0000*/
+#define TX_CFG_TXS_DUMP 0x00008000 /* Self Clearing */
+#define TX_CFG_TXD_DUMP 0x00004000 /* Self Clearing */
+#define TX_CFG_TXSAO 0x00000004 /* R/W */
+#define TX_CFG_TX_ON 0x00000002 /* R/W */
+#define TX_CFG_STOP_TX 0x00000001 /* Self Clearing */
+
+#define HW_CFG 0x74
+#define HW_CFG_TTM 0x00200000 /* R/W */
+#define HW_CFG_SF 0x00100000 /* R/W */
+#define HW_CFG_TX_FIF_SZ 0x000F0000 /* R/W */
+#define HW_CFG_TR 0x00003000 /* R/W */
+#define HW_CFG_PHY_CLK_SEL 0x00000060 /* R/W */
+#define HW_CFG_PHY_CLK_SEL_INT_PHY 0x00000000 /* R/W */
+#define HW_CFG_PHY_CLK_SEL_EXT_PHY 0x00000020 /* R/W */
+#define HW_CFG_PHY_CLK_SEL_CLK_DIS 0x00000040 /* R/W */
+#define HW_CFG_SMI_SEL 0x00000010 /* R/W */
+#define HW_CFG_EXT_PHY_DET 0x00000008 /* RO */
+#define HW_CFG_EXT_PHY_EN 0x00000004 /* R/W */
+#define HW_CFG_32_16_BIT_MODE 0x00000004 /* RO */
+#define HW_CFG_SRST_TO 0x00000002 /* RO */
+#define HW_CFG_SRST 0x00000001 /* Self Clearing */
+
+#define RX_DP_CTRL 0x78
+#define RX_DP_CTRL_RX_FFWD 0x80000000 /* R/W */
+#define RX_DP_CTRL_FFWD_BUSY 0x80000000 /* RO */
+
+#define RX_FIFO_INF 0x7C
+#define RX_FIFO_INF_RXSUSED 0x00FF0000 /* RO */
+#define RX_FIFO_INF_RXDUSED 0x0000FFFF /* RO */
+
+#define TX_FIFO_INF 0x80
+#define TX_FIFO_INF_TSUSED 0x00FF0000 /* RO */
+#define TX_FIFO_INF_TDFREE 0x0000FFFF /* RO */
+
+#define PMT_CTRL 0x84
+#define PMT_CTRL_PM_MODE 0x00003000 /* Self Clearing */
+#define PMT_CTRL_PHY_RST 0x00000400 /* Self Clearing */
+#define PMT_CTRL_WOL_EN 0x00000200 /* R/W */
+#define PMT_CTRL_ED_EN 0x00000100 /* R/W */
+ /* R/W Not Affected by SW Reset */
+#define PMT_CTRL_PME_TYPE 0x00000040
+#define PMT_CTRL_WUPS 0x00000030 /* R/WC */
+#define PMT_CTRL_WUPS_NOWAKE 0x00000000 /* R/WC */
+#define PMT_CTRL_WUPS_ED 0x00000010 /* R/WC */
+#define PMT_CTRL_WUPS_WOL 0x00000020 /* R/WC */
+#define PMT_CTRL_WUPS_MULTI 0x00000030 /* R/WC */
+#define PMT_CTRL_PME_IND 0x00000008 /* R/W */
+#define PMT_CTRL_PME_POL 0x00000004 /* R/W */
+ /* R/W Not Affected by SW Reset */
+#define PMT_CTRL_PME_EN 0x00000002
+#define PMT_CTRL_READY 0x00000001 /* RO */
+
+#define GPIO_CFG 0x88
+#define GPIO_CFG_LED3_EN 0x40000000 /* R/W */
+#define GPIO_CFG_LED2_EN 0x20000000 /* R/W */
+#define GPIO_CFG_LED1_EN 0x10000000 /* R/W */
+#define GPIO_CFG_GPIO2_INT_POL 0x04000000 /* R/W */
+#define GPIO_CFG_GPIO1_INT_POL 0x02000000 /* R/W */
+#define GPIO_CFG_GPIO0_INT_POL 0x01000000 /* R/W */
+#define GPIO_CFG_EEPR_EN 0x00700000 /* R/W */
+#define GPIO_CFG_GPIOBUF2 0x00040000 /* R/W */
+#define GPIO_CFG_GPIOBUF1 0x00020000 /* R/W */
+#define GPIO_CFG_GPIOBUF0 0x00010000 /* R/W */
+#define GPIO_CFG_GPIODIR2 0x00000400 /* R/W */
+#define GPIO_CFG_GPIODIR1 0x00000200 /* R/W */
+#define GPIO_CFG_GPIODIR0 0x00000100 /* R/W */
+#define GPIO_CFG_GPIOD4 0x00000010 /* R/W */
+#define GPIO_CFG_GPIOD3 0x00000008 /* R/W */
+#define GPIO_CFG_GPIOD2 0x00000004 /* R/W */
+#define GPIO_CFG_GPIOD1 0x00000002 /* R/W */
+#define GPIO_CFG_GPIOD0 0x00000001 /* R/W */
+
+#define GPT_CFG 0x8C
+#define GPT_CFG_TIMER_EN 0x20000000 /* R/W */
+#define GPT_CFG_GPT_LOAD 0x0000FFFF /* R/W */
+
+#define GPT_CNT 0x90
+#define GPT_CNT_GPT_CNT 0x0000FFFF /* RO */
+
+#define ENDIAN 0x98
+#define FREE_RUN 0x9C
+#define RX_DROP 0xA0
+#define MAC_CSR_CMD 0xA4
+#define MAC_CSR_CMD_CSR_BUSY 0x80000000 /* Self Clearing */
+#define MAC_CSR_CMD_R_NOT_W 0x40000000 /* R/W */
+#define MAC_CSR_CMD_CSR_ADDR 0x000000FF /* R/W */
+
+#define MAC_CSR_DATA 0xA8
+#define AFC_CFG 0xAC
+#define AFC_CFG_AFC_HI 0x00FF0000 /* R/W */
+#define AFC_CFG_AFC_LO 0x0000FF00 /* R/W */
+#define AFC_CFG_BACK_DUR 0x000000F0 /* R/W */
+#define AFC_CFG_FCMULT 0x00000008 /* R/W */
+#define AFC_CFG_FCBRD 0x00000004 /* R/W */
+#define AFC_CFG_FCADD 0x00000002 /* R/W */
+#define AFC_CFG_FCANY 0x00000001 /* R/W */
+
+#define E2P_CMD 0xB0
+#define E2P_CMD_EPC_BUSY 0x80000000 /* Self Clearing */
+#define E2P_CMD_EPC_CMD 0x70000000 /* R/W */
+#define E2P_CMD_EPC_CMD_READ 0x00000000 /* R/W */
+#define E2P_CMD_EPC_CMD_EWDS 0x10000000 /* R/W */
+#define E2P_CMD_EPC_CMD_EWEN 0x20000000 /* R/W */
+#define E2P_CMD_EPC_CMD_WRITE 0x30000000 /* R/W */
+#define E2P_CMD_EPC_CMD_WRAL 0x40000000 /* R/W */
+#define E2P_CMD_EPC_CMD_ERASE 0x50000000 /* R/W */
+#define E2P_CMD_EPC_CMD_ERAL 0x60000000 /* R/W */
+#define E2P_CMD_EPC_CMD_RELOAD 0x70000000 /* R/W */
+#define E2P_CMD_EPC_TIMEOUT 0x00000200 /* RO */
+#define E2P_CMD_MAC_ADDR_LOADED 0x00000100 /* RO */
+#define E2P_CMD_EPC_ADDR 0x000000FF /* R/W */
+
+#define E2P_DATA 0xB4
+#define E2P_DATA_EEPROM_DATA 0x000000FF /* R/W */
+/* end of LAN register offsets and bit definitions */
+
+/* MAC Control and Status registers */
+#define MAC_CR 0x01 /* R/W */
+
+/* MAC_CR - MAC Control Register */
+#define MAC_CR_RXALL 0x80000000
+/* TODO: delete this bit? It is not described in the data sheet. */
+#define MAC_CR_HBDIS 0x10000000
+#define MAC_CR_RCVOWN 0x00800000
+#define MAC_CR_LOOPBK 0x00200000
+#define MAC_CR_FDPX 0x00100000
+#define MAC_CR_MCPAS 0x00080000
+#define MAC_CR_PRMS 0x00040000
+#define MAC_CR_INVFILT 0x00020000
+#define MAC_CR_PASSBAD 0x00010000
+#define MAC_CR_HFILT 0x00008000
+#define MAC_CR_HPFILT 0x00002000
+#define MAC_CR_LCOLL 0x00001000
+#define MAC_CR_BCAST 0x00000800
+#define MAC_CR_DISRTY 0x00000400
+#define MAC_CR_PADSTR 0x00000100
+#define MAC_CR_BOLMT_MASK 0x000000C0
+#define MAC_CR_DFCHK 0x00000020
+#define MAC_CR_TXEN 0x00000008
+#define MAC_CR_RXEN 0x00000004
+
+#define ADDRH 0x02 /* R/W mask 0x0000FFFFUL */
+#define ADDRL 0x03 /* R/W mask 0xFFFFFFFFUL */
+#define HASHH 0x04 /* R/W */
+#define HASHL 0x05 /* R/W */
+
+#define MII_ACC 0x06 /* R/W */
+#define MII_ACC_PHY_ADDR 0x0000F800
+#define MII_ACC_MIIRINDA 0x000007C0
+#define MII_ACC_MII_WRITE 0x00000002
+#define MII_ACC_MII_BUSY 0x00000001
+
+#define MII_DATA 0x07 /* R/W mask 0x0000FFFFUL */
+
+#define FLOW 0x08 /* R/W */
+#define FLOW_FCPT 0xFFFF0000
+#define FLOW_FCPASS 0x00000004
+#define FLOW_FCEN 0x00000002
+#define FLOW_FCBSY 0x00000001
+
+#define VLAN1 0x09 /* R/W mask 0x0000FFFFUL */
+#define VLAN1_VTI1 0x0000ffff
+
+#define VLAN2 0x0A /* R/W mask 0x0000FFFFUL */
+#define VLAN2_VTI2 0x0000ffff
+
+#define WUFF 0x0B /* WO */
+
+#define WUCSR 0x0C /* R/W */
+#define WUCSR_GUE 0x00000200
+#define WUCSR_WUFR 0x00000040
+#define WUCSR_MPR 0x00000020
+#define WUCSR_WAKE_EN 0x00000004
+#define WUCSR_MPEN 0x00000002
+
+/* Chip ID values */
+#define CHIP_89218 0x218a
+#define CHIP_9115 0x115
+#define CHIP_9116 0x116
+#define CHIP_9117 0x117
+#define CHIP_9118 0x118
+#define CHIP_9211 0x9211
+#define CHIP_9215 0x115a
+#define CHIP_9216 0x116a
+#define CHIP_9217 0x117a
+#define CHIP_9218 0x118a
+#define CHIP_9220 0x9220
+#define CHIP_9221 0x9221
+
+struct chip_id {
+ u16 id;
+ char *name;
+};
+
+static const struct chip_id chip_ids[] = {
+ { CHIP_89218, "LAN89218" },
+ { CHIP_9115, "LAN9115" },
+ { CHIP_9116, "LAN9116" },
+ { CHIP_9117, "LAN9117" },
+ { CHIP_9118, "LAN9118" },
+ { CHIP_9211, "LAN9211" },
+ { CHIP_9215, "LAN9215" },
+ { CHIP_9216, "LAN9216" },
+ { CHIP_9217, "LAN9217" },
+ { CHIP_9218, "LAN9218" },
+ { CHIP_9220, "LAN9220" },
+ { CHIP_9221, "LAN9221" },
+ { 0, NULL },
+};
+
+static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg)
+{
+ while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ smc911x_reg_write(dev, MAC_CSR_CMD,
+ MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
+ while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+
+ return smc911x_reg_read(dev, MAC_CSR_DATA);
+}
+
+static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data)
+{
+ while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ smc911x_reg_write(dev, MAC_CSR_DATA, data);
+ smc911x_reg_write(dev, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
+ while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+}
+
+static int smc911x_detect_chip(struct eth_device *dev)
+{
+ unsigned long val, i;
+
+ val = smc911x_reg_read(dev, BYTE_TEST);
+ if (val == 0xffffffff) {
+ /* Special case -- no chip present */
+ return -1;
+ } else if (val != 0x87654321) {
+ printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
+ return -1;
+ }
+
+ val = smc911x_reg_read(dev, ID_REV) >> 16;
+ for (i = 0; chip_ids[i].id != 0; i++) {
+ if (chip_ids[i].id == val) break;
+ }
+ if (!chip_ids[i].id) {
+ printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
+ return -1;
+ }
+
+ dev->priv = (void *)&chip_ids[i];
+
+ return 0;
+}
+
+static void smc911x_reset(struct eth_device *dev)
+{
+ int timeout;
+
+ /*
+ * Take out of PM setting first
+ * Device is already wake up if PMT_CTRL_READY bit is set
+ */
+ if ((smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY) == 0) {
+ /* Write to the bytetest will take out of powerdown */
+ smc911x_reg_write(dev, BYTE_TEST, 0x0);
+
+ timeout = 10;
+
+ while (timeout-- &&
+ !(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY))
+ udelay(10);
+ if (timeout < 0) {
+ printf(DRIVERNAME
+ ": timeout waiting for PM restore\n");
+ return;
+ }
+ }
+
+ /* Disable interrupts */
+ smc911x_reg_write(dev, INT_EN, 0);
+
+ smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST);
+
+ timeout = 1000;
+ while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
+ udelay(10);
+
+ if (timeout < 0) {
+ printf(DRIVERNAME ": reset timeout\n");
+ return;
+ }
+
+ /* Reset the FIFO level and flow control settings */
+ smc911x_set_mac_csr(dev, FLOW, FLOW_FCPT | FLOW_FCEN);
+ smc911x_reg_write(dev, AFC_CFG, 0x0050287F);
+
+ /* Set to LED outputs */
+ smc911x_reg_write(dev, GPIO_CFG, 0x70070000);
+}
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/sunxi_wemac.c b/qemu/roms/u-boot/drivers/net/sunxi_wemac.c
new file mode 100644
index 000000000..699a38158
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/sunxi_wemac.c
@@ -0,0 +1,525 @@
+/*
+ * sunxi_wemac.c -- Allwinner A10 ethernet driver
+ *
+ * (C) Copyright 2012, Stefan Roese <sr@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+
+/* EMAC register */
+struct wemac_regs {
+ u32 ctl; /* 0x00 */
+ u32 tx_mode; /* 0x04 */
+ u32 tx_flow; /* 0x08 */
+ u32 tx_ctl0; /* 0x0c */
+ u32 tx_ctl1; /* 0x10 */
+ u32 tx_ins; /* 0x14 */
+ u32 tx_pl0; /* 0x18 */
+ u32 tx_pl1; /* 0x1c */
+ u32 tx_sta; /* 0x20 */
+ u32 tx_io_data; /* 0x24 */
+ u32 tx_io_data1; /* 0x28 */
+ u32 tx_tsvl0; /* 0x2c */
+ u32 tx_tsvh0; /* 0x30 */
+ u32 tx_tsvl1; /* 0x34 */
+ u32 tx_tsvh1; /* 0x38 */
+ u32 rx_ctl; /* 0x3c */
+ u32 rx_hash0; /* 0x40 */
+ u32 rx_hash1; /* 0x44 */
+ u32 rx_sta; /* 0x48 */
+ u32 rx_io_data; /* 0x4c */
+ u32 rx_fbc; /* 0x50 */
+ u32 int_ctl; /* 0x54 */
+ u32 int_sta; /* 0x58 */
+ u32 mac_ctl0; /* 0x5c */
+ u32 mac_ctl1; /* 0x60 */
+ u32 mac_ipgt; /* 0x64 */
+ u32 mac_ipgr; /* 0x68 */
+ u32 mac_clrt; /* 0x6c */
+ u32 mac_maxf; /* 0x70 */
+ u32 mac_supp; /* 0x74 */
+ u32 mac_test; /* 0x78 */
+ u32 mac_mcfg; /* 0x7c */
+ u32 mac_mcmd; /* 0x80 */
+ u32 mac_madr; /* 0x84 */
+ u32 mac_mwtd; /* 0x88 */
+ u32 mac_mrdd; /* 0x8c */
+ u32 mac_mind; /* 0x90 */
+ u32 mac_ssrr; /* 0x94 */
+ u32 mac_a0; /* 0x98 */
+ u32 mac_a1; /* 0x9c */
+};
+
+/* SRAMC register */
+struct sunxi_sramc_regs {
+ u32 ctrl0;
+ u32 ctrl1;
+};
+
+/* 0: Disable 1: Aborted frame enable(default) */
+#define EMAC_TX_AB_M (0x1 << 0)
+/* 0: CPU 1: DMA(default) */
+#define EMAC_TX_TM (0x1 << 1)
+
+#define EMAC_TX_SETUP (0)
+
+/* 0: DRQ asserted 1: DRQ automatically(default) */
+#define EMAC_RX_DRQ_MODE (0x1 << 1)
+/* 0: CPU 1: DMA(default) */
+#define EMAC_RX_TM (0x1 << 2)
+/* 0: Normal(default) 1: Pass all Frames */
+#define EMAC_RX_PA (0x1 << 4)
+/* 0: Normal(default) 1: Pass Control Frames */
+#define EMAC_RX_PCF (0x1 << 5)
+/* 0: Normal(default) 1: Pass Frames with CRC Error */
+#define EMAC_RX_PCRCE (0x1 << 6)
+/* 0: Normal(default) 1: Pass Frames with Length Error */
+#define EMAC_RX_PLE (0x1 << 7)
+/* 0: Normal 1: Pass Frames length out of range(default) */
+#define EMAC_RX_POR (0x1 << 8)
+/* 0: Not accept 1: Accept unicast Packets(default) */
+#define EMAC_RX_UCAD (0x1 << 16)
+/* 0: Normal(default) 1: DA Filtering */
+#define EMAC_RX_DAF (0x1 << 17)
+/* 0: Not accept 1: Accept multicast Packets(default) */
+#define EMAC_RX_MCO (0x1 << 20)
+/* 0: Disable(default) 1: Enable Hash filter */
+#define EMAC_RX_MHF (0x1 << 21)
+/* 0: Not accept 1: Accept Broadcast Packets(default) */
+#define EMAC_RX_BCO (0x1 << 22)
+/* 0: Disable(default) 1: Enable SA Filtering */
+#define EMAC_RX_SAF (0x1 << 24)
+/* 0: Normal(default) 1: Inverse Filtering */
+#define EMAC_RX_SAIF (0x1 << 25)
+
+#define EMAC_RX_SETUP (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \
+ EMAC_RX_MCO | EMAC_RX_BCO)
+
+/* 0: Disable 1: Enable Receive Flow Control(default) */
+#define EMAC_MAC_CTL0_RFC (0x1 << 2)
+/* 0: Disable 1: Enable Transmit Flow Control(default) */
+#define EMAC_MAC_CTL0_TFC (0x1 << 3)
+
+#define EMAC_MAC_CTL0_SETUP (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC)
+
+/* 0: Disable 1: Enable MAC Frame Length Checking(default) */
+#define EMAC_MAC_CTL1_FLC (0x1 << 1)
+/* 0: Disable(default) 1: Enable Huge Frame */
+#define EMAC_MAC_CTL1_HF (0x1 << 2)
+/* 0: Disable(default) 1: Enable MAC Delayed CRC */
+#define EMAC_MAC_CTL1_DCRC (0x1 << 3)
+/* 0: Disable 1: Enable MAC CRC(default) */
+#define EMAC_MAC_CTL1_CRC (0x1 << 4)
+/* 0: Disable 1: Enable MAC PAD Short frames(default) */
+#define EMAC_MAC_CTL1_PC (0x1 << 5)
+/* 0: Disable(default) 1: Enable MAC PAD Short frames and append CRC */
+#define EMAC_MAC_CTL1_VC (0x1 << 6)
+/* 0: Disable(default) 1: Enable MAC auto detect Short frames */
+#define EMAC_MAC_CTL1_ADP (0x1 << 7)
+/* 0: Disable(default) 1: Enable */
+#define EMAC_MAC_CTL1_PRE (0x1 << 8)
+/* 0: Disable(default) 1: Enable */
+#define EMAC_MAC_CTL1_LPE (0x1 << 9)
+/* 0: Disable(default) 1: Enable no back off */
+#define EMAC_MAC_CTL1_NB (0x1 << 12)
+/* 0: Disable(default) 1: Enable */
+#define EMAC_MAC_CTL1_BNB (0x1 << 13)
+/* 0: Disable(default) 1: Enable */
+#define EMAC_MAC_CTL1_ED (0x1 << 14)
+
+#define EMAC_MAC_CTL1_SETUP (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \
+ EMAC_MAC_CTL1_PC)
+
+#define EMAC_MAC_IPGT 0x15
+
+#define EMAC_MAC_NBTB_IPG1 0xC
+#define EMAC_MAC_NBTB_IPG2 0x12
+
+#define EMAC_MAC_CW 0x37
+#define EMAC_MAC_RM 0xF
+
+#define EMAC_MAC_MFL 0x0600
+
+/* Receive status */
+#define EMAC_CRCERR (1 << 4)
+#define EMAC_LENERR (3 << 5)
+
+#define DMA_CPU_TRRESHOLD 2000
+
+struct wemac_eth_dev {
+ u32 speed;
+ u32 duplex;
+ u32 phy_configured;
+ int link_printed;
+};
+
+struct wemac_rxhdr {
+ s16 rx_len;
+ u16 rx_status;
+};
+
+static void wemac_inblk_32bit(void *reg, void *data, int count)
+{
+ int cnt = (count + 3) >> 2;
+
+ if (cnt) {
+ u32 *buf = data;
+
+ do {
+ u32 x = readl(reg);
+ *buf++ = x;
+ } while (--cnt);
+ }
+}
+
+static void wemac_outblk_32bit(void *reg, void *data, int count)
+{
+ int cnt = (count + 3) >> 2;
+
+ if (cnt) {
+ const u32 *buf = data;
+
+ do {
+ writel(*buf++, reg);
+ } while (--cnt);
+ }
+}
+
+/*
+ * Read a word from phyxcer
+ */
+static int wemac_phy_read(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+ /* issue the phy address and reg */
+ writel(addr << 8 | reg, &regs->mac_madr);
+
+ /* pull up the phy io line */
+ writel(0x1, &regs->mac_mcmd);
+
+ /* Wait read complete */
+ mdelay(1);
+
+ /* push down the phy io line */
+ writel(0x0, &regs->mac_mcmd);
+
+ /* and write data */
+ *value = readl(&regs->mac_mrdd);
+
+ return 0;
+}
+
+/*
+ * Write a word to phyxcer
+ */
+static int wemac_phy_write(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+ /* issue the phy address and reg */
+ writel(addr << 8 | reg, &regs->mac_madr);
+
+ /* pull up the phy io line */
+ writel(0x1, &regs->mac_mcmd);
+
+ /* Wait write complete */
+ mdelay(1);
+
+ /* push down the phy io line */
+ writel(0x0, &regs->mac_mcmd);
+
+ /* and write data */
+ writel(value, &regs->mac_mwtd);
+
+ return 0;
+}
+
+static void emac_setup(struct eth_device *dev)
+{
+ struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+ u32 reg_val;
+ u16 phy_val;
+ u32 duplex_flag;
+
+ /* Set up TX */
+ writel(EMAC_TX_SETUP, &regs->tx_mode);
+
+ /* Set up RX */
+ writel(EMAC_RX_SETUP, &regs->rx_ctl);
+
+ /* Set MAC */
+ /* Set MAC CTL0 */
+ writel(EMAC_MAC_CTL0_SETUP, &regs->mac_ctl0);
+
+ /* Set MAC CTL1 */
+ wemac_phy_read(dev->name, 1, 0, &phy_val);
+ debug("PHY SETUP, reg 0 value: %x\n", phy_val);
+ duplex_flag = !!(phy_val & (1 << 8));
+
+ reg_val = 0;
+ if (duplex_flag)
+ reg_val = (0x1 << 0);
+ writel(EMAC_MAC_CTL1_SETUP | reg_val, &regs->mac_ctl1);
+
+ /* Set up IPGT */
+ writel(EMAC_MAC_IPGT, &regs->mac_ipgt);
+
+ /* Set up IPGR */
+ writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), &regs->mac_ipgr);
+
+ /* Set up Collison window */
+ writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), &regs->mac_clrt);
+
+ /* Set up Max Frame Length */
+ writel(EMAC_MAC_MFL, &regs->mac_maxf);
+}
+
+static void wemac_reset(struct eth_device *dev)
+{
+ struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+ debug("resetting device\n");
+
+ /* RESET device */
+ writel(0, &regs->ctl);
+ udelay(200);
+
+ writel(1, &regs->ctl);
+ udelay(200);
+}
+
+static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd)
+{
+ struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+ struct wemac_eth_dev *priv = dev->priv;
+ u16 phy_reg;
+
+ /* Init EMAC */
+
+ /* Flush RX FIFO */
+ setbits_le32(&regs->rx_ctl, 0x8);
+ udelay(1);
+
+ /* Init MAC */
+
+ /* Soft reset MAC */
+ clrbits_le32(&regs->mac_ctl0, 1 << 15);
+
+ /* Set MII clock */
+ clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2);
+
+ /* Clear RX counter */
+ writel(0x0, &regs->rx_fbc);
+ udelay(1);
+
+ /* Set up EMAC */
+ emac_setup(dev);
+
+ writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
+ dev->enetaddr[2], &regs->mac_a1);
+ writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
+ dev->enetaddr[5], &regs->mac_a0);
+
+ mdelay(1);
+
+ wemac_reset(dev);
+
+ /* PHY POWER UP */
+ wemac_phy_read(dev->name, 1, 0, &phy_reg);
+ wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11)));
+ mdelay(1);
+
+ wemac_phy_read(dev->name, 1, 0, &phy_reg);
+
+ priv->speed = miiphy_speed(dev->name, 0);
+ priv->duplex = miiphy_duplex(dev->name, 0);
+
+ /* Print link status only once */
+ if (!priv->link_printed) {
+ printf("ENET Speed is %d Mbps - %s duplex connection\n",
+ priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
+ priv->link_printed = 1;
+ }
+
+ /* Set EMAC SPEED depend on PHY */
+ clrsetbits_le32(&regs->mac_supp, 1 << 8,
+ ((phy_reg & (1 << 13)) >> 13) << 8);
+
+ /* Set duplex depend on phy */
+ clrsetbits_le32(&regs->mac_ctl1, 1 << 0,
+ ((phy_reg & (1 << 8)) >> 8) << 0);
+
+ /* Enable RX/TX */
+ setbits_le32(&regs->ctl, 0x7);
+
+ return 0;
+}
+
+static void sunxi_wemac_eth_halt(struct eth_device *dev)
+{
+ /* Nothing to do here */
+}
+
+static int sunxi_wemac_eth_recv(struct eth_device *dev)
+{
+ struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+ struct wemac_rxhdr rxhdr;
+ u32 rxcount;
+ u32 reg_val;
+ int rx_len;
+ int rx_status;
+ int good_packet;
+
+ /* Check packet ready or not */
+
+ /*
+ * Race warning: The first packet might arrive with
+ * the interrupts disabled, but the second will fix
+ */
+ rxcount = readl(&regs->rx_fbc);
+ if (!rxcount) {
+ /* Had one stuck? */
+ rxcount = readl(&regs->rx_fbc);
+ if (!rxcount)
+ return 0;
+ }
+
+ reg_val = readl(&regs->rx_io_data);
+ if (reg_val != 0x0143414d) {
+ /* Disable RX */
+ clrbits_le32(&regs->ctl, 1 << 2);
+
+ /* Flush RX FIFO */
+ setbits_le32(&regs->rx_ctl, 1 << 3);
+ while (readl(&regs->rx_ctl) & (1 << 3))
+ ;
+
+ /* Enable RX */
+ setbits_le32(&regs->ctl, 1 << 2);
+
+ return 0;
+ }
+
+ /*
+ * A packet ready now
+ * Get status/length
+ */
+ good_packet = 1;
+
+ wemac_inblk_32bit(&regs->rx_io_data, &rxhdr, sizeof(rxhdr));
+
+ rx_len = rxhdr.rx_len;
+ rx_status = rxhdr.rx_status;
+
+ /* Packet Status check */
+ if (rx_len < 0x40) {
+ good_packet = 0;
+ debug("RX: Bad Packet (runt)\n");
+ }
+
+ /* rx_status is identical to RSR register. */
+ if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) {
+ good_packet = 0;
+ if (rx_status & EMAC_CRCERR)
+ printf("crc error\n");
+ if (rx_status & EMAC_LENERR)
+ printf("length error\n");
+ }
+
+ /* Move data from WEMAC */
+ if (good_packet) {
+ if (rx_len > DMA_CPU_TRRESHOLD) {
+ printf("Received packet is too big (len=%d)\n", rx_len);
+ } else {
+ wemac_inblk_32bit((void *)&regs->rx_io_data,
+ NetRxPackets[0], rx_len);
+
+ /* Pass to upper layer */
+ NetReceive(NetRxPackets[0], rx_len);
+ return rx_len;
+ }
+ }
+
+ return 0;
+}
+
+static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len)
+{
+ struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+ /* Select channel 0 */
+ writel(0, &regs->tx_ins);
+
+ /* Write packet */
+ wemac_outblk_32bit((void *)&regs->tx_io_data, packet, len);
+
+ /* Set TX len */
+ writel(len, &regs->tx_pl0);
+
+ /* Start translate from fifo to phy */
+ setbits_le32(&regs->tx_ctl0, 1);
+
+ return 0;
+}
+
+int sunxi_wemac_initialize(void)
+{
+ struct sunxi_ccm_reg *const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_sramc_regs *sram =
+ (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
+ struct eth_device *dev;
+ struct wemac_eth_dev *priv;
+ int pin;
+
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL)
+ return -ENOMEM;
+
+ priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev));
+ if (!priv) {
+ free(dev);
+ return -ENOMEM;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ memset(priv, 0, sizeof(struct wemac_eth_dev));
+
+ /* Map SRAM to EMAC */
+ setbits_le32(&sram->ctrl1, 0x5 << 2);
+
+ /* Configure pin mux settings for MII Ethernet */
+ for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++)
+ sunxi_gpio_set_cfgpin(pin, 2);
+
+ /* Set up clock gating */
+ setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC);
+
+ dev->iobase = SUNXI_EMAC_BASE;
+ dev->priv = priv;
+ dev->init = sunxi_wemac_eth_init;
+ dev->halt = sunxi_wemac_eth_halt;
+ dev->send = sunxi_wemac_eth_send;
+ dev->recv = sunxi_wemac_eth_recv;
+ strcpy(dev->name, "wemac");
+
+ eth_register(dev);
+
+ miiphy_register(dev->name, wemac_phy_read, wemac_phy_write);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/tsec.c b/qemu/roms/u-boot/drivers/net/tsec.c
new file mode 100644
index 000000000..e9138f033
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/tsec.c
@@ -0,0 +1,688 @@
+/*
+ * Freescale Three Speed Ethernet Controller driver
+ *
+ * This software may be used and distributed according to the
+ * terms of the GNU Public License, Version 2, incorporated
+ * herein by reference.
+ *
+ * Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * author Andy Fleming
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <command.h>
+#include <tsec.h>
+#include <fsl_mdio.h>
+#include <asm/errno.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TX_BUF_CNT 2
+
+static uint rx_idx; /* index of the current RX buffer */
+static uint tx_idx; /* index of the current TX buffer */
+
+#ifdef __GNUC__
+static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8);
+static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8);
+
+#else
+#error "rtx must be 64-bit aligned"
+#endif
+
+static int tsec_send(struct eth_device *dev, void *packet, int length);
+
+/* Default initializations for TSEC controllers. */
+
+static struct tsec_info_struct tsec_info[] = {
+#ifdef CONFIG_TSEC1
+ STD_TSEC_INFO(1), /* TSEC1 */
+#endif
+#ifdef CONFIG_TSEC2
+ STD_TSEC_INFO(2), /* TSEC2 */
+#endif
+#ifdef CONFIG_MPC85XX_FEC
+ {
+ .regs = TSEC_GET_REGS(2, 0x2000),
+ .devname = CONFIG_MPC85XX_FEC_NAME,
+ .phyaddr = FEC_PHY_ADDR,
+ .flags = FEC_FLAGS,
+ .mii_devname = DEFAULT_MII_NAME
+ }, /* FEC */
+#endif
+#ifdef CONFIG_TSEC3
+ STD_TSEC_INFO(3), /* TSEC3 */
+#endif
+#ifdef CONFIG_TSEC4
+ STD_TSEC_INFO(4), /* TSEC4 */
+#endif
+};
+
+#define TBIANA_SETTINGS ( \
+ TBIANA_ASYMMETRIC_PAUSE \
+ | TBIANA_SYMMETRIC_PAUSE \
+ | TBIANA_FULL_DUPLEX \
+ )
+
+/* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */
+#ifndef CONFIG_TSEC_TBICR_SETTINGS
+#define CONFIG_TSEC_TBICR_SETTINGS ( \
+ TBICR_PHY_RESET \
+ | TBICR_ANEG_ENABLE \
+ | TBICR_FULL_DUPLEX \
+ | TBICR_SPEED1_SET \
+ )
+#endif /* CONFIG_TSEC_TBICR_SETTINGS */
+
+/* Configure the TBI for SGMII operation */
+static void tsec_configure_serdes(struct tsec_private *priv)
+{
+ /* Access TBI PHY registers at given TSEC register offset as opposed
+ * to the register offset used for external PHY accesses */
+ tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
+ 0, TBI_ANA, TBIANA_SETTINGS);
+ tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
+ 0, TBI_TBICON, TBICON_CLK_SELECT);
+ tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
+ 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS);
+}
+
+#ifdef CONFIG_MCAST_TFTP
+
+/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */
+
+/* Set the appropriate hash bit for the given addr */
+
+/* The algorithm works like so:
+ * 1) Take the Destination Address (ie the multicast address), and
+ * do a CRC on it (little endian), and reverse the bits of the
+ * result.
+ * 2) Use the 8 most significant bits as a hash into a 256-entry
+ * table. The table is controlled through 8 32-bit registers:
+ * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is entry
+ * 255. This means that the 3 most significant bits in the
+ * hash index which gaddr register to use, and the 5 other bits
+ * indicate which bit (assuming an IBM numbering scheme, which
+ * for PowerPC (tm) is usually the case) in the register holds
+ * the entry. */
+static int
+tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ u32 result, value;
+ u8 whichbit, whichreg;
+
+ result = ether_crc(MAC_ADDR_LEN, mcast_mac);
+ whichbit = (result >> 24) & 0x1f; /* the 5 LSB = which bit to set */
+ whichreg = result >> 29; /* the 3 MSB = which reg to set it in */
+
+ value = 1 << (31-whichbit);
+
+ if (set)
+ setbits_be32(&regs->hash.gaddr0 + whichreg, value);
+ else
+ clrbits_be32(&regs->hash.gaddr0 + whichreg, value);
+
+ return 0;
+}
+#endif /* Multicast TFTP ? */
+
+/* Initialized required registers to appropriate values, zeroing
+ * those we don't care about (unless zero is bad, in which case,
+ * choose a more appropriate value)
+ */
+static void init_registers(struct tsec __iomem *regs)
+{
+ /* Clear IEVENT */
+ out_be32(&regs->ievent, IEVENT_INIT_CLEAR);
+
+ out_be32(&regs->imask, IMASK_INIT_CLEAR);
+
+ out_be32(&regs->hash.iaddr0, 0);
+ out_be32(&regs->hash.iaddr1, 0);
+ out_be32(&regs->hash.iaddr2, 0);
+ out_be32(&regs->hash.iaddr3, 0);
+ out_be32(&regs->hash.iaddr4, 0);
+ out_be32(&regs->hash.iaddr5, 0);
+ out_be32(&regs->hash.iaddr6, 0);
+ out_be32(&regs->hash.iaddr7, 0);
+
+ out_be32(&regs->hash.gaddr0, 0);
+ out_be32(&regs->hash.gaddr1, 0);
+ out_be32(&regs->hash.gaddr2, 0);
+ out_be32(&regs->hash.gaddr3, 0);
+ out_be32(&regs->hash.gaddr4, 0);
+ out_be32(&regs->hash.gaddr5, 0);
+ out_be32(&regs->hash.gaddr6, 0);
+ out_be32(&regs->hash.gaddr7, 0);
+
+ out_be32(&regs->rctrl, 0x00000000);
+
+ /* Init RMON mib registers */
+ memset((void *)&regs->rmon, 0, sizeof(regs->rmon));
+
+ out_be32(&regs->rmon.cam1, 0xffffffff);
+ out_be32(&regs->rmon.cam2, 0xffffffff);
+
+ out_be32(&regs->mrblr, MRBLR_INIT_SETTINGS);
+
+ out_be32(&regs->minflr, MINFLR_INIT_SETTINGS);
+
+ out_be32(&regs->attr, ATTR_INIT_SETTINGS);
+ out_be32(&regs->attreli, ATTRELI_INIT_SETTINGS);
+
+}
+
+/* Configure maccfg2 based on negotiated speed and duplex
+ * reported by PHY handling code
+ */
+static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
+{
+ struct tsec __iomem *regs = priv->regs;
+ u32 ecntrl, maccfg2;
+
+ if (!phydev->link) {
+ printf("%s: No link.\n", phydev->dev->name);
+ return;
+ }
+
+ /* clear all bits relative with interface mode */
+ ecntrl = in_be32(&regs->ecntrl);
+ ecntrl &= ~ECNTRL_R100;
+
+ maccfg2 = in_be32(&regs->maccfg2);
+ maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX);
+
+ if (phydev->duplex)
+ maccfg2 |= MACCFG2_FULL_DUPLEX;
+
+ switch (phydev->speed) {
+ case 1000:
+ maccfg2 |= MACCFG2_GMII;
+ break;
+ case 100:
+ case 10:
+ maccfg2 |= MACCFG2_MII;
+
+ /* Set R100 bit in all modes although
+ * it is only used in RGMII mode
+ */
+ if (phydev->speed == 100)
+ ecntrl |= ECNTRL_R100;
+ break;
+ default:
+ printf("%s: Speed was bad\n", phydev->dev->name);
+ break;
+ }
+
+ out_be32(&regs->ecntrl, ecntrl);
+ out_be32(&regs->maccfg2, maccfg2);
+
+ printf("Speed: %d, %s duplex%s\n", phydev->speed,
+ (phydev->duplex) ? "full" : "half",
+ (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
+}
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
+/*
+ * When MACCFG1[Rx_EN] is enabled during system boot as part
+ * of the eTSEC port initialization sequence,
+ * the eTSEC Rx logic may not be properly initialized.
+ */
+void redundant_init(struct eth_device *dev)
+{
+ struct tsec_private *priv = dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ uint t, count = 0;
+ int fail = 1;
+ static const u8 pkt[] = {
+ 0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25,
+ 0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00,
+ 0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01,
+ 0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1,
+ 0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00,
+ 0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+ 0x71, 0x72};
+
+ /* Enable promiscuous mode */
+ setbits_be32(&regs->rctrl, 0x8);
+ /* Enable loopback mode */
+ setbits_be32(&regs->maccfg1, MACCFG1_LOOPBACK);
+ /* Enable transmit and receive */
+ setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
+
+ /* Tell the DMA it is clear to go */
+ setbits_be32(&regs->dmactrl, DMACTRL_INIT_SETTINGS);
+ out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+ out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+ clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+
+ do {
+ uint16_t status;
+ tsec_send(dev, (void *)pkt, sizeof(pkt));
+
+ /* Wait for buffer to be received */
+ for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) {
+ if (t >= 10 * TOUT_LOOP) {
+ printf("%s: tsec: rx error\n", dev->name);
+ break;
+ }
+ }
+
+ if (!memcmp(pkt, (void *)NetRxPackets[rx_idx], sizeof(pkt)))
+ fail = 0;
+
+ out_be16(&rxbd[rx_idx].length, 0);
+ status = RXBD_EMPTY;
+ if ((rx_idx + 1) == PKTBUFSRX)
+ status |= RXBD_WRAP;
+ out_be16(&rxbd[rx_idx].status, status);
+ rx_idx = (rx_idx + 1) % PKTBUFSRX;
+
+ if (in_be32(&regs->ievent) & IEVENT_BSY) {
+ out_be32(&regs->ievent, IEVENT_BSY);
+ out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+ }
+ if (fail) {
+ printf("loopback recv packet error!\n");
+ clrbits_be32(&regs->maccfg1, MACCFG1_RX_EN);
+ udelay(1000);
+ setbits_be32(&regs->maccfg1, MACCFG1_RX_EN);
+ }
+ } while ((count++ < 4) && (fail == 1));
+
+ if (fail)
+ panic("eTSEC init fail!\n");
+ /* Disable promiscuous mode */
+ clrbits_be32(&regs->rctrl, 0x8);
+ /* Disable loopback mode */
+ clrbits_be32(&regs->maccfg1, MACCFG1_LOOPBACK);
+}
+#endif
+
+/* Set up the buffers and their descriptors, and bring up the
+ * interface
+ */
+static void startup_tsec(struct eth_device *dev)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ uint16_t status;
+ int i;
+
+ /* reset the indices to zero */
+ rx_idx = 0;
+ tx_idx = 0;
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
+ uint svr;
+#endif
+
+ /* Point to the buffer descriptors */
+ out_be32(&regs->tbase, (u32)&txbd[0]);
+ out_be32(&regs->rbase, (u32)&rxbd[0]);
+
+ /* Initialize the Rx Buffer descriptors */
+ for (i = 0; i < PKTBUFSRX; i++) {
+ out_be16(&rxbd[i].status, RXBD_EMPTY);
+ out_be16(&rxbd[i].length, 0);
+ out_be32(&rxbd[i].bufptr, (u32)NetRxPackets[i]);
+ }
+ status = in_be16(&rxbd[PKTBUFSRX - 1].status);
+ out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
+
+ /* Initialize the TX Buffer Descriptors */
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ out_be16(&txbd[i].status, 0);
+ out_be16(&txbd[i].length, 0);
+ out_be32(&txbd[i].bufptr, 0);
+ }
+ status = in_be16(&txbd[TX_BUF_CNT - 1].status);
+ out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
+ svr = get_svr();
+ if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
+ redundant_init(dev);
+#endif
+ /* Enable Transmit and Receive */
+ setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
+
+ /* Tell the DMA it is clear to go */
+ setbits_be32(&regs->dmactrl, DMACTRL_INIT_SETTINGS);
+ out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+ out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+ clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+}
+
+/* This returns the status bits of the device. The return value
+ * is never checked, and this is what the 8260 driver did, so we
+ * do the same. Presumably, this would be zero if there were no
+ * errors
+ */
+static int tsec_send(struct eth_device *dev, void *packet, int length)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ uint16_t status;
+ int result = 0;
+ int i;
+
+ /* Find an empty buffer descriptor */
+ for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
+ if (i >= TOUT_LOOP) {
+ debug("%s: tsec: tx buffers full\n", dev->name);
+ return result;
+ }
+ }
+
+ out_be32(&txbd[tx_idx].bufptr, (u32)packet);
+ out_be16(&txbd[tx_idx].length, length);
+ status = in_be16(&txbd[tx_idx].status);
+ out_be16(&txbd[tx_idx].status, status |
+ (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
+
+ /* Tell the DMA to go */
+ out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+
+ /* Wait for buffer to be transmitted */
+ for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
+ if (i >= TOUT_LOOP) {
+ debug("%s: tsec: tx error\n", dev->name);
+ return result;
+ }
+ }
+
+ tx_idx = (tx_idx + 1) % TX_BUF_CNT;
+ result = in_be16(&txbd[tx_idx].status) & TXBD_STATS;
+
+ return result;
+}
+
+static int tsec_recv(struct eth_device *dev)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+
+ while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) {
+ int length = in_be16(&rxbd[rx_idx].length);
+ uint16_t status = in_be16(&rxbd[rx_idx].status);
+
+ /* Send the packet up if there were no errors */
+ if (!(status & RXBD_STATS))
+ NetReceive(NetRxPackets[rx_idx], length - 4);
+ else
+ printf("Got error %x\n", (status & RXBD_STATS));
+
+ out_be16(&rxbd[rx_idx].length, 0);
+
+ status = RXBD_EMPTY;
+ /* Set the wrap bit if this is the last element in the list */
+ if ((rx_idx + 1) == PKTBUFSRX)
+ status |= RXBD_WRAP;
+ out_be16(&rxbd[rx_idx].status, status);
+
+ rx_idx = (rx_idx + 1) % PKTBUFSRX;
+ }
+
+ if (in_be32(&regs->ievent) & IEVENT_BSY) {
+ out_be32(&regs->ievent, IEVENT_BSY);
+ out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+ }
+
+ return -1;
+
+}
+
+/* Stop the interface */
+static void tsec_halt(struct eth_device *dev)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+
+ clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+ setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+
+ while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
+ != (IEVENT_GRSC | IEVENT_GTSC))
+ ;
+
+ clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
+
+ /* Shut down the PHY, as needed */
+ phy_shutdown(priv->phydev);
+}
+
+/* Initializes data structures and registers for the controller,
+ * and brings the interface up. Returns the link status, meaning
+ * that it returns success if the link is up, failure otherwise.
+ * This allows u-boot to find the first active controller.
+ */
+static int tsec_init(struct eth_device *dev, bd_t * bd)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ u32 tempval;
+ int ret;
+
+ /* Make sure the controller is stopped */
+ tsec_halt(dev);
+
+ /* Init MACCFG2. Defaults to GMII */
+ out_be32(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
+
+ /* Init ECNTRL */
+ out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
+
+ /* Copy the station address into the address registers.
+ * For a station address of 0x12345678ABCD in transmission
+ * order (BE), MACnADDR1 is set to 0xCDAB7856 and
+ * MACnADDR2 is set to 0x34120000.
+ */
+ tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
+ (dev->enetaddr[3] << 8) | dev->enetaddr[2];
+
+ out_be32(&regs->macstnaddr1, tempval);
+
+ tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
+
+ out_be32(&regs->macstnaddr2, tempval);
+
+ /* Clear out (for the most part) the other registers */
+ init_registers(regs);
+
+ /* Ready the device for tx/rx */
+ startup_tsec(dev);
+
+ /* Start up the PHY */
+ ret = phy_startup(priv->phydev);
+ if (ret) {
+ printf("Could not initialize PHY %s\n",
+ priv->phydev->dev->name);
+ return ret;
+ }
+
+ adjust_link(priv, priv->phydev);
+
+ /* If there's no link, fail */
+ return priv->phydev->link ? 0 : -1;
+}
+
+static phy_interface_t tsec_get_interface(struct tsec_private *priv)
+{
+ struct tsec __iomem *regs = priv->regs;
+ u32 ecntrl;
+
+ ecntrl = in_be32(&regs->ecntrl);
+
+ if (ecntrl & ECNTRL_SGMII_MODE)
+ return PHY_INTERFACE_MODE_SGMII;
+
+ if (ecntrl & ECNTRL_TBI_MODE) {
+ if (ecntrl & ECNTRL_REDUCED_MODE)
+ return PHY_INTERFACE_MODE_RTBI;
+ else
+ return PHY_INTERFACE_MODE_TBI;
+ }
+
+ if (ecntrl & ECNTRL_REDUCED_MODE) {
+ if (ecntrl & ECNTRL_REDUCED_MII_MODE)
+ return PHY_INTERFACE_MODE_RMII;
+ else {
+ phy_interface_t interface = priv->interface;
+
+ /*
+ * This isn't autodetected, so it must
+ * be set by the platform code.
+ */
+ if ((interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
+ (interface == PHY_INTERFACE_MODE_RGMII_RXID))
+ return interface;
+
+ return PHY_INTERFACE_MODE_RGMII;
+ }
+ }
+
+ if (priv->flags & TSEC_GIGABIT)
+ return PHY_INTERFACE_MODE_GMII;
+
+ return PHY_INTERFACE_MODE_MII;
+}
+
+
+/* Discover which PHY is attached to the device, and configure it
+ * properly. If the PHY is not recognized, then return 0
+ * (failure). Otherwise, return 1
+ */
+static int init_phy(struct eth_device *dev)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct phy_device *phydev;
+ struct tsec __iomem *regs = priv->regs;
+ u32 supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full);
+
+ if (priv->flags & TSEC_GIGABIT)
+ supported |= SUPPORTED_1000baseT_Full;
+
+ /* Assign a Physical address to the TBI */
+ out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
+
+ priv->interface = tsec_get_interface(priv);
+
+ if (priv->interface == PHY_INTERFACE_MODE_SGMII)
+ tsec_configure_serdes(priv);
+
+ phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+
+ phydev->supported &= supported;
+ phydev->advertising = phydev->supported;
+
+ priv->phydev = phydev;
+
+ phy_config(phydev);
+
+ return 1;
+}
+
+/* Initialize device structure. Returns success if PHY
+ * initialization succeeded (i.e. if it recognizes the PHY)
+ */
+static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
+{
+ struct eth_device *dev;
+ int i;
+ struct tsec_private *priv;
+
+ dev = (struct eth_device *)malloc(sizeof *dev);
+
+ if (NULL == dev)
+ return 0;
+
+ memset(dev, 0, sizeof *dev);
+
+ priv = (struct tsec_private *)malloc(sizeof(*priv));
+
+ if (NULL == priv)
+ return 0;
+
+ priv->regs = tsec_info->regs;
+ priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
+
+ priv->phyaddr = tsec_info->phyaddr;
+ priv->flags = tsec_info->flags;
+
+ sprintf(dev->name, tsec_info->devname);
+ priv->interface = tsec_info->interface;
+ priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
+ dev->iobase = 0;
+ dev->priv = priv;
+ dev->init = tsec_init;
+ dev->halt = tsec_halt;
+ dev->send = tsec_send;
+ dev->recv = tsec_recv;
+#ifdef CONFIG_MCAST_TFTP
+ dev->mcast = tsec_mcast_addr;
+#endif
+
+ /* Tell u-boot to get the addr from the env */
+ for (i = 0; i < 6; i++)
+ dev->enetaddr[i] = 0;
+
+ eth_register(dev);
+
+ /* Reset the MAC */
+ setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+ udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
+ clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+
+ /* Try to initialize PHY here, and return */
+ return init_phy(dev);
+}
+
+/*
+ * Initialize all the TSEC devices
+ *
+ * Returns the number of TSEC devices that were initialized
+ */
+int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
+{
+ int i;
+ int ret, count = 0;
+
+ for (i = 0; i < num; i++) {
+ ret = tsec_initialize(bis, &tsecs[i]);
+ if (ret > 0)
+ count += ret;
+ }
+
+ return count;
+}
+
+int tsec_standard_init(bd_t *bis)
+{
+ struct fsl_pq_mdio_info info;
+
+ info.regs = TSEC_GET_MDIO_REGS_BASE(1);
+ info.name = DEFAULT_MII_NAME;
+
+ fsl_pq_mdio_init(bis, &info);
+
+ return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
+}
diff --git a/qemu/roms/u-boot/drivers/net/tsi108_eth.c b/qemu/roms/u-boot/drivers/net/tsi108_eth.c
new file mode 100644
index 000000000..72b8159d8
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/tsi108_eth.c
@@ -0,0 +1,1016 @@
+/***********************************************************************
+ *
+ * Copyright (c) 2005 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Description:
+ * Ethernet interface for Tundra TSI108 bridge chip
+ *
+ ***********************************************************************/
+
+#include <config.h>
+
+#if !defined(CONFIG_TSI108_ETH_NUM_PORTS) || (CONFIG_TSI108_ETH_NUM_PORTS > 2)
+#error "CONFIG_TSI108_ETH_NUM_PORTS must be defined as 1 or 2"
+#endif
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/cache.h>
+
+#ifdef DEBUG
+#define TSI108_ETH_DEBUG 7
+#else
+#define TSI108_ETH_DEBUG 0
+#endif
+
+#if TSI108_ETH_DEBUG > 0
+#define debug_lev(lev, fmt, args...) \
+if (lev <= TSI108_ETH_DEBUG) \
+printf ("%s %d: " fmt, __FUNCTION__, __LINE__, ##args)
+#else
+#define debug_lev(lev, fmt, args...) do{}while(0)
+#endif
+
+#define RX_PRINT_ERRORS
+#define TX_PRINT_ERRORS
+
+#define ETH_BASE (CONFIG_SYS_TSI108_CSR_BASE + 0x6000)
+
+#define ETH_PORT_OFFSET 0x400
+
+#define __REG32(base, offset) (*((volatile u32 *)((char *)(base) + (offset))))
+
+#define reg_MAC_CONFIG_1(base) __REG32(base, 0x00000000)
+#define MAC_CONFIG_1_TX_ENABLE (0x00000001)
+#define MAC_CONFIG_1_SYNC_TX_ENABLE (0x00000002)
+#define MAC_CONFIG_1_RX_ENABLE (0x00000004)
+#define MAC_CONFIG_1_SYNC_RX_ENABLE (0x00000008)
+#define MAC_CONFIG_1_TX_FLOW_CONTROL (0x00000010)
+#define MAC_CONFIG_1_RX_FLOW_CONTROL (0x00000020)
+#define MAC_CONFIG_1_LOOP_BACK (0x00000100)
+#define MAC_CONFIG_1_RESET_TX_FUNCTION (0x00010000)
+#define MAC_CONFIG_1_RESET_RX_FUNCTION (0x00020000)
+#define MAC_CONFIG_1_RESET_TX_MAC (0x00040000)
+#define MAC_CONFIG_1_RESET_RX_MAC (0x00080000)
+#define MAC_CONFIG_1_SIM_RESET (0x40000000)
+#define MAC_CONFIG_1_SOFT_RESET (0x80000000)
+
+#define reg_MAC_CONFIG_2(base) __REG32(base, 0x00000004)
+#define MAC_CONFIG_2_FULL_DUPLEX (0x00000001)
+#define MAC_CONFIG_2_CRC_ENABLE (0x00000002)
+#define MAC_CONFIG_2_PAD_CRC (0x00000004)
+#define MAC_CONFIG_2_LENGTH_CHECK (0x00000010)
+#define MAC_CONFIG_2_HUGE_FRAME (0x00000020)
+#define MAC_CONFIG_2_INTERFACE_MODE(val) (((val) & 0x3) << 8)
+#define MAC_CONFIG_2_PREAMBLE_LENGTH(val) (((val) & 0xf) << 12)
+#define INTERFACE_MODE_NIBBLE 1 /* 10/100 Mb/s MII) */
+#define INTERFACE_MODE_BYTE 2 /* 1000 Mb/s GMII/TBI */
+
+#define reg_MAXIMUM_FRAME_LENGTH(base) __REG32(base, 0x00000010)
+
+#define reg_MII_MGMT_CONFIG(base) __REG32(base, 0x00000020)
+#define MII_MGMT_CONFIG_MGMT_CLOCK_SELECT(val) ((val) & 0x7)
+#define MII_MGMT_CONFIG_NO_PREAMBLE (0x00000010)
+#define MII_MGMT_CONFIG_SCAN_INCREMENT (0x00000020)
+#define MII_MGMT_CONFIG_RESET_MGMT (0x80000000)
+
+#define reg_MII_MGMT_COMMAND(base) __REG32(base, 0x00000024)
+#define MII_MGMT_COMMAND_READ_CYCLE (0x00000001)
+#define MII_MGMT_COMMAND_SCAN_CYCLE (0x00000002)
+
+#define reg_MII_MGMT_ADDRESS(base) __REG32(base, 0x00000028)
+#define reg_MII_MGMT_CONTROL(base) __REG32(base, 0x0000002c)
+#define reg_MII_MGMT_STATUS(base) __REG32(base, 0x00000030)
+
+#define reg_MII_MGMT_INDICATORS(base) __REG32(base, 0x00000034)
+#define MII_MGMT_INDICATORS_BUSY (0x00000001)
+#define MII_MGMT_INDICATORS_SCAN (0x00000002)
+#define MII_MGMT_INDICATORS_NOT_VALID (0x00000004)
+
+#define reg_INTERFACE_STATUS(base) __REG32(base, 0x0000003c)
+#define INTERFACE_STATUS_LINK_FAIL (0x00000008)
+#define INTERFACE_STATUS_EXCESS_DEFER (0x00000200)
+
+#define reg_STATION_ADDRESS_1(base) __REG32(base, 0x00000040)
+#define reg_STATION_ADDRESS_2(base) __REG32(base, 0x00000044)
+
+#define reg_PORT_CONTROL(base) __REG32(base, 0x00000200)
+#define PORT_CONTROL_PRI (0x00000001)
+#define PORT_CONTROL_BPT (0x00010000)
+#define PORT_CONTROL_SPD (0x00040000)
+#define PORT_CONTROL_RBC (0x00080000)
+#define PORT_CONTROL_PRB (0x00200000)
+#define PORT_CONTROL_DIS (0x00400000)
+#define PORT_CONTROL_TBI (0x00800000)
+#define PORT_CONTROL_STE (0x10000000)
+#define PORT_CONTROL_ZOR (0x20000000)
+#define PORT_CONTROL_CLR (0x40000000)
+#define PORT_CONTROL_SRT (0x80000000)
+
+#define reg_TX_CONFIG(base) __REG32(base, 0x00000220)
+#define TX_CONFIG_START_Q (0x00000003)
+#define TX_CONFIG_EHP (0x00400000)
+#define TX_CONFIG_CHP (0x00800000)
+#define TX_CONFIG_RST (0x80000000)
+
+#define reg_TX_CONTROL(base) __REG32(base, 0x00000224)
+#define TX_CONTROL_GO (0x00008000)
+#define TX_CONTROL_MP (0x01000000)
+#define TX_CONTROL_EAI (0x20000000)
+#define TX_CONTROL_ABT (0x40000000)
+#define TX_CONTROL_EII (0x80000000)
+
+#define reg_TX_STATUS(base) __REG32(base, 0x00000228)
+#define TX_STATUS_QUEUE_USABLE (0x0000000f)
+#define TX_STATUS_CURR_Q (0x00000300)
+#define TX_STATUS_ACT (0x00008000)
+#define TX_STATUS_QUEUE_IDLE (0x000f0000)
+#define TX_STATUS_EOQ_PENDING (0x0f000000)
+
+#define reg_TX_EXTENDED_STATUS(base) __REG32(base, 0x0000022c)
+#define TX_EXTENDED_STATUS_END_OF_QUEUE_CONDITION (0x0000000f)
+#define TX_EXTENDED_STATUS_END_OF_FRAME_CONDITION (0x00000f00)
+#define TX_EXTENDED_STATUS_DESCRIPTOR_INTERRUPT_CONDITION (0x000f0000)
+#define TX_EXTENDED_STATUS_ERROR_FLAG (0x0f000000)
+
+#define reg_TX_THRESHOLDS(base) __REG32(base, 0x00000230)
+
+#define reg_TX_DIAGNOSTIC_ADDR(base) __REG32(base, 0x00000270)
+#define TX_DIAGNOSTIC_ADDR_INDEX (0x0000007f)
+#define TX_DIAGNOSTIC_ADDR_DFR (0x40000000)
+#define TX_DIAGNOSTIC_ADDR_AI (0x80000000)
+
+#define reg_TX_DIAGNOSTIC_DATA(base) __REG32(base, 0x00000274)
+
+#define reg_TX_ERROR_STATUS(base) __REG32(base, 0x00000278)
+#define TX_ERROR_STATUS (0x00000278)
+#define TX_ERROR_STATUS_QUEUE_0_ERROR_RESPONSE (0x0000000f)
+#define TX_ERROR_STATUS_TEA_ON_QUEUE_0 (0x00000010)
+#define TX_ERROR_STATUS_RER_ON_QUEUE_0 (0x00000020)
+#define TX_ERROR_STATUS_TER_ON_QUEUE_0 (0x00000040)
+#define TX_ERROR_STATUS_DER_ON_QUEUE_0 (0x00000080)
+#define TX_ERROR_STATUS_QUEUE_1_ERROR_RESPONSE (0x00000f00)
+#define TX_ERROR_STATUS_TEA_ON_QUEUE_1 (0x00001000)
+#define TX_ERROR_STATUS_RER_ON_QUEUE_1 (0x00002000)
+#define TX_ERROR_STATUS_TER_ON_QUEUE_1 (0x00004000)
+#define TX_ERROR_STATUS_DER_ON_QUEUE_1 (0x00008000)
+#define TX_ERROR_STATUS_QUEUE_2_ERROR_RESPONSE (0x000f0000)
+#define TX_ERROR_STATUS_TEA_ON_QUEUE_2 (0x00100000)
+#define TX_ERROR_STATUS_RER_ON_QUEUE_2 (0x00200000)
+#define TX_ERROR_STATUS_TER_ON_QUEUE_2 (0x00400000)
+#define TX_ERROR_STATUS_DER_ON_QUEUE_2 (0x00800000)
+#define TX_ERROR_STATUS_QUEUE_3_ERROR_RESPONSE (0x0f000000)
+#define TX_ERROR_STATUS_TEA_ON_QUEUE_3 (0x10000000)
+#define TX_ERROR_STATUS_RER_ON_QUEUE_3 (0x20000000)
+#define TX_ERROR_STATUS_TER_ON_QUEUE_3 (0x40000000)
+#define TX_ERROR_STATUS_DER_ON_QUEUE_3 (0x80000000)
+
+#define reg_TX_QUEUE_0_CONFIG(base) __REG32(base, 0x00000280)
+#define TX_QUEUE_0_CONFIG_OCN_PORT (0x0000003f)
+#define TX_QUEUE_0_CONFIG_BSWP (0x00000400)
+#define TX_QUEUE_0_CONFIG_WSWP (0x00000800)
+#define TX_QUEUE_0_CONFIG_AM (0x00004000)
+#define TX_QUEUE_0_CONFIG_GVI (0x00008000)
+#define TX_QUEUE_0_CONFIG_EEI (0x00010000)
+#define TX_QUEUE_0_CONFIG_ELI (0x00020000)
+#define TX_QUEUE_0_CONFIG_ENI (0x00040000)
+#define TX_QUEUE_0_CONFIG_ESI (0x00080000)
+#define TX_QUEUE_0_CONFIG_EDI (0x00100000)
+
+#define reg_TX_QUEUE_0_BUF_CONFIG(base) __REG32(base, 0x00000284)
+#define TX_QUEUE_0_BUF_CONFIG_OCN_PORT (0x0000003f)
+#define TX_QUEUE_0_BUF_CONFIG_BURST (0x00000300)
+#define TX_QUEUE_0_BUF_CONFIG_BSWP (0x00000400)
+#define TX_QUEUE_0_BUF_CONFIG_WSWP (0x00000800)
+
+#define OCN_PORT_HLP 0 /* HLP Interface */
+#define OCN_PORT_PCI_X 1 /* PCI-X Interface */
+#define OCN_PORT_PROCESSOR_MASTER 2 /* Processor Interface (master) */
+#define OCN_PORT_PROCESSOR_SLAVE 3 /* Processor Interface (slave) */
+#define OCN_PORT_MEMORY 4 /* Memory Controller */
+#define OCN_PORT_DMA 5 /* DMA Controller */
+#define OCN_PORT_ETHERNET 6 /* Ethernet Controller */
+#define OCN_PORT_PRINT 7 /* Print Engine Interface */
+
+#define reg_TX_QUEUE_0_PTR_LOW(base) __REG32(base, 0x00000288)
+
+#define reg_TX_QUEUE_0_PTR_HIGH(base) __REG32(base, 0x0000028c)
+#define TX_QUEUE_0_PTR_HIGH_VALID (0x80000000)
+
+#define reg_RX_CONFIG(base) __REG32(base, 0x00000320)
+#define RX_CONFIG_DEF_Q (0x00000003)
+#define RX_CONFIG_EMF (0x00000100)
+#define RX_CONFIG_EUF (0x00000200)
+#define RX_CONFIG_BFE (0x00000400)
+#define RX_CONFIG_MFE (0x00000800)
+#define RX_CONFIG_UFE (0x00001000)
+#define RX_CONFIG_SE (0x00002000)
+#define RX_CONFIG_ABF (0x00200000)
+#define RX_CONFIG_APE (0x00400000)
+#define RX_CONFIG_CHP (0x00800000)
+#define RX_CONFIG_RST (0x80000000)
+
+#define reg_RX_CONTROL(base) __REG32(base, 0x00000324)
+#define GE_E0_RX_CONTROL_QUEUE_ENABLES (0x0000000f)
+#define GE_E0_RX_CONTROL_GO (0x00008000)
+#define GE_E0_RX_CONTROL_EAI (0x20000000)
+#define GE_E0_RX_CONTROL_ABT (0x40000000)
+#define GE_E0_RX_CONTROL_EII (0x80000000)
+
+#define reg_RX_EXTENDED_STATUS(base) __REG32(base, 0x0000032c)
+#define RX_EXTENDED_STATUS (0x0000032c)
+#define RX_EXTENDED_STATUS_EOQ (0x0000000f)
+#define RX_EXTENDED_STATUS_EOQ_0 (0x00000001)
+#define RX_EXTENDED_STATUS_EOF (0x00000f00)
+#define RX_EXTENDED_STATUS_DESCRIPTOR_INTERRUPT_CONDITION (0x000f0000)
+#define RX_EXTENDED_STATUS_ERROR_FLAG (0x0f000000)
+
+#define reg_RX_THRESHOLDS(base) __REG32(base, 0x00000330)
+
+#define reg_RX_DIAGNOSTIC_ADDR(base) __REG32(base, 0x00000370)
+#define RX_DIAGNOSTIC_ADDR_INDEX (0x0000007f)
+#define RX_DIAGNOSTIC_ADDR_DFR (0x40000000)
+#define RX_DIAGNOSTIC_ADDR_AI (0x80000000)
+
+#define reg_RX_DIAGNOSTIC_DATA(base) __REG32(base, 0x00000374)
+
+#define reg_RX_QUEUE_0_CONFIG(base) __REG32(base, 0x00000380)
+#define RX_QUEUE_0_CONFIG_OCN_PORT (0x0000003f)
+#define RX_QUEUE_0_CONFIG_BSWP (0x00000400)
+#define RX_QUEUE_0_CONFIG_WSWP (0x00000800)
+#define RX_QUEUE_0_CONFIG_AM (0x00004000)
+#define RX_QUEUE_0_CONFIG_EEI (0x00010000)
+#define RX_QUEUE_0_CONFIG_ELI (0x00020000)
+#define RX_QUEUE_0_CONFIG_ENI (0x00040000)
+#define RX_QUEUE_0_CONFIG_ESI (0x00080000)
+#define RX_QUEUE_0_CONFIG_EDI (0x00100000)
+
+#define reg_RX_QUEUE_0_BUF_CONFIG(base) __REG32(base, 0x00000384)
+#define RX_QUEUE_0_BUF_CONFIG_OCN_PORT (0x0000003f)
+#define RX_QUEUE_0_BUF_CONFIG_BURST (0x00000300)
+#define RX_QUEUE_0_BUF_CONFIG_BSWP (0x00000400)
+#define RX_QUEUE_0_BUF_CONFIG_WSWP (0x00000800)
+
+#define reg_RX_QUEUE_0_PTR_LOW(base) __REG32(base, 0x00000388)
+
+#define reg_RX_QUEUE_0_PTR_HIGH(base) __REG32(base, 0x0000038c)
+#define RX_QUEUE_0_PTR_HIGH_VALID (0x80000000)
+
+/*
+ * PHY register definitions
+ */
+/* the first 15 PHY registers are standard. */
+#define PHY_CTRL_REG 0 /* Control Register */
+#define PHY_STATUS_REG 1 /* Status Regiser */
+#define PHY_ID1_REG 2 /* Phy Id Reg (word 1) */
+#define PHY_ID2_REG 3 /* Phy Id Reg (word 2) */
+#define PHY_AN_ADV_REG 4 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY_REG 5 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP_REG 6 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX_REG 7 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE_REG 8 /* Link Partner Next Page */
+#define PHY_1000T_CTRL_REG 9 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS_REG 10 /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS_REG 11 /* Extended Status Reg */
+
+/*
+ * PHY Register bit masks.
+ */
+#define PHY_CTRL_RESET (1 << 15)
+#define PHY_CTRL_LOOPBACK (1 << 14)
+#define PHY_CTRL_SPEED0 (1 << 13)
+#define PHY_CTRL_AN_EN (1 << 12)
+#define PHY_CTRL_PWR_DN (1 << 11)
+#define PHY_CTRL_ISOLATE (1 << 10)
+#define PHY_CTRL_RESTART_AN (1 << 9)
+#define PHY_CTRL_FULL_DUPLEX (1 << 8)
+#define PHY_CTRL_CT_EN (1 << 7)
+#define PHY_CTRL_SPEED1 (1 << 6)
+
+#define PHY_STAT_100BASE_T4 (1 << 15)
+#define PHY_STAT_100BASE_X_FD (1 << 14)
+#define PHY_STAT_100BASE_X_HD (1 << 13)
+#define PHY_STAT_10BASE_T_FD (1 << 12)
+#define PHY_STAT_10BASE_T_HD (1 << 11)
+#define PHY_STAT_100BASE_T2_FD (1 << 10)
+#define PHY_STAT_100BASE_T2_HD (1 << 9)
+#define PHY_STAT_EXT_STAT (1 << 8)
+#define PHY_STAT_RESERVED (1 << 7)
+#define PHY_STAT_MFPS (1 << 6) /* Management Frames Preamble Suppression */
+#define PHY_STAT_AN_COMPLETE (1 << 5)
+#define PHY_STAT_REM_FAULT (1 << 4)
+#define PHY_STAT_AN_CAP (1 << 3)
+#define PHY_STAT_LINK_UP (1 << 2)
+#define PHY_STAT_JABBER (1 << 1)
+#define PHY_STAT_EXT_CAP (1 << 0)
+
+#define TBI_CONTROL_2 0x11
+#define TBI_CONTROL_2_ENABLE_COMMA_DETECT 0x0001
+#define TBI_CONTROL_2_ENABLE_WRAP 0x0002
+#define TBI_CONTROL_2_G_MII_MODE 0x0010
+#define TBI_CONTROL_2_RECEIVE_CLOCK_SELECT 0x0020
+#define TBI_CONTROL_2_AUTO_NEGOTIATION_SENSE 0x0100
+#define TBI_CONTROL_2_DISABLE_TRANSMIT_RUNNING_DISPARITY 0x1000
+#define TBI_CONTROL_2_DISABLE_RECEIVE_RUNNING_DISPARITY 0x2000
+#define TBI_CONTROL_2_SHORTCUT_LINK_TIMER 0x4000
+#define TBI_CONTROL_2_SOFT_RESET 0x8000
+
+/* marvel specific */
+#define MV1111_EXT_CTRL1_REG 16 /* PHY Specific Control Reg */
+#define MV1111_SPEC_STAT_REG 17 /* PHY Specific Status Reg */
+#define MV1111_EXT_CTRL2_REG 20 /* Extended PHY Specific Control Reg */
+
+/*
+ * MARVELL 88E1111 PHY register bit masks
+ */
+/* PHY Specific Status Register (MV1111_EXT_CTRL1_REG) */
+
+#define SPEC_STAT_SPEED_MASK (3 << 14)
+#define SPEC_STAT_FULL_DUP (1 << 13)
+#define SPEC_STAT_PAGE_RCVD (1 << 12)
+#define SPEC_STAT_RESOLVED (1 << 11) /* Speed and Duplex Resolved */
+#define SPEC_STAT_LINK_UP (1 << 10)
+#define SPEC_STAT_CABLE_LEN_MASK (7 << 7)/* Cable Length (100/1000 modes only) */
+#define SPEC_STAT_MDIX (1 << 6)
+#define SPEC_STAT_POLARITY (1 << 1)
+#define SPEC_STAT_JABBER (1 << 0)
+
+#define SPEED_1000 (2 << 14)
+#define SPEED_100 (1 << 14)
+#define SPEED_10 (0 << 14)
+
+#define TBI_ADDR 0x1E /* Ten Bit Interface address */
+
+/* negotiated link parameters */
+#define LINK_SPEED_UNKNOWN 0
+#define LINK_SPEED_10 1
+#define LINK_SPEED_100 2
+#define LINK_SPEED_1000 3
+
+#define LINK_DUPLEX_UNKNOWN 0
+#define LINK_DUPLEX_HALF 1
+#define LINK_DUPLEX_FULL 2
+
+static unsigned int phy_address[] = { 8, 9 };
+
+#define vuint32 volatile u32
+
+/* TX/RX buffer descriptors. MUST be cache line aligned in memory. (32 byte)
+ * This structure is accessed by the ethernet DMA engine which means it
+ * MUST be in LITTLE ENDIAN format */
+struct dma_descriptor {
+ vuint32 start_addr0; /* buffer address, least significant bytes. */
+ vuint32 start_addr1; /* buffer address, most significant bytes. */
+ vuint32 next_descr_addr0;/* next descriptor address, least significant bytes. Must be 64-bit aligned. */
+ vuint32 next_descr_addr1;/* next descriptor address, most significant bytes. */
+ vuint32 vlan_byte_count;/* VLAN tag(top 2 bytes) and byte countt (bottom 2 bytes). */
+ vuint32 config_status; /* Configuration/Status. */
+ vuint32 reserved1; /* reserved to make the descriptor cache line aligned. */
+ vuint32 reserved2; /* reserved to make the descriptor cache line aligned. */
+};
+
+/* last next descriptor address flag */
+#define DMA_DESCR_LAST (1 << 31)
+
+/* TX DMA descriptor config status bits */
+#define DMA_DESCR_TX_EOF (1 << 0) /* end of frame */
+#define DMA_DESCR_TX_SOF (1 << 1) /* start of frame */
+#define DMA_DESCR_TX_PFVLAN (1 << 2)
+#define DMA_DESCR_TX_HUGE (1 << 3)
+#define DMA_DESCR_TX_PAD (1 << 4)
+#define DMA_DESCR_TX_CRC (1 << 5)
+#define DMA_DESCR_TX_DESCR_INT (1 << 14)
+#define DMA_DESCR_TX_RETRY_COUNT 0x000F0000
+#define DMA_DESCR_TX_ONE_COLLISION (1 << 20)
+#define DMA_DESCR_TX_LATE_COLLISION (1 << 24)
+#define DMA_DESCR_TX_UNDERRUN (1 << 25)
+#define DMA_DESCR_TX_RETRY_LIMIT (1 << 26)
+#define DMA_DESCR_TX_OK (1 << 30)
+#define DMA_DESCR_TX_OWNER (1 << 31)
+
+/* RX DMA descriptor status bits */
+#define DMA_DESCR_RX_EOF (1 << 0)
+#define DMA_DESCR_RX_SOF (1 << 1)
+#define DMA_DESCR_RX_VTF (1 << 2)
+#define DMA_DESCR_RX_FRAME_IS_TYPE (1 << 3)
+#define DMA_DESCR_RX_SHORT_FRAME (1 << 4)
+#define DMA_DESCR_RX_HASH_MATCH (1 << 7)
+#define DMA_DESCR_RX_BAD_FRAME (1 << 8)
+#define DMA_DESCR_RX_OVERRUN (1 << 9)
+#define DMA_DESCR_RX_MAX_FRAME_LEN (1 << 11)
+#define DMA_DESCR_RX_CRC_ERROR (1 << 12)
+#define DMA_DESCR_RX_DESCR_INT (1 << 13)
+#define DMA_DESCR_RX_OWNER (1 << 15)
+
+#define RX_BUFFER_SIZE PKTSIZE
+#define NUM_RX_DESC PKTBUFSRX
+
+static struct dma_descriptor tx_descriptor __attribute__ ((aligned(32)));
+
+static struct dma_descriptor rx_descr_array[NUM_RX_DESC]
+ __attribute__ ((aligned(32)));
+
+static struct dma_descriptor *rx_descr_current;
+
+static int tsi108_eth_probe (struct eth_device *dev, bd_t * bis);
+static int tsi108_eth_send(struct eth_device *dev, void *packet, int length);
+static int tsi108_eth_recv (struct eth_device *dev);
+static void tsi108_eth_halt (struct eth_device *dev);
+static unsigned int read_phy (unsigned int base,
+ unsigned int phy_addr, unsigned int phy_reg);
+static void write_phy (unsigned int base,
+ unsigned int phy_addr,
+ unsigned int phy_reg, unsigned int phy_data);
+
+#if TSI108_ETH_DEBUG > 100
+/*
+ * print phy debug infomation
+ */
+static void dump_phy_regs (unsigned int phy_addr)
+{
+ int i;
+
+ printf ("PHY %d registers\n", phy_addr);
+ for (i = 0; i <= 30; i++) {
+ printf ("%2d 0x%04x\n", i, read_phy (ETH_BASE, phy_addr, i));
+ }
+ printf ("\n");
+
+}
+#else
+#define dump_phy_regs(base) do{}while(0)
+#endif
+
+#if TSI108_ETH_DEBUG > 100
+/*
+ * print debug infomation
+ */
+static void tx_diag_regs (unsigned int base)
+{
+ int i;
+ unsigned long dummy;
+
+ printf ("TX diagnostics registers\n");
+ reg_TX_DIAGNOSTIC_ADDR(base) = 0x00 | TX_DIAGNOSTIC_ADDR_AI;
+ udelay (1000);
+ dummy = reg_TX_DIAGNOSTIC_DATA(base);
+ for (i = 0x00; i <= 0x05; i++) {
+ udelay (1000);
+ printf ("0x%02x 0x%08x\n", i, reg_TX_DIAGNOSTIC_DATA(base));
+ }
+ reg_TX_DIAGNOSTIC_ADDR(base) = 0x40 | TX_DIAGNOSTIC_ADDR_AI;
+ udelay (1000);
+ dummy = reg_TX_DIAGNOSTIC_DATA(base);
+ for (i = 0x40; i <= 0x47; i++) {
+ udelay (1000);
+ printf ("0x%02x 0x%08x\n", i, reg_TX_DIAGNOSTIC_DATA(base));
+ }
+ printf ("\n");
+
+}
+#else
+#define tx_diag_regs(base) do{}while(0)
+#endif
+
+#if TSI108_ETH_DEBUG > 100
+/*
+ * print debug infomation
+ */
+static void rx_diag_regs (unsigned int base)
+{
+ int i;
+ unsigned long dummy;
+
+ printf ("RX diagnostics registers\n");
+ reg_RX_DIAGNOSTIC_ADDR(base) = 0x00 | RX_DIAGNOSTIC_ADDR_AI;
+ udelay (1000);
+ dummy = reg_RX_DIAGNOSTIC_DATA(base);
+ for (i = 0x00; i <= 0x05; i++) {
+ udelay (1000);
+ printf ("0x%02x 0x%08x\n", i, reg_RX_DIAGNOSTIC_DATA(base));
+ }
+ reg_RX_DIAGNOSTIC_ADDR(base) = 0x40 | RX_DIAGNOSTIC_ADDR_AI;
+ udelay (1000);
+ dummy = reg_RX_DIAGNOSTIC_DATA(base);
+ for (i = 0x08; i <= 0x0a; i++) {
+ udelay (1000);
+ printf ("0x%02x 0x%08x\n", i, reg_RX_DIAGNOSTIC_DATA(base));
+ }
+ printf ("\n");
+
+}
+#else
+#define rx_diag_regs(base) do{}while(0)
+#endif
+
+#if TSI108_ETH_DEBUG > 100
+/*
+ * print debug infomation
+ */
+static void debug_mii_regs (unsigned int base)
+{
+ printf ("MII_MGMT_CONFIG 0x%08x\n", reg_MII_MGMT_CONFIG(base));
+ printf ("MII_MGMT_COMMAND 0x%08x\n", reg_MII_MGMT_COMMAND(base));
+ printf ("MII_MGMT_ADDRESS 0x%08x\n", reg_MII_MGMT_ADDRESS(base));
+ printf ("MII_MGMT_CONTROL 0x%08x\n", reg_MII_MGMT_CONTROL(base));
+ printf ("MII_MGMT_STATUS 0x%08x\n", reg_MII_MGMT_STATUS(base));
+ printf ("MII_MGMT_INDICATORS 0x%08x\n", reg_MII_MGMT_INDICATORS(base));
+ printf ("\n");
+
+}
+#else
+#define debug_mii_regs(base) do{}while(0)
+#endif
+
+/*
+ * Wait until the phy bus is non-busy
+ */
+static void phy_wait (unsigned int base, unsigned int condition)
+{
+ int timeout;
+
+ timeout = 0;
+ while (reg_MII_MGMT_INDICATORS(base) & condition) {
+ udelay (10);
+ if (++timeout > 10000) {
+ printf ("ERROR: timeout waiting for phy bus (%d)\n",
+ condition);
+ break;
+ }
+ }
+}
+
+/*
+ * read phy register
+ */
+static unsigned int read_phy (unsigned int base,
+ unsigned int phy_addr, unsigned int phy_reg)
+{
+ unsigned int value;
+
+ phy_wait (base, MII_MGMT_INDICATORS_BUSY);
+
+ reg_MII_MGMT_ADDRESS(base) = (phy_addr << 8) | phy_reg;
+
+ /* Ensure that the Read Cycle bit is cleared prior to next read cycle */
+ reg_MII_MGMT_COMMAND(base) = 0;
+
+ /* start the read */
+ reg_MII_MGMT_COMMAND(base) = MII_MGMT_COMMAND_READ_CYCLE;
+
+ /* wait for the read to complete */
+ phy_wait (base,
+ MII_MGMT_INDICATORS_NOT_VALID | MII_MGMT_INDICATORS_BUSY);
+
+ value = reg_MII_MGMT_STATUS(base);
+
+ reg_MII_MGMT_COMMAND(base) = 0;
+
+ return value;
+}
+
+/*
+ * write phy register
+ */
+static void write_phy (unsigned int base,
+ unsigned int phy_addr,
+ unsigned int phy_reg, unsigned int phy_data)
+{
+ phy_wait (base, MII_MGMT_INDICATORS_BUSY);
+
+ reg_MII_MGMT_ADDRESS(base) = (phy_addr << 8) | phy_reg;
+
+ /* Ensure that the Read Cycle bit is cleared prior to next cycle */
+ reg_MII_MGMT_COMMAND(base) = 0;
+
+ /* start the write */
+ reg_MII_MGMT_CONTROL(base) = phy_data;
+}
+
+/*
+ * configure the marvell 88e1111 phy
+ */
+static int marvell_88e_phy_config (struct eth_device *dev, int *speed,
+ int *duplex)
+{
+ unsigned long base;
+ unsigned long phy_addr;
+ unsigned int phy_status;
+ unsigned int phy_spec_status;
+ int timeout;
+ int phy_speed;
+ int phy_duplex;
+ unsigned int value;
+
+ phy_speed = LINK_SPEED_UNKNOWN;
+ phy_duplex = LINK_DUPLEX_UNKNOWN;
+
+ base = dev->iobase;
+ phy_addr = (unsigned long)dev->priv;
+
+ /* Take the PHY out of reset. */
+ write_phy (ETH_BASE, phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
+
+ /* Wait for the reset process to complete. */
+ udelay (10);
+ timeout = 0;
+ while ((phy_status =
+ read_phy (ETH_BASE, phy_addr, PHY_CTRL_REG)) & PHY_CTRL_RESET) {
+ udelay (10);
+ if (++timeout > 10000) {
+ printf ("ERROR: timeout waiting for phy reset\n");
+ break;
+ }
+ }
+
+ /* TBI Configuration. */
+ write_phy (base, TBI_ADDR, TBI_CONTROL_2, TBI_CONTROL_2_G_MII_MODE |
+ TBI_CONTROL_2_RECEIVE_CLOCK_SELECT);
+ /* Wait for the link to be established. */
+ timeout = 0;
+ do {
+ udelay (20000);
+ phy_status = read_phy (ETH_BASE, phy_addr, PHY_STATUS_REG);
+ if (++timeout > 100) {
+ debug_lev(1, "ERROR: unable to establish link!!!\n");
+ break;
+ }
+ } while ((phy_status & PHY_STAT_LINK_UP) == 0);
+
+ if ((phy_status & PHY_STAT_LINK_UP) == 0)
+ return 0;
+
+ value = 0;
+ phy_spec_status = read_phy (ETH_BASE, phy_addr, MV1111_SPEC_STAT_REG);
+ if (phy_spec_status & SPEC_STAT_RESOLVED) {
+ switch (phy_spec_status & SPEC_STAT_SPEED_MASK) {
+ case SPEED_1000:
+ phy_speed = LINK_SPEED_1000;
+ value |= PHY_CTRL_SPEED1;
+ break;
+ case SPEED_100:
+ phy_speed = LINK_SPEED_100;
+ value |= PHY_CTRL_SPEED0;
+ break;
+ case SPEED_10:
+ phy_speed = LINK_SPEED_10;
+ break;
+ }
+ if (phy_spec_status & SPEC_STAT_FULL_DUP) {
+ phy_duplex = LINK_DUPLEX_FULL;
+ value |= PHY_CTRL_FULL_DUPLEX;
+ } else
+ phy_duplex = LINK_DUPLEX_HALF;
+ }
+ /* set TBI speed */
+ write_phy (base, TBI_ADDR, PHY_CTRL_REG, value);
+ write_phy (base, TBI_ADDR, PHY_AN_ADV_REG, 0x0060);
+
+#if TSI108_ETH_DEBUG > 0
+ printf ("%s link is up", dev->name);
+ phy_spec_status = read_phy (ETH_BASE, phy_addr, MV1111_SPEC_STAT_REG);
+ if (phy_spec_status & SPEC_STAT_RESOLVED) {
+ switch (phy_speed) {
+ case LINK_SPEED_1000:
+ printf (", 1000 Mbps");
+ break;
+ case LINK_SPEED_100:
+ printf (", 100 Mbps");
+ break;
+ case LINK_SPEED_10:
+ printf (", 10 Mbps");
+ break;
+ }
+ if (phy_duplex == LINK_DUPLEX_FULL)
+ printf (", Full duplex");
+ else
+ printf (", Half duplex");
+ }
+ printf ("\n");
+#endif
+
+ dump_phy_regs (TBI_ADDR);
+ if (speed)
+ *speed = phy_speed;
+ if (duplex)
+ *duplex = phy_duplex;
+
+ return 1;
+}
+
+/*
+ * External interface
+ *
+ * register the tsi108 ethernet controllers with the multi-ethernet system
+ */
+int tsi108_eth_initialize (bd_t * bis)
+{
+ struct eth_device *dev;
+ int index;
+
+ for (index = 0; index < CONFIG_TSI108_ETH_NUM_PORTS; index++) {
+ dev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ if (!dev) {
+ printf("tsi108: Can not allocate memory\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+ sprintf (dev->name, "TSI108_eth%d", index);
+
+ dev->iobase = ETH_BASE + (index * ETH_PORT_OFFSET);
+ dev->priv = (void *)(phy_address[index]);
+ dev->init = tsi108_eth_probe;
+ dev->halt = tsi108_eth_halt;
+ dev->send = tsi108_eth_send;
+ dev->recv = tsi108_eth_recv;
+
+ eth_register(dev);
+ }
+ return index;
+}
+
+/*
+ * probe for and initialize a single ethernet interface
+ */
+static int tsi108_eth_probe (struct eth_device *dev, bd_t * bis)
+{
+ unsigned long base;
+ unsigned long value;
+ int index;
+ struct dma_descriptor *tx_descr;
+ struct dma_descriptor *rx_descr;
+ int speed;
+ int duplex;
+
+ base = dev->iobase;
+
+ reg_PORT_CONTROL(base) = PORT_CONTROL_STE | PORT_CONTROL_BPT;
+
+ /* Bring DMA/FIFO out of reset. */
+ reg_TX_CONFIG(base) = 0x00000000;
+ reg_RX_CONFIG(base) = 0x00000000;
+
+ reg_TX_THRESHOLDS(base) = (192 << 16) | 192;
+ reg_RX_THRESHOLDS(base) = (192 << 16) | 112;
+
+ /* Bring MAC out of reset. */
+ reg_MAC_CONFIG_1(base) = 0x00000000;
+
+ /* DMA MAC configuration. */
+ reg_MAC_CONFIG_1(base) =
+ MAC_CONFIG_1_RX_ENABLE | MAC_CONFIG_1_TX_ENABLE;
+
+ reg_MII_MGMT_CONFIG(base) = MII_MGMT_CONFIG_NO_PREAMBLE;
+ reg_MAXIMUM_FRAME_LENGTH(base) = RX_BUFFER_SIZE;
+
+ /* Note: Early tsi108 manual did not have correct byte order
+ * for the station address.*/
+ reg_STATION_ADDRESS_1(base) = (dev->enetaddr[5] << 24) |
+ (dev->enetaddr[4] << 16) |
+ (dev->enetaddr[3] << 8) | (dev->enetaddr[2] << 0);
+
+ reg_STATION_ADDRESS_2(base) = (dev->enetaddr[1] << 24) |
+ (dev->enetaddr[0] << 16);
+
+ if (marvell_88e_phy_config(dev, &speed, &duplex) == 0)
+ return -1;
+
+ value =
+ MAC_CONFIG_2_PREAMBLE_LENGTH(7) | MAC_CONFIG_2_PAD_CRC |
+ MAC_CONFIG_2_CRC_ENABLE;
+ if (speed == LINK_SPEED_1000)
+ value |= MAC_CONFIG_2_INTERFACE_MODE(INTERFACE_MODE_BYTE);
+ else {
+ value |= MAC_CONFIG_2_INTERFACE_MODE(INTERFACE_MODE_NIBBLE);
+ reg_PORT_CONTROL(base) |= PORT_CONTROL_SPD;
+ }
+ if (duplex == LINK_DUPLEX_FULL) {
+ value |= MAC_CONFIG_2_FULL_DUPLEX;
+ reg_PORT_CONTROL(base) &= ~PORT_CONTROL_BPT;
+ } else
+ reg_PORT_CONTROL(base) |= PORT_CONTROL_BPT;
+ reg_MAC_CONFIG_2(base) = value;
+
+ reg_RX_CONFIG(base) = RX_CONFIG_SE;
+ reg_RX_QUEUE_0_CONFIG(base) = OCN_PORT_MEMORY;
+ reg_RX_QUEUE_0_BUF_CONFIG(base) = OCN_PORT_MEMORY;
+
+ /* initialize the RX DMA descriptors */
+ rx_descr = &rx_descr_array[0];
+ rx_descr_current = rx_descr;
+ for (index = 0; index < NUM_RX_DESC; index++) {
+ /* make sure the receive buffers are not in cache */
+ invalidate_dcache_range((unsigned long)NetRxPackets[index],
+ (unsigned long)NetRxPackets[index] +
+ RX_BUFFER_SIZE);
+ rx_descr->start_addr0 =
+ cpu_to_le32((vuint32) NetRxPackets[index]);
+ rx_descr->start_addr1 = 0;
+ rx_descr->next_descr_addr0 =
+ cpu_to_le32((vuint32) (rx_descr + 1));
+ rx_descr->next_descr_addr1 = 0;
+ rx_descr->vlan_byte_count = 0;
+ rx_descr->config_status = cpu_to_le32((RX_BUFFER_SIZE << 16) |
+ DMA_DESCR_RX_OWNER);
+ rx_descr++;
+ }
+ rx_descr--;
+ rx_descr->next_descr_addr0 = 0;
+ rx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST);
+ /* Push the descriptors to RAM so the ethernet DMA can see them */
+ invalidate_dcache_range((unsigned long)rx_descr_array,
+ (unsigned long)rx_descr_array +
+ sizeof(rx_descr_array));
+
+ /* enable RX queue */
+ reg_RX_CONTROL(base) = TX_CONTROL_GO | 0x01;
+ reg_RX_QUEUE_0_PTR_LOW(base) = (u32) rx_descr_current;
+ /* enable receive DMA */
+ reg_RX_QUEUE_0_PTR_HIGH(base) = RX_QUEUE_0_PTR_HIGH_VALID;
+
+ reg_TX_QUEUE_0_CONFIG(base) = OCN_PORT_MEMORY;
+ reg_TX_QUEUE_0_BUF_CONFIG(base) = OCN_PORT_MEMORY;
+
+ /* initialize the TX DMA descriptor */
+ tx_descr = &tx_descriptor;
+
+ tx_descr->start_addr0 = 0;
+ tx_descr->start_addr1 = 0;
+ tx_descr->next_descr_addr0 = 0;
+ tx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST);
+ tx_descr->vlan_byte_count = 0;
+ tx_descr->config_status = cpu_to_le32(DMA_DESCR_TX_OK |
+ DMA_DESCR_TX_SOF |
+ DMA_DESCR_TX_EOF);
+ /* enable TX queue */
+ reg_TX_CONTROL(base) = TX_CONTROL_GO | 0x01;
+
+ return 0;
+}
+
+/*
+ * send a packet
+ */
+static int tsi108_eth_send(struct eth_device *dev, void *packet, int length)
+{
+ unsigned long base;
+ int timeout;
+ struct dma_descriptor *tx_descr;
+ unsigned long status;
+
+ base = dev->iobase;
+ tx_descr = &tx_descriptor;
+
+ /* Wait until the last packet has been transmitted. */
+ timeout = 0;
+ do {
+ /* make sure we see the changes made by the DMA engine */
+ invalidate_dcache_range((unsigned long)tx_descr,
+ (unsigned long)tx_descr +
+ sizeof(struct dma_descriptor));
+
+ if (timeout != 0)
+ udelay (15);
+ if (++timeout > 10000) {
+ tx_diag_regs(base);
+ debug_lev(1,
+ "ERROR: timeout waiting for last transmit packet to be sent\n");
+ return 0;
+ }
+ } while (tx_descr->config_status & cpu_to_le32(DMA_DESCR_TX_OWNER));
+
+ status = le32_to_cpu(tx_descr->config_status);
+ if ((status & DMA_DESCR_TX_OK) == 0) {
+#ifdef TX_PRINT_ERRORS
+ printf ("TX packet error: 0x%08lx\n %s%s%s%s\n", status,
+ status & DMA_DESCR_TX_OK ? "tx error, " : "",
+ status & DMA_DESCR_TX_RETRY_LIMIT ?
+ "retry limit reached, " : "",
+ status & DMA_DESCR_TX_UNDERRUN ? "underrun, " : "",
+ status & DMA_DESCR_TX_LATE_COLLISION ? "late collision, "
+ : "");
+#endif
+ }
+
+ debug_lev (9, "sending packet %d\n", length);
+ tx_descr->start_addr0 = cpu_to_le32((vuint32) packet);
+ tx_descr->start_addr1 = 0;
+ tx_descr->next_descr_addr0 = 0;
+ tx_descr->next_descr_addr1 = cpu_to_le32(DMA_DESCR_LAST);
+ tx_descr->vlan_byte_count = cpu_to_le32(length);
+ tx_descr->config_status = cpu_to_le32(DMA_DESCR_TX_OWNER |
+ DMA_DESCR_TX_CRC |
+ DMA_DESCR_TX_PAD |
+ DMA_DESCR_TX_SOF |
+ DMA_DESCR_TX_EOF);
+
+ invalidate_dcache_range((unsigned long)tx_descr,
+ (unsigned long)tx_descr +
+ sizeof(struct dma_descriptor));
+
+ invalidate_dcache_range((unsigned long)packet,
+ (unsigned long)packet + length);
+
+ reg_TX_QUEUE_0_PTR_LOW(base) = (u32) tx_descr;
+ reg_TX_QUEUE_0_PTR_HIGH(base) = TX_QUEUE_0_PTR_HIGH_VALID;
+
+ return length;
+}
+
+/*
+ * Check for received packets and send them up the protocal stack
+ */
+static int tsi108_eth_recv (struct eth_device *dev)
+{
+ struct dma_descriptor *rx_descr;
+ unsigned long base;
+ int length = 0;
+ unsigned long status;
+ uchar *buffer;
+
+ base = dev->iobase;
+
+ /* make sure we see the changes made by the DMA engine */
+ invalidate_dcache_range ((unsigned long)rx_descr_array,
+ (unsigned long)rx_descr_array +
+ sizeof(rx_descr_array));
+
+ /* process all of the received packets */
+ rx_descr = rx_descr_current;
+ while ((rx_descr->config_status & cpu_to_le32(DMA_DESCR_RX_OWNER)) == 0) {
+ /* check for error */
+ status = le32_to_cpu(rx_descr->config_status);
+ if (status & DMA_DESCR_RX_BAD_FRAME) {
+#ifdef RX_PRINT_ERRORS
+ printf ("RX packet error: 0x%08lx\n %s%s%s%s%s%s\n",
+ status,
+ status & DMA_DESCR_RX_FRAME_IS_TYPE ? "too big, "
+ : "",
+ status & DMA_DESCR_RX_SHORT_FRAME ? "too short, "
+ : "",
+ status & DMA_DESCR_RX_BAD_FRAME ? "bad frame, " :
+ "",
+ status & DMA_DESCR_RX_OVERRUN ? "overrun, " : "",
+ status & DMA_DESCR_RX_MAX_FRAME_LEN ?
+ "max length, " : "",
+ status & DMA_DESCR_RX_CRC_ERROR ? "CRC error, " :
+ "");
+#endif
+ } else {
+ length =
+ le32_to_cpu(rx_descr->vlan_byte_count) & 0xFFFF;
+
+ /*** process packet ***/
+ buffer = (uchar *)(le32_to_cpu(rx_descr->start_addr0));
+ NetReceive(buffer, length);
+
+ invalidate_dcache_range ((unsigned long)buffer,
+ (unsigned long)buffer +
+ RX_BUFFER_SIZE);
+ }
+ /* Give this buffer back to the DMA engine */
+ rx_descr->vlan_byte_count = 0;
+ rx_descr->config_status = cpu_to_le32 ((RX_BUFFER_SIZE << 16) |
+ DMA_DESCR_RX_OWNER);
+ /* move descriptor pointer forward */
+ rx_descr =
+ (struct dma_descriptor
+ *)(le32_to_cpu (rx_descr->next_descr_addr0));
+ if (rx_descr == 0)
+ rx_descr = &rx_descr_array[0];
+ }
+ /* remember where we are for next time */
+ rx_descr_current = rx_descr;
+
+ /* If the DMA engine has reached the end of the queue
+ * start over at the begining */
+ if (reg_RX_EXTENDED_STATUS(base) & RX_EXTENDED_STATUS_EOQ_0) {
+
+ reg_RX_EXTENDED_STATUS(base) = RX_EXTENDED_STATUS_EOQ_0;
+ reg_RX_QUEUE_0_PTR_LOW(base) = (u32) & rx_descr_array[0];
+ reg_RX_QUEUE_0_PTR_HIGH(base) = RX_QUEUE_0_PTR_HIGH_VALID;
+ }
+
+ return length;
+}
+
+/*
+ * disable an ethernet interface
+ */
+static void tsi108_eth_halt (struct eth_device *dev)
+{
+ unsigned long base;
+
+ base = dev->iobase;
+
+ /* Put DMA/FIFO into reset state. */
+ reg_TX_CONFIG(base) = TX_CONFIG_RST;
+ reg_RX_CONFIG(base) = RX_CONFIG_RST;
+
+ /* Put MAC into reset state. */
+ reg_MAC_CONFIG_1(base) = MAC_CONFIG_1_SOFT_RESET;
+}
diff --git a/qemu/roms/u-boot/drivers/net/uli526x.c b/qemu/roms/u-boot/drivers/net/uli526x.c
new file mode 100644
index 000000000..538f11e3e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/uli526x.c
@@ -0,0 +1,996 @@
+/*
+ * Copyright 2007, 2010 Freescale Semiconductor, Inc.
+ *
+ * Author: Roy Zang <tie-fei.zang@freescale.com>, Sep, 2007
+ *
+ * Description:
+ * ULI 526x Ethernet port driver.
+ * Based on the Linux driver: drivers/net/tulip/uli526x.c
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <miiphy.h>
+
+/* some kernel function compatible define */
+
+#undef DEBUG
+
+/* Board/System/Debug information/definition */
+#define ULI_VENDOR_ID 0x10B9
+#define ULI5261_DEVICE_ID 0x5261
+#define ULI5263_DEVICE_ID 0x5263
+/* ULi M5261 ID*/
+#define PCI_ULI5261_ID (ULI5261_DEVICE_ID << 16 | ULI_VENDOR_ID)
+/* ULi M5263 ID*/
+#define PCI_ULI5263_ID (ULI5263_DEVICE_ID << 16 | ULI_VENDOR_ID)
+
+#define ULI526X_IO_SIZE 0x100
+#define TX_DESC_CNT 0x10 /* Allocated Tx descriptors */
+#define RX_DESC_CNT PKTBUFSRX /* Allocated Rx descriptors */
+#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2) /* Max TX packet count */
+#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3) /* TX wakeup count */
+#define DESC_ALL_CNT (TX_DESC_CNT + RX_DESC_CNT)
+#define TX_BUF_ALLOC 0x300
+#define RX_ALLOC_SIZE PKTSIZE
+#define ULI526X_RESET 1
+#define CR0_DEFAULT 0
+#define CR6_DEFAULT 0x22200000
+#define CR7_DEFAULT 0x180c1
+#define CR15_DEFAULT 0x06 /* TxJabber RxWatchdog */
+#define TDES0_ERR_MASK 0x4302 /* TXJT, LC, EC, FUE */
+#define MAX_PACKET_SIZE 1514
+#define ULI5261_MAX_MULTICAST 14
+#define RX_COPY_SIZE 100
+#define MAX_CHECK_PACKET 0x8000
+
+#define ULI526X_10MHF 0
+#define ULI526X_100MHF 1
+#define ULI526X_10MFD 4
+#define ULI526X_100MFD 5
+#define ULI526X_AUTO 8
+
+#define ULI526X_TXTH_72 0x400000 /* TX TH 72 byte */
+#define ULI526X_TXTH_96 0x404000 /* TX TH 96 byte */
+#define ULI526X_TXTH_128 0x0000 /* TX TH 128 byte */
+#define ULI526X_TXTH_256 0x4000 /* TX TH 256 byte */
+#define ULI526X_TXTH_512 0x8000 /* TX TH 512 byte */
+#define ULI526X_TXTH_1K 0xC000 /* TX TH 1K byte */
+
+/* CR9 definition: SROM/MII */
+#define CR9_SROM_READ 0x4800
+#define CR9_SRCS 0x1
+#define CR9_SRCLK 0x2
+#define CR9_CRDOUT 0x8
+#define SROM_DATA_0 0x0
+#define SROM_DATA_1 0x4
+#define PHY_DATA_1 0x20000
+#define PHY_DATA_0 0x00000
+#define MDCLKH 0x10000
+
+#define PHY_POWER_DOWN 0x800
+
+#define SROM_V41_CODE 0x14
+
+#define SROM_CLK_WRITE(data, ioaddr) do { \
+ outl(data|CR9_SROM_READ|CR9_SRCS, ioaddr); \
+ udelay(5); \
+ outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK, ioaddr); \
+ udelay(5); \
+ outl(data|CR9_SROM_READ|CR9_SRCS, ioaddr); \
+ udelay(5); \
+ } while (0)
+
+/* Structure/enum declaration */
+
+struct tx_desc {
+ u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
+ char *tx_buf_ptr; /* Data for us */
+ struct tx_desc *next_tx_desc;
+};
+
+struct rx_desc {
+ u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
+ char *rx_buf_ptr; /* Data for us */
+ struct rx_desc *next_rx_desc;
+};
+
+struct uli526x_board_info {
+ u32 chip_id; /* Chip vendor/Device ID */
+ pci_dev_t pdev;
+
+ long ioaddr; /* I/O base address */
+ u32 cr0_data;
+ u32 cr5_data;
+ u32 cr6_data;
+ u32 cr7_data;
+ u32 cr15_data;
+
+ /* pointer for memory physical address */
+ dma_addr_t buf_pool_dma_ptr; /* Tx buffer pool memory */
+ dma_addr_t buf_pool_dma_start; /* Tx buffer pool align dword */
+ dma_addr_t desc_pool_dma_ptr; /* descriptor pool memory */
+ dma_addr_t first_tx_desc_dma;
+ dma_addr_t first_rx_desc_dma;
+
+ /* descriptor pointer */
+ unsigned char *buf_pool_ptr; /* Tx buffer pool memory */
+ unsigned char *buf_pool_start; /* Tx buffer pool align dword */
+ unsigned char *desc_pool_ptr; /* descriptor pool memory */
+ struct tx_desc *first_tx_desc;
+ struct tx_desc *tx_insert_ptr;
+ struct tx_desc *tx_remove_ptr;
+ struct rx_desc *first_rx_desc;
+ struct rx_desc *rx_ready_ptr; /* packet come pointer */
+ unsigned long tx_packet_cnt; /* transmitted packet count */
+
+ u16 PHY_reg4; /* Saved Phyxcer register 4 value */
+
+ u8 media_mode; /* user specify media mode */
+ u8 op_mode; /* real work dedia mode */
+ u8 phy_addr;
+
+ /* NIC SROM data */
+ unsigned char srom[128];
+};
+
+enum uli526x_offsets {
+ DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
+ DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
+ DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
+ DCR15 = 0x78
+};
+
+enum uli526x_CR6_bits {
+ CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
+ CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
+ CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
+};
+
+/* Global variable declaration -- */
+
+static unsigned char uli526x_media_mode = ULI526X_AUTO;
+
+static struct tx_desc desc_pool_array[DESC_ALL_CNT + 0x20]
+ __attribute__ ((aligned(32)));
+static char buf_pool[TX_BUF_ALLOC * TX_DESC_CNT + 4];
+
+/* For module input parameter */
+static int mode = 8;
+
+/* function declaration -- */
+static int uli526x_start_xmit(struct eth_device *dev, void *packet, int length);
+static const struct ethtool_ops netdev_ethtool_ops;
+static u16 read_srom_word(long, int);
+static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
+static void allocate_rx_buffer(struct uli526x_board_info *);
+static void update_cr6(u32, unsigned long);
+static u16 uli_phy_read(unsigned long, u8, u8, u32);
+static u16 phy_readby_cr10(unsigned long, u8, u8);
+static void uli_phy_write(unsigned long, u8, u8, u16, u32);
+static void phy_writeby_cr10(unsigned long, u8, u8, u16);
+static void phy_write_1bit(unsigned long, u32, u32);
+static u16 phy_read_1bit(unsigned long, u32);
+static int uli526x_rx_packet(struct eth_device *);
+static void uli526x_free_tx_pkt(struct eth_device *,
+ struct uli526x_board_info *);
+static void uli526x_reuse_buf(struct rx_desc *);
+static void uli526x_init(struct eth_device *);
+static void uli526x_set_phyxcer(struct uli526x_board_info *);
+
+
+static int uli526x_init_one(struct eth_device *, bd_t *);
+static void uli526x_disable(struct eth_device *);
+static void set_mac_addr(struct eth_device *);
+
+static struct pci_device_id uli526x_pci_tbl[] = {
+ { ULI_VENDOR_ID, ULI5261_DEVICE_ID}, /* 5261 device */
+ { ULI_VENDOR_ID, ULI5263_DEVICE_ID}, /* 5263 device */
+ {}
+};
+
+/* ULI526X network board routine */
+
+/*
+ * Search ULI526X board, register it
+ */
+
+int uli526x_initialize(bd_t *bis)
+{
+ pci_dev_t devno;
+ int card_number = 0;
+ struct eth_device *dev;
+ struct uli526x_board_info *db; /* board information structure */
+
+ u32 iobase;
+ int idx = 0;
+
+ while (1) {
+ /* Find PCI device */
+ devno = pci_find_devices(uli526x_pci_tbl, idx++);
+ if (devno < 0)
+ break;
+
+ pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+ iobase &= ~0xf;
+
+ dev = (struct eth_device *)malloc(sizeof *dev);
+ if (!dev) {
+ printf("uli526x: Can not allocate memory\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+ sprintf(dev->name, "uli526x#%d", card_number);
+ db = (struct uli526x_board_info *)
+ malloc(sizeof(struct uli526x_board_info));
+
+ dev->priv = db;
+ db->pdev = devno;
+ dev->iobase = iobase;
+
+ dev->init = uli526x_init_one;
+ dev->halt = uli526x_disable;
+ dev->send = uli526x_start_xmit;
+ dev->recv = uli526x_rx_packet;
+
+ /* init db */
+ db->ioaddr = dev->iobase;
+ /* get chip id */
+
+ pci_read_config_dword(devno, PCI_VENDOR_ID, &db->chip_id);
+#ifdef DEBUG
+ printf("uli526x: uli526x @0x%x\n", iobase);
+ printf("uli526x: chip_id%x\n", db->chip_id);
+#endif
+ eth_register(dev);
+ card_number++;
+ pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x20);
+ udelay(10 * 1000);
+ }
+ return card_number;
+}
+
+static int uli526x_init_one(struct eth_device *dev, bd_t *bis)
+{
+
+ struct uli526x_board_info *db = dev->priv;
+ int i;
+
+ switch (mode) {
+ case ULI526X_10MHF:
+ case ULI526X_100MHF:
+ case ULI526X_10MFD:
+ case ULI526X_100MFD:
+ uli526x_media_mode = mode;
+ break;
+ default:
+ uli526x_media_mode = ULI526X_AUTO;
+ break;
+ }
+
+ /* Allocate Tx/Rx descriptor memory */
+ db->desc_pool_ptr = (uchar *)&desc_pool_array[0];
+ db->desc_pool_dma_ptr = (dma_addr_t)&desc_pool_array[0];
+ if (db->desc_pool_ptr == NULL)
+ return -1;
+
+ db->buf_pool_ptr = (uchar *)&buf_pool[0];
+ db->buf_pool_dma_ptr = (dma_addr_t)&buf_pool[0];
+ if (db->buf_pool_ptr == NULL)
+ return -1;
+
+ db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
+ db->first_tx_desc_dma = db->desc_pool_dma_ptr;
+
+ db->buf_pool_start = db->buf_pool_ptr;
+ db->buf_pool_dma_start = db->buf_pool_dma_ptr;
+
+#ifdef DEBUG
+ printf("%s(): db->ioaddr= 0x%x\n",
+ __FUNCTION__, db->ioaddr);
+ printf("%s(): media_mode= 0x%x\n",
+ __FUNCTION__, uli526x_media_mode);
+ printf("%s(): db->desc_pool_ptr= 0x%x\n",
+ __FUNCTION__, db->desc_pool_ptr);
+ printf("%s(): db->desc_pool_dma_ptr= 0x%x\n",
+ __FUNCTION__, db->desc_pool_dma_ptr);
+ printf("%s(): db->buf_pool_ptr= 0x%x\n",
+ __FUNCTION__, db->buf_pool_ptr);
+ printf("%s(): db->buf_pool_dma_ptr= 0x%x\n",
+ __FUNCTION__, db->buf_pool_dma_ptr);
+#endif
+
+ /* read 64 word srom data */
+ for (i = 0; i < 64; i++)
+ ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr,
+ i));
+
+ /* Set Node address */
+ if (((db->srom[0] == 0xff) && (db->srom[1] == 0xff)) ||
+ ((db->srom[0] == 0x00) && (db->srom[1] == 0x00)))
+ /* SROM absent, so write MAC address to ID Table */
+ set_mac_addr(dev);
+ else { /*Exist SROM*/
+ for (i = 0; i < 6; i++)
+ dev->enetaddr[i] = db->srom[20 + i];
+ }
+#ifdef DEBUG
+ for (i = 0; i < 6; i++)
+ printf("%c%02x", i ? ':' : ' ', dev->enetaddr[i]);
+#endif
+ db->PHY_reg4 = 0x1e0;
+
+ /* system variable init */
+ db->cr6_data = CR6_DEFAULT ;
+ db->cr6_data |= ULI526X_TXTH_256;
+ db->cr0_data = CR0_DEFAULT;
+ uli526x_init(dev);
+ return 0;
+}
+
+static void uli526x_disable(struct eth_device *dev)
+{
+#ifdef DEBUG
+ printf("uli526x_disable\n");
+#endif
+ struct uli526x_board_info *db = dev->priv;
+
+ if (!((inl(db->ioaddr + DCR12)) & 0x8)) {
+ /* Reset & stop ULI526X board */
+ outl(ULI526X_RESET, db->ioaddr + DCR0);
+ udelay(5);
+ uli_phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
+
+ /* reset the board */
+ db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */
+ update_cr6(db->cr6_data, dev->iobase);
+ outl(0, dev->iobase + DCR7); /* Disable Interrupt */
+ outl(inl(dev->iobase + DCR5), dev->iobase + DCR5);
+ }
+}
+
+/* Initialize ULI526X board
+ * Reset ULI526X board
+ * Initialize TX/Rx descriptor chain structure
+ * Send the set-up frame
+ * Enable Tx/Rx machine
+ */
+
+static void uli526x_init(struct eth_device *dev)
+{
+
+ struct uli526x_board_info *db = dev->priv;
+ u8 phy_tmp;
+ u16 phy_value;
+ u16 phy_reg_reset;
+
+ /* Reset M526x MAC controller */
+ outl(ULI526X_RESET, db->ioaddr + DCR0); /* RESET MAC */
+ udelay(100);
+ outl(db->cr0_data, db->ioaddr + DCR0);
+ udelay(5);
+
+ /* Phy addr : In some boards,M5261/M5263 phy address != 1 */
+ db->phy_addr = 1;
+ db->tx_packet_cnt = 0;
+ for (phy_tmp = 0; phy_tmp < 32; phy_tmp++) {
+ /* peer add */
+ phy_value = uli_phy_read(db->ioaddr, phy_tmp, 3, db->chip_id);
+ if (phy_value != 0xffff && phy_value != 0) {
+ db->phy_addr = phy_tmp;
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ printf("%s(): db->ioaddr= 0x%x\n", __FUNCTION__, db->ioaddr);
+ printf("%s(): db->phy_addr= 0x%x\n", __FUNCTION__, db->phy_addr);
+#endif
+ if (phy_tmp == 32)
+ printf("Can not find the phy address!!!");
+
+ /* Parser SROM and media mode */
+ db->media_mode = uli526x_media_mode;
+
+ if (!(inl(db->ioaddr + DCR12) & 0x8)) {
+ /* Phyxcer capability setting */
+ phy_reg_reset = uli_phy_read(db->ioaddr,
+ db->phy_addr, 0, db->chip_id);
+ phy_reg_reset = (phy_reg_reset | 0x8000);
+ uli_phy_write(db->ioaddr, db->phy_addr, 0,
+ phy_reg_reset, db->chip_id);
+ udelay(500);
+
+ /* Process Phyxcer Media Mode */
+ uli526x_set_phyxcer(db);
+ }
+ /* Media Mode Process */
+ if (!(db->media_mode & ULI526X_AUTO))
+ db->op_mode = db->media_mode; /* Force Mode */
+
+ /* Initialize Transmit/Receive decriptor and CR3/4 */
+ uli526x_descriptor_init(db, db->ioaddr);
+
+ /* Init CR6 to program M526X operation */
+ update_cr6(db->cr6_data, db->ioaddr);
+
+ /* Init CR7, interrupt active bit */
+ db->cr7_data = CR7_DEFAULT;
+ outl(db->cr7_data, db->ioaddr + DCR7);
+
+ /* Init CR15, Tx jabber and Rx watchdog timer */
+ outl(db->cr15_data, db->ioaddr + DCR15);
+
+ /* Enable ULI526X Tx/Rx function */
+ db->cr6_data |= CR6_RXSC | CR6_TXSC;
+ update_cr6(db->cr6_data, db->ioaddr);
+ while (!(inl(db->ioaddr + DCR12) & 0x8))
+ udelay(10);
+}
+
+/*
+ * Hardware start transmission.
+ * Send a packet to media from the upper layer.
+ */
+
+static int uli526x_start_xmit(struct eth_device *dev, void *packet, int length)
+{
+ struct uli526x_board_info *db = dev->priv;
+ struct tx_desc *txptr;
+ unsigned int len = length;
+ /* Too large packet check */
+ if (len > MAX_PACKET_SIZE) {
+ printf(": big packet = %d\n", len);
+ return 0;
+ }
+
+ /* No Tx resource check, it never happen nromally */
+ if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
+ printf("No Tx resource %ld\n", db->tx_packet_cnt);
+ return 0;
+ }
+
+ /* Disable NIC interrupt */
+ outl(0, dev->iobase + DCR7);
+
+ /* transmit this packet */
+ txptr = db->tx_insert_ptr;
+ memcpy((char *)txptr->tx_buf_ptr, (char *)packet, (int)length);
+ txptr->tdes1 = cpu_to_le32(0xe1000000 | length);
+
+ /* Point to next transmit free descriptor */
+ db->tx_insert_ptr = txptr->next_tx_desc;
+
+ /* Transmit Packet Process */
+ if ((db->tx_packet_cnt < TX_DESC_CNT)) {
+ txptr->tdes0 = cpu_to_le32(0x80000000); /* Set owner bit */
+ db->tx_packet_cnt++; /* Ready to send */
+ outl(0x1, dev->iobase + DCR1); /* Issue Tx polling */
+ }
+
+ /* Got ULI526X status */
+ db->cr5_data = inl(db->ioaddr + DCR5);
+ outl(db->cr5_data, db->ioaddr + DCR5);
+
+#ifdef TX_DEBUG
+ printf("%s(): length = 0x%x\n", __FUNCTION__, length);
+ printf("%s(): cr5_data=%x\n", __FUNCTION__, db->cr5_data);
+#endif
+
+ outl(db->cr7_data, dev->iobase + DCR7);
+ uli526x_free_tx_pkt(dev, db);
+
+ return length;
+}
+
+/*
+ * Free TX resource after TX complete
+ */
+
+static void uli526x_free_tx_pkt(struct eth_device *dev,
+ struct uli526x_board_info *db)
+{
+ struct tx_desc *txptr;
+ u32 tdes0;
+
+ txptr = db->tx_remove_ptr;
+ while (db->tx_packet_cnt) {
+ tdes0 = le32_to_cpu(txptr->tdes0);
+ /* printf(DRV_NAME ": tdes0=%x\n", tdes0); */
+ if (tdes0 & 0x80000000)
+ break;
+
+ /* A packet sent completed */
+ db->tx_packet_cnt--;
+
+ if (tdes0 != 0x7fffffff) {
+#ifdef TX_DEBUG
+ printf("%s()tdes0=%x\n", __FUNCTION__, tdes0);
+#endif
+ if (tdes0 & TDES0_ERR_MASK) {
+ if (tdes0 & 0x0002) { /* UnderRun */
+ if (!(db->cr6_data & CR6_SFT)) {
+ db->cr6_data = db->cr6_data |
+ CR6_SFT;
+ update_cr6(db->cr6_data,
+ db->ioaddr);
+ }
+ }
+ }
+ }
+
+ txptr = txptr->next_tx_desc;
+ }/* End of while */
+
+ /* Update TX remove pointer to next */
+ db->tx_remove_ptr = txptr;
+}
+
+
+/*
+ * Receive the come packet and pass to upper layer
+ */
+
+static int uli526x_rx_packet(struct eth_device *dev)
+{
+ struct uli526x_board_info *db = dev->priv;
+ struct rx_desc *rxptr;
+ int rxlen = 0;
+ u32 rdes0;
+
+ rxptr = db->rx_ready_ptr;
+
+ rdes0 = le32_to_cpu(rxptr->rdes0);
+#ifdef RX_DEBUG
+ printf("%s(): rxptr->rdes0=%x:%x\n", __FUNCTION__, rxptr->rdes0);
+#endif
+ if (!(rdes0 & 0x80000000)) { /* packet owner check */
+ if ((rdes0 & 0x300) != 0x300) {
+ /* A packet without First/Last flag */
+ /* reuse this buf */
+ printf("A packet without First/Last flag");
+ uli526x_reuse_buf(rxptr);
+ } else {
+ /* A packet with First/Last flag */
+ rxlen = ((rdes0 >> 16) & 0x3fff) - 4;
+#ifdef RX_DEBUG
+ printf("%s(): rxlen =%x\n", __FUNCTION__, rxlen);
+#endif
+ /* error summary bit check */
+ if (rdes0 & 0x8000) {
+ /* This is a error packet */
+ printf("Error: rdes0: %x\n", rdes0);
+ }
+
+ if (!(rdes0 & 0x8000) ||
+ ((db->cr6_data & CR6_PM) && (rxlen > 6))) {
+
+#ifdef RX_DEBUG
+ printf("%s(): rx_skb_ptr =%x\n",
+ __FUNCTION__, rxptr->rx_buf_ptr);
+ printf("%s(): rxlen =%x\n",
+ __FUNCTION__, rxlen);
+
+ printf("%s(): buf addr =%x\n",
+ __FUNCTION__, rxptr->rx_buf_ptr);
+ printf("%s(): rxlen =%x\n",
+ __FUNCTION__, rxlen);
+ int i;
+ for (i = 0; i < 0x20; i++)
+ printf("%s(): data[%x] =%x\n",
+ __FUNCTION__, i, rxptr->rx_buf_ptr[i]);
+#endif
+
+ NetReceive((uchar *)rxptr->rx_buf_ptr, rxlen);
+ uli526x_reuse_buf(rxptr);
+
+ } else {
+ /* Reuse SKB buffer when the packet is error */
+ printf("Reuse buffer, rdes0");
+ uli526x_reuse_buf(rxptr);
+ }
+ }
+
+ rxptr = rxptr->next_rx_desc;
+ }
+
+ db->rx_ready_ptr = rxptr;
+ return rxlen;
+}
+
+/*
+ * Reuse the RX buffer
+ */
+
+static void uli526x_reuse_buf(struct rx_desc *rxptr)
+{
+
+ if (!(rxptr->rdes0 & cpu_to_le32(0x80000000)))
+ rxptr->rdes0 = cpu_to_le32(0x80000000);
+ else
+ printf("Buffer reuse method error");
+}
+/*
+ * Initialize transmit/Receive descriptor
+ * Using Chain structure, and allocate Tx/Rx buffer
+ */
+
+static void uli526x_descriptor_init(struct uli526x_board_info *db,
+ unsigned long ioaddr)
+{
+ struct tx_desc *tmp_tx;
+ struct rx_desc *tmp_rx;
+ unsigned char *tmp_buf;
+ dma_addr_t tmp_tx_dma, tmp_rx_dma;
+ dma_addr_t tmp_buf_dma;
+ int i;
+ /* tx descriptor start pointer */
+ db->tx_insert_ptr = db->first_tx_desc;
+ db->tx_remove_ptr = db->first_tx_desc;
+
+ outl(db->first_tx_desc_dma, ioaddr + DCR4); /* TX DESC address */
+
+ /* rx descriptor start pointer */
+ db->first_rx_desc = (void *)db->first_tx_desc +
+ sizeof(struct tx_desc) * TX_DESC_CNT;
+ db->first_rx_desc_dma = db->first_tx_desc_dma +
+ sizeof(struct tx_desc) * TX_DESC_CNT;
+ db->rx_ready_ptr = db->first_rx_desc;
+ outl(db->first_rx_desc_dma, ioaddr + DCR3); /* RX DESC address */
+#ifdef DEBUG
+ printf("%s(): db->first_tx_desc= 0x%x\n",
+ __FUNCTION__, db->first_tx_desc);
+ printf("%s(): db->first_rx_desc_dma= 0x%x\n",
+ __FUNCTION__, db->first_rx_desc_dma);
+#endif
+ /* Init Transmit chain */
+ tmp_buf = db->buf_pool_start;
+ tmp_buf_dma = db->buf_pool_dma_start;
+ tmp_tx_dma = db->first_tx_desc_dma;
+ for (tmp_tx = db->first_tx_desc, i = 0;
+ i < TX_DESC_CNT; i++, tmp_tx++) {
+ tmp_tx->tx_buf_ptr = (char *)tmp_buf;
+ tmp_tx->tdes0 = cpu_to_le32(0);
+ tmp_tx->tdes1 = cpu_to_le32(0x81000000); /* IC, chain */
+ tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
+ tmp_tx_dma += sizeof(struct tx_desc);
+ tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
+ tmp_tx->next_tx_desc = tmp_tx + 1;
+ tmp_buf = tmp_buf + TX_BUF_ALLOC;
+ tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
+ }
+ (--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
+ tmp_tx->next_tx_desc = db->first_tx_desc;
+
+ /* Init Receive descriptor chain */
+ tmp_rx_dma = db->first_rx_desc_dma;
+ for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT;
+ i++, tmp_rx++) {
+ tmp_rx->rdes0 = cpu_to_le32(0);
+ tmp_rx->rdes1 = cpu_to_le32(0x01000600);
+ tmp_rx_dma += sizeof(struct rx_desc);
+ tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
+ tmp_rx->next_rx_desc = tmp_rx + 1;
+ }
+ (--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
+ tmp_rx->next_rx_desc = db->first_rx_desc;
+
+ /* pre-allocate Rx buffer */
+ allocate_rx_buffer(db);
+}
+
+/*
+ * Update CR6 value
+ * Firstly stop ULI526X, then written value and start
+ */
+
+static void update_cr6(u32 cr6_data, unsigned long ioaddr)
+{
+
+ outl(cr6_data, ioaddr + DCR6);
+ udelay(5);
+}
+
+/*
+ * Allocate rx buffer,
+ */
+
+static void allocate_rx_buffer(struct uli526x_board_info *db)
+{
+ int index;
+ struct rx_desc *rxptr;
+ rxptr = db->first_rx_desc;
+ u32 addr;
+
+ for (index = 0; index < RX_DESC_CNT; index++) {
+ addr = (u32)NetRxPackets[index];
+ addr += (16 - (addr & 15));
+ rxptr->rx_buf_ptr = (char *) addr;
+ rxptr->rdes2 = cpu_to_le32(addr);
+ rxptr->rdes0 = cpu_to_le32(0x80000000);
+#ifdef DEBUG
+ printf("%s(): Number 0x%x:\n", __FUNCTION__, index);
+ printf("%s(): addr 0x%x:\n", __FUNCTION__, addr);
+ printf("%s(): rxptr address = 0x%x\n", __FUNCTION__, rxptr);
+ printf("%s(): rxptr buf address = 0x%x\n", \
+ __FUNCTION__, rxptr->rx_buf_ptr);
+ printf("%s(): rdes2 = 0x%x\n", __FUNCTION__, rxptr->rdes2);
+#endif
+ rxptr = rxptr->next_rx_desc;
+ }
+}
+
+/*
+ * Read one word data from the serial ROM
+ */
+
+static u16 read_srom_word(long ioaddr, int offset)
+{
+ int i;
+ u16 srom_data = 0;
+ long cr9_ioaddr = ioaddr + DCR9;
+
+ outl(CR9_SROM_READ, cr9_ioaddr);
+ outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+ /* Send the Read Command 110b */
+ SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+ SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+ SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);
+
+ /* Send the offset */
+ for (i = 5; i >= 0; i--) {
+ srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
+ SROM_CLK_WRITE(srom_data, cr9_ioaddr);
+ }
+
+ outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+ for (i = 16; i > 0; i--) {
+ outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
+ udelay(5);
+ srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT)
+ ? 1 : 0);
+ outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+ udelay(5);
+ }
+
+ outl(CR9_SROM_READ, cr9_ioaddr);
+ return srom_data;
+}
+
+/*
+ * Set 10/100 phyxcer capability
+ * AUTO mode : phyxcer register4 is NIC capability
+ * Force mode: phyxcer register4 is the force media
+ */
+
+static void uli526x_set_phyxcer(struct uli526x_board_info *db)
+{
+ u16 phy_reg;
+
+ /* Phyxcer capability setting */
+ phy_reg = uli_phy_read(db->ioaddr,
+ db->phy_addr, 4, db->chip_id) & ~0x01e0;
+
+ if (db->media_mode & ULI526X_AUTO) {
+ /* AUTO Mode */
+ phy_reg |= db->PHY_reg4;
+ } else {
+ /* Force Mode */
+ switch (db->media_mode) {
+ case ULI526X_10MHF: phy_reg |= 0x20; break;
+ case ULI526X_10MFD: phy_reg |= 0x40; break;
+ case ULI526X_100MHF: phy_reg |= 0x80; break;
+ case ULI526X_100MFD: phy_reg |= 0x100; break;
+ }
+
+ }
+
+ /* Write new capability to Phyxcer Reg4 */
+ if (!(phy_reg & 0x01e0)) {
+ phy_reg |= db->PHY_reg4;
+ db->media_mode |= ULI526X_AUTO;
+ }
+ uli_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
+
+ /* Restart Auto-Negotiation */
+ uli_phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
+ udelay(50);
+}
+
+/*
+ * Write a word to Phy register
+ */
+
+static void uli_phy_write(unsigned long iobase, u8 phy_addr, u8 offset,
+ u16 phy_data, u32 chip_id)
+{
+ u16 i;
+ unsigned long ioaddr;
+
+ if (chip_id == PCI_ULI5263_ID) {
+ phy_writeby_cr10(iobase, phy_addr, offset, phy_data);
+ return;
+ }
+ /* M5261/M5263 Chip */
+ ioaddr = iobase + DCR9;
+
+ /* Send 33 synchronization clock to Phy controller */
+ for (i = 0; i < 35; i++)
+ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+ /* Send start command(01) to Phy */
+ phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+ /* Send write command(01) to Phy */
+ phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+ /* Send Phy address */
+ for (i = 0x10; i > 0; i = i >> 1)
+ phy_write_1bit(ioaddr, phy_addr & i ?
+ PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+ /* Send register address */
+ for (i = 0x10; i > 0; i = i >> 1)
+ phy_write_1bit(ioaddr, offset & i ?
+ PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+ /* written trasnition */
+ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+ phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+
+ /* Write a word data to PHY controller */
+ for (i = 0x8000; i > 0; i >>= 1)
+ phy_write_1bit(ioaddr, phy_data & i ?
+ PHY_DATA_1 : PHY_DATA_0, chip_id);
+}
+
+/*
+ * Read a word data from phy register
+ */
+
+static u16 uli_phy_read(unsigned long iobase, u8 phy_addr, u8 offset,
+ u32 chip_id)
+{
+ int i;
+ u16 phy_data;
+ unsigned long ioaddr;
+
+ if (chip_id == PCI_ULI5263_ID)
+ return phy_readby_cr10(iobase, phy_addr, offset);
+ /* M5261/M5263 Chip */
+ ioaddr = iobase + DCR9;
+
+ /* Send 33 synchronization clock to Phy controller */
+ for (i = 0; i < 35; i++)
+ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+ /* Send start command(01) to Phy */
+ phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+
+ /* Send read command(10) to Phy */
+ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
+ phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
+
+ /* Send Phy address */
+ for (i = 0x10; i > 0; i = i >> 1)
+ phy_write_1bit(ioaddr, phy_addr & i ?
+ PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+ /* Send register address */
+ for (i = 0x10; i > 0; i = i >> 1)
+ phy_write_1bit(ioaddr, offset & i ?
+ PHY_DATA_1 : PHY_DATA_0, chip_id);
+
+ /* Skip transition state */
+ phy_read_1bit(ioaddr, chip_id);
+
+ /* read 16bit data */
+ for (phy_data = 0, i = 0; i < 16; i++) {
+ phy_data <<= 1;
+ phy_data |= phy_read_1bit(ioaddr, chip_id);
+ }
+
+ return phy_data;
+}
+
+static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset)
+{
+ unsigned long ioaddr, cr10_value;
+
+ ioaddr = iobase + DCR10;
+ cr10_value = phy_addr;
+ cr10_value = (cr10_value<<5) + offset;
+ cr10_value = (cr10_value<<16) + 0x08000000;
+ outl(cr10_value, ioaddr);
+ udelay(1);
+ while (1) {
+ cr10_value = inl(ioaddr);
+ if (cr10_value & 0x10000000)
+ break;
+ }
+ return (cr10_value&0x0ffff);
+}
+
+static void phy_writeby_cr10(unsigned long iobase, u8 phy_addr,
+ u8 offset, u16 phy_data)
+{
+ unsigned long ioaddr, cr10_value;
+
+ ioaddr = iobase + DCR10;
+ cr10_value = phy_addr;
+ cr10_value = (cr10_value<<5) + offset;
+ cr10_value = (cr10_value<<16) + 0x04000000 + phy_data;
+ outl(cr10_value, ioaddr);
+ udelay(1);
+}
+/*
+ * Write one bit data to Phy Controller
+ */
+
+static void phy_write_1bit(unsigned long ioaddr, u32 phy_data, u32 chip_id)
+{
+ outl(phy_data , ioaddr); /* MII Clock Low */
+ udelay(1);
+ outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */
+ udelay(1);
+ outl(phy_data , ioaddr); /* MII Clock Low */
+ udelay(1);
+}
+
+/*
+ * Read one bit phy data from PHY controller
+ */
+
+static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id)
+{
+ u16 phy_data;
+
+ outl(0x50000 , ioaddr);
+ udelay(1);
+ phy_data = (inl(ioaddr) >> 19) & 0x1;
+ outl(0x40000 , ioaddr);
+ udelay(1);
+
+ return phy_data;
+}
+
+/*
+ * Set MAC address to ID Table
+ */
+
+static void set_mac_addr(struct eth_device *dev)
+{
+ int i;
+ u16 addr;
+ struct uli526x_board_info *db = dev->priv;
+ outl(0x10000, db->ioaddr + DCR0); /* Diagnosis mode */
+ /* Reset dianostic pointer port */
+ outl(0x1c0, db->ioaddr + DCR13);
+ outl(0, db->ioaddr + DCR14); /* Clear reset port */
+ outl(0x10, db->ioaddr + DCR14); /* Reset ID Table pointer */
+ outl(0, db->ioaddr + DCR14); /* Clear reset port */
+ outl(0, db->ioaddr + DCR13); /* Clear CR13 */
+ /* Select ID Table access port */
+ outl(0x1b0, db->ioaddr + DCR13);
+ /* Read MAC address from CR14 */
+ for (i = 0; i < 3; i++) {
+ addr = dev->enetaddr[2 * i] | (dev->enetaddr[2 * i + 1] << 8);
+ outl(addr, db->ioaddr + DCR14);
+ }
+ /* write end */
+ outl(0, db->ioaddr + DCR13); /* Clear CR13 */
+ outl(0, db->ioaddr + DCR0); /* Clear CR0 */
+ udelay(10);
+ return;
+}
diff --git a/qemu/roms/u-boot/drivers/net/vsc7385.c b/qemu/roms/u-boot/drivers/net/vsc7385.c
new file mode 100644
index 000000000..a5110e516
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/vsc7385.c
@@ -0,0 +1,97 @@
+/*
+ * Vitesse 7385 Switch Firmware Upload
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. This file is licensed
+ * under the terms of the GNU General Public License version 2. This
+ * program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
+ *
+ * This module uploads proprietary firmware for the Vitesse VSC7385 5-port
+ * switch.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include "vsc7385.h"
+
+/*
+ * Upload a Vitesse VSC7385 firmware image to the hardware
+ *
+ * This function takes a pointer to a VSC7385 firmware image and a size, and
+ * uploads that firmware to the VSC7385.
+ *
+ * This firmware is typically located at a board-specific flash address,
+ * and the size is typically 8KB.
+ *
+ * The firmware is Vitesse proprietary.
+ *
+ * Further details on the register information can be obtained from Vitesse.
+ */
+int vsc7385_upload_firmware(void *firmware, unsigned int size)
+{
+ u8 *fw = firmware;
+ unsigned int i;
+
+ u32 *gloreset = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c050);
+ u32 *icpu_ctrl = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c040);
+ u32 *icpu_addr = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c044);
+ u32 *icpu_data = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c048);
+ u32 *icpu_rom_map = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c070);
+#ifdef DEBUG
+ u32 *chipid = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c060);
+#endif
+
+ out_be32(gloreset, 3);
+ udelay(200);
+
+ out_be32(icpu_ctrl, 0x8E);
+ udelay(20);
+
+ out_be32(icpu_rom_map, 1);
+ udelay(20);
+
+ /* Write the firmware to I-RAM */
+ out_be32(icpu_addr, 0);
+ udelay(20);
+
+ for (i = 0; i < size; i++) {
+ out_be32(icpu_data, fw[i]);
+ udelay(20);
+ if (ctrlc())
+ return -EINTR;
+ }
+
+ /* Read back and compare */
+ out_be32(icpu_addr, 0);
+ udelay(20);
+
+ for (i = 0; i < size; i++) {
+ u8 value;
+
+ value = (u8) in_be32(icpu_data);
+ udelay(20);
+ if (value != fw[i]) {
+ debug("VSC7385: Upload mismatch: address 0x%x, "
+ "read value 0x%x, image value 0x%x\n",
+ i, value, fw[i]);
+
+ return -EIO;
+ }
+ if (ctrlc())
+ break;
+ }
+
+ out_be32(icpu_ctrl, 0x0B);
+ udelay(20);
+
+#ifdef DEBUG
+ printf("VSC7385: Chip ID is %08x\n", in_be32(chipid));
+ udelay(20);
+#endif
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_axi_emac.c b/qemu/roms/u-boot/drivers/net/xilinx_axi_emac.c
new file mode 100644
index 000000000..262b67b6c
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_axi_emac.c
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2011 PetaLogix
+ * Copyright (C) 2010 Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <phy.h>
+#include <miiphy.h>
+
+#if !defined(CONFIG_PHYLIB)
+# error AXI_ETHERNET requires PHYLIB
+#endif
+
+/* Link setup */
+#define XAE_EMMC_LINKSPEED_MASK 0xC0000000 /* Link speed */
+#define XAE_EMMC_LINKSPD_10 0x00000000 /* Link Speed mask for 10 Mbit */
+#define XAE_EMMC_LINKSPD_100 0x40000000 /* Link Speed mask for 100 Mbit */
+#define XAE_EMMC_LINKSPD_1000 0x80000000 /* Link Speed mask for 1000 Mbit */
+
+/* Interrupt Status/Enable/Mask Registers bit definitions */
+#define XAE_INT_RXRJECT_MASK 0x00000008 /* Rx frame rejected */
+#define XAE_INT_MGTRDY_MASK 0x00000080 /* MGT clock Lock */
+
+/* Receive Configuration Word 1 (RCW1) Register bit definitions */
+#define XAE_RCW1_RX_MASK 0x10000000 /* Receiver enable */
+
+/* Transmitter Configuration (TC) Register bit definitions */
+#define XAE_TC_TX_MASK 0x10000000 /* Transmitter enable */
+
+#define XAE_UAW1_UNICASTADDR_MASK 0x0000FFFF
+
+/* MDIO Management Configuration (MC) Register bit definitions */
+#define XAE_MDIO_MC_MDIOEN_MASK 0x00000040 /* MII management enable*/
+
+/* MDIO Management Control Register (MCR) Register bit definitions */
+#define XAE_MDIO_MCR_PHYAD_MASK 0x1F000000 /* Phy Address Mask */
+#define XAE_MDIO_MCR_PHYAD_SHIFT 24 /* Phy Address Shift */
+#define XAE_MDIO_MCR_REGAD_MASK 0x001F0000 /* Reg Address Mask */
+#define XAE_MDIO_MCR_REGAD_SHIFT 16 /* Reg Address Shift */
+#define XAE_MDIO_MCR_OP_READ_MASK 0x00008000 /* Op Code Read Mask */
+#define XAE_MDIO_MCR_OP_WRITE_MASK 0x00004000 /* Op Code Write Mask */
+#define XAE_MDIO_MCR_INITIATE_MASK 0x00000800 /* Ready Mask */
+#define XAE_MDIO_MCR_READY_MASK 0x00000080 /* Ready Mask */
+
+#define XAE_MDIO_DIV_DFT 29 /* Default MDIO clock divisor */
+
+/* DMA macros */
+/* Bitmasks of XAXIDMA_CR_OFFSET register */
+#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA channel */
+#define XAXIDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */
+
+/* Bitmasks of XAXIDMA_SR_OFFSET register */
+#define XAXIDMA_HALTED_MASK 0x00000001 /* DMA channel halted */
+
+/* Bitmask for interrupts */
+#define XAXIDMA_IRQ_IOC_MASK 0x00001000 /* Completion intr */
+#define XAXIDMA_IRQ_DELAY_MASK 0x00002000 /* Delay interrupt */
+#define XAXIDMA_IRQ_ALL_MASK 0x00007000 /* All interrupts */
+
+/* Bitmasks of XAXIDMA_BD_CTRL_OFFSET register */
+#define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+
+#define DMAALIGN 128
+
+static u8 rxframe[PKTSIZE_ALIGN] __attribute((aligned(DMAALIGN)));
+
+/* Reflect dma offsets */
+struct axidma_reg {
+ u32 control; /* DMACR */
+ u32 status; /* DMASR */
+ u32 current; /* CURDESC */
+ u32 reserved;
+ u32 tail; /* TAILDESC */
+};
+
+/* Private driver structures */
+struct axidma_priv {
+ struct axidma_reg *dmatx;
+ struct axidma_reg *dmarx;
+ int phyaddr;
+
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+};
+
+/* BD descriptors */
+struct axidma_bd {
+ u32 next; /* Next descriptor pointer */
+ u32 reserved1;
+ u32 phys; /* Buffer address */
+ u32 reserved2;
+ u32 reserved3;
+ u32 reserved4;
+ u32 cntrl; /* Control */
+ u32 status; /* Status */
+ u32 app0;
+ u32 app1; /* TX start << 16 | insert */
+ u32 app2; /* TX csum seed */
+ u32 app3;
+ u32 app4;
+ u32 sw_id_offset;
+ u32 reserved5;
+ u32 reserved6;
+};
+
+/* Static BDs - driver uses only one BD */
+static struct axidma_bd tx_bd __attribute((aligned(DMAALIGN)));
+static struct axidma_bd rx_bd __attribute((aligned(DMAALIGN)));
+
+struct axi_regs {
+ u32 reserved[3];
+ u32 is; /* 0xC: Interrupt status */
+ u32 reserved2;
+ u32 ie; /* 0x14: Interrupt enable */
+ u32 reserved3[251];
+ u32 rcw1; /* 0x404: Rx Configuration Word 1 */
+ u32 tc; /* 0x408: Tx Configuration */
+ u32 reserved4;
+ u32 emmc; /* 0x410: EMAC mode configuration */
+ u32 reserved5[59];
+ u32 mdio_mc; /* 0x500: MII Management Config */
+ u32 mdio_mcr; /* 0x504: MII Management Control */
+ u32 mdio_mwd; /* 0x508: MII Management Write Data */
+ u32 mdio_mrd; /* 0x50C: MII Management Read Data */
+ u32 reserved6[124];
+ u32 uaw0; /* 0x700: Unicast address word 0 */
+ u32 uaw1; /* 0x704: Unicast address word 1 */
+};
+
+/* Use MII register 1 (MII status register) to detect PHY */
+#define PHY_DETECT_REG 1
+
+/*
+ * Mask used to verify certain PHY features (or register contents)
+ * in the register above:
+ * 0x1000: 10Mbps full duplex support
+ * 0x0800: 10Mbps half duplex support
+ * 0x0008: Auto-negotiation support
+ */
+#define PHY_DETECT_MASK 0x1808
+
+static inline int mdio_wait(struct eth_device *dev)
+{
+ struct axi_regs *regs = (struct axi_regs *)dev->iobase;
+ u32 timeout = 200;
+
+ /* Wait till MDIO interface is ready to accept a new transaction. */
+ while (timeout && (!(in_be32(&regs->mdio_mcr)
+ & XAE_MDIO_MCR_READY_MASK))) {
+ timeout--;
+ udelay(1);
+ }
+ if (!timeout) {
+ printf("%s: Timeout\n", __func__);
+ return 1;
+ }
+ return 0;
+}
+
+static u32 phyread(struct eth_device *dev, u32 phyaddress, u32 registernum,
+ u16 *val)
+{
+ struct axi_regs *regs = (struct axi_regs *)dev->iobase;
+ u32 mdioctrlreg = 0;
+
+ if (mdio_wait(dev))
+ return 1;
+
+ mdioctrlreg = ((phyaddress << XAE_MDIO_MCR_PHYAD_SHIFT) &
+ XAE_MDIO_MCR_PHYAD_MASK) |
+ ((registernum << XAE_MDIO_MCR_REGAD_SHIFT)
+ & XAE_MDIO_MCR_REGAD_MASK) |
+ XAE_MDIO_MCR_INITIATE_MASK |
+ XAE_MDIO_MCR_OP_READ_MASK;
+
+ out_be32(&regs->mdio_mcr, mdioctrlreg);
+
+ if (mdio_wait(dev))
+ return 1;
+
+ /* Read data */
+ *val = in_be32(&regs->mdio_mrd);
+ return 0;
+}
+
+static u32 phywrite(struct eth_device *dev, u32 phyaddress, u32 registernum,
+ u32 data)
+{
+ struct axi_regs *regs = (struct axi_regs *)dev->iobase;
+ u32 mdioctrlreg = 0;
+
+ if (mdio_wait(dev))
+ return 1;
+
+ mdioctrlreg = ((phyaddress << XAE_MDIO_MCR_PHYAD_SHIFT) &
+ XAE_MDIO_MCR_PHYAD_MASK) |
+ ((registernum << XAE_MDIO_MCR_REGAD_SHIFT)
+ & XAE_MDIO_MCR_REGAD_MASK) |
+ XAE_MDIO_MCR_INITIATE_MASK |
+ XAE_MDIO_MCR_OP_WRITE_MASK;
+
+ /* Write data */
+ out_be32(&regs->mdio_mwd, data);
+
+ out_be32(&regs->mdio_mcr, mdioctrlreg);
+
+ if (mdio_wait(dev))
+ return 1;
+
+ return 0;
+}
+
+/* Setting axi emac and phy to proper setting */
+static int setup_phy(struct eth_device *dev)
+{
+ u16 phyreg;
+ u32 i, speed, emmc_reg, ret;
+ struct axidma_priv *priv = dev->priv;
+ struct axi_regs *regs = (struct axi_regs *)dev->iobase;
+ struct phy_device *phydev;
+
+ u32 supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full;
+
+ if (priv->phyaddr == -1) {
+ /* Detect the PHY address */
+ for (i = 31; i >= 0; i--) {
+ ret = phyread(dev, i, PHY_DETECT_REG, &phyreg);
+ if (!ret && (phyreg != 0xFFFF) &&
+ ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
+ /* Found a valid PHY address */
+ priv->phyaddr = i;
+ debug("axiemac: Found valid phy address, %x\n",
+ phyreg);
+ break;
+ }
+ }
+ }
+
+ /* Interface - look at tsec */
+ phydev = phy_connect(priv->bus, priv->phyaddr, dev, 0);
+
+ phydev->supported &= supported;
+ phydev->advertising = phydev->supported;
+ priv->phydev = phydev;
+ phy_config(phydev);
+ if (phy_startup(phydev)) {
+ printf("axiemac: could not initialize PHY %s\n",
+ phydev->dev->name);
+ return 0;
+ }
+ if (!phydev->link) {
+ printf("%s: No link.\n", phydev->dev->name);
+ return 0;
+ }
+
+ switch (phydev->speed) {
+ case 1000:
+ speed = XAE_EMMC_LINKSPD_1000;
+ break;
+ case 100:
+ speed = XAE_EMMC_LINKSPD_100;
+ break;
+ case 10:
+ speed = XAE_EMMC_LINKSPD_10;
+ break;
+ default:
+ return 0;
+ }
+
+ /* Setup the emac for the phy speed */
+ emmc_reg = in_be32(&regs->emmc);
+ emmc_reg &= ~XAE_EMMC_LINKSPEED_MASK;
+ emmc_reg |= speed;
+
+ /* Write new speed setting out to Axi Ethernet */
+ out_be32(&regs->emmc, emmc_reg);
+
+ /*
+ * Setting the operating speed of the MAC needs a delay. There
+ * doesn't seem to be register to poll, so please consider this
+ * during your application design.
+ */
+ udelay(1);
+
+ return 1;
+}
+
+/* STOP DMA transfers */
+static void axiemac_halt(struct eth_device *dev)
+{
+ struct axidma_priv *priv = dev->priv;
+ u32 temp;
+
+ /* Stop the hardware */
+ temp = in_be32(&priv->dmatx->control);
+ temp &= ~XAXIDMA_CR_RUNSTOP_MASK;
+ out_be32(&priv->dmatx->control, temp);
+
+ temp = in_be32(&priv->dmarx->control);
+ temp &= ~XAXIDMA_CR_RUNSTOP_MASK;
+ out_be32(&priv->dmarx->control, temp);
+
+ debug("axiemac: Halted\n");
+}
+
+static int axi_ethernet_init(struct eth_device *dev)
+{
+ struct axi_regs *regs = (struct axi_regs *)dev->iobase;
+ u32 timeout = 200;
+
+ /*
+ * Check the status of the MgtRdy bit in the interrupt status
+ * registers. This must be done to allow the MGT clock to become stable
+ * for the Sgmii and 1000BaseX PHY interfaces. No other register reads
+ * will be valid until this bit is valid.
+ * The bit is always a 1 for all other PHY interfaces.
+ */
+ while (timeout && (!(in_be32(&regs->is) & XAE_INT_MGTRDY_MASK))) {
+ timeout--;
+ udelay(1);
+ }
+ if (!timeout) {
+ printf("%s: Timeout\n", __func__);
+ return 1;
+ }
+
+ /* Stop the device and reset HW */
+ /* Disable interrupts */
+ out_be32(&regs->ie, 0);
+
+ /* Disable the receiver */
+ out_be32(&regs->rcw1, in_be32(&regs->rcw1) & ~XAE_RCW1_RX_MASK);
+
+ /*
+ * Stopping the receiver in mid-packet causes a dropped packet
+ * indication from HW. Clear it.
+ */
+ /* Set the interrupt status register to clear the interrupt */
+ out_be32(&regs->is, XAE_INT_RXRJECT_MASK);
+
+ /* Setup HW */
+ /* Set default MDIO divisor */
+ out_be32(&regs->mdio_mc, XAE_MDIO_DIV_DFT | XAE_MDIO_MC_MDIOEN_MASK);
+
+ debug("axiemac: InitHw done\n");
+ return 0;
+}
+
+static int axiemac_setup_mac(struct eth_device *dev)
+{
+ struct axi_regs *regs = (struct axi_regs *)dev->iobase;
+
+ /* Set the MAC address */
+ int val = ((dev->enetaddr[3] << 24) | (dev->enetaddr[2] << 16) |
+ (dev->enetaddr[1] << 8) | (dev->enetaddr[0]));
+ out_be32(&regs->uaw0, val);
+
+ val = (dev->enetaddr[5] << 8) | dev->enetaddr[4] ;
+ val |= in_be32(&regs->uaw1) & ~XAE_UAW1_UNICASTADDR_MASK;
+ out_be32(&regs->uaw1, val);
+ return 0;
+}
+
+/* Reset DMA engine */
+static void axi_dma_init(struct eth_device *dev)
+{
+ struct axidma_priv *priv = dev->priv;
+ u32 timeout = 500;
+
+ /* Reset the engine so the hardware starts from a known state */
+ out_be32(&priv->dmatx->control, XAXIDMA_CR_RESET_MASK);
+ out_be32(&priv->dmarx->control, XAXIDMA_CR_RESET_MASK);
+
+ /* At the initialization time, hardware should finish reset quickly */
+ while (timeout--) {
+ /* Check transmit/receive channel */
+ /* Reset is done when the reset bit is low */
+ if (!(in_be32(&priv->dmatx->control) |
+ in_be32(&priv->dmarx->control))
+ & XAXIDMA_CR_RESET_MASK) {
+ break;
+ }
+ }
+ if (!timeout)
+ printf("%s: Timeout\n", __func__);
+}
+
+static int axiemac_init(struct eth_device *dev, bd_t * bis)
+{
+ struct axidma_priv *priv = dev->priv;
+ struct axi_regs *regs = (struct axi_regs *)dev->iobase;
+ u32 temp;
+
+ debug("axiemac: Init started\n");
+ /*
+ * Initialize AXIDMA engine. AXIDMA engine must be initialized before
+ * AxiEthernet. During AXIDMA engine initialization, AXIDMA hardware is
+ * reset, and since AXIDMA reset line is connected to AxiEthernet, this
+ * would ensure a reset of AxiEthernet.
+ */
+ axi_dma_init(dev);
+
+ /* Initialize AxiEthernet hardware. */
+ if (axi_ethernet_init(dev))
+ return -1;
+
+ /* Disable all RX interrupts before RxBD space setup */
+ temp = in_be32(&priv->dmarx->control);
+ temp &= ~XAXIDMA_IRQ_ALL_MASK;
+ out_be32(&priv->dmarx->control, temp);
+
+ /* Start DMA RX channel. Now it's ready to receive data.*/
+ out_be32(&priv->dmarx->current, (u32)&rx_bd);
+
+ /* Setup the BD. */
+ memset(&rx_bd, 0, sizeof(rx_bd));
+ rx_bd.next = (u32)&rx_bd;
+ rx_bd.phys = (u32)&rxframe;
+ rx_bd.cntrl = sizeof(rxframe);
+ /* Flush the last BD so DMA core could see the updates */
+ flush_cache((u32)&rx_bd, sizeof(rx_bd));
+
+ /* It is necessary to flush rxframe because if you don't do it
+ * then cache can contain uninitialized data */
+ flush_cache((u32)&rxframe, sizeof(rxframe));
+
+ /* Start the hardware */
+ temp = in_be32(&priv->dmarx->control);
+ temp |= XAXIDMA_CR_RUNSTOP_MASK;
+ out_be32(&priv->dmarx->control, temp);
+
+ /* Rx BD is ready - start */
+ out_be32(&priv->dmarx->tail, (u32)&rx_bd);
+
+ /* Enable TX */
+ out_be32(&regs->tc, XAE_TC_TX_MASK);
+ /* Enable RX */
+ out_be32(&regs->rcw1, XAE_RCW1_RX_MASK);
+
+ /* PHY setup */
+ if (!setup_phy(dev)) {
+ axiemac_halt(dev);
+ return -1;
+ }
+
+ debug("axiemac: Init complete\n");
+ return 0;
+}
+
+static int axiemac_send(struct eth_device *dev, void *ptr, int len)
+{
+ struct axidma_priv *priv = dev->priv;
+ u32 timeout;
+
+ if (len > PKTSIZE_ALIGN)
+ len = PKTSIZE_ALIGN;
+
+ /* Flush packet to main memory to be trasfered by DMA */
+ flush_cache((u32)ptr, len);
+
+ /* Setup Tx BD */
+ memset(&tx_bd, 0, sizeof(tx_bd));
+ /* At the end of the ring, link the last BD back to the top */
+ tx_bd.next = (u32)&tx_bd;
+ tx_bd.phys = (u32)ptr;
+ /* Save len */
+ tx_bd.cntrl = len | XAXIDMA_BD_CTRL_TXSOF_MASK |
+ XAXIDMA_BD_CTRL_TXEOF_MASK;
+
+ /* Flush the last BD so DMA core could see the updates */
+ flush_cache((u32)&tx_bd, sizeof(tx_bd));
+
+ if (in_be32(&priv->dmatx->status) & XAXIDMA_HALTED_MASK) {
+ u32 temp;
+ out_be32(&priv->dmatx->current, (u32)&tx_bd);
+ /* Start the hardware */
+ temp = in_be32(&priv->dmatx->control);
+ temp |= XAXIDMA_CR_RUNSTOP_MASK;
+ out_be32(&priv->dmatx->control, temp);
+ }
+
+ /* Start transfer */
+ out_be32(&priv->dmatx->tail, (u32)&tx_bd);
+
+ /* Wait for transmission to complete */
+ debug("axiemac: Waiting for tx to be done\n");
+ timeout = 200;
+ while (timeout && (!in_be32(&priv->dmatx->status) &
+ (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) {
+ timeout--;
+ udelay(1);
+ }
+ if (!timeout) {
+ printf("%s: Timeout\n", __func__);
+ return 1;
+ }
+
+ debug("axiemac: Sending complete\n");
+ return 0;
+}
+
+static int isrxready(struct eth_device *dev)
+{
+ u32 status;
+ struct axidma_priv *priv = dev->priv;
+
+ /* Read pending interrupts */
+ status = in_be32(&priv->dmarx->status);
+
+ /* Acknowledge pending interrupts */
+ out_be32(&priv->dmarx->status, status & XAXIDMA_IRQ_ALL_MASK);
+
+ /*
+ * If Reception done interrupt is asserted, call RX call back function
+ * to handle the processed BDs and then raise the according flag.
+ */
+ if ((status & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK)))
+ return 1;
+
+ return 0;
+}
+
+static int axiemac_recv(struct eth_device *dev)
+{
+ u32 length;
+ struct axidma_priv *priv = dev->priv;
+ u32 temp;
+
+ /* Wait for an incoming packet */
+ if (!isrxready(dev))
+ return 0;
+
+ debug("axiemac: RX data ready\n");
+
+ /* Disable IRQ for a moment till packet is handled */
+ temp = in_be32(&priv->dmarx->control);
+ temp &= ~XAXIDMA_IRQ_ALL_MASK;
+ out_be32(&priv->dmarx->control, temp);
+
+ length = rx_bd.app4 & 0xFFFF; /* max length mask */
+#ifdef DEBUG
+ print_buffer(&rxframe, &rxframe[0], 1, length, 16);
+#endif
+ /* Pass the received frame up for processing */
+ if (length)
+ NetReceive(rxframe, length);
+
+#ifdef DEBUG
+ /* It is useful to clear buffer to be sure that it is consistent */
+ memset(rxframe, 0, sizeof(rxframe));
+#endif
+ /* Setup RxBD */
+ /* Clear the whole buffer and setup it again - all flags are cleared */
+ memset(&rx_bd, 0, sizeof(rx_bd));
+ rx_bd.next = (u32)&rx_bd;
+ rx_bd.phys = (u32)&rxframe;
+ rx_bd.cntrl = sizeof(rxframe);
+
+ /* Write bd to HW */
+ flush_cache((u32)&rx_bd, sizeof(rx_bd));
+
+ /* It is necessary to flush rxframe because if you don't do it
+ * then cache will contain previous packet */
+ flush_cache((u32)&rxframe, sizeof(rxframe));
+
+ /* Rx BD is ready - start again */
+ out_be32(&priv->dmarx->tail, (u32)&rx_bd);
+
+ debug("axiemac: RX completed, framelength = %d\n", length);
+
+ return length;
+}
+
+static int axiemac_miiphy_read(const char *devname, uchar addr,
+ uchar reg, ushort *val)
+{
+ struct eth_device *dev = eth_get_dev();
+ u32 ret;
+
+ ret = phyread(dev, addr, reg, val);
+ debug("axiemac: Read MII 0x%x, 0x%x, 0x%x\n", addr, reg, *val);
+ return ret;
+}
+
+static int axiemac_miiphy_write(const char *devname, uchar addr,
+ uchar reg, ushort val)
+{
+ struct eth_device *dev = eth_get_dev();
+
+ debug("axiemac: Write MII 0x%x, 0x%x, 0x%x\n", addr, reg, val);
+ return phywrite(dev, addr, reg, val);
+}
+
+static int axiemac_bus_reset(struct mii_dev *bus)
+{
+ debug("axiemac: Bus reset\n");
+ return 0;
+}
+
+int xilinx_axiemac_initialize(bd_t *bis, unsigned long base_addr,
+ unsigned long dma_addr)
+{
+ struct eth_device *dev;
+ struct axidma_priv *priv;
+
+ dev = calloc(1, sizeof(struct eth_device));
+ if (dev == NULL)
+ return -1;
+
+ dev->priv = calloc(1, sizeof(struct axidma_priv));
+ if (dev->priv == NULL) {
+ free(dev);
+ return -1;
+ }
+ priv = dev->priv;
+
+ sprintf(dev->name, "aximac.%lx", base_addr);
+
+ dev->iobase = base_addr;
+ priv->dmatx = (struct axidma_reg *)dma_addr;
+ /* RX channel offset is 0x30 */
+ priv->dmarx = (struct axidma_reg *)(dma_addr + 0x30);
+ dev->init = axiemac_init;
+ dev->halt = axiemac_halt;
+ dev->send = axiemac_send;
+ dev->recv = axiemac_recv;
+ dev->write_hwaddr = axiemac_setup_mac;
+
+#ifdef CONFIG_PHY_ADDR
+ priv->phyaddr = CONFIG_PHY_ADDR;
+#else
+ priv->phyaddr = -1;
+#endif
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
+ miiphy_register(dev->name, axiemac_miiphy_read, axiemac_miiphy_write);
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+ priv->bus->reset = axiemac_bus_reset;
+#endif
+ return 1;
+}
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_emaclite.c b/qemu/roms/u-boot/drivers/net/xilinx_emaclite.c
new file mode 100644
index 000000000..2a5cc4455
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_emaclite.c
@@ -0,0 +1,392 @@
+/*
+ * (C) Copyright 2007-2009 Michal Simek
+ * (C) Copyright 2003 Xilinx Inc.
+ *
+ * Michal SIMEK <monstr@monstr.eu>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <net.h>
+#include <config.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <fdtdec.h>
+
+#undef DEBUG
+
+#define ENET_ADDR_LENGTH 6
+
+/* EmacLite constants */
+#define XEL_BUFFER_OFFSET 0x0800 /* Next buffer's offset */
+#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */
+#define XEL_TSR_OFFSET 0x07FC /* Tx status */
+#define XEL_RSR_OFFSET 0x17FC /* Rx status */
+#define XEL_RXBUFF_OFFSET 0x1000 /* Receive Buffer */
+
+/* Xmit complete */
+#define XEL_TSR_XMIT_BUSY_MASK 0x00000001UL
+/* Xmit interrupt enable bit */
+#define XEL_TSR_XMIT_IE_MASK 0x00000008UL
+/* Buffer is active, SW bit only */
+#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000UL
+/* Program the MAC address */
+#define XEL_TSR_PROGRAM_MASK 0x00000002UL
+/* define for programming the MAC address into the EMAC Lite */
+#define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK)
+
+/* Transmit packet length upper byte */
+#define XEL_TPLR_LENGTH_MASK_HI 0x0000FF00UL
+/* Transmit packet length lower byte */
+#define XEL_TPLR_LENGTH_MASK_LO 0x000000FFUL
+
+/* Recv complete */
+#define XEL_RSR_RECV_DONE_MASK 0x00000001UL
+/* Recv interrupt enable bit */
+#define XEL_RSR_RECV_IE_MASK 0x00000008UL
+
+struct xemaclite {
+ u32 nexttxbuffertouse; /* Next TX buffer to write to */
+ u32 nextrxbuffertouse; /* Next RX buffer to read from */
+ u32 txpp; /* TX ping pong buffer */
+ u32 rxpp; /* RX ping pong buffer */
+};
+
+static u32 etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
+
+static void xemaclite_alignedread(u32 *srcptr, void *destptr, u32 bytecount)
+{
+ u32 i;
+ u32 alignbuffer;
+ u32 *to32ptr;
+ u32 *from32ptr;
+ u8 *to8ptr;
+ u8 *from8ptr;
+
+ from32ptr = (u32 *) srcptr;
+
+ /* Word aligned buffer, no correction needed. */
+ to32ptr = (u32 *) destptr;
+ while (bytecount > 3) {
+ *to32ptr++ = *from32ptr++;
+ bytecount -= 4;
+ }
+ to8ptr = (u8 *) to32ptr;
+
+ alignbuffer = *from32ptr++;
+ from8ptr = (u8 *) &alignbuffer;
+
+ for (i = 0; i < bytecount; i++)
+ *to8ptr++ = *from8ptr++;
+}
+
+static void xemaclite_alignedwrite(void *srcptr, u32 destptr, u32 bytecount)
+{
+ u32 i;
+ u32 alignbuffer;
+ u32 *to32ptr = (u32 *) destptr;
+ u32 *from32ptr;
+ u8 *to8ptr;
+ u8 *from8ptr;
+
+ from32ptr = (u32 *) srcptr;
+ while (bytecount > 3) {
+
+ *to32ptr++ = *from32ptr++;
+ bytecount -= 4;
+ }
+
+ alignbuffer = 0;
+ to8ptr = (u8 *) &alignbuffer;
+ from8ptr = (u8 *) from32ptr;
+
+ for (i = 0; i < bytecount; i++)
+ *to8ptr++ = *from8ptr++;
+
+ *to32ptr++ = alignbuffer;
+}
+
+static void emaclite_halt(struct eth_device *dev)
+{
+ debug("eth_halt\n");
+}
+
+static int emaclite_init(struct eth_device *dev, bd_t *bis)
+{
+ struct xemaclite *emaclite = dev->priv;
+ debug("EmacLite Initialization Started\n");
+
+/*
+ * TX - TX_PING & TX_PONG initialization
+ */
+ /* Restart PING TX */
+ out_be32 (dev->iobase + XEL_TSR_OFFSET, 0);
+ /* Copy MAC address */
+ xemaclite_alignedwrite(dev->enetaddr, dev->iobase, ENET_ADDR_LENGTH);
+ /* Set the length */
+ out_be32 (dev->iobase + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
+ /* Update the MAC address in the EMAC Lite */
+ out_be32 (dev->iobase + XEL_TSR_OFFSET, XEL_TSR_PROG_MAC_ADDR);
+ /* Wait for EMAC Lite to finish with the MAC address update */
+ while ((in_be32 (dev->iobase + XEL_TSR_OFFSET) &
+ XEL_TSR_PROG_MAC_ADDR) != 0)
+ ;
+
+ if (emaclite->txpp) {
+ /* The same operation with PONG TX */
+ out_be32 (dev->iobase + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0);
+ xemaclite_alignedwrite(dev->enetaddr, dev->iobase +
+ XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH);
+ out_be32 (dev->iobase + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
+ out_be32 (dev->iobase + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET,
+ XEL_TSR_PROG_MAC_ADDR);
+ while ((in_be32 (dev->iobase + XEL_TSR_OFFSET +
+ XEL_BUFFER_OFFSET) & XEL_TSR_PROG_MAC_ADDR) != 0)
+ ;
+ }
+
+/*
+ * RX - RX_PING & RX_PONG initialization
+ */
+ /* Write out the value to flush the RX buffer */
+ out_be32 (dev->iobase + XEL_RSR_OFFSET, XEL_RSR_RECV_IE_MASK);
+
+ if (emaclite->rxpp)
+ out_be32 (dev->iobase + XEL_RSR_OFFSET + XEL_BUFFER_OFFSET,
+ XEL_RSR_RECV_IE_MASK);
+
+ debug("EmacLite Initialization complete\n");
+ return 0;
+}
+
+static int xemaclite_txbufferavailable(struct eth_device *dev)
+{
+ u32 reg;
+ u32 txpingbusy;
+ u32 txpongbusy;
+ struct xemaclite *emaclite = dev->priv;
+
+ /*
+ * Read the other buffer register
+ * and determine if the other buffer is available
+ */
+ reg = in_be32 (dev->iobase +
+ emaclite->nexttxbuffertouse + 0);
+ txpingbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) ==
+ XEL_TSR_XMIT_BUSY_MASK);
+
+ reg = in_be32 (dev->iobase +
+ (emaclite->nexttxbuffertouse ^ XEL_TSR_OFFSET) + 0);
+ txpongbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) ==
+ XEL_TSR_XMIT_BUSY_MASK);
+
+ return !(txpingbusy && txpongbusy);
+}
+
+static int emaclite_send(struct eth_device *dev, void *ptr, int len)
+{
+ u32 reg;
+ u32 baseaddress;
+ struct xemaclite *emaclite = dev->priv;
+
+ u32 maxtry = 1000;
+
+ if (len > PKTSIZE)
+ len = PKTSIZE;
+
+ while (!xemaclite_txbufferavailable(dev) && maxtry) {
+ udelay(10);
+ maxtry--;
+ }
+
+ if (!maxtry) {
+ printf("Error: Timeout waiting for ethernet TX buffer\n");
+ /* Restart PING TX */
+ out_be32 (dev->iobase + XEL_TSR_OFFSET, 0);
+ if (emaclite->txpp) {
+ out_be32 (dev->iobase + XEL_TSR_OFFSET +
+ XEL_BUFFER_OFFSET, 0);
+ }
+ return -1;
+ }
+
+ /* Determine the expected TX buffer address */
+ baseaddress = (dev->iobase + emaclite->nexttxbuffertouse);
+
+ /* Determine if the expected buffer address is empty */
+ reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
+ if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0)
+ && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET)
+ & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
+
+ if (emaclite->txpp)
+ emaclite->nexttxbuffertouse ^= XEL_BUFFER_OFFSET;
+
+ debug("Send packet from 0x%x\n", baseaddress);
+ /* Write the frame to the buffer */
+ xemaclite_alignedwrite(ptr, baseaddress, len);
+ out_be32 (baseaddress + XEL_TPLR_OFFSET,(len &
+ (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)));
+ reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
+ reg |= XEL_TSR_XMIT_BUSY_MASK;
+ if ((reg & XEL_TSR_XMIT_IE_MASK) != 0)
+ reg |= XEL_TSR_XMIT_ACTIVE_MASK;
+ out_be32 (baseaddress + XEL_TSR_OFFSET, reg);
+ return 0;
+ }
+
+ if (emaclite->txpp) {
+ /* Switch to second buffer */
+ baseaddress ^= XEL_BUFFER_OFFSET;
+ /* Determine if the expected buffer address is empty */
+ reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
+ if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0)
+ && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET)
+ & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
+ debug("Send packet from 0x%x\n", baseaddress);
+ /* Write the frame to the buffer */
+ xemaclite_alignedwrite(ptr, baseaddress, len);
+ out_be32 (baseaddress + XEL_TPLR_OFFSET, (len &
+ (XEL_TPLR_LENGTH_MASK_HI |
+ XEL_TPLR_LENGTH_MASK_LO)));
+ reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
+ reg |= XEL_TSR_XMIT_BUSY_MASK;
+ if ((reg & XEL_TSR_XMIT_IE_MASK) != 0)
+ reg |= XEL_TSR_XMIT_ACTIVE_MASK;
+ out_be32 (baseaddress + XEL_TSR_OFFSET, reg);
+ return 0;
+ }
+ }
+
+ puts("Error while sending frame\n");
+ return -1;
+}
+
+static int emaclite_recv(struct eth_device *dev)
+{
+ u32 length;
+ u32 reg;
+ u32 baseaddress;
+ struct xemaclite *emaclite = dev->priv;
+
+ baseaddress = dev->iobase + emaclite->nextrxbuffertouse;
+ reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
+ debug("Testing data at address 0x%x\n", baseaddress);
+ if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
+ if (emaclite->rxpp)
+ emaclite->nextrxbuffertouse ^= XEL_BUFFER_OFFSET;
+ } else {
+
+ if (!emaclite->rxpp) {
+ debug("No data was available - address 0x%x\n",
+ baseaddress);
+ return 0;
+ } else {
+ baseaddress ^= XEL_BUFFER_OFFSET;
+ reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
+ if ((reg & XEL_RSR_RECV_DONE_MASK) !=
+ XEL_RSR_RECV_DONE_MASK) {
+ debug("No data was available - address 0x%x\n",
+ baseaddress);
+ return 0;
+ }
+ }
+ }
+ /* Get the length of the frame that arrived */
+ switch(((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0xC))) &
+ 0xFFFF0000 ) >> 16) {
+ case 0x806:
+ length = 42 + 20; /* FIXME size of ARP */
+ debug("ARP Packet\n");
+ break;
+ case 0x800:
+ length = 14 + 14 +
+ (((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET +
+ 0x10))) & 0xFFFF0000) >> 16);
+ /* FIXME size of IP packet */
+ debug ("IP Packet\n");
+ break;
+ default:
+ debug("Other Packet\n");
+ length = PKTSIZE;
+ break;
+ }
+
+ xemaclite_alignedread((u32 *) (baseaddress + XEL_RXBUFF_OFFSET),
+ etherrxbuff, length);
+
+ /* Acknowledge the frame */
+ reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
+ reg &= ~XEL_RSR_RECV_DONE_MASK;
+ out_be32 (baseaddress + XEL_RSR_OFFSET, reg);
+
+ debug("Packet receive from 0x%x, length %dB\n", baseaddress, length);
+ NetReceive((uchar *) etherrxbuff, length);
+ return length;
+
+}
+
+int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr,
+ int txpp, int rxpp)
+{
+ struct eth_device *dev;
+ struct xemaclite *emaclite;
+
+ dev = calloc(1, sizeof(*dev));
+ if (dev == NULL)
+ return -1;
+
+ emaclite = calloc(1, sizeof(struct xemaclite));
+ if (emaclite == NULL) {
+ free(dev);
+ return -1;
+ }
+
+ dev->priv = emaclite;
+
+ emaclite->txpp = txpp;
+ emaclite->rxpp = rxpp;
+
+ sprintf(dev->name, "Xelite.%lx", base_addr);
+
+ dev->iobase = base_addr;
+ dev->init = emaclite_init;
+ dev->halt = emaclite_halt;
+ dev->send = emaclite_send;
+ dev->recv = emaclite_recv;
+
+ eth_register(dev);
+
+ return 1;
+}
+
+#ifdef CONFIG_OF_CONTROL
+int xilinx_emaclite_of_init(const void *blob)
+{
+ int offset = 0;
+ u32 ret = 0;
+ u32 reg;
+
+ do {
+ offset = fdt_node_offset_by_compatible(blob, offset,
+ "xlnx,xps-ethernetlite-1.00.a");
+ if (offset != -1) {
+ reg = fdtdec_get_addr(blob, offset, "reg");
+ if (reg != FDT_ADDR_T_NONE) {
+ u32 rxpp = fdtdec_get_int(blob, offset,
+ "xlnx,rx-ping-pong", 0);
+ u32 txpp = fdtdec_get_int(blob, offset,
+ "xlnx,tx-ping-pong", 0);
+ ret |= xilinx_emaclite_initialize(NULL, reg,
+ txpp, rxpp);
+ } else {
+ debug("EMACLITE: Can't get base address\n");
+ return -1;
+ }
+ }
+ } while (offset != -1);
+
+ return ret;
+}
+#endif
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_ll_temac.c b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac.c
new file mode 100644
index 000000000..dab78d073
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac.c
@@ -0,0 +1,402 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * supports SDMA or FIFO access and MDIO bus communication
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]: [0]/ip_documentation/xps_ll_temac.pdf
+ * [A]: [0]/application_notes/xapp1041.pdf
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <netdev.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <miiphy.h>
+
+#include "xilinx_ll_temac.h"
+#include "xilinx_ll_temac_fifo.h"
+#include "xilinx_ll_temac_sdma.h"
+#include "xilinx_ll_temac_mdio.h"
+
+#if !defined(CONFIG_MII)
+# error "LL_TEMAC requires MII -- missing CONFIG_MII"
+#endif
+
+#if !defined(CONFIG_PHYLIB)
+# error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB"
+#endif
+
+struct ll_temac_info {
+ int flags;
+ unsigned long base_addr;
+ unsigned long ctrl_addr;
+ char *devname;
+ unsigned int phyaddr;
+ char *mdio_busname;
+};
+
+/* Ethernet interface ready status */
+int ll_temac_check_status(struct temac_reg *regs, u32 mask)
+{
+ unsigned timeout = 50; /* 1usec * 50 = 50usec */
+
+ /*
+ * Quote from LL TEMAC documentation: The bits in the RDY
+ * register are asserted when there is no access in progress.
+ * When an access is in progress, a bit corresponding to the
+ * type of access is automatically de-asserted. The bit is
+ * automatically re-asserted when the access is complete.
+ */
+ while (timeout && (!(in_be32(&regs->rdy) & mask))) {
+ timeout--;
+ udelay(1);
+ }
+
+ if (!timeout) {
+ printf("%s: Timeout on 0x%08x @%p\n", __func__,
+ mask, &regs->rdy);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Indirect write to ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 23, second paragraph, The use of CTL0 register or CTL1 register
+ */
+int ll_temac_indirect_set(struct temac_reg *regs, u16 regn, u32 reg_data)
+{
+ out_be32(&regs->lsw, (reg_data & MLSW_MASK));
+ out_be32(&regs->ctl, CTL_WEN | (regn & CTL_ADDR_MASK));
+
+ if (ll_temac_check_status(regs, RSE_CFG_WR))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Indirect read from ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 23, second paragraph, The use of CTL0 register or CTL1 register
+ */
+int ll_temac_indirect_get(struct temac_reg *regs, u16 regn, u32* reg_data)
+{
+ out_be32(&regs->ctl, (regn & CTL_ADDR_MASK));
+
+ if (ll_temac_check_status(regs, RSE_CFG_RR))
+ return 0;
+
+ *reg_data = in_be32(&regs->lsw) & MLSW_MASK;
+ return 1;
+}
+
+/* setting sub-controller and ll_temac to proper setting */
+static int ll_temac_setup_ctrl(struct eth_device *dev)
+{
+ struct ll_temac *ll_temac = dev->priv;
+ struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+
+ if (ll_temac->ctrlreset && ll_temac->ctrlreset(dev))
+ return 0;
+
+ if (ll_temac->ctrlinit && ll_temac->ctrlinit(dev))
+ return 0;
+
+ /* Promiscuous mode disable */
+ if (!ll_temac_indirect_set(regs, TEMAC_AFM, 0))
+ return 0;
+
+ /* Enable Receiver - RX bit */
+ if (!ll_temac_indirect_set(regs, TEMAC_RCW1, RCW1_RX))
+ return 0;
+
+ /* Enable Transmitter - TX bit */
+ if (!ll_temac_indirect_set(regs, TEMAC_TC, TC_TX))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Configure ll_temac based on negotiated speed and duplex
+ * reported by PHY handling code
+ */
+static int ll_temac_adjust_link(struct eth_device *dev)
+{
+ unsigned int speed, emmc_reg;
+ struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+ struct ll_temac *ll_temac = dev->priv;
+ struct phy_device *phydev = ll_temac->phydev;
+
+ if (!phydev->link) {
+ printf("%s: No link.\n", phydev->dev->name);
+ return 0;
+ }
+
+ switch (phydev->speed) {
+ case 1000:
+ speed = EMMC_LSPD_1000;
+ break;
+ case 100:
+ speed = EMMC_LSPD_100;
+ break;
+ case 10:
+ speed = EMMC_LSPD_10;
+ break;
+ default:
+ return 0;
+ }
+
+ if (!ll_temac_indirect_get(regs, TEMAC_EMMC, &emmc_reg))
+ return 0;
+
+ emmc_reg &= ~EMMC_LSPD_MASK;
+ emmc_reg |= speed;
+
+ if (!ll_temac_indirect_set(regs, TEMAC_EMMC, emmc_reg))
+ return 0;
+
+ printf("%s: PHY is %s with %dbase%s, %s%s\n",
+ dev->name, phydev->drv->name,
+ phydev->speed, (phydev->port == PORT_TP) ? "T" : "X",
+ (phydev->duplex) ? "FDX" : "HDX",
+ (phydev->port == PORT_OTHER) ? ", unkown mode" : "");
+
+ return 1;
+}
+
+/* setup mac addr */
+static int ll_temac_setup_mac_addr(struct eth_device *dev)
+{
+ struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+ u32 val;
+
+ /* set up unicast MAC address filter */
+ val = ((dev->enetaddr[3] << 24) | (dev->enetaddr[2] << 16) |
+ (dev->enetaddr[1] << 8) | (dev->enetaddr[0]));
+ val &= UAW0_UADDR_MASK;
+
+ if (!ll_temac_indirect_set(regs, TEMAC_UAW0, val))
+ return 1;
+
+ val = ((dev->enetaddr[5] << 8) | dev->enetaddr[4]);
+ val &= UAW1_UADDR_MASK;
+
+ if (!ll_temac_indirect_set(regs, TEMAC_UAW1, val))
+ return 1;
+
+ return 0;
+}
+
+/* halt device */
+static void ll_temac_halt(struct eth_device *dev)
+{
+ struct ll_temac *ll_temac = dev->priv;
+ struct temac_reg *regs = (struct temac_reg *)dev->iobase;
+
+ /* Disable Receiver */
+ ll_temac_indirect_set(regs, TEMAC_RCW0, 0);
+
+ /* Disable Transmitter */
+ ll_temac_indirect_set(regs, TEMAC_TC, 0);
+
+ if (ll_temac->ctrlhalt)
+ ll_temac->ctrlhalt(dev);
+
+ /* Shut down the PHY, as needed */
+ phy_shutdown(ll_temac->phydev);
+}
+
+static int ll_temac_init(struct eth_device *dev, bd_t *bis)
+{
+ struct ll_temac *ll_temac = dev->priv;
+ int ret;
+
+ printf("%s: Xilinx XPS LocalLink Tri-Mode Ether MAC #%d at 0x%08X.\n",
+ dev->name, dev->index, dev->iobase);
+
+ if (!ll_temac_setup_ctrl(dev))
+ return -1;
+
+ /* Start up the PHY */
+ ret = phy_startup(ll_temac->phydev);
+ if (ret) {
+ printf("%s: Could not initialize PHY %s\n",
+ dev->name, ll_temac->phydev->dev->name);
+ return ret;
+ }
+
+ if (!ll_temac_adjust_link(dev)) {
+ ll_temac_halt(dev);
+ return -1;
+ }
+
+ /* If there's no link, fail */
+ return ll_temac->phydev->link ? 0 : -1;
+}
+
+/*
+ * Discover which PHY is attached to the device, and configure it
+ * properly. If the PHY is not recognized, then return 0
+ * (failure). Otherwise, return 1
+ */
+static int ll_temac_phy_init(struct eth_device *dev)
+{
+ struct ll_temac *ll_temac = dev->priv;
+ struct phy_device *phydev;
+ unsigned int supported = PHY_GBIT_FEATURES;
+
+ /* interface - look at driver/net/tsec.c */
+ phydev = phy_connect(ll_temac->bus, ll_temac->phyaddr,
+ dev, PHY_INTERFACE_MODE_NONE);
+
+ phydev->supported &= supported;
+ phydev->advertising = phydev->supported;
+
+ ll_temac->phydev = phydev;
+
+ phy_config(phydev);
+
+ return 1;
+}
+
+/*
+ * Initialize a single ll_temac devices
+ *
+ * Returns the result of ll_temac phy interface that were initialized
+ */
+int xilinx_ll_temac_initialize(bd_t *bis, struct ll_temac_info *devinf)
+{
+ struct eth_device *dev;
+ struct ll_temac *ll_temac;
+
+ dev = calloc(1, sizeof(*dev));
+ if (dev == NULL)
+ return 0;
+
+ ll_temac = calloc(1, sizeof(struct ll_temac));
+ if (ll_temac == NULL) {
+ free(dev);
+ return 0;
+ }
+
+ /* use given name or generate its own unique name */
+ if (devinf->devname) {
+ strncpy(dev->name, devinf->devname, sizeof(dev->name));
+ } else {
+ snprintf(dev->name, sizeof(dev->name), "lltemac.%lx", devinf->base_addr);
+ devinf->devname = dev->name;
+ }
+
+ dev->iobase = devinf->base_addr;
+
+ dev->priv = ll_temac;
+ dev->init = ll_temac_init;
+ dev->halt = ll_temac_halt;
+ dev->write_hwaddr = ll_temac_setup_mac_addr;
+
+ ll_temac->ctrladdr = devinf->ctrl_addr;
+ if (devinf->flags & XILINX_LL_TEMAC_M_SDMA_PLB) {
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+ if (devinf->flags & XILINX_LL_TEMAC_M_SDMA_DCR) {
+ ll_temac_collect_xldcr_sdma_reg_addr(dev);
+ ll_temac->in32 = ll_temac_xldcr_in32;
+ ll_temac->out32 = ll_temac_xldcr_out32;
+ } else
+#endif
+ {
+ ll_temac_collect_xlplb_sdma_reg_addr(dev);
+ ll_temac->in32 = ll_temac_xlplb_in32;
+ ll_temac->out32 = ll_temac_xlplb_out32;
+ }
+ ll_temac->ctrlinit = ll_temac_init_sdma;
+ ll_temac->ctrlhalt = ll_temac_halt_sdma;
+ ll_temac->ctrlreset = ll_temac_reset_sdma;
+ dev->recv = ll_temac_recv_sdma;
+ dev->send = ll_temac_send_sdma;
+ } else {
+ ll_temac->in32 = NULL;
+ ll_temac->out32 = NULL;
+ ll_temac->ctrlinit = NULL;
+ ll_temac->ctrlhalt = NULL;
+ ll_temac->ctrlreset = ll_temac_reset_fifo;
+ dev->recv = ll_temac_recv_fifo;
+ dev->send = ll_temac_send_fifo;
+ }
+
+ /* Link to specified MDIO bus */
+ strncpy(ll_temac->mdio_busname, devinf->mdio_busname, MDIO_NAME_LEN);
+ ll_temac->bus = miiphy_get_dev_by_name(ll_temac->mdio_busname);
+
+ /* Looking for a valid PHY address if it is not yet set */
+ if (devinf->phyaddr == -1)
+ ll_temac->phyaddr = ll_temac_phy_addr(ll_temac->bus);
+ else
+ ll_temac->phyaddr = devinf->phyaddr;
+
+ eth_register(dev);
+
+ /* Try to initialize PHY here, and return */
+ return ll_temac_phy_init(dev);
+}
+
+/*
+ * Initialize a single ll_temac device with its mdio bus behind ll_temac
+ *
+ * Returns 1 if the ll_temac device and the mdio bus were initialized
+ * otherwise returns 0
+ */
+int xilinx_ll_temac_eth_init(bd_t *bis, unsigned long base_addr, int flags,
+ unsigned long ctrl_addr)
+{
+ struct ll_temac_info devinf;
+ struct ll_temac_mdio_info mdioinf;
+ int ret;
+
+ /* prepare the internal driver informations */
+ devinf.flags = flags;
+ devinf.base_addr = base_addr;
+ devinf.ctrl_addr = ctrl_addr;
+ devinf.devname = NULL;
+ devinf.phyaddr = -1;
+
+ mdioinf.name = devinf.mdio_busname = NULL;
+ mdioinf.regs = (struct temac_reg *)devinf.base_addr;
+
+ ret = xilinx_ll_temac_mdio_initialize(bis, &mdioinf);
+ if (ret >= 0) {
+
+ /*
+ * If there was no MDIO bus name then take over the
+ * new automaticaly generated by the MDIO init code.
+ */
+ if (mdioinf.name != devinf.mdio_busname)
+ devinf.mdio_busname = mdioinf.name;
+
+ ret = xilinx_ll_temac_initialize(bis, &devinf);
+ if (ret > 0)
+ return 1;
+
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_ll_temac.h b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac.h
new file mode 100644
index 000000000..56362ba20
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac.h
@@ -0,0 +1,307 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * LL_TEMAC interface
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]: [0]/ip_documentation/xps_ll_temac.pdf
+ * [A]: [0]/application_notes/xapp1041.pdf
+ */
+#ifndef _XILINX_LL_TEMAC_
+#define _XILINX_LL_TEMAC_
+
+#include <config.h>
+#include <net.h>
+#include <phy.h>
+#include <miiphy.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#include "xilinx_ll_temac_sdma.h"
+
+#if !defined(__BIG_ENDIAN)
+# error LL_TEMAC requires big endianess
+#endif
+
+/*
+ * TEMAC Memory and Register Definition
+ *
+ * [1]: [0]/ip_documentation/xps_ll_temac.pdf
+ * page 19, Memory and Register Descriptions
+ */
+struct temac_reg {
+ /* direct soft registers (low part) */
+ u32 raf; /* Reset and Address Filter */
+ u32 tpf; /* Transmit Pause Frame */
+ u32 ifgp; /* Transmit Inter Frame Gap Adjustment */
+ u32 is; /* Interrupt Status */
+ u32 ip; /* Interrupt Pending */
+ u32 ie; /* Interrupt Enable */
+ u32 ttag; /* Transmit VLAN Tag */
+ u32 rtag; /* Receive VLAN Tag */
+ /* hard TEMAC registers */
+ u32 msw; /* Most Significant Word Data */
+ u32 lsw; /* Least Significant Word Data */
+ u32 ctl; /* Control */
+ u32 rdy; /* Ready Status */
+ /* direct soft registers (high part) */
+ u32 uawl; /* Unicast Address Word Lower */
+ u32 uawu; /* Unicast Address Word Upper */
+ u32 tpid0; /* VLAN TPID Word 0 */
+ u32 tpid1; /* VLAN TPID Word 1 */
+};
+
+/* Reset and Address Filter Registers (raf), [1] p25 */
+#define RAF_SR (1 << 13)
+#define RAF_EMFE (1 << 12)
+#define RAF_NFE (1 << 11)
+#define RAF_RVSTM_POS 9
+#define RAF_RVSTM_MASK (3 << RAF_RVSTM_POS)
+#define RAF_TVSTM_POS 7
+#define RAF_TVSTM_MASK (3 << RAF_TVSTM_POS)
+#define RAF_RVTM_POS 5
+#define RAF_RVTM_MASK (3 << RAF_RVTM_POS)
+#define RAF_TVTM_POS 3
+#define RAF_TVTM_MASK (3 << RAF_TVTM_POS)
+#define RAF_BCREJ (1 << 2)
+#define RAF_MCREJ (1 << 1)
+#define RAF_HTRST (1 << 0)
+
+/* Transmit Pause Frame Registers (tpf), [1] p28 */
+#define TPF_TPFV_POS 0
+#define TPF_TPFV_MASK (0xFFFF << TPF_TPFV_POS)
+
+/* Transmit Inter Frame Gap Adjustment Registers (ifgp), [1] p28 */
+#define IFGP_POS 0
+#define IFGP_MASK (0xFF << IFGP_POS)
+
+/* Interrupt Status, Pending, Enable Registers (is, ip, ie), [1] p29-33 */
+#define ISPE_MR (1 << 7)
+#define ISPE_RDL (1 << 6)
+#define ISPE_TC (1 << 5)
+#define ISPE_RFO (1 << 4)
+#define ISPE_RR (1 << 3)
+#define ISPE_RC (1 << 2)
+#define ISPE_AN (1 << 1)
+#define ISPE_HAC (1 << 0)
+
+/* Transmit, Receive VLAN Tag Registers (ttag, rtag), [1] p34-35 */
+#define TRTAG_TPID_POS 16
+#define TRTAG_TPID_MASK (0xFFFF << TRTAG_TPID_POS)
+#define TRTAG_PRIO_POS 13
+#define TRTAG_PRIO_MASK (7 << TRTAG_PRIO_POS)
+#define TRTAG_CFI (1 << 12)
+#define TRTAG_VID_POS 0
+#define TRTAG_VID_MASK (0xFFF << TRTAG_VID_POS)
+
+/* Most, Least Significant Word Data Register (msw, lsw), [1] p46 */
+#define MLSW_POS 0
+#define MLSW_MASK (~0UL << MLSW_POS)
+
+/* LSW Data Register for PHY addresses (lsw), [1] p66 */
+#define LSW_REGAD_POS 0
+#define LSW_REGAD_MASK (0x1F << LSW_REGAD_POS)
+#define LSW_PHYAD_POS 5
+#define LSW_PHYAD_MASK (0x1F << LSW_PHYAD_POS)
+
+/* LSW Data Register for PHY data (lsw), [1] p66 */
+#define LSW_REGDAT_POS 0
+#define LSW_REGDAT_MASK (0xFFFF << LSW_REGDAT_POS)
+
+/* Control Register (ctl), [1] p47 */
+#define CTL_WEN (1 << 15)
+#define CTL_ADDR_POS 0
+#define CTL_ADDR_MASK (0x3FF << CTL_ADDR_POS)
+
+/* Ready Status Register Ethernet (rdy), [1] p48 */
+#define RSE_HACS_RDY (1 << 14)
+#define RSE_CFG_WR (1 << 6)
+#define RSE_CFG_RR (1 << 5)
+#define RSE_AF_WR (1 << 4)
+#define RSE_AF_RR (1 << 3)
+#define RSE_MIIM_WR (1 << 2)
+#define RSE_MIIM_RR (1 << 1)
+#define RSE_FABR_RR (1 << 0)
+
+/* Unicast Address Word Lower, Upper Registers (uawl, uawu), [1] p35-36 */
+#define UAWL_UADDR_POS 0
+#define UAWL_UADDR_MASK (~0UL << UAWL_UADDR_POS)
+#define UAWU_UADDR_POS 0
+#define UAWU_UADDR_MASK (0xFFFF << UAWU_UADDR_POS)
+
+/* VLAN TPID Word 0, 1 Registers (tpid0, tpid1), [1] p37 */
+#define TPID0_V0_POS 0
+#define TPID0_V0_MASK (0xFFFF << TPID0_V0_POS)
+#define TPID0_V1_POS 16
+#define TPID0_V1_MASK (0xFFFF << TPID0_V1_POS)
+#define TPID1_V2_POS 0
+#define TPID1_V2_MASK (0xFFFF << TPID1_V2_POS)
+#define TPID1_V3_POS 16
+#define TPID1_V3_MASK (0xFFFF << TPID1_V3_POS)
+
+/*
+ * TEMAC Indirectly Addressable Register Index Enumeration
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [1]: [0]/ip_documentation/xps_ll_temac.pdf
+ * page 23, PLB Indirectly Addressable TEMAC Registers
+ */
+enum temac_ctrl {
+ TEMAC_RCW0 = 0x200,
+ TEMAC_RCW1 = 0x240,
+ TEMAC_TC = 0x280,
+ TEMAC_FCC = 0x2C0,
+ TEMAC_EMMC = 0x300,
+ TEMAC_PHYC = 0x320,
+ TEMAC_MC = 0x340,
+ TEMAC_UAW0 = 0x380,
+ TEMAC_UAW1 = 0x384,
+ TEMAC_MAW0 = 0x388,
+ TEMAC_MAW1 = 0x38C,
+ TEMAC_AFM = 0x390,
+ TEMAC_TIS = 0x3A0,
+ TEMAC_TIE = 0x3A4,
+ TEMAC_MIIMWD = 0x3B0,
+ TEMAC_MIIMAI = 0x3B4
+};
+
+/* Receive Configuration Word 0, 1 Registers (RCW0, RCW1), [1] p50-51 */
+#define RCW0_PADDR_POS 0
+#define RCW0_PADDR_MASK (~0UL << RCW_PADDR_POS)
+#define RCW1_RST (1 << 31)
+#define RCW1_JUM (1 << 30)
+#define RCW1_FCS (1 << 29)
+#define RCW1_RX (1 << 28)
+#define RCW1_VLAN (1 << 27)
+#define RCW1_HD (1 << 26)
+#define RCW1_LT_DIS (1 << 25)
+#define RCW1_PADDR_POS 0
+#define RCW1_PADDR_MASK (0xFFFF << RCW_PADDR_POS)
+
+/* Transmit Configuration Registers (TC), [1] p52 */
+#define TC_RST (1 << 31)
+#define TC_JUM (1 << 30)
+#define TC_FCS (1 << 29)
+#define TC_TX (1 << 28)
+#define TC_VLAN (1 << 27)
+#define TC_HD (1 << 26)
+#define TC_IFG (1 << 25)
+
+/* Flow Control Configuration Registers (FCC), [1] p54 */
+#define FCC_FCTX (1 << 30)
+#define FCC_FCRX (1 << 29)
+
+/* Ethernet MAC Mode Configuration Registers (EMMC), [1] p54 */
+#define EMMC_LSPD_POS 30
+#define EMMC_LSPD_MASK (3 << EMMC_LSPD_POS)
+#define EMMC_LSPD_1000 (2 << EMMC_LSPD_POS)
+#define EMMC_LSPD_100 (1 << EMMC_LSPD_POS)
+#define EMMC_LSPD_10 0
+#define EMMC_RGMII (1 << 29)
+#define EMMC_SGMII (1 << 28)
+#define EMMC_GPCS (1 << 27)
+#define EMMC_HOST (1 << 26)
+#define EMMC_TX16 (1 << 25)
+#define EMMC_RX16 (1 << 24)
+
+/* RGMII/SGMII Configuration Registers (PHYC), [1] p56 */
+#define PHYC_SLSPD_POS 30
+#define PHYC_SLSPD_MASK (3 << EMMC_SLSPD_POS)
+#define PHYC_SLSPD_1000 (2 << EMMC_SLSPD_POS)
+#define PHYC_SLSPD_100 (1 << EMMC_SLSPD_POS)
+#define PHYC_SLSPD_10 0
+#define PHYC_RLSPD_POS 2
+#define PHYC_RLSPD_MASK (3 << EMMC_RLSPD_POS)
+#define PHYC_RLSPD_1000 (2 << EMMC_RLSPD_POS)
+#define PHYC_RLSPD_100 (1 << EMMC_RLSPD_POS)
+#define PHYC_RLSPD_10 0
+#define PHYC_RGMII_HD (1 << 1)
+#define PHYC_RGMII_LINK (1 << 0)
+
+/* Management Configuration Registers (MC), [1] p57 */
+#define MC_MDIOEN (1 << 6)
+#define MC_CLKDIV_POS 0
+#define MC_CLKDIV_MASK (0x3F << MC_CLKDIV_POS)
+
+/*
+ * fHOSTCLK fMDC = fHOSTCLK
+ * fMDC = ------------------- ---------> MC_CLKDIV = -------- - 1
+ * (1 + MC_CLKDIV) * 2 2.5 MHz 5MHz
+ */
+#define MC_CLKDIV(f, m) ((f / (2 * m)) - 1)
+#define MC_CLKDIV_25(f) MC_CLKDIV(f, 2500000)
+#define MC_CLKDIV_20(f) MC_CLKDIV(f, 2000000)
+#define MC_CLKDIV_15(f) MC_CLKDIV(f, 1500000)
+#define MC_CLKDIV_10(f) MC_CLKDIV(f, 1000000)
+
+/* Unicast Address Word 0, 1 Registers (UAW0, UAW1), [1] p58-59 */
+#define UAW0_UADDR_POS 0
+#define UAW0_UADDR_MASK (~0UL << UAW0_UADDR_POS)
+#define UAW1_UADDR_POS 0
+#define UAW1_UADDR_MASK (0xFFFF << UAW1_UADDR_POS)
+
+/* Multicast Address Word 0, 1 Registers (MAW0, MAW1), [1] p60 */
+#define MAW0_MADDR_POS 0
+#define MAW0_MADDR_MASK (~0UL << MAW0_MADDR_POS)
+#define MAW1_RNW (1 << 23)
+#define MAW1_MAIDX_POS 16
+#define MAW1_MAIDX_MASK (3 << MAW1_MAIDX_POS)
+#define MAW1_MADDR_POS 0
+#define MAW1_MADDR_MASK (0xFFFF << MAW1_MADDR_POS)
+
+/* Address Filter Mode Registers (AFM), [1] p63 */
+#define AFM_PM (1 << 31)
+
+/* Interrupt Status, Enable Registers (TIS, TIE), [1] p63-65 */
+#define TISE_CFG_W (1 << 6)
+#define TISE_CFG_R (1 << 5)
+#define TISE_AF_W (1 << 4)
+#define TISE_AF_R (1 << 3)
+#define TISE_MIIM_W (1 << 2)
+#define TISE_MIIM_R (1 << 1)
+#define TISE_FABR_R (1 << 0)
+
+/* MII Management Write Data Registers (MIIMWD), [1] p66 */
+#define MIIMWD_DATA_POS 0
+#define MIIMWD_DATA_MASK (0xFFFF << MIIMWD_DATA_POS)
+
+/* Ethernet interface ready status */
+int ll_temac_check_status(struct temac_reg *regs, u32 mask);
+
+/* Indirect write to ll_temac. */
+int ll_temac_indirect_set(struct temac_reg *regs, u16 regn, u32 reg_data);
+
+/* Indirect read from ll_temac. */
+int ll_temac_indirect_get(struct temac_reg *regs, u16 regn, u32* reg_data);
+
+struct ll_temac {
+ phys_addr_t ctrladdr;
+ phys_addr_t sdma_reg_addr[SDMA_CTRL_REGNUMS];
+
+ unsigned (*in32)(phys_addr_t);
+ void (*out32)(phys_addr_t, unsigned);
+
+ int (*ctrlinit) (struct eth_device *);
+ int (*ctrlhalt) (struct eth_device *);
+ int (*ctrlreset) (struct eth_device *);
+
+ int phyaddr;
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+ char mdio_busname[MDIO_NAME_LEN];
+};
+
+#endif /* _XILINX_LL_TEMAC_ */
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_fifo.c b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_fifo.c
new file mode 100644
index 000000000..b8993cdb2
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_fifo.c
@@ -0,0 +1,139 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * FIFO sub-controller
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * CREDITS: tsec driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [F]: [0]/ip_documentation/xps_ll_fifo.pdf
+ * [S]: [0]/ip_documentation/xps_ll_temac.pdf
+ * [A]: [0]/application_notes/xapp1041.pdf
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include "xilinx_ll_temac.h"
+#include "xilinx_ll_temac_fifo.h"
+
+int ll_temac_reset_fifo(struct eth_device *dev)
+{
+ struct ll_temac *ll_temac = dev->priv;
+ struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+
+ out_be32(&fifo_ctrl->tdfr, LL_FIFO_TDFR_KEY);
+ out_be32(&fifo_ctrl->rdfr, LL_FIFO_RDFR_KEY);
+ out_be32(&fifo_ctrl->isr, ~0UL);
+ out_be32(&fifo_ctrl->ier, 0);
+
+ return 0;
+}
+
+int ll_temac_recv_fifo(struct eth_device *dev)
+{
+ int i, length = 0;
+ u32 *buf = (u32 *)NetRxPackets[0];
+ struct ll_temac *ll_temac = dev->priv;
+ struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+
+ if (in_be32(&fifo_ctrl->isr) & LL_FIFO_ISR_RC) {
+
+ /* reset isr */
+ out_be32(&fifo_ctrl->isr, ~0UL);
+
+ /*
+ * MAYBE here:
+ * while (fifo_ctrl->isr);
+ */
+
+ /*
+ * The length is written (into RLR) by the XPS LL FIFO
+ * when the packet is received across the RX LocalLink
+ * interface and the receive data FIFO had enough
+ * locations that all of the packet data has been saved.
+ * The RLR should only be read when a receive packet is
+ * available for processing (the receive occupancy is
+ * not zero). Once the RLR is read, the receive packet
+ * data should be read from the receive data FIFO before
+ * the RLR is read again.
+ *
+ * [F] page 17, Receive Length Register (RLR)
+ */
+ if (in_be32(&fifo_ctrl->rdfo) & LL_FIFO_RDFO_MASK) {
+ length = in_be32(&fifo_ctrl->rlf) & LL_FIFO_RLF_MASK;
+ } else {
+ printf("%s: Got error, no receive occupancy\n",
+ __func__);
+ return -1;
+ }
+
+ if (length > PKTSIZE_ALIGN) {
+ printf("%s: Got error, receive package too big (%i)\n",
+ __func__, length);
+ ll_temac_reset_fifo(dev);
+ return -1;
+ }
+
+ for (i = 0; i < length; i += 4)
+ *buf++ = in_be32(&fifo_ctrl->rdfd);
+
+ NetReceive(NetRxPackets[0], length);
+ }
+
+ return 0;
+}
+
+int ll_temac_send_fifo(struct eth_device *dev, void *packet, int length)
+{
+ int i;
+ u32 *buf = (u32 *)packet;
+ struct ll_temac *ll_temac = dev->priv;
+ struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
+
+ if (length < LL_FIFO_TLF_MIN) {
+ printf("%s: Got error, transmit package too small (%i)\n",
+ __func__, length);
+ return -1;
+ }
+
+ if (length > LL_FIFO_TLF_MAX) {
+ printf("%s: Got error, transmit package too big (%i)\n",
+ __func__, length);
+ return -1;
+ }
+
+ for (i = 0; i < length; i += 4)
+ out_be32(&fifo_ctrl->tdfd, *buf++);
+
+ /*
+ * Once the packet length is written to the TLR it is
+ * automatically moved to the transmit data FIFO with
+ * the packet data freeing up the TLR for another value.
+ * The packet length must be written to the TLR after
+ * the packet data is written to the transmit data FIFO.
+ * It is not valid to write data for multiple packets
+ * to the transmit data FIFO before writing the packet
+ * length values.
+ *
+ * [F] page 17, Transmit Length Register (TLR)
+ */
+ out_be32(&fifo_ctrl->tlf, length);
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_fifo.h b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_fifo.h
new file mode 100644
index 000000000..c1bf7cc64
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_fifo.h
@@ -0,0 +1,118 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * FIFO sub-controller interface
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]: [0]/ip_documentation/xps_ll_temac.pdf
+ * [A]: [0]/application_notes/xapp1041.pdf
+ */
+#ifndef _XILINX_LL_TEMAC_FIFO_
+#define _XILINX_LL_TEMAC_FIFO_
+
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#if !defined(__BIG_ENDIAN)
+# error LL_TEMAC requires big endianess
+#endif
+
+/*
+ * FIFO Register Definition
+ *
+ * Used for memory mapped access from and to (Rd/Td) the LocalLink (LL)
+ * Tri-Mode Ether MAC (TEMAC) via the 2 kb full duplex FIFO Controller,
+ * one for each.
+ *
+ * [1]: [0]/ip_documentation/xps_ll_fifo.pdf
+ * page 10, Registers Definition
+ */
+struct fifo_ctrl {
+ u32 isr; /* Interrupt Status Register (RW) */
+ u32 ier; /* Interrupt Enable Register (RW) */
+ u32 tdfr; /* Transmit Data FIFO Reset (WO) */
+ u32 tdfv; /* Transmit Data FIFO Vacancy (RO) */
+ u32 tdfd; /* Transmit Data FIFO 32bit wide Data write port (WO) */
+ u32 tlf; /* Transmit Length FIFO (WO) */
+ u32 rdfr; /* Receive Data FIFO Reset (WO) */
+ u32 rdfo; /* Receive Data FIFO Occupancy (RO) */
+ u32 rdfd; /* Receive Data FIFO 32bit wide Data read port (RO) */
+ u32 rlf; /* Receive Length FIFO (RO) */
+ u32 llr; /* LocalLink Reset (WO) */
+};
+
+/* Interrupt Status Register (ISR), [1] p11 */
+#define LL_FIFO_ISR_RPURE (1 << 31) /* Receive Packet Underrun Read Err */
+#define LL_FIFO_ISR_RPORE (1 << 30) /* Receive Packet Overrun Read Err */
+#define LL_FIFO_ISR_RPUE (1 << 29) /* Receive Packet Underrun Error */
+#define LL_FIFO_ISR_TPOE (1 << 28) /* Transmit Packet Overrun Error */
+#define LL_FIFO_ISR_TC (1 << 27) /* Transmit Complete */
+#define LL_FIFO_ISR_RC (1 << 26) /* Receive Complete */
+#define LL_FIFO_ISR_TSE (1 << 25) /* Transmit Size Error */
+#define LL_FIFO_ISR_TRC (1 << 24) /* Transmit Reset Complete */
+#define LL_FIFO_ISR_RRC (1 << 23) /* Receive Reset Complete */
+
+/* Interrupt Enable Register (IER), [1] p12/p13 */
+#define LL_FIFO_IER_RPURE (1 << 31) /* Receive Packet Underrun Read Err */
+#define LL_FIFO_IER_RPORE (1 << 30) /* Receive Packet Overrun Read Err */
+#define LL_FIFO_IER_RPUE (1 << 29) /* Receive Packet Underrun Error */
+#define LL_FIFO_IER_TPOE (1 << 28) /* Transmit Packet Overrun Error */
+#define LL_FIFO_IER_TC (1 << 27) /* Transmit Complete */
+#define LL_FIFO_IER_RC (1 << 26) /* Receive Complete */
+#define LL_FIFO_IER_TSE (1 << 25) /* Transmit Size Error */
+#define LL_FIFO_IER_TRC (1 << 24) /* Transmit Reset Complete */
+#define LL_FIFO_IER_RRC (1 << 23) /* Receive Reset Complete */
+
+/* Transmit Data FIFO Reset (TDFR), [1] p13/p14 */
+#define LL_FIFO_TDFR_KEY 0x000000A5UL
+
+/* Transmit Data FIFO Vacancy (TDFV), [1] p14 */
+#define LL_FIFO_TDFV_POS 0
+#define LL_FIFO_TDFV_MASK (0x000001FFUL << LL_FIFO_TDFV_POS)
+
+/* Transmit Length FIFO (TLF), [1] p16/p17 */
+#define LL_FIFO_TLF_POS 0
+#define LL_FIFO_TLF_MASK (0x000007FFUL << LL_FIFO_TLF_POS)
+#define LL_FIFO_TLF_MIN ((4 * sizeof(u32)) & LL_FIFO_TLF_MASK)
+#define LL_FIFO_TLF_MAX ((510 * sizeof(u32)) & LL_FIFO_TLF_MASK)
+
+/* Receive Data FIFO Reset (RDFR), [1] p15 */
+#define LL_FIFO_RDFR_KEY 0x000000A5UL
+
+/* Receive Data FIFO Occupancy (RDFO), [1] p16 */
+#define LL_FIFO_RDFO_POS 0
+#define LL_FIFO_RDFO_MASK (0x000001FFUL << LL_FIFO_RDFO_POS)
+
+/* Receive Length FIFO (RLF), [1] p17/p18 */
+#define LL_FIFO_RLF_POS 0
+#define LL_FIFO_RLF_MASK (0x000007FFUL << LL_FIFO_RLF_POS)
+#define LL_FIFO_RLF_MIN ((4 * sizeof(uint32)) & LL_FIFO_RLF_MASK)
+#define LL_FIFO_RLF_MAX ((510 * sizeof(uint32)) & LL_FIFO_RLF_MASK)
+
+/* LocalLink Reset (LLR), [1] p18 */
+#define LL_FIFO_LLR_KEY 0x000000A5UL
+
+
+/* reset FIFO and IRQ, disable interrupts */
+int ll_temac_reset_fifo(struct eth_device *dev);
+
+/* receive buffered data from FIFO (polling ISR) */
+int ll_temac_recv_fifo(struct eth_device *dev);
+
+/* send buffered data to FIFO */
+int ll_temac_send_fifo(struct eth_device *dev, void *packet, int length);
+
+#endif /* _XILINX_LL_TEMAC_FIFO_ */
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_mdio.c b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_mdio.c
new file mode 100644
index 000000000..b7bab794e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_mdio.c
@@ -0,0 +1,177 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * MDIO bus access
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * CREDITS: tsec driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]: [0]/ip_documentation/xps_ll_temac.pdf
+ * [A]: [0]/application_notes/xapp1041.pdf
+ */
+
+#include <config.h>
+#include <common.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#include "xilinx_ll_temac.h"
+#include "xilinx_ll_temac_mdio.h"
+
+#if !defined(CONFIG_MII)
+# error "LL_TEMAC requires MII -- missing CONFIG_MII"
+#endif
+
+#if !defined(CONFIG_PHYLIB)
+# error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB"
+#endif
+
+/*
+ * Prior to PHY access, the MDIO clock must be setup. This driver will set a
+ * safe default that should work with PLB bus speeds of up to 150 MHz and keep
+ * the MDIO clock below 2.5 MHz. If the user wishes faster access to the PHY
+ * then the clock divisor can be set to a different value by setting the
+ * correct bus speed value with CONFIG_XILINX_LL_TEMAC_CLK.
+ */
+#if !defined(CONFIG_XILINX_LL_TEMAC_CLK)
+#define MDIO_CLOCK_DIV MC_CLKDIV_10(150000000)
+#else
+#define MDIO_CLOCK_DIV MC_CLKDIV_25(CONFIG_XILINX_LL_TEMAC_CLK)
+#endif
+
+static int ll_temac_mdio_setup(struct mii_dev *bus)
+{
+ struct temac_reg *regs = (struct temac_reg *)bus->priv;
+
+ /* setup MDIO clock */
+ ll_temac_indirect_set(regs, TEMAC_MC,
+ MC_MDIOEN | (MDIO_CLOCK_DIV & MC_CLKDIV_MASK));
+
+ return 0;
+}
+
+/*
+ * Indirect MII PHY read via ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 67, Using the MII Management to Access PHY Registers
+ */
+int ll_temac_local_mdio_read(struct temac_reg *regs, int addr, int devad,
+ int regnum)
+{
+ out_be32(&regs->lsw,
+ ((addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
+ (regnum & LSW_REGAD_MASK));
+ out_be32(&regs->ctl, TEMAC_MIIMAI);
+
+ ll_temac_check_status(regs, RSE_MIIM_RR);
+
+ return in_be32(&regs->lsw) & LSW_REGDAT_MASK;
+}
+
+/*
+ * Indirect MII PHY write via ll_temac.
+ *
+ * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
+ * page 67, Using the MII Management to Access PHY Registers
+ */
+void ll_temac_local_mdio_write(struct temac_reg *regs, int addr, int devad,
+ int regnum, u16 value)
+{
+ out_be32(&regs->lsw, (value & LSW_REGDAT_MASK));
+ out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMWD);
+
+ out_be32(&regs->lsw,
+ ((addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
+ (regnum & LSW_REGAD_MASK));
+ out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMAI);
+
+ ll_temac_check_status(regs, RSE_MIIM_WR);
+}
+
+int ll_temac_phy_read(struct mii_dev *bus, int addr, int devad, int regnum)
+{
+ struct temac_reg *regs = (struct temac_reg *)bus->priv;
+
+ return ll_temac_local_mdio_read(regs, addr, devad, regnum);
+}
+
+int ll_temac_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
+ u16 value)
+{
+ struct temac_reg *regs = (struct temac_reg *)bus->priv;
+
+ ll_temac_local_mdio_write(regs, addr, devad, regnum, value);
+
+ return 0;
+}
+
+/*
+ * Use MII register 1 (MII status register) to detect PHY
+ *
+ * A Mask used to verify certain PHY features (register content)
+ * in the PHY detection register:
+ * Auto-negotiation support, 10Mbps half/full duplex support
+ */
+#define PHY_DETECT_REG MII_BMSR
+#define PHY_DETECT_MASK (BMSR_10FULL | BMSR_10HALF | BMSR_ANEGCAPABLE)
+
+/* Looking for a valid PHY address */
+int ll_temac_phy_addr(struct mii_dev *bus)
+{
+ struct temac_reg *regs = (struct temac_reg *)bus->priv;
+ unsigned short val;
+ unsigned int phy;
+
+ for (phy = PHY_MAX_ADDR; phy >= 0; phy--) {
+ val = ll_temac_local_mdio_read(regs, phy, 0, PHY_DETECT_REG);
+ if ((val != 0xFFFF) &&
+ ((val & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
+ /* Found a valid PHY address */
+ return phy;
+ }
+ }
+
+ return -1;
+}
+
+int xilinx_ll_temac_mdio_initialize(bd_t *bis, struct ll_temac_mdio_info *info)
+{
+ struct mii_dev *bus = mdio_alloc();
+
+ if (!bus) {
+ printf("Failed to allocate LL_TEMAC MDIO bus: %s\n",
+ info->name);
+ return -1;
+ }
+
+ bus->read = ll_temac_phy_read;
+ bus->write = ll_temac_phy_write;
+ bus->reset = NULL;
+
+ /* use given name or generate its own unique name */
+ if (info->name) {
+ strncpy(bus->name, info->name, MDIO_NAME_LEN);
+ } else {
+ snprintf(bus->name, MDIO_NAME_LEN, "lltemii.%p", info->regs);
+ info->name = bus->name;
+ }
+
+ bus->priv = info->regs;
+
+ ll_temac_mdio_setup(bus);
+ return mdio_register(bus);
+}
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_mdio.h b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_mdio.h
new file mode 100644
index 000000000..0603c6445
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_mdio.h
@@ -0,0 +1,50 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * MDIO bus access interface
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]: [0]/ip_documentation/xps_ll_temac.pdf
+ * [A]: [0]/application_notes/xapp1041.pdf
+ */
+#ifndef _XILINX_LL_TEMAC_MDIO_
+#define _XILINX_LL_TEMAC_MDIO_
+
+#include <net.h>
+#include <miiphy.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#include "xilinx_ll_temac.h"
+
+int ll_temac_local_mdio_read(struct temac_reg *regs, int addr, int devad,
+ int regnum);
+void ll_temac_local_mdio_write(struct temac_reg *regs, int addr, int devad,
+ int regnum, u16 value);
+
+int ll_temac_phy_read(struct mii_dev *bus, int addr, int devad, int regnum);
+int ll_temac_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
+ u16 value);
+
+int ll_temac_phy_addr(struct mii_dev *bus);
+
+struct ll_temac_mdio_info {
+ struct temac_reg *regs;
+ char *name;
+};
+
+int xilinx_ll_temac_mdio_initialize(bd_t *bis, struct ll_temac_mdio_info *info);
+
+#endif /* _XILINX_LL_TEMAC_MDIO_ */
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_sdma.c b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_sdma.c
new file mode 100644
index 000000000..32a822eea
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_sdma.c
@@ -0,0 +1,366 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * SDMA sub-controller
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * CREDITS: tsec driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [M]: [0]/ip_documentation/mpmc.pdf
+ * [S]: [0]/ip_documentation/xps_ll_temac.pdf
+ * [A]: [0]/application_notes/xapp1041.pdf
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include "xilinx_ll_temac.h"
+#include "xilinx_ll_temac_sdma.h"
+
+#define TX_BUF_CNT 2
+
+static unsigned int rx_idx; /* index of the current RX buffer */
+static unsigned int tx_idx; /* index of the current TX buffer */
+
+struct rtx_cdmac_bd {
+ struct cdmac_bd rx[PKTBUFSRX];
+ struct cdmac_bd tx[TX_BUF_CNT];
+};
+
+/*
+ * DMA Buffer Descriptor alignment
+ *
+ * If the address contained in the Next Descriptor Pointer register is not
+ * 8-word aligned or reaches beyond the range of available memory, the SDMA
+ * halts processing and sets the CDMAC_BD_STCTRL_ERROR bit in the respective
+ * status register (tx_chnl_sts or rx_chnl_sts).
+ *
+ * [1]: [0]/ip_documentation/mpmc.pdf
+ * page 161, Next Descriptor Pointer
+ */
+static struct rtx_cdmac_bd cdmac_bd __aligned(32);
+
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+
+/*
+ * Indirect DCR access operations mi{ft}dcr_xilinx() espacialy
+ * for Xilinx PowerPC implementations on FPGA.
+ *
+ * FIXME: This part should go up to arch/powerpc -- but where?
+ */
+#include <asm/processor.h>
+#define XILINX_INDIRECT_DCR_ADDRESS_REG 0
+#define XILINX_INDIRECT_DCR_ACCESS_REG 1
+inline unsigned mifdcr_xilinx(const unsigned dcrn)
+{
+ mtdcr(XILINX_INDIRECT_DCR_ADDRESS_REG, dcrn);
+ return mfdcr(XILINX_INDIRECT_DCR_ACCESS_REG);
+}
+inline void mitdcr_xilinx(const unsigned dcrn, int val)
+{
+ mtdcr(XILINX_INDIRECT_DCR_ADDRESS_REG, dcrn);
+ mtdcr(XILINX_INDIRECT_DCR_ACCESS_REG, val);
+}
+
+/* Xilinx Device Control Register (DCR) in/out accessors */
+inline unsigned ll_temac_xldcr_in32(phys_addr_t addr)
+{
+ return mifdcr_xilinx((const unsigned)addr);
+}
+inline void ll_temac_xldcr_out32(phys_addr_t addr, unsigned value)
+{
+ mitdcr_xilinx((const unsigned)addr, value);
+}
+
+void ll_temac_collect_xldcr_sdma_reg_addr(struct eth_device *dev)
+{
+ struct ll_temac *ll_temac = dev->priv;
+ phys_addr_t dmac_ctrl = ll_temac->ctrladdr;
+ phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+ ra[TX_NXTDESC_PTR] = dmac_ctrl + TX_NXTDESC_PTR;
+ ra[TX_CURBUF_ADDR] = dmac_ctrl + TX_CURBUF_ADDR;
+ ra[TX_CURBUF_LENGTH] = dmac_ctrl + TX_CURBUF_LENGTH;
+ ra[TX_CURDESC_PTR] = dmac_ctrl + TX_CURDESC_PTR;
+ ra[TX_TAILDESC_PTR] = dmac_ctrl + TX_TAILDESC_PTR;
+ ra[TX_CHNL_CTRL] = dmac_ctrl + TX_CHNL_CTRL;
+ ra[TX_IRQ_REG] = dmac_ctrl + TX_IRQ_REG;
+ ra[TX_CHNL_STS] = dmac_ctrl + TX_CHNL_STS;
+ ra[RX_NXTDESC_PTR] = dmac_ctrl + RX_NXTDESC_PTR;
+ ra[RX_CURBUF_ADDR] = dmac_ctrl + RX_CURBUF_ADDR;
+ ra[RX_CURBUF_LENGTH] = dmac_ctrl + RX_CURBUF_LENGTH;
+ ra[RX_CURDESC_PTR] = dmac_ctrl + RX_CURDESC_PTR;
+ ra[RX_TAILDESC_PTR] = dmac_ctrl + RX_TAILDESC_PTR;
+ ra[RX_CHNL_CTRL] = dmac_ctrl + RX_CHNL_CTRL;
+ ra[RX_IRQ_REG] = dmac_ctrl + RX_IRQ_REG;
+ ra[RX_CHNL_STS] = dmac_ctrl + RX_CHNL_STS;
+ ra[DMA_CONTROL_REG] = dmac_ctrl + DMA_CONTROL_REG;
+}
+
+#endif /* CONFIG_XILINX_440 || ONFIG_XILINX_405 */
+
+/* Xilinx Processor Local Bus (PLB) in/out accessors */
+inline unsigned ll_temac_xlplb_in32(phys_addr_t addr)
+{
+ return in_be32((void *)addr);
+}
+inline void ll_temac_xlplb_out32(phys_addr_t addr, unsigned value)
+{
+ out_be32((void *)addr, value);
+}
+
+/* collect all register addresses for Xilinx PLB in/out accessors */
+void ll_temac_collect_xlplb_sdma_reg_addr(struct eth_device *dev)
+{
+ struct ll_temac *ll_temac = dev->priv;
+ struct sdma_ctrl *sdma_ctrl = (void *)ll_temac->ctrladdr;
+ phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+ ra[TX_NXTDESC_PTR] = (phys_addr_t)&sdma_ctrl->tx_nxtdesc_ptr;
+ ra[TX_CURBUF_ADDR] = (phys_addr_t)&sdma_ctrl->tx_curbuf_addr;
+ ra[TX_CURBUF_LENGTH] = (phys_addr_t)&sdma_ctrl->tx_curbuf_length;
+ ra[TX_CURDESC_PTR] = (phys_addr_t)&sdma_ctrl->tx_curdesc_ptr;
+ ra[TX_TAILDESC_PTR] = (phys_addr_t)&sdma_ctrl->tx_taildesc_ptr;
+ ra[TX_CHNL_CTRL] = (phys_addr_t)&sdma_ctrl->tx_chnl_ctrl;
+ ra[TX_IRQ_REG] = (phys_addr_t)&sdma_ctrl->tx_irq_reg;
+ ra[TX_CHNL_STS] = (phys_addr_t)&sdma_ctrl->tx_chnl_sts;
+ ra[RX_NXTDESC_PTR] = (phys_addr_t)&sdma_ctrl->rx_nxtdesc_ptr;
+ ra[RX_CURBUF_ADDR] = (phys_addr_t)&sdma_ctrl->rx_curbuf_addr;
+ ra[RX_CURBUF_LENGTH] = (phys_addr_t)&sdma_ctrl->rx_curbuf_length;
+ ra[RX_CURDESC_PTR] = (phys_addr_t)&sdma_ctrl->rx_curdesc_ptr;
+ ra[RX_TAILDESC_PTR] = (phys_addr_t)&sdma_ctrl->rx_taildesc_ptr;
+ ra[RX_CHNL_CTRL] = (phys_addr_t)&sdma_ctrl->rx_chnl_ctrl;
+ ra[RX_IRQ_REG] = (phys_addr_t)&sdma_ctrl->rx_irq_reg;
+ ra[RX_CHNL_STS] = (phys_addr_t)&sdma_ctrl->rx_chnl_sts;
+ ra[DMA_CONTROL_REG] = (phys_addr_t)&sdma_ctrl->dma_control_reg;
+}
+
+/* Check for TX and RX channel errors. */
+static inline int ll_temac_sdma_error(struct eth_device *dev)
+{
+ int err;
+ struct ll_temac *ll_temac = dev->priv;
+ phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+ err = ll_temac->in32(ra[TX_CHNL_STS]) & CHNL_STS_ERROR;
+ err |= ll_temac->in32(ra[RX_CHNL_STS]) & CHNL_STS_ERROR;
+
+ return err;
+}
+
+int ll_temac_init_sdma(struct eth_device *dev)
+{
+ struct ll_temac *ll_temac = dev->priv;
+ struct cdmac_bd *rx_dp;
+ struct cdmac_bd *tx_dp;
+ phys_addr_t *ra = ll_temac->sdma_reg_addr;
+ int i;
+
+ printf("%s: SDMA: %d Rx buffers, %d Tx buffers\n",
+ dev->name, PKTBUFSRX, TX_BUF_CNT);
+
+ /* Initialize the Rx Buffer descriptors */
+ for (i = 0; i < PKTBUFSRX; i++) {
+ rx_dp = &cdmac_bd.rx[i];
+ memset(rx_dp, 0, sizeof(*rx_dp));
+ rx_dp->next_p = rx_dp;
+ rx_dp->buf_len = PKTSIZE_ALIGN;
+ rx_dp->phys_buf_p = (u8 *)NetRxPackets[i];
+ flush_cache((u32)rx_dp->phys_buf_p, PKTSIZE_ALIGN);
+ }
+ flush_cache((u32)cdmac_bd.rx, sizeof(cdmac_bd.rx));
+
+ /* Initialize the TX Buffer Descriptors */
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ tx_dp = &cdmac_bd.tx[i];
+ memset(tx_dp, 0, sizeof(*tx_dp));
+ tx_dp->next_p = tx_dp;
+ }
+ flush_cache((u32)cdmac_bd.tx, sizeof(cdmac_bd.tx));
+
+ /* Reset index counter to the Rx and Tx Buffer descriptors */
+ rx_idx = tx_idx = 0;
+
+ /* initial Rx DMA start by writing to respective TAILDESC_PTR */
+ ll_temac->out32(ra[RX_CURDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
+ ll_temac->out32(ra[RX_TAILDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
+
+ return 0;
+}
+
+int ll_temac_halt_sdma(struct eth_device *dev)
+{
+ unsigned timeout = 50; /* 1usec * 50 = 50usec */
+ struct ll_temac *ll_temac = dev->priv;
+ phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+ /*
+ * Soft reset the DMA
+ *
+ * Quote from MPMC documentation: Writing a 1 to this field
+ * forces the DMA engine to shutdown and reset itself. After
+ * setting this bit, software must poll it until the bit is
+ * cleared by the DMA. This indicates that the reset process
+ * is done and the pipeline has been flushed.
+ */
+ ll_temac->out32(ra[DMA_CONTROL_REG], DMA_CONTROL_RESET);
+ while (timeout && (ll_temac->in32(ra[DMA_CONTROL_REG])
+ & DMA_CONTROL_RESET)) {
+ timeout--;
+ udelay(1);
+ }
+
+ if (!timeout) {
+ printf("%s: Timeout\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int ll_temac_reset_sdma(struct eth_device *dev)
+{
+ u32 r;
+ struct ll_temac *ll_temac = dev->priv;
+ phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+ /* Soft reset the DMA. */
+ if (ll_temac_halt_sdma(dev))
+ return -1;
+
+ /* Now clear the interrupts. */
+ r = ll_temac->in32(ra[TX_CHNL_CTRL]);
+ r &= ~CHNL_CTRL_IRQ_MASK;
+ ll_temac->out32(ra[TX_CHNL_CTRL], r);
+
+ r = ll_temac->in32(ra[RX_CHNL_CTRL]);
+ r &= ~CHNL_CTRL_IRQ_MASK;
+ ll_temac->out32(ra[RX_CHNL_CTRL], r);
+
+ /* Now ACK pending IRQs. */
+ ll_temac->out32(ra[TX_IRQ_REG], IRQ_REG_IRQ_MASK);
+ ll_temac->out32(ra[RX_IRQ_REG], IRQ_REG_IRQ_MASK);
+
+ /* Set tail-ptr mode, disable errors for both channels. */
+ ll_temac->out32(ra[DMA_CONTROL_REG],
+ /* Enable use of tail pointer register */
+ DMA_CONTROL_TPE |
+ /* Disable error when 2 or 4 bit coalesce cnt overfl */
+ DMA_CONTROL_RXOCEID |
+ /* Disable error when 2 or 4 bit coalesce cnt overfl */
+ DMA_CONTROL_TXOCEID);
+
+ return 0;
+}
+
+int ll_temac_recv_sdma(struct eth_device *dev)
+{
+ int length, pb_idx;
+ struct cdmac_bd *rx_dp = &cdmac_bd.rx[rx_idx];
+ struct ll_temac *ll_temac = dev->priv;
+ phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+ if (ll_temac_sdma_error(dev)) {
+
+ if (ll_temac_reset_sdma(dev))
+ return -1;
+
+ ll_temac_init_sdma(dev);
+ }
+
+ flush_cache((u32)rx_dp, sizeof(*rx_dp));
+
+ if (!(rx_dp->sca.stctrl & CDMAC_BD_STCTRL_COMPLETED))
+ return 0;
+
+ if (rx_dp->sca.stctrl & (CDMAC_BD_STCTRL_SOP | CDMAC_BD_STCTRL_EOP)) {
+ pb_idx = rx_idx;
+ length = rx_dp->sca.app[4] & CDMAC_BD_APP4_RXBYTECNT_MASK;
+ } else {
+ pb_idx = -1;
+ length = 0;
+ printf("%s: Got part of package, unsupported (%x)\n",
+ __func__, rx_dp->sca.stctrl);
+ }
+
+ /* flip the buffer */
+ flush_cache((u32)rx_dp->phys_buf_p, length);
+
+ /* reset the current descriptor */
+ rx_dp->sca.stctrl = 0;
+ rx_dp->sca.app[4] = 0;
+ flush_cache((u32)rx_dp, sizeof(*rx_dp));
+
+ /* Find next empty buffer descriptor, preparation for next iteration */
+ rx_idx = (rx_idx + 1) % PKTBUFSRX;
+ rx_dp = &cdmac_bd.rx[rx_idx];
+ flush_cache((u32)rx_dp, sizeof(*rx_dp));
+
+ /* DMA start by writing to respective TAILDESC_PTR */
+ ll_temac->out32(ra[RX_CURDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
+ ll_temac->out32(ra[RX_TAILDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
+
+ if (length > 0 && pb_idx != -1)
+ NetReceive(NetRxPackets[pb_idx], length);
+
+ return 0;
+}
+
+int ll_temac_send_sdma(struct eth_device *dev, void *packet, int length)
+{
+ unsigned timeout = 50; /* 1usec * 50 = 50usec */
+ struct cdmac_bd *tx_dp = &cdmac_bd.tx[tx_idx];
+ struct ll_temac *ll_temac = dev->priv;
+ phys_addr_t *ra = ll_temac->sdma_reg_addr;
+
+ if (ll_temac_sdma_error(dev)) {
+
+ if (ll_temac_reset_sdma(dev))
+ return -1;
+
+ ll_temac_init_sdma(dev);
+ }
+
+ tx_dp->phys_buf_p = (u8 *)packet;
+ tx_dp->buf_len = length;
+ tx_dp->sca.stctrl = CDMAC_BD_STCTRL_SOP | CDMAC_BD_STCTRL_EOP |
+ CDMAC_BD_STCTRL_STOP_ON_END;
+
+ flush_cache((u32)packet, length);
+ flush_cache((u32)tx_dp, sizeof(*tx_dp));
+
+ /* DMA start by writing to respective TAILDESC_PTR */
+ ll_temac->out32(ra[TX_CURDESC_PTR], (int)tx_dp);
+ ll_temac->out32(ra[TX_TAILDESC_PTR], (int)tx_dp);
+
+ /* Find next empty buffer descriptor, preparation for next iteration */
+ tx_idx = (tx_idx + 1) % TX_BUF_CNT;
+ tx_dp = &cdmac_bd.tx[tx_idx];
+
+ do {
+ flush_cache((u32)tx_dp, sizeof(*tx_dp));
+ udelay(1);
+ } while (timeout-- && !(tx_dp->sca.stctrl & CDMAC_BD_STCTRL_COMPLETED));
+
+ if (!timeout) {
+ printf("%s: Timeout\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_sdma.h b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_sdma.h
new file mode 100644
index 000000000..41659c0ee
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/xilinx_ll_temac_sdma.h
@@ -0,0 +1,277 @@
+/*
+ * Xilinx xps_ll_temac ethernet driver for u-boot
+ *
+ * SDMA sub-controller interface
+ *
+ * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008 - 2011 PetaLogix
+ *
+ * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
+ * Copyright (C) 2008 Nissin Systems Co.,Ltd.
+ * March 2008 created
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [S]: [0]/ip_documentation/xps_ll_temac.pdf
+ * [A]: [0]/application_notes/xapp1041.pdf
+ */
+#ifndef _XILINX_LL_TEMAC_SDMA_
+#define _XILINX_LL_TEMAC_SDMA_
+
+#include <net.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#include <linux/compiler.h>
+
+#if !defined(__BIG_ENDIAN)
+# error LL_TEMAC requires big endianess
+#endif
+
+/*
+ * DMA Buffer Descriptor for CDMAC
+ *
+ * Used for data connection from and to (Rx/Tx) the LocalLink (LL) TEMAC via
+ * the Communications Direct Memory Access Controller (CDMAC) -- one for each.
+ *
+ * overview:
+ * ftp://ftp.xilinx.com/pub/documentation/misc/mpmc_getting_started.pdf
+ *
+ * [1]: [0]/ip_documentation/mpmc.pdf
+ * page 140, DMA Operation Descriptors
+ *
+ * [2]: [0]/user_guides/ug200.pdf
+ * page 229, DMA Controller -- Descriptor Format
+ *
+ * [3]: [0]/ip_documentation/xps_ll_temac.pdf
+ * page 72, Transmit LocalLink Frame Format
+ * page 73, Receive LocalLink Frame Format
+ */
+struct cdmac_bd {
+ struct cdmac_bd *next_p; /* Next Descriptor Pointer */
+ u8 *phys_buf_p; /* Buffer Address */
+ u32 buf_len; /* Buffer Length */
+ union {
+ u8 stctrl; /* Status/Control the DMA transfer */
+ u32 app[5]; /* application specific data */
+ } __packed __aligned(1) sca;
+};
+
+/* CDMAC Descriptor Status and Control (stctrl), [1] p140, [2] p230 */
+#define CDMAC_BD_STCTRL_ERROR (1 << 7)
+#define CDMAC_BD_STCTRL_IRQ_ON_END (1 << 6)
+#define CDMAC_BD_STCTRL_STOP_ON_END (1 << 5)
+#define CDMAC_BD_STCTRL_COMPLETED (1 << 4)
+#define CDMAC_BD_STCTRL_SOP (1 << 3)
+#define CDMAC_BD_STCTRL_EOP (1 << 2)
+#define CDMAC_BD_STCTRL_DMACHBUSY (1 << 1)
+
+/* CDMAC Descriptor APP0: Transmit LocalLink Footer Word 3, [3] p72 */
+#define CDMAC_BD_APP0_TXCSCNTRL (1 << 0)
+
+/* CDMAC Descriptor APP1: Transmit LocalLink Footer Word 4, [3] p73 */
+#define CDMAC_BD_APP1_TXCSBEGIN_POS 16
+#define CDMAC_BD_APP1_TXCSBEGIN_MASK (0xFFFF << CDMAC_BD_APP1_TXCSBEGIN_POS)
+#define CDMAC_BD_APP1_TXCSINSERT_POS 0
+#define CDMAC_BD_APP1_TXCSINSERT_MASK (0xFFFF << CDMAC_BD_APP1_TXCSINSERT_POS)
+
+/* CDMAC Descriptor APP2: Transmit LocalLink Footer Word 5, [3] p73 */
+#define CDMAC_BD_APP2_TXCSINIT_POS 0
+#define CDMAC_BD_APP2_TXCSINIT_MASK (0xFFFF << CDMAC_BD_APP2_TXCSINIT_POS)
+
+/* CDMAC Descriptor APP0: Receive LocalLink Footer Word 3, [3] p73 */
+#define CDMAC_BD_APP0_MADDRU_POS 0
+#define CDMAC_BD_APP0_MADDRU_MASK (0xFFFF << CDMAC_BD_APP0_MADDRU_POS)
+
+/* CDMAC Descriptor APP1: Receive LocalLink Footer Word 4, [3] p74 */
+#define CDMAC_BD_APP1_MADDRL_POS 0
+#define CDMAC_BD_APP1_MADDRL_MASK (~0UL << CDMAC_BD_APP1_MADDRL_POS)
+
+/* CDMAC Descriptor APP2: Receive LocalLink Footer Word 5, [3] p74 */
+#define CDMAC_BD_APP2_BCAST_FRAME (1 << 2)
+#define CDMAC_BD_APP2_IPC_MCAST_FRAME (1 << 1)
+#define CDMAC_BD_APP2_MAC_MCAST_FRAME (1 << 0)
+
+/* CDMAC Descriptor APP3: Receive LocalLink Footer Word 6, [3] p74 */
+#define CDMAC_BD_APP3_TLTPID_POS 16
+#define CDMAC_BD_APP3_TLTPID_MASK (0xFFFF << CDMAC_BD_APP3_TLTPID_POS)
+#define CDMAC_BD_APP3_RXCSRAW_POS 0
+#define CDMAC_BD_APP3_RXCSRAW_MASK (0xFFFF << CDMAC_BD_APP3_RXCSRAW_POS)
+
+/* CDMAC Descriptor APP4: Receive LocalLink Footer Word 7, [3] p74 */
+#define CDMAC_BD_APP4_VLANTAG_POS 16
+#define CDMAC_BD_APP4_VLANTAG_MASK (0xFFFF << CDMAC_BD_APP4_VLANTAG_POS)
+#define CDMAC_BD_APP4_RXBYTECNT_POS 0
+#define CDMAC_BD_APP4_RXBYTECNT_MASK (0x3FFF << CDMAC_BD_APP4_RXBYTECNT_POS)
+
+/*
+ * SDMA Register Definition
+ *
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * [1]: [0]/ip_documentation/mpmc.pdf
+ * page 54, SDMA Register Summary
+ * page 160, SDMA Registers
+ *
+ * [2]: [0]/user_guides/ug200.pdf
+ * page 244, DMA Controller -- Programming Interface and Registers
+ */
+#define SDMA_CTRL_REGTYPE u32
+#define SDMA_CTRL_REGSIZE sizeof(SDMA_CTRL_REGTYPE)
+struct sdma_ctrl {
+ /* Transmit Registers */
+ SDMA_CTRL_REGTYPE tx_nxtdesc_ptr; /* TX Next Description Pointer */
+ SDMA_CTRL_REGTYPE tx_curbuf_addr; /* TX Current Buffer Address */
+ SDMA_CTRL_REGTYPE tx_curbuf_length; /* TX Current Buffer Length */
+ SDMA_CTRL_REGTYPE tx_curdesc_ptr; /* TX Current Descriptor Pointer */
+ SDMA_CTRL_REGTYPE tx_taildesc_ptr; /* TX Tail Descriptor Pointer */
+ SDMA_CTRL_REGTYPE tx_chnl_ctrl; /* TX Channel Control */
+ SDMA_CTRL_REGTYPE tx_irq_reg; /* TX Interrupt Register */
+ SDMA_CTRL_REGTYPE tx_chnl_sts; /* TX Status Register */
+ /* Receive Registers */
+ SDMA_CTRL_REGTYPE rx_nxtdesc_ptr; /* RX Next Descriptor Pointer */
+ SDMA_CTRL_REGTYPE rx_curbuf_addr; /* RX Current Buffer Address */
+ SDMA_CTRL_REGTYPE rx_curbuf_length; /* RX Current Buffer Length */
+ SDMA_CTRL_REGTYPE rx_curdesc_ptr; /* RX Current Descriptor Pointer */
+ SDMA_CTRL_REGTYPE rx_taildesc_ptr; /* RX Tail Descriptor Pointer */
+ SDMA_CTRL_REGTYPE rx_chnl_ctrl; /* RX Channel Control */
+ SDMA_CTRL_REGTYPE rx_irq_reg; /* RX Interrupt Register */
+ SDMA_CTRL_REGTYPE rx_chnl_sts; /* RX Status Register */
+ /* Control Registers */
+ SDMA_CTRL_REGTYPE dma_control_reg; /* DMA Control Register */
+};
+
+#define SDMA_CTRL_REGNUMS sizeof(struct sdma_ctrl)/SDMA_CTRL_REGSIZE
+
+/*
+ * DMAC Register Index Enumeration
+ *
+ * [2]: http://www.xilinx.com/support/documentation/user_guides/ug200.pdf
+ * page 244, DMA Controller -- Programming Interface and Registers
+ */
+enum dmac_ctrl {
+ /* Transmit Registers */
+ TX_NXTDESC_PTR = 0, /* TX Next Description Pointer */
+ TX_CURBUF_ADDR, /* TX Current Buffer Address */
+ TX_CURBUF_LENGTH, /* TX Current Buffer Length */
+ TX_CURDESC_PTR, /* TX Current Descriptor Pointer */
+ TX_TAILDESC_PTR, /* TX Tail Descriptor Pointer */
+ TX_CHNL_CTRL, /* TX Channel Control */
+ TX_IRQ_REG, /* TX Interrupt Register */
+ TX_CHNL_STS, /* TX Status Register */
+ /* Receive Registers */
+ RX_NXTDESC_PTR, /* RX Next Descriptor Pointer */
+ RX_CURBUF_ADDR, /* RX Current Buffer Address */
+ RX_CURBUF_LENGTH, /* RX Current Buffer Length */
+ RX_CURDESC_PTR, /* RX Current Descriptor Pointer */
+ RX_TAILDESC_PTR, /* RX Tail Descriptor Pointer */
+ RX_CHNL_CTRL, /* RX Channel Control */
+ RX_IRQ_REG, /* RX Interrupt Register */
+ RX_CHNL_STS, /* RX Status Register */
+ /* Control Registers */
+ DMA_CONTROL_REG /* DMA Control Register */
+};
+
+/* Rx/Tx Channel Control Register (*_chnl_ctrl), [1] p163, [2] p246/p252 */
+#define CHNL_CTRL_ITO_POS 24
+#define CHNL_CTRL_ITO_MASK (0xFF << CHNL_CTRL_ITO_POS)
+#define CHNL_CTRL_IC_POS 16
+#define CHNL_CTRL_IC_MASK (0xFF << CHNL_CTRL_IC_POS)
+#define CHNL_CTRL_MSBADDR_POS 12
+#define CHNL_CTRL_MSBADDR_MASK (0xF << CHNL_CTRL_MSBADDR_POS)
+#define CHNL_CTRL_AME (1 << 11)
+#define CHNL_CTRL_OBWC (1 << 10)
+#define CHNL_CTRL_IOE (1 << 9)
+#define CHNL_CTRL_LIC (1 << 8)
+#define CHNL_CTRL_IE (1 << 7)
+#define CHNL_CTRL_IEE (1 << 2)
+#define CHNL_CTRL_IDE (1 << 1)
+#define CHNL_CTRL_ICE (1 << 0)
+
+/* All interrupt enable bits */
+#define CHNL_CTRL_IRQ_MASK (CHNL_CTRL_IE | \
+ CHNL_CTRL_IEE | \
+ CHNL_CTRL_IDE | \
+ CHNL_CTRL_ICE)
+
+/* Rx/Tx Interrupt Status Register (*_irq_reg), [1] p164, [2] p247/p253 */
+#define IRQ_REG_DTV_POS 24
+#define IRQ_REG_DTV_MASK (0xFF << IRQ_REG_DTV_POS)
+#define IRQ_REG_CCV_POS 16
+#define IRQ_REG_CCV_MASK (0xFF << IRQ_REG_CCV_POS)
+#define IRQ_REG_WRCQ_EMPTY (1 << 14)
+#define IRQ_REG_CIC_POS 10
+#define IRQ_REG_CIC_MASK (0xF << IRQ_REG_CIC_POS)
+#define IRQ_REG_DIC_POS 8
+#define IRQ_REG_DIC_MASK (3 << 8)
+#define IRQ_REG_PLB_RD_NMI (1 << 4)
+#define IRQ_REG_PLB_WR_NMI (1 << 3)
+#define IRQ_REG_EI (1 << 2)
+#define IRQ_REG_DI (1 << 1)
+#define IRQ_REG_CI (1 << 0)
+
+/* All interrupt bits */
+#define IRQ_REG_IRQ_MASK (IRQ_REG_PLB_RD_NMI | \
+ IRQ_REG_PLB_WR_NMI | \
+ IRQ_REG_EI | IRQ_REG_DI | IRQ_REG_CI)
+
+/* Rx/Tx Channel Status Register (*_chnl_sts), [1] p165, [2] p249/p255 */
+#define CHNL_STS_ERROR_TAIL (1 << 21)
+#define CHNL_STS_ERROR_CMP (1 << 20)
+#define CHNL_STS_ERROR_ADDR (1 << 19)
+#define CHNL_STS_ERROR_NXTP (1 << 18)
+#define CHNL_STS_ERROR_CURP (1 << 17)
+#define CHNL_STS_ERROR_BSYWR (1 << 16)
+#define CHNL_STS_ERROR (1 << 7)
+#define CHNL_STS_IOE (1 << 6)
+#define CHNL_STS_SOE (1 << 5)
+#define CHNL_STS_CMPLT (1 << 4)
+#define CHNL_STS_SOP (1 << 3)
+#define CHNL_STS_EOP (1 << 2)
+#define CHNL_STS_EBUSY (1 << 1)
+
+/* DMA Control Register (dma_control_reg), [1] p166, [2] p256 */
+#define DMA_CONTROL_PLBED (1 << 5)
+#define DMA_CONTROL_RXOCEID (1 << 4)
+#define DMA_CONTROL_TXOCEID (1 << 3)
+#define DMA_CONTROL_TPE (1 << 2)
+#define DMA_CONTROL_RESET (1 << 0)
+
+#if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405)
+
+/* Xilinx Device Control Register (DCR) in/out accessors */
+unsigned ll_temac_xldcr_in32(phys_addr_t addr);
+void ll_temac_xldcr_out32(phys_addr_t addr, unsigned value);
+
+/* collect all register addresses for Xilinx DCR in/out accessors */
+void ll_temac_collect_xldcr_sdma_reg_addr(struct eth_device *dev);
+
+#endif /* CONFIG_XILINX_440 || CONFIG_XILINX_405 */
+
+/* Xilinx Processor Local Bus (PLB) in/out accessors */
+unsigned ll_temac_xlplb_in32(phys_addr_t base);
+void ll_temac_xlplb_out32(phys_addr_t base, unsigned value);
+
+/* collect all register addresses for Xilinx PLB in/out accessors */
+void ll_temac_collect_xlplb_sdma_reg_addr(struct eth_device *dev);
+
+/* initialize both Rx/Tx buffer descriptors */
+int ll_temac_init_sdma(struct eth_device *dev);
+
+/* halt both Rx/Tx transfers */
+int ll_temac_halt_sdma(struct eth_device *dev);
+
+/* reset SDMA and IRQ, disable interrupts and errors */
+int ll_temac_reset_sdma(struct eth_device *dev);
+
+/* receive buffered data from SDMA (polling ISR) */
+int ll_temac_recv_sdma(struct eth_device *dev);
+
+/* send buffered data to SDMA */
+int ll_temac_send_sdma(struct eth_device *dev, void *packet, int length);
+
+#endif /* _XILINX_LL_TEMAC_SDMA_ */
diff --git a/qemu/roms/u-boot/drivers/net/zynq_gem.c b/qemu/roms/u-boot/drivers/net/zynq_gem.c
new file mode 100644
index 000000000..3cadd23bb
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/net/zynq_gem.c
@@ -0,0 +1,580 @@
+/*
+ * (C) Copyright 2011 Michal Simek
+ *
+ * Michal SIMEK <monstr@monstr.eu>
+ *
+ * Based on Xilinx gmac driver:
+ * (C) Copyright 2011 Xilinx
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <net.h>
+#include <netdev.h>
+#include <config.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <phy.h>
+#include <miiphy.h>
+#include <watchdog.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+
+#if !defined(CONFIG_PHYLIB)
+# error XILINX_GEM_ETHERNET requires PHYLIB
+#endif
+
+/* Bit/mask specification */
+#define ZYNQ_GEM_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */
+#define ZYNQ_GEM_PHYMNTNC_OP_R_MASK 0x20000000 /* read operation */
+#define ZYNQ_GEM_PHYMNTNC_OP_W_MASK 0x10000000 /* write operation */
+#define ZYNQ_GEM_PHYMNTNC_PHYAD_SHIFT_MASK 23 /* Shift bits for PHYAD */
+#define ZYNQ_GEM_PHYMNTNC_PHREG_SHIFT_MASK 18 /* Shift bits for PHREG */
+
+#define ZYNQ_GEM_RXBUF_EOF_MASK 0x00008000 /* End of frame. */
+#define ZYNQ_GEM_RXBUF_SOF_MASK 0x00004000 /* Start of frame. */
+#define ZYNQ_GEM_RXBUF_LEN_MASK 0x00003FFF /* Mask for length field */
+
+#define ZYNQ_GEM_RXBUF_WRAP_MASK 0x00000002 /* Wrap bit, last BD */
+#define ZYNQ_GEM_RXBUF_NEW_MASK 0x00000001 /* Used bit.. */
+#define ZYNQ_GEM_RXBUF_ADD_MASK 0xFFFFFFFC /* Mask for address */
+
+/* Wrap bit, last descriptor */
+#define ZYNQ_GEM_TXBUF_WRAP_MASK 0x40000000
+#define ZYNQ_GEM_TXBUF_LAST_MASK 0x00008000 /* Last buffer */
+
+#define ZYNQ_GEM_NWCTRL_TXEN_MASK 0x00000008 /* Enable transmit */
+#define ZYNQ_GEM_NWCTRL_RXEN_MASK 0x00000004 /* Enable receive */
+#define ZYNQ_GEM_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */
+#define ZYNQ_GEM_NWCTRL_STARTTX_MASK 0x00000200 /* Start tx (tx_go) */
+
+#define ZYNQ_GEM_NWCFG_SPEED100 0x000000001 /* 100 Mbps operation */
+#define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */
+#define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */
+#define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */
+#define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000080000 /* Div pclk by 32, 80MHz */
+#define ZYNQ_GEM_NWCFG_MDCCLKDIV2 0x0000c0000 /* Div pclk by 48, 120MHz */
+
+#define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_NWCFG_FDEN | \
+ ZYNQ_GEM_NWCFG_FSREM | \
+ ZYNQ_GEM_NWCFG_MDCCLKDIV)
+
+#define ZYNQ_GEM_NWSR_MDIOIDLE_MASK 0x00000004 /* PHY management idle */
+
+#define ZYNQ_GEM_DMACR_BLENGTH 0x00000004 /* INCR4 AHB bursts */
+/* Use full configured addressable space (8 Kb) */
+#define ZYNQ_GEM_DMACR_RXSIZE 0x00000300
+/* Use full configured addressable space (4 Kb) */
+#define ZYNQ_GEM_DMACR_TXSIZE 0x00000400
+/* Set with binary 00011000 to use 1536 byte(1*max length frame/buffer) */
+#define ZYNQ_GEM_DMACR_RXBUF 0x00180000
+
+#define ZYNQ_GEM_DMACR_INIT (ZYNQ_GEM_DMACR_BLENGTH | \
+ ZYNQ_GEM_DMACR_RXSIZE | \
+ ZYNQ_GEM_DMACR_TXSIZE | \
+ ZYNQ_GEM_DMACR_RXBUF)
+
+/* Use MII register 1 (MII status register) to detect PHY */
+#define PHY_DETECT_REG 1
+
+/* Mask used to verify certain PHY features (or register contents)
+ * in the register above:
+ * 0x1000: 10Mbps full duplex support
+ * 0x0800: 10Mbps half duplex support
+ * 0x0008: Auto-negotiation support
+ */
+#define PHY_DETECT_MASK 0x1808
+
+/* TX BD status masks */
+#define ZYNQ_GEM_TXBUF_FRMLEN_MASK 0x000007ff
+#define ZYNQ_GEM_TXBUF_EXHAUSTED 0x08000000
+#define ZYNQ_GEM_TXBUF_UNDERRUN 0x10000000
+
+/* Clock frequencies for different speeds */
+#define ZYNQ_GEM_FREQUENCY_10 2500000UL
+#define ZYNQ_GEM_FREQUENCY_100 25000000UL
+#define ZYNQ_GEM_FREQUENCY_1000 125000000UL
+
+/* Device registers */
+struct zynq_gem_regs {
+ u32 nwctrl; /* Network Control reg */
+ u32 nwcfg; /* Network Config reg */
+ u32 nwsr; /* Network Status reg */
+ u32 reserved1;
+ u32 dmacr; /* DMA Control reg */
+ u32 txsr; /* TX Status reg */
+ u32 rxqbase; /* RX Q Base address reg */
+ u32 txqbase; /* TX Q Base address reg */
+ u32 rxsr; /* RX Status reg */
+ u32 reserved2[2];
+ u32 idr; /* Interrupt Disable reg */
+ u32 reserved3;
+ u32 phymntnc; /* Phy Maintaince reg */
+ u32 reserved4[18];
+ u32 hashl; /* Hash Low address reg */
+ u32 hashh; /* Hash High address reg */
+#define LADDR_LOW 0
+#define LADDR_HIGH 1
+ u32 laddr[4][LADDR_HIGH + 1]; /* Specific1 addr low/high reg */
+ u32 match[4]; /* Type ID1 Match reg */
+ u32 reserved6[18];
+ u32 stat[44]; /* Octects transmitted Low reg - stat start */
+};
+
+/* BD descriptors */
+struct emac_bd {
+ u32 addr; /* Next descriptor pointer */
+ u32 status;
+};
+
+#define RX_BUF 3
+/* Page table entries are set to 1MB, or multiples of 1MB
+ * (not < 1MB). driver uses less bd's so use 1MB bdspace.
+ */
+#define BD_SPACE 0x100000
+/* BD separation space */
+#define BD_SEPRN_SPACE 64
+
+/* Initialized, rxbd_current, rx_first_buf must be 0 after init */
+struct zynq_gem_priv {
+ struct emac_bd *tx_bd;
+ struct emac_bd *rx_bd;
+ char *rxbuffers;
+ u32 rxbd_current;
+ u32 rx_first_buf;
+ int phyaddr;
+ u32 emio;
+ int init;
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+};
+
+static inline int mdio_wait(struct eth_device *dev)
+{
+ struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
+ u32 timeout = 200;
+
+ /* Wait till MDIO interface is ready to accept a new transaction. */
+ while (--timeout) {
+ if (readl(&regs->nwsr) & ZYNQ_GEM_NWSR_MDIOIDLE_MASK)
+ break;
+ WATCHDOG_RESET();
+ }
+
+ if (!timeout) {
+ printf("%s: Timeout\n", __func__);
+ return 1;
+ }
+
+ return 0;
+}
+
+static u32 phy_setup_op(struct eth_device *dev, u32 phy_addr, u32 regnum,
+ u32 op, u16 *data)
+{
+ u32 mgtcr;
+ struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
+
+ if (mdio_wait(dev))
+ return 1;
+
+ /* Construct mgtcr mask for the operation */
+ mgtcr = ZYNQ_GEM_PHYMNTNC_OP_MASK | op |
+ (phy_addr << ZYNQ_GEM_PHYMNTNC_PHYAD_SHIFT_MASK) |
+ (regnum << ZYNQ_GEM_PHYMNTNC_PHREG_SHIFT_MASK) | *data;
+
+ /* Write mgtcr and wait for completion */
+ writel(mgtcr, &regs->phymntnc);
+
+ if (mdio_wait(dev))
+ return 1;
+
+ if (op == ZYNQ_GEM_PHYMNTNC_OP_R_MASK)
+ *data = readl(&regs->phymntnc);
+
+ return 0;
+}
+
+static u32 phyread(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 *val)
+{
+ return phy_setup_op(dev, phy_addr, regnum,
+ ZYNQ_GEM_PHYMNTNC_OP_R_MASK, val);
+}
+
+static u32 phywrite(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 data)
+{
+ return phy_setup_op(dev, phy_addr, regnum,
+ ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data);
+}
+
+static void phy_detection(struct eth_device *dev)
+{
+ int i;
+ u16 phyreg;
+ struct zynq_gem_priv *priv = dev->priv;
+
+ if (priv->phyaddr != -1) {
+ phyread(dev, priv->phyaddr, PHY_DETECT_REG, &phyreg);
+ if ((phyreg != 0xFFFF) &&
+ ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
+ /* Found a valid PHY address */
+ debug("Default phy address %d is valid\n",
+ priv->phyaddr);
+ return;
+ } else {
+ debug("PHY address is not setup correctly %d\n",
+ priv->phyaddr);
+ priv->phyaddr = -1;
+ }
+ }
+
+ debug("detecting phy address\n");
+ if (priv->phyaddr == -1) {
+ /* detect the PHY address */
+ for (i = 31; i >= 0; i--) {
+ phyread(dev, i, PHY_DETECT_REG, &phyreg);
+ if ((phyreg != 0xFFFF) &&
+ ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
+ /* Found a valid PHY address */
+ priv->phyaddr = i;
+ debug("Found valid phy address, %d\n", i);
+ return;
+ }
+ }
+ }
+ printf("PHY is not detected\n");
+}
+
+static int zynq_gem_setup_mac(struct eth_device *dev)
+{
+ u32 i, macaddrlow, macaddrhigh;
+ struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
+
+ /* Set the MAC bits [31:0] in BOT */
+ macaddrlow = dev->enetaddr[0];
+ macaddrlow |= dev->enetaddr[1] << 8;
+ macaddrlow |= dev->enetaddr[2] << 16;
+ macaddrlow |= dev->enetaddr[3] << 24;
+
+ /* Set MAC bits [47:32] in TOP */
+ macaddrhigh = dev->enetaddr[4];
+ macaddrhigh |= dev->enetaddr[5] << 8;
+
+ for (i = 0; i < 4; i++) {
+ writel(0, &regs->laddr[i][LADDR_LOW]);
+ writel(0, &regs->laddr[i][LADDR_HIGH]);
+ /* Do not use MATCHx register */
+ writel(0, &regs->match[i]);
+ }
+
+ writel(macaddrlow, &regs->laddr[0][LADDR_LOW]);
+ writel(macaddrhigh, &regs->laddr[0][LADDR_HIGH]);
+
+ return 0;
+}
+
+static int zynq_gem_init(struct eth_device *dev, bd_t * bis)
+{
+ u32 i;
+ unsigned long clk_rate = 0;
+ struct phy_device *phydev;
+ const u32 stat_size = (sizeof(struct zynq_gem_regs) -
+ offsetof(struct zynq_gem_regs, stat)) / 4;
+ struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
+ struct zynq_gem_priv *priv = dev->priv;
+ const u32 supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full;
+
+ if (!priv->init) {
+ /* Disable all interrupts */
+ writel(0xFFFFFFFF, &regs->idr);
+
+ /* Disable the receiver & transmitter */
+ writel(0, &regs->nwctrl);
+ writel(0, &regs->txsr);
+ writel(0, &regs->rxsr);
+ writel(0, &regs->phymntnc);
+
+ /* Clear the Hash registers for the mac address
+ * pointed by AddressPtr
+ */
+ writel(0x0, &regs->hashl);
+ /* Write bits [63:32] in TOP */
+ writel(0x0, &regs->hashh);
+
+ /* Clear all counters */
+ for (i = 0; i <= stat_size; i++)
+ readl(&regs->stat[i]);
+
+ /* Setup RxBD space */
+ memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd));
+
+ for (i = 0; i < RX_BUF; i++) {
+ priv->rx_bd[i].status = 0xF0000000;
+ priv->rx_bd[i].addr =
+ ((u32)(priv->rxbuffers) +
+ (i * PKTSIZE_ALIGN));
+ }
+ /* WRAP bit to last BD */
+ priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK;
+ /* Write RxBDs to IP */
+ writel((u32)priv->rx_bd, &regs->rxqbase);
+
+ /* Setup for DMA Configuration register */
+ writel(ZYNQ_GEM_DMACR_INIT, &regs->dmacr);
+
+ /* Setup for Network Control register, MDIO, Rx and Tx enable */
+ setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
+
+ priv->init++;
+ }
+
+ phy_detection(dev);
+
+ /* interface - look at tsec */
+ phydev = phy_connect(priv->bus, priv->phyaddr, dev,
+ PHY_INTERFACE_MODE_MII);
+
+ phydev->supported = supported | ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause;
+ phydev->advertising = phydev->supported;
+ priv->phydev = phydev;
+ phy_config(phydev);
+ phy_startup(phydev);
+
+ if (!phydev->link) {
+ printf("%s: No link.\n", phydev->dev->name);
+ return -1;
+ }
+
+ switch (phydev->speed) {
+ case SPEED_1000:
+ writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000,
+ &regs->nwcfg);
+ clk_rate = ZYNQ_GEM_FREQUENCY_1000;
+ break;
+ case SPEED_100:
+ clrsetbits_le32(&regs->nwcfg, ZYNQ_GEM_NWCFG_SPEED1000,
+ ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100);
+ clk_rate = ZYNQ_GEM_FREQUENCY_100;
+ break;
+ case SPEED_10:
+ clk_rate = ZYNQ_GEM_FREQUENCY_10;
+ break;
+ }
+
+ /* Change the rclk and clk only not using EMIO interface */
+ if (!priv->emio)
+ zynq_slcr_gem_clk_setup(dev->iobase !=
+ ZYNQ_GEM_BASEADDR0, clk_rate);
+
+ setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
+ ZYNQ_GEM_NWCTRL_TXEN_MASK);
+
+ return 0;
+}
+
+static int zynq_gem_send(struct eth_device *dev, void *ptr, int len)
+{
+ u32 addr, size;
+ struct zynq_gem_priv *priv = dev->priv;
+ struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
+
+ /* setup BD */
+ writel((u32)priv->tx_bd, &regs->txqbase);
+
+ /* Setup Tx BD */
+ memset(priv->tx_bd, 0, sizeof(struct emac_bd));
+
+ priv->tx_bd->addr = (u32)ptr;
+ priv->tx_bd->status = (len & ZYNQ_GEM_TXBUF_FRMLEN_MASK) |
+ ZYNQ_GEM_TXBUF_LAST_MASK;
+
+ addr = (u32) ptr;
+ addr &= ~(ARCH_DMA_MINALIGN - 1);
+ size = roundup(len, ARCH_DMA_MINALIGN);
+ flush_dcache_range(addr, addr + size);
+ barrier();
+
+ /* Start transmit */
+ setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK);
+
+ /* Read TX BD status */
+ if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_UNDERRUN)
+ printf("TX underrun\n");
+ if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_EXHAUSTED)
+ printf("TX buffers exhausted in mid frame\n");
+
+ return 0;
+}
+
+/* Do not check frame_recd flag in rx_status register 0x20 - just poll BD */
+static int zynq_gem_recv(struct eth_device *dev)
+{
+ int frame_len;
+ struct zynq_gem_priv *priv = dev->priv;
+ struct emac_bd *current_bd = &priv->rx_bd[priv->rxbd_current];
+ struct emac_bd *first_bd;
+
+ if (!(current_bd->addr & ZYNQ_GEM_RXBUF_NEW_MASK))
+ return 0;
+
+ if (!(current_bd->status &
+ (ZYNQ_GEM_RXBUF_SOF_MASK | ZYNQ_GEM_RXBUF_EOF_MASK))) {
+ printf("GEM: SOF or EOF not set for last buffer received!\n");
+ return 0;
+ }
+
+ frame_len = current_bd->status & ZYNQ_GEM_RXBUF_LEN_MASK;
+ if (frame_len) {
+ u32 addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK;
+ addr &= ~(ARCH_DMA_MINALIGN - 1);
+ u32 size = roundup(frame_len, ARCH_DMA_MINALIGN);
+ invalidate_dcache_range(addr, addr + size);
+
+ NetReceive((u8 *)addr, frame_len);
+
+ if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK)
+ priv->rx_first_buf = priv->rxbd_current;
+ else {
+ current_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK;
+ current_bd->status = 0xF0000000; /* FIXME */
+ }
+
+ if (current_bd->status & ZYNQ_GEM_RXBUF_EOF_MASK) {
+ first_bd = &priv->rx_bd[priv->rx_first_buf];
+ first_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK;
+ first_bd->status = 0xF0000000;
+ }
+
+ if ((++priv->rxbd_current) >= RX_BUF)
+ priv->rxbd_current = 0;
+ }
+
+ return frame_len;
+}
+
+static void zynq_gem_halt(struct eth_device *dev)
+{
+ struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
+
+ clrsetbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
+ ZYNQ_GEM_NWCTRL_TXEN_MASK, 0);
+}
+
+static int zynq_gem_miiphyread(const char *devname, uchar addr,
+ uchar reg, ushort *val)
+{
+ struct eth_device *dev = eth_get_dev();
+ int ret;
+
+ ret = phyread(dev, addr, reg, val);
+ debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, *val);
+ return ret;
+}
+
+static int zynq_gem_miiphy_write(const char *devname, uchar addr,
+ uchar reg, ushort val)
+{
+ struct eth_device *dev = eth_get_dev();
+
+ debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, val);
+ return phywrite(dev, addr, reg, val);
+}
+
+int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio)
+{
+ struct eth_device *dev;
+ struct zynq_gem_priv *priv;
+ void *bd_space;
+
+ dev = calloc(1, sizeof(*dev));
+ if (dev == NULL)
+ return -1;
+
+ dev->priv = calloc(1, sizeof(struct zynq_gem_priv));
+ if (dev->priv == NULL) {
+ free(dev);
+ return -1;
+ }
+ priv = dev->priv;
+
+ /* Align rxbuffers to ARCH_DMA_MINALIGN */
+ priv->rxbuffers = memalign(ARCH_DMA_MINALIGN, RX_BUF * PKTSIZE_ALIGN);
+ memset(priv->rxbuffers, 0, RX_BUF * PKTSIZE_ALIGN);
+
+ /* Align bd_space to 1MB */
+ bd_space = memalign(1 << MMU_SECTION_SHIFT, BD_SPACE);
+ mmu_set_region_dcache_behaviour((u32)bd_space, BD_SPACE, DCACHE_OFF);
+
+ /* Initialize the bd spaces for tx and rx bd's */
+ priv->tx_bd = (struct emac_bd *)bd_space;
+ priv->rx_bd = (struct emac_bd *)((u32)bd_space + BD_SEPRN_SPACE);
+
+ priv->phyaddr = phy_addr;
+ priv->emio = emio;
+
+ sprintf(dev->name, "Gem.%x", base_addr);
+
+ dev->iobase = base_addr;
+
+ dev->init = zynq_gem_init;
+ dev->halt = zynq_gem_halt;
+ dev->send = zynq_gem_send;
+ dev->recv = zynq_gem_recv;
+ dev->write_hwaddr = zynq_gem_setup_mac;
+
+ eth_register(dev);
+
+ miiphy_register(dev->name, zynq_gem_miiphyread, zynq_gem_miiphy_write);
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+
+ return 1;
+}
+
+#ifdef CONFIG_OF_CONTROL
+int zynq_gem_of_init(const void *blob)
+{
+ int offset = 0;
+ u32 ret = 0;
+ u32 reg, phy_reg;
+
+ debug("ZYNQ GEM: Initialization\n");
+
+ do {
+ offset = fdt_node_offset_by_compatible(blob, offset,
+ "xlnx,ps7-ethernet-1.00.a");
+ if (offset != -1) {
+ reg = fdtdec_get_addr(blob, offset, "reg");
+ if (reg != FDT_ADDR_T_NONE) {
+ offset = fdtdec_lookup_phandle(blob, offset,
+ "phy-handle");
+ if (offset != -1)
+ phy_reg = fdtdec_get_addr(blob, offset,
+ "reg");
+ else
+ phy_reg = 0;
+
+ debug("ZYNQ GEM: addr %x, phyaddr %x\n",
+ reg, phy_reg);
+
+ ret |= zynq_gem_initialize(NULL, reg,
+ phy_reg, 0);
+
+ } else {
+ debug("ZYNQ GEM: Can't get base address\n");
+ return -1;
+ }
+ }
+ } while (offset != -1);
+
+ return ret;
+}
+#endif