Drivers/Net: Create PHY driver for Marvell platforms

MvPhyDxe implements support for Marvell 1512 PHYs. MARVELL_PHY_PROTOCOL is
produced in order to provide Status and Initialize functions to network
controller drivers. This driver requires MARVELL_MDIO_PROTOCOL to
communicate with PHY device.

Several PCDs were added to enable PHY ids and connection types
configuration. These are described in attached documentation.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Bartosz Szczepanek <bsz@semihalf.com>
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
diff --git a/Documentation/Marvell/PortingGuide/Phy.txt b/Documentation/Marvell/PortingGuide/Phy.txt
new file mode 100644
index 0000000..69dae02
--- /dev/null
+++ b/Documentation/Marvell/PortingGuide/Phy.txt
@@ -0,0 +1,45 @@
+PHY driver configuration

+------------------------

+MvPhyDxe provides basic initialization and status routines for Marvell PHYs.

+Currently only 1512 series PHYs are supported. Following PCDs are required:

+

+  gMarvellTokenSpaceGuid.PcdPhyConnectionTypes

+  (list of values corresponding to PHY_CONNECTION enum)

+  gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg

+  (boolean - if true, driver waits for autonegotiation on startup)

+  gMarvellTokenSpaceGuid.PcdPhyDeviceIds

+  (list of values corresponding to MV_PHY_DEVICE_ID enum)

+

+PHY_CONNECTION enum type is defined as follows:

+

+  typedef enum {

+0    PHY_CONNECTION_RGMII,

+1    PHY_CONNECTION_RGMII_ID,

+2    PHY_CONNECTION_RGMII_TXID,

+3    PHY_CONNECTION_RGMII_RXID,

+4    PHY_CONNECTION_SGMII,

+5    PHY_CONNECTION_RTBI,

+6    PHY_CONNECTION_XAUI,

+7    PHY_CONNECTION_RXAUI

+  } PHY_CONNECTION;

+

+MV_PHY_DEVICE_ID:

+

+  typedef enum {

+0    MV_PHY_DEVICE_1512,

+  } MV_PHY_DEVICE_ID;

+

+It should be extended when adding support for other PHY

+models.

+

+Thus in order to set RGMII for 1st PHY and SGMII for 2nd, PCD should be:

+

+  gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0x0, 0x4 }

+

+with disabled autonegotiation:

+

+  gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE

+

+assuming, that PHY models are 1512:

+

+  gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0x0, 0x0 }

diff --git a/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c b/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c
new file mode 100644
index 0000000..aeb6f7a
--- /dev/null
+++ b/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c
@@ -0,0 +1,438 @@
+/********************************************************************************

+Copyright (C) 2016 Marvell International Ltd.

+

+Marvell BSD License Option

+

+If you received this File from Marvell, you may opt to use, redistribute and/or

+modify this File under the following licensing terms.

+Redistribution and use in source and binary forms, with or without modification,

+are permitted provided that the following conditions are met:

+

+  * Redistributions of source code must retain the above copyright notice,

+    this list of conditions and the following disclaimer.

+

+  * Redistributions in binary form must reproduce the above copyright

+    notice, this list of conditions and the following disclaimer in the

+    documentation and/or other materials provided with the distribution.

+

+  * Neither the name of Marvell nor the names of its contributors may be

+    used to endorse or promote products derived from this software without

+    specific prior written permission.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND

+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR

+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON

+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+

+*******************************************************************************/

+

+#include <Protocol/DriverBinding.h>

+#include <Protocol/Mdio.h>

+#include <Protocol/MvPhy.h>

+

+#include <Library/BaseLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/IoLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/PcdLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiLib.h>

+

+#include "MvPhyDxe.h"

+

+#define TIMEOUT   500

+

+STATIC MARVELL_MDIO_PROTOCOL *Mdio;

+

+STATIC MV_PHY_DEVICE MvPhyDevices[] = {

+  { MV_PHY_DEVICE_1512, MvPhyInit1512 },

+  { 0, NULL }

+};

+

+EFI_STATUS

+MvPhyStatus (

+  IN CONST MARVELL_PHY_PROTOCOL *This,

+  IN PHY_DEVICE  *PhyDev

+  );

+

+EFI_STATUS

+MvPhyReset (

+  IN UINT32 PhyAddr

+  )

