Adds EMAC support for DM646x. With this patch only 10/100 mode
will work. A patch to support gigabit mode will be submitted
at a later point of time.

Signed-off-by: Chaithrika U.S <[EMAIL PROTECTED]>
---
 arch/arm/mach-davinci/clock.c   |    5 ++
 arch/arm/mach-davinci/devices.c |   46 +++++++++++++++++-
 drivers/net/davinci_emac.c      |  100 +++++++++++++++++++++++++++++++++++----
 3 files changed, 139 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 28acbc3..9c02446 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -289,6 +289,11 @@ static struct clk davinci_dm646x_clks[] = {
                .lpsc = DM646X_LPSC_AEMIF,
                .usecount = 1,
        },
+       {
+               .name = "EMACCLK",
+               .rate = &div_by_four,
+               .lpsc = DM646X_LPSC_EMAC,
+       },
 };
 
 #ifdef CONFIG_DAVINCI_RESET_CLOCKS
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index 7bb4a93..deef946 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -24,6 +24,7 @@
 #include <mach/hardware.h>
 #include <mach/emac.h>
 #include <mach/i2c.h>
+#include <mach/cpu.h>
 
 
 #if defined(CONFIG_I2C_DAVINCI) || defined(CONFIG_I2C_DAVINCI_MODULE)
@@ -112,6 +113,7 @@ static struct resource emac_resources[] = {
        },
        {
                .start = IRQ_EMACINT,
+               .end   = IRQ_EMACINT,
                .flags = IORESOURCE_IRQ,
        },
 };
@@ -128,6 +130,44 @@ static struct platform_device davinci_emac_device = {
        }
 };
 
+static struct resource dm646x_emac_resources[] = {
+       {
+               .start = DAVINCI_EMAC_CNTRL_REGS_BASE,
+               .end   = DAVINCI_EMAC_CNTRL_REGS_BASE + 0x4800,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_DM646X_EMACRXTHINT,
+               .end    = IRQ_DM646X_EMACRXTHINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_DM646X_EMACRXINT,
+               .end    = IRQ_DM646X_EMACRXINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_DM646X_EMACTXINT,
+               .end    = IRQ_DM646X_EMACTXINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_DM646X_EMACMISCINT,
+               .end    = IRQ_DM646X_EMACMISCINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dm646x_emac_device = {
+       .name = "davinci_emac",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(dm646x_emac_resources),
+       .resource = dm646x_emac_resources,
+       .dev = {
+               .platform_data = &emac_pdata,
+       }
+};
+
 void davinci_init_emac(char *mac_addr)
 {
        DECLARE_MAC_BUF(buf);
@@ -145,8 +185,10 @@ void davinci_init_emac(char *mac_addr)
                printk(KERN_WARNING "%s: using random MAC addr: %s\n",
                       __func__, print_mac(buf, emac_pdata.mac_addr));
        }
-
-       (void) platform_device_register(&davinci_emac_device);
+       if ((cpu_is_davinci_dm644x()))
+               (void) platform_device_register(&davinci_emac_device);
+       else
+               (void) platform_device_register(&dm646x_emac_device);
 }
 
 #else
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index be4cf2a..d1513e8 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -235,6 +235,10 @@ const char emac_version_string[] = "TI DaVinci EMAC Linux 
v6.0";
 #define EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC         (0xFF00)
 #define EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC         (0xFF)
 
+/** NOTE:: For DM646x the IN_VECTOR has changed */
+#define EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC   (1 << EMAC_DEF_RX_CH)
+#define EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC   (0x10000 << EMAC_DEF_TX_CH)
+
 /* CPPI bit positions */
 #define EMAC_CPPI_SOP_BIT              (1 << 31)
 #define EMAC_CPPI_EOP_BIT              (1 << 30)
@@ -263,6 +267,8 @@ const char emac_version_string[] = "TI DaVinci EMAC Linux 
v6.0";
 #define EMAC_TXINTMASKCLEAR    0x8C
 #define EMAC_MACINVECTOR       0x90
 
+#define EMAC_DM646X_MACEOIVECTOR       0x94
+
 #define EMAC_RXINTSTATRAW      0xA0
 #define EMAC_RXINTSTATMASKED   0xA4
 #define EMAC_RXINTMASKSET      0xA8
@@ -344,6 +350,13 @@ const char emac_version_string[] = "TI DaVinci EMAC Linux 
v6.0";
 #define EMAC_CTRL_EWCTL        (0x4)
 #define EMAC_CTRL_EWINTTCNT    (0x8)
 
+/* EMAC DM646X control module registers */
+#define EMAC_DM646X_CMRXINTEN  (0x14)
+#define EMAC_DM646X_CMTXINTEN  (0x18)
+
+/* EMAC EOI codes for C0 */
+#define EMAC_DM646X_MAC_EOI_C0_RXEN    (0x01)
+#define EMAC_DM646X_MAC_EOI_C0_TXEN    (0x02)
 
 /** net_buf_obj: EMAC network bufferdata structure
  *
@@ -1184,8 +1197,23 @@ static void emac_timer_cb(struct emac_priv *priv)
  */
 static void emac_int_disable(struct emac_priv *priv)
 {
-       /* Set DM644x control registers for interrupt control */
-       emac_ctrl_write(EMAC_CTRL_EWCTL, 0x0);
+       if (cpu_is_davinci_dm646x()) {
+               unsigned long flags;
+
+               local_irq_save(flags);
+
+               /* Program C0_Int_En to zero to turn off
+               * interrupts to the CPU */
+               emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0x0);
+               emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0x0);
+               /* NOTE: Rx Threshold and Misc interrupts are not disabled */
+
+               local_irq_restore(flags);
+
+       } else {
+               /* Set DM644x control registers for interrupt control */
+               emac_ctrl_write(EMAC_CTRL_EWCTL, 0x0);
+       }
 }
 
 /**
@@ -1197,8 +1225,28 @@ static void emac_int_disable(struct emac_priv *priv)
  */
 static void emac_int_enable(struct emac_priv *priv)
 {
-       /* Set DM644x control registers for interrupt control */
-       emac_ctrl_write(EMAC_CTRL_EWCTL, 0x1);
+       if (cpu_is_davinci_dm646x()) {
+               emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0xff);
+               emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0xff);
+
+               /* In addition to turning on interrupt Enable, we need
+                * ack by writing appropriate values to the EOI
+                * register */
+
+               /* NOTE: Rx Threshold and Misc interrupts are not enabled */
+
+               /* ack rxen only then a new pulse will be generated */
+               emac_write(EMAC_DM646X_MACEOIVECTOR,
+                       EMAC_DM646X_MAC_EOI_C0_RXEN);
+
+               /* ack txen- only then a new pulse will be generated */
+               emac_write(EMAC_DM646X_MACEOIVECTOR,
+                       EMAC_DM646X_MAC_EOI_C0_TXEN);
+
+       } else {
+               /* Set DM644x control registers for interrupt control */
+               emac_ctrl_write(EMAC_CTRL_EWCTL, 0x1);
+       }
 }
 
 /**
@@ -2323,6 +2371,7 @@ static int emac_hw_enable(struct emac_priv *priv)
  */
 static int emac_poll(struct napi_struct *napi, int budget)
 {
+       unsigned int mask;
        struct emac_priv *priv = container_of(napi, struct emac_priv, napi);
        struct net_device *ndev = priv->ndev;
        u32 status = 0;
@@ -2337,14 +2386,24 @@ static int emac_poll(struct napi_struct *napi, int 
budget)
        status = emac_read(EMAC_MACINVECTOR);
 
        /* Since we support only 1 TX ch, for now check all TX int mask */
-       if (status & EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC) {
+       mask = EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC;
+
+       if (cpu_is_davinci_dm646x())
+               mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC;
+
+       if (status & mask) {
                num_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH,
                                          EMAC_DEF_TX_MAX_SERVICE,
                                          &txpending);
        } /* TX processing */
 
-       /* Since we support only 1 TX ch, for now check all TX int mask */
-       if (status & EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC) {
+       /* Since we support only 1 RX ch, for now check all RX int mask */
+       mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC;
+
+       if (cpu_is_davinci_dm646x())
+               mask = EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC;
+
+       if (status & mask) {
                num_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH,
                                          budget, &rxpending);
        } /* RX processing */
@@ -2450,6 +2509,10 @@ typedef void (*timer_tick_func) (unsigned long);
 static int emac_dev_open(struct net_device *ndev)
 {
        u32 rc, cnt, ch;
+       struct resource *res;
+       int q, m;
+       int i = 0;
+       int k = 0;
        struct emac_priv *priv = netdev_priv(ndev);
 
        netif_carrier_off(ndev);
@@ -2496,9 +2559,14 @@ static int emac_dev_open(struct net_device *ndev)
        }
 
        /* Request IRQ */
-       if (request_irq(ndev->irq, emac_irq, IRQF_DISABLED, ndev->name, ndev)) {
-               dev_err(EMAC_DEV, "DaVinci EMAC: request_irq() failed");
-               return (-EBUSY);
+
+       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
+               for (i = res->start; i <= res->end; i++) {
+                       if (request_irq(i, emac_irq, IRQF_DISABLED,
+                                       ndev->name, ndev))
+                               goto rollback;
+               }
+               k++;
        }
 
        /* Start/Enable EMAC hardware */
@@ -2510,6 +2578,18 @@ static int emac_dev_open(struct net_device *ndev)
                dev_notice(EMAC_DEV, "DaVinci EMAC: Opened %s\n", ndev->name);
 
        return (0);
+
+rollback:
+
+       dev_err(EMAC_DEV, "DaVinci EMAC: request_irq() failed");
+
+       for (q = k; k >= 0; k--) {
+               for (m = i; m >= res->start; m--)
+                       free_irq(m, ndev);
+               res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k-1);
+               m = res->end;
+       }
+       return -EBUSY;
 }
 
 /**
-- 
1.5.4.1

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to