Merge tag 'u-boot-imx-20200310' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx

Fixes for 2020.04
-----------------

- DM : mx6sabresd
- mx6ul_14x14_evk: fix video
- mx8qxp; fix console for booting
- sync DTS with kernel (imx6sx)
- drop obsolete woodburn (mx35)

Travis: https://travis-ci.org/sbabic/u-boot-imx/builds/660550811
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
index 8648058..f66d58a 100644
--- a/.azure-pipelines.yml
+++ b/.azure-pipelines.yml
@@ -361,7 +361,7 @@
         sun50i:
           BUILDMAN: "sun50i"
         arm_catch_all:
-          BUILDMAN: "arm -x arm11,arm7,arm9,aarch64,at91,bcm,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap,rockchip,toradex,socfpga,k2,k3,zynq"
+          BUILDMAN: "arm -x arm11,arm7,arm9,aarch64,at91,bcm,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap,rk,toradex,socfpga,k2,k3,zynq"
         sandbox_x86:
           BUILDMAN: "sandbox x86"
         technexion:
@@ -399,9 +399,9 @@
         uniphier:
           BUILDMAN: "uniphier"
         aarch64_catch_all:
-          BUILDMAN: "aarch64 -x bcm,k3,tegra,ls1,ls2,mvebu,uniphier,sunxi,samsung,rockchip,versal,zynq"
+          BUILDMAN: "aarch64 -x bcm,k3,tegra,ls1,ls2,lx216,mvebu,uniphier,sunxi,samsung,socfpga,rk,versal,zynq"
         rockchip:
-          BUILDMAN: "rockchip"
+          BUILDMAN: "rk"
         sh:
           BUILDMAN: "sh -x arm"
         zynq:
diff --git a/.travis.yml b/.travis.yml
index 7ab855a..c59bd77 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -248,7 +248,7 @@
         - BUILDMAN="sun50i -x orangepi"
     - name: "buildman catch-all ARM"
       env:
-        - BUILDMAN="arm -x arm11,arm7,arm9,aarch64,at91,bcm,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap,rockchip,toradex,socfpga,k2,k3,zynq"
+        - BUILDMAN="arm -x arm11,arm7,arm9,aarch64,at91,bcm,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap,rk,toradex,socfpga,k2,k3,zynq"
     - name: "buildman sandbox x86"
       env:
         - BUILDMAN="sandbox x86"
@@ -322,10 +322,10 @@
         - BUILDMAN="uniphier"
     - name: "buildman catch-all AArch64"
       env:
-        - BUILDMAN="aarch64 -x bcm,k3,tegra,ls1,ls2,mvebu,uniphier,sunxi,samsung,rockchip,versal,zynq"
+        - BUILDMAN="aarch64 -x bcm,k3,tegra,ls1,ls2,lx216,mvebu,uniphier,sunxi,samsung,socfpga,rk,versal,zynq"
     - name: "buildman rockchip"
       env:
-        - BUILDMAN="rockchip -x orangepi"
+        - BUILDMAN="rk -x orangepi"
     - name: "buildman sh"
       env:
         - BUILDMAN="sh -x arm"
diff --git a/Makefile b/Makefile
index 55aa90c..07539ca 100644
--- a/Makefile
+++ b/Makefile
@@ -1830,7 +1830,7 @@
 	(grep -v '^#' | \
 	 grep -v '^$$' | \
 	 tr '\n' '\0' | \
-	 sed -e 's/\\\x0/\n/g' | \
+	 sed -e 's/\\\x0\s*//g' | \
 	 xxd -i ; echo ", 0x00" ; )
 endef
 
diff --git a/configs/sama5d3_xplained_nandflash_defconfig b/configs/sama5d3_xplained_nandflash_defconfig
index 2749290..83ff270 100644
--- a/configs/sama5d3_xplained_nandflash_defconfig
+++ b/configs/sama5d3_xplained_nandflash_defconfig
@@ -25,6 +25,7 @@
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs"
 # CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_SPL_SEPARATE_BSS=y
 CONFIG_SPL_NAND_SUPPORT=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
diff --git a/doc/README.drivers.eth b/doc/README.drivers.eth
deleted file mode 100644
index 1a9a23b..0000000
--- a/doc/README.drivers.eth
+++ /dev/null
@@ -1,215 +0,0 @@
-!!! WARNING !!!
-
-This guide describes to the old way of doing things. No new Ethernet drivers
-should be implemented this way. All new drivers should be written against the
-U-Boot core driver model. See doc/driver-model/README.txt
-
------------------------
- Ethernet Driver Guide
------------------------
-
-The networking stack in Das U-Boot is designed for multiple network devices
-to be easily added and controlled at runtime.  This guide is meant for people
-who wish to review the net driver stack with an eye towards implementing your
-own ethernet device driver.  Here we will describe a new pseudo 'APE' driver.
-
-------------------
- Driver Functions
-------------------
-
-All functions you will be implementing in this document have the return value
-meaning of 0 for success and non-zero for failure.
-
- ----------
-  Register
- ----------
-
-When U-Boot initializes, it will call the common function eth_initialize().
-This will in turn call the board-specific board_eth_init() (or if that fails,
-the cpu-specific cpu_eth_init()).  These board-specific functions can do random
-system handling, but ultimately they will call the driver-specific register
-function which in turn takes care of initializing that particular instance.
-
-Keep in mind that you should code the driver to avoid storing state in global
-data as someone might want to hook up two of the same devices to one board.
-Any such information that is specific to an interface should be stored in a
-private, driver-defined data structure and pointed to by eth->priv (see below).
-
-So the call graph at this stage would look something like:
-board_init()
-	eth_initialize()
-		board_eth_init() / cpu_eth_init()
-			driver_register()
-				initialize eth_device
-				eth_register()
-
-At this point in time, the only thing you need to worry about is the driver's
-register function.  The pseudo code would look something like:
-int ape_register(bd_t *bis, int iobase)
-{
-	struct ape_priv *priv;
-	struct eth_device *dev;
-	struct mii_dev *bus;
-
-	priv = malloc(sizeof(*priv));
-	if (priv == NULL)
-		return -ENOMEM;
-
-	dev = malloc(sizeof(*dev));
-	if (dev == NULL) {
-		free(priv);
-		return -ENOMEM;
-	}
-
-	/* setup whatever private state you need */
-
-	memset(dev, 0, sizeof(*dev));
-	sprintf(dev->name, "APE");
-
-	/*
-	 * if your device has dedicated hardware storage for the
-	 * MAC, read it and initialize dev->enetaddr with it
-	 */
-	ape_mac_read(dev->enetaddr);
-
-	dev->iobase = iobase;
-	dev->priv = priv;
-	dev->init = ape_init;
-	dev->halt = ape_halt;
-	dev->send = ape_send;
-	dev->recv = ape_recv;
-	dev->write_hwaddr = ape_write_hwaddr;
-
-	eth_register(dev);
-
-#ifdef CONFIG_PHYLIB
-	bus = mdio_alloc();
-	if (!bus) {
-		free(priv);
-		free(dev);
-		return -ENOMEM;
-	}
-
-	bus->read = ape_mii_read;
-	bus->write = ape_mii_write;
-	mdio_register(bus);
-#endif
-
-	return 1;
-}
-
-The exact arguments needed to initialize your device are up to you.  If you
-need to pass more/less arguments, that's fine.  You should also add the
-prototype for your new register function to include/netdev.h.
-
-The return value for this function should be as follows:
-< 0 - failure (hardware failure, not probe failure)
->=0 - number of interfaces detected
-
-You might notice that many drivers seem to use xxx_initialize() rather than
-xxx_register().  This is the old naming convention and should be avoided as it
-causes confusion with the driver-specific init function.
-
-Other than locating the MAC address in dedicated hardware storage, you should
-not touch the hardware in anyway.  That step is handled in the driver-specific
-init function.  Remember that we are only registering the device here, we are
-not checking its state or doing random probing.
-
- -----------
-  Callbacks
- -----------
-
-Now that we've registered with the ethernet layer, we can start getting some
-real work done.  You will need five functions:
-	int ape_init(struct eth_device *dev, bd_t *bis);
-	int ape_send(struct eth_device *dev, volatile void *packet, int length);
-	int ape_recv(struct eth_device *dev);
-	int ape_halt(struct eth_device *dev);
-	int ape_write_hwaddr(struct eth_device *dev);
-
-The init function checks the hardware (probing/identifying) and gets it ready
-for send/recv operations.  You often do things here such as resetting the MAC
-and/or PHY, and waiting for the link to autonegotiate.  You should also take
-the opportunity to program the device's MAC address with the dev->enetaddr
-member.  This allows the rest of U-Boot to dynamically change the MAC address
-and have the new settings be respected.
-
-The send function does what you think -- transmit the specified packet whose
-size is specified by length (in bytes).  You should not return until the
-transmission is complete, and you should leave the state such that the send
-function can be called multiple times in a row.
-
-The recv function should process packets as long as the hardware has them
-readily available before returning.  i.e. you should drain the hardware fifo.
-For each packet you receive, you should call the net_process_received_packet() function on it
-along with the packet length.  The common code sets up packet buffers for you
-already in the .bss (net_rx_packets), so there should be no need to allocate your
-own.  This doesn't mean you must use the net_rx_packets array however; you're
-free to call the net_process_received_packet() function with any buffer you wish.  So the pseudo
-code here would look something like:
-int ape_recv(struct eth_device *dev)
-{
-	int length, i = 0;
-	...
-	while (packets_are_available()) {
-		...
-		length = ape_get_packet(&net_rx_packets[i]);
-		...
-		net_process_received_packet(&net_rx_packets[i], length);
-		...
-		if (++i >= PKTBUFSRX)
-			i = 0;
-		...
-	}
-	...
-	return 0;
-}
-
-The halt function should turn off / disable the hardware and place it back in
-its reset state.  It can be called at any time (before any call to the related
-init function), so make sure it can handle this sort of thing.
-
-The write_hwaddr function should program the MAC address stored in dev->enetaddr
-into the Ethernet controller.
-
-So the call graph at this stage would look something like:
-some net operation (ping / tftp / whatever...)
-	eth_init()
-		dev->init()
-	eth_send()
-		dev->send()
-	eth_rx()
-		dev->recv()
-	eth_halt()
-		dev->halt()
-
---------------------------------
- CONFIG_PHYLIB / CONFIG_CMD_MII
---------------------------------
-
-If your device supports banging arbitrary values on the MII bus (pretty much
-every device does), you should add support for the mii command.  Doing so is
-fairly trivial and makes debugging mii issues a lot easier at runtime.
-
-After you have called eth_register() in your driver's register function, add
-a call to mdio_alloc() and mdio_register() like so:
-	bus = mdio_alloc();
-	if (!bus) {
-		free(priv);
-		free(dev);
-		return -ENOMEM;
-	}
-
-	bus->read = ape_mii_read;
-	bus->write = ape_mii_write;
-	mdio_register(bus);
-
-And then define the mii_read and mii_write functions if you haven't already.
-Their syntax is straightforward:
-	int mii_read(struct mii_dev *bus, int addr, int devad, int reg);
-	int mii_write(struct mii_dev *bus, int addr, int devad, int reg,
-		      u16 val);
-
-The read function should read the register 'reg' from the phy at address 'addr'
-and return the result to its caller.  The implementation for the write function
-should logically follow.
diff --git a/doc/device-tree-bindings/net/ti,dp83867.txt b/doc/device-tree-bindings/net/ti,dp83867.txt
deleted file mode 100644
index 2682209..0000000
--- a/doc/device-tree-bindings/net/ti,dp83867.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-* Texas Instruments - dp83867 Giga bit ethernet phy
-
-Required properties:
-	- reg - The ID number for the phy, usually a small integer
-	- ti,rx-internal-delay - RGMII Recieve Clock Delay - see dt-bindings/net/ti-dp83867.h
-		for applicable values
-	- ti,tx-internal-delay - RGMII Transmit Clock Delay - see dt-bindings/net/ti-dp83867.h
-		for applicable values
-	- ti,fifo-depth - Transmitt FIFO depth- see dt-bindings/net/ti-dp83867.h
-		for applicable values
-	- enet-phy-lane-swap - Indicates that PHY will swap the TX/RX lanes to
-		compensate for the board being designed with the lanes swapped.
-	- enet-phy-no-lane-swap - Indicates that PHY will disable swap of the
-		TX/RX lanes.
-	- ti,clk-output-sel - Muxing option for CLK_OUT pin.  See dt-bindings/net/ti-dp83867.h
-			      for applicable values.  The CLK_OUT pin can also
-			      be disabled by this property.  When omitted, the
-			      PHY's default will be left as is.
-
-Default child nodes are standard Ethernet PHY device
-nodes as described in doc/devicetree/bindings/net/ethernet.txt
-
-Example:
-
-	ethernet-phy@0 {
-		reg = <0>;
-		ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
-		ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
-		ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
-		enet-phy-lane-no-swap;
-		ti,clk-output-sel = <DP83867_CLK_O_SEL_CHN_A_TCLK>;
-	};
-
-Datasheet can be found:
-http://www.ti.com/product/DP83867IR/datasheet
diff --git a/doc/driver-model/ethernet.rst b/doc/driver-model/ethernet.rst
new file mode 100644
index 0000000..359a052
--- /dev/null
+++ b/doc/driver-model/ethernet.rst
@@ -0,0 +1,321 @@
+Ethernet Driver Guide
+=======================
+
+The networking stack in Das U-Boot is designed for multiple network devices
+to be easily added and controlled at runtime.  This guide is meant for people
+who wish to review the net driver stack with an eye towards implementing your
+own ethernet device driver.  Here we will describe a new pseudo 'APE' driver.
+
+Most existing drivers do already - and new network driver MUST - use the
+U-Boot core driver model. Generic information about this can be found in
+doc/driver-model/design.rst, this document will thus focus on the network
+specific code parts.
+Some drivers are still using the old Ethernet interface, differences between
+the two and hints about porting will be handled at the end.
+
+Driver framework
+------------------
+
+A network driver following the driver model must declare itself using
+the UCLASS_ETH .id field in the U-Boot driver struct:
+
+.. code-block:: c
+
+	U_BOOT_DRIVER(eth_ape) = {
+		.name			= "eth_ape",
+		.id			= UCLASS_ETH,
+		.of_match		= eth_ape_ids,
+		.ofdata_to_platdata	= eth_ape_ofdata_to_platdata,
+		.probe			= eth_ape_probe,
+		.ops			= &eth_ape_ops,
+		.priv_auto_alloc_size	= sizeof(struct eth_ape_priv),
+		.platdata_auto_alloc_size = sizeof(struct eth_ape_pdata),
+		.flags			= DM_FLAG_ALLOC_PRIV_DMA,
+	};
+
+struct eth_ape_priv contains runtime per-instance data, like buffers, pointers
+to current descriptors, current speed settings, pointers to PHY related data
+(like struct mii_dev) and so on. Declaring its size in .priv_auto_alloc_size
+will let the driver framework allocate it at the right time.
+It can be retrieved using a dev_get_priv(dev) call.
+
+struct eth_ape_pdata contains static platform data, like the MMIO base address,
+a hardware variant, the MAC address. ``struct eth_pdata eth_pdata``
+as the first member of this struct helps to avoid duplicated code.
+If you don't need any more platform data beside the standard member,
+just use sizeof(struct eth_pdata) for the platdata_auto_alloc_size.
+
+PCI devices add a line pointing to supported vendor/device ID pairs:
+
+.. code-block:: c
+
+	static struct pci_device_id supported[] = {
+		{ PCI_DEVICE(PCI_VENDOR_ID_APE, 0x4223) },
+		{}
+	};
+
+	U_BOOT_PCI_DEVICE(eth_ape, supported);
+
+It is also possible to declare support for a whole class of PCI devices::
+
+	{ PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_SDHCI << 8, 0xffff00) },
+
+Device probing and instantiation will be handled by the driver model framework,
+so follow the guidelines there. The probe() function would initialise the
+platform specific parts of the hardware, like clocks, resets, GPIOs, the MDIO
+bus. Also it would take care of any special PHY setup (power rails, enable
+bits for internal PHYs, etc.).
+
+Driver methods
+----------------
+
+The real work will be done in the driver method functions the driver provides
+by defining the members of struct eth_ops:
+
+.. code-block:: c
+
+	struct eth_ops {
+		int (*start)(struct udevice *dev);
+		int (*send)(struct udevice *dev, void *packet, int length);
+		int (*recv)(struct udevice *dev, int flags, uchar **packetp);
+		int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
+		void (*stop)(struct udevice *dev);
+		int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
+		int (*write_hwaddr)(struct udevice *dev);
+		int (*read_rom_hwaddr)(struct udevice *dev);
+	};
+
+An up-to-date version of this struct together with more information can be
+found in include/net.h.
+
+Only start, stop, send and recv are required, the rest are optional and are
+handled by generic code or ignored if not provided.
+
+The **start** function initialises the hardware and gets it ready for send/recv
+operations.  You often do things here such as resetting the MAC
+and/or PHY, and waiting for the link to autonegotiate.  You should also take
+the opportunity to program the device's MAC address with the enetaddr member
+of the generic struct eth_pdata (which would be the first member of your
+own platdata struct). This allows the rest of U-Boot to dynamically change
+the MAC address and have the new settings be respected.
+
+The **send** function does what you think -- transmit the specified packet
+whose size is specified by length (in bytes). The packet buffer can (and
+will!) be reused for subsequent calls to send(), so it must be no longer
+used when the send() function returns. The easiest way to achieve this is
+to wait until the transmission is complete. Alternatively, if supported by
+the hardware, just waiting for the buffer to be consumed (by some DMA engine)
+might be an option as well.
+Another way of consuming the buffer could be to copy the data to be send,
+then just queue the copied packet (for instance handing it over to a DMA
+engine), and return immediately afterwards.
+In any case you should leave the state such that the send function can be
+called multiple times in a row.
+
+The **recv** function polls for availability of a new packet. If none is
+available, it must return with -EAGAIN.
+If a packet has been received, make sure it is accessible to the CPU
+(invalidate caches if needed), then write its address to the packetp pointer,
+and return the length. If there is an error (receive error, too short or too
+long packet), return 0 if you require the packet to be cleaned up normally,
+or a negative error code otherwise (cleanup not necessary or already done).
+The U-Boot network stack will then process the packet.
+
+If **free_pkt** is defined, U-Boot will call it after a received packet has
+been processed, so the packet buffer can be freed or recycled. Typically you
+would hand it back to the hardware to acquire another packet. free_pkt() will
+be called after recv(), for the same packet, so you don't necessarily need
+to infer the buffer to free from the ``packet`` pointer, but can rely on that
+being the last packet that recv() handled.
+The common code sets up packet buffers for you already in the .bss
+(net_rx_packets), so there should be no need to allocate your own. This doesn't
+mean you must use the net_rx_packets array however; you're free to use any
+buffer you wish.
+
+The **stop** function should turn off / disable the hardware and place it back
+in its reset state.  It can be called at any time (before any call to the
+related start() function), so make sure it can handle this sort of thing.
+
+The (optional) **write_hwaddr** function should program the MAC address stored
+in pdata->enetaddr into the Ethernet controller.
+
+So the call graph at this stage would look something like:
+
+.. code-block:: c
+
+	(some net operation (ping / tftp / whatever...))
+	eth_init()
+		ops->start()
+	eth_send()
+		ops->send()
+	eth_rx()
+		ops->recv()
+		(process packet)
+		if (ops->free_pkt)
+			ops->free_pkt()
+	eth_halt()
+		ops->stop()
+
+
+CONFIG_PHYLIB / CONFIG_CMD_MII
+--------------------------------
+
+If your device supports banging arbitrary values on the MII bus (pretty much
+every device does), you should add support for the mii command.  Doing so is
+fairly trivial and makes debugging mii issues a lot easier at runtime.
+
+In your driver's ``probe()`` function, add a call to mdio_alloc() and
+mdio_register() like so:
+
+.. code-block:: c
+
+	bus = mdio_alloc();
+	if (!bus) {
+		...
+		return -ENOMEM;
+	}
+
+	bus->read = ape_mii_read;
+	bus->write = ape_mii_write;
+	mdio_register(bus);
+
+And then define the mii_read and mii_write functions if you haven't already.
+Their syntax is straightforward::
+
+	int mii_read(struct mii_dev *bus, int addr, int devad, int reg);
+	int mii_write(struct mii_dev *bus, int addr, int devad, int reg,
+		      u16 val);
+
+The read function should read the register 'reg' from the phy at address 'addr'
+and return the result to its caller.  The implementation for the write function
+should logically follow.
+
+................................................................
+
+Legacy network drivers
+------------------------
+
+!!! WARNING !!!
+
+This section below describes the old way of doing things. No new Ethernet
+drivers should be implemented this way. All new drivers should be written
+against the U-Boot core driver model, as described above.
+
+The actual callback functions are fairly similar, the differences are:
+
+- ``start()`` is called ``init()``
+- ``stop()`` is called ``halt()``
+- The ``recv()`` function must loop until all packets have been received, for
+  each packet it must call the net_process_received_packet() function,
+  handing it over the pointer and the length. Afterwards it should free
+  the packet, before checking for new data.
+
+For porting an old driver to the new driver model, split the existing recv()
+function into the actual new recv() function, just fetching **one** packet,
+remove the call to net_process_received_packet(), then move the packet
+cleanup into the ``free_pkt()`` function.
+
+Registering the driver and probing a device is handled very differently,
+follow the recommendations in the driver model design documentation for
+instructions on how to port this over. For the records, the old way of
+initialising a network driver is as follows:
+
+Old network driver registration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When U-Boot initializes, it will call the common function eth_initialize().
+This will in turn call the board-specific board_eth_init() (or if that fails,
+the cpu-specific cpu_eth_init()).  These board-specific functions can do random
+system handling, but ultimately they will call the driver-specific register
+function which in turn takes care of initializing that particular instance.
+
+Keep in mind that you should code the driver to avoid storing state in global
+data as someone might want to hook up two of the same devices to one board.
+Any such information that is specific to an interface should be stored in a
+private, driver-defined data structure and pointed to by eth->priv (see below).
+
+So the call graph at this stage would look something like:
+
+.. code-block:: c
+
+	board_init()
+		eth_initialize()
+			board_eth_init() / cpu_eth_init()
+				driver_register()
+					initialize eth_device
+					eth_register()
+
+At this point in time, the only thing you need to worry about is the driver's
+register function.  The pseudo code would look something like:
+
+.. code-block:: c
+
+	int ape_register(bd_t *bis, int iobase)
+	{
+		struct ape_priv *priv;
+		struct eth_device *dev;
+		struct mii_dev *bus;
+
+		priv = malloc(sizeof(*priv));
+		if (priv == NULL)
+			return -ENOMEM;
+
+		dev = malloc(sizeof(*dev));
+		if (dev == NULL) {
+			free(priv);
+			return -ENOMEM;
+		}
+
+		/* setup whatever private state you need */
+
+		memset(dev, 0, sizeof(*dev));
+		sprintf(dev->name, "APE");
+
+		/*
+		 * if your device has dedicated hardware storage for the
+		 * MAC, read it and initialize dev->enetaddr with it
+		 */
+		ape_mac_read(dev->enetaddr);
+
+		dev->iobase = iobase;
+		dev->priv = priv;
+		dev->init = ape_init;
+		dev->halt = ape_halt;
+		dev->send = ape_send;
+		dev->recv = ape_recv;
+		dev->write_hwaddr = ape_write_hwaddr;
+
+		eth_register(dev);
+
+	#ifdef CONFIG_PHYLIB
+		bus = mdio_alloc();
+		if (!bus) {
+			free(priv);
+			free(dev);
+			return -ENOMEM;
+		}
+
+		bus->read = ape_mii_read;
+		bus->write = ape_mii_write;
+		mdio_register(bus);
+	#endif
+
+		return 1;
+	}
+
+The exact arguments needed to initialize your device are up to you.  If you
+need to pass more/less arguments, that's fine.  You should also add the
+prototype for your new register function to include/netdev.h.
+
+The return value for this function should be as follows:
+< 0 - failure (hardware failure, not probe failure)
+>=0 - number of interfaces detected
+
+You might notice that many drivers seem to use xxx_initialize() rather than
+xxx_register().  This is the old naming convention and should be avoided as it
+causes confusion with the driver-specific init function.
+
+Other than locating the MAC address in dedicated hardware storage, you should
+not touch the hardware in anyway.  That step is handled in the driver-specific
+init function.  Remember that we are only registering the device here, we are
+not checking its state or doing random probing.
diff --git a/doc/driver-model/index.rst b/doc/driver-model/index.rst
index 6d55774..b9df221 100644
--- a/doc/driver-model/index.rst
+++ b/doc/driver-model/index.rst
@@ -8,6 +8,7 @@
 
    debugging
    design
+   ethernet
    fdt-fixup
    fs_firmware_loader
    i2c-howto
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index dceea15..d1f049e 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -267,4 +267,8 @@
 	  on, the link is always up with fixed speed and fixed duplex-setting.
 	  More information: doc/device-tree-bindings/net/fixed-link.txt
 
+config PHY_NCSI
+	bool "NC-SI based PHY"
+	depends on DM_ETH
+
 endif #PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 78955c5..1d81516 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -31,3 +31,4 @@
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
 obj-$(CONFIG_PHY_MSCC) += mscc.o
 obj-$(CONFIG_PHY_FIXED) += fixed.o
+obj-$(CONFIG_PHY_NCSI) += ncsi.o
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index c4bd443..8ece926 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -306,30 +306,29 @@
 					   AQUANTIA_VND1_GSTART_RATE_1G},
 	[PHY_INTERFACE_MODE_SGMII_2500] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G,
 					   AQUANTIA_VND1_GSTART_RATE_2_5G},
-	[PHY_INTERFACE_MODE_XGMII] =      {0x100, AQUANTIA_VND1_GSYSCFG_10G,
-					   AQUANTIA_VND1_GSTART_RATE_10G},
 	[PHY_INTERFACE_MODE_XFI] =        {0x100, AQUANTIA_VND1_GSYSCFG_10G,
 					   AQUANTIA_VND1_GSTART_RATE_10G},
 	[PHY_INTERFACE_MODE_USXGMII] =    {0x080, AQUANTIA_VND1_GSYSCFG_10G,
 					   AQUANTIA_VND1_GSTART_RATE_10G},
 };
 
-static int aquantia_set_proto(struct phy_device *phydev)
+static int aquantia_set_proto(struct phy_device *phydev,
+			      phy_interface_t interface)
 {
 	int i;
 
-	if (!aquantia_syscfg[phydev->interface].cnt)
+	if (!aquantia_syscfg[interface].cnt)
 		return 0;
 
 	/* set the default rate to enable the SI link */
 	phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
-		  aquantia_syscfg[phydev->interface].start_rate);
+		  aquantia_syscfg[interface].start_rate);
 
 	/* set selected protocol for all relevant line side link speeds */
-	for (i = 0; i <= aquantia_syscfg[phydev->interface].cnt; i++)
+	for (i = 0; i <= aquantia_syscfg[interface].cnt; i++)
 		phy_write(phydev, MDIO_MMD_VEND1,
 			  AQUANTIA_VND1_GSYSCFG_BASE + i,
-			  aquantia_syscfg[phydev->interface].syscfg);
+			  aquantia_syscfg[interface].syscfg);
 	return 0;
 }
 
@@ -425,9 +424,9 @@
 	fault = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_FAULT);
 
 	if (id != 0)
-		printf("%s running firmware version %X.%X.%X\n",
-		       phydev->dev->name, (id >> 8), id & 0xff,
-		       (rstatus >> 4) & 0xf);
+		debug("%s running firmware version %X.%X.%X\n",
+		      phydev->dev->name, (id >> 8), id & 0xff,
+		      (rstatus >> 4) & 0xf);
 
 	if (fault != 0)
 		printf("%s fault 0x%04x detected\n", phydev->dev->name, fault);
@@ -444,6 +443,8 @@
 	 * on FW config
 	 */
 	if (interface == PHY_INTERFACE_MODE_XGMII) {
+		debug("use XFI or USXGMII SI protos, XGMII is not valid\n");
+
 		reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS,
 				    AQUANTIA_SYSTEM_INTERFACE_SR);
 		if ((reg_val1 & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII)
@@ -466,7 +467,7 @@
 		mdelay(10);
 
 		/* configure protocol based on phydev->interface */
-		aquantia_set_proto(phydev);
+		aquantia_set_proto(phydev, interface);
 		/* apply custom configuration based on DT */
 		aquantia_dts_config(phydev);
 
@@ -506,12 +507,12 @@
 
 		if (usx_an) {
 			reg_val1 |= AQUANTIA_USX_AUTONEG_CONTROL_ENA;
-			printf("%s: system interface USXGMII\n",
-			       phydev->dev->name);
+			debug("%s: system interface USXGMII\n",
+			      phydev->dev->name);
 		} else {
 			reg_val1 &= ~AQUANTIA_USX_AUTONEG_CONTROL_ENA;
-			printf("%s: system interface XFI\n",
-			       phydev->dev->name);
+			debug("%s: system interface XFI\n",
+			      phydev->dev->name);
 		}
 
 		phy_write(phydev, MDIO_MMD_PHYXS,
@@ -538,11 +539,11 @@
 	val = phy_read(phydev, MDIO_MMD_VEND1, AQUANTIA_RESERVED_STATUS);
 	reg_val1 = phy_read(phydev, MDIO_MMD_VEND1, AQUANTIA_FIRMWARE_ID);
 
-	printf("%s: %s Firmware Version %x.%x.%x\n", phydev->dev->name,
-	       phydev->drv->name,
-	       (reg_val1 & AQUANTIA_FIRMWARE_MAJOR_MASK) >> 8,
-	       reg_val1 & AQUANTIA_FIRMWARE_MINOR_MASK,
-	       (val & AQUANTIA_FIRMWARE_BUILD_MASK) >> 4);
+	debug("%s: %s Firmware Version %x.%x.%x\n", phydev->dev->name,
+	      phydev->drv->name,
+	      (reg_val1 & AQUANTIA_FIRMWARE_MAJOR_MASK) >> 8,
+	      reg_val1 & AQUANTIA_FIRMWARE_MINOR_MASK,
+	      (val & AQUANTIA_FIRMWARE_BUILD_MASK) >> 4);
 
 	return 0;
 }
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index 0098997..50804c1 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -29,6 +29,7 @@
 #define DP83867_STRAP_STS2	0x006f
 #define DP83867_RGMIIDCTL	0x0086
 #define DP83867_IO_MUX_CFG	0x0170
+#define DP83867_SGMIICTL	0x00D3
 
 #define DP83867_SW_RESET	BIT(15)
 #define DP83867_SW_RESTART	BIT(14)
@@ -101,6 +102,9 @@
 /* CFG4 bits */
 #define DP83867_CFG4_PORT_MIRROR_EN		BIT(0)
 
+/* SGMIICTL bits */
+#define DP83867_SGMII_TYPE			BIT(14)
+
 enum {
 	DP83867_PORT_MIRRORING_KEEP,
 	DP83867_PORT_MIRRORING_EN,
@@ -116,6 +120,7 @@
 	int port_mirroring;
 	bool set_clk_output;
 	unsigned int clk_output_sel;
+	bool sgmii_ref_clk_en;
 };
 
 static int dp83867_config_port_mirroring(struct phy_device *phydev)
@@ -236,6 +241,9 @@
 	if (ofnode_read_bool(node, "enet-phy-lane-no-swap"))
 		dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS;
 
+	if (ofnode_read_bool(node, "ti,sgmii-ref-clock-output-enable"))
+		dp83867->sgmii_ref_clk_en = true;
+
 	return 0;
 }
 #else
@@ -331,6 +339,10 @@
 	}
 
 	if (phy_interface_is_sgmii(phydev)) {
+		if (dp83867->sgmii_ref_clk_en)
+			phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL,
+				      DP83867_SGMII_TYPE);
+
 		phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR,
 			  (BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000));
 
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index efbbd31..93cf44a 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -303,9 +303,9 @@
 }
 
 /**
- * m88e1518_phy_writebits - write bits to a register
+ * m88e151x_phy_writebits - write bits to a register
  */
-void m88e1518_phy_writebits(struct phy_device *phydev,
+void m88e151x_phy_writebits(struct phy_device *phydev,
 			    u8 reg_num, u16 offset, u16 len, u16 data)
 {
 	u16 reg, mask;
@@ -323,7 +323,7 @@
 	phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg);
 }
 
-static int m88e1518_config(struct phy_device *phydev)
+static int m88e151x_config(struct phy_device *phydev)
 {
 	u16 reg;
 
@@ -350,11 +350,11 @@
 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 18);
 
 		/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
-		m88e1518_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL,
+		m88e151x_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL,
 				       0, 3, MIIM_88E151x_MODE_SGMII);
 
 		/* PHY reset is necessary after changing MODE[2:0] */
-		m88e1518_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL,
+		m88e151x_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL,
 				       MIIM_88E151x_RESET_OFFS, 1, 1);
 
 		/* Reset page selection */
@@ -401,33 +401,6 @@
 	return 0;
 }
 
-/* Marvell 88E1510 */
-static int m88e1510_config(struct phy_device *phydev)
-{
-	/* Select page 3 */
-	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE,
-		  MIIM_88E1118_PHY_LED_PAGE);
-
-	/* Enable INTn output on LED[2] */
-	m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_TIMER_CTRL,
-			       MIIM_88E151x_INT_EN_OFFS, 1, 1);
-
-	/* Configure LEDs */
-	/* LED[0]:0011 (ACT) */
-	m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_FUNC_CTRL,
-			       MIIM_88E151x_LED0_OFFS, MIIM_88E151x_LED_FLD_SZ,
-			       MIIM_88E151x_LED0_ACT);
-	/* LED[1]:0110 (LINK 100/1000 Mbps) */
-	m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_FUNC_CTRL,
-			       MIIM_88E151x_LED1_OFFS, MIIM_88E151x_LED_FLD_SZ,
-			       MIIM_88E151x_LED1_100_1000_LINK);
-
-	/* Reset page selection */
-	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0);
-
-	return m88e1518_config(phydev);
-}
-
 /* Marvell 88E1118 */
 static int m88e1118_config(struct phy_device *phydev)
 {
@@ -685,29 +658,12 @@
 	.shutdown = &genphy_shutdown,
 };
 
-static struct phy_driver M88E1510_driver = {
-	.name = "Marvell 88E1510",
+static struct phy_driver M88E151x_driver = {
+	.name = "Marvell 88E151x",
 	.uid = 0x1410dd0,
-	.mask = 0xfffffff,
-	.features = PHY_GBIT_FEATURES,
-	.config = &m88e1510_config,
-	.startup = &m88e1011s_startup,
-	.shutdown = &genphy_shutdown,
-	.readext = &m88e1xxx_phy_extread,
-	.writeext = &m88e1xxx_phy_extwrite,
-};
-
-/*
- * This supports:
- *  88E1518, uid 0x1410dd1
- *  88E1512, uid 0x1410dd4
- */
-static struct phy_driver M88E1518_driver = {
-	.name = "Marvell 88E1518",
-	.uid = 0x1410dd0,
-	.mask = 0xffffffa,
+	.mask = 0xffffff0,
 	.features = PHY_GBIT_FEATURES,
-	.config = &m88e1518_config,
+	.config = &m88e151x_config,
 	.startup = &m88e1011s_startup,
 	.shutdown = &genphy_shutdown,
 	.readext = &m88e1xxx_phy_extread,
@@ -744,8 +700,7 @@
 	phy_register(&M88E1118R_driver);
 	phy_register(&M88E1111S_driver);
 	phy_register(&M88E1011S_driver);
-	phy_register(&M88E1510_driver);
-	phy_register(&M88E1518_driver);
+	phy_register(&M88E151x_driver);
 	phy_register(&M88E1680_driver);
 
 	return 0;
diff --git a/drivers/net/phy/ncsi.c b/drivers/net/phy/ncsi.c
new file mode 100644
index 0000000..adc3ac0
--- /dev/null
+++ b/drivers/net/phy/ncsi.c
@@ -0,0 +1,897 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NC-SI protocol configuration
+ *
+ * Copyright (C) 2019, IBM Corporation.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <phy.h>
+#include <net/ncsi.h>
+#include <net/ncsi-pkt.h>
+#include <asm/unaligned.h>
+
+#define NCSI_PACKAGE_MAX 8
+#define NCSI_CHANNEL_MAX 31
+
+#define NCSI_PACKAGE_SHIFT      5
+#define NCSI_PACKAGE_INDEX(c)   (((c) >> NCSI_PACKAGE_SHIFT) & 0x7)
+#define NCSI_RESERVED_CHANNEL   0x1f
+#define NCSI_CHANNEL_INDEX(c)   ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
+#define NCSI_TO_CHANNEL(p, c)   (((p) << NCSI_PACKAGE_SHIFT) | (c))
+
+#define NCSI_PKT_REVISION       0x01
+
+#define NCSI_CAP_GENERIC_MASK	0x7f
+#define NCSI_CAP_BC_MASK	0x0f
+#define NCSI_CAP_MC_MASK	0x3f
+#define NCSI_CAP_AEN_MASK	0x07
+#define NCSI_CAP_VLAN_MASK	0x07
+
+static void ncsi_send_ebf(unsigned int np, unsigned int nc);
+static void ncsi_send_ae(unsigned int np, unsigned int nc);
+static void ncsi_send_gls(unsigned int np, unsigned int nc);
+static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd,
+			     uchar *payload, int len, bool wait);
+
+struct ncsi_channel {
+	unsigned int	id;
+	bool		has_link;
+
+	/* capabilities */
+	u32 cap_generic;
+	u32 cap_bc;
+	u32 cap_mc;
+	u32 cap_buffer;
+	u32 cap_aen;
+	u32 cap_vlan;
+
+	/* version information */
+	struct {
+		u32 version;            /* Supported BCD encoded NCSI version */
+		u32 alpha2;             /* Supported BCD encoded NCSI version */
+		u8  fw_name[12];        /* Firmware name string               */
+		u32 fw_version;         /* Firmware version                   */
+		u16 pci_ids[4];         /* PCI identification                 */
+		u32 mf_id;              /* Manufacture ID                     */
+	} version;
+
+};
+
+struct ncsi_package {
+	unsigned int		id;
+	unsigned int		n_channels;
+	struct ncsi_channel	*channels;
+};
+
+struct ncsi {
+	enum {
+		NCSI_PROBE_PACKAGE_SP,
+		NCSI_PROBE_PACKAGE_DP,
+		NCSI_PROBE_CHANNEL_SP,
+		NCSI_PROBE_CHANNEL,
+		NCSI_CONFIG,
+	} state;
+
+	unsigned int	pending_requests;
+	unsigned int	requests[256];
+	unsigned int	last_request;
+
+	unsigned int	current_package;
+	unsigned int	current_channel;
+
+	unsigned int		n_packages;
+	struct ncsi_package	*packages;
+};
+
+struct ncsi *ncsi_priv;
+
+bool ncsi_active(void)
+{
+	unsigned int np, nc;
+
+	if (!ncsi_priv)
+		return false;
+
+	np = ncsi_priv->current_package;
+	nc = ncsi_priv->current_channel;
+
+	if (ncsi_priv->state != NCSI_CONFIG)
+		return false;
+
+	return np < NCSI_PACKAGE_MAX && nc < NCSI_CHANNEL_MAX &&
+		ncsi_priv->packages[np].channels[nc].has_link;
+}
+
+static unsigned int cmd_payload(int cmd)
+{
+	switch (cmd) {
+	case NCSI_PKT_CMD_CIS:
+		return 0;
+	case NCSI_PKT_CMD_SP:
+		return 4;
+	case NCSI_PKT_CMD_DP:
+		return 0;
+	case NCSI_PKT_CMD_EC:
+		return 0;
+	case NCSI_PKT_CMD_DC:
+		return 4;
+	case NCSI_PKT_CMD_RC:
+		return 4;
+	case NCSI_PKT_CMD_ECNT:
+		return 0;
+	case NCSI_PKT_CMD_DCNT:
+		return 0;
+	case NCSI_PKT_CMD_AE:
+		return 8;
+	case NCSI_PKT_CMD_SL:
+		return 8;
+	case NCSI_PKT_CMD_GLS:
+		return 0;
+	case NCSI_PKT_CMD_SVF:
+		return 8;
+	case NCSI_PKT_CMD_EV:
+		return 4;
+	case NCSI_PKT_CMD_DV:
+		return 0;
+	case NCSI_PKT_CMD_SMA:
+		return 8;
+	case NCSI_PKT_CMD_EBF:
+		return 4;
+	case NCSI_PKT_CMD_DBF:
+		return 0;
+	case NCSI_PKT_CMD_EGMF:
+		return 4;
+	case NCSI_PKT_CMD_DGMF:
+		return 0;
+	case NCSI_PKT_CMD_SNFC:
+		return 4;
+	case NCSI_PKT_CMD_GVI:
+		return 0;
+	case NCSI_PKT_CMD_GC:
+		return 0;
+	case NCSI_PKT_CMD_GP:
+		return 0;
+	case NCSI_PKT_CMD_GCPS:
+		return 0;
+	case NCSI_PKT_CMD_GNS:
+		return 0;
+	case NCSI_PKT_CMD_GNPTS:
+		return 0;
+	case NCSI_PKT_CMD_GPS:
+		return 0;
+	default:
+		printf("NCSI: Unknown command 0x%02x\n", cmd);
+		return 0;
+	}
+}
+
+static u32 ncsi_calculate_checksum(unsigned char *data, int len)
+{
+	u32 checksum = 0;
+	int i;
+
+	for (i = 0; i < len; i += 2)
+		checksum += (((u32)data[i] << 8) | data[i + 1]);
+
+	checksum = (~checksum + 1);
+	return checksum;
+}
+
+static int ncsi_validate_rsp(struct ncsi_rsp_pkt *pkt, int payload)
+{
+	struct ncsi_rsp_pkt_hdr *hdr = &pkt->rsp;
+	u32 checksum, c_offset;
+	__be32 pchecksum;
+
+	if (hdr->common.revision != 1) {
+		printf("NCSI: 0x%02x response has unsupported revision 0x%x\n",
+		       hdr->common.type, hdr->common.revision);
+		return -1;
+	}
+
+	if (hdr->code != 0) {
+		printf("NCSI: 0x%02x response returns error %d\n",
+		       hdr->common.type, __be16_to_cpu(hdr->code));
+		if (ntohs(hdr->reason) == 0x05)
+			printf("(Invalid command length)\n");
+		return -1;
+	}
+
+	if (ntohs(hdr->common.length) != payload) {
+		printf("NCSI: 0x%02x response has incorrect length %d\n",
+		       hdr->common.type, hdr->common.length);
+		return -1;
+	}
+
+	c_offset = sizeof(struct ncsi_rsp_pkt_hdr) + payload - sizeof(checksum);
+	pchecksum = get_unaligned_be32((void *)hdr + c_offset);
+	if (pchecksum != 0) {
+		checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+						   c_offset);
+		if (pchecksum != checksum) {
+			printf("NCSI: 0x%02x response has invalid checksum\n",
+			       hdr->common.type);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void ncsi_rsp_ec(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (ncsi_priv->packages[np].channels[nc].cap_aen != 0)
+		ncsi_send_ae(np, nc);
+	/* else, done */
+}
+
+static void ncsi_rsp_ecnt(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_EC, NULL, 0, true);
+}
+
+static void ncsi_rsp_ebf(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_ECNT, NULL, 0, true);
+}
+
+static void ncsi_rsp_sma(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_ebf(np, nc);
+}
+
+static void ncsi_rsp_gc(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gc_pkt *gc = (struct ncsi_rsp_gc_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gc->rsp;
+	struct ncsi_channel *c;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	c = &ncsi_priv->packages[np].channels[nc];
+	c->cap_generic = ntohl(gc->cap) & NCSI_CAP_GENERIC_MASK;
+	c->cap_bc = ntohl(gc->bc_cap) & NCSI_CAP_BC_MASK;
+	c->cap_mc = ntohl(gc->mc_cap) & NCSI_CAP_MC_MASK;
+	c->cap_aen = ntohl(gc->aen_cap) & NCSI_CAP_AEN_MASK;
+	c->cap_vlan = ntohl(gc->vlan_mode) & NCSI_CAP_VLAN_MASK;
+
+	/* End of probe for this channel */
+}
+
+static void ncsi_rsp_gvi(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gvi_pkt *gvi = (struct ncsi_rsp_gvi_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gvi->rsp;
+	struct ncsi_channel *c;
+	unsigned int np, nc, i;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	c = &ncsi_priv->packages[np].channels[nc];
+	c->version.version = get_unaligned_be32(&gvi->ncsi_version);
+	c->version.alpha2 = gvi->alpha2;
+	memcpy(c->version.fw_name, gvi->fw_name, sizeof(c->version.fw_name));
+	c->version.fw_version = get_unaligned_be32(&gvi->fw_version);
+	for (i = 0; i < ARRAY_SIZE(c->version.pci_ids); i++)
+		c->version.pci_ids[i] = get_unaligned_be16(gvi->pci_ids + i);
+	c->version.mf_id = get_unaligned_be32(&gvi->mf_id);
+
+	if (ncsi_priv->state == NCSI_PROBE_CHANNEL)
+		ncsi_send_command(np, nc, NCSI_PKT_CMD_GC, NULL, 0, true);
+}
+
+static void ncsi_rsp_gls(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gls_pkt *gls = (struct ncsi_rsp_gls_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gls->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	ncsi_priv->packages[np].channels[nc].has_link =
+					!!(get_unaligned_be32(&gls->status));
+
+	if (ncsi_priv->state == NCSI_PROBE_CHANNEL)
+		ncsi_send_command(np, nc, NCSI_PKT_CMD_GVI, NULL, 0, true);
+}
+
+static void ncsi_rsp_cis(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	struct ncsi_package *package;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages) {
+		printf("NCSI: Mystery package 0x%02x from CIS\n", np);
+		return;
+	}
+
+	package = &ncsi_priv->packages[np];
+
+	if (nc < package->n_channels) {
+		/*
+		 * This is fine in general but in the current design we
+		 * don't send CIS commands to known channels.
+		 */
+		debug("NCSI: Duplicate channel 0x%02x\n", nc);
+		return;
+	}
+
+	package->channels = realloc(package->channels,
+				    sizeof(struct ncsi_channel) *
+				    (package->n_channels + 1));
+	if (!package->channels) {
+		printf("NCSI: Could not allocate memory for new channel\n");
+		return;
+	}
+
+	debug("NCSI: New channel 0x%02x\n", nc);
+
+	package->channels[nc].id = nc;
+	package->channels[nc].has_link = false;
+	package->n_channels++;
+
+	ncsi_send_gls(np, nc);
+}
+
+static void ncsi_rsp_dp(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	unsigned int np;
+
+	/* No action needed */
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	if (np >= ncsi_priv->n_packages)
+		debug("NCSI: DP response from unknown package %d\n", np);
+}
+
+static void ncsi_rsp_sp(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	unsigned int np;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+
+	if (np < ncsi_priv->n_packages) {
+		/* Already know about this package */
+		debug("NCSI: package 0x%02x selected\n", np);
+		return;
+	}
+
+	debug("NCSI: adding new package %d\n", np);
+
+	ncsi_priv->packages = realloc(ncsi_priv->packages,
+				      sizeof(struct ncsi_package) *
+				      (ncsi_priv->n_packages + 1));
+	if (!ncsi_priv->packages) {
+		printf("NCSI: could not allocate memory for new package\n");
+		return;
+	}
+
+	ncsi_priv->packages[np].id = np;
+	ncsi_priv->packages[np].n_channels = 0;
+	ncsi_priv->packages[np].channels = NULL;
+	ncsi_priv->n_packages++;
+}
+
+static void ncsi_update_state(struct ncsi_rsp_pkt_hdr *nh)
+{
+	bool timeout = !nh;
+	int np, nc;
+
+	switch (ncsi_priv->state) {
+	case NCSI_PROBE_PACKAGE_SP:
+		if (!timeout &&
+		    ncsi_priv->current_package + 1 < NCSI_PACKAGE_MAX) {
+			ncsi_priv->current_package++;
+		} else {
+			ncsi_priv->state = NCSI_PROBE_PACKAGE_DP;
+			ncsi_priv->current_package = 0;
+		}
+		return ncsi_probe_packages();
+	case NCSI_PROBE_PACKAGE_DP:
+		if (ncsi_priv->current_package + 1 < ncsi_priv->n_packages &&
+		    !timeout) {
+			ncsi_priv->current_package++;
+		} else {
+			if (!ncsi_priv->n_packages) {
+				printf("NCSI: no packages found\n");
+				net_set_state(NETLOOP_FAIL);
+				return;
+			}
+			printf("NCSI: probing channels\n");
+			ncsi_priv->state = NCSI_PROBE_CHANNEL_SP;
+			ncsi_priv->current_package = 0;
+			ncsi_priv->current_channel = 0;
+		}
+		return ncsi_probe_packages();
+	case NCSI_PROBE_CHANNEL_SP:
+		if (!timeout && nh->common.type == NCSI_PKT_RSP_SP) {
+			ncsi_priv->state = NCSI_PROBE_CHANNEL;
+			return ncsi_probe_packages();
+		}
+		printf("NCSI: failed to select package 0x%0x2 or timeout\n",
+		       ncsi_priv->current_package);
+		net_set_state(NETLOOP_FAIL);
+		break;
+	case NCSI_PROBE_CHANNEL:
+		// TODO only does package 0 for now
+		if (ncsi_priv->pending_requests == 0) {
+			np = ncsi_priv->current_package;
+			nc = ncsi_priv->current_channel;
+
+			/* Configure first channel that has link */
+			if (ncsi_priv->packages[np].channels[nc].has_link) {
+				ncsi_priv->state = NCSI_CONFIG;
+			} else if (ncsi_priv->current_channel + 1 <
+				   NCSI_CHANNEL_MAX) {
+				ncsi_priv->current_channel++;
+			} else {
+				// XXX As above only package 0
+				printf("NCSI: no channel found with link\n");
+				net_set_state(NETLOOP_FAIL);
+				return;
+			}
+			return ncsi_probe_packages();
+		}
+		break;
+	case NCSI_CONFIG:
+		if (ncsi_priv->pending_requests == 0) {
+			printf("NCSI: configuration done!\n");
+			net_set_state(NETLOOP_SUCCESS);
+		} else if (timeout) {
+			printf("NCSI: timeout during configure\n");
+			net_set_state(NETLOOP_FAIL);
+		}
+		break;
+	default:
+		printf("NCSI: something went very wrong, nevermind\n");
+		net_set_state(NETLOOP_FAIL);
+		break;
+	}
+}
+
+static void ncsi_timeout_handler(void)
+{
+	if (ncsi_priv->pending_requests)
+		ncsi_priv->pending_requests--;
+
+	ncsi_update_state(NULL);
+}
+
+static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd,
+			     uchar *payload, int len, bool wait)
+{
+	struct ncsi_pkt_hdr *hdr;
+	__be32 *pchecksum;
+	int eth_hdr_size;
+	u32 checksum;
+	uchar *pkt, *start;
+	int final_len;
+
+	pkt = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
+	if (!pkt)
+		return -ENOMEM;
+	start = pkt;
+
+	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_NCSI);
+	pkt += eth_hdr_size;
+
+	/* Set NCSI command header fields */
+	hdr = (struct ncsi_pkt_hdr *)pkt;
+	hdr->mc_id = 0;
+	hdr->revision = NCSI_PKT_REVISION;
+	hdr->id = ++ncsi_priv->last_request;
+	ncsi_priv->requests[ncsi_priv->last_request] = 1;
+	hdr->type = cmd;
+	hdr->channel = NCSI_TO_CHANNEL(np, nc);
+	hdr->length = htons(len);
+
+	if (payload && len)
+		memcpy(pkt + sizeof(struct ncsi_pkt_hdr), payload, len);
+
+	/* Calculate checksum */
+	checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+					   sizeof(*hdr) + len);
+	pchecksum = (__be32 *)((void *)(hdr + 1) + len);
+	put_unaligned_be32(htonl(checksum), pchecksum);
+
+	if (wait) {
+		net_set_timeout_handler(1000UL, ncsi_timeout_handler);
+		ncsi_priv->pending_requests++;
+	}
+
+	if (len < 26)
+		len = 26;
+	/* frame header, packet header, payload, checksum */
+	final_len = eth_hdr_size + sizeof(struct ncsi_cmd_pkt_hdr) + len + 4;
+
+	net_send_packet(start, final_len);
+	free(start);
+	return 0;
+}
+
+static void ncsi_handle_aen(struct ip_udp_hdr *ip, unsigned int len)
+{
+	struct ncsi_aen_pkt_hdr *hdr = (struct ncsi_aen_pkt_hdr *)ip;
+	int payload, i;
+	__be32 pchecksum;
+	u32 checksum;
+
+	switch (hdr->type) {
+	case NCSI_PKT_AEN_LSC:
+		printf("NCSI: link state changed\n");
+		payload = 12;
+		break;
+	case NCSI_PKT_AEN_CR:
+		printf("NCSI: re-configuration required\n");
+		payload = 4;
+		break;
+	case NCSI_PKT_AEN_HNCDSC:
+		/* Host notifcation - N/A but weird */
+		debug("NCSI: HNCDSC AEN received\n");
+		return;
+	default:
+		printf("%s: Invalid type 0x%02x\n", __func__, hdr->type);
+		return;
+	}
+
+	/* Validate packet */
+	if (hdr->common.revision != 1) {
+		printf("NCSI: 0x%02x response has unsupported revision 0x%x\n",
+		       hdr->common.type, hdr->common.revision);
+		return;
+	}
+
+	if (ntohs(hdr->common.length) != payload) {
+		printf("NCSI: 0x%02x response has incorrect length %d\n",
+		       hdr->common.type, hdr->common.length);
+		return;
+	}
+
+	pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4);
+	if (pchecksum != 0) {
+		checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+						   sizeof(*hdr) + payload - 4);
+		if (pchecksum != checksum) {
+			printf("NCSI: 0x%02x response has invalid checksum\n",
+			       hdr->common.type);
+			return;
+		}
+	}
+
+	/* Link or configuration lost - just redo the discovery process */
+	ncsi_priv->state = NCSI_PROBE_PACKAGE_SP;
+	for (i = 0; i < ncsi_priv->n_packages; i++)
+		free(ncsi_priv->packages[i].channels);
+	free(ncsi_priv->packages);
+	ncsi_priv->n_packages = 0;
+
+	ncsi_priv->current_package = NCSI_PACKAGE_MAX;
+	ncsi_priv->current_channel = NCSI_CHANNEL_MAX;
+
+	ncsi_probe_packages();
+}
+
+void ncsi_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip,
+		  unsigned int len)
+{
+	struct ncsi_rsp_pkt *pkt = (struct ncsi_rsp_pkt *)ip;
+	struct ncsi_rsp_pkt_hdr *nh = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	void (*handler)(struct ncsi_rsp_pkt *pkt) = NULL;
+	unsigned short payload;
+
+	if (ncsi_priv->pending_requests)
+		ncsi_priv->pending_requests--;
+
+	if (len < sizeof(struct ncsi_rsp_pkt_hdr)) {
+		printf("NCSI: undersized packet: %u bytes\n", len);
+		goto out;
+	}
+
+	if (nh->common.type == NCSI_PKT_AEN)
+		return ncsi_handle_aen(ip, len);
+
+	switch (nh->common.type) {
+	case NCSI_PKT_RSP_SP:
+		payload = 4;
+		handler = ncsi_rsp_sp;
+		break;
+	case NCSI_PKT_RSP_DP:
+		payload = 4;
+		handler = ncsi_rsp_dp;
+		break;
+	case NCSI_PKT_RSP_CIS:
+		payload = 4;
+		handler = ncsi_rsp_cis;
+		break;
+	case NCSI_PKT_RSP_GLS:
+		payload = 16;
+		handler = ncsi_rsp_gls;
+		break;
+	case NCSI_PKT_RSP_GVI:
+		payload = 40;
+		handler = ncsi_rsp_gvi;
+		break;
+	case NCSI_PKT_RSP_GC:
+		payload = 32;
+		handler = ncsi_rsp_gc;
+		break;
+	case NCSI_PKT_RSP_SMA:
+		payload = 4;
+		handler = ncsi_rsp_sma;
+		break;
+	case NCSI_PKT_RSP_EBF:
+		payload = 4;
+		handler = ncsi_rsp_ebf;
+		break;
+	case NCSI_PKT_RSP_ECNT:
+		payload = 4;
+		handler = ncsi_rsp_ecnt;
+		break;
+	case NCSI_PKT_RSP_EC:
+		payload = 4;
+		handler = ncsi_rsp_ec;
+		break;
+	case NCSI_PKT_RSP_AE:
+		payload = 4;
+		handler = NULL;
+		break;
+	default:
+		printf("NCSI: unsupported packet type 0x%02x\n",
+		       nh->common.type);
+		goto out;
+	}
+
+	if (ncsi_validate_rsp(pkt, payload) != 0) {
+		printf("NCSI: discarding invalid packet of type 0x%02x\n",
+		       nh->common.type);
+		goto out;
+	}
+
+	if (handler)
+		handler(pkt);
+out:
+	ncsi_update_state(nh);
+}
+
+static void ncsi_send_sp(unsigned int np)
+{
+	uchar payload[4] = {0};
+
+	ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_SP,
+			  (unsigned char *)&payload,
+			  cmd_payload(NCSI_PKT_CMD_SP), true);
+}
+
+static void ncsi_send_dp(unsigned int np)
+{
+	ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_DP, NULL, 0,
+			  true);
+}
+
+static void ncsi_send_gls(unsigned int np, unsigned int nc)
+{
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_GLS, NULL, 0, true);
+}
+
+static void ncsi_send_cis(unsigned int np, unsigned int nc)
+{
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_CIS, NULL, 0, true);
+}
+
+static void ncsi_send_ae(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_ae_pkt cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_aen);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_AE,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_AE), true);
+}
+
+static void ncsi_send_ebf(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_ebf_pkt cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_bc);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_EBF,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_EBF), true);
+}
+
+static void ncsi_send_sma(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_sma_pkt cmd;
+	unsigned char *addr, i;
+
+	addr = eth_get_ethaddr();
+	if (!addr) {
+		printf("NCSI: no MAC address configured\n");
+		return;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	for (i = 0; i < ARP_HLEN; i++)
+		cmd.mac[i] = addr[i];
+	cmd.index = 1;
+	cmd.at_e = 1;
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_SMA,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_SMA), true);
+}
+
+void ncsi_probe_packages(void)
+{
+	struct ncsi_package *package;
+	unsigned int np, nc;
+
+	switch (ncsi_priv->state) {
+	case NCSI_PROBE_PACKAGE_SP:
+		if (ncsi_priv->current_package == NCSI_PACKAGE_MAX)
+			ncsi_priv->current_package = 0;
+		ncsi_send_sp(ncsi_priv->current_package);
+		break;
+	case NCSI_PROBE_PACKAGE_DP:
+		ncsi_send_dp(ncsi_priv->current_package);
+		break;
+	case NCSI_PROBE_CHANNEL_SP:
+		if (ncsi_priv->n_packages > 0)
+			ncsi_send_sp(ncsi_priv->current_package);
+		else
+			printf("NCSI: no packages discovered, configuration not possible\n");
+		break;
+	case NCSI_PROBE_CHANNEL:
+		/* Kicks off chain of channel discovery */
+		ncsi_send_cis(ncsi_priv->current_package,
+			      ncsi_priv->current_channel);
+		break;
+	case NCSI_CONFIG:
+		for (np = 0; np < ncsi_priv->n_packages; np++) {
+			package = &ncsi_priv->packages[np];
+			for (nc = 0; nc < package->n_channels; nc++)
+				if (package->channels[nc].has_link)
+					break;
+			if (nc < package->n_channels)
+				break;
+		}
+		if (np == ncsi_priv->n_packages) {
+			printf("NCSI: no link available\n");
+			return;
+		}
+
+		printf("NCSI: configuring channel %d\n", nc);
+		ncsi_priv->current_package = np;
+		ncsi_priv->current_channel = nc;
+		/* Kicks off rest of configure chain */
+		ncsi_send_sma(np, nc);
+		break;
+	default:
+		printf("NCSI: unknown state 0x%x\n", ncsi_priv->state);
+	}
+}
+
+int ncsi_probe(struct phy_device *phydev)
+{
+	if (!phydev->priv) {
+		phydev->priv = malloc(sizeof(struct ncsi));
+		if (!phydev->priv)
+			return -ENOMEM;
+		memset(phydev->priv, 0, sizeof(struct ncsi));
+	}
+
+	ncsi_priv = phydev->priv;
+
+	return 0;
+}
+
+int ncsi_startup(struct phy_device *phydev)
+{
+	/* Set phydev parameters */
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	/* Normal phy reset is N/A */
+	phydev->flags |= PHY_FLAG_BROKEN_RESET;
+
+	/* Set initial probe state */
+	ncsi_priv->state = NCSI_PROBE_PACKAGE_SP;
+
+	/* No active package/channel yet */
+	ncsi_priv->current_package = NCSI_PACKAGE_MAX;
+	ncsi_priv->current_channel = NCSI_CHANNEL_MAX;
+
+	/* Pretend link works so the MAC driver sets final bits up */
+	phydev->link = true;
+
+	/* Set ncsi_priv so we can use it when called from net_loop() */
+	ncsi_priv = phydev->priv;
+
+	return 0;
+}
+
+int ncsi_shutdown(struct phy_device *phydev)
+{
+	printf("NCSI: Disabling package %d\n", ncsi_priv->current_package);
+	ncsi_send_dp(ncsi_priv->current_package);
+	return 0;
+}
+
+static struct phy_driver ncsi_driver = {
+	.uid		= PHY_NCSI_ID,
+	.mask		= 0xffffffff,
+	.name		= "NC-SI",
+	.features	= PHY_100BT_FEATURES | PHY_DEFAULT_FEATURES |
+				SUPPORTED_100baseT_Full | SUPPORTED_MII,
+	.probe		= ncsi_probe,
+	.startup	= ncsi_startup,
+	.shutdown	= ncsi_shutdown,
+};
+
+int phy_ncsi_init(void)
+{
+	phy_register(&ncsi_driver);
+	return 0;
+}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 80a7664..505d3ab 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -244,7 +244,7 @@
 			/*
 			 * Timeout reached ?
 			 */
-			if (i > PHY_ANEG_TIMEOUT) {
+			if (i > (PHY_ANEG_TIMEOUT / 50)) {
 				printf(" TIMEOUT !\n");
 				phydev->link = 0;
 				return -ETIMEDOUT;
@@ -545,6 +545,9 @@
 #ifdef CONFIG_PHY_FIXED
 	phy_fixed_init();
 #endif
+#ifdef CONFIG_PHY_NCSI
+	phy_ncsi_init();
+#endif
 #ifdef CONFIG_PHY_XILINX_GMII2RGMII
 	phy_xilinx_gmii2rgmii_init();
 #endif
@@ -1002,6 +1005,12 @@
 #ifdef CONFIG_PHY_FIXED
 	phydev = phy_connect_fixed(bus, dev, interface);
 #endif
+
+#ifdef CONFIG_PHY_NCSI
+	if (!phydev)
+		phydev = phy_device_create(bus, 0, PHY_NCSI_ID, false, interface);
+#endif
+
 #ifdef CONFIG_PHY_XILINX_GMII2RGMII
 	if (!phydev)
 		phydev = phy_connect_gmii2rgmii(bus, dev, interface);
diff --git a/env/mmc.c b/env/mmc.c
index b24c35c..251ad07 100644
--- a/env/mmc.c
+++ b/env/mmc.c
@@ -353,6 +353,7 @@
 	int ret;
 	int dev = mmc_get_env_dev();
 	const char *errmsg;
+	env_t *ep = NULL;
 
 	mmc = find_mmc_device(dev);
 
@@ -374,6 +375,10 @@
 	}
 
 	ret = env_import(buf, 1);
+	if (!ret) {
+		ep = (env_t *)buf;
+		gd->env_addr = (ulong)&ep->data;
+	}
 
 fini:
 	fini_mmc_for_env(mmc);
diff --git a/include/configs/sama5d3_xplained.h b/include/configs/sama5d3_xplained.h
index 696933d..42c1400 100644
--- a/include/configs/sama5d3_xplained.h
+++ b/include/configs/sama5d3_xplained.h
@@ -9,6 +9,7 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
+#include <linux/sizes.h>
 #include "at91-sama5_common.h"
 
 /*
@@ -64,7 +65,8 @@
 #define CONFIG_SYS_SPL_MALLOC_START	0x20080000
 #define CONFIG_SYS_SPL_MALLOC_SIZE	0x80000
 
-#define CONFIG_SYS_MONITOR_LEN		(512 << 10)
+/* size of u-boot.bin to load */
+#define CONFIG_SYS_MONITOR_LEN		(2 * SZ_512K)
 
 #ifdef CONFIG_SD_BOOT
 #define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION	1
diff --git a/include/net.h b/include/net.h
index 8a02c92..82500ee 100644
--- a/include/net.h
+++ b/include/net.h
@@ -356,6 +356,7 @@
 #define PROT_VLAN	0x8100		/* IEEE 802.1q protocol		*/
 #define PROT_IPV6	0x86dd		/* IPv6 over bluebook		*/
 #define PROT_PPP_SES	0x8864		/* PPPoE session messages	*/
+#define PROT_NCSI	0x88f8		/* NC-SI control packets        */
 
 #define IPPROTO_ICMP	 1	/* Internet Control Message Protocol	*/
 #define IPPROTO_UDP	17	/* User Datagram Protocol		*/
diff --git a/include/net/ncsi-pkt.h b/include/net/ncsi-pkt.h
new file mode 100644
index 0000000..a8e9def
--- /dev/null
+++ b/include/net/ncsi-pkt.h
@@ -0,0 +1,442 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright Gavin Shan, IBM Corporation 2016.
+ */
+
+#ifndef __NCSI_PKT_H__
+#define __NCSI_PKT_H__
+
+struct ncsi_pkt_hdr {
+	unsigned char mc_id;        /* Management controller ID */
+	unsigned char revision;     /* NCSI version - 0x01      */
+	unsigned char reserved;     /* Reserved                 */
+	unsigned char id;           /* Packet sequence number   */
+	unsigned char type;         /* Packet type              */
+	unsigned char channel;      /* Network controller ID    */
+	__be16        length;       /* Payload length           */
+	__be32        reserved1[2]; /* Reserved                 */
+};
+
+struct ncsi_cmd_pkt_hdr {
+	struct ncsi_pkt_hdr common; /* Common NCSI packet header */
+};
+
+struct ncsi_rsp_pkt_hdr {
+	struct ncsi_pkt_hdr common; /* Common NCSI packet header */
+	__be16              code;   /* Response code             */
+	__be16              reason; /* Response reason           */
+};
+
+struct ncsi_aen_pkt_hdr {
+	struct ncsi_pkt_hdr common;       /* Common NCSI packet header */
+	unsigned char       reserved2[3]; /* Reserved                  */
+	unsigned char       type;         /* AEN packet type           */
+};
+
+/* NCSI common command packet */
+struct ncsi_cmd_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[26];
+};
+
+struct ncsi_rsp_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
+	__be32                  checksum; /* Checksum        */
+	unsigned char           pad[22];
+};
+
+/* Select Package */
+struct ncsi_cmd_sp_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;            /* Command header */
+	unsigned char           reserved[3];    /* Reserved       */
+	unsigned char           hw_arbitration; /* HW arbitration */
+	__be32                  checksum;       /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Disable Channel */
+struct ncsi_cmd_dc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header  */
+	unsigned char           reserved[3]; /* Reserved        */
+	unsigned char           ald;         /* Allow link down */
+	__be32                  checksum;    /* Checksum        */
+	unsigned char           pad[22];
+};
+
+/* Reset Channel */
+struct ncsi_cmd_rc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  reserved; /* Reserved       */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* AEN Enable */
+struct ncsi_cmd_ae_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
+	unsigned char           reserved[3]; /* Reserved         */
+	unsigned char           mc_id;       /* MC ID            */
+	__be32                  mode;        /* AEN working mode */
+	__be32                  checksum;    /* Checksum         */
+	unsigned char           pad[18];
+};
+
+/* Set Link */
+struct ncsi_cmd_sl_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header    */
+	__be32                  mode;     /* Link working mode */
+	__be32                  oem_mode; /* OEM link mode     */
+	__be32                  checksum; /* Checksum          */
+	unsigned char           pad[18];
+};
+
+/* Set VLAN Filter */
+struct ncsi_cmd_svf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;       /* Command header    */
+	__be16                  reserved;  /* Reserved          */
+	__be16                  vlan;      /* VLAN ID           */
+	__be16                  reserved1; /* Reserved          */
+	unsigned char           index;     /* VLAN table index  */
+	unsigned char           enable;    /* Enable or disable */
+	__be32                  checksum;  /* Checksum          */
+	unsigned char           pad[18];
+};
+
+/* Enable VLAN */
+struct ncsi_cmd_ev_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
+	unsigned char           reserved[3]; /* Reserved         */
+	unsigned char           mode;        /* VLAN filter mode */
+	__be32                  checksum;    /* Checksum         */
+	unsigned char           pad[22];
+};
+
+/* Set MAC Address */
+struct ncsi_cmd_sma_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header          */
+	unsigned char           mac[6];   /* MAC address             */
+	unsigned char           index;    /* MAC table index         */
+	unsigned char           at_e;     /* Addr type and operation */
+	__be32                  checksum; /* Checksum                */
+	unsigned char           pad[18];
+};
+
+/* Enable Broadcast Filter */
+struct ncsi_cmd_ebf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  mode;     /* Filter mode    */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Enable Global Multicast Filter */
+struct ncsi_cmd_egmf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  mode;     /* Global MC mode */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Set NCSI Flow Control */
+struct ncsi_cmd_snfc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header    */
+	unsigned char           reserved[3]; /* Reserved          */
+	unsigned char           mode;        /* Flow control mode */
+	__be32                  checksum;    /* Checksum          */
+	unsigned char           pad[22];
+};
+
+/* OEM Request Command as per NCSI Specification */
+struct ncsi_cmd_oem_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header    */
+	__be32                  mfr_id;      /* Manufacture ID    */
+	unsigned char           data[];      /* OEM Payload Data  */
+};
+
+/* OEM Response Packet as per NCSI Specification */
+struct ncsi_rsp_oem_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;         /* Command header    */
+	__be32                  mfr_id;      /* Manufacture ID    */
+	unsigned char           data[];      /* Payload data      */
+};
+
+/* Mellanox Response Data */
+struct ncsi_rsp_oem_mlx_pkt {
+	unsigned char           cmd_rev;     /* Command Revision  */
+	unsigned char           cmd;         /* Command ID        */
+	unsigned char           param;       /* Parameter         */
+	unsigned char           optional;    /* Optional data     */
+	unsigned char           data[];      /* Data              */
+};
+
+/* Broadcom Response Data */
+struct ncsi_rsp_oem_bcm_pkt {
+	unsigned char           ver;         /* Payload Version   */
+	unsigned char           type;        /* OEM Command type  */
+	__be16                  len;         /* Payload Length    */
+	unsigned char           data[];      /* Cmd specific Data */
+};
+
+/* Get Link Status */
+struct ncsi_rsp_gls_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;        /* Response header   */
+	__be32                  status;     /* Link status       */
+	__be32                  other;      /* Other indications */
+	__be32                  oem_status; /* OEM link status   */
+	__be32                  checksum;
+	unsigned char           pad[10];
+};
+
+/* Get Version ID */
+struct ncsi_rsp_gvi_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;          /* Response header */
+	__be32                  ncsi_version; /* NCSI version    */
+	unsigned char           reserved[3];  /* Reserved        */
+	unsigned char           alpha2;       /* NCSI version    */
+	unsigned char           fw_name[12];  /* f/w name string */
+	__be32                  fw_version;   /* f/w version     */
+	__be16                  pci_ids[4];   /* PCI IDs         */
+	__be32                  mf_id;        /* Manufacture ID  */
+	__be32                  checksum;
+};
+
+/* Get Capabilities */
+struct ncsi_rsp_gc_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;         /* Response header   */
+	__be32                  cap;         /* Capabilities      */
+	__be32                  bc_cap;      /* Broadcast cap     */
+	__be32                  mc_cap;      /* Multicast cap     */
+	__be32                  buf_cap;     /* Buffering cap     */
+	__be32                  aen_cap;     /* AEN cap           */
+	unsigned char           vlan_cnt;    /* VLAN filter count */
+	unsigned char           mixed_cnt;   /* Mix filter count  */
+	unsigned char           mc_cnt;      /* MC filter count   */
+	unsigned char           uc_cnt;      /* UC filter count   */
+	unsigned char           reserved[2]; /* Reserved          */
+	unsigned char           vlan_mode;   /* VLAN mode         */
+	unsigned char           channel_cnt; /* Channel count     */
+	__be32                  checksum;    /* Checksum          */
+};
+
+/* Get Parameters */
+struct ncsi_rsp_gp_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;          /* Response header       */
+	unsigned char           mac_cnt;      /* Number of MAC addr    */
+	unsigned char           reserved[2];  /* Reserved              */
+	unsigned char           mac_enable;   /* MAC addr enable flags */
+	unsigned char           vlan_cnt;     /* VLAN tag count        */
+	unsigned char           reserved1;    /* Reserved              */
+	__be16                  vlan_enable;  /* VLAN tag enable flags */
+	__be32                  link_mode;    /* Link setting          */
+	__be32                  bc_mode;      /* BC filter mode        */
+	__be32                  valid_modes;  /* Valid mode parameters */
+	unsigned char           vlan_mode;    /* VLAN mode             */
+	unsigned char           fc_mode;      /* Flow control mode     */
+	unsigned char           reserved2[2]; /* Reserved              */
+	__be32                  aen_mode;     /* AEN mode              */
+	unsigned char           mac[6];       /* Supported MAC addr    */
+	__be16                  vlan;         /* Supported VLAN tags   */
+	__be32                  checksum;     /* Checksum              */
+};
+
+/* Get Controller Packet Statistics */
+struct ncsi_rsp_gcps_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;            /* Response header            */
+	__be32                  cnt_hi;         /* Counter cleared            */
+	__be32                  cnt_lo;         /* Counter cleared            */
+	__be32                  rx_bytes;       /* Rx bytes                   */
+	__be32                  tx_bytes;       /* Tx bytes                   */
+	__be32                  rx_uc_pkts;     /* Rx UC packets              */
+	__be32                  rx_mc_pkts;     /* Rx MC packets              */
+	__be32                  rx_bc_pkts;     /* Rx BC packets              */
+	__be32                  tx_uc_pkts;     /* Tx UC packets              */
+	__be32                  tx_mc_pkts;     /* Tx MC packets              */
+	__be32                  tx_bc_pkts;     /* Tx BC packets              */
+	__be32                  fcs_err;        /* FCS errors                 */
+	__be32                  align_err;      /* Alignment errors           */
+	__be32                  false_carrier;  /* False carrier detection    */
+	__be32                  runt_pkts;      /* Rx runt packets            */
+	__be32                  jabber_pkts;    /* Rx jabber packets          */
+	__be32                  rx_pause_xon;   /* Rx pause XON frames        */
+	__be32                  rx_pause_xoff;  /* Rx XOFF frames             */
+	__be32                  tx_pause_xon;   /* Tx XON frames              */
+	__be32                  tx_pause_xoff;  /* Tx XOFF frames             */
+	__be32                  tx_s_collision; /* Single collision frames    */
+	__be32                  tx_m_collision; /* Multiple collision frames  */
+	__be32                  l_collision;    /* Late collision frames      */
+	__be32                  e_collision;    /* Excessive collision frames */
+	__be32                  rx_ctl_frames;  /* Rx control frames          */
+	__be32                  rx_64_frames;   /* Rx 64-bytes frames         */
+	__be32                  rx_127_frames;  /* Rx 65-127 bytes frames     */
+	__be32                  rx_255_frames;  /* Rx 128-255 bytes frames    */
+	__be32                  rx_511_frames;  /* Rx 256-511 bytes frames    */
+	__be32                  rx_1023_frames; /* Rx 512-1023 bytes frames   */
+	__be32                  rx_1522_frames; /* Rx 1024-1522 bytes frames  */
+	__be32                  rx_9022_frames; /* Rx 1523-9022 bytes frames  */
+	__be32                  tx_64_frames;   /* Tx 64-bytes frames         */
+	__be32                  tx_127_frames;  /* Tx 65-127 bytes frames     */
+	__be32                  tx_255_frames;  /* Tx 128-255 bytes frames    */
+	__be32                  tx_511_frames;  /* Tx 256-511 bytes frames    */
+	__be32                  tx_1023_frames; /* Tx 512-1023 bytes frames   */
+	__be32                  tx_1522_frames; /* Tx 1024-1522 bytes frames  */
+	__be32                  tx_9022_frames; /* Tx 1523-9022 bytes frames  */
+	__be32                  rx_valid_bytes; /* Rx valid bytes             */
+	__be32                  rx_runt_pkts;   /* Rx error runt packets      */
+	__be32                  rx_jabber_pkts; /* Rx error jabber packets    */
+	__be32                  checksum;       /* Checksum                   */
+};
+
+/* Get NCSI Statistics */
+struct ncsi_rsp_gns_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;           /* Response header         */
+	__be32                  rx_cmds;       /* Rx NCSI commands        */
+	__be32                  dropped_cmds;  /* Dropped commands        */
+	__be32                  cmd_type_errs; /* Command type errors     */
+	__be32                  cmd_csum_errs; /* Command checksum errors */
+	__be32                  rx_pkts;       /* Rx NCSI packets         */
+	__be32                  tx_pkts;       /* Tx NCSI packets         */
+	__be32                  tx_aen_pkts;   /* Tx AEN packets          */
+	__be32                  checksum;      /* Checksum                */
+};
+
+/* Get NCSI Pass-through Statistics */
+struct ncsi_rsp_gnpts_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;            /* Response header     */
+	__be32                  tx_pkts;        /* Tx packets          */
+	__be32                  tx_dropped;     /* Tx dropped packets  */
+	__be32                  tx_channel_err; /* Tx channel errors   */
+	__be32                  tx_us_err;      /* Tx undersize errors */
+	__be32                  rx_pkts;        /* Rx packets          */
+	__be32                  rx_dropped;     /* Rx dropped packets  */
+	__be32                  rx_channel_err; /* Rx channel errors   */
+	__be32                  rx_us_err;      /* Rx undersize errors */
+	__be32                  rx_os_err;      /* Rx oversize errors  */
+	__be32                  checksum;       /* Checksum            */
+};
+
+/* Get package status */
+struct ncsi_rsp_gps_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header             */
+	__be32                  status;   /* Hardware arbitration status */
+	__be32                  checksum;
+};
+
+/* Get package UUID */
+struct ncsi_rsp_gpuuid_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
+	unsigned char           uuid[16]; /* UUID            */
+	__be32                  checksum;
+};
+
+/* AEN: Link State Change */
+struct ncsi_aen_lsc_pkt {
+	struct ncsi_aen_pkt_hdr aen;        /* AEN header      */
+	__be32                  status;     /* Link status     */
+	__be32                  oem_status; /* OEM link status */
+	__be32                  checksum;   /* Checksum        */
+	unsigned char           pad[14];
+};
+
+/* AEN: Configuration Required */
+struct ncsi_aen_cr_pkt {
+	struct ncsi_aen_pkt_hdr aen;      /* AEN header */
+	__be32                  checksum; /* Checksum   */
+	unsigned char           pad[22];
+};
+
+/* AEN: Host Network Controller Driver Status Change */
+struct ncsi_aen_hncdsc_pkt {
+	struct ncsi_aen_pkt_hdr aen;      /* AEN header */
+	__be32                  status;   /* Status     */
+	__be32                  checksum; /* Checksum   */
+	unsigned char           pad[18];
+};
+
+/* NCSI packet revision */
+#define NCSI_PKT_REVISION	0x01
+
+/* NCSI packet commands */
+#define NCSI_PKT_CMD_CIS	0x00 /* Clear Initial State              */
+#define NCSI_PKT_CMD_SP		0x01 /* Select Package                   */
+#define NCSI_PKT_CMD_DP		0x02 /* Deselect Package                 */
+#define NCSI_PKT_CMD_EC		0x03 /* Enable Channel                   */
+#define NCSI_PKT_CMD_DC		0x04 /* Disable Channel                  */
+#define NCSI_PKT_CMD_RC		0x05 /* Reset Channel                    */
+#define NCSI_PKT_CMD_ECNT	0x06 /* Enable Channel Network Tx        */
+#define NCSI_PKT_CMD_DCNT	0x07 /* Disable Channel Network Tx       */
+#define NCSI_PKT_CMD_AE		0x08 /* AEN Enable                       */
+#define NCSI_PKT_CMD_SL		0x09 /* Set Link                         */
+#define NCSI_PKT_CMD_GLS	0x0a /* Get Link                         */
+#define NCSI_PKT_CMD_SVF	0x0b /* Set VLAN Filter                  */
+#define NCSI_PKT_CMD_EV		0x0c /* Enable VLAN                      */
+#define NCSI_PKT_CMD_DV		0x0d /* Disable VLAN                     */
+#define NCSI_PKT_CMD_SMA	0x0e /* Set MAC address                  */
+#define NCSI_PKT_CMD_EBF	0x10 /* Enable Broadcast Filter          */
+#define NCSI_PKT_CMD_DBF	0x11 /* Disable Broadcast Filter         */
+#define NCSI_PKT_CMD_EGMF	0x12 /* Enable Global Multicast Filter   */
+#define NCSI_PKT_CMD_DGMF	0x13 /* Disable Global Multicast Filter  */
+#define NCSI_PKT_CMD_SNFC	0x14 /* Set NCSI Flow Control            */
+#define NCSI_PKT_CMD_GVI	0x15 /* Get Version ID                   */
+#define NCSI_PKT_CMD_GC		0x16 /* Get Capabilities                 */
+#define NCSI_PKT_CMD_GP		0x17 /* Get Parameters                   */
+#define NCSI_PKT_CMD_GCPS	0x18 /* Get Controller Packet Statistics */
+#define NCSI_PKT_CMD_GNS	0x19 /* Get NCSI Statistics              */
+#define NCSI_PKT_CMD_GNPTS	0x1a /* Get NCSI Pass-throu Statistics   */
+#define NCSI_PKT_CMD_GPS	0x1b /* Get package status               */
+#define NCSI_PKT_CMD_OEM	0x50 /* OEM                              */
+#define NCSI_PKT_CMD_PLDM	0x51 /* PLDM request over NCSI over RBT  */
+#define NCSI_PKT_CMD_GPUUID	0x52 /* Get package UUID                 */
+
+/* NCSI packet responses */
+#define NCSI_PKT_RSP_CIS	(NCSI_PKT_CMD_CIS    + 0x80)
+#define NCSI_PKT_RSP_SP		(NCSI_PKT_CMD_SP     + 0x80)
+#define NCSI_PKT_RSP_DP		(NCSI_PKT_CMD_DP     + 0x80)
+#define NCSI_PKT_RSP_EC		(NCSI_PKT_CMD_EC     + 0x80)
+#define NCSI_PKT_RSP_DC		(NCSI_PKT_CMD_DC     + 0x80)
+#define NCSI_PKT_RSP_RC		(NCSI_PKT_CMD_RC     + 0x80)
+#define NCSI_PKT_RSP_ECNT	(NCSI_PKT_CMD_ECNT   + 0x80)
+#define NCSI_PKT_RSP_DCNT	(NCSI_PKT_CMD_DCNT   + 0x80)
+#define NCSI_PKT_RSP_AE		(NCSI_PKT_CMD_AE     + 0x80)
+#define NCSI_PKT_RSP_SL		(NCSI_PKT_CMD_SL     + 0x80)
+#define NCSI_PKT_RSP_GLS	(NCSI_PKT_CMD_GLS    + 0x80)
+#define NCSI_PKT_RSP_SVF	(NCSI_PKT_CMD_SVF    + 0x80)
+#define NCSI_PKT_RSP_EV		(NCSI_PKT_CMD_EV     + 0x80)
+#define NCSI_PKT_RSP_DV		(NCSI_PKT_CMD_DV     + 0x80)
+#define NCSI_PKT_RSP_SMA	(NCSI_PKT_CMD_SMA    + 0x80)
+#define NCSI_PKT_RSP_EBF	(NCSI_PKT_CMD_EBF    + 0x80)
+#define NCSI_PKT_RSP_DBF	(NCSI_PKT_CMD_DBF    + 0x80)
+#define NCSI_PKT_RSP_EGMF	(NCSI_PKT_CMD_EGMF   + 0x80)
+#define NCSI_PKT_RSP_DGMF	(NCSI_PKT_CMD_DGMF   + 0x80)
+#define NCSI_PKT_RSP_SNFC	(NCSI_PKT_CMD_SNFC   + 0x80)
+#define NCSI_PKT_RSP_GVI	(NCSI_PKT_CMD_GVI    + 0x80)
+#define NCSI_PKT_RSP_GC		(NCSI_PKT_CMD_GC     + 0x80)
+#define NCSI_PKT_RSP_GP		(NCSI_PKT_CMD_GP     + 0x80)
+#define NCSI_PKT_RSP_GCPS	(NCSI_PKT_CMD_GCPS   + 0x80)
+#define NCSI_PKT_RSP_GNS	(NCSI_PKT_CMD_GNS    + 0x80)
+#define NCSI_PKT_RSP_GNPTS	(NCSI_PKT_CMD_GNPTS  + 0x80)
+#define NCSI_PKT_RSP_GPS	(NCSI_PKT_CMD_GPS    + 0x80)
+#define NCSI_PKT_RSP_OEM	(NCSI_PKT_CMD_OEM    + 0x80)
+#define NCSI_PKT_RSP_PLDM	(NCSI_PKT_CMD_PLDM   + 0x80)
+#define NCSI_PKT_RSP_GPUUID	(NCSI_PKT_CMD_GPUUID + 0x80)
+
+/* NCSI response code/reason */
+#define NCSI_PKT_RSP_C_COMPLETED	0x0000 /* Command Completed        */
+#define NCSI_PKT_RSP_C_FAILED		0x0001 /* Command Failed           */
+#define NCSI_PKT_RSP_C_UNAVAILABLE	0x0002 /* Command Unavailable      */
+#define NCSI_PKT_RSP_C_UNSUPPORTED	0x0003 /* Command Unsupported      */
+#define NCSI_PKT_RSP_R_NO_ERROR		0x0000 /* No Error                 */
+#define NCSI_PKT_RSP_R_INTERFACE	0x0001 /* Interface not ready      */
+#define NCSI_PKT_RSP_R_PARAM		0x0002 /* Invalid Parameter        */
+#define NCSI_PKT_RSP_R_CHANNEL		0x0003 /* Channel not Ready        */
+#define NCSI_PKT_RSP_R_PACKAGE		0x0004 /* Package not Ready        */
+#define NCSI_PKT_RSP_R_LENGTH		0x0005 /* Invalid payload length   */
+#define NCSI_PKT_RSP_R_UNKNOWN		0x7fff /* Command type unsupported */
+
+/* NCSI AEN packet type */
+#define NCSI_PKT_AEN		0xFF /* AEN Packet               */
+#define NCSI_PKT_AEN_LSC	0x00 /* Link status change       */
+#define NCSI_PKT_AEN_CR		0x01 /* Configuration required   */
+#define NCSI_PKT_AEN_HNCDSC	0x02 /* HNC driver status change */
+
+#endif /* __NCSI_PKT_H__ */
diff --git a/include/net/ncsi.h b/include/net/ncsi.h
new file mode 100644
index 0000000..2800c84
--- /dev/null
+++ b/include/net/ncsi.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * NC-SI PHY
+ *
+ * Copyright (C) 2019, IBM Corporation.
+ */
+
+#include <common.h>
+#include <phy.h>
+
+bool ncsi_active(void);
+void ncsi_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip,
+		  unsigned int len);
+void ncsi_probe_packages(void);
diff --git a/include/phy.h b/include/phy.h
index 42cfc59..b5de14c 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -15,9 +15,12 @@
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/mdio.h>
+#include <log.h>
 #include <phy_interface.h>
 
 #define PHY_FIXED_ID		0xa5a55a5a
