use broken-out patches for the coldfire to make it easier to follow differences again...
[15.05/openwrt.git] / target / linux / coldfire / patches / 010-m5445x_fec.patch
diff --git a/target/linux/coldfire/patches/010-m5445x_fec.patch b/target/linux/coldfire/patches/010-m5445x_fec.patch
new file mode 100644 (file)
index 0000000..0a87bd4
--- /dev/null
@@ -0,0 +1,392 @@
+From c562ab80fe383e6fa49dbe38257421cf37f0e4b3 Mon Sep 17 00:00:00 2001
+From: Kurt Mahan <kmahan@freescale.com>
+Date: Wed, 31 Oct 2007 17:07:25 -0600
+Subject: [PATCH] MCF5445x FEC support.
+
+LTIBName: m5445x-fec
+Signed-off-by: Kurt Mahan <kmahan@freescale.com>
+---
+ drivers/net/Kconfig |    8 ++-
+ drivers/net/fec.c   |  207 ++++++++++++++++++++++++++++++++++++++++++++++----
+ drivers/net/fec.h   |    2 +-
+ 3 files changed, 198 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -1973,7 +1973,7 @@ config 68360_ENET
+ config FEC
+       bool "FEC ethernet controller (of ColdFire CPUs)"
+-      depends on M523x || M527x || M5272 || M528x || M520x
++      depends on M523x || M527x || M5272 || M528x || M520x || M54455
+       help
+         Say Y here if you want to use the built-in 10/100 Fast ethernet
+         controller on some Motorola ColdFire processors.
+@@ -1985,6 +1985,12 @@ config FEC2
+         Say Y here if you want to use the second built-in 10/100 Fast
+         ethernet controller on some Motorola ColdFire processors.
++config FEC_SHARED_PHY
++      bool "Shared PHY interface(on some ColdFire designs)"
++      depends on FEC2
++      help
++        Say Y here if both PHYs are controlled via a single channel.
++
+ config FEC_MPC52xx
+       tristate "MPC52xx FEC driver"
+       depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC
+--- a/drivers/net/fec.c
++++ b/drivers/net/fec.c
+@@ -51,7 +51,9 @@
+ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
+     defined(CONFIG_M5272) || defined(CONFIG_M528x) || \
+-    defined(CONFIG_M520x) || defined(CONFIG_M532x)
++    defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
++    defined(CONFIG_M54455)
++
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+ #include "fec.h"
+@@ -82,6 +84,11 @@ static unsigned int fec_hw[] = {
+       (MCF_MBAR+0x30000),
+ #elif defined(CONFIG_M532x)
+       (MCF_MBAR+0xfc030000),
++#elif defined(CONFIG_M54455)
++      (MCF_MBAR+0xfc030000),
++#if defined(CONFIG_FEC2)
++      (MCF_MBAR+0xfc034000),
++#endif
+ #else
+       &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec),
+ #endif
+@@ -172,7 +179,7 @@ typedef struct {
+  * account when setting it.
+  */
+ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+-    defined(CONFIG_M520x) || defined(CONFIG_M532x)
++    defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M54455)
+ #define       OPT_FRAME_SIZE  (PKT_MAXBUF_SIZE << 16)
+ #else
+ #define       OPT_FRAME_SIZE  0
+@@ -213,6 +220,7 @@ struct fec_enet_private {
+       uint    phy_speed;
+       phy_info_t const        *phy;
+       struct work_struct phy_task;
++      volatile fec_t  *phy_hwp;
+       uint    sequence_done;
+       uint    mii_phy_task_queued;
+@@ -349,7 +357,8 @@ fec_enet_start_xmit(struct sk_buff *skb,
+       if (bdp->cbd_bufaddr & 0x3) {
+               unsigned int index;
+               index = bdp - fep->tx_bd_base;
+-              memcpy(fep->tx_bounce[index], (void *) bdp->cbd_bufaddr, bdp->cbd_datlen);
++              memcpy(fep->tx_bounce[index],
++                     (void *)skb->data, bdp->cbd_datlen);
+               bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]);
+       }
+@@ -702,7 +711,7 @@ fec_enet_mii(struct net_device *dev)
+       uint            mii_reg;
+       fep = netdev_priv(dev);
+-      ep = fep->hwp;
++      ep = fep->phy_hwp;
+       mii_reg = ep->fec_mii_data;
+       spin_lock(&fep->lock);
+@@ -753,7 +762,7 @@ mii_queue(struct net_device *dev, int re
+                       mii_tail = mip;
+               } else {
+                       mii_head = mii_tail = mip;
+-                      fep->hwp->fec_mii_data = regval;
++                      fep->phy_hwp->fec_mii_data = regval;
+               }
+       } else {
+               retval = 1;
+@@ -1151,8 +1160,7 @@ static phy_info_t const phy_info_ks8721b
+ };
+ /* ------------------------------------------------------------------------- */
+-/* register definitions for the DP83848 */
+-
++/* register definitions for the DP83848 and DP83849 */
+ #define MII_DP8384X_PHYSTST    16  /* PHY Status Register */
+ static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev)
+@@ -1186,27 +1194,50 @@ static void mii_parse_dp8384x_sr2(uint m
+               *s |= PHY_STAT_FAULT;
+ }
++static phy_cmd_t const phy_cmd_dp8384x_ack_int[] = {
++              { mk_mii_end, }
++      };
++
++static phy_cmd_t const phy_cmd_dp8384x_shutdown[] = {
++              { mk_mii_end, }
++      };
++
+ static phy_info_t phy_info_dp83848= {
+-      0x020005c9,
+-      "DP83848",
++      .id = 0x020005c9,
++      .name = "DP83848",
+-      (const phy_cmd_t []) {  /* config */
++      .config = (const phy_cmd_t []) {  /* config */
+               { mk_mii_read(MII_REG_CR), mii_parse_cr },
+               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+               { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 },
+               { mk_mii_end, }
+       },
+-      (const phy_cmd_t []) {  /* startup - enable interrupts */
++      .startup = (const phy_cmd_t []) {  /* startup - enable interrupts */
+               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+               { mk_mii_read(MII_REG_SR), mii_parse_sr },
+               { mk_mii_end, }
+       },
+-      (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */
++      .ack_int = phy_cmd_dp8384x_ack_int,
++      .shutdown = phy_cmd_dp8384x_shutdown,
++};
++
++static phy_info_t phy_info_dp83849 = {
++      .id = 0x020005ca,
++      .name = "DP83849",
++
++      .config = (const phy_cmd_t []) {  /* config */
++              { mk_mii_read(MII_REG_CR), mii_parse_cr },
++              { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++              { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 },
+               { mk_mii_end, }
+       },
+-      (const phy_cmd_t []) {  /* shutdown */
++      .startup = (const phy_cmd_t []) {  /* startup - enable interrupts */
++              { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++              { mk_mii_read(MII_REG_SR), mii_parse_sr },
+               { mk_mii_end, }
+       },
++      .ack_int = phy_cmd_dp8384x_ack_int,
++      .shutdown = phy_cmd_dp8384x_shutdown,
+ };
+ /* ------------------------------------------------------------------------- */
+@@ -1218,6 +1249,7 @@ static phy_info_t const * const phy_info
+       &phy_info_am79c874,
+       &phy_info_ks8721bl,
+       &phy_info_dp83848,
++      &phy_info_dp83849,
+       NULL
+ };
+@@ -1799,6 +1831,138 @@ static void __inline__ fec_uncache(unsig
+ /* ------------------------------------------------------------------------- */
++#elif defined(CONFIG_M54455)
++/*
++ * Code specific for M54455
++ */
++
++static void __inline__ fec_request_intrs(struct net_device *dev)
++{
++      struct fec_enet_private *fep;
++      int b;
++      static const struct idesc {
++              char *name;
++              unsigned short irq;
++      } *idp, id[] = {
++          { "fec(TXF)", 36 },
++          { "fec(TXB)", 37 },
++          { "fec(TXFIFO)", 38 },
++          { "fec(TXCR)", 39 },
++          { "fec(RXF)", 40 },
++          { "fec(RXB)", 41 },
++          { "fec(MII)", 42 },
++          { "fec(LC)", 43 },
++          { "fec(HBERR)", 44 },
++          { "fec(GRA)", 45 },
++          { "fec(EBERR)", 46 },
++          { "fec(BABT)", 47 },
++          { "fec(BABR)", 48 },
++          { NULL },
++      };
++
++      fep = netdev_priv(dev);
++      b = (fep->index) ? 77 : 64;
++
++      /* Setup interrupt handlers. */
++      for (idp = id; idp->name; idp++) {
++              if (request_irq(b+idp->irq, fec_enet_interrupt, 0,
++                  idp->name, dev) != 0)
++                      printk(KERN_ERR "FEC: Could not alloc %s IRQ(%d)!\n",
++                              idp->name, b+idp->irq);
++      }
++
++      if (fep->index) {
++              /* Configure RMII */
++              MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC &
++                      MCF_GPIO_PAR_FEC_FEC1_MASK) |
++                      MCF_GPIO_PAR_FEC_FEC1_RMII_GPIO;
++      } else {
++              /* Configure RMII */
++              MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC &
++                      MCF_GPIO_PAR_FEC_FEC0_MASK) |
++                      MCF_GPIO_PAR_FEC_FEC0_RMII_GPIO;
++      }
++
++      /* Set up gpio outputs for MII lines on FEC0 */
++      MCF_GPIO_PAR_FECI2C |= (0 |
++              MCF_GPIO_PAR_FECI2C_MDIO0_MDIO0 |
++              MCF_GPIO_PAR_FECI2C_MDC0_MDC0);
++}
++
++static void __inline__ fec_set_mii(struct net_device *dev,
++      struct fec_enet_private *fep)
++{
++      volatile fec_t *fecp;
++
++      fecp = fep->hwp;
++      fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
++      fecp->fec_x_cntrl = 0x00;
++
++      /*
++       * Set MII speed to 2.5 MHz
++       */
++      fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
++      fecp->fec_mii_speed = fep->phy_speed;
++
++      fec_restart(dev, 0);
++}
++
++static void __inline__ fec_get_mac(struct net_device *dev)
++{
++      struct fec_enet_private *fep = netdev_priv(dev);
++      volatile fec_t *fecp;
++      unsigned char *iap, tmpaddr[ETH_ALEN];
++
++      fecp = fep->hwp;
++
++      if (FEC_FLASHMAC) {
++              /*
++               * Get MAC address from FLASH.
++               * If it is all 1's or 0's, use the default.
++               */
++              iap = FEC_FLASHMAC;
++              if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
++                  (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
++                      iap = fec_mac_default;
++              if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
++                  (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
++                      iap = fec_mac_default;
++      } else {
++              *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
++              *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
++              iap = &tmpaddr[0];
++      }
++
++      memcpy(dev->dev_addr, iap, ETH_ALEN);
++
++      /* Adjust MAC if using default MAC address */
++      if (iap == fec_mac_default)
++              dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] +
++                      fep->index;
++}
++
++static void __inline__ fec_enable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_disable_phy_intr(void)
++{
++}
++
++static void __inline__ fec_phy_ack_intr(void)
++{
++}
++
++static void __inline__ fec_localhw_setup(void)
++{
++}
++
++static void __inline__ fec_uncache(unsigned long addr)
++{
++}
++
++/* ------------------------------------------------------------------------- */
++
+ #else
+@@ -2305,7 +2469,7 @@ fec_set_mac_address(struct net_device *d
+ }
+-/* Initialize the FEC Ethernet on 860T (or ColdFire 5272).
++/* Initialize the FEC Ethernet.
+  */
+  /*
+   * XXX:  We need to clean up on failure exits here.
+@@ -2326,7 +2490,7 @@ int __init fec_enet_init(struct net_devi
+       /* Allocate memory for buffer descriptors.
+       */
+-      mem_addr = __get_free_page(GFP_KERNEL);
++      mem_addr = __get_free_page(GFP_DMA);
+       if (mem_addr == 0) {
+               printk("FEC: allocate descriptor memory failed?\n");
+               return -ENOMEM;
+@@ -2339,6 +2503,11 @@ int __init fec_enet_init(struct net_devi
+       fep->index = index;
+       fep->hwp = fecp;
+       fep->netdev = dev;
++#ifdef CONFIG_FEC_SHARED_PHY
++      fep->phy_hwp = (volatile fec_t *) fec_hw[index & ~1];
++#else
++      fep->phy_hwp = fecp;
++#endif
+       /* Whack a reset.  We should wait for this.
+       */
+@@ -2375,7 +2544,7 @@ int __init fec_enet_init(struct net_devi
+               /* Allocate a page.
+               */
+-              mem_addr = __get_free_page(GFP_KERNEL);
++              mem_addr = __get_free_page(GFP_DMA);
+               /* XXX: missing check for allocation failure */
+               fec_uncache(mem_addr);
+@@ -2400,7 +2569,7 @@ int __init fec_enet_init(struct net_devi
+       bdp = fep->tx_bd_base;
+       for (i=0, j=FEC_ENET_TX_FRPPG; i<TX_RING_SIZE; i++) {
+               if (j >= FEC_ENET_TX_FRPPG) {
+-                      mem_addr = __get_free_page(GFP_KERNEL);
++                      mem_addr = __get_free_page(GFP_DMA);
+                       j = 1;
+               } else {
+                       mem_addr += FEC_ENET_TX_FRSIZE;
+@@ -2462,7 +2631,11 @@ int __init fec_enet_init(struct net_devi
+        * remainder of the interface.
+        */
+       fep->phy_id_done = 0;
++#ifndef CONFIG_FEC_SHARED_PHY
+       fep->phy_addr = 0;
++#else
++      fep->phy_addr = fep->index;
++#endif
+       mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
+       index++;
+--- a/drivers/net/fec.h
++++ b/drivers/net/fec.h
+@@ -14,7 +14,7 @@
+ /****************************************************************************/
+ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+-    defined(CONFIG_M520x) || defined(CONFIG_M532x)
++    defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M54455)
+ /*
+  *    Just figures, Motorola would have to change the offsets for
+  *    registers in the same peripheral device on different models