
On Wednesday, August 24, 2011 03:07:18 PM Ajay Bhargav wrote:
This patch adds support for Fast Ethernet Controller driver for Armada100 series.
Signed-off-by: Ajay Bhargav ajay.bhargav@einfochips.com
[...]
diff --git a/drivers/net/armada100_fec.c b/drivers/net/armada100_fec.c new file mode 100644 index 0000000..e36dca6 --- /dev/null +++ b/drivers/net/armada100_fec.c @@ -0,0 +1,761 @@ +/*
- (C) Copyright 2011
- eInfochips Ltd. <www.einfochips.com>
- Written-by: Ajay Bhargav ajay.bhargav@einfochips.com
- (C) Copyright 2010
- Marvell Semiconductor <www.marvell.com>
- Contributor: Mahavir Jain mjain@marvell.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- MA 02110-1301 USA
- */
+#include <common.h> +#include <net.h> +#include <malloc.h> +#include <miiphy.h> +#include <netdev.h> +#include <asm/types.h> +#include <asm/byteorder.h> +#include <linux/err.h> +#include <linux/mii.h> +#include <asm/io.h> +#include <asm/arch/armada100.h> +#include "armada100_fec.h"
+#define PHY_ADR_REQ 0xFF /* Magic number to read/write PHY address */
+#ifdef DEBUG +static int eth_dump_regs(struct eth_device *dev) +{
- struct armdfec_device *darmdfec = to_darmdfec(dev);
- struct armdfec_reg *regs = darmdfec->regs;
- unsigned int i = 0;
- printf("\noffset: phy_adr, value: 0x%x\n", readl(®s->phyadr));
- printf("offset: smi, value: 0x%x\n", readl(®s->smi));
- for (i = 0x400; i <= 0x4e4; i += 4)
printf("offset: 0x%x, value: 0x%x\n",
i, readl(ARMD1_FEC_BASE + i));
- return 0;
+} +#endif
+static int armdfec_phy_timeout(u32 reg, u32 flag, int cond) +{
- u32 timeout = PHY_WAIT_ITERATIONS;
- while (--timeout) {
if (cond && (readl(reg) & flag))
break;
else if (!cond && !(readl(reg) & flag))
You can read the register into some temporary variable so you don't need the readl() at two places.
break;
udelay(PHY_WAIT_MICRO_SECONDS);
- }
- return !timeout;
+}
+static int smi_reg_read(const char *devname, u8 phy_addr, u8 phy_reg,
u16 *value)
+{
- struct eth_device *dev = eth_get_dev_by_name(devname);
- struct armdfec_device *darmdfec = to_darmdfec(dev);
- struct armdfec_reg *regs = darmdfec->regs;
- u32 val, reg_data;
- if (phy_addr == PHY_ADR_REQ && phy_reg == PHY_ADR_REQ) {
reg_data = readl(®s->phyadr);
*value = (u16) (reg_data & 0x1f);
return 0;
- }
- /* check parameters */
- if (phy_addr > PHY_MASK) {
printf("Err..(%s) Invalid phy address: 0x%X\n",
__func__, phy_addr);
return -EINVAL;
- }
- if (phy_reg > PHY_MASK) {
printf("Err..(%s) Invalid register offset: 0x%X\n",
__func__, phy_reg);
return -EINVAL;
- }
- /* wait for the SMI register to become available */
- if (armdfec_phy_timeout((u32)®s->smi, SMI_BUSY, FALSE)) {
Adjust the function so you don't need the cast.
printf("Error (%s) PHY busy timeout\n", __func__);
return -1;
- }
- writel(phy_addr << 16 | phy_reg << 21 | SMI_OP_R, ®s->smi);
Parentheses missing maybe ?
- /* now wait for the data to be valid */
- if (armdfec_phy_timeout((u32)®s->smi, SMI_R_VALID, TRUE)) {
val = readl(®s->smi);
printf("Err (%s) PHY Read timeout, val=0x%x\n", __func__, val);
return -1;
- }
- val = readl(®s->smi);
- *value = val & 0xffff;
- return 0;
+}
+static int smi_reg_write(const char *devname,
u8 phy_addr, u8 phy_reg, u16 value)
+{
- struct eth_device *dev = eth_get_dev_by_name(devname);
- struct armdfec_device *darmdfec = to_darmdfec(dev);
- struct armdfec_reg *regs = darmdfec->regs;
- if (phy_addr == PHY_ADR_REQ && phy_reg == PHY_ADR_REQ) {
clrsetbits_le32(®s->phyadr, 0x1f, value & 0x1f);
return 0;
- }
- /* check parameters */
- if (phy_addr > PHY_MASK) {
printf("Err..(%s) Invalid phy address\n", __func__);
return -EINVAL;
- }
- if (phy_reg > PHY_MASK) {
printf("Err..(%s) Invalid register offset\n", __func__);
return -EINVAL;
- }
- /* wait for the SMI register to become available */
- if (armdfec_phy_timeout((u32)®s->smi, SMI_BUSY, FALSE)) {
printf("Error (%s) PHY busy timeout\n", __func__);
return -1;
- }
- writel(phy_addr << 16 | phy_reg << 21 | SMI_OP_W | (value & 0xffff),
®s->smi);
- return 0;
+}
+/*
- Abort any transmit and receive operations and put DMA
- in idle state. AT and AR bits are cleared upon entering
- in IDLE state. So poll those bits to verify operation.
- */
+static void abortdma(struct eth_device *dev) +{
- struct armdfec_device *darmdfec = to_darmdfec(dev);
- struct armdfec_reg *regs = darmdfec->regs;
- int delay;
- int maxretries = 40;
- do {
writel(SDMA_CMD_AR | SDMA_CMD_AT, ®s->sdma_cmd);
udelay(100);
delay = 10;
while ((readl(®s->sdma_cmd) &
(SDMA_CMD_AR | SDMA_CMD_AT))
&& delay-- > 0) {
udelay(10);
}
- } while (maxretries-- > 0 && delay <= 0);
Didn't I comment on this one in V1?
- if (maxretries <= 0)
printf("%s : DMA Stuck\n", __func__);
+}
[...]
+int armada100_fec_register() +{
- struct armdfec_device *darmdfec;
- struct eth_device *dev;
- int phy_adr;
- darmdfec = malloc(sizeof(struct armdfec_device));
- if (!darmdfec)
goto error;
- memset(darmdfec, 0, sizeof(struct armdfec_device));
- darmdfec->htpr = memalign(8, HASH_ADDR_TABLE_SIZE);
- if (!darmdfec->htpr)
goto error;
- darmdfec->p_rxdesc = (struct rx_desc *) memalign(PKTALIGN,
ARMDFEC_RXQ_DESC_ALIGNED_SIZE * RINGSZ + 1);
- if (!darmdfec->p_rxdesc)
goto error;
- darmdfec->p_rxbuf = (u8 *) memalign(PKTALIGN,
RINGSZ * PKTSIZE_ALIGN + 1);
Is the cast needed ? You should review your casts, most of them can be solved by using proper type!
- if (!darmdfec->p_rxbuf)
goto error;
- darmdfec->p_aligned_txbuf = memalign(8, PKTSIZE_ALIGN);
- if (!darmdfec->p_aligned_txbuf)
goto error;
- darmdfec->p_txdesc = (struct tx_desc *)
memalign(PKTALIGN, sizeof(struct tx_desc) + 1);
- if (!darmdfec->p_txdesc)
goto error;
- dev = &darmdfec->dev;
- /* Assign ARMADA100 Fast Ethernet Controller Base Address */
- darmdfec->regs = (void *) ARMD1_FEC_BASE;
Cheers!