+#define PHY_NCSI_ID            0xbeefcafe
+
 /*
  * There is no actual id for this.
  * This is just a dummy id for gmii2rgmmi converter.
@@ -171,6 +174,11 @@
 {
 	struct mii_dev *bus = phydev->bus;
 
+	if (!bus || !bus->read) {
+		debug("%s: No bus configured\n", __func__);
+		return -1;
+	}
+
 	return bus->read(bus, phydev->addr, devad, regnum);
 }
 
@@ -179,6 +187,11 @@
 {
 	struct mii_dev *bus = phydev->bus;
 
+	if (!bus || !bus->read) {
+		debug("%s: No bus configured\n", __func__);
+		return -1;
+	}
+
 	return bus->write(bus, phydev->addr, devad, regnum, val);
 }
 
@@ -247,10 +260,15 @@
 #ifdef CONFIG_PHYLIB_10G
 extern struct phy_driver gen10g_driver;
 
-/* For now, XGMII is the only 10G interface */
+/*
+ * List all 10G interfaces here, the assumption being that PHYs on these
+ * interfaces are C45
+ */
 static inline int is_10g_interface(phy_interface_t interface)
 {
-	return interface == PHY_INTERFACE_MODE_XGMII;
+	return interface == PHY_INTERFACE_MODE_XGMII ||
+	       interface == PHY_INTERFACE_MODE_USXGMII ||
+	       interface == PHY_INTERFACE_MODE_XFI;
 }
 
 #endif
@@ -400,6 +418,7 @@
 int phy_xilinx_init(void);
 int phy_mscc_init(void);
 int phy_fixed_init(void);
+int phy_ncsi_init(void);
 int phy_xilinx_gmii2rgmii_init(void);
 
 int board_phy_config(struct phy_device *phydev);
diff --git a/include/phy_interface.h b/include/phy_interface.h
index 73f3a36..31ca72a 100644
--- a/include/phy_interface.h
+++ b/include/phy_interface.h
@@ -31,6 +31,7 @@
 	PHY_INTERFACE_MODE_XLAUI,
 	PHY_INTERFACE_MODE_CAUI2,
 	PHY_INTERFACE_MODE_CAUI4,
+	PHY_INTERFACE_MODE_NCSI,
 	PHY_INTERFACE_MODE_XFI,
 	PHY_INTERFACE_MODE_USXGMII,
 	PHY_INTERFACE_MODE_NONE,	/* Must be last */
@@ -60,6 +61,7 @@
 	[PHY_INTERFACE_MODE_XLAUI]		= "xlaui4",
 	[PHY_INTERFACE_MODE_CAUI2]		= "caui2",
 	[PHY_INTERFACE_MODE_CAUI4]		= "caui4",
+	[PHY_INTERFACE_MODE_NCSI]		= "NC-SI",
 	[PHY_INTERFACE_MODE_XFI]		= "xfi",
 	[PHY_INTERFACE_MODE_USXGMII]		= "usxgmii",
 	[PHY_INTERFACE_MODE_NONE]		= "",
diff --git a/net/tftp.c b/net/tftp.c
index 0240189..585eb6e 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -223,7 +223,7 @@
 
 	tosend = min(net_boot_file_size - offset, tosend);
 	(void)memcpy(dst, (void *)(image_save_addr + offset), tosend);
-	debug("%s: block=%d, offset=%ld, len=%d, tosend=%ld\n", __func__,
+	debug("%s: block=%u, offset=%lu, len=%u, tosend=%lu\n", __func__,
 	      block, offset, len, tosend);
 	return tosend;
 }