[PATCH] lpc24xx/lpc17xx: Probe for ETHERNET PHY MII address

Pavel Pisa ppisa4lists at pikron.com
Fri Jan 3 13:39:54 UTC 2014


The default used address 0 is reserved by MII PHY specification
and some PHY do not respond to it. It is possible to use
SCANINC in MCFG register as another alternative.

The DP83848 PHY support is added as well.

Signed-off-by: Pavel Pisa <ppisa at pikron.com>
---

 Code requires testing on alredy supported LPC24xx
 and LPC17xx boards equipped by KSZ80X1RNL PHY.


 .../libbsp/arm/shared/lpc/network/lpc-ethernet.c   |   83 +++++++++++++++++---
 1 file changed, 74 insertions(+), 9 deletions(-)

diff --git a/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c 
b/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c
index ca43143..9136860 100644
--- a/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c
+++ b/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c
@@ -62,8 +62,11 @@
 #endif
 
 #define DEFAULT_PHY 0
+#define DEFAULT_SELECTED_PHY 0
 #define WATCHDOG_TIMEOUT 5
 
+static int lpc_eth_selected_phy = DEFAULT_SELECTED_PHY;
+
 typedef struct {
   uint32_t start;
   uint32_t control;
@@ -232,6 +235,8 @@ static volatile lpc_eth_controller *const lpc_eth =
 
 #define ETH_MCFG_CLOCK_SELECT(val) BSP_FLD32(val, 2, 4)
 
+#define ETH_MCFG_RESETMIIMGMT BSP_BIT32(15)
+
 /* ETH_MCMD */
 
 #define ETH_MCMD_READ BSP_BIT32(0)
@@ -1089,15 +1094,24 @@ static int lpc_eth_mdio_wait_for_not_busy(void)
     ++i;
   }
 
+  LPC_ETH_PRINTK("tx: lpc_eth_mdio_wait %s after %d\n",
+                 i != one_second? "succeed": "timeout", i);
+
   return i != one_second ? 0 : ETIMEDOUT;
 }
 
-static uint32_t lpc_eth_mdio_read_anlpar(void)
+static uint32_t lpc_eth_mdio_read_anlpar(int phy)
 {
-  uint32_t madr = ETH_MADR_REG(MII_ANLPAR) | ETH_MADR_PHY(DEFAULT_PHY);
+  uint32_t madr;
   uint32_t anlpar = 0;
   int eno = 0;
 
+  if (phy == DEFAULT_PHY)
+    phy = lpc_eth_selected_phy;
+
+  madr = ETH_MADR_REG(MII_ANLPAR) | ETH_MADR_PHY(phy);
+
+
   if (lpc_eth->madr != madr) {
     lpc_eth->madr = madr;
   }
@@ -1128,8 +1142,11 @@ static int lpc_eth_mdio_read(
 {
   int eno = 0;
 
-  if (phy == -1 || phy == 0) {
-    lpc_eth->madr = ETH_MADR_REG(reg) | ETH_MADR_PHY(DEFAULT_PHY);
+  if (phy == DEFAULT_PHY)
+    phy = lpc_eth_selected_phy;
+
+  if ((phy != -1) && (phy <= 31)) {
+    lpc_eth->madr = ETH_MADR_REG(reg) | ETH_MADR_PHY(phy);
     lpc_eth->mcmd = 0;
     lpc_eth->mcmd = ETH_MCMD_READ;
     eno = lpc_eth_mdio_wait_for_not_busy();
@@ -1153,8 +1170,11 @@ static int lpc_eth_mdio_write(
 {
   int eno = 0;
 
-  if (phy == -1 || phy == 0) {
-    lpc_eth->madr = ETH_MADR_REG(reg) | ETH_MADR_PHY(DEFAULT_PHY);
+  if (phy == DEFAULT_PHY)
+    phy = lpc_eth_selected_phy;
+
+  if ((phy != -1) || (phy != 0)) {
+    lpc_eth->madr = ETH_MADR_REG(reg) | ETH_MADR_PHY(phy);
     lpc_eth->mwtd = val;
     eno = lpc_eth_mdio_wait_for_not_busy();
   } else {
@@ -1182,6 +1202,7 @@ static int lpc_eth_phy_get_id(uint32_t *id)
 }
 
 #define PHY_KSZ80X1RNL 0x221550
+#define PHY_DP83848    0x20005c90
 
 typedef struct {
   unsigned reg;
@@ -1230,9 +1251,41 @@ static const lpc_eth_phy_action lpc_eth_phy_up_post_action_KSZ80X1RNL [] = {
   { 0x10, 0x10, 0 }
 };
 
+#ifdef LPC24XX_PIN_ETHERNET_POWER_DOWN
+static const lpc24xx_pin_range powrdown_pin_cfg[] = {
+  LPC24XX_PIN_ETHERNET_POWER_DOWN,
+  LPC24XX_PIN_TERMINAL
+};
+#endif /*LPC24XX_PIN_ETHERNET_POWER_DOWN*/
+
 static int lpc_eth_phy_up(lpc_eth_driver_entry *e)
 {
-  int eno = lpc_eth_phy_get_id(&e->phy_id);
+  int eno;
+  int retries = 64;
+  uint32_t val;
+
+#ifdef LPC24XX_PIN_ETHERNET_POWER_DOWN
+  const lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL;
+  if (powrdown_pin_cfg[0].value != terminal.value) {
+    int powrdown_pin = LPC24XX_IO_INDEX_BY_PORT(powrdown_pin_cfg[0].fields.port,
+                                                powrdown_pin_cfg[0].fields.port_bit);
+
+    lpc24xx_pin_config(&powrdown_pin_cfg[0], LPC24XX_PIN_SET_FUNCTION);
+    lpc24xx_gpio_config(powrdown_pin, LPC24XX_GPIO_OUTPUT);
+    lpc24xx_gpio_write(powrdown_pin, 1);
+  }
+#endif /*LPC24XX_PIN_ETHERNET_POWER_DOWN*/
+
+  lpc_eth_selected_phy = DEFAULT_SELECTED_PHY - 1;
+  do {
+    if (lpc_eth_selected_phy++ >= 32)
+      lpc_eth_selected_phy = 1;
+    rtems_task_wake_after(1);
+    eno = lpc_eth_phy_get_id(&e->phy_id);
+  } while (retries-- && (eno || (e->phy_id == 0xfffffff0) || (e->phy_id == 0)));
+
+  LPC_ETH_PRINTF("lpc_eth_phy_get_id: 0x%08" PRIx32 " from phy %d retries %d\n",
+                 e->phy_id, lpc_eth_selected_phy, retries);
 
   if (eno == 0) {
     switch (e->phy_id) {
@@ -1242,9 +1295,17 @@ static int lpc_eth_phy_up(lpc_eth_driver_entry *e)
           RTEMS_ARRAY_SIZE(lpc_eth_phy_up_pre_action_KSZ80X1RNL)
         );
         break;
+      case PHY_DP83848:
+        eno = lpc_eth_mdio_read(DEFAULT_PHY, NULL, 0x17, &val);
+        LPC_ETH_PRINTF("phy PHY_DP83848 RBR 0x%08" PRIx32 "\n", val);
+        /* val = 0x21; */
+        val = 0x32 ;
+        eno = lpc_eth_mdio_write(DEFAULT_PHY, NULL, 0x17, &val);
+
       case 0:
       case 0xfffffff0:
         eno = EIO;
+        lpc_eth_selected_phy = 0;
         break;
       default:
         break;
@@ -1327,7 +1388,11 @@ static int lpc_eth_up_or_down(lpc_eth_driver_entry *e, bool up)
     lpc_eth->mac1 = 0xf00;
 
     /* Initialize PHY */
-    lpc_eth->mcfg = ETH_MCFG_CLOCK_SELECT(0x7);
+    /* Clock value 10 (divide by 44 ) is safe on LPC178x up to 100 MHz AHB clock */
+    lpc_eth->mcfg = ETH_MCFG_CLOCK_SELECT(10) | ETH_MCFG_RESETMIIMGMT;
+    rtems_task_wake_after(1);
+    lpc_eth->mcfg = ETH_MCFG_CLOCK_SELECT(10);
+    rtems_task_wake_after(1);
     eno = lpc_eth_phy_up(e);
 
     if (eno == 0) {
@@ -1571,7 +1636,7 @@ static void lpc_eth_interface_watchdog(struct ifnet *ifp)
   lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc;
 
   if (e->state == LPC_ETH_STATE_UP) {
-    uint32_t anlpar = lpc_eth_mdio_read_anlpar();
+    uint32_t anlpar = lpc_eth_mdio_read_anlpar(DEFAULT_PHY);
 
     if (e->anlpar != anlpar) {
       bool full_duplex = false;
-- 
1.7.10.4




More information about the devel mailing list