+{

+  UINT32 Reg = 0;

+  INTN timeout = TIMEOUT;

+

+  Mdio->Read(Mdio, PhyAddr, MII_BMCR, &Reg);

+  Reg |= BMCR_RESET;

+  Mdio->Write(Mdio, PhyAddr, MII_BMCR, Reg);

+

+  while ((Reg & BMCR_RESET) && timeout--) {

+    Mdio->Read(Mdio, PhyAddr, MII_BMCR, &Reg);

+    gBS->Stall(1000);

+  }

+

+  if (Reg & BMCR_RESET) {

+    DEBUG((DEBUG_ERROR, "PHY reset timed out\n"));

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+/* Marvell 88E1111S */

+EFI_STATUS

+MvPhyM88e1111sConfig (

+  IN PHY_DEVICE *PhyDev

+  )

+{

+  UINT32 Reg;

+

+  if ((PhyDev->Connection == PHY_CONNECTION_RGMII) ||

+      (PhyDev->Connection == PHY_CONNECTION_RGMII_ID) ||

+      (PhyDev->Connection == PHY_CONNECTION_RGMII_RXID) ||

+      (PhyDev->Connection == PHY_CONNECTION_RGMII_TXID)) {

+    Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, &Reg);

+

+    if ((PhyDev->Connection == PHY_CONNECTION_RGMII) ||

+      (PhyDev->Connection == PHY_CONNECTION_RGMII_ID)) {

+      Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);

+    } else if (PhyDev->Connection == PHY_CONNECTION_RGMII_RXID) {

+      Reg &= ~MIIM_88E1111_TX_DELAY;

+      Reg |= MIIM_88E1111_RX_DELAY;

+    } else if (PhyDev->Connection == PHY_CONNECTION_RGMII_TXID) {

+      Reg &= ~MIIM_88E1111_RX_DELAY;

+      Reg |= MIIM_88E1111_TX_DELAY;

+    }

+

+    Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, Reg);

+

+    Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg);

+

+    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;

+

+    Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg);

+  }

+

+  if (PhyDev->Connection == PHY_CONNECTION_SGMII) {

+    Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg);

+

+    Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);

+    Reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK;

+    Reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;

+

+    Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg);

+  }

+

+  if (PhyDev->Connection == PHY_CONNECTION_RTBI) {

+    Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, &Reg);

+    Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);

+    Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, Reg);

+

+    Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg);

+    Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |

+      MIIM_88E1111_HWCFG_FIBER_COPPER_RES);

+    Reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;

+    Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg);

+

+    /* Soft reset */

+    MvPhyReset(PhyDev->Addr);

+

+    Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg);

+    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;

+    Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg);

+  }

+

+  Mdio->Read(Mdio, PhyDev->Addr, MII_BMCR, &Reg);

+  Reg |= (BMCR_ANENABLE | BMCR_ANRESTART);

+  Reg &= ~BMCR_ISOLATE;

+  Mdio->Write(Mdio, PhyDev->Addr, MII_BMCR, Reg);

+

+  /* Soft reset */

+  MvPhyReset(PhyDev->Addr);

+

+  MvPhyReset(PhyDev->Addr);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+MvPhyParseStatus (

+  IN PHY_DEVICE *PhyDev

+  )

+{

+  UINT32 Data;

+  UINT32 Speed;

+

+  Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1xxx_PHY_STATUS, &Data);

+

+  if ((Data & MIIM_88E1xxx_PHYSTAT_LINK) &&

+    !(Data & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {

+    INTN i = 0;

+

+    DEBUG((DEBUG_ERROR,"MvPhyDxe: Waiting for PHY realtime link"));

+    while (!(Data & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {

+      if (i > PHY_AUTONEGOTIATE_TIMEOUT) {

+        DEBUG((DEBUG_ERROR," TIMEOUT !\n"));

+        PhyDev->LinkUp = FALSE;

+        break;

+      }

+

+      if ((i++ % 1000) == 0)

+        DEBUG((DEBUG_ERROR, "."));

+      gBS->Stall(1000);

+      Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1xxx_PHY_STATUS, &Data);

+    }

+    DEBUG((DEBUG_ERROR," done\n"));

+    gBS->Stall(500000);

+  } else {

+    if (Data & MIIM_88E1xxx_PHYSTAT_LINK) {

+      DEBUG((DEBUG_ERROR, "MvPhyDxe: link up, "));

+      PhyDev->LinkUp = TRUE;

+    } else {

+      DEBUG((DEBUG_ERROR, "MvPhyDxe: link down, "));

+      PhyDev->LinkUp = FALSE;

+    }

+  }

+

+  if (Data & MIIM_88E1xxx_PHYSTAT_DUPLEX) {

+    DEBUG((DEBUG_ERROR, "full duplex, "));

+    PhyDev->FullDuplex = TRUE;

+  } else {

+    DEBUG((DEBUG_ERROR, "half duplex, "));

+    PhyDev->FullDuplex = FALSE;

+  }

+

+  Speed = Data & MIIM_88E1xxx_PHYSTAT_SPEED;

+

+  switch (Speed) {

+  case MIIM_88E1xxx_PHYSTAT_GBIT:

+    DEBUG((DEBUG_ERROR, "speed 1000\n"));

+    PhyDev->Speed = SPEED_1000;

+    break;

+  case MIIM_88E1xxx_PHYSTAT_100:

+    DEBUG((DEBUG_ERROR, "speed 100\n"));

+    PhyDev->Speed = SPEED_100;

+    break;

+  default:

+    DEBUG((DEBUG_ERROR, "speed 10\n"));

+    PhyDev->Speed = SPEED_10;

+    break;

+  }

+

+  return EFI_SUCCESS;

+}

+

+STATIC

+VOID

+MvPhy1512WriteBits (

+  IN UINT32 PhyAddr,

+  IN UINT8 RegNum,

+  IN UINT16 Offset,

+  IN UINT16 Len,

+  IN UINT16 Data)

+{

+  UINT32 Reg, Mask;

+

+  if ((Len + Offset) >= 16)

+    Mask = 0 - (1 << Offset);

+  else

+    Mask = (1 << (Len + Offset)) - (1 << Offset);

+

+  Mdio->Read(Mdio, PhyAddr, RegNum, &Reg);

+

+  Reg &= ~Mask;

+  Reg |= Data << Offset;

+

+  Mdio->Write(Mdio, PhyAddr, RegNum, Reg);

+}

+

+STATIC

+EFI_STATUS

+MvPhyInit1512 (

+    IN CONST MARVELL_PHY_PROTOCOL *Snp,

+    IN UINT32 PhyAddr,

+    IN OUT PHY_DEVICE *PhyDev

+    )

+{

+  UINT32 Data;

+  INTN i;

+

+  if (PhyDev->Connection == PHY_CONNECTION_SGMII) {

+    /* Select page 0xff and update configuration registers according to

+     * Marvell Release Notes - Alaska 88E1510/88E1518/88E1512 Rev A0,

+     * Errata Section 3.1 - needed in SGMII mode.

+     */

+    Mdio->Write(Mdio, PhyAddr, 22, 0x00ff);

+    Mdio->Write(Mdio, PhyAddr, 17, 0x214B);

+    Mdio->Write(Mdio, PhyAddr, 16, 0x2144);

+    Mdio->Write(Mdio, PhyAddr, 17, 0x0C28);

+    Mdio->Write(Mdio, PhyAddr, 16, 0x2146);

+    Mdio->Write(Mdio, PhyAddr, 17, 0xB233);

+    Mdio->Write(Mdio, PhyAddr, 16, 0x214D);

+    Mdio->Write(Mdio, PhyAddr, 17, 0xCC0C);

+    Mdio->Write(Mdio, PhyAddr, 16, 0x2159);

+

+    /* Reset page selection and select page 0x12 */

+    Mdio->Write(Mdio, PhyAddr, 22, 0x0000);

+    Mdio->Write(Mdio, PhyAddr, 22, 0x0012);

+

+    /* Write HWCFG_MODE = SGMII to Copper */

+    MvPhy1512WriteBits(PhyAddr, 20, 0, 3, 1);

+

+    /* Phy reset - necessary after changing mode */

+    MvPhy1512WriteBits(PhyAddr, 20, 15, 1, 1);

+

+    /* Reset page selection */

+    Mdio->Write(Mdio, PhyAddr, 22, 0x0000);

+    gBS->Stall(100);

+  }

+

+  MvPhyM88e1111sConfig (PhyDev);

+

+  /* autonegotiation on startup is not always required */

+  if (!PcdGetBool (PcdPhyStartupAutoneg))

+    return EFI_SUCCESS;

+

+  Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data);

+

+  if ((Data & BMSR_ANEGCAPABLE) && !(Data & BMSR_ANEGCOMPLETE)) {

+

+    DEBUG((DEBUG_ERROR, "MvPhyDxe: Waiting for PHY auto negotiation... "));

+    for (i = 0; !(Data & BMSR_ANEGCOMPLETE); i++) {

+      if (i > PHY_ANEG_TIMEOUT) {

+        DEBUG((DEBUG_ERROR, "timeout\n"));

+        PhyDev->LinkUp = FALSE;

+        return EFI_TIMEOUT;

+      }

+

+      gBS->Stall(1000);  /* 1 ms */

+      Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data);

+    }

+    PhyDev->LinkUp = TRUE;

+    DEBUG((DEBUG_INFO, "MvPhyDxe: link up\n"));

+  } else {

+    Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data);

+

+    if (Data & BMSR_LSTATUS) {

+      PhyDev->LinkUp = TRUE;

+      DEBUG((DEBUG_INFO, "MvPhyDxe: link up\n"));

+    } else {

+      PhyDev->LinkUp = FALSE;

+      DEBUG((DEBUG_INFO, "MvPhyDxe: link down\n"));

+    }

+  }

+  MvPhyParseStatus (PhyDev);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+MvPhyInit (

+  IN CONST MARVELL_PHY_PROTOCOL *Snp,

+  IN UINT32 PhyAddr,

+  IN PHY_CONNECTION PhyConnection,

+  IN OUT PHY_DEVICE **OutPhyDev

+  )

+{

+  EFI_STATUS Status;

+  PHY_DEVICE *PhyDev;

+  UINT8 *DeviceIds;

+  INTN i;

+

+  Status = gBS->LocateProtocol (

+      &gMarvellMdioProtocolGuid,

+      NULL,

+      (VOID **) &Mdio

+      );

+  if (EFI_ERROR(Status))

+    return Status;

+

+  /* perform setup common for all PHYs */

+  PhyDev = AllocateZeroPool (sizeof (PHY_DEVICE));

+  PhyDev->Addr = PhyAddr;

+  PhyDev->Connection = PhyConnection;

+  DEBUG((DEBUG_INFO, "MvPhyDxe: PhyAddr is %d, connection %d\n",

+        PhyAddr, PhyConnection));

+  *OutPhyDev = PhyDev;

+

+  DeviceIds = PcdGetPtr (PcdPhyDeviceIds);

+  for (i = 0; i < PcdGetSize (PcdPhyDeviceIds); i++) {

+    /* find MvPhyDevices fitting entry */

+    if (MvPhyDevices[i].DevId == DeviceIds[i]) {

+      ASSERT (MvPhyDevices[i].DevInit != NULL);

+      /* proceed with PHY-specific initialization */

+      return MvPhyDevices[i].DevInit(Snp, PhyAddr, PhyDev);

+    }

+  }

+

+  /* if we are here, no matching DevId was found */

+  Status = EFI_INVALID_PARAMETER;

+  FreePool (PhyDev);

+  return Status;

+}

+

+EFI_STATUS

+MvPhyStatus (

+  IN CONST MARVELL_PHY_PROTOCOL *This,

+  IN PHY_DEVICE  *PhyDev

+  )

+{

+  UINT32 Data;

+

+  Mdio->Read(Mdio, PhyDev->Addr, MII_BMSR, &Data);

+  Mdio->Read(Mdio, PhyDev->Addr, MII_BMSR, &Data);

+

+  if ((Data & BMSR_LSTATUS) == 0) {

+    PhyDev->LinkUp = FALSE;

+  } else {

+    PhyDev->LinkUp = TRUE;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+MvPhyDxeInitialise (

+  IN EFI_HANDLE  ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+  MARVELL_PHY_PROTOCOL *Phy;

+  EFI_STATUS Status;

+  EFI_HANDLE Handle = NULL;

+

+  Phy = AllocateZeroPool (sizeof (MARVELL_PHY_PROTOCOL));

+  Phy->Status = MvPhyStatus;

+  Phy->Init = MvPhyInit;

+

+  Status = gBS->InstallMultipleProtocolInterfaces (

+                  &Handle,

+                  &gMarvellPhyProtocolGuid, Phy,

+                  NULL

+                  );

+

+  if (EFI_ERROR(Status)) {

+    DEBUG((DEBUG_ERROR, "Failed to install interfaces\n"));

+    return Status;

+  }

+  DEBUG((DEBUG_ERROR, "Succesfully installed protocol interfaces\n"));

+

+  return EFI_SUCCESS;

+}

diff --git a/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h b/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h
new file mode 100644
index 0000000..6bd06c5
--- /dev/null
+++ b/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h
@@ -0,0 +1,194 @@
+/********************************************************************************

+Copyright (C) 2016 Marvell International Ltd.

+

+Marvell BSD License Option

+

+If you received this File from Marvell, you may opt to use, redistribute and/or

+modify this File under the following licensing terms.

+Redistribution and use in source and binary forms, with or without modification,

+are permitted provided that the following conditions are met:

+

+  * Redistributions of source code must retain the above copyright notice,

+    this list of conditions and the following disclaimer.

+

+  * Redistributions in binary form must reproduce the above copyright

+    notice, this list of conditions and the following disclaimer in the

+    documentation and/or other materials provided with the distribution.

+

+  * Neither the name of Marvell nor the names of its contributors may be

+    used to endorse or promote products derived from this software without

+    specific prior written permission.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND

+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR

+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON

+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+

+*******************************************************************************/

+#ifndef __MV_PHY_DXE_H__

+#define __MV_PHY_DXE_H__

+

+#define MII_BMCR      0x00  /* Basic mode control Register */

+#define MII_BMSR      0x01  /* Basic mode status Register  */

+#define MII_PHYSID1      0x02  /* PHYS ID 1           */

+#define MII_PHYSID2      0x03  /* PHYS ID 2           */

+#define MII_ADVERTISE      0x04  /* Advertisement control Reg   */

+#define MII_LPA        0x05  /* Link partner ability Reg    */

+#define MII_EXPANSION      0x06  /* Expansion Register         */

+#define MII_CTRL1000      0x09  /* 1000BASE-T control         */

+#define MII_STAT1000      0x0a  /* 1000BASE-T status         */

+#define MII_ESTATUS      0x0f  /* Extended Status */

+#define MII_DCOUNTER      0x12  /* Disconnect counter         */

+#define MII_FCSCOUNTER      0x13  /* False carrier counter       */

+#define MII_NWAYTEST      0x14  /* N-way auto-neg test Reg     */

+#define MII_RERRCOUNTER     0x15  /* Receive error counter       */

+#define MII_SREVISION      0x16  /* Silicon revision         */

+#define MII_RESV1      0x17  /* Reserved...           */

+#define MII_LBRERROR      0x18  /* Lpback, rx, bypass error    */

+#define MII_PHYADDR      0x19  /* PHY address           */

+#define MII_RESV2      0x1a  /* Reserved...           */

+#define MII_TPISTATUS      0x1b  /* TPI status for 10mbps       */

+#define MII_NCONFIG      0x1c  /* Network interface config    */

+

+/* Basic mode control Register. */

+#define BMCR_RESV    0x003f  /* Unused...           */

+#define BMCR_SPEED1000    0x0040  /* MSB of Speed (1000)         */

+#define BMCR_CTST    0x0080  /* Collision test         */

+#define BMCR_FULLDPLX    0x0100  /* Full duplex           */

+#define BMCR_ANRESTART    0x0200  /* Auto negotiation restart    */

+#define BMCR_ISOLATE    0x0400  /* Disconnect DP83840 from MII */

+#define BMCR_PDOWN    0x0800  /* Powerdown the DP83840       */

+#define BMCR_ANENABLE    0x1000  /* Enable auto negotiation     */

+#define BMCR_SPEED100    0x2000  /* Select 100Mbps         */

+#define BMCR_LOOPBACK    0x4000  /* TXD loopback bits         */

+#define BMCR_RESET    0x8000  /* Reset the DP83840         */

+

+/* Basic mode status Register. */

+#define BMSR_ERCAP    0x0001  /* Ext-Reg capability         */

+#define BMSR_JCD    0x0002  /* Jabber detected         */

+#define BMSR_LSTATUS    0x0004  /* Link status           */

+#define BMSR_ANEGCAPABLE  0x0008  /* Able to do auto-negotiation */

+#define BMSR_RFAULT    0x0010  /* Remote fault detected       */

+#define BMSR_ANEGCOMPLETE  0x0020  /* Auto-negotiation complete   */

+#define BMSR_RESV    0x00c0  /* Unused...           */

+#define BMSR_ESTATEN    0x0100  /* Extended Status in R15 */

+#define BMSR_100HALF2    0x0200  /* Can do 100BASE-T2 HDX */

+#define BMSR_100FULL2    0x0400  /* Can do 100BASE-T2 FDX */

+#define BMSR_10HALF    0x0800  /* Can do 10mbps, half-duplex  */

+#define BMSR_10FULL    0x1000  /* Can do 10mbps, full-duplex  */

+#define BMSR_100HALF    0x2000  /* Can do 100mbps, half-duplex */

+#define BMSR_100FULL    0x4000  /* Can do 100mbps, full-duplex */

+#define BMSR_100BASE4    0x8000  /* Can do 100mbps, 4k packets  */

+

+#define PHY_ANEG_TIMEOUT 4000

+

+#define PHY_INTERFACE_MODE_RGMII 0

+#define PHY_INTERFACE_MODE_RGMII_ID 1

+#define PHY_INTERFACE_MODE_RGMII_RXID 2

+#define PHY_INTERFACE_MODE_RGMII_TXID 3

+#define PHY_INTERFACE_MODE_SGMII 4

+#define PHY_INTERFACE_MODE_RTBI 5

+

+#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

+

+typedef enum {

+  MV_PHY_DEVICE_1512

+} MV_PHY_DEVICE_ID;

+

+typedef

+EFI_STATUS

+(*MV_PHY_DEVICE_INIT) (

+    IN CONST MARVELL_PHY_PROTOCOL *Snp,

+    IN UINT32 PhyAddr,

+    IN OUT PHY_DEVICE *PhyDev

+    );

+

+typedef struct {

+  MV_PHY_DEVICE_ID DevId;

+  MV_PHY_DEVICE_INIT DevInit;

+} MV_PHY_DEVICE;

+

+STATIC

+EFI_STATUS

+MvPhyInit1512 (

+    IN CONST MARVELL_PHY_PROTOCOL *Snp,

+    IN UINT32 PhyAddr,

+    IN OUT PHY_DEVICE *PhyDev

+    );

+

+#endif

diff --git a/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf b/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
new file mode 100644
index 0000000..713eada
--- /dev/null
+++ b/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
@@ -0,0 +1,71 @@
+# Copyright (C) 2016 Marvell International Ltd.

+#

+# Marvell BSD License Option

+#

+# If you received this File from Marvell, you may opt to use, redistribute and/or

+# modify this File under the following licensing terms.

+# Redistribution and use in source and binary forms, with or without modification,

+# are permitted provided that the following conditions are met:

+#

+#  * Redistributions of source code must retain the above copyright notice,

+#    this list of conditions and the following disclaimer.

+#

+#  * Redistributions in binary form must reproduce the above copyright

+#    notice, this list of conditions and the following disclaimer in the

+#    documentation and/or other materials provided with the distribution.

+#

+#  * Neither the name of Marvell nor the names of its contributors may be

+#    used to endorse or promote products derived from this software without

+#    specific prior written permission.

+#

+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND

+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR

+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON

+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = MvPhyDxe

+  FILE_GUID                      = 5aac3843-d8d4-40ba-ae07-38967138509c

+  MODULE_TYPE                    = DXE_DRIVER

+  VERSION_STRING                 = 1.0

+  ENTRY_POINT                    = MvPhyDxeInitialise

+

+[Sources.common]

+  MvPhyDxe.c

+

+[Packages]

+  ArmPkg/ArmPkg.dec

+  ArmPlatformPkg/ArmPlatformPkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+  MdePkg/MdePkg.dec

+  OpenPlatformPkg/Platforms/Marvell/Marvell.dec

+

+[LibraryClasses]

+  BaseLib

+  BaseMemoryLib

+  DebugLib

+  IoLib

+  PcdLib

+  UefiBootServicesTableLib

+  UefiDriverEntryPoint

+  UefiLib

+

+[Protocols]

+  gMarvellMdioProtocolGuid

+  gMarvellPhyProtocolGuid

+

+[Pcd]

+  gMarvellTokenSpaceGuid.PcdPhyConnectionTypes

+  gMarvellTokenSpaceGuid.PcdPhyDeviceIds

+  gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg

+

+[Depex]

+  TRUE

diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec
index 9c53b8c..73102ed 100644
--- a/Platforms/Marvell/Marvell.dec
+++ b/Platforms/Marvell/Marvell.dec
@@ -181,6 +181,11 @@
 #MDIO

   gMarvellTokenSpaceGuid.PcdMdioBaseAddress|0|UINT64|0x3000043

 

+#PHY

+  gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0 }|VOID*|0x3000044

+  gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0 }|VOID*|0x3000095

+  gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE|BOOLEAN|0x3000070

+

 [Protocols]

   gMarvellEepromProtocolGuid               = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }}

   gMarvellMdioProtocolGuid                 = { 0x0d728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }}