summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorFrank Li <frank.li@freescale.com>2010-01-18 16:32:13 +0800
committerFrank Li <frank.li@freescale.com>2010-01-25 16:53:54 +0800
commitc77b09d0ede28f2d9ab940ed15bd16bdafb7ea26 (patch)
treed2bae95d336dcfb306f8607f15be01217511af87 /drivers
parent8a42ad8f7feea158bf3589a90981f7499032a5cd (diff)
downloadu-boot-imx-c77b09d0ede28f2d9ab940ed15bd16bdafb7ea26.zip
u-boot-imx-c77b09d0ede28f2d9ab940ed15bd16bdafb7ea26.tar.gz
u-boot-imx-c77b09d0ede28f2d9ab940ed15bd16bdafb7ea26.tar.bz2
ENGR00120206 iMX28 Enable Ethernet and MMC boot supportrel_imx_2.6.31_10.02.00
Enable Ethernet and MMC boot support for imx28-evk Signed-off-by: Frank Li <frank.li@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/imx_ssp_mmc.c371
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/mxc_enet.c742
4 files changed, 1115 insertions, 0 deletions
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 2902ba5..39a8913 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -34,6 +34,7 @@ COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
COBJS-$(CONFIG_FSL_MMC) += fsl_esdhc.o
COBJS-$(CONFIG_IMX_MMC) += imx_esdhc.o
+COBJS-$(CONFIG_IMX_SSP_MMC) += imx_ssp_mmc.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/mmc/imx_ssp_mmc.c b/drivers/mmc/imx_ssp_mmc.c
new file mode 100644
index 0000000..61a1d85
--- /dev/null
+++ b/drivers/mmc/imx_ssp_mmc.c
@@ -0,0 +1,371 @@
+/*
+ * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Terry Lv
+ *
+ * Copyright 2007, Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based vaguely on the pxa mmc code:
+ * (C) Copyright 2003
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/arch/mx28.h>
+#include <asm/arch/regs-ssp.h>
+#include <asm/arch/regs-clkctrl.h>
+
+#undef IMX_SSP_MMC_DEBUG
+
+extern void ssp_mmc_board_init(void);
+extern u32 ssp_mmc_is_wp(void);
+
+static inline void mdelay(unsigned long msec)
+{
+ unsigned long i;
+ for (i = 0; i < msec; i++)
+ udelay(1000);
+}
+
+static inline void sdelay(unsigned long sec)
+{
+ unsigned long i;
+ for (i = 0; i < sec; i++)
+ mdelay(1000);
+}
+
+/*
+ * Sends a command out on the bus. Takes the mmc pointer,
+ * a command pointer, and an optional data pointer.
+ */
+static int
+ssp_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+ int i;
+
+#ifdef IMX_SSP_MMC_DEBUG
+ printf("MMC: CMD%d\n", cmd->cmdidx);
+#endif
+
+ /* Check bus busy */
+ i = 0;
+ while (REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS) & (BM_SSP_STATUS_BUSY |
+ BM_SSP_STATUS_DATA_BUSY | BM_SSP_STATUS_CMD_BUSY)) {
+ mdelay(1);
+ i++;
+ if (i == 1000) {
+ printf("MMC: Bus busy timeout!\n");
+ return TIMEOUT;
+ }
+ }
+
+ /* See if card is present */
+ if (REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS) & BM_SSP_STATUS_CARD_DETECT) {
+ printf("MMC: No card detected!\n");
+ return NO_CARD_ERR;
+ }
+
+ /* Clear all control bits except bus width */
+ REG_CLR(REGS_SSP0_BASE, HW_SSP_CTRL0, 0xff3fffff);
+
+ /* Set up command */
+ if (!(cmd->resp_type & MMC_RSP_CRC))
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_IGNORE_CRC);
+ if (cmd->resp_type & MMC_RSP_PRESENT) /* Need to get response */
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_GET_RESP);
+ if (cmd->resp_type & MMC_RSP_136) /* It's a 136 bits response */
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_LONG_RESP);
+
+ /* Command index */
+ REG_WR(REGS_SSP0_BASE, HW_SSP_CMD0,
+ (REG_RD(REGS_SSP0_BASE, HW_SSP_CMD0) & ~BM_SSP_CMD0_CMD) |
+ (cmd->cmdidx << BP_SSP_CMD0_CMD));
+ /* Command argument */
+ REG_WR(REGS_SSP0_BASE, HW_SSP_CMD1, cmd->cmdarg);
+
+ /* Set up data */
+ if (data) {
+ /* READ or WRITE */
+ if (data->flags & MMC_DATA_READ) {
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0,
+ BM_SSP_CTRL0_READ);
+ } else if (ssp_mmc_is_wp()) {
+ printf("MMC: Can not write a locked card!\n");
+ return UNUSABLE_ERR;
+ }
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_DATA_XFER);
+ REG_WR(REGS_SSP0_BASE, HW_SSP_BLOCK_SIZE,
+ ((data->blocks - 1) <<
+ BP_SSP_BLOCK_SIZE_BLOCK_COUNT) |
+ ((ffs(data->blocksize) - 1) <<
+ BP_SSP_BLOCK_SIZE_BLOCK_SIZE));
+ REG_WR(REGS_SSP0_BASE, HW_SSP_XFER_SIZE,
+ data->blocksize * data->blocks);
+ }
+
+ /* Kick off the command */
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_WAIT_FOR_IRQ);
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_ENABLE);
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN);
+
+ /* Wait for the command to complete */
+ i = 0;
+ do {
+ mdelay(10);
+ if (i++ == 100) {
+ printf("MMC: Command %d busy\n", cmd->cmdidx);
+ break;
+ }
+ } while (REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS) &
+ BM_SSP_STATUS_CMD_BUSY);
+
+ /* Check command timeout */
+ if (REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS) &
+ BM_SSP_STATUS_RESP_TIMEOUT) {
+#ifdef IMX_SSP_MMC_DEBUG
+ printf("MMC: Command %d timeout\n", cmd->cmdidx);
+#endif
+ return TIMEOUT;
+ }
+
+ /* Check command errors */
+ if (REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS) &
+ (BM_SSP_STATUS_RESP_CRC_ERR | BM_SSP_STATUS_RESP_ERR)) {
+ printf("MMC: Command %d error (status 0x%08x)!\n",
+ cmd->cmdidx, REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS));
+ return COMM_ERR;
+ }
+
+ /* Copy response to response buffer */
+ if (cmd->resp_type & MMC_RSP_136) {
+ cmd->response[3] = REG_RD(REGS_SSP0_BASE, HW_SSP_SDRESP0);
+ cmd->response[2] = REG_RD(REGS_SSP0_BASE, HW_SSP_SDRESP1);
+ cmd->response[1] = REG_RD(REGS_SSP0_BASE, HW_SSP_SDRESP2);
+ cmd->response[0] = REG_RD(REGS_SSP0_BASE, HW_SSP_SDRESP3);
+ } else
+ cmd->response[0] = REG_RD(REGS_SSP0_BASE, HW_SSP_SDRESP0);
+
+ /* Return if no data to process */
+ if (!data)
+ return 0;
+
+ /* Process the data */
+ u32 xfer_cnt = data->blocksize * data->blocks;
+ u32 *tmp_ptr;
+
+ if (data->flags & MMC_DATA_READ) {
+ tmp_ptr = (u32 *)data->dest;
+ while (xfer_cnt > 0) {
+ if ((REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS) &
+ BM_SSP_STATUS_FIFO_EMPTY) == 0) {
+ *tmp_ptr++ = REG_RD(REGS_SSP0_BASE, HW_SSP_DATA);
+ xfer_cnt -= 4;
+ }
+ }
+ } else {
+ tmp_ptr = (u32 *)data->src;
+ while (xfer_cnt > 0) {
+ if ((REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS) &
+ BM_SSP_STATUS_FIFO_FULL) == 0) {
+ REG_WR(REGS_SSP0_BASE, HW_SSP_DATA, *tmp_ptr++);
+ xfer_cnt -= 4;
+ }
+ }
+ }
+
+ /* Check data errors */
+ if (REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS) &
+ (BM_SSP_STATUS_TIMEOUT | BM_SSP_STATUS_DATA_CRC_ERR |
+ BM_SSP_STATUS_FIFO_OVRFLW | BM_SSP_STATUS_FIFO_UNDRFLW)) {
+ printf("MMC: Data error with command %d (status 0x%08x)!\n",
+ cmd->cmdidx, REG_RD(REGS_SSP0_BASE, HW_SSP_STATUS));
+ return COMM_ERR;
+ }
+
+ return 0;
+}
+
+static void set_bit_clock(u32 clock)
+{
+ const u32 sspclk = 480000 * 18 / 29 / 1; /* 297931 KHz */
+ u32 divide, rate, tgtclk;
+
+ /*
+ * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
+ * CLOCK_DIVIDE has to be an even value from 2 to 254, and
+ * CLOCK_RATE could be any integer from 0 to 255.
+ */
+ clock /= 1000; /* KHz */
+ for (divide = 2; divide < 254; divide += 2) {
+ rate = sspclk / clock / divide;
+ if (rate <= 256)
+ break;
+ }
+
+ tgtclk = sspclk / divide / rate;
+ while (tgtclk > clock) {
+ rate++;
+ tgtclk = sspclk / divide / rate;
+ }
+ if (rate > 256)
+ rate = 256;
+
+ /* Always set timeout the maximum */
+ REG_WR(REGS_SSP0_BASE, HW_SSP_TIMING, BM_SSP_TIMING_TIMEOUT |
+ divide << BP_SSP_TIMING_CLOCK_DIVIDE |
+ (rate - 1) << BP_SSP_TIMING_CLOCK_RATE);
+
+#ifdef IMX_SSP_MMC_DEBUG
+ printf("MMC: Set clock rate to %d KHz (requested %d KHz)\n",
+ tgtclk, clock);
+#endif
+}
+
+static void ssp_mmc_set_ios(struct mmc *mmc)
+{
+ u32 regval;
+
+ /* Set the clock speed */
+ if (mmc->clock)
+ set_bit_clock(mmc->clock);
+
+ /* Set the bus width */
+ regval = REG_RD(REGS_SSP0_BASE, HW_SSP_CTRL0);
+ regval &= ~BM_SSP_CTRL0_BUS_WIDTH;
+ switch (mmc->bus_width) {
+ case 1:
+ regval |= (BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT <<
+ BP_SSP_CTRL0_BUS_WIDTH);
+ break;
+ case 4:
+ regval |= (BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT <<
+ BP_SSP_CTRL0_BUS_WIDTH);
+ break;
+ case 8:
+ regval |= (BV_SSP_CTRL0_BUS_WIDTH__EIGHT_BIT <<
+ BP_SSP_CTRL0_BUS_WIDTH);
+ }
+ REG_WR(REGS_SSP0_BASE, HW_SSP_CTRL0, regval);
+
+#ifdef IMX_SSP_MMC_DEBUG
+ printf("MMC: Set %d bits bus width\n", mmc->bus_width);
+#endif
+}
+
+static int ssp_mmc_init(struct mmc *mmc)
+{
+ u32 regval;
+
+ /* Board level init */
+ ssp_mmc_board_init();
+
+ /*
+ * Set up SSPCLK
+ */
+ /* Set REF_IO0 at 480 MHz */
+ regval = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0);
+ regval &= ~BM_CLKCTRL_FRAC0_IO0FRAC;
+ REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0,
+ regval | (29 << BP_CLKCTRL_FRAC0_IO0FRAC));
+ /* Enable REF_IO0 */
+ REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0,
+ BM_CLKCTRL_FRAC0_CLKGATEIO0);
+ /* Source SSPCLK from REF_IO0 */
+ REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ,
+ BM_CLKCTRL_CLKSEQ_BYPASS_SSP0);
+ /* Turn on SSPCLK */
+ REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_SSP0,
+ REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_SSP0) &
+ ~BM_CLKCTRL_SSP0_CLKGATE);
+ /* Set SSPCLK divide 1 */
+ regval = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_SSP0);
+ regval &= ~(BM_CLKCTRL_SSP0_DIV_FRAC_EN | BM_CLKCTRL_SSP0_DIV);
+ REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_SSP0,
+ regval | (1 << BP_CLKCTRL_SSP0_DIV));
+ /* Wait for new divide ready */
+ do {
+ udelay(10);
+ } while (REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_SSP0) &
+ BM_CLKCTRL_SSP0_BUSY);
+
+ /* Prepare for software reset */
+ REG_CLR(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_SFTRST);
+ REG_CLR(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_CLKGATE);
+ /* Assert reset */
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_SFTRST);
+ /* Wait for confirmation */
+ while (!(REG_RD(REGS_SSP0_BASE, HW_SSP_CTRL0) & BM_SSP_CTRL0_CLKGATE))
+ ;
+ /* Done */
+ REG_CLR(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_SFTRST);
+ REG_CLR(REGS_SSP0_BASE, HW_SSP_CTRL0, BM_SSP_CTRL0_CLKGATE);
+
+ /* 8 bits word length in MMC mode */
+ regval = REG_RD(REGS_SSP0_BASE, HW_SSP_CTRL1);
+ regval &= ~(BM_SSP_CTRL1_SSP_MODE | BM_SSP_CTRL1_WORD_LENGTH);
+ REG_WR(REGS_SSP0_BASE, HW_SSP_CTRL1, regval |
+ (BV_SSP_CTRL1_SSP_MODE__SD_MMC << BP_SSP_CTRL1_SSP_MODE) |
+ (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS <<
+ BP_SSP_CTRL1_WORD_LENGTH));
+
+ /* Set initial bit clock 400 KHz */
+ set_bit_clock(400000);
+
+ /* Send initial 74 clock cycles (185 us @ 400 KHz)*/
+ REG_SET(REGS_SSP0_BASE, HW_SSP_CMD0, BM_SSP_CMD0_CONT_CLKING_EN);
+ udelay(200);
+ REG_CLR(REGS_SSP0_BASE, HW_SSP_CMD0, BM_SSP_CMD0_CONT_CLKING_EN);
+
+ return 0;
+}
+
+int imx_ssp_mmc_initialize(bd_t *bis)
+{
+ struct mmc *mmc;
+
+ mmc = malloc(sizeof(struct mmc));
+
+ sprintf(mmc->name, "IMX_SSP_MMC");
+ mmc->send_cmd = ssp_mmc_send_cmd;
+ mmc->set_ios = ssp_mmc_set_ios;
+ mmc->init = ssp_mmc_init;
+
+ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_31_32 | MMC_VDD_30_31 |
+ MMC_VDD_29_30 | MMC_VDD_28_29 | MMC_VDD_27_28;
+
+ mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT |
+ MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+ /*
+ * SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz
+ * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
+ * CLOCK_DIVIDE has to be an even value from 2 to 254, and
+ * CLOCK_RATE could be any integer from 0 to 255.
+ */
+ mmc->f_min = 400000;
+ mmc->f_max = 148000000; /* 297.731 MHz / 2 */
+
+ mmc_register(mmc);
+
+ return 0;
+}
+
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 6ba00be..9318015 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -50,6 +50,7 @@ COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
COBJS-$(CONFIG_MPC512x_FEC) += mpc512x_fec.o
COBJS-$(CONFIG_MXC_FEC) += mxc_fec.o
+COBJS-$(CONFIG_MXC_ENET) += mxc_enet.o
COBJS-$(CONFIG_NATSEMI) += natsemi.o
COBJS-$(CONFIG_DRIVER_NE2000) += ne2000.o ne2000_base.o
COBJS-$(CONFIG_DRIVER_AX88796L) += ax88796.o ne2000_base.o
diff --git a/drivers/net/mxc_enet.c b/drivers/net/mxc_enet.c
new file mode 100644
index 0000000..edfbc1a
--- /dev/null
+++ b/drivers/net/mxc_enet.c
@@ -0,0 +1,742 @@
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <asm/arch/mx28.h>
+#include <asm/arch/regs-enet.h>
+#include <asm/arch/regs-clkctrl.h>
+
+/*
+ * Debug message switch
+ */
+#undef MXC_ENET_DEBUG
+
+/*
+ * Buffer descriptor control/status used by Ethernet receive.
+ */
+#define BD_ENET_RX_EMPTY ((ushort)0x8000)
+#define BD_ENET_RX_RO1 ((ushort)0x4000)
+#define BD_ENET_RX_WRAP ((ushort)0x2000)
+#define BD_ENET_RX_INTR ((ushort)0x1000)
+#define BD_ENET_RX_RO2 BD_ENET_RX_INTR
+#define BD_ENET_RX_LAST ((ushort)0x0800)
+#define BD_ENET_RX_FIRST ((ushort)0x0400)
+#define BD_ENET_RX_MISS ((ushort)0x0100)
+#define BD_ENET_RX_BC ((ushort)0x0080)
+#define BD_ENET_RX_MC ((ushort)0x0040)
+#define BD_ENET_RX_LG ((ushort)0x0020)
+#define BD_ENET_RX_NO ((ushort)0x0010)
+#define BD_ENET_RX_SH ((ushort)0x0008)
+#define BD_ENET_RX_CR ((ushort)0x0004)
+#define BD_ENET_RX_OV ((ushort)0x0002)
+#define BD_ENET_RX_CL ((ushort)0x0001)
+#define BD_ENET_RX_TR BD_ENET_RX_CL
+#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
+
+/*
+ * Buffer descriptor control/status used by Ethernet transmit.
+ */
+#define BD_ENET_TX_READY ((ushort)0x8000)
+#define BD_ENET_TX_PAD ((ushort)0x4000)
+#define BD_ENET_TX_TO1 BD_ENET_TX_PAD
+#define BD_ENET_TX_WRAP ((ushort)0x2000)
+#define BD_ENET_TX_INTR ((ushort)0x1000)
+#define BD_ENET_TX_TO2 BD_ENET_TX_INTR_
+#define BD_ENET_TX_LAST ((ushort)0x0800)
+#define BD_ENET_TX_TC ((ushort)0x0400)
+#define BD_ENET_TX_DEF ((ushort)0x0200)
+#define BD_ENET_TX_ABC BD_ENET_TX_DEF
+#define BD_ENET_TX_HB ((ushort)0x0100)
+#define BD_ENET_TX_LC ((ushort)0x0080)
+#define BD_ENET_TX_RL ((ushort)0x0040)
+#define BD_ENET_TX_RCMASK ((ushort)0x003c)
+#define BD_ENET_TX_UN ((ushort)0x0002)
+#define BD_ENET_TX_CSL ((ushort)0x0001)
+#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */
+
+/*
+ * Buffer descriptors
+ */
+typedef struct cpm_buf_desc {
+ ushort cbd_datlen; /* Data length in buffer */
+ ushort cbd_sc; /* Status and Control */
+ uint cbd_bufaddr; /* Buffer address in host memory */
+} cbd_t;
+
+/* ENET private information */
+struct enet_info_s {
+ int index;
+ u32 iobase;
+ int phy_addr;
+ int dup_spd;
+ char *phy_name;
+ int phyname_init;
+ cbd_t *rxbd; /* Rx BD */
+ cbd_t *txbd; /* Tx BD */
+ uint rxIdx;
+ uint txIdx;
+ char *rxbuf;
+ char *txbuf;
+ int initialized;
+ struct enet_info_s *next;
+};
+
+/* Register read/write struct */
+typedef struct enet {
+ u32 resv0; /* 0x0000 */
+ u32 eir; /* 0x0004 */
+ u32 eimr; /* 0x0008 */
+ u32 resv1; /* 0x000c */
+ u32 rdar; /* 0x0010 */
+ u32 tdar; /* 0x0014 */
+ u32 resv2[3]; /* 0x0018 */
+ u32 ecr; /* 0x0024 */
+ u32 resv3[6]; /* 0x0028 */
+ u32 mmfr; /* 0x0040 */
+ u32 mscr; /* 0x0044 */
+ u32 resv4[7]; /* 0x0048 */
+ u32 mibc; /* 0x0064 */
+ u32 resv5[7]; /* 0x0068 */
+ u32 rcr; /* 0x0084 */
+ u32 resv6[15]; /* 0x0088 */
+ u32 tcr; /* 0x00c4 */
+ u32 resv7[7]; /* 0x00c8 */
+ u32 palr; /* 0x00e4 */
+ u32 paur; /* 0x00e8 */
+ u32 opd; /* 0x00ec */
+ u32 resv8[10]; /* 0x00f0 */
+ u32 iaur; /* 0x0118 */
+ u32 ialr; /* 0x011c */
+ u32 gaur; /* 0x0120 */
+ u32 galr; /* 0x0124 */
+ u32 resv9[7]; /* 0x0128 */
+ u32 tfwr; /* 0x0144 */
+ u32 resv10; /* 0x0148 */
+ u32 frbr; /* 0x014c */
+ u32 frsr; /* 0x0150 */
+ u32 resv11[11]; /* 0x0154 */
+ u32 erdsr; /* 0x0180 */
+ u32 etdsr; /* 0x0184 */
+ u32 emrbr; /* 0x0188 */
+ /* Unused registers ... */
+} enet_t;
+
+/*
+ * Ethernet Transmit and Receive Buffers
+ */
+#define DBUF_LENGTH 1520
+#define RX_BUF_CNT (PKTBUFSRX)
+#define TX_BUF_CNT (RX_BUF_CNT)
+#define PKT_MINBUF_SIZE 64
+#define PKT_MAXBLR_SIZE 1520
+#define LAST_RX_BUF (RX_BUF_CNT - 1)
+#define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY)
+#define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST)
+
+/*
+ * MII definitions
+ */
+#define ENET_MII_ST 0x40000000
+#define ENET_MII_OP_OFF 28
+#define ENET_MII_OP_MASK 0x03
+#define ENET_MII_OP_RD 0x02
+#define ENET_MII_OP_WR 0x01
+#define ENET_MII_PA_OFF 23
+#define ENET_MII_PA_MASK 0xFF
+#define ENET_MII_RA_OFF 18
+#define ENET_MII_RA_MASK 0xFF
+#define ENET_MII_TA 0x00020000
+#define ENET_MII_DATA_OFF 0
+#define ENET_MII_DATA_MASK 0x0000FFFF
+
+#define ENET_MII_FRAME \
+ (ENET_MII_ST | ENET_MII_TA)
+
+#define ENET_MII_OP(x) \
+ (((x) & ENET_MII_OP_MASK) << ENET_MII_OP_OFF)
+
+#define ENET_MII_PA(pa) \
+ (((pa) & ENET_MII_PA_MASK) << ENET_MII_PA_OFF)
+
+#define ENET_MII_RA(ra) \
+ (((ra) & ENET_MII_RA_MASK) << ENET_MII_RA_OFF)
+
+#define ENET_MII_SET_DATA(v) \
+ (((v) & ENET_MII_DATA_MASK) << ENET_MII_DATA_OFF)
+
+#define ENET_MII_GET_DATA(v) \
+ (((v) >> ENET_MII_DATA_OFF) & ENET_MII_DATA_MASK)
+
+#define ENET_MII_READ(pa, ra) \
+ ((ENET_MII_FRAME | ENET_MII_OP(ENET_MII_OP_RD)) | \
+ ENET_MII_PA(pa) | ENET_MII_RA(ra))
+
+#define ENET_MII_WRITE(pa, ra, v) \
+ (ENET_MII_FRAME | ENET_MII_OP(ENET_MII_OP_WR) | \
+ ENET_MII_PA(pa) | ENET_MII_RA(ra) | ENET_MII_SET_DATA(v))
+
+#define ENET_MII_TIMEOUT 50000
+#define ENET_MII_TICK 2
+#define ENET_MII_PHYADDR 0x0
+
+/*
+ * Misc definitions
+ */
+#ifndef CONFIG_SYS_CACHELINE_SIZE
+#define CONFIG_SYS_CACHELINE_SIZE 32
+#endif
+
+#define ENET_RESET_DELAY 100
+#define ENET_MAX_TIMEOUT 50000
+#define ENET_TIMEOUT_TICKET 2
+
+#define __swap_32(x) ((((unsigned long)x) << 24) | \
+ ((0x0000FF00UL & ((unsigned long)x)) << 8) | \
+ ((0x00FF0000UL & ((unsigned long)x)) >> 8) | \
+ (((unsigned long)x) >> 24))
+
+/*
+ * Functions
+ */
+extern void enet_board_init(void);
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI)
+static struct enet_info_s enet_info[] = {
+ {
+ 0, /* index */
+ REGS_ENET_BASE, /* io base */
+#ifdef CONFIG_DISCOVER_PHY
+ -1, /* discover phy_addr */
+#else
+ ENET_MII_PHYADDR, /* phy_addr for MAC0 */
+#endif
+ 0, /* duplex and speed */
+ 0, /* phy name */
+ 0, /* phyname init */
+ 0, /* RX BD */
+ 0, /* TX BD */
+ 0, /* rx Index */
+ 0, /* tx Index */
+ 0, /* tx buffer */
+ 0 /* initialized flag */
+ }
+};
+
+static inline int __enet_mii_read(volatile enet_t *enetp, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ int waiting = ENET_MII_TIMEOUT;
+ if (enetp->eir & BM_ENET_MAC0_EIR_MII)
+ enetp->eir |= BM_ENET_MAC0_EIR_MII;
+
+ enetp->mmfr = ENET_MII_READ(addr, reg);
+ while (1) {
+ if (enetp->eir & BM_ENET_MAC0_EIR_MII) {
+ enetp->eir |= BM_ENET_MAC0_EIR_MII;
+ break;
+ }
+ if ((waiting--) <= 0)
+ return -1;
+ udelay(ENET_MII_TICK);
+ }
+ *value = ENET_MII_GET_DATA(enetp->mmfr);
+ return 0;
+}
+
+static inline int __enet_mii_write(volatile enet_t *enetp, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ int waiting = ENET_MII_TIMEOUT;
+ if (enetp->eir & BM_ENET_MAC0_EIR_MII)
+ enetp->eir |= BM_ENET_MAC0_EIR_MII;
+
+ enetp->mmfr = ENET_MII_WRITE(addr, reg, value);
+ while (1) {
+ if (enetp->eir & BM_ENET_MAC0_EIR_MII) {
+ enetp->eir |= BM_ENET_MAC0_EIR_MII;
+ break;
+ }
+ if ((waiting--) <= 0)
+ return -1;
+ udelay(ENET_MII_TICK);
+ }
+ return 0;
+}
+
+static int mxc_enet_mii_read(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct enet_info_s *info;
+ volatile enet_t *enetp;
+
+ if (!dev)
+ return -1;
+ info = dev->priv;
+ enetp = (enet_t *) (info->iobase);
+ return __enet_mii_read(enetp, addr, reg, value);
+}
+
+static int mxc_enet_mii_write(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct enet_info_s *info;
+ volatile enet_t *enetp;
+ if (!dev)
+ return -1;
+ info = dev->priv;
+ enetp = (enet_t *) (info->iobase);
+ return __enet_mii_write(enetp, addr, reg, value);
+}
+
+static void mxc_enet_mii_init(volatile enet_t *enetp)
+{
+ /* Set RMII mode */
+ enetp->rcr |= BM_ENET_MAC0_RCR_RMII_MODE;
+
+ /* The phy requires MDC clock below 2.5 MHz */
+ enetp->mscr |= (enetp->mscr & ~BM_ENET_MAC0_MSCR_MII_SPEED) |
+ (40 << BP_ENET_MAC0_MSCR_MII_SPEED);
+}
+
+#ifdef CONFIG_DISCOVER_PHY
+static inline int __enet_mii_info(volatile enet_t *enetp, unsigned char addr)
+{
+ unsigned int id = 0;
+ unsigned short val;
+
+ if (__enet_mii_read(enetp, addr, PHY_PHYIDR2, &val) != 0)
+ return -1;
+ id = val;
+ if (id == 0xffff)
+ return -1;
+
+ if (__enet_mii_read(enetp, addr, PHY_PHYIDR1, &val) != 0)
+ return -1;
+
+ if (val == 0xffff)
+ return -1;
+
+ id |= val << 16;
+
+#ifdef MXC_ENMXC_ENET_DEBUG
+ printf("PHY indentify @ 0x%x = 0x%08x\n", addr, id);
+#endif
+ return 0;
+}
+
+static int mxc_enet_mii_discover_phy(struct eth_device *dev)
+{
+ unsigned short addr, val;
+ struct enet_info_s *info = dev->priv;
+ volatile enet_t *enetp = (enet_t *) (info->iobase);
+
+ /* Dummy read with delay to get phy start working */
+ do {
+ __enet_mii_read(enetp, ENET_MII_PHYADDR, PHY_PHYIDR1, &val);
+ udelay(10000);
+#ifdef MXC_ENET_DEBUG
+ printf("Dummy read on phy\n");
+#endif
+ } while (val == 0 || val == 0xffff);
+
+ /* Read phy ID */
+ for (addr = 0; addr < 0x20; addr++) {
+ if (!__enet_mii_info(enetp, addr))
+ return addr;
+ }
+
+ return -1;
+}
+#endif
+
+static void set_duplex_speed(volatile enet_t *enetp, unsigned char addr,
+ int dup_spd)
+{
+ unsigned short val;
+ int ret;
+
+ ret = __enet_mii_read(enetp, addr, PHY_BMCR, &val);
+ switch (dup_spd >> 16) {
+ case HALF:
+ val &= (~PHY_BMCR_DPLX);
+ break;
+ case FULL:
+ val |= PHY_BMCR_DPLX;
+ break;
+ default:
+ val |= PHY_BMCR_AUTON | PHY_BMCR_RST_NEG;
+ }
+ ret |= __enet_mii_write(enetp, addr, PHY_BMCR, val);
+
+ if (!ret && (val & PHY_BMCR_AUTON)) {
+ ret = 0;
+ while (ret++ < ENET_MII_TIMEOUT) {
+ if (__enet_mii_read(enetp, addr, PHY_BMSR, &val))
+ break;
+ if (!(val & PHY_BMSR_AUTN_ABLE))
+ break;
+ if (val & PHY_BMSR_AUTN_COMP)
+ break;
+ }
+ }
+
+ if (__enet_mii_read(enetp, addr, PHY_BMSR, &val)) {
+ dup_spd = _100BASET | (FULL << 16);
+ } else {
+ if (val & (PHY_BMSR_100TXF | PHY_BMSR_100TXH | PHY_BMSR_100T4))
+ dup_spd = _100BASET;
+ else
+ dup_spd = _10BASET;
+ if (val & (PHY_BMSR_100TXF | PHY_BMSR_10TF))
+ dup_spd |= (FULL << 16);
+ else
+ dup_spd |= (HALF << 16);
+ }
+
+ if ((dup_spd >> 16) == FULL) {
+ enetp->tcr |= BM_ENET_MAC0_TCR_FEDN;
+#ifdef MXC_ENET_DEBUG
+ printf("full duplex, ");
+#endif
+ } else {
+ enetp->rcr |= BM_ENET_MAC0_RCR_DRT;
+ enetp->tcr &= ~BM_ENET_MAC0_TCR_FEDN;
+#ifdef MXC_ENET_DEBUG
+ printf("half duplex, ");
+#endif
+ }
+#ifdef MXC_ENET_DEBUG
+ if ((dup_spd & 0xffff) == _100BASET)
+ printf("100 Mbps\n");
+ else
+ printf("10 Mbps\n");
+#endif
+}
+
+static void copy_packet(char *pdst, char *psrc, int length)
+{
+ long *pldst = (long *)pdst;
+ long *plsrc = (long *)psrc;
+
+ length /= sizeof(long);
+ while (length--) {
+ *pldst = __swap_32(*plsrc);
+ pldst++;
+ plsrc++;
+ }
+}
+
+static int enet_send(struct eth_device *dev, volatile void *packet, int length)
+{
+ struct enet_info_s *info = dev->priv;
+ volatile enet_t *enetp = (enet_t *) (info->iobase);
+ int i;
+ u16 phyStatus;
+
+ __enet_mii_read(enetp, info->phy_addr, PHY_BMSR, &phyStatus);
+
+ if (!(phyStatus & PHY_BMSR_LS)) {
+ printf("ENET: Link is down %x\n", phyStatus);
+ return -1;
+ }
+
+ /* Wait for ready */
+ i = 0;
+ while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) &&
+ (i < ENET_MAX_TIMEOUT)) {
+ udelay(ENET_TIMEOUT_TICKET);
+ i++;
+ }
+ if (i >= ENET_MAX_TIMEOUT)
+ printf("TX buffer is NOT ready\n");
+
+ /* Manipulate the packet buffer */
+ copy_packet((char *)info->txbd[info->txIdx].cbd_bufaddr,
+ (char *)packet, length + (4 - length % 4));
+
+ /* Set up transmit Buffer Descriptor */
+ info->txbd[info->txIdx].cbd_datlen = length;
+ info->txbd[info->txIdx].cbd_sc =
+ (info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_WRAP) |
+ BD_ENET_TX_TC | BD_ENET_TX_RDY_LST;
+
+ /* Activate transmit Buffer Descriptor polling */
+ enetp->tdar = 0x01000000;
+
+ /* Move Buffer Descriptor to the next */
+ info->txIdx = (info->txIdx + 1) % TX_BUF_CNT;
+
+ return length;
+}
+
+static int enet_recv(struct eth_device *dev)
+{
+ struct enet_info_s *info = dev->priv;
+ volatile enet_t *enetp = (enet_t *) (info->iobase);
+ int length;
+
+ for (;;) {
+ if (info->rxbd[info->rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ length = info->rxbd[info->rxIdx].cbd_datlen;
+
+ if (info->rxbd[info->rxIdx].cbd_sc & 0x003f) {
+#ifdef MXC_ENET_DEBUG
+ printf("%s[%d] err: %x\n",
+ __func__, __LINE__,
+ info->rxbd[info->rxIdx].cbd_sc);
+#endif
+ } else {
+ length -= 4;
+
+ /* Manipulate the packet buffer */
+ copy_packet((char *)NetRxPackets[info->rxIdx],
+ (char *)info->rxbd[info->rxIdx].cbd_bufaddr,
+ length + (4 - length % 4));
+
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[info->rxIdx], length);
+ }
+
+ /* Give the buffer back to the ENET */
+ info->rxbd[info->rxIdx].cbd_datlen = 0;
+
+ /* Wrap around buffer index when necessary */
+ if (info->rxIdx == LAST_RX_BUF) {
+ info->rxbd[RX_BUF_CNT - 1].cbd_sc = BD_ENET_RX_W_E;
+ info->rxIdx = 0;
+ } else {
+ info->rxbd[info->rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ info->rxIdx++;
+ }
+
+ /* Try to fill Buffer Descriptors */
+ enetp->rdar = 0x01000000;
+ }
+
+ return length;
+}
+
+static void enet_reset(struct eth_device *dev)
+{
+ int i;
+ struct enet_info_s *info = dev->priv;
+ volatile enet_t *enetp = (enet_t *) (info->iobase);
+
+ enetp->ecr |= BM_ENET_MAC0_ECR_RESET;
+ for (i = 0; (enetp->ecr & BM_ENET_MAC0_ECR_RESET) && (i < ENET_RESET_DELAY); ++i)
+ udelay(1);
+
+ if (i == ENET_RESET_DELAY)
+ printf("ENET reset timeout\n");
+}
+
+static void enet_halt(struct eth_device *dev)
+{
+ struct enet_info_s *info = dev->priv;
+
+ /* Reset ENET controller to stop transmit and receive */
+ enet_reset(dev);
+
+ /* Clear buffers */
+ info->rxIdx = info->txIdx = 0;
+ memset(info->rxbd, 0, RX_BUF_CNT * sizeof(cbd_t));
+ memset(info->txbd, 0, TX_BUF_CNT * sizeof(cbd_t));
+ memset(info->rxbuf, 0, RX_BUF_CNT * DBUF_LENGTH);
+ memset(info->txbuf, 0, TX_BUF_CNT * DBUF_LENGTH);
+}
+
+static int enet_init(struct eth_device *dev, bd_t *bd)
+{
+ struct enet_info_s *info = dev->priv;
+ volatile enet_t *enetp = (enet_t *) (info->iobase);
+ int i;
+ u8 *ea = NULL;
+
+ /* Turn on ENET clocks */
+ REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET,
+ REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET) &
+ ~(BM_CLKCTRL_ENET_SLEEP | BM_CLKCTRL_ENET_DISABLE));
+
+ /* Set up ENET PLL for 50 MHz */
+ REG_SET(REGS_CLKCTRL_BASE, HW_CLKCTRL_PLL2CTRL0,
+ BM_CLKCTRL_PLL2CTRL0_POWER); /* Power on ENET PLL */
+ udelay(10); /* Wait 10 us */
+ REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_PLL2CTRL0,
+ BM_CLKCTRL_PLL2CTRL0_CLKGATE); /* Gate on ENET PLL */
+ REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET,
+ REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET) |
+ BM_CLKCTRL_ENET_CLK_OUT_EN); /* Enable pad output */
+
+ /* Board level init */
+ enet_board_init();
+
+ /* Reset ENET controller */
+ enet_reset(dev);
+
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_MII) || \
+ defined(CONFIG_DISCOVER_PHY)
+ mxc_enet_mii_init(enetp);
+#ifdef CONFIG_DISCOVER_PHY
+ if (info->phy_addr < 0 || info->phy_addr > 0x1f)
+ info->phy_addr = mxc_enet_mii_discover_phy(dev);
+#endif
+ set_duplex_speed(enetp, (unsigned char)info->phy_addr, info->dup_spd);
+#else
+#ifndef CONFIG_DISCOVER_PHY
+ set_duplex_speed(enetp, (unsigned char)info->phy_addr,
+ (ENETDUPLEX << 16) | ENETSPEED);
+#endif
+#endif
+ /* We use strictly polling mode only */
+ enetp->eimr = 0;
+
+ /* Clear any pending interrupt */
+ enetp->eir = 0xffffffff;
+
+ /* Disable loopback mode */
+ enetp->rcr &= ~BM_ENET_MAC0_RCR_LOOP;
+
+ /* Enable RX flow control */
+ enetp->rcr |= BM_ENET_MAC0_RCR_FCE;
+
+ /* Set station address and enable it for TX */
+ ea = dev->enetaddr;
+ enetp->palr = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+ enetp->paur = (ea[4] << 24) | (ea[5] << 16);
+ enetp->tcr |= BM_ENET_MAC0_TCR_TX_ADDR_INS;
+
+ /* Clear unicast address hash table */
+ enetp->iaur = 0;
+ enetp->ialr = 0;
+
+ /* Clear multicast address hash table */
+ enetp->gaur = 0;
+ enetp->galr = 0;
+
+ /* Set maximum receive buffer size. */
+ enetp->emrbr = PKT_MAXBLR_SIZE;
+
+ /* Setup Buffers and Buffer Desriptors */
+ info->rxIdx = 0;
+ info->txIdx = 0;
+
+ /*
+ * Setup Receiver Buffer Descriptors
+ * Settings:
+ * Empty, Wrap
+ */
+ for (i = 0; i < RX_BUF_CNT; i++) {
+ info->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ info->rxbd[i].cbd_datlen = 0; /* Reset */
+ info->rxbd[i].cbd_bufaddr =
+ (uint) (&info->rxbuf[0] + i * DBUF_LENGTH);
+ }
+ info->rxbd[RX_BUF_CNT - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /*
+ * Setup Transmitter Buffer Descriptors
+ * Settings:
+ * Last, Tx CRC
+ */
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ info->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC;
+ info->txbd[i].cbd_datlen = 0; /* Reset */
+ info->txbd[i].cbd_bufaddr =
+ (uint) (&info->txbuf[0] + i * DBUF_LENGTH);
+ }
+ info->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* Set receive and transmit descriptor base */
+ enetp->erdsr = (unsigned int)(&info->rxbd[0]);
+ enetp->etdsr = (unsigned int)(&info->txbd[0]);
+
+ /* Now enable the transmit and receive processing */
+ enetp->ecr |= BM_ENET_MAC0_ECR_ETHER_EN;
+
+ /* And last, try to fill Rx Buffer Descriptors */
+ enetp->rdar = 0x01000000;
+
+ return 0;
+}
+
+int mxc_enet_initialize(bd_t *bis)
+{
+ struct eth_device *dev;
+ int i;
+
+ for (i = 0; i < sizeof(enet_info) / sizeof(enet_info[0]); i++) {
+ dev = (struct eth_device *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ sizeof(*dev));
+ if (dev == NULL)
+ hang();
+
+ memset(dev, 0, sizeof(*dev));
+
+ /* Regiester device */
+ sprintf(dev->name, "ENET%d", enet_info[i].index);
+ dev->priv = &enet_info[i];
+ dev->init = enet_init;
+ dev->halt = enet_halt;
+ dev->send = enet_send;
+ dev->recv = enet_recv;
+ eth_register(dev);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, mxc_enet_mii_read, mxc_enet_mii_write);
+#endif
+ /* Setup Receive and Transmit buffer descriptor */
+ enet_info[i].rxbd =
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ RX_BUF_CNT * sizeof(cbd_t));
+ enet_info[i].rxbuf =
+ (char *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ RX_BUF_CNT * DBUF_LENGTH);
+ enet_info[i].txbd =
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ TX_BUF_CNT * sizeof(cbd_t));
+ enet_info[i].txbuf =
+ (char *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ TX_BUF_CNT * DBUF_LENGTH);
+ enet_info[i].phy_name =
+ (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
+#ifdef MXC_ENET_DEBUG
+ printf("%s: rxbd %x txbd %x ->%x\n", dev->name,
+ (int)enet_info[i].rxbd, (int)enet_info[i].txbd,
+ (int)enet_info[i].txbuf);
+#endif
+ }
+
+ return 1;
+}
+
+#endif /* defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) */