Commit 9ffd0b8e authored by Chaithrika U.S's avatar Chaithrika U.S Committed by Kevin Hilman

ARM: DaVinci: Adds EMAC support for DM646x

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: default avatarChaithrika U.S <chaithrika@ti.com>
parent 668c8747
......@@ -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,
},
};
static struct clk davinci_dm355_clks[] = {
{
......
......@@ -25,6 +25,7 @@
#include <mach/hardware.h>
#include <mach/emac.h>
#include <mach/i2c.h>
#include <mach/cpu.h>
static struct resource i2c_resources[] = {
{
......@@ -100,6 +101,7 @@ static struct resource emac_resources[] = {
},
{
.start = IRQ_EMACINT,
.end = IRQ_EMACINT,
.flags = IORESOURCE_IRQ,
},
};
......@@ -116,6 +118,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);
......@@ -133,8 +173,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
......
......@@ -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;
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment