summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/kirkwood_i2c.c1
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/mxcmmc.c522
-rw-r--r--drivers/mtd/nand/omap_gpmc.c41
-rw-r--r--drivers/mtd/spi/Makefile1
-rw-r--r--drivers/mtd/spi/eeprom_m95xxx.c117
-rw-r--r--drivers/net/4xx_enet.c2
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/e1000.c3096
-rw-r--r--drivers/net/e1000.h837
-rw-r--r--drivers/net/ftmac100.c278
-rw-r--r--drivers/net/ftmac100.h154
-rw-r--r--drivers/net/kirkwood_egiga.c15
-rw-r--r--drivers/net/phy/mv88e61xx.c23
-rw-r--r--drivers/qe/uec.c17
-rw-r--r--drivers/qe/uec_phy.c36
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/cf_spi.c357
-rw-r--r--drivers/video/bus_vcxk.c1
19 files changed, 4944 insertions, 557 deletions
diff --git a/drivers/i2c/kirkwood_i2c.c b/drivers/i2c/kirkwood_i2c.c
index dd30499b3a4..37b7d99bd2e 100644
--- a/drivers/i2c/kirkwood_i2c.c
+++ b/drivers/i2c/kirkwood_i2c.c
@@ -481,4 +481,3 @@ unsigned int i2c_get_bus_num(void)
return i2c_bus_num;
#endif
}
-
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 1b0af12a74c..6fa04b84fc8 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -30,6 +30,7 @@ COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o
COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
+COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
COBJS := $(COBJS-y)
diff --git a/drivers/mmc/mxcmmc.c b/drivers/mmc/mxcmmc.c
new file mode 100644
index 00000000000..d30717661f9
--- /dev/null
+++ b/drivers/mmc/mxcmmc.c
@@ -0,0 +1,522 @@
+/*
+ * This is a driver for the SDHC controller found in Freescale MX2/MX3
+ * SoCs. It is basically the same hardware as found on MX1 (imxmmc.c).
+ * Unlike the hardware found on MX1, this hardware just works and does
+ * not need all the quirks found in imxmmc.c, hence the seperate driver.
+ *
+ * Copyright (C) 2009 Ilya Yanok, <yanok@emcraft.com>
+ * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
+ *
+ * derived from pxamci.c by Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#ifdef CONFIG_MX27
+#include <asm/arch/clock.h>
+#endif
+
+#define DRIVER_NAME "mxc-mmc"
+
+struct mxcmci_regs {
+ u32 str_stp_clk;
+ u32 status;
+ u32 clk_rate;
+ u32 cmd_dat_cont;
+ u32 res_to;
+ u32 read_to;
+ u32 blk_len;
+ u32 nob;
+ u32 rev_no;
+ u32 int_cntr;
+ u32 cmd;
+ u32 arg;
+ u32 pad;
+ u32 res_fifo;
+ u32 buffer_access;
+};
+
+#define STR_STP_CLK_RESET (1 << 3)
+#define STR_STP_CLK_START_CLK (1 << 1)
+#define STR_STP_CLK_STOP_CLK (1 << 0)
+
+#define STATUS_CARD_INSERTION (1 << 31)
+#define STATUS_CARD_REMOVAL (1 << 30)
+#define STATUS_YBUF_EMPTY (1 << 29)
+#define STATUS_XBUF_EMPTY (1 << 28)
+#define STATUS_YBUF_FULL (1 << 27)
+#define STATUS_XBUF_FULL (1 << 26)
+#define STATUS_BUF_UND_RUN (1 << 25)
+#define STATUS_BUF_OVFL (1 << 24)
+#define STATUS_SDIO_INT_ACTIVE (1 << 14)
+#define STATUS_END_CMD_RESP (1 << 13)
+#define STATUS_WRITE_OP_DONE (1 << 12)
+#define STATUS_DATA_TRANS_DONE (1 << 11)
+#define STATUS_READ_OP_DONE (1 << 11)
+#define STATUS_WR_CRC_ERROR_CODE_MASK (3 << 10)
+#define STATUS_CARD_BUS_CLK_RUN (1 << 8)
+#define STATUS_BUF_READ_RDY (1 << 7)
+#define STATUS_BUF_WRITE_RDY (1 << 6)
+#define STATUS_RESP_CRC_ERR (1 << 5)
+#define STATUS_CRC_READ_ERR (1 << 3)
+#define STATUS_CRC_WRITE_ERR (1 << 2)
+#define STATUS_TIME_OUT_RESP (1 << 1)
+#define STATUS_TIME_OUT_READ (1 << 0)
+#define STATUS_ERR_MASK 0x2f
+
+#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1 << 12)
+#define CMD_DAT_CONT_STOP_READWAIT (1 << 11)
+#define CMD_DAT_CONT_START_READWAIT (1 << 10)
+#define CMD_DAT_CONT_BUS_WIDTH_4 (2 << 8)
+#define CMD_DAT_CONT_INIT (1 << 7)
+#define CMD_DAT_CONT_WRITE (1 << 4)
+#define CMD_DAT_CONT_DATA_ENABLE (1 << 3)
+#define CMD_DAT_CONT_RESPONSE_48BIT_CRC (1 << 0)
+#define CMD_DAT_CONT_RESPONSE_136BIT (2 << 0)
+#define CMD_DAT_CONT_RESPONSE_48BIT (3 << 0)
+
+#define INT_SDIO_INT_WKP_EN (1 << 18)
+#define INT_CARD_INSERTION_WKP_EN (1 << 17)
+#define INT_CARD_REMOVAL_WKP_EN (1 << 16)
+#define INT_CARD_INSERTION_EN (1 << 15)
+#define INT_CARD_REMOVAL_EN (1 << 14)
+#define INT_SDIO_IRQ_EN (1 << 13)
+#define INT_DAT0_EN (1 << 12)
+#define INT_BUF_READ_EN (1 << 4)
+#define INT_BUF_WRITE_EN (1 << 3)
+#define INT_END_CMD_RES_EN (1 << 2)
+#define INT_WRITE_OP_DONE_EN (1 << 1)
+#define INT_READ_OP_EN (1 << 0)
+
+struct mxcmci_host {
+ struct mmc *mmc;
+ struct mxcmci_regs *base;
+ int irq;
+ int detect_irq;
+ int dma;
+ int do_dma;
+ unsigned int power_mode;
+
+ struct mmc_cmd *cmd;
+ struct mmc_data *data;
+
+ unsigned int dma_nents;
+ unsigned int datasize;
+ unsigned int dma_dir;
+
+ u16 rev_no;
+ unsigned int cmdat;
+
+ int clock;
+};
+
+static struct mxcmci_host mxcmci_host;
+static struct mxcmci_host *host = &mxcmci_host;
+
+static inline int mxcmci_use_dma(struct mxcmci_host *host)
+{
+ return host->do_dma;
+}
+
+static void mxcmci_softreset(struct mxcmci_host *host)
+{
+ int i;
+
+ /* reset sequence */
+ writew(STR_STP_CLK_RESET, &host->base->str_stp_clk);
+ writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
+ &host->base->str_stp_clk);
+
+ for (i = 0; i < 8; i++)
+ writew(STR_STP_CLK_START_CLK, &host->base->str_stp_clk);
+
+ writew(0xff, &host->base->res_to);
+}
+
+static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
+{
+ unsigned int nob = data->blocks;
+ unsigned int blksz = data->blocksize;
+ unsigned int datasize = nob * blksz;
+
+ host->data = data;
+
+ writew(nob, &host->base->nob);
+ writew(blksz, &host->base->blk_len);
+ host->datasize = datasize;
+}
+
+static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_cmd *cmd,
+ unsigned int cmdat)
+{
+ if (host->cmd != NULL)
+ printf("mxcmci: error!\n");
+ host->cmd = cmd;
+
+ switch (cmd->resp_type) {
+ case MMC_RSP_R1: /* short CRC, OPCODE */
+ case MMC_RSP_R1b:/* short CRC, OPCODE, BUSY */
+ cmdat |= CMD_DAT_CONT_RESPONSE_48BIT_CRC;
+ break;
+ case MMC_RSP_R2: /* long 136 bit + CRC */
+ cmdat |= CMD_DAT_CONT_RESPONSE_136BIT;
+ break;
+ case MMC_RSP_R3: /* short */
+ cmdat |= CMD_DAT_CONT_RESPONSE_48BIT;
+ break;
+ case MMC_RSP_NONE:
+ break;
+ default:
+ printf("mxcmci: unhandled response type 0x%x\n",
+ cmd->resp_type);
+ return -EINVAL;
+ }
+
+ writew(cmd->cmdidx, &host->base->cmd);
+ writel(cmd->cmdarg, &host->base->arg);
+ writew(cmdat, &host->base->cmd_dat_cont);
+
+ return 0;
+}
+
+static void mxcmci_finish_request(struct mxcmci_host *host,
+ struct mmc_cmd *cmd, struct mmc_data *data)
+{
+ host->cmd = NULL;
+ host->data = NULL;
+}
+
+static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
+{
+ int data_error = 0;
+
+ if (stat & STATUS_ERR_MASK) {
+ printf("request failed. status: 0x%08x\n",
+ stat);
+ if (stat & STATUS_CRC_READ_ERR) {
+ data_error = -EILSEQ;
+ } else if (stat & STATUS_CRC_WRITE_ERR) {
+ u32 err_code = (stat >> 9) & 0x3;
+ if (err_code == 2) /* No CRC response */
+ data_error = TIMEOUT;
+ else
+ data_error = -EILSEQ;
+ } else if (stat & STATUS_TIME_OUT_READ) {
+ data_error = TIMEOUT;
+ } else {
+ data_error = -EIO;
+ }
+ }
+
+ host->data = NULL;
+
+ return data_error;
+}
+
+static int mxcmci_read_response(struct mxcmci_host *host, unsigned int stat)
+{
+ struct mmc_cmd *cmd = host->cmd;
+ int i;
+ u32 a, b, c;
+ u32 *resp = (u32 *)cmd->response;
+
+ if (!cmd)
+ return 0;
+
+ if (stat & STATUS_TIME_OUT_RESP) {
+ printf("CMD TIMEOUT\n");
+ return TIMEOUT;
+ } else if (stat & STATUS_RESP_CRC_ERR && cmd->resp_type & MMC_RSP_CRC) {
+ printf("cmd crc error\n");
+ return -EILSEQ;
+ }
+
+ if (cmd->resp_type & MMC_RSP_PRESENT) {
+ if (cmd->resp_type & MMC_RSP_136) {
+ for (i = 0; i < 4; i++) {
+ a = readw(&host->base->res_fifo);
+ b = readw(&host->base->res_fifo);
+ resp[i] = a << 16 | b;
+ }
+ } else {
+ a = readw(&host->base->res_fifo);
+ b = readw(&host->base->res_fifo);
+ c = readw(&host->base->res_fifo);
+ resp[0] = a << 24 | b << 8 | c >> 8;
+ }
+ }
+ return 0;
+}
+
+static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
+{
+ u32 stat;
+ unsigned long timeout = get_ticks() + CONFIG_SYS_HZ;
+
+ do {
+ stat = readl(&host->base->status);
+ if (stat & STATUS_ERR_MASK)
+ return stat;
+ if (timeout < get_ticks())
+ return STATUS_TIME_OUT_READ;
+ if (stat & mask)
+ return 0;
+ } while (1);
+}
+
+static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
+{
+ unsigned int stat;
+ u32 *buf = _buf;
+
+ while (bytes > 3) {
+ stat = mxcmci_poll_status(host,
+ STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
+ if (stat)
+ return stat;
+ *buf++ = readl(&host->base->buffer_access);
+ bytes -= 4;
+ }
+
+ if (bytes) {
+ u8 *b = (u8 *)buf;
+ u32 tmp;
+
+ stat = mxcmci_poll_status(host,
+ STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
+ if (stat)
+ return stat;
+ tmp = readl(&host->base->buffer_access);
+ memcpy(b, &tmp, bytes);
+ }
+
+ return 0;
+}
+
+static int mxcmci_push(struct mxcmci_host *host, const void *_buf, int bytes)
+{
+ unsigned int stat;
+ const u32 *buf = _buf;
+
+ while (bytes > 3) {
+ stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
+ if (stat)
+ return stat;
+ writel(*buf++, &host->base->buffer_access);
+ bytes -= 4;
+ }
+
+ if (bytes) {
+ const u8 *b = (u8 *)buf;
+ u32 tmp;
+
+ stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
+ if (stat)
+ return stat;
+
+ memcpy(&tmp, b, bytes);
+ writel(tmp, &host->base->buffer_access);
+ }
+
+ stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
+ if (stat)
+ return stat;
+
+ return 0;
+}
+
+static int mxcmci_transfer_data(struct mxcmci_host *host)
+{
+ struct mmc_data *data = host->data;
+ int stat;
+ unsigned long length;
+
+ length = data->blocks * data->blocksize;
+ host->datasize = 0;
+
+ if (data->flags & MMC_DATA_READ) {
+ stat = mxcmci_pull(host, data->dest, length);
+ if (stat)
+ return stat;
+ host->datasize += length;
+ } else {
+ stat = mxcmci_push(host, (const void *)(data->src), length);
+ if (stat)
+ return stat;
+ host->datasize += length;
+ stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE);
+ if (stat)
+ return stat;
+ }
+ return 0;
+}
+
+static int mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
+{
+ int datastat;
+ int ret;
+
+ ret = mxcmci_read_response(host, stat);
+
+ if (ret) {
+ mxcmci_finish_request(host, host->cmd, host->data);
+ return ret;
+ }
+
+ if (!host->data) {
+ mxcmci_finish_request(host, host->cmd, host->data);
+ return 0;
+ }
+
+ datastat = mxcmci_transfer_data(host);
+ ret = mxcmci_finish_data(host, datastat);
+ mxcmci_finish_request(host, host->cmd, host->data);
+ return ret;
+}
+
+static int mxcmci_request(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct mxcmci_host *host = mmc->priv;
+ unsigned int cmdat = host->cmdat;
+ u32 stat;
+ int ret;
+
+ host->cmdat &= ~CMD_DAT_CONT_INIT;
+ if (data) {
+ mxcmci_setup_data(host, data);
+
+ cmdat |= CMD_DAT_CONT_DATA_ENABLE;
+
+ if (data->flags & MMC_DATA_WRITE)
+ cmdat |= CMD_DAT_CONT_WRITE;
+ }
+
+ if ((ret = mxcmci_start_cmd(host, cmd, cmdat))) {
+ mxcmci_finish_request(host, cmd, data);
+ return ret;
+ }
+
+ do {
+ stat = readl(&host->base->status);
+ writel(stat, &host->base->status);
+ } while (!(stat & STATUS_END_CMD_RESP));
+
+ return mxcmci_cmd_done(host, stat);
+}
+
+static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
+{
+ unsigned int divider;
+ int prescaler = 0;
+ unsigned long clk_in = imx_get_perclk2();
+
+ while (prescaler <= 0x800) {
+ for (divider = 1; divider <= 0xF; divider++) {
+ int x;
+
+ x = (clk_in / (divider + 1));
+
+ if (prescaler)
+ x /= (prescaler * 2);
+
+ if (x <= clk_ios)
+ break;
+ }
+ if (divider < 0x10)
+ break;
+
+ if (prescaler == 0)
+ prescaler = 1;
+ else
+ prescaler <<= 1;
+ }
+
+ writew((prescaler << 4) | divider, &host->base->clk_rate);
+}
+
+static void mxcmci_set_ios(struct mmc *mmc)
+{
+ struct mxcmci_host *host = mmc->priv;
+ if (mmc->bus_width == 4)
+ host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
+ else
+ host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4;
+
+ if (mmc->clock) {
+ mxcmci_set_clk_rate(host, mmc->clock);
+ writew(STR_STP_CLK_START_CLK, &host->base->str_stp_clk);
+ } else {
+ writew(STR_STP_CLK_STOP_CLK, &host->base->str_stp_clk);
+ }
+
+ host->clock = mmc->clock;
+}
+
+static int mxcmci_init(struct mmc *mmc)
+{
+ struct mxcmci_host *host = mmc->priv;
+
+ mxcmci_softreset(host);
+
+ host->rev_no = readw(&host->base->rev_no);
+ if (host->rev_no != 0x400) {
+ printf("wrong rev.no. 0x%08x. aborting.\n",
+ host->rev_no);
+ return -ENODEV;
+ }
+
+ /* recommended in data sheet */
+ writew(0x2db4, &host->base->read_to);
+
+ writel(0, &host->base->int_cntr);
+
+ return 0;
+}
+
+static int mxcmci_initialize(bd_t *bis)
+{
+ struct mmc *mmc = NULL;
+
+ mmc = malloc(sizeof(struct mmc));
+
+ if (!mmc)
+ return -ENOMEM;
+
+ sprintf(mmc->name, "MXC MCI");
+ mmc->send_cmd = mxcmci_request;
+ mmc->set_ios = mxcmci_set_ios;
+ mmc->init = mxcmci_init;
+ mmc->host_caps = MMC_MODE_4BIT;
+
+ host->base = (struct mxcmci_regs *)CONFIG_MXC_MCI_REGS_BASE;
+ mmc->priv = host;
+ host->mmc = mmc;
+
+ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ mmc->f_min = imx_get_perclk2() >> 7;
+ mmc->f_max = imx_get_perclk2() >> 1;
+
+ mmc_register(mmc);
+
+ return 0;
+}
+
+int mxc_mmc_init(bd_t *bis)
+{
+ return mxcmci_initialize(bis);
+}
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 5f8ed3984d8..99b9cef17c2 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -30,8 +30,6 @@
#include <nand.h>
static uint8_t cs;
-static gpmc_t *gpmc_base = (gpmc_t *)GPMC_BASE;
-static gpmc_csx_t *gpmc_cs_base;
static struct nand_ecclayout hw_nand_oob = GPMC_NAND_HW_ECC_LAYOUT;
/*
@@ -49,13 +47,13 @@ static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
*/
switch (ctrl) {
case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
- this->IO_ADDR_W = (void __iomem *)&gpmc_cs_base->nand_cmd;
+ this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
break;
case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
- this->IO_ADDR_W = (void __iomem *)&gpmc_cs_base->nand_adr;
+ this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
break;
case NAND_CTRL_CHANGE | NAND_NCE:
- this->IO_ADDR_W = (void __iomem *)&gpmc_cs_base->nand_dat;
+ this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
break;
}
@@ -75,8 +73,8 @@ static void omap_hwecc_init(struct nand_chip *chip)
* Init ECC Control Register
* Clear all ECC | Enable Reg1
*/
- writel(ECCCLEAR | ECCRESULTREG1, &gpmc_base->ecc_control);
- writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, &gpmc_base->ecc_size_config);
+ writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
+ writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, &gpmc_cfg->ecc_size_config);
}
/*
@@ -179,7 +177,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
u_int32_t val;
/* Start Reading from HW ECC1_Result = 0x200 */
- val = readl(&gpmc_base->ecc1_result);
+ val = readl(&gpmc_cfg->ecc1_result);
ecc_code[0] = val & 0xFF;
ecc_code[1] = (val >> 16) & 0xFF;
@@ -189,7 +187,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
* Stop reading anymore ECC vals and clear old results
* enable will be called if more reads are required
*/
- writel(0x000, &gpmc_base->ecc_config);
+ writel(0x000, &gpmc_cfg->ecc_config);
return 0;
}
@@ -208,7 +206,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
case NAND_ECC_READ:
case NAND_ECC_WRITE:
/* Clear the ecc result registers, select ecc reg as 1 */
- writel(ECCCLEAR | ECCRESULTREG1, &gpmc_base->ecc_control);
+ writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
/*
* Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes
@@ -216,9 +214,9 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
* we just have a single ECC engine for all CS
*/
writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL,
- &gpmc_base->ecc_size_config);
+ &gpmc_cfg->ecc_size_config);
val = (dev_width << 7) | (cs << 1) | (0x1);
- writel(val, &gpmc_base->ecc_config);
+ writel(val, &gpmc_cfg->ecc_config);
break;
default:
printf("Error: Unrecognized Mode[%d]!\n", mode);
@@ -311,15 +309,8 @@ int board_nand_init(struct nand_chip *nand)
* devices.
*/
while (cs < GPMC_MAX_CS) {
- /*
- * Each GPMC set for a single CS is at offset 0x30
- * - already remapped for us
- */
- gpmc_cs_base = (gpmc_csx_t *)(GPMC_CONFIG_CS0_BASE +
- (cs * GPMC_CONFIG_WIDTH));
/* Check if NAND type is set */
- if ((readl(&gpmc_cs_base->config1) & 0xC00) ==
- 0x800) {
+ if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
/* Found it!! */
break;
}
@@ -331,18 +322,18 @@ int board_nand_init(struct nand_chip *nand)
return -ENODEV;
}
- gpmc_config = readl(&gpmc_base->config);
+ gpmc_config = readl(&gpmc_cfg->config);
/* Disable Write protect */
gpmc_config |= 0x10;
- writel(gpmc_config, &gpmc_base->config);
+ writel(gpmc_config, &gpmc_cfg->config);
- nand->IO_ADDR_R = (void __iomem *)&gpmc_cs_base->nand_dat;
- nand->IO_ADDR_W = (void __iomem *)&gpmc_cs_base->nand_cmd;
+ nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
+ nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
nand->cmd_ctrl = omap_nand_hwcontrol;
nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR;
/* If we are 16 bit dev, our gpmc config tells us that */
- if ((readl(gpmc_cs_base) & 0x3000) == 0x1000)
+ if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
nand->options |= NAND_BUSWIDTH_16;
nand->chip_delay = 100;
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 27dcbffab11..e3e0292808c 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.o
COBJS-$(CONFIG_SPI_FLASH_SPANSION) += spansion.o
COBJS-$(CONFIG_SPI_FLASH_SST) += sst.o
COBJS-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.o
+COBJS-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/mtd/spi/eeprom_m95xxx.c b/drivers/mtd/spi/eeprom_m95xxx.c
new file mode 100644
index 00000000000..59f80e39ff2
--- /dev/null
+++ b/drivers/mtd/spi/eeprom_m95xxx.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009
+ * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <spi.h>
+
+#define SPI_EEPROM_WREN 0x06
+#define SPI_EEPROM_RDSR 0x05
+#define SPI_EEPROM_READ 0x03
+#define SPI_EEPROM_WRITE 0x02
+
+#ifndef CONFIG_DEFAULT_SPI_BUS
+#define CONFIG_DEFAULT_SPI_BUS 0
+#endif
+
+#ifndef CONFIG_DEFAULT_SPI_MODE
+#define CONFIG_DEFAULT_SPI_MODE SPI_MODE_0
+#endif
+
+ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+ struct spi_slave *slave;
+ u8 cmd = SPI_EEPROM_READ;
+
+ slave = spi_setup_slave(CONFIG_DEFAULT_SPI_BUS, 1, 1000000,
+ CONFIG_DEFAULT_SPI_MODE);
+ spi_claim_bus(slave);
+
+ /* command */
+ if(spi_xfer(slave, 8, &cmd, NULL, SPI_XFER_BEGIN))
+ return -1;
+
+ /*
+ * if alen == 3, addr[0] is the block number, we never use it here. All we
+ * need are the lower 16 bits
+ */
+ if (alen == 3)
+ addr++;
+
+ /* address, and data */
+ if(spi_xfer(slave, 16, addr, NULL, 0))
+ return -1;
+ if(spi_xfer(slave, 8 * len, NULL, buffer, SPI_XFER_END))
+ return -1;
+
+ spi_release_bus(slave);
+ spi_free_slave(slave);
+ return len;
+}
+
+ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+ struct spi_slave *slave;
+ int i;
+ char buf[3];
+
+ slave = spi_setup_slave(CONFIG_DEFAULT_SPI_BUS, 1, 1000000,
+ CONFIG_DEFAULT_SPI_MODE);
+ spi_claim_bus(slave);
+
+ buf[0] = SPI_EEPROM_WREN;
+ if(spi_xfer(slave, 8, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END))
+ return -1;
+
+ buf[0] = SPI_EEPROM_WRITE;
+
+ /* As for reading, drop addr[0] if alen is 3 */
+ if (alen == 3) {
+ alen--;
+ addr++;
+ }
+
+ memcpy(buf + 1, addr, alen);
+ /* command + addr, then data */
+ if(spi_xfer(slave, 24, buf, NULL, SPI_XFER_BEGIN))
+ return -1;
+ if(spi_xfer(slave, len * 8, buffer, NULL, SPI_XFER_END))
+ return -1;
+
+ reset_timer_masked();
+ do {
+ buf[0] = SPI_EEPROM_RDSR;
+ buf[1] = 0;
+ spi_xfer(slave, 16, buf, buf, SPI_XFER_BEGIN | SPI_XFER_END);
+
+ if (!(buf[1] & 1))
+ break;
+
+ } while (get_timer_masked() < CONFIG_SYS_SPI_WRITE_TOUT);
+
+ if (buf[1] & 1)
+ printf ("*** spi_write: Time out while writing!\n");
+
+ spi_release_bus(slave);
+ spi_free_slave(slave);
+ return len;
+}
diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c
index c0200481c62..329eef07df5 100644
--- a/drivers/net/4xx_enet.c
+++ b/drivers/net/4xx_enet.c
@@ -1,4 +1,6 @@
/*-----------------------------------------------------------------------------+
+ * This source code is dual-licensed. You may use it under the terms of the
+ * GNU General Public License version 2, or under the license below.
*
* This source code has been made available to you by IBM on an AS-IS
* basis. Anyone receiving this source is licensed under IBM
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 34b56d82530..1c6e402246e 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -39,6 +39,7 @@ COBJS-$(CONFIG_EEPRO100) += eepro100.o
COBJS-$(CONFIG_ENC28J60) += enc28j60.o
COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
+COBJS-$(CONFIG_FTMAC100) += ftmac100.o
COBJS-$(CONFIG_GRETH) += greth.o
COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
COBJS-$(CONFIG_KIRKWOOD_EGIGA) += kirkwood_egiga.o
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index a52749d78cc..777783a91bf 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -51,7 +51,7 @@ tested on both gig copper and gig fiber boards
#define bus_to_phys(devno, a) pci_mem_to_phys(devno, a)
#define mdelay(n) udelay((n)*1000)
-#define E1000_DEFAULT_PBA 0x00000030
+#define E1000_DEFAULT_PBA 0x000a0026
/* NIC specific static variables go here */
@@ -82,6 +82,28 @@ static struct pci_device_id supported[] = {
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541GI_LF},
+ /* E1000 PCIe card */
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_FIBER },
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES },
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571PT_QUAD_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_COPPER_LOWPROFILE},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES_DUAL},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES_QUAD},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_COPPER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_FIBER},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_SERDES},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573E},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573E_IAMT},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573L},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546GB_QUAD_COPPER_KSP3},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_COPPER_DPT},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_SERDES_DPT},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_COPPER_SPT},
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_SERDES_SPT},
{}
};
@@ -95,16 +117,20 @@ static int e1000_config_mac_to_phy(struct e1000_hw *hw);
static int e1000_config_fc_after_link_up(struct e1000_hw *hw);
static int e1000_check_for_link(struct eth_device *nic);
static int e1000_wait_autoneg(struct e1000_hw *hw);
-static void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed,
+static int e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed,
uint16_t * duplex);
static int e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
uint16_t * phy_data);
static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
uint16_t phy_data);
-static void e1000_phy_hw_reset(struct e1000_hw *hw);
+static int32_t e1000_phy_hw_reset(struct e1000_hw *hw);
static int e1000_phy_reset(struct e1000_hw *hw);
static int e1000_detect_gig_phy(struct e1000_hw *hw);
+static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
+static void e1000_set_media_type(struct e1000_hw *hw);
+static int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
+static int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
#define E1000_WRITE_REG(a, reg, value) (writel((value), ((a)->hw_addr + E1000_##reg)))
#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_##reg))
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) (\
@@ -114,6 +140,9 @@ static int e1000_detect_gig_phy(struct e1000_hw *hw);
#define E1000_WRITE_FLUSH(a) {uint32_t x; x = E1000_READ_REG(a, STATUS);}
#ifndef CONFIG_AP1000 /* remove for warnings */
+static int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words,
+ uint16_t *data);
/******************************************************************************
* Raises the EEPROM's clock input.
*
@@ -204,17 +233,17 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count)
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
static uint16_t
-e1000_shift_in_ee_bits(struct e1000_hw *hw)
+e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count)
{
uint32_t eecd;
uint32_t i;
uint16_t data;
- /* In order to read a register from the EEPROM, we need to shift 16 bits
- * in from the EEPROM. Bits are "shifted in" by raising the clock input to
- * the EEPROM (setting the SK bit), and then reading the value of the "DO"
- * bit. During this "shifting in" process the "DI" bit should always be
- * clear..
+ /* In order to read a register from the EEPROM, we need to shift 'count'
+ * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+ * input to the EEPROM (setting the SK bit), and then reading the
+ * value of the "DO" bit. During this "shifting in" process the
+ * "DI" bit should always be clear.
*/
eecd = E1000_READ_REG(hw, EECD);
@@ -222,7 +251,7 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw)
eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
data = 0;
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < count; i++) {
data = data << 1;
e1000_raise_ee_clk(hw, &eecd);
@@ -239,213 +268,600 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw)
}
/******************************************************************************
- * Prepares EEPROM for access
+ * Returns EEPROM to a "standby" state
*
* hw - Struct containing variables accessed by shared code
- *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
- * function should be called before issuing a command to the EEPROM.
*****************************************************************************/
static void
-e1000_setup_eeprom(struct e1000_hw *hw)
+e1000_standby_eeprom(struct e1000_hw *hw)
{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
uint32_t eecd;
eecd = E1000_READ_REG(hw, EECD);
- /* Clear SK and DI */
- eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
- E1000_WRITE_REG(hw, EECD, eecd);
+ if (eeprom->type == e1000_eeprom_microwire) {
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
- /* Set CS */
- eecd |= E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
+ /* Clock high */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+
+ /* Clock low */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ } else if (eeprom->type == e1000_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ }
+}
+
+/***************************************************************************
+* Description: Determines if the onboard NVM is FLASH or EEPROM.
+*
+* hw - Struct containing variables accessed by shared code
+****************************************************************************/
+static boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
+{
+ uint32_t eecd = 0;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type == e1000_ich8lan)
+ return FALSE;
+
+ if (hw->mac_type == e1000_82573) {
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Isolate bits 15 & 16 */
+ eecd = ((eecd >> 15) & 0x03);
+
+ /* If both bits are set, device is Flash type */
+ if (eecd == 0x03)
+ return FALSE;
+ }
+ return TRUE;
}
/******************************************************************************
- * Returns EEPROM to a "standby" state
+ * Prepares EEPROM for access
*
* hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
*****************************************************************************/
-static void
-e1000_standby_eeprom(struct e1000_hw *hw)
+static int32_t
+e1000_acquire_eeprom(struct e1000_hw *hw)
{
- uint32_t eecd;
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd, i = 0;
+
+ DEBUGOUT();
+ if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM))
+ return -E1000_ERR_SWFW_SYNC;
eecd = E1000_READ_REG(hw, EECD);
- /* Deselct EEPROM */
- eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ if (hw->mac_type != e1000_82573) {
+ /* Request EEPROM Access */
+ if (hw->mac_type > e1000_82544) {
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+ while ((!(eecd & E1000_EECD_GNT)) &&
+ (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+ i++;
+ udelay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if (!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ return -E1000_ERR_EEPROM;
+ }
+ }
+ }
- /* Clock high */
- eecd |= E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ /* Setup EEPROM for Read/Write */
- /* Select EEPROM */
- eecd |= E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ if (eeprom->type == e1000_eeprom_microwire) {
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
- /* Clock low */
- eecd &= ~E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ } else if (eeprom->type == e1000_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ udelay(1);
+ }
+
+ return E1000_SUCCESS;
}
/******************************************************************************
- * Reads a 16 bit word from the EEPROM.
+ * Sets up eeprom variables in the hw struct. Must be called after mac_type
+ * is configured. Additionally, if this is ICH8, the flash controller GbE
+ * registers must be mapped, or this will crash.
*
* hw - Struct containing variables accessed by shared code
- * offset - offset of word in the EEPROM to read
- * data - word read from the EEPROM
*****************************************************************************/
-static int
-e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, uint16_t * data)
+static int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
{
- uint32_t eecd;
- uint32_t i = 0;
- int large_eeprom = FALSE;
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd = E1000_READ_REG(hw, EECD);
+ int32_t ret_val = E1000_SUCCESS;
+ uint16_t eeprom_size;
- /* Request EEPROM Access */
- if (hw->mac_type > e1000_82544) {
- eecd = E1000_READ_REG(hw, EECD);
- if (eecd & E1000_EECD_SIZE)
- large_eeprom = TRUE;
- eecd |= E1000_EECD_REQ;
- E1000_WRITE_REG(hw, EECD, eecd);
- eecd = E1000_READ_REG(hw, EECD);
- while ((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
- i++;
- udelay(10);
- eecd = E1000_READ_REG(hw, EECD);
+ DEBUGOUT();
+
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+ case e1000_82544:
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->word_size = 64;
+ eeprom->opcode_bits = 3;
+ eeprom->address_bits = 6;
+ eeprom->delay_usec = 50;
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82545_rev_3:
+ case e1000_82546:
+ case e1000_82546_rev_3:
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if (eecd & E1000_EECD_SIZE) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
}
- if (!(eecd & E1000_EECD_GNT)) {
- eecd &= ~E1000_EECD_REQ;
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
+ case e1000_82541:
+ case e1000_82541_rev_2:
+ case e1000_82547:
+ case e1000_82547_rev_2:
+ if (eecd & E1000_EECD_TYPE) {
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ } else {
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
+ }
+ }
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
+ case e1000_82573:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = TRUE;
+ eeprom->use_eewr = TRUE;
+ if (e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
+ eeprom->type = e1000_eeprom_flash;
+ eeprom->word_size = 2048;
+
+ /* Ensure that the Autonomous FLASH update bit is cleared due to
+ * Flash update issue on parts which use a FLASH for NVM. */
+ eecd &= ~E1000_EECD_AUPDEN;
E1000_WRITE_REG(hw, EECD, eecd);
- DEBUGOUT("Could not acquire EEPROM grant\n");
- return -E1000_ERR_EEPROM;
}
- }
+ break;
+ case e1000_80003es2lan:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = TRUE;
+ eeprom->use_eewr = FALSE;
+ break;
- /* Prepare the EEPROM for reading */
- e1000_setup_eeprom(hw);
+ /* ich8lan does not support currently. if needed, please
+ * add corresponding code and functions.
+ */
+#if 0
+ case e1000_ich8lan:
+ {
+ int32_t i = 0;
+
+ eeprom->type = e1000_eeprom_ich8;
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ eeprom->word_size = E1000_SHADOW_RAM_WORDS;
+ uint32_t flash_size = E1000_READ_ICH_FLASH_REG(hw,
+ ICH_FLASH_GFPREG);
+ /* Zero the shadow RAM structure. But don't load it from NVM
+ * so as to save time for driver init */
+ if (hw->eeprom_shadow_ram != NULL) {
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ hw->eeprom_shadow_ram[i].modified = FALSE;
+ hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+ }
+ }
- /* Send the READ command (opcode + addr) */
- e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
- e1000_shift_out_ee_bits(hw, offset, (large_eeprom) ? 8 : 6);
+ hw->flash_base_addr = (flash_size & ICH_GFPREG_BASE_MASK) *
+ ICH_FLASH_SECTOR_SIZE;
- /* Read the data */
- *data = e1000_shift_in_ee_bits(hw);
+ hw->flash_bank_size = ((flash_size >> 16)
+ & ICH_GFPREG_BASE_MASK) + 1;
+ hw->flash_bank_size -= (flash_size & ICH_GFPREG_BASE_MASK);
- /* End this read operation */
- e1000_standby_eeprom(hw);
+ hw->flash_bank_size *= ICH_FLASH_SECTOR_SIZE;
- /* Stop requesting EEPROM access */
- if (hw->mac_type > e1000_82544) {
- eecd = E1000_READ_REG(hw, EECD);
- eecd &= ~E1000_EECD_REQ;
- E1000_WRITE_REG(hw, EECD, eecd);
+ hw->flash_bank_size /= 2 * sizeof(uint16_t);
+ break;
+ }
+#endif
+ default:
+ break;
}
- return 0;
+ if (eeprom->type == e1000_eeprom_spi) {
+ /* eeprom_size will be an enum [0..8] that maps
+ * to eeprom sizes 128B to
+ * 32KB (incremented by powers of 2).
+ */
+ if (hw->mac_type <= e1000_82547_rev_2) {
+ /* Set to default value for initial eeprom read. */
+ eeprom->word_size = 64;
+ ret_val = e1000_read_eeprom(hw, EEPROM_CFG, 1,
+ &eeprom_size);
+ if (ret_val)
+ return ret_val;
+ eeprom_size = (eeprom_size & EEPROM_SIZE_MASK)
+ >> EEPROM_SIZE_SHIFT;
+ /* 256B eeprom size was not supported in earlier
+ * hardware, so we bump eeprom_size up one to
+ * ensure that "1" (which maps to 256B) is never
+ * the result used in the shifting logic below. */
+ if (eeprom_size)
+ eeprom_size++;
+ } else {
+ eeprom_size = (uint16_t)((eecd &
+ E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+ }
+
+ eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT);
+ }
+ return ret_val;
}
-#if 0
-static void
-e1000_eeprom_cleanup(struct e1000_hw *hw)
+/******************************************************************************
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd)
{
- uint32_t eecd;
+ uint32_t attempts = 100000;
+ uint32_t i, reg = 0;
+ int32_t done = E1000_ERR_EEPROM;
- eecd = E1000_READ_REG(hw, EECD);
- eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
- E1000_WRITE_REG(hw, EECD, eecd);
- e1000_raise_ee_clk(hw, &eecd);
- e1000_lower_ee_clk(hw, &eecd);
+ for (i = 0; i < attempts; i++) {
+ if (eerd == E1000_EEPROM_POLL_READ)
+ reg = E1000_READ_REG(hw, EERD);
+ else
+ reg = E1000_READ_REG(hw, EEWR);
+
+ if (reg & E1000_EEPROM_RW_REG_DONE) {
+ done = E1000_SUCCESS;
+ break;
+ }
+ udelay(5);
+ }
+
+ return done;
}
-static uint16_t
-e1000_wait_eeprom_done(struct e1000_hw *hw)
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+static int32_t
+e1000_read_eeprom_eerd(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
{
- uint32_t eecd;
- uint32_t i;
+ uint32_t i, eerd = 0;
+ int32_t error = 0;
+
+ for (i = 0; i < words; i++) {
+ eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
+ E1000_EEPROM_RW_REG_START;
+
+ E1000_WRITE_REG(hw, EERD, eerd);
+ error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
+
+ if (error)
+ break;
+ data[i] = (E1000_READ_REG(hw, EERD) >>
+ E1000_EEPROM_RW_REG_DATA);
- e1000_standby_eeprom(hw);
- for (i = 0; i < 200; i++) {
- eecd = E1000_READ_REG(hw, EECD);
- if (eecd & E1000_EECD_DO)
- return (TRUE);
- udelay(5);
}
- return (FALSE);
+
+ return error;
}
-static int
-e1000_write_eeprom(struct e1000_hw *hw, uint16_t Reg, uint16_t Data)
+static void
+e1000_release_eeprom(struct e1000_hw *hw)
{
uint32_t eecd;
- int large_eeprom = FALSE;
- int i = 0;
- /* Request EEPROM Access */
- if (hw->mac_type > e1000_82544) {
- eecd = E1000_READ_REG(hw, EECD);
- if (eecd & E1000_EECD_SIZE)
- large_eeprom = TRUE;
- eecd |= E1000_EECD_REQ;
+ DEBUGFUNC();
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if (hw->eeprom.type == e1000_eeprom_spi) {
+ eecd |= E1000_EECD_CS; /* Pull CS high */
+ eecd &= ~E1000_EECD_SK; /* Lower SCK */
+
E1000_WRITE_REG(hw, EECD, eecd);
- eecd = E1000_READ_REG(hw, EECD);
- while ((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
- i++;
- udelay(5);
- eecd = E1000_READ_REG(hw, EECD);
- }
- if (!(eecd & E1000_EECD_GNT)) {
- eecd &= ~E1000_EECD_REQ;
- E1000_WRITE_REG(hw, EECD, eecd);
- DEBUGOUT("Could not acquire EEPROM grant\n");
- return FALSE;
- }
- }
- e1000_setup_eeprom(hw);
- e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
- e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 6 : 4);
- e1000_standby_eeprom(hw);
- e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3);
- e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 8 : 6);
- e1000_shift_out_ee_bits(hw, Data, 16);
- if (!e1000_wait_eeprom_done(hw)) {
- return FALSE;
+
+ udelay(hw->eeprom.delay_usec);
+ } else if (hw->eeprom.type == e1000_eeprom_microwire) {
+ /* cleanup eeprom */
+
+ /* CS on Microwire is active-high */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Rising edge of clock */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+
+ /* Falling edge of clock */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
}
- e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
- e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 6 : 4);
- e1000_eeprom_cleanup(hw);
/* Stop requesting EEPROM access */
if (hw->mac_type > e1000_82544) {
- eecd = E1000_READ_REG(hw, EECD);
eecd &= ~E1000_EECD_REQ;
E1000_WRITE_REG(hw, EECD, eecd);
}
- i = 0;
- eecd = E1000_READ_REG(hw, EECD);
- while (((eecd & E1000_EECD_GNT)) && (i < 500)) {
- i++;
- udelay(10);
- eecd = E1000_READ_REG(hw, EECD);
- }
- if ((eecd & E1000_EECD_GNT)) {
- DEBUGOUT("Could not release EEPROM grant\n");
+}
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+e1000_spi_eeprom_ready(struct e1000_hw *hw)
+{
+ uint16_t retry_count = 0;
+ uint8_t spi_stat_reg;
+
+ DEBUGFUNC();
+
+ /* Read "Status Register" repeatedly until the LSB is cleared. The
+ * EEPROM will signal that the command has been completed by clearing
+ * bit 0 of the internal status register. If it's not cleared within
+ * 5 milliseconds, then error out.
+ */
+ retry_count = 0;
+ do {
+ e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+ hw->eeprom.opcode_bits);
+ spi_stat_reg = (uint8_t)e1000_shift_in_ee_bits(hw, 8);
+ if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+ break;
+
+ udelay(5);
+ retry_count += 5;
+
+ e1000_standby_eeprom(hw);
+ } while (retry_count < EEPROM_MAX_RETRY_SPI);
+
+ /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+ * only 0-5mSec on 5V devices)
+ */
+ if (retry_count >= EEPROM_MAX_RETRY_SPI) {
+ DEBUGOUT("SPI EEPROM Status error\n");
+ return -E1000_ERR_EEPROM;
}
- return TRUE;
+
+ return E1000_SUCCESS;
}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ *****************************************************************************/
+static int32_t
+e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t i = 0;
+
+ DEBUGFUNC();
+
+ /* If eeprom is not yet detected, do so now */
+ if (eeprom->word_size == 0)
+ e1000_init_eeprom_params(hw);
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= eeprom->word_size) ||
+ (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("\"words\" parameter out of bounds."
+ "Words = %d, size = %d\n", offset, eeprom->word_size);
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* EEPROM's that don't use EERD to read require us to bit-bang the SPI
+ * directly. In this case, we need to acquire the EEPROM so that
+ * FW or other port software does not interrupt.
+ */
+ if (e1000_is_onboard_nvm_eeprom(hw) == TRUE &&
+ hw->eeprom.use_eerd == FALSE) {
+
+ /* Prepare the EEPROM for bit-bang reading */
+ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Eerd register EEPROM access requires no eeprom aquire/release */
+ if (eeprom->use_eerd == TRUE)
+ return e1000_read_eeprom_eerd(hw, offset, words, data);
+
+ /* ich8lan does not support currently. if needed, please
+ * add corresponding code and functions.
+ */
+#if 0
+ /* ICH EEPROM access is done via the ICH flash controller */
+ if (eeprom->type == e1000_eeprom_ich8)
+ return e1000_read_eeprom_ich8(hw, offset, words, data);
#endif
+ /* Set up the SPI or Microwire EEPROM for bit-bang reading. We have
+ * acquired the EEPROM at this point, so any returns should relase it */
+ if (eeprom->type == e1000_eeprom_spi) {
+ uint16_t word_in;
+ uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
+
+ if (e1000_spi_eeprom_ready(hw)) {
+ e1000_release_eeprom(hw);
+ return -E1000_ERR_EEPROM;
+ }
+
+ e1000_standby_eeprom(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in
+ * the opcode */
+ if ((eeprom->address_bits == 8) && (offset >= 128))
+ read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2),
+ eeprom->address_bits);
+
+ /* Read the data. The address of the eeprom internally
+ * increments with each byte (spi) being read, saving on the
+ * overhead of eeprom setup and tear-down. The address
+ * counter will roll over if reading beyond the size of
+ * the eeprom, thus allowing the entire memory to be read
+ * starting from any offset. */
+ for (i = 0; i < words; i++) {
+ word_in = e1000_shift_in_ee_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
+ } else if (eeprom->type == e1000_eeprom_microwire) {
+ for (i = 0; i < words; i++) {
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw,
+ EEPROM_READ_OPCODE_MICROWIRE,
+ eeprom->opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset + i),
+ eeprom->address_bits);
+
+ /* Read the data. For microwire, each word requires
+ * the overhead of eeprom setup and tear-down. */
+ data[i] = e1000_shift_in_ee_bits(hw, 16);
+ e1000_standby_eeprom(hw);
+ }
+ }
+
+ /* End this read operation */
+ e1000_release_eeprom(hw);
+
+ return E1000_SUCCESS;
+}
/******************************************************************************
* Verifies that the EEPROM has a valid checksum
@@ -466,7 +882,7 @@ e1000_validate_eeprom_checksum(struct eth_device *nic)
DEBUGFUNC();
for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
- if (e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+ if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -480,8 +896,205 @@ e1000_validate_eeprom_checksum(struct eth_device *nic)
return -E1000_ERR_EEPROM;
}
}
+
+/*****************************************************************************
+ * Set PHY to class A mode
+ * Assumes the following operations will follow to enable the new class mode.
+ * 1. Do a PHY soft reset
+ * 2. Restart auto-negotiation or force link.
+ *
+ * hw - Struct containing variables accessed by shared code
+ ****************************************************************************/
+static int32_t
+e1000_set_phy_mode(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC();
+
+ if ((hw->mac_type == e1000_82545_rev_3) &&
+ (hw->media_type == e1000_media_type_copper)) {
+ ret_val = e1000_read_eeprom(hw, EEPROM_PHY_CLASS_WORD,
+ 1, &eeprom_data);
+ if (ret_val)
+ return ret_val;
+
+ if ((eeprom_data != EEPROM_RESERVED_WORD) &&
+ (eeprom_data & EEPROM_PHY_CLASS_A)) {
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_PHY_PAGE_SELECT, 0x000B);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_PHY_GEN_CONTROL, 0x8104);
+ if (ret_val)
+ return ret_val;
+
+ hw->phy_reset_disable = FALSE;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
#endif /* #ifndef CONFIG_AP1000 */
+/***************************************************************************
+ *
+ * Obtaining software semaphore bit (SMBI) before resetting PHY.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to obtain semaphore.
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_software_semaphore(struct e1000_hw *hw)
+{
+ int32_t timeout = hw->eeprom.word_size + 1;
+ uint32_t swsm;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type != e1000_80003es2lan)
+ return E1000_SUCCESS;
+
+ while (timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ /* If SMBI bit cleared, it is now set and we hold
+ * the semaphore */
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+ mdelay(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+static void
+e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+ uint32_t swsm;
+
+ DEBUGFUNC();
+
+ if (!hw->eeprom_semaphore_present)
+ return;
+
+ swsm = E1000_READ_REG(hw, SWSM);
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Release both semaphores. */
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ } else
+ swsm &= ~(E1000_SWSM_SWESMBI);
+ E1000_WRITE_REG(hw, SWSM, swsm);
+}
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+ int32_t timeout;
+ uint32_t swsm;
+
+ DEBUGFUNC();
+
+ if (!hw->eeprom_semaphore_present)
+ return E1000_SUCCESS;
+
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Get the SW semaphore. */
+ if (e1000_get_software_semaphore(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Get the FW semaphore. */
+ timeout = hw->eeprom.word_size + 1;
+ while (timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ swsm |= E1000_SWSM_SWESMBI;
+ E1000_WRITE_REG(hw, SWSM, swsm);
+ /* if we managed to set the bit we got the semaphore. */
+ swsm = E1000_READ_REG(hw, SWSM);
+ if (swsm & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ timeout--;
+ }
+
+ if (!timeout) {
+ /* Release semaphores */
+ e1000_put_hw_eeprom_semaphore(hw);
+ DEBUGOUT("Driver can't access the Eeprom - "
+ "SWESMBI bit is set.\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ return E1000_SUCCESS;
+}
+
+static int32_t
+e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
+{
+ uint32_t swfw_sync = 0;
+ uint32_t swmask = mask;
+ uint32_t fwmask = mask << 16;
+ int32_t timeout = 200;
+
+ DEBUGFUNC();
+ while (timeout) {
+ if (e1000_get_hw_eeprom_semaphore(hw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /* firmware currently using resource (fwmask) */
+ /* or other software thread currently using resource (swmask) */
+ e1000_put_hw_eeprom_semaphore(hw);
+ mdelay(5);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ return -E1000_ERR_SWFW_SYNC;
+ }
+
+ swfw_sync |= swmask;
+ E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_eeprom_semaphore(hw);
+ return E1000_SUCCESS;
+}
+
/******************************************************************************
* Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
* second function of dual function devices
@@ -501,7 +1114,7 @@ e1000_read_mac_addr(struct eth_device *nic)
for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
offset = i >> 1;
- if (e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+ if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -605,7 +1218,7 @@ e1000_clear_vfta(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
-static int
+int32_t
e1000_set_mac_type(struct e1000_hw *hw)
{
DEBUGFUNC();
@@ -636,21 +1249,88 @@ e1000_set_mac_type(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
hw->mac_type = e1000_82540;
break;
case E1000_DEV_ID_82545EM_COPPER:
- case E1000_DEV_ID_82545GM_COPPER:
case E1000_DEV_ID_82545EM_FIBER:
hw->mac_type = e1000_82545;
break;
+ case E1000_DEV_ID_82545GM_COPPER:
+ case E1000_DEV_ID_82545GM_FIBER:
+ case E1000_DEV_ID_82545GM_SERDES:
+ hw->mac_type = e1000_82545_rev_3;
+ break;
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
hw->mac_type = e1000_82546;
break;
+ case E1000_DEV_ID_82546GB_COPPER:
+ case E1000_DEV_ID_82546GB_FIBER:
+ case E1000_DEV_ID_82546GB_SERDES:
+ case E1000_DEV_ID_82546GB_PCIE:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+ hw->mac_type = e1000_82546_rev_3;
+ break;
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541EI_MOBILE:
+ case E1000_DEV_ID_82541ER_LOM:
+ hw->mac_type = e1000_82541;
+ break;
case E1000_DEV_ID_82541ER:
+ case E1000_DEV_ID_82541GI:
case E1000_DEV_ID_82541GI_LF:
+ case E1000_DEV_ID_82541GI_MOBILE:
hw->mac_type = e1000_82541_rev_2;
break;
+ case E1000_DEV_ID_82547EI:
+ case E1000_DEV_ID_82547EI_MOBILE:
+ hw->mac_type = e1000_82547;
+ break;
+ case E1000_DEV_ID_82547GI:
+ hw->mac_type = e1000_82547_rev_2;
+ break;
+ case E1000_DEV_ID_82571EB_COPPER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES_DUAL:
+ case E1000_DEV_ID_82571EB_SERDES_QUAD:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571PT_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
+ hw->mac_type = e1000_82571;
+ break;
+ case E1000_DEV_ID_82572EI_COPPER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82572EI_SERDES:
+ case E1000_DEV_ID_82572EI:
+ hw->mac_type = e1000_82572;
+ break;
+ case E1000_DEV_ID_82573E:
+ case E1000_DEV_ID_82573E_IAMT:
+ case E1000_DEV_ID_82573L:
+ hw->mac_type = e1000_82573;
+ break;
+ case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
+ case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->mac_type = e1000_80003es2lan;
+ break;
+ case E1000_DEV_ID_ICH8_IGP_M_AMT:
+ case E1000_DEV_ID_ICH8_IGP_AMT:
+ case E1000_DEV_ID_ICH8_IGP_C:
+ case E1000_DEV_ID_ICH8_IFE:
+ case E1000_DEV_ID_ICH8_IFE_GT:
+ case E1000_DEV_ID_ICH8_IFE_G:
+ case E1000_DEV_ID_ICH8_IGP_M:
+ hw->mac_type = e1000_ich8lan;
+ break;
default:
/* Should never have loaded on this device */
return -E1000_ERR_MAC_TYPE;
@@ -677,8 +1357,7 @@ e1000_reset_hw(struct e1000_hw *hw)
if (hw->mac_type == e1000_82542_rev2_0) {
DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
pci_write_config_word(hw->pdev, PCI_COMMAND,
- hw->
- pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
+ hw->pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
}
/* Clear interrupt mask to stop board from generating interrupts */
@@ -709,12 +1388,7 @@ e1000_reset_hw(struct e1000_hw *hw)
DEBUGOUT("Issuing a global reset to MAC\n");
ctrl = E1000_READ_REG(hw, CTRL);
-#if 0
- if (hw->mac_type > e1000_82543)
- E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
- else
-#endif
- E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
/* Force a reload from the EEPROM if necessary */
if (hw->mac_type < e1000_82540) {
@@ -746,6 +1420,127 @@ e1000_reset_hw(struct e1000_hw *hw)
if (hw->mac_type == e1000_82542_rev2_0) {
pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word);
}
+ E1000_WRITE_REG(hw, PBA, E1000_DEFAULT_PBA);
+}
+
+/******************************************************************************
+ *
+ * Initialize a number of hardware-dependent bits
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * This function contains hardware limitation workarounds for PCI-E adapters
+ *
+ *****************************************************************************/
+static void
+e1000_initialize_hardware_bits(struct e1000_hw *hw)
+{
+ if ((hw->mac_type >= e1000_82571) &&
+ (!hw->initialize_hw_bits_disable)) {
+ /* Settings common to all PCI-express silicon */
+ uint32_t reg_ctrl, reg_ctrl_ext;
+ uint32_t reg_tarc0, reg_tarc1;
+ uint32_t reg_tctl;
+ uint32_t reg_txdctl, reg_txdctl1;
+
+ /* link autonegotiation/sync workarounds */
+ reg_tarc0 = E1000_READ_REG(hw, TARC0);
+ reg_tarc0 &= ~((1 << 30)|(1 << 29)|(1 << 28)|(1 << 27));
+
+ /* Enable not-done TX descriptor counting */
+ reg_txdctl = E1000_READ_REG(hw, TXDCTL);
+ reg_txdctl |= E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, TXDCTL, reg_txdctl);
+
+ reg_txdctl1 = E1000_READ_REG(hw, TXDCTL1);
+ reg_txdctl1 |= E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, TXDCTL1, reg_txdctl1);
+
+ switch (hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ /* Clear PHY TX compatible mode bits */
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ reg_tarc1 &= ~((1 << 30)|(1 << 29));
+
+ /* link autonegotiation/sync workarounds */
+ reg_tarc0 |= ((1 << 26)|(1 << 25)|(1 << 24)|(1 << 23));
+
+ /* TX ring control fixes */
+ reg_tarc1 |= ((1 << 26)|(1 << 25)|(1 << 24));
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ case e1000_82573:
+ reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ reg_ctrl_ext &= ~(1 << 23);
+ reg_ctrl_ext |= (1 << 22);
+
+ /* TX byte count fix */
+ reg_ctrl = E1000_READ_REG(hw, CTRL);
+ reg_ctrl &= ~(1 << 29);
+
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
+ E1000_WRITE_REG(hw, CTRL, reg_ctrl);
+ break;
+ case e1000_80003es2lan:
+ /* improve small packet performace for fiber/serdes */
+ if ((hw->media_type == e1000_media_type_fiber)
+ || (hw->media_type ==
+ e1000_media_type_internal_serdes)) {
+ reg_tarc0 &= ~(1 << 20);
+ }
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ case e1000_ich8lan:
+ /* Reduce concurrent DMA requests to 3 from 4 */
+ if ((hw->revision_id < 3) ||
+ ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
+ (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))
+ reg_tarc0 |= ((1 << 29)|(1 << 28));
+
+ reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ reg_ctrl_ext |= (1 << 22);
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
+
+ /* workaround TX hang with TSO=on */
+ reg_tarc0 |= ((1 << 27)|(1 << 26)|(1 << 24)|(1 << 23));
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ /* workaround TX hang with TSO=on */
+ reg_tarc1 |= ((1 << 30)|(1 << 26)|(1 << 24));
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ default:
+ break;
+ }
+
+ E1000_WRITE_REG(hw, TARC0, reg_tarc0);
+ }
}
/******************************************************************************
@@ -763,49 +1558,43 @@ static int
e1000_init_hw(struct eth_device *nic)
{
struct e1000_hw *hw = nic->priv;
- uint32_t ctrl, status;
+ uint32_t ctrl;
uint32_t i;
int32_t ret_val;
uint16_t pcix_cmd_word;
uint16_t pcix_stat_hi_word;
uint16_t cmd_mmrbc;
uint16_t stat_mmrbc;
- e1000_bus_type bus_type = e1000_bus_type_unknown;
-
+ uint32_t mta_size;
+ uint32_t reg_data;
+ uint32_t ctrl_ext;
DEBUGFUNC();
-#if 0
- /* Initialize Identification LED */
- ret_val = e1000_id_led_init(hw);
- if (ret_val < 0) {
- DEBUGOUT("Error Initializing Identification LED\n");
- return ret_val;
- }
-#endif
- /* Set the Media Type and exit with error if it is not valid. */
- if (hw->mac_type != e1000_82543) {
- /* tbi_compatibility is only valid on 82543 */
- hw->tbi_compatibility_en = FALSE;
+ /* force full DMA clock frequency for 10/100 on ICH8 A0-B0 */
+ if ((hw->mac_type == e1000_ich8lan) &&
+ ((hw->revision_id < 3) ||
+ ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
+ (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))) {
+ reg_data = E1000_READ_REG(hw, STATUS);
+ reg_data &= ~0x80000000;
+ E1000_WRITE_REG(hw, STATUS, reg_data);
}
+ /* Do not need initialize Identification LED */
- if (hw->mac_type >= e1000_82543) {
- status = E1000_READ_REG(hw, STATUS);
- if (status & E1000_STATUS_TBIMODE) {
- hw->media_type = e1000_media_type_fiber;
- /* tbi_compatibility not valid on fiber */
- hw->tbi_compatibility_en = FALSE;
- } else {
- hw->media_type = e1000_media_type_copper;
- }
- } else {
- /* This is an 82542 (fiber only) */
- hw->media_type = e1000_media_type_fiber;
- }
+ /* Set the media type and TBI compatibility */
+ e1000_set_media_type(hw);
+
+ /* Must be called after e1000_set_media_type
+ * because media_type is used */
+ e1000_initialize_hardware_bits(hw);
/* Disabling VLAN filtering. */
DEBUGOUT("Initializing the IEEE VLAN\n");
- E1000_WRITE_REG(hw, VET, 0);
-
- e1000_clear_vfta(hw);
+ /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
+ if (hw->mac_type != e1000_ich8lan) {
+ if (hw->mac_type < e1000_82545_rev_3)
+ E1000_WRITE_REG(hw, VET, 0);
+ e1000_clear_vfta(hw);
+ }
/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
if (hw->mac_type == e1000_82542_rev2_0) {
@@ -833,26 +1622,33 @@ e1000_init_hw(struct eth_device *nic)
/* Zero out the Multicast HASH table */
DEBUGOUT("Zeroing the MTA\n");
- for (i = 0; i < E1000_MC_TBL_SIZE; i++)
+ mta_size = E1000_MC_TBL_SIZE;
+ if (hw->mac_type == e1000_ich8lan)
+ mta_size = E1000_MC_TBL_SIZE_ICH8LAN;
+ for (i = 0; i < mta_size; i++) {
E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
-
+ /* use write flush to prevent Memory Write Block (MWB) from
+ * occuring when accessing our register space */
+ E1000_WRITE_FLUSH(hw);
+ }
#if 0
/* Set the PCI priority bit correctly in the CTRL register. This
* determines if the adapter gives priority to receives, or if it
- * gives equal priority to transmits and receives.
+ * gives equal priority to transmits and receives. Valid only on
+ * 82542 and 82543 silicon.
*/
- if (hw->dma_fairness) {
+ if (hw->dma_fairness && hw->mac_type <= e1000_82543) {
ctrl = E1000_READ_REG(hw, CTRL);
E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
}
#endif
- if (hw->mac_type >= e1000_82543) {
- status = E1000_READ_REG(hw, STATUS);
- bus_type = (status & E1000_STATUS_PCIX_MODE) ?
- e1000_bus_type_pcix : e1000_bus_type_pci;
- }
+ switch (hw->mac_type) {
+ case e1000_82545_rev_3:
+ case e1000_82546_rev_3:
+ break;
+ default:
/* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
- if (bus_type == e1000_bus_type_pcix) {
+ if (hw->bus_type == e1000_bus_type_pcix) {
pci_read_config_word(hw->pdev, PCIX_COMMAND_REGISTER,
&pcix_cmd_word);
pci_read_config_word(hw->pdev, PCIX_STATUS_REGISTER_HI,
@@ -872,6 +1668,12 @@ e1000_init_hw(struct eth_device *nic)
pcix_cmd_word);
}
}
+ break;
+ }
+
+ /* More time needed for PHY to initialize */
+ if (hw->mac_type == e1000_ich8lan)
+ mdelay(15);
/* Call a subroutine to configure the link and setup flow control. */
ret_val = e1000_setup_link(nic);
@@ -884,6 +1686,48 @@ e1000_init_hw(struct eth_device *nic)
E1000_TXDCTL_FULL_TX_DESC_WB;
E1000_WRITE_REG(hw, TXDCTL, ctrl);
}
+
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_80003es2lan:
+ /* Enable retransmit on late collisions */
+ reg_data = E1000_READ_REG(hw, TCTL);
+ reg_data |= E1000_TCTL_RTLC;
+ E1000_WRITE_REG(hw, TCTL, reg_data);
+
+ /* Configure Gigabit Carry Extend Padding */
+ reg_data = E1000_READ_REG(hw, TCTL_EXT);
+ reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+ reg_data |= DEFAULT_80003ES2LAN_TCTL_EXT_GCEX;
+ E1000_WRITE_REG(hw, TCTL_EXT, reg_data);
+
+ /* Configure Transmit Inter-Packet Gap */
+ reg_data = E1000_READ_REG(hw, TIPG);
+ reg_data &= ~E1000_TIPG_IPGT_MASK;
+ reg_data |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
+ E1000_WRITE_REG(hw, TIPG, reg_data);
+
+ reg_data = E1000_READ_REG_ARRAY(hw, FFLT, 0x0001);
+ reg_data &= ~0x00100000;
+ E1000_WRITE_REG_ARRAY(hw, FFLT, 0x0001, reg_data);
+ /* Fall through */
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_ich8lan:
+ ctrl = E1000_READ_REG(hw, TXDCTL1);
+ ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH)
+ | E1000_TXDCTL_FULL_TX_DESC_WB;
+ E1000_WRITE_REG(hw, TXDCTL1, ctrl);
+ break;
+ }
+
+ if (hw->mac_type == e1000_82573) {
+ uint32_t gcr = E1000_READ_REG(hw, GCR);
+ gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+ E1000_WRITE_REG(hw, GCR, gcr);
+ }
+
#if 0
/* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
@@ -891,8 +1735,22 @@ e1000_init_hw(struct eth_device *nic)
* is no link.
*/
e1000_clear_hw_cntrs(hw);
+
+ /* ICH8 No-snoop bits are opposite polarity.
+ * Set to snoop by default after reset. */
+ if (hw->mac_type == e1000_ich8lan)
+ e1000_set_pci_ex_no_snoop(hw, PCI_EX_82566_SNOOP_ALL);
#endif
+ if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER ||
+ hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) {
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ /* Relaxed ordering must be disabled to avoid a parity
+ * error crash in a PCI slot. */
+ ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+
return ret_val;
}
@@ -917,6 +1775,11 @@ e1000_setup_link(struct eth_device *nic)
DEBUGFUNC();
+ /* In the case of the phy reset being blocked, we already have a link.
+ * We do not have to set it up again. */
+ if (e1000_check_phy_reset_block(hw))
+ return E1000_SUCCESS;
+
#ifndef CONFIG_AP1000
/* Read and store word 0x0F of the EEPROM. This word contains bits
* that determine the hardware's default PAUSE (flow control) mode,
@@ -926,7 +1789,8 @@ e1000_setup_link(struct eth_device *nic)
* control setting, then the variable hw->fc will
* be initialized based on a value in the EEPROM.
*/
- if (e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+ if (e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1,
+ &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -937,13 +1801,31 @@ e1000_setup_link(struct eth_device *nic)
#endif
if (hw->fc == e1000_fc_default) {
- if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
- hw->fc = e1000_fc_none;
- else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
- EEPROM_WORD0F_ASM_DIR)
- hw->fc = e1000_fc_tx_pause;
- else
+ switch (hw->mac_type) {
+ case e1000_ich8lan:
+ case e1000_82573:
hw->fc = e1000_fc_full;
+ break;
+ default:
+#ifndef CONFIG_AP1000
+ ret_val = e1000_read_eeprom(hw,
+ EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
+ if (ret_val) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+#else
+ eeprom_data = 0xb220;
+#endif
+ if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+ hw->fc = e1000_fc_none;
+ else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+ EEPROM_WORD0F_ASM_DIR)
+ hw->fc = e1000_fc_tx_pause;
+ else
+ hw->fc = e1000_fc_full;
+ break;
+ }
}
/* We want to save off the original Flow Control configuration just
@@ -985,12 +1867,16 @@ e1000_setup_link(struct eth_device *nic)
* control is disabled, because it does not hurt anything to
* initialize these registers.
*/
- DEBUGOUT
- ("Initializing the Flow Control address, type and timer regs\n");
+ DEBUGOUT("Initializing the Flow Control address, type"
+ "and timer regs\n");
+
+ /* FCAL/H and FCT are hardcoded to standard values in e1000_ich8lan. */
+ if (hw->mac_type != e1000_ich8lan) {
+ E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+ E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+ }
- E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
- E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
- E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
/* Set the flow control receive threshold registers. Normally,
@@ -1155,17 +2041,15 @@ e1000_setup_fiber_link(struct eth_device *nic)
}
/******************************************************************************
-* Detects which PHY is present and the speed and duplex
+* Make sure we have a valid PHY and change PHY mode before link setup.
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
-static int
-e1000_setup_copper_link(struct eth_device *nic)
+static int32_t
+e1000_copper_link_preconfig(struct e1000_hw *hw)
{
- struct e1000_hw *hw = nic->priv;
uint32_t ctrl;
int32_t ret_val;
- uint16_t i;
uint16_t phy_data;
DEBUGFUNC();
@@ -1180,28 +2064,684 @@ e1000_setup_copper_link(struct eth_device *nic)
ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
E1000_WRITE_REG(hw, CTRL, ctrl);
} else {
- ctrl |=
- (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX
+ | E1000_CTRL_SLU);
E1000_WRITE_REG(hw, CTRL, ctrl);
- e1000_phy_hw_reset(hw);
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val)
+ return ret_val;
}
/* Make sure we have a valid PHY */
ret_val = e1000_detect_gig_phy(hw);
- if (ret_val < 0) {
+ if (ret_val) {
DEBUGOUT("Error, did not detect valid phy.\n");
return ret_val;
}
DEBUGOUT("Phy ID = %x \n", hw->phy_id);
- /* Enable CRS on TX. This must be set for half-duplex operation. */
- if (e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
+#ifndef CONFIG_AP1000
+ /* Set PHY to class A mode (if necessary) */
+ ret_val = e1000_set_phy_mode(hw);
+ if (ret_val)
+ return ret_val;
+#endif
+ if ((hw->mac_type == e1000_82545_rev_3) ||
+ (hw->mac_type == e1000_82546_rev_3)) {
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+ &phy_data);
+ phy_data |= 0x00000008;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+ phy_data);
+ }
+
+ if (hw->mac_type <= e1000_82543 ||
+ hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
+ hw->mac_type == e1000_82541_rev_2
+ || hw->mac_type == e1000_82547_rev_2)
+ hw->phy_reset_disable = FALSE;
+
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu state according to the active flag. When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ * E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+static int32_t
+e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active)
+{
+ uint32_t phy_ctrl = 0;
+ int32_t ret_val;
+ uint16_t phy_data;
+ DEBUGFUNC();
+
+ if (hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2
+ && hw->phy_type != e1000_phy_igp_3)
+ return E1000_SUCCESS;
+
+ /* During driver activity LPLU should not be used or it will attain link
+ * from the lowest speeds starting from 10Mbps. The capability is used
+ * for Dx transitions and states */
+ if (hw->mac_type == e1000_82541_rev_2
+ || hw->mac_type == e1000_82547_rev_2) {
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->mac_type == e1000_ich8lan) {
+ /* MAC writes into PHY register based on the state transition
+ * and start auto-negotiation. SW driver can overwrite the
+ * settings in CSR PHY power control E1000_PHY_CTRL register. */
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+ } else {
+ ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ if (!active) {
+ if (hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547_rev_2) {
+ phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
+ phy_data &= ~IGP02E1000_PM_D3_LPLU;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
+ * Dx states where the power conservation is most important. During
+ * driver activity we should enable SmartSpeed, so performance is
+ * maintained. */
+ if (hw->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ } else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT)
+ || (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL) ||
+ (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
+
+ if (hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547_rev_2) {
+ phy_data |= IGP01E1000_GMII_FLEX_SPD;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_GMII_FIFO, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
+ phy_data |= IGP02E1000_PM_D3_LPLU;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ /* When LPLU is enabled we should disable SmartSpeed */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu d0 state according to the active flag. When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ * E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+static int32_t
+e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active)
+{
+ uint32_t phy_ctrl = 0;
+ int32_t ret_val;
+ uint16_t phy_data;
+ DEBUGFUNC();
+
+ if (hw->mac_type <= e1000_82547_rev_2)
+ return E1000_SUCCESS;
+
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+ } else {
+ ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ if (!active) {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
+ phy_data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
+ * Dx states where the power conservation is most important. During
+ * driver activity we should enable SmartSpeed, so performance is
+ * maintained. */
+ if (hw->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+
+ } else {
+
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
+ phy_data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* When LPLU is enabled we should disable SmartSpeed */
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ }
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_igp series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_igp_setup(struct e1000_hw *hw)
+{
+ uint32_t led_ctrl;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGOUT();
+
+ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ ret_val = e1000_phy_reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
}
+
+ /* Wait 15ms for MAC to configure PHY from eeprom settings */
+ mdelay(15);
+ if (hw->mac_type != e1000_ich8lan) {
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
+
+ /* The NVM settings will configure LPLU in D3 for IGP2 and IGP3 PHYs */
+ if (hw->phy_type == e1000_phy_igp) {
+ /* disable lplu d3 during driver init */
+ ret_val = e1000_set_d3_lplu_state(hw, FALSE);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D3\n");
+ return ret_val;
+ }
+ }
+
+ /* disable lplu d0 during driver init */
+ ret_val = e1000_set_d0_lplu_state(hw, FALSE);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D0\n");
+ return ret_val;
+ }
+ /* Configure mdi-mdix settings */
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ hw->dsp_config_state = e1000_dsp_config_disabled;
+ /* Force MDI for earlier revs of the IGP PHY */
+ phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX
+ | IGP01E1000_PSCR_FORCE_MDI_MDIX);
+ hw->mdix = 1;
+
+ } else {
+ hw->dsp_config_state = e1000_dsp_config_enabled;
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 2:
+ phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 0:
+ default:
+ phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
+ break;
+ }
+ }
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* set auto-master slave resolution settings */
+ if (hw->autoneg) {
+ e1000_ms_type phy_ms_setting = hw->master_slave;
+
+ if (hw->ffe_config_state == e1000_ffe_config_active)
+ hw->ffe_config_state = e1000_ffe_config_enabled;
+
+ if (hw->dsp_config_state == e1000_dsp_config_activated)
+ hw->dsp_config_state = e1000_dsp_config_enabled;
+
+ /* when autonegotiation advertisment is only 1000Mbps then we
+ * should disable SmartSpeed and enable Auto MasterSlave
+ * resolution as hardware default. */
+ if (hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+ ret_val = e1000_read_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if (ret_val)
+ return ret_val;
+ /* Set auto Master/Slave resolution process */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* load defaults for future use */
+ hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
+ ((phy_data & CR_1000T_MS_VALUE) ?
+ e1000_ms_force_master :
+ e1000_ms_force_slave) :
+ e1000_ms_auto;
+
+ switch (phy_ms_setting) {
+ case e1000_ms_force_master:
+ phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_force_slave:
+ phy_data |= CR_1000T_MS_ENABLE;
+ phy_data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_auto:
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ default:
+ break;
+ }
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * This function checks the mode of the firmware.
+ *
+ * returns - TRUE when the mode is IAMT or FALSE.
+ ****************************************************************************/
+boolean_t
+e1000_check_mng_mode(struct e1000_hw *hw)
+{
+ uint32_t fwsm;
+ DEBUGFUNC();
+
+ fwsm = E1000_READ_REG(hw, FWSM);
+
+ if (hw->mac_type == e1000_ich8lan) {
+ if ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ return TRUE;
+ } else if ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ return TRUE;
+
+ return FALSE;
+}
+
+static int32_t
+e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data)
+{
+ uint32_t reg_val;
+ uint16_t swfw;
+ DEBUGFUNC();
+
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+ } else {
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT)
+ & E1000_KUMCTRLSTA_OFFSET) | data;
+ E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
+ udelay(2);
+
+ return E1000_SUCCESS;
+}
+
+static int32_t
+e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data)
+{
+ uint32_t reg_val;
+ uint16_t swfw;
+ DEBUGFUNC();
+
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+ } else {
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ /* Write register address */
+ reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) &
+ E1000_KUMCTRLSTA_OFFSET) | E1000_KUMCTRLSTA_REN;
+ E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
+ udelay(2);
+
+ /* Read the data returned */
+ reg_val = E1000_READ_REG(hw, KUMCTRLSTA);
+ *data = (uint16_t)reg_val;
+
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_gg82563 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_ggp_setup(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+ uint32_t reg_data;
+
+ DEBUGFUNC();
+
+ if (!hw->phy_reset_disable) {
+ /* Enable CRS on TX for half-duplex operation. */
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ /* Use 25MHz for both link down and 1000BASE-T for Tx clock */
+ phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
+
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+ break;
+ case 2:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+ break;
+ case 0:
+ default:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_SPEC_CTRL, phy_data);
+
+ if (ret_val)
+ return ret_val;
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+ } /* phy_reset_disable */
+
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Bypass RX and TX FIFO's */
+ ret_val = e1000_write_kmrn_reg(hw,
+ E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL,
+ E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS
+ | E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_SPEC_CTRL_2, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_SPEC_CTRL_2, phy_data);
+
+ if (ret_val)
+ return ret_val;
+
+ reg_data = E1000_READ_REG(hw, CTRL_EXT);
+ reg_data &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_data);
+
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_PWR_MGMT_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Do not init these registers when the HW is in IAMT mode, since the
+ * firmware will have already initialized them. We only initialize
+ * them if the HW is not in IAMT mode.
+ */
+ if (e1000_check_mng_mode(hw) == FALSE) {
+ /* Enable Electrical Idle on the PHY */
+ phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_PWR_MGMT_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_KMRN_MODE_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_KMRN_MODE_CTRL, phy_data);
+
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Workaround: Disable padding in Kumeran interface in the MAC
+ * and in the PHY to avoid CRC errors.
+ */
+ ret_val = e1000_read_phy_reg(hw,
+ GG82563_PHY_INBAND_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_data |= GG82563_ICR_DIS_PADDING;
+ ret_val = e1000_write_phy_reg(hw,
+ GG82563_PHY_INBAND_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_m88 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_mgp_setup(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
+
+ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-#if 0
/* Options:
* MDI/MDI-X = 0 (default)
* 0 - Auto for all speeds
@@ -1210,6 +2750,7 @@ e1000_setup_copper_link(struct eth_device *nic)
* 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
*/
phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
switch (hw->mdix) {
case 1:
phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
@@ -1225,68 +2766,75 @@ e1000_setup_copper_link(struct eth_device *nic)
phy_data |= M88E1000_PSCR_AUTO_X_MODE;
break;
}
-#else
- phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-#endif
-#if 0
/* Options:
* disable_polarity_correction = 0 (default)
- * Automatic Correction for Reversed Cable Polarity
+ * Automatic Correction for Reversed Cable Polarity
* 0 - Disabled
* 1 - Enabled
*/
phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
- if (hw->disable_polarity_correction == 1)
- phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-#else
- phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-#endif
- if (e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
- DEBUGOUT("PHY Write Error\n");
- return -E1000_ERR_PHY;
- }
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
- /* Force TX_CLK in the Extended PHY Specific Control Register
- * to 25MHz clock.
- */
- if (e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
- phy_data |= M88E1000_EPSCR_TX_CLK_25;
- /* Configure Master and Slave downshift values */
- phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
- M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
- phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
- M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
- if (e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
- DEBUGOUT("PHY Write Error\n");
- return -E1000_ERR_PHY;
+ if (hw->phy_revision < M88E1011_I_REV_4) {
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = e1000_read_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if ((hw->phy_revision == E1000_REVISION_2) &&
+ (hw->phy_id == M88E1111_I_PHY_ID)) {
+ /* Vidalia Phy, set the downshift counter to 5x */
+ phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK);
+ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK
+ | M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X
+ | M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
}
/* SW Reset the PHY so all changes take effect */
ret_val = e1000_phy_reset(hw);
- if (ret_val < 0) {
+ if (ret_val) {
DEBUGOUT("Error Resetting the PHY\n");
return ret_val;
}
- /* Options:
- * autoneg = 1 (default)
- * PHY will advertise value(s) parsed from
- * autoneg_advertised and fc
- * autoneg = 0
- * PHY will be set to 10H, 10F, 100H, or 100F
- * depending on value parsed from forced_speed_duplex.
- */
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Setup auto-negotiation and flow control advertisements,
+* and then perform auto-negotiation.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC();
- /* Is autoneg enabled? This is enabled by default or by software override.
- * If so, call e1000_phy_setup_autoneg routine to parse the
- * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
- * user should have provided a speed/duplex override. If so, then call
- * e1000_phy_force_speed_duplex to parse and set this up.
- */
/* Perform some bounds checking on the hw->autoneg_advertised
* parameter. If this variable is zero, then set it to the default.
*/
@@ -1298,9 +2846,13 @@ e1000_setup_copper_link(struct eth_device *nic)
if (hw->autoneg_advertised == 0)
hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ /* IFE phy only supports 10/100 */
+ if (hw->phy_type == e1000_phy_ife)
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL;
+
DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
ret_val = e1000_phy_setup_autoneg(hw);
- if (ret_val < 0) {
+ if (ret_val) {
DEBUGOUT("Error Setting up Auto-Negotiation\n");
return ret_val;
}
@@ -1309,82 +2861,177 @@ e1000_setup_copper_link(struct eth_device *nic)
/* Restart auto-negotiation by setting the Auto Neg Enable bit and
* the Auto Neg Restart bit in the PHY control register.
*/
- if (e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
- if (e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
- DEBUGOUT("PHY Write Error\n");
- return -E1000_ERR_PHY;
- }
-#if 0
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
/* Does the user want to wait for Auto-Neg to complete here, or
* check at a later time (for example, callback routine).
*/
+ /* If we do not wait for autonegtation to complete I
+ * do not see a valid link status.
+ * wait_autoneg_complete = 1 .
+ */
if (hw->wait_autoneg_complete) {
ret_val = e1000_wait_autoneg(hw);
- if (ret_val < 0) {
- DEBUGOUT
- ("Error while waiting for autoneg to complete\n");
+ if (ret_val) {
+ DEBUGOUT("Error while waiting for autoneg"
+ "to complete\n");
return ret_val;
}
}
-#else
- /* If we do not wait for autonegtation to complete I
- * do not see a valid link status.
- */
- ret_val = e1000_wait_autoneg(hw);
- if (ret_val < 0) {
- DEBUGOUT("Error while waiting for autoneg to complete\n");
+
+ hw->get_link_status = TRUE;
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Config the MAC and the PHY after link is up.
+* 1) Set up the MAC to the current PHY speed/duplex
+* if we are on 82543. If we
+* are on newer silicon, we only need to configure
+* collision distance in the Transmit Control Register.
+* 2) Set up flow control on the MAC to that established with
+* the link partner.
+* 3) Config DSP to improve Gigabit link quality for some PHY revisions.
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_copper_link_postconfig(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ DEBUGFUNC();
+
+ if (hw->mac_type >= e1000_82544) {
+ e1000_config_collision_dist(hw);
+ } else {
+ ret_val = e1000_config_mac_to_phy(hw);
+ if (ret_val) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Configuring Flow Control\n");
return ret_val;
}
-#endif
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Detects which PHY is present and setup the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int
+e1000_setup_copper_link(struct eth_device *nic)
+{
+ struct e1000_hw *hw = nic->priv;
+ int32_t ret_val;
+ uint16_t i;
+ uint16_t phy_data;
+ uint16_t reg_data;
+
+ DEBUGFUNC();
+
+ switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ case e1000_ich8lan:
+ /* Set the mac to wait the maximum time between each
+ * iteration and increase the max iterations when
+ * polling the phy; this fixes erroneous timeouts at 10Mbps. */
+ ret_val = e1000_write_kmrn_reg(hw,
+ GG82563_REG(0x34, 4), 0xFFFF);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_kmrn_reg(hw,
+ GG82563_REG(0x34, 9), &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= 0x3F;
+ ret_val = e1000_write_kmrn_reg(hw,
+ GG82563_REG(0x34, 9), reg_data);
+ if (ret_val)
+ return ret_val;
+ default:
+ break;
+ }
+
+ /* Check if it is a valid PHY and set PHY mode if necessary. */
+ ret_val = e1000_copper_link_preconfig(hw);
+ if (ret_val)
+ return ret_val;
+ switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ /* Kumeran registers are written-only */
+ reg_data =
+ E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT;
+ reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING;
+ ret_val = e1000_write_kmrn_reg(hw,
+ E1000_KUMCTRLSTA_OFFSET_INB_CTRL, reg_data);
+ if (ret_val)
+ return ret_val;
+ break;
+ default:
+ break;
+ }
+
+ if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
+ hw->phy_type == e1000_phy_igp_2) {
+ ret_val = e1000_copper_link_igp_setup(hw);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->phy_type == e1000_phy_m88) {
+ ret_val = e1000_copper_link_mgp_setup(hw);
+ if (ret_val)
+ return ret_val;
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+ ret_val = e1000_copper_link_ggp_setup(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* always auto */
+ /* Setup autoneg and flow control advertisement
+ * and perform autonegotiation */
+ ret_val = e1000_copper_link_autoneg(hw);
+ if (ret_val)
+ return ret_val;
/* Check link status. Wait up to 100 microseconds for link to become
* valid.
*/
for (i = 0; i < 10; i++) {
- if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
- if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
if (phy_data & MII_SR_LINK_STATUS) {
- /* We have link, so we need to finish the config process:
- * 1) Set up the MAC to the current PHY speed/duplex
- * if we are on 82543. If we
- * are on newer silicon, we only need to configure
- * collision distance in the Transmit Control Register.
- * 2) Set up flow control on the MAC to that established with
- * the link partner.
- */
- if (hw->mac_type >= e1000_82544) {
- e1000_config_collision_dist(hw);
- } else {
- ret_val = e1000_config_mac_to_phy(hw);
- if (ret_val < 0) {
- DEBUGOUT
- ("Error configuring MAC to PHY settings\n");
- return ret_val;
- }
- }
- ret_val = e1000_config_fc_after_link_up(hw);
- if (ret_val < 0) {
- DEBUGOUT("Error Configuring Flow Control\n");
+ /* Config the MAC and PHY after link is up */
+ ret_val = e1000_copper_link_postconfig(hw);
+ if (ret_val)
return ret_val;
- }
+
DEBUGOUT("Valid link established!!!\n");
- return 0;
+ return E1000_SUCCESS;
}
udelay(10);
}
DEBUGOUT("Unable to establish link!!!\n");
- return -E1000_ERR_NOLINK;
+ return E1000_SUCCESS;
}
/******************************************************************************
@@ -1392,25 +3039,28 @@ e1000_setup_copper_link(struct eth_device *nic)
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
-static int
+int32_t
e1000_phy_setup_autoneg(struct e1000_hw *hw)
{
+ int32_t ret_val;
uint16_t mii_autoneg_adv_reg;
uint16_t mii_1000t_ctrl_reg;
DEBUGFUNC();
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
- if (e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
+ ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
- /* Read the MII 1000Base-T Control Register (Address 9). */
- if (e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
+ if (hw->phy_type != e1000_phy_ife) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
+ &mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ } else
+ mii_1000t_ctrl_reg = 0;
/* Need to parse both autoneg_advertised and fc and set up
* the appropriate PHY registers. First we will parse for
@@ -1421,7 +3071,7 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
/* First we clear all the 10/100 mb speed bits in the Auto-Neg
* Advertisement Register (Address 4) and the 1000 mb speed bits in
- * the 1000Base-T Control Register (Address 9).
+ * the 1000Base-T Control Register (Address 9).
*/
mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
@@ -1517,18 +3167,20 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
return -E1000_ERR_CONFIG;
}
- if (e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) {
- DEBUGOUT("PHY Write Error\n");
- return -E1000_ERR_PHY;
- }
+ ret_val = e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
DEBUGOUT("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
- if (e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) {
- DEBUGOUT("PHY Write Error\n");
- return -E1000_ERR_PHY;
+ if (hw->phy_type != e1000_phy_ife) {
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+ mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
}
- return 0;
+
+ return E1000_SUCCESS;
}
/******************************************************************************
@@ -1542,12 +3194,19 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
static void
e1000_config_collision_dist(struct e1000_hw *hw)
{
- uint32_t tctl;
+ uint32_t tctl, coll_dist;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type < e1000_82543)
+ coll_dist = E1000_COLLISION_DISTANCE_82542;
+ else
+ coll_dist = E1000_COLLISION_DISTANCE;
tctl = E1000_READ_REG(hw, TCTL);
tctl &= ~E1000_TCTL_COLD;
- tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+ tctl |= coll_dist << E1000_COLD_SHIFT;
E1000_WRITE_REG(hw, TCTL, tctl);
E1000_WRITE_FLUSH(hw);
@@ -1681,7 +3340,7 @@ e1000_force_mac_fc(struct e1000_hw *hw)
* based on the flow control negotiated by the PHY. In TBI mode, the TFCE
* and RFCE bits will be automaticaly set to the negotiated flow control mode.
*****************************************************************************/
-static int
+static int32_t
e1000_config_fc_after_link_up(struct e1000_hw *hw)
{
int32_t ret_val;
@@ -1697,7 +3356,11 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* so we had to force link. In this case, we need to force the
* configuration of the MAC to match the "fc" parameter.
*/
- if ((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) {
+ if (((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed))
+ || ((hw->media_type == e1000_media_type_internal_serdes)
+ && (hw->autoneg_failed))
+ || ((hw->media_type == e1000_media_type_copper)
+ && (!hw->autoneg))) {
ret_val = e1000_force_mac_fc(hw);
if (ret_val < 0) {
DEBUGOUT("Error forcing flow control settings\n");
@@ -1881,7 +3544,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
("Copper PHY and Auto Neg has not completed.\r\n");
}
}
- return 0;
+ return E1000_SUCCESS;
}
/******************************************************************************
@@ -2070,17 +3733,92 @@ e1000_check_for_link(struct eth_device *nic)
}
/******************************************************************************
+* Configure the MAC-to-PHY interface for 10/100Mbps
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, uint16_t duplex)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint32_t tipg;
+ uint16_t reg_data;
+
+ DEBUGFUNC();
+
+ reg_data = E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT;
+ ret_val = e1000_write_kmrn_reg(hw,
+ E1000_KUMCTRLSTA_OFFSET_HD_CTRL, reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100;
+ E1000_WRITE_REG(hw, TIPG, tipg);
+
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+ if (ret_val)
+ return ret_val;
+
+ if (duplex == HALF_DUPLEX)
+ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ else
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+ return ret_val;
+}
+
+static int32_t
+e1000_configure_kmrn_for_1000(struct e1000_hw *hw)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint16_t reg_data;
+ uint32_t tipg;
+
+ DEBUGFUNC();
+
+ reg_data = E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT;
+ ret_val = e1000_write_kmrn_reg(hw,
+ E1000_KUMCTRLSTA_OFFSET_HD_CTRL, reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
+ E1000_WRITE_REG(hw, TIPG, tipg);
+
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+ if (ret_val)
+ return ret_val;
+
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+ return ret_val;
+}
+
+/******************************************************************************
* Detects the current speed and duplex settings of the hardware.
*
* hw - Struct containing variables accessed by shared code
* speed - Speed of the connection
* duplex - Duplex setting of the connection
*****************************************************************************/
-static void
-e1000_get_speed_and_duplex(struct e1000_hw *hw,
- uint16_t * speed, uint16_t * duplex)
+static int
+e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t *speed,
+ uint16_t *duplex)
{
uint32_t status;
+ int32_t ret_val;
+ uint16_t phy_data;
DEBUGFUNC();
@@ -2109,6 +3847,41 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
*speed = SPEED_1000;
*duplex = FULL_DUPLEX;
}
+
+ /* IGP01 PHY may advertise full duplex operation after speed downgrade
+ * even if it is operating at half duplex. Here we set the duplex
+ * settings to match the duplex in the link partner's capabilities.
+ */
+ if (hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
+ ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(phy_data & NWAY_ER_LP_NWAY_CAPS))
+ *duplex = HALF_DUPLEX;
+ else {
+ ret_val = e1000_read_phy_reg(hw,
+ PHY_LP_ABILITY, &phy_data);
+ if (ret_val)
+ return ret_val;
+ if ((*speed == SPEED_100 &&
+ !(phy_data & NWAY_LPAR_100TX_FD_CAPS))
+ || (*speed == SPEED_10
+ && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
+ *duplex = HALF_DUPLEX;
+ }
+ }
+
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (hw->media_type == e1000_media_type_copper)) {
+ if (*speed == SPEED_1000)
+ ret_val = e1000_configure_kmrn_for_1000(hw);
+ else
+ ret_val = e1000_configure_kmrn_for_10_100(hw, *duplex);
+ if (ret_val)
+ return ret_val;
+ }
+ return E1000_SUCCESS;
}
/******************************************************************************
@@ -2429,30 +4202,132 @@ e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t phy_data)
}
/******************************************************************************
+ * Checks if PHY reset is blocked due to SOL/IDER session, for example.
+ * Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to
+ * the caller to figure out how to deal with it.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_BLK_PHY_RESET
+ * E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+e1000_check_phy_reset_block(struct e1000_hw *hw)
+{
+ uint32_t manc = 0;
+ uint32_t fwsm = 0;
+
+ if (hw->mac_type == e1000_ich8lan) {
+ fwsm = E1000_READ_REG(hw, FWSM);
+ return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS
+ : E1000_BLK_PHY_RESET;
+ }
+
+ if (hw->mac_type > e1000_82547_rev_2)
+ manc = E1000_READ_REG(hw, MANC);
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+ E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * Checks if the PHY configuration is done
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_phy_cfg_done(struct e1000_hw *hw)
+{
+ int32_t timeout = PHY_CFG_TIMEOUT;
+ uint32_t cfg_mask = E1000_EEPROM_CFG_DONE;
+
+ DEBUGFUNC();
+
+ switch (hw->mac_type) {
+ default:
+ mdelay(10);
+ break;
+ case e1000_80003es2lan:
+ /* Separate *_CFG_DONE_* bit for each port */
+ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+ cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1;
+ /* Fall Through */
+ case e1000_82571:
+ case e1000_82572:
+ while (timeout) {
+ if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
+ break;
+ else
+ mdelay(1);
+ timeout--;
+ }
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not "
+ "completed.\n");
+ return -E1000_ERR_RESET;
+ }
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
* Returns the PHY to the power-on reset state
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
-static void
+int32_t
e1000_phy_hw_reset(struct e1000_hw *hw)
{
- uint32_t ctrl;
- uint32_t ctrl_ext;
+ uint32_t ctrl, ctrl_ext;
+ uint32_t led_ctrl;
+ int32_t ret_val;
+ uint16_t swfw;
DEBUGFUNC();
+ /* In the case of the phy reset being blocked, it's not an error, we
+ * simply return success without performing the reset. */
+ ret_val = e1000_check_phy_reset_block(hw);
+ if (ret_val)
+ return E1000_SUCCESS;
+
DEBUGOUT("Resetting Phy...\n");
if (hw->mac_type > e1000_82543) {
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+ } else {
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw)) {
+ DEBUGOUT("Unable to acquire swfw sync\n");
+ return -E1000_ERR_SWFW_SYNC;
+ }
/* Read the device control register and assert the E1000_CTRL_PHY_RST
* bit. Then, take it out of reset.
*/
ctrl = E1000_READ_REG(hw, CTRL);
E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
E1000_WRITE_FLUSH(hw);
- mdelay(10);
+
+ if (hw->mac_type < e1000_82571)
+ udelay(10);
+ else
+ udelay(100);
+
E1000_WRITE_REG(hw, CTRL, ctrl);
E1000_WRITE_FLUSH(hw);
+
+ if (hw->mac_type >= e1000_82571)
+ mdelay(10);
+
} else {
/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
* bit to put the PHY into reset. Then, take it out of reset.
@@ -2468,6 +4343,127 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
}
udelay(150);
+
+ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
+
+ /* Wait for FW to finish PHY configuration. */
+ ret_val = e1000_get_phy_cfg_done(hw);
+ if (ret_val != E1000_SUCCESS)
+ return ret_val;
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * IGP phy init script - initializes the GbE PHY
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_phy_init_script(struct e1000_hw *hw)
+{
+ uint32_t ret_val;
+ uint16_t phy_saved_data;
+ DEBUGFUNC();
+
+ if (hw->phy_init_script) {
+ mdelay(20);
+
+ /* Save off the current value of register 0x2F5B to be
+ * restored at the end of this routine. */
+ ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+ /* Disabled the PHY transmitter */
+ e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+ mdelay(20);
+
+ e1000_write_phy_reg(hw, 0x0000, 0x0140);
+
+ mdelay(5);
+
+ switch (hw->mac_type) {
+ case e1000_82541:
+ case e1000_82547:
+ e1000_write_phy_reg(hw, 0x1F95, 0x0001);
+
+ e1000_write_phy_reg(hw, 0x1F71, 0xBD21);
+
+ e1000_write_phy_reg(hw, 0x1F79, 0x0018);
+
+ e1000_write_phy_reg(hw, 0x1F30, 0x1600);
+
+ e1000_write_phy_reg(hw, 0x1F31, 0x0014);
+
+ e1000_write_phy_reg(hw, 0x1F32, 0x161C);
+
+ e1000_write_phy_reg(hw, 0x1F94, 0x0003);
+
+ e1000_write_phy_reg(hw, 0x1F96, 0x003F);
+
+ e1000_write_phy_reg(hw, 0x2010, 0x0008);
+ break;
+
+ case e1000_82541_rev_2:
+ case e1000_82547_rev_2:
+ e1000_write_phy_reg(hw, 0x1F73, 0x0099);
+ break;
+ default:
+ break;
+ }
+
+ e1000_write_phy_reg(hw, 0x0000, 0x3300);
+
+ mdelay(20);
+
+ /* Now enable the transmitter */
+ e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+ if (hw->mac_type == e1000_82547) {
+ uint16_t fused, fine, coarse;
+
+ /* Move to analog registers page */
+ e1000_read_phy_reg(hw,
+ IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
+
+ if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
+ e1000_read_phy_reg(hw,
+ IGP01E1000_ANALOG_FUSE_STATUS, &fused);
+
+ fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
+ coarse = fused
+ & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
+
+ if (coarse >
+ IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
+ coarse -=
+ IGP01E1000_ANALOG_FUSE_COARSE_10;
+ fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
+ } else if (coarse
+ == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
+ fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
+
+ fused = (fused
+ & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
+ (fine
+ & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
+ (coarse
+ & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
+
+ e1000_write_phy_reg(hw,
+ IGP01E1000_ANALOG_FUSE_CONTROL, fused);
+ e1000_write_phy_reg(hw,
+ IGP01E1000_ANALOG_FUSE_BYPASS,
+ IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
+ }
+ }
+ }
}
/******************************************************************************
@@ -2475,26 +4471,49 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
*
-* Sets bit 15 of the MII Control regiser
+* Sets bit 15 of the MII Control register
******************************************************************************/
-static int
+int32_t
e1000_phy_reset(struct e1000_hw *hw)
{
+ int32_t ret_val;
uint16_t phy_data;
DEBUGFUNC();
- if (e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
- phy_data |= MII_CR_RESET;
- if (e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
- DEBUGOUT("PHY Write Error\n");
- return -E1000_ERR_PHY;
+ /* In the case of the phy reset being blocked, it's not an error, we
+ * simply return success without performing the reset. */
+ ret_val = e1000_check_phy_reset_block(hw);
+ if (ret_val)
+ return E1000_SUCCESS;
+
+ switch (hw->phy_type) {
+ case e1000_phy_igp:
+ case e1000_phy_igp_2:
+ case e1000_phy_igp_3:
+ case e1000_phy_ife:
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val)
+ return ret_val;
+ break;
+ default:
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= MII_CR_RESET;
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+ break;
}
- udelay(1);
- return 0;
+
+ if (hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2)
+ e1000_phy_init_script(hw);
+
+ return E1000_SUCCESS;
}
static int e1000_set_phy_type (struct e1000_hw *hw)
@@ -2508,14 +4527,31 @@ static int e1000_set_phy_type (struct e1000_hw *hw)
case M88E1000_E_PHY_ID:
case M88E1000_I_PHY_ID:
case M88E1011_I_PHY_ID:
+ case M88E1111_I_PHY_ID:
hw->phy_type = e1000_phy_m88;
break;
case IGP01E1000_I_PHY_ID:
if (hw->mac_type == e1000_82541 ||
- hw->mac_type == e1000_82541_rev_2) {
+ hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547 ||
+ hw->mac_type == e1000_82547_rev_2) {
+ hw->phy_type = e1000_phy_igp;
hw->phy_type = e1000_phy_igp;
break;
}
+ case IGP03E1000_E_PHY_ID:
+ hw->phy_type = e1000_phy_igp_3;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ hw->phy_type = e1000_phy_ife;
+ break;
+ case GG82563_E_PHY_ID:
+ if (hw->mac_type == e1000_80003es2lan) {
+ hw->phy_type = e1000_phy_gg82563;
+ break;
+ }
/* Fall Through */
default:
/* Should never have loaded on this device */
@@ -2531,27 +4567,47 @@ static int e1000_set_phy_type (struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
-static int
+static int32_t
e1000_detect_gig_phy(struct e1000_hw *hw)
{
- int32_t phy_init_status;
+ int32_t phy_init_status, ret_val;
uint16_t phy_id_high, phy_id_low;
- int match = FALSE;
+ boolean_t match = FALSE;
DEBUGFUNC();
- /* Read the PHY ID Registers to identify which PHY is onboard. */
- if (e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
+ /* The 82571 firmware may still be configuring the PHY. In this
+ * case, we cannot access the PHY until the configuration is done. So
+ * we explicitly set the PHY values. */
+ if (hw->mac_type == e1000_82571 ||
+ hw->mac_type == e1000_82572) {
+ hw->phy_id = IGP01E1000_I_PHY_ID;
+ hw->phy_type = e1000_phy_igp_2;
+ return E1000_SUCCESS;
}
+
+ /* ESB-2 PHY reads require e1000_phy_gg82563 to be set because of a
+ * work- around that forces PHY page 0 to be set or the reads fail.
+ * The rest of the code in this routine uses e1000_read_phy_reg to
+ * read the PHY ID. So for ESB-2 we need to have this set so our
+ * reads won't fail. If the attached PHY is not a e1000_phy_gg82563,
+ * the routines below will figure this out as well. */
+ if (hw->mac_type == e1000_80003es2lan)
+ hw->phy_type = e1000_phy_gg82563;
+
+ /* Read the PHY ID Registers to identify which PHY is onboard. */
+ ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
+ if (ret_val)
+ return ret_val;
+
hw->phy_id = (uint32_t) (phy_id_high << 16);
- udelay(2);
- if (e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
+ udelay(20);
+ ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low);
+ if (ret_val)
+ return ret_val;
+
hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+ hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
switch (hw->mac_type) {
case e1000_82543:
@@ -2564,15 +4620,38 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
break;
case e1000_82540:
case e1000_82545:
+ case e1000_82545_rev_3:
case e1000_82546:
+ case e1000_82546_rev_3:
if (hw->phy_id == M88E1011_I_PHY_ID)
match = TRUE;
break;
+ case e1000_82541:
case e1000_82541_rev_2:
+ case e1000_82547:
+ case e1000_82547_rev_2:
if(hw->phy_id == IGP01E1000_I_PHY_ID)
match = TRUE;
break;
+ case e1000_82573:
+ if (hw->phy_id == M88E1111_I_PHY_ID)
+ match = TRUE;
+ break;
+ case e1000_80003es2lan:
+ if (hw->phy_id == GG82563_E_PHY_ID)
+ match = TRUE;
+ break;
+ case e1000_ich8lan:
+ if (hw->phy_id == IGP03E1000_E_PHY_ID)
+ match = TRUE;
+ if (hw->phy_id == IFE_E_PHY_ID)
+ match = TRUE;
+ if (hw->phy_id == IFE_PLUS_E_PHY_ID)
+ match = TRUE;
+ if (hw->phy_id == IFE_C_E_PHY_ID)
+ match = TRUE;
+ break;
default:
DEBUGOUT("Invalid MAC type %d\n", hw->mac_type);
return -E1000_ERR_CONFIG;
@@ -2588,6 +4667,60 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
return -E1000_ERR_PHY;
}
+/*****************************************************************************
+ * Set media type and TBI compatibility.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * **************************************************************************/
+void
+e1000_set_media_type(struct e1000_hw *hw)
+{
+ uint32_t status;
+
+ DEBUGFUNC();
+
+ if (hw->mac_type != e1000_82543) {
+ /* tbi_compatibility is only valid on 82543 */
+ hw->tbi_compatibility_en = FALSE;
+ }
+
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82545GM_SERDES:
+ case E1000_DEV_ID_82546GB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES_DUAL:
+ case E1000_DEV_ID_82571EB_SERDES_QUAD:
+ case E1000_DEV_ID_82572EI_SERDES:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->media_type = e1000_media_type_internal_serdes;
+ break;
+ default:
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ hw->media_type = e1000_media_type_fiber;
+ break;
+ case e1000_ich8lan:
+ case e1000_82573:
+ /* The STATUS_TBIMODE bit is reserved or reused
+ * for the this device.
+ */
+ hw->media_type = e1000_media_type_copper;
+ break;
+ default:
+ status = E1000_READ_REG(hw, STATUS);
+ if (status & E1000_STATUS_TBIMODE) {
+ hw->media_type = e1000_media_type_fiber;
+ /* tbi_compatibility not valid on fiber */
+ hw->tbi_compatibility_en = FALSE;
+ } else {
+ hw->media_type = e1000_media_type_copper;
+ }
+ break;
+ }
+ }
+}
+
/**
* e1000_sw_init - Initialize general software structures (struct e1000_adapter)
*
@@ -2619,6 +4752,17 @@ e1000_sw_init(struct eth_device *nic, int cardnum)
return result;
}
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_82541:
+ case e1000_82547:
+ case e1000_82541_rev_2:
+ case e1000_82547_rev_2:
+ hw->phy_init_script = 1;
+ break;
+ }
+
/* lan a vs. lan b settings */
if (hw->mac_type == e1000_82546)
/*this also works w/ multiple 82546 cards */
@@ -2634,6 +4778,7 @@ e1000_sw_init(struct eth_device *nic, int cardnum)
hw->fc_send_xon = 1;
/* Media type - copper or fiber */
+ e1000_set_media_type(hw);
if (hw->mac_type >= e1000_82543) {
uint32_t status = E1000_READ_REG(hw, STATUS);
@@ -2649,22 +4794,13 @@ e1000_sw_init(struct eth_device *nic, int cardnum)
hw->media_type = e1000_media_type_fiber;
}
+ hw->tbi_compatibility_en = TRUE;
+ hw->wait_autoneg_complete = TRUE;
if (hw->mac_type < e1000_82543)
hw->report_tx_early = 0;
else
hw->report_tx_early = 1;
- hw->tbi_compatibility_en = TRUE;
-#if 0
- hw->wait_autoneg_complete = FALSE;
- hw->adaptive_ifs = TRUE;
-
- /* Copper options */
- if (hw->media_type == e1000_media_type_copper) {
- hw->mdix = AUTO_ALL_MODES;
- hw->disable_polarity_correction = FALSE;
- }
-#endif
return E1000_SUCCESS;
}
@@ -2693,7 +4829,8 @@ e1000_configure_tx(struct e1000_hw *hw)
{
unsigned long ptr;
unsigned long tctl;
- unsigned long tipg;
+ unsigned long tipg, tarc;
+ uint32_t ipgr1, ipgr2;
ptr = (u32) tx_pool;
if (ptr & 0xf)
@@ -2712,45 +4849,64 @@ e1000_configure_tx(struct e1000_hw *hw)
tx_tail = 0;
/* Set the default values for the Tx Inter Packet Gap timer */
+ if (hw->mac_type <= e1000_82547_rev_2 &&
+ (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes))
+ tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+ else
+ tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+
+ /* Set the default values for the Tx Inter Packet Gap timer */
switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
tipg = DEFAULT_82542_TIPG_IPGT;
- tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
- tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+ ipgr1 = DEFAULT_82542_TIPG_IPGR1;
+ ipgr2 = DEFAULT_82542_TIPG_IPGR2;
+ break;
+ case e1000_80003es2lan:
+ ipgr1 = DEFAULT_82543_TIPG_IPGR1;
+ ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2;
break;
default:
- if (hw->media_type == e1000_media_type_fiber)
- tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
- else
- tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
- tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
- tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+ ipgr1 = DEFAULT_82543_TIPG_IPGR1;
+ ipgr2 = DEFAULT_82543_TIPG_IPGR2;
+ break;
}
+ tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
+ tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
E1000_WRITE_REG(hw, TIPG, tipg);
-#if 0
- /* Set the Tx Interrupt Delay register */
- E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay);
- if (hw->mac_type >= e1000_82540)
- E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay);
-#endif
/* Program the Transmit Control Register */
tctl = E1000_READ_REG(hw, TCTL);
tctl &= ~E1000_TCTL_CT;
tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
- E1000_WRITE_REG(hw, TCTL, tctl);
+
+ if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) {
+ tarc = E1000_READ_REG(hw, TARC0);
+ /* set the speed mode bit, we'll clear it if we're not at
+ * gigabit link later */
+ /* git bit can be set to 1*/
+ } else if (hw->mac_type == e1000_80003es2lan) {
+ tarc = E1000_READ_REG(hw, TARC0);
+ tarc |= 1;
+ E1000_WRITE_REG(hw, TARC0, tarc);
+ tarc = E1000_READ_REG(hw, TARC1);
+ tarc |= 1;
+ E1000_WRITE_REG(hw, TARC1, tarc);
+ }
+
e1000_config_collision_dist(hw);
-#if 0
- /* Setup Transmit Descriptor Settings for this adapter */
- adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
+ /* Setup Transmit Descriptor Settings for eop descriptor */
+ hw->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
- if (adapter->hw.report_tx_early == 1)
- adapter->txd_cmd |= E1000_TXD_CMD_RS;
+ /* Need to set up RS bit */
+ if (hw->mac_type < e1000_82543)
+ hw->txd_cmd |= E1000_TXD_CMD_RPS;
else
- adapter->txd_cmd |= E1000_TXD_CMD_RPS;
-#endif
+ hw->txd_cmd |= E1000_TXD_CMD_RS;
+ E1000_WRITE_REG(hw, TCTL, tctl);
}
/**
@@ -2766,8 +4922,9 @@ e1000_setup_rctl(struct e1000_hw *hw)
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
- rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF; /* |
- (hw.mc_filter_type << E1000_RCTL_MO_SHIFT); */
+ rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO
+ | E1000_RCTL_RDMTS_HALF; /* |
+ (hw.mc_filter_type << E1000_RCTL_MO_SHIFT); */
if (hw->tbi_compatibility_on == 1)
rctl |= E1000_RCTL_SBP;
@@ -2775,26 +4932,8 @@ e1000_setup_rctl(struct e1000_hw *hw)
rctl &= ~E1000_RCTL_SBP;
rctl &= ~(E1000_RCTL_SZ_4096);
-#if 0
- switch (adapter->rx_buffer_len) {
- case E1000_RXBUFFER_2048:
- default:
-#endif
rctl |= E1000_RCTL_SZ_2048;
rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
-#if 0
- break;
- case E1000_RXBUFFER_4096:
- rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
- break;
- case E1000_RXBUFFER_8192:
- rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
- break;
- case E1000_RXBUFFER_16384:
- rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
- break;
- }
-#endif
E1000_WRITE_REG(hw, RCTL, rctl);
}
@@ -2808,23 +4947,12 @@ static void
e1000_configure_rx(struct e1000_hw *hw)
{
unsigned long ptr;
- unsigned long rctl;
-#if 0
- unsigned long rxcsum;
-#endif
+ unsigned long rctl, ctrl_ext;
rx_tail = 0;
/* make sure receives are disabled while setting up the descriptors */
rctl = E1000_READ_REG(hw, RCTL);
E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
-#if 0
- /* set the Receive Delay Timer Register */
-
- E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay);
-#endif
if (hw->mac_type >= e1000_82540) {
-#if 0
- E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay);
-#endif
/* Set the interrupt throttling rate. Value is calculated
* as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
#define MAX_INTS_PER_SEC 8000
@@ -2832,6 +4960,13 @@ e1000_configure_rx(struct e1000_hw *hw)
E1000_WRITE_REG(hw, ITR, DEFAULT_ITR);
}
+ if (hw->mac_type >= e1000_82571) {
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ /* Reset delay timers after every interrupt */
+ ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
/* Setup the Base and Length of the Rx Descriptor Ring */
ptr = (u32) rx_pool;
if (ptr & 0xf)
@@ -2845,14 +4980,6 @@ e1000_configure_rx(struct e1000_hw *hw)
/* Setup the HW Rx Head and Tail Descriptor Pointers */
E1000_WRITE_REG(hw, RDH, 0);
E1000_WRITE_REG(hw, RDT, 0);
-#if 0
- /* Enable 82543 Receive Checksum Offload for TCP and UDP */
- if ((adapter->hw.mac_type >= e1000_82543) && (adapter->rx_csum == TRUE)) {
- rxcsum = E1000_READ_REG(hw, RXCSUM);
- rxcsum |= E1000_RXCSUM_TUOFL;
- E1000_WRITE_REG(hw, RXCSUM, rxcsum);
- }
-#endif
/* Enable Receives */
E1000_WRITE_REG(hw, RCTL, rctl);
@@ -2891,11 +5018,11 @@ e1000_transmit(struct eth_device *nic, volatile void *packet, int length)
tx_tail = (tx_tail + 1) % 8;
txp->buffer_addr = cpu_to_le64(virt_to_bus(packet));
- txp->lower.data = cpu_to_le32(E1000_TXD_CMD_RPS | E1000_TXD_CMD_EOP |
- E1000_TXD_CMD_IFCS | length);
+ txp->lower.data = cpu_to_le32(hw->txd_cmd | length);
txp->upper.data = 0;
E1000_WRITE_REG(hw, TDT, tx_tail);
+ E1000_WRITE_FLUSH(hw);
while (!(le32_to_cpu(txp->upper.data) & E1000_TXD_STAT_DD)) {
if (i++ > TOUT_LOOP) {
DEBUGOUT("e1000: tx timeout\n");
@@ -2972,6 +5099,37 @@ e1000_init(struct eth_device *nic, bd_t * bis)
return 1;
}
+/******************************************************************************
+ * Gets the current PCI bus type of hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void e1000_get_bus_type(struct e1000_hw *hw)
+{
+ uint32_t status;
+
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ hw->bus_type = e1000_bus_type_pci;
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_82573:
+ case e1000_80003es2lan:
+ hw->bus_type = e1000_bus_type_pci_express;
+ break;
+ case e1000_ich8lan:
+ hw->bus_type = e1000_bus_type_pci_express;
+ break;
+ default:
+ status = E1000_READ_REG(hw, STATUS);
+ hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+ e1000_bus_type_pcix : e1000_bus_type_pci;
+ break;
+ }
+}
+
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
You should omit the last argument struct pci_device * for a non-PCI NIC
@@ -3017,14 +5175,10 @@ e1000_initialize(bd_t * bis)
sprintf(nic->name, "e1000#%d", card_number);
/* Are these variables needed? */
-#if 0
- hw->fc = e1000_fc_none;
- hw->original_fc = e1000_fc_none;
-#else
hw->fc = e1000_fc_default;
hw->original_fc = e1000_fc_default;
-#endif
hw->autoneg_failed = 0;
+ hw->autoneg = 1;
hw->get_link_status = TRUE;
hw->hw_addr = (typeof(hw->hw_addr)) iobase;
hw->mac_type = e1000_undefined;
@@ -3035,7 +5189,16 @@ e1000_initialize(bd_t * bis)
free(nic);
return 0;
}
+ if (e1000_check_phy_reset_block(hw))
+ printf("phy reset block error \n");
+ e1000_reset_hw(hw);
#if !(defined(CONFIG_AP1000) || defined(CONFIG_MVBC_1G))
+ if (e1000_init_eeprom_params(hw)) {
+ printf("The EEPROM Checksum Is Not Valid\n");
+ free(hw);
+ free(nic);
+ return 0;
+ }
if (e1000_validate_eeprom_checksum(nic) < 0) {
printf("The EEPROM Checksum Is Not Valid\n");
free(hw);
@@ -3045,7 +5208,8 @@ e1000_initialize(bd_t * bis)
#endif
e1000_read_mac_addr(nic);
- E1000_WRITE_REG(hw, PBA, E1000_DEFAULT_PBA);
+ /* get the bus type information */
+ e1000_get_bus_type(hw);
printf("e1000: %02x:%02x:%02x:%02x:%02x:%02x\n",
nic->enetaddr[0], nic->enetaddr[1], nic->enetaddr[2],
diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h
index 08042a8cc3c..eb0804b412b 100644
--- a/drivers/net/e1000.h
+++ b/drivers/net/e1000.h
@@ -71,9 +71,18 @@ typedef enum {
e1000_82544,
e1000_82540,
e1000_82545,
+ e1000_82545_rev_3,
e1000_82546,
+ e1000_82546_rev_3,
e1000_82541,
e1000_82541_rev_2,
+ e1000_82547,
+ e1000_82547_rev_2,
+ e1000_82571,
+ e1000_82572,
+ e1000_82573,
+ e1000_80003es2lan,
+ e1000_ich8lan,
e1000_num_macs
} e1000_mac_type;
@@ -81,10 +90,21 @@ typedef enum {
typedef enum {
e1000_media_type_copper = 0,
e1000_media_type_fiber = 1,
+ e1000_media_type_internal_serdes = 2,
e1000_num_media_types
} e1000_media_type;
typedef enum {
+ e1000_eeprom_uninitialized = 0,
+ e1000_eeprom_spi,
+ e1000_eeprom_microwire,
+ e1000_eeprom_flash,
+ e1000_eeprom_ich8,
+ e1000_eeprom_none, /* No NVM support */
+ e1000_num_eeprom_types
+} e1000_eeprom_type;
+
+typedef enum {
e1000_10_half = 0,
e1000_10_full = 1,
e1000_100_half = 2,
@@ -109,7 +129,9 @@ typedef enum {
typedef enum {
e1000_bus_type_unknown = 0,
e1000_bus_type_pci,
- e1000_bus_type_pcix
+ e1000_bus_type_pcix,
+ e1000_bus_type_pci_express,
+ e1000_bus_type_reserved
} e1000_bus_type;
/* PCI bus speeds */
@@ -172,10 +194,13 @@ typedef enum {
} e1000_1000t_rx_status;
typedef enum {
- e1000_phy_m88 = 0,
- e1000_phy_igp,
- e1000_phy_igp_2,
- e1000_phy_undefined = 0xFF
+ e1000_phy_m88 = 0,
+ e1000_phy_igp,
+ e1000_phy_igp_2,
+ e1000_phy_gg82563,
+ e1000_phy_igp_3,
+ e1000_phy_ife,
+ e1000_phy_undefined = 0xFF
} e1000_phy_type;
struct e1000_phy_info {
@@ -207,6 +232,7 @@ struct e1000_phy_stats {
#define E1000_ERR_MASTER_REQUESTS_PENDING 10
#define E1000_ERR_HOST_INTERFACE_COMMAND 11
#define E1000_BLK_PHY_RESET 12
+#define E1000_ERR_SWFW_SYNC 13
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
@@ -217,14 +243,151 @@ struct e1000_phy_stats {
#define E1000_DEV_ID_82544GC_COPPER 0x100C
#define E1000_DEV_ID_82544GC_LOM 0x100D
#define E1000_DEV_ID_82540EM 0x100E
-#define E1000_DEV_ID_82540EM_LOM 0x1015
-#define E1000_DEV_ID_82545GM_COPPER 0x1026
-#define E1000_DEV_ID_82545EM_COPPER 0x100F
-#define E1000_DEV_ID_82545EM_FIBER 0x1011
-#define E1000_DEV_ID_82546EB_COPPER 0x1010
-#define E1000_DEV_ID_82546EB_FIBER 0x1012
-#define E1000_DEV_ID_82541ER 0x1078
-#define E1000_DEV_ID_82541GI_LF 0x107C
+#define E1000_DEV_ID_82540EM_LOM 0x1015
+#define E1000_DEV_ID_82540EP_LOM 0x1016
+#define E1000_DEV_ID_82540EP 0x1017
+#define E1000_DEV_ID_82540EP_LP 0x101E
+#define E1000_DEV_ID_82545EM_COPPER 0x100F
+#define E1000_DEV_ID_82545EM_FIBER 0x1011
+#define E1000_DEV_ID_82545GM_COPPER 0x1026
+#define E1000_DEV_ID_82545GM_FIBER 0x1027
+#define E1000_DEV_ID_82545GM_SERDES 0x1028
+#define E1000_DEV_ID_82546EB_COPPER 0x1010
+#define E1000_DEV_ID_82546EB_FIBER 0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI 0x1013
+#define E1000_DEV_ID_82541EI_MOBILE 0x1018
+#define E1000_DEV_ID_82541ER_LOM 0x1014
+#define E1000_DEV_ID_82541ER 0x1078
+#define E1000_DEV_ID_82547GI 0x1075
+#define E1000_DEV_ID_82541GI 0x1076
+#define E1000_DEV_ID_82541GI_MOBILE 0x1077
+#define E1000_DEV_ID_82541GI_LF 0x107C
+#define E1000_DEV_ID_82546GB_COPPER 0x1079
+#define E1000_DEV_ID_82546GB_FIBER 0x107A
+#define E1000_DEV_ID_82546GB_SERDES 0x107B
+#define E1000_DEV_ID_82546GB_PCIE 0x108A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+#define E1000_DEV_ID_82547EI 0x1019
+#define E1000_DEV_ID_82547EI_MOBILE 0x101A
+#define E1000_DEV_ID_82571EB_COPPER 0x105E
+#define E1000_DEV_ID_82571EB_FIBER 0x105F
+#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC
+#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
+#define E1000_DEV_ID_82572EI_COPPER 0x107D
+#define E1000_DEV_ID_82572EI_FIBER 0x107E
+#define E1000_DEV_ID_82572EI_SERDES 0x107F
+#define E1000_DEV_ID_82572EI 0x10B9
+#define E1000_DEV_ID_82573E 0x108B
+#define E1000_DEV_ID_82573E_IAMT 0x108C
+#define E1000_DEV_ID_82573L 0x109A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
+#define E1000_DEV_ID_ICH8_IGP_C 0x104B
+#define E1000_DEV_ID_ICH8_IFE 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M 0x104D
+
+#define IGP03E1000_E_PHY_ID 0x02A80390
+#define IFE_E_PHY_ID 0x02A80330 /* 10/100 PHY */
+#define IFE_PLUS_E_PHY_ID 0x02A80320
+#define IFE_C_E_PHY_ID 0x02A80310
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 /* 100BaseTx Extended Status,
+ Control and Address */
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY special
+ control register */
+#define IFE_PHY_RCV_FALSE_CARRIER 0x13 /* 100BaseTx Receive False
+ Carrier Counter */
+#define IFE_PHY_RCV_DISCONNECT 0x14 /* 100BaseTx Receive Disconnet
+ Counter */
+#define IFE_PHY_RCV_ERROT_FRAME 0x15 /* 100BaseTx Receive Error
+ Frame Counter */
+#define IFE_PHY_RCV_SYMBOL_ERR 0x16 /* Receive Symbol Error
+ Counter */
+#define IFE_PHY_PREM_EOF_ERR 0x17 /* 100BaseTx Receive
+ Premature End Of Frame
+ Error Counter */
+#define IFE_PHY_RCV_EOF_ERR 0x18 /* 10BaseT Receive End Of
+ Frame Error Counter */
+#define IFE_PHY_TX_JABBER_DETECT 0x19 /* 10BaseT Transmit Jabber
+ Detect Counter */
+#define IFE_PHY_EQUALIZER 0x1A /* PHY Equalizer Control and
+ Status */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY special control and
+ LED configuration */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control register */
+#define IFE_PHY_HWI_CONTROL 0x1D /* Hardware Integrity Control
+ (HWI) */
+
+#define IFE_PESC_REDUCED_POWER_DOWN_DISABLE 0x2000 /* Defaut 1 = Disable auto
+ reduced power down */
+#define IFE_PESC_100BTX_POWER_DOWN 0x0400 /* Indicates the power
+ state of 100BASE-TX */
+#define IFE_PESC_10BTX_POWER_DOWN 0x0200 /* Indicates the power
+ state of 10BASE-T */
+#define IFE_PESC_POLARITY_REVERSED 0x0100 /* Indicates 10BASE-T
+ polarity */
+#define IFE_PESC_PHY_ADDR_MASK 0x007C /* Bit 6:2 for sampled PHY
+ address */
+#define IFE_PESC_SPEED 0x0002 /* Auto-negotiation speed
+ result 1=100Mbs, 0=10Mbs */
+#define IFE_PESC_DUPLEX 0x0001 /* Auto-negotiation
+ duplex result 1=Full, 0=Half */
+#define IFE_PESC_POLARITY_REVERSED_SHIFT 8
+
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 /* 1 = Dyanmic Power Down
+ disabled */
+#define IFE_PSC_FORCE_POLARITY 0x0020 /* 1=Reversed Polarity,
+ 0=Normal */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 /* 1=Auto Polarity
+ Disabled, 0=Enabled */
+#define IFE_PSC_JABBER_FUNC_DISABLE 0x0001 /* 1=Jabber Disabled,
+ 0=Normal Jabber Operation */
+#define IFE_PSC_FORCE_POLARITY_SHIFT 5
+#define IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT 4
+
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable MDI/MDI-X
+ feature, default 0=disabled */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDIX-X,
+ 0=force MDI */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorithm
+ is completed */
+#define IFE_PMC_MDIX_MODE_SHIFT 6
+#define IFE_PHC_MDIX_RESET_ALL_MASK 0x0000 /* Disable auto MDI-X */
+
+#define IFE_PHC_HWI_ENABLE 0x8000 /* Enable the HWI
+ feature */
+#define IFE_PHC_ABILITY_CHECK 0x4000 /* 1= Test Passed,
+ 0=failed */
+#define IFE_PHC_TEST_EXEC 0x2000 /* PHY launch test pulses
+ on the wire */
+#define IFE_PHC_HIGHZ 0x0200 /* 1 = Open Circuit */
+#define IFE_PHC_LOWZ 0x0400 /* 1 = Short Circuit */
+#define IFE_PHC_LOW_HIGH_Z_MASK 0x0600 /* Mask for indication
+ type of problem on the line */
+#define IFE_PHC_DISTANCE_MASK 0x01FF /* Mask for distance to
+ the cable problem, in 80cm granularity */
+#define IFE_PHC_RESET_ALL_MASK 0x0000 /* Disable HWI */
+#define IFE_PSCL_PROBE_MODE 0x0020 /* LED Probe mode */
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2
+ off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+
#define NUM_DEV_IDS 16
#define NODE_ADDRESS_SIZE 6
@@ -235,6 +398,10 @@ struct e1000_phy_stats {
#define E1000_82542_2_0_REV_ID 2
#define E1000_82542_2_1_REV_ID 3
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
#define SPEED_10 10
#define SPEED_100 100
@@ -522,11 +689,27 @@ struct e1000_ffvt_entry {
#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */
#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */
#define E1000_TCTL 0x00400 /* TX Control - RW */
+#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_TBT 0x00448 /* TX Burst Timer - RW */
#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
+#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
+#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
+#define FEXTNVM_SW_CONFIG 0x0001
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
+#define E1000_PBS 0x01008 /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
+#define E1000_FLASH_UPDATES 1000
+#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT 0x01028 /* FLASH Timer Register */
+#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL 0x01030 /* FLASH control register */
+#define E1000_FLSWDATA 0x01034 /* FLASH data register */
+#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */
+#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
+#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */
@@ -539,6 +722,11 @@ struct e1000_ffvt_entry {
#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */
+#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */
#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */
#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
@@ -548,6 +736,14 @@ struct e1000_ffvt_entry {
#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */
#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */
#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */
+#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */
+#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */
+#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */
+#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */
+#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */
+#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */
+#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */
#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
@@ -812,6 +1008,44 @@ struct e1000_hw_stats {
uint64_t tsctfc;
};
+struct e1000_eeprom_info {
+ e1000_eeprom_type type;
+ uint16_t word_size;
+ uint16_t opcode_bits;
+ uint16_t address_bits;
+ uint16_t delay_usec;
+ uint16_t page_size;
+ boolean_t use_eerd;
+ boolean_t use_eewr;
+};
+
+typedef enum {
+ e1000_smart_speed_default = 0,
+ e1000_smart_speed_on,
+ e1000_smart_speed_off
+} e1000_smart_speed;
+
+typedef enum {
+ e1000_dsp_config_disabled = 0,
+ e1000_dsp_config_enabled,
+ e1000_dsp_config_activated,
+ e1000_dsp_config_undefined = 0xFF
+} e1000_dsp_config;
+
+typedef enum {
+ e1000_ms_hw_default = 0,
+ e1000_ms_force_master,
+ e1000_ms_force_slave,
+ e1000_ms_auto
+} e1000_ms_type;
+
+typedef enum {
+ e1000_ffe_config_enabled = 0,
+ e1000_ffe_config_active,
+ e1000_ffe_config_blocked
+} e1000_ffe_config;
+
+
/* Structure containing variables used by the shared code (e1000_hw.c) */
struct e1000_hw {
pci_dev_t pdev;
@@ -819,16 +1053,26 @@ struct e1000_hw {
e1000_mac_type mac_type;
e1000_phy_type phy_type;
uint32_t phy_init_script;
+ uint32_t txd_cmd;
e1000_media_type media_type;
e1000_lan_loc lan_loc;
e1000_fc_type fc;
+ e1000_bus_type bus_type;
#if 0
e1000_bus_speed bus_speed;
e1000_bus_width bus_width;
- e1000_bus_type bus_type;
uint32_t io_base;
#endif
+ uint32_t asf_firmware_present;
+ uint32_t eeprom_semaphore_present;
+ uint32_t swfw_sync_present;
+ uint32_t swfwhw_semaphore_present;
+ struct e1000_eeprom_info eeprom;
+ e1000_ms_type master_slave;
+ e1000_ms_type original_master_slave;
+ e1000_ffe_config ffe_config_state;
uint32_t phy_id;
+ uint32_t phy_revision;
uint32_t phy_addr;
uint32_t original_fc;
uint32_t txcw;
@@ -861,31 +1105,45 @@ struct e1000_hw {
uint16_t subsystem_id;
uint16_t subsystem_vendor_id;
uint8_t revision_id;
-#if 0
uint8_t autoneg;
uint8_t mdix;
uint8_t forced_speed_duplex;
uint8_t wait_autoneg_complete;
uint8_t dma_fairness;
-#endif
#if 0
uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
- boolean_t disable_polarity_correction;
#endif
+ boolean_t disable_polarity_correction;
+ boolean_t speed_downgraded;
boolean_t get_link_status;
boolean_t tbi_compatibility_en;
boolean_t tbi_compatibility_on;
+ boolean_t fc_strict_ieee;
boolean_t fc_send_xon;
boolean_t report_tx_early;
+ boolean_t phy_reset_disable;
+ boolean_t initialize_hw_bits_disable;
#if 0
boolean_t adaptive_ifs;
boolean_t ifs_params_forced;
boolean_t in_ifs_mode;
#endif
+ e1000_smart_speed smart_speed;
+ e1000_dsp_config dsp_config_state;
};
#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */
+#define E1000_EEPROM_RW_REG_DATA 16 /* Offset to data in EEPROM
+ read/write registers */
+#define E1000_EEPROM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START 1 /* First bit for telling part to start
+ operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write
+ complete */
+#define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */
+#define EEPROM_RESERVED_WORD 0xFFFF
/* Register Bit Masks */
/* Device Control */
@@ -957,6 +1215,30 @@ struct e1000_hw {
#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */
#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */
#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+ * (0-small, 1-large) */
+
+#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD 0x00000200 /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT 11
+#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT 22
+#define E1000_STM_OPCODE 0xDB00
+#define E1000_HICR_FW_RESET 0xC0
+
+#define E1000_SHADOW_RAM_WORDS 2048
+#define E1000_ICH_NVM_SIG_WORD 0x13
+#define E1000_ICH_NVM_SIG_MASK 0xC0
/* EEPROM Read */
#define E1000_EERD_START 0x00000001 /* Start Read */
@@ -966,14 +1248,62 @@ struct e1000_hw {
#define E1000_EERD_DATA_SHIFT 16
#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Commands - SPI */
+#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI 0x04 /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status register */
+#define EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */
+#define EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */
+#define EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */
+
+/* EEPROM Size definitions */
+#define EEPROM_WORD_SIZE_SHIFT 6
+#define EEPROM_SIZE_SHIFT 10
+#define EEPROM_SIZE_MASK 0x1C00
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT 0x0003
+#define EEPROM_ID_LED_SETTINGS 0x0004
+#define EEPROM_VERSION 0x0005
+#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude
+ adjustment. */
+#define EEPROM_PHY_CLASS_WORD 0x0007
+#define EEPROM_INIT_CONTROL1_REG 0x000A
+#define EEPROM_INIT_CONTROL2_REG 0x000F
+#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define EEPROM_INIT_CONTROL3_PORT_B 0x0014
+#define EEPROM_INIT_3GIO_3 0x001A
+#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define EEPROM_INIT_CONTROL3_PORT_A 0x0024
+#define EEPROM_CFG 0x0012
+#define EEPROM_FLASH_VERSION 0x0032
+#define EEPROM_CHECKSUM_REG 0x003F
+
+#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
+#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */
+
/* Extended Device Control */
#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */
#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */
#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */
#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */
-#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
-#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable
+ Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable
+ Pin 5 */
#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA
#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
#define E1000_CTRL_EXT_SWDPIN6 0x00000040 /* SWDPIN 6 value */
@@ -989,6 +1319,7 @@ struct e1000_hw {
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */
#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000
@@ -1010,6 +1341,12 @@ struct e1000_hw {
#define E1000_MDIC_INT_EN 0x20000000
#define E1000_MDIC_ERROR 0x40000000
+#define E1000_PHY_CTRL_SPD_EN 0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU 0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
+#define E1000_PHY_CTRL_B2B_EN 0x00000080
/* LED Control */
#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
#define E1000_LEDCTL_LED0_MODE_SHIFT 0
@@ -1153,6 +1490,12 @@ struct e1000_hw {
#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
+/* SW_W_SYNC definitions */
+#define E1000_SWFW_EEP_SM 0x0001
+#define E1000_SWFW_PHY0_SM 0x0002
+#define E1000_SWFW_PHY1_SM 0x0004
+#define E1000_SWFW_MAC_CSR_SM 0x0008
+
/* Receive Descriptor */
#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */
#define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */
@@ -1173,12 +1516,14 @@ struct e1000_hw {
#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */
/* Transmit Descriptor Control */
-#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
-#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */
-#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */
#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+ still to be processed. */
/* Transmit Configuration Word */
#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */
@@ -1212,6 +1557,7 @@ struct e1000_hw {
#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */
#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
/* Receive Checksum Control */
#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */
@@ -1349,9 +1695,10 @@ struct e1000_hw {
#define PBA_SIZE 4
/* Collision related configuration parameters */
-#define E1000_COLLISION_THRESHOLD 16
+#define E1000_COLLISION_THRESHOLD 0xF
#define E1000_CT_SHIFT 4
-#define E1000_COLLISION_DISTANCE 64
+#define E1000_COLLISION_DISTANCE 63
+#define E1000_COLLISION_DISTANCE_82542 64
#define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
#define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
#define E1000_GB_HDX_COLLISION_DISTANCE 512
@@ -1376,6 +1723,7 @@ struct e1000_hw {
#define DEFAULT_82542_TIPG_IPGR2 10
#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
#define E1000_TIPG_IPGR2_SHIFT 20
#define E1000_TXDMAC_DPP 0x00000001
@@ -1396,6 +1744,7 @@ struct e1000_hw {
/* PBA constants */
#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
#define E1000_PBA_24K 0x0018
+#define E1000_PBA_38K 0x0026
#define E1000_PBA_40K 0x0028
#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */
@@ -1537,8 +1886,22 @@ struct e1000_hw {
#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
+
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00
+
/* IGP01E1000 specifics */
#define IGP01E1000_IEEE_REGS_PAGE 0x0000
#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300
@@ -1554,6 +1917,290 @@ struct e1000_hw {
#define IGP02E1000_PHY_POWER_MGMT 0x19
#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */
+/* IGP01E1000 AGC Registers - stores the cable length values*/
+#define IGP01E1000_PHY_AGC_A 0x1172
+#define IGP01E1000_PHY_AGC_B 0x1272
+#define IGP01E1000_PHY_AGC_C 0x1472
+#define IGP01E1000_PHY_AGC_D 0x1872
+
+/* IGP01E1000 Specific Port Config Register - R/W */
+#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010
+#define IGP01E1000_PSCFR_PRE_EN 0x0020
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK 0x0100
+#define IGP01E1000_PSCFR_DISABLE_JABBER 0x0400
+#define IGP01E1000_PSCFR_DISABLE_TRANSMIT 0x2000
+/* IGP02E1000 AGC Registers for cable length values */
+#define IGP02E1000_PHY_AGC_A 0x11B1
+#define IGP02E1000_PHY_AGC_B 0x12B1
+#define IGP02E1000_PHY_AGC_C 0x14B1
+#define IGP02E1000_PHY_AGC_D 0x18B1
+
+#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D3_LPLU 0x0004 /* Enable LPLU in
+ non-D0a modes */
+#define IGP02E1000_PM_D0_LPLU 0x0002 /* Enable LPLU in
+ D0a mode */
+
+/* IGP01E1000 DSP Reset Register */
+#define IGP01E1000_PHY_DSP_RESET 0x1F33
+#define IGP01E1000_PHY_DSP_SET 0x1F71
+#define IGP01E1000_PHY_DSP_FFE 0x1F35
+
+#define IGP01E1000_PHY_CHANNEL_NUM 4
+#define IGP02E1000_PHY_CHANNEL_NUM 4
+
+#define IGP01E1000_PHY_AGC_PARAM_A 0x1171
+#define IGP01E1000_PHY_AGC_PARAM_B 0x1271
+#define IGP01E1000_PHY_AGC_PARAM_C 0x1471
+#define IGP01E1000_PHY_AGC_PARAM_D 0x1871
+
+#define IGP01E1000_PHY_EDAC_MU_INDEX 0xC000
+#define IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS 0x8000
+
+#define IGP01E1000_PHY_ANALOG_TX_STATE 0x2890
+#define IGP01E1000_PHY_ANALOG_CLASS_A 0x2000
+#define IGP01E1000_PHY_FORCE_ANALOG_ENABLE 0x0004
+#define IGP01E1000_PHY_DSP_FFE_CM_CP 0x0069
+
+#define IGP01E1000_PHY_DSP_FFE_DEFAULT 0x002A
+/* IGP01E1000 PCS Initialization register - stores the polarity status when
+ * speed = 1000 Mbps. */
+#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+#define IGP01E1000_PHY_PCS_CTRL_REG 0x00B5
+
+#define IGP01E1000_ANALOG_REGS_PAGE 0x20C0
+
+/* IGP01E1000 GMII FIFO Register */
+#define IGP01E1000_GMII_FLEX_SPD 0x10 /* Enable flexible speed
+ * on Link-Up */
+#define IGP01E1000_GMII_SPD 0x20 /* Enable SPD */
+
+/* IGP01E1000 Analog Register */
+#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS 0x20D1
+#define IGP01E1000_ANALOG_FUSE_STATUS 0x20D0
+#define IGP01E1000_ANALOG_FUSE_CONTROL 0x20DC
+#define IGP01E1000_ANALOG_FUSE_BYPASS 0x20DE
+
+#define IGP01E1000_ANALOG_FUSE_POLY_MASK 0xF000
+#define IGP01E1000_ANALOG_FUSE_FINE_MASK 0x0F80
+#define IGP01E1000_ANALOG_FUSE_COARSE_MASK 0x0070
+#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED 0x0100
+#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL 0x0002
+
+#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH 0x0040
+#define IGP01E1000_ANALOG_FUSE_COARSE_10 0x0010
+#define IGP01E1000_ANALOG_FUSE_FINE_1 0x0080
+#define IGP01E1000_ANALOG_FUSE_FINE_10 0x0500
+
+/* IGP01E1000 Specific Port Control Register - R/W */
+#define IGP01E1000_PSCR_TP_LOOPBACK 0x0010
+#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR 0x0200
+#define IGP01E1000_PSCR_TEN_CRS_SELECT 0x0400
+#define IGP01E1000_PSCR_FLIP_CHIP 0x0800
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0-MDI, 1-MDIX */
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_DISABLE_JABBER 0x0001 /* 1=Disable Jabber */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Polarity Reversal
+ Disabled */
+#define GG82563_PSCR_POWER_DOWN 0x0004 /* 1=Power Down */
+#define GG82563_PSCR_COPPER_TRANSMITER_DISABLE 0x0008 /* 1=Transmitter
+ Disabled */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI
+ configuration */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX
+ configuration */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Automatic
+ crossover */
+#define GG82563_PSCR_ENALBE_EXTENDED_DISTANCE 0x0080 /* 1=Enable Extended
+ Distance */
+#define GG82563_PSCR_ENERGY_DETECT_MASK 0x0300
+#define GG82563_PSCR_ENERGY_DETECT_OFF 0x0000 /* 00,01=Off */
+#define GG82563_PSCR_ENERGY_DETECT_RX 0x0200 /* 10=Sense on Rx only
+ (Energy Detect) */
+#define GG82563_PSCR_ENERGY_DETECT_RX_TM 0x0300 /* 11=Sense and Tx NLP */
+#define GG82563_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force Link Good */
+#define GG82563_PSCR_DOWNSHIFT_ENABLE 0x0800 /* 1=Enable Downshift */
+#define GG82563_PSCR_DOWNSHIFT_COUNTER_MASK 0x7000
+#define GG82563_PSCR_DOWNSHIFT_COUNTER_SHIFT 12
+
+/* PHY Specific Status Register (Page 0, Register 17) */
+#define GG82563_PSSR_JABBER 0x0001 /* 1=Jabber */
+#define GG82563_PSSR_POLARITY 0x0002 /* 1=Polarity Reversed */
+#define GG82563_PSSR_LINK 0x0008 /* 1=Link is Up */
+#define GG82563_PSSR_ENERGY_DETECT 0x0010 /* 1=Sleep, 0=Active */
+#define GG82563_PSSR_DOWNSHIFT 0x0020 /* 1=Downshift */
+#define GG82563_PSSR_CROSSOVER_STATUS 0x0040 /* 1=MDIX, 0=MDI */
+#define GG82563_PSSR_RX_PAUSE_ENABLED 0x0100 /* 1=Receive Pause Enabled */
+#define GG82563_PSSR_TX_PAUSE_ENABLED 0x0200 /* 1=Transmit Pause Enabled */
+#define GG82563_PSSR_LINK_UP 0x0400 /* 1=Link Up */
+#define GG82563_PSSR_SPEED_DUPLEX_RESOLVED 0x0800 /* 1=Resolved */
+#define GG82563_PSSR_PAGE_RECEIVED 0x1000 /* 1=Page Received */
+#define GG82563_PSSR_DUPLEX 0x2000 /* 1-Full-Duplex */
+#define GG82563_PSSR_SPEED_MASK 0xC000
+#define GG82563_PSSR_SPEED_10MBPS 0x0000 /* 00=10Mbps */
+#define GG82563_PSSR_SPEED_100MBPS 0x4000 /* 01=100Mbps */
+#define GG82563_PSSR_SPEED_1000MBPS 0x8000 /* 10=1000Mbps */
+
+/* PHY Specific Status Register 2 (Page 0, Register 19) */
+#define GG82563_PSSR2_JABBER 0x0001 /* 1=Jabber */
+#define GG82563_PSSR2_POLARITY_CHANGED 0x0002 /* 1=Polarity Changed */
+#define GG82563_PSSR2_ENERGY_DETECT_CHANGED 0x0010 /* 1=Energy Detect Changed */
+#define GG82563_PSSR2_DOWNSHIFT_INTERRUPT 0x0020 /* 1=Downshift Detected */
+#define GG82563_PSSR2_MDI_CROSSOVER_CHANGE 0x0040 /* 1=Crossover Changed */
+#define GG82563_PSSR2_FALSE_CARRIER 0x0100 /* 1=False Carrier */
+#define GG82563_PSSR2_SYMBOL_ERROR 0x0200 /* 1=Symbol Error */
+#define GG82563_PSSR2_LINK_STATUS_CHANGED 0x0400 /* 1=Link Status Changed */
+#define GG82563_PSSR2_AUTO_NEG_COMPLETED 0x0800 /* 1=Auto-Neg Completed */
+#define GG82563_PSSR2_PAGE_RECEIVED 0x1000 /* 1=Page Received */
+#define GG82563_PSSR2_DUPLEX_CHANGED 0x2000 /* 1=Duplex Changed */
+#define GG82563_PSSR2_SPEED_CHANGED 0x4000 /* 1=Speed Changed */
+#define GG82563_PSSR2_AUTO_NEG_ERROR 0x8000 /* 1=Auto-Neg Error */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_10BT_POLARITY_FORCE 0x0002 /* 1=Force Negative
+ Polarity */
+#define GG82563_PSCR2_1000MB_TEST_SELECT_MASK 0x000C
+#define GG82563_PSCR2_1000MB_TEST_SELECT_NORMAL 0x0000 /* 00,01=Normal
+ Operation */
+#define GG82563_PSCR2_1000MB_TEST_SELECT_112NS 0x0008 /* 10=Select 112ns
+ Sequence */
+#define GG82563_PSCR2_1000MB_TEST_SELECT_16NS 0x000C /* 11=Select 16ns
+ Sequence */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 /* 1=Reverse
+ Auto-Negotiation */
+#define GG82563_PSCR2_1000BT_DISABLE 0x4000 /* 1=Disable
+ 1000BASE-T */
+#define GG82563_PSCR2_TRANSMITER_TYPE_MASK 0x8000
+#define GG82563_PSCR2_TRANSMITTER_TYPE_CLASS_B 0x0000 /* 0=Class B */
+#define GG82563_PSCR2_TRANSMITTER_TYPE_CLASS_A 0x8000 /* 1=Class A */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK 0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ 0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25MHZ 0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_2_5MHZ 0x0006
+#define GG82563_MSCR_TX_CLK_1000MBPS_25MHZ 0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M;
+ 1 = 50-80M;
+ 2 = 80-110M;
+ 3 = 110-140M;
+ 4 = >140M */
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PHY_LEDS_EN 0x0020 /* 1=PHY LEDs,
+ 0=Kumeran Inband LEDs */
+#define GG82563_KMCR_FORCE_LINK_UP 0x0040 /* 1=Force Link Up */
+#define GG82563_KMCR_SUPPRESS_SGMII_EPD_EXT 0x0080
+#define GG82563_KMCR_MDIO_BUS_SPEED_SELECT_MASK 0x0400
+#define GG82563_KMCR_MDIO_BUS_SPEED_SELECT 0x0400 /* 1=6.25MHz,
+ 0=0.8MHz */
+#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 /* 1=Enalbe SERDES
+ Electrical Idle */
+#define GG82563_PMCR_DISABLE_PORT 0x0002 /* 1=Disable Port */
+#define GG82563_PMCR_DISABLE_SERDES 0x0004 /* 1=Disable SERDES */
+#define GG82563_PMCR_REVERSE_AUTO_NEG 0x0008 /* 1=Enable Reverse
+ Auto-Negotiation */
+#define GG82563_PMCR_DISABLE_1000_NON_D0 0x0010 /* 1=Disable 1000Mbps
+ Auto-Neg in non D0 */
+#define GG82563_PMCR_DISABLE_1000 0x0020 /* 1=Disable 1000Mbps
+ Auto-Neg Always */
+#define GG82563_PMCR_REVERSE_AUTO_NEG_D0A 0x0040 /* 1=Enable D0a
+ Reverse Auto-Negotiation */
+#define GG82563_PMCR_FORCE_POWER_STATE 0x0080 /* 1=Force Power State */
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_MASK 0x0300
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_DR 0x0000 /* 00=Dr */
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D0U 0x0100 /* 01=D0u */
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D0A 0x0200 /* 10=D0a */
+#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D3 0x0300 /* 11=D3 */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding Use */
+
+
+/* Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT 5
+#define GG82563_REG(page, reg) \
+ (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG 30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL \
+ GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS \
+ GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE \
+ GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2 \
+ GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR \
+ GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT \
+ GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2 \
+ GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT \
+ GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL \
+ GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL \
+ GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2 \
+ GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE \
+ GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL \
+ GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET \
+ GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID \
+ GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID \
+ GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL \
+ GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL \
+ GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+ GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL \
+ GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL \
+ GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC \
+ GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS \
+ GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY \
+ GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+ GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE \
+ GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+ GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC \
+ GG82563_REG(194, 26) /* Misc. */
+
/* PHY Control Register */
#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
@@ -1765,6 +2412,10 @@ struct e1000_hw {
#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
#define IGP01E1000_I_PHY_ID 0x02A80380
+#define M88E1011_I_REV_4 0x04
+#define M88E1111_I_PHY_ID 0x01410CC0
+#define L1LXT971A_PHY_ID 0x001378E0
+#define GG82563_E_PHY_ID 0x01410CA0
/* Miscellaneous PHY bit definitions. */
#define PHY_PREAMBLE 0xFFFFFFFF
@@ -1791,4 +2442,142 @@ struct e1000_hw {
#define ADVERTISE_1000_FULL 0x0020
#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+#define ICH_FLASH_GFPREG 0x0000
+#define ICH_FLASH_HSFSTS 0x0004
+#define ICH_FLASH_HSFCTL 0x0006
+#define ICH_FLASH_FADDR 0x0008
+#define ICH_FLASH_FDATA0 0x0010
+#define ICH_FLASH_FRACC 0x0050
+#define ICH_FLASH_FREG0 0x0054
+#define ICH_FLASH_FREG1 0x0058
+#define ICH_FLASH_FREG2 0x005C
+#define ICH_FLASH_FREG3 0x0060
+#define ICH_FLASH_FPR0 0x0074
+#define ICH_FLASH_FPR1 0x0078
+#define ICH_FLASH_SSFSTS 0x0090
+#define ICH_FLASH_SSFCTL 0x0092
+#define ICH_FLASH_PREOP 0x0094
+#define ICH_FLASH_OPTYPE 0x0096
+#define ICH_FLASH_OPMENU 0x0098
+
+#define ICH_FLASH_REG_MAPSIZE 0x00A0
+#define ICH_FLASH_SECTOR_SIZE 4096
+#define ICH_GFPREG_BASE_MASK 0x1FFF
+#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+
+#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
+#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+
+/* SPI EEPROM Status Register */
+#define EEPROM_STATUS_RDY_SPI 0x01
+#define EEPROM_STATUS_WEN_SPI 0x02
+#define EEPROM_STATUS_BP0_SPI 0x04
+#define EEPROM_STATUS_BP1_SPI 0x08
+#define EEPROM_STATUS_WPEN_SPI 0x80
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */
+
+/* FW Semaphore Register */
+#define E1000_FWSM_MODE_MASK 0x0000000E /* FW mode */
+#define E1000_FWSM_MODE_SHIFT 1
+#define E1000_FWSM_FW_VALID 0x00008000 /* FW established a valid mode */
+
+#define E1000_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI reset */
+#define E1000_FWSM_DISSW 0x10000000 /* FW disable SW Write Access */
+#define E1000_FWSM_SKUSEL_MASK 0x60000000 /* LAN SKU select */
+#define E1000_FWSM_SKUEL_SHIFT 29
+#define E1000_FWSM_SKUSEL_EMB 0x0 /* Embedded SKU */
+#define E1000_FWSM_SKUSEL_CONS 0x1 /* Consumer SKU */
+#define E1000_FWSM_SKUSEL_PERF_100 0x2 /* Perf & Corp 10/100 SKU */
+#define E1000_FWSM_SKUSEL_PERF_GBE 0x3 /* Perf & Copr GbE SKU */
+
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM 0x05B50 /* SW Semaphore */
+#define E1000_FWSM 0x05B54 /* FW Semaphore */
+#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
+#define E1000_HICR 0x08F00 /* Host Inteface Control */
+
+#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE 0x07000000
+
+/* Mask bit for PHY class in Word 7 of the EEPROM */
+#define EEPROM_PHY_CLASS_A 0x8000
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds*/
+#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds*/
+
+#define E1000_KUMCTRLSTA_MASK 0x0000FFFF
+#define E1000_KUMCTRLSTA_OFFSET 0x001F0000
+#define E1000_KUMCTRLSTA_OFFSET_SHIFT 16
+#define E1000_KUMCTRLSTA_REN 0x00200000
+
+#define E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL 0x00000000
+#define E1000_KUMCTRLSTA_OFFSET_CTRL 0x00000001
+#define E1000_KUMCTRLSTA_OFFSET_INB_CTRL 0x00000002
+#define E1000_KUMCTRLSTA_OFFSET_DIAG 0x00000003
+#define E1000_KUMCTRLSTA_OFFSET_TIMEOUTS 0x00000004
+#define E1000_KUMCTRLSTA_OFFSET_INB_PARAM 0x00000009
+#define E1000_KUMCTRLSTA_OFFSET_HD_CTRL 0x00000010
+#define E1000_KUMCTRLSTA_OFFSET_M2P_SERDES 0x0000001E
+#define E1000_KUMCTRLSTA_OFFSET_M2P_MODES 0x0000001F
+
+/* FIFO Control */
+#define E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS 0x00000008
+#define E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS 0x00000800
+
+/* In-Band Control */
+#define E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT 0x00000500
+#define E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010
+
+/* Half-Duplex Control */
+#define E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004
+#define E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000
+
+#define E1000_KUMCTRLSTA_OFFSET_K0S_CTRL 0x0000001E
+
+#define E1000_KUMCTRLSTA_DIAG_FELPBK 0x2000
+#define E1000_KUMCTRLSTA_DIAG_NELPBK 0x1000
+
+#define E1000_KUMCTRLSTA_K0S_100_EN 0x2000
+#define E1000_KUMCTRLSTA_K0S_GBE_EN 0x1000
+#define E1000_KUMCTRLSTA_K0S_ENTRY_LATENCY_MASK 0x0003
+
+#define E1000_MNG_ICH_IAMT_MODE 0x2
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
+#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT 100
+#define DEFAULT_80003ES2LAN_TIPG_IPGT_10_100 0x00000009
+#define DEFAULT_80003ES2LAN_TIPG_IPGT_1000 0x00000008
+#define E1000_TXDMAC_DPP 0x00000001
+#define AUTO_ALL_MODES 0
+
+#ifndef E1000_MASTER_SLAVE
+/* Switch to override PHY master/slave setting */
+#define E1000_MASTER_SLAVE e1000_ms_hw_default
+#endif
+/* Extended Transmit Control */
+#define E1000_TCTL_EXT_BST_MASK 0x000003FF /* Backoff Slot Time */
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+
+#define DEFAULT_80003ES2LAN_TCTL_EXT_GCEX 0x00010000
+
+#define PCI_EX_82566_SNOOP_ALL PCI_EX_NO_SNOOP_ALL
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+#define E1000_MC_TBL_SIZE_ICH8LAN 32
+
+#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers
+ after IMS clear */
#endif /* _E1000_HW_H_ */
diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c
new file mode 100644
index 00000000000..2328cb51d2f
--- /dev/null
+++ b/drivers/net/ftmac100.c
@@ -0,0 +1,278 @@
+/*
+ * Faraday FTMAC100 Ethernet
+ *
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+
+#include "ftmac100.h"
+
+#define ETH_ZLEN 60
+
+struct ftmac100_data {
+ volatile struct ftmac100_txdes txdes[1];
+ volatile struct ftmac100_rxdes rxdes[PKTBUFSRX];
+ int rx_index;
+};
+
+/*
+ * Reset MAC
+ */
+static void ftmac100_reset (struct eth_device *dev)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+
+ debug ("%s()\n", __func__);
+
+ writel (FTMAC100_MACCR_SW_RST, &ftmac100->maccr);
+
+ while (readl (&ftmac100->maccr) & FTMAC100_MACCR_SW_RST)
+ ;
+}
+
+/*
+ * Set MAC address
+ */
+static void ftmac100_set_mac (struct eth_device *dev, const unsigned char *mac)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+ unsigned int maddr = mac[0] << 8 | mac[1];
+ unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
+
+ debug ("%s(%x %x)\n", __func__, maddr, laddr);
+
+ writel (maddr, &ftmac100->mac_madr);
+ writel (laddr, &ftmac100->mac_ladr);
+}
+
+static void ftmac100_set_mac_from_env (struct eth_device *dev)
+{
+ eth_getenv_enetaddr ("ethaddr", dev->enetaddr);
+
+ ftmac100_set_mac (dev, dev->enetaddr);
+}
+
+/*
+ * disable transmitter, receiver
+ */
+static void ftmac100_halt (struct eth_device *dev)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+
+ debug ("%s()\n", __func__);
+
+ writel (0, &ftmac100->maccr);
+}
+
+static int ftmac100_init (struct eth_device *dev, bd_t *bd)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+ struct ftmac100_data *priv = dev->priv;
+ volatile struct ftmac100_txdes *txdes = priv->txdes;
+ volatile struct ftmac100_rxdes *rxdes = priv->rxdes;
+ unsigned int maccr;
+ int i;
+
+ debug ("%s()\n", __func__);
+
+ ftmac100_reset (dev);
+
+ /* set the ethernet address */
+
+ ftmac100_set_mac_from_env (dev);
+
+ /* disable all interrupts */
+
+ writel (0, &ftmac100->imr);
+
+ /* initialize descriptors */
+
+ priv->rx_index = 0;
+
+ txdes[0].txdes1 = FTMAC100_TXDES1_EDOTR;
+ rxdes[PKTBUFSRX - 1].rxdes1 = FTMAC100_RXDES1_EDORR;
+
+ for (i = 0; i < PKTBUFSRX; i++) {
+ /* RXBUF_BADR */
+ rxdes[i].rxdes2 = (unsigned int)NetRxPackets[i];
+ rxdes[i].rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE (PKTSIZE_ALIGN);
+ rxdes[i].rxdes0 = FTMAC100_RXDES0_RXDMA_OWN;
+ }
+
+ /* transmit ring */
+
+ writel ((unsigned int)txdes, &ftmac100->txr_badr);
+
+ /* receive ring */
+
+ writel ((unsigned int)rxdes, &ftmac100->rxr_badr);
+
+ /* poll receive descriptor automatically */
+
+ writel (FTMAC100_APTC_RXPOLL_CNT (1), &ftmac100->aptc);
+
+ /* enable transmitter, receiver */
+
+ maccr = FTMAC100_MACCR_XMT_EN |
+ FTMAC100_MACCR_RCV_EN |
+ FTMAC100_MACCR_XDMA_EN |
+ FTMAC100_MACCR_RDMA_EN |
+ FTMAC100_MACCR_CRC_APD |
+ FTMAC100_MACCR_ENRX_IN_HALFTX |
+ FTMAC100_MACCR_RX_RUNT |
+ FTMAC100_MACCR_RX_BROADPKT;
+
+ writel (maccr, &ftmac100->maccr);
+
+ return 0;
+}
+
+/*
+ * Get a data block via Ethernet
+ */
+static int ftmac100_recv (struct eth_device *dev)
+{
+ struct ftmac100_data *priv = dev->priv;
+ volatile struct ftmac100_rxdes *curr_des;
+ unsigned short rxlen;
+
+ curr_des = &priv->rxdes[priv->rx_index];
+
+ if (curr_des->rxdes0 & FTMAC100_RXDES0_RXDMA_OWN)
+ return -1;
+
+ if (curr_des->rxdes0 & (FTMAC100_RXDES0_RX_ERR |
+ FTMAC100_RXDES0_CRC_ERR |
+ FTMAC100_RXDES0_FTL |
+ FTMAC100_RXDES0_RUNT |
+ FTMAC100_RXDES0_RX_ODD_NB)) {
+ return -1;
+ }
+
+ rxlen = FTMAC100_RXDES0_RFL (curr_des->rxdes0);
+
+ debug ("%s(): RX buffer %d, %x received\n",
+ __func__, priv->rx_index, rxlen);
+
+ /* pass the packet up to the protocol layers. */
+
+ NetReceive ((void *)curr_des->rxdes2, rxlen);
+
+ /* release buffer to DMA */
+
+ curr_des->rxdes0 |= FTMAC100_RXDES0_RXDMA_OWN;
+
+ priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
+
+ return 0;
+}
+
+/*
+ * Send a data block via Ethernet
+ */
+static int
+ftmac100_send (struct eth_device *dev, volatile void *packet, int length)
+{
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
+ struct ftmac100_data *priv = dev->priv;
+ volatile struct ftmac100_txdes *curr_des = priv->txdes;
+ int tmo;
+
+ if (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) {
+ debug ("%s(): no TX descriptor available\n", __func__);
+ return -1;
+ }
+
+ debug ("%s(%x, %x)\n", __func__, (int)packet, length);
+
+ length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
+
+ /* initiate a transmit sequence */
+
+ curr_des->txdes2 = (unsigned int)packet; /* TXBUF_BADR */
+
+ curr_des->txdes1 &= FTMAC100_TXDES1_EDOTR;
+ curr_des->txdes1 |= FTMAC100_TXDES1_FTS |
+ FTMAC100_TXDES1_LTS |
+ FTMAC100_TXDES1_TXBUF_SIZE (length);
+
+ curr_des->txdes0 = FTMAC100_TXDES0_TXDMA_OWN;
+
+ /* start transmit */
+
+ writel (1, &ftmac100->txpd);
+
+ /* wait for transfer to succeed */
+
+ tmo = get_timer (0) + 5 * CONFIG_SYS_HZ;
+ while (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) {
+ if (get_timer (0) >= tmo) {
+ debug ("%s(): timed out\n", __func__);
+ return -1;
+ }
+ }
+
+ debug ("%s(): packet sent\n", __func__);
+
+ return 0;
+}
+
+int ftmac100_initialize (bd_t *bd)
+{
+ struct eth_device *dev;
+ struct ftmac100_data *priv;
+
+ dev = malloc (sizeof *dev);
+ if (!dev) {
+ printf ("%s(): failed to allocate dev\n", __func__);
+ goto out;
+ }
+
+ /* Transmit and receive descriptors should align to 16 bytes */
+
+ priv = memalign (16, sizeof (struct ftmac100_data));
+ if (!priv) {
+ printf ("%s(): failed to allocate priv\n", __func__);
+ goto free_dev;
+ }
+
+ memset (dev, 0, sizeof (*dev));
+ memset (priv, 0, sizeof (*priv));
+
+ sprintf (dev->name, "FTMAC100");
+ dev->iobase = CONFIG_FTMAC100_BASE;
+ dev->init = ftmac100_init;
+ dev->halt = ftmac100_halt;
+ dev->send = ftmac100_send;
+ dev->recv = ftmac100_recv;
+ dev->priv = priv;
+
+ eth_register (dev);
+
+ return 1;
+
+free_dev:
+ free (dev);
+out:
+ return 0;
+}
diff --git a/drivers/net/ftmac100.h b/drivers/net/ftmac100.h
new file mode 100644
index 00000000000..21142d96610
--- /dev/null
+++ b/drivers/net/ftmac100.h
@@ -0,0 +1,154 @@
+/*
+ * Faraday FTMAC100 Ethernet
+ *
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FTMAC100_H
+#define __FTMAC100_H
+
+struct ftmac100 {
+ unsigned int isr; /* 0x00 */
+ unsigned int imr; /* 0x04 */
+ unsigned int mac_madr; /* 0x08 */
+ unsigned int mac_ladr; /* 0x0c */
+ unsigned int maht0; /* 0x10 */
+ unsigned int maht1; /* 0x14 */
+ unsigned int txpd; /* 0x18 */
+ unsigned int rxpd; /* 0x1c */
+ unsigned int txr_badr; /* 0x20 */
+ unsigned int rxr_badr; /* 0x24 */
+ unsigned int itc; /* 0x28 */
+ unsigned int aptc; /* 0x2c */
+ unsigned int dblac; /* 0x30 */
+ unsigned int pad1[3]; /* 0x34 - 0x3c */
+ unsigned int pad2[16]; /* 0x40 - 0x7c */
+ unsigned int pad3[2]; /* 0x80 - 0x84 */
+ unsigned int maccr; /* 0x88 */
+ unsigned int macsr; /* 0x8c */
+ unsigned int phycr; /* 0x90 */
+ unsigned int phywdata; /* 0x94 */
+ unsigned int fcr; /* 0x98 */
+ unsigned int bpr; /* 0x9c */
+ unsigned int pad4[8]; /* 0xa0 - 0xbc */
+ unsigned int pad5; /* 0xc0 */
+ unsigned int ts; /* 0xc4 */
+ unsigned int dmafifos; /* 0xc8 */
+ unsigned int tm; /* 0xcc */
+ unsigned int pad6; /* 0xd0 */
+ unsigned int tx_mcol_scol; /* 0xd4 */
+ unsigned int rpf_aep; /* 0xd8 */
+ unsigned int xm_pg; /* 0xdc */
+ unsigned int runt_tlcc; /* 0xe0 */
+ unsigned int crcer_ftl; /* 0xe4 */
+ unsigned int rlc_rcc; /* 0xe8 */
+ unsigned int broc; /* 0xec */
+ unsigned int mulca; /* 0xf0 */
+ unsigned int rp; /* 0xf4 */
+ unsigned int xp; /* 0xf8 */
+};
+
+/*
+ * Interrupt status register & interrupt mask register
+ */
+#define FTMAC100_INT_RPKT_FINISH (1 << 0)
+#define FTMAC100_INT_NORXBUF (1 << 1)
+#define FTMAC100_INT_XPKT_FINISH (1 << 2)
+#define FTMAC100_INT_NOTXBUF (1 << 3)
+#define FTMAC100_INT_XPKT_OK (1 << 4)
+#define FTMAC100_INT_XPKT_LOST (1 << 5)
+#define FTMAC100_INT_RPKT_SAV (1 << 6)
+#define FTMAC100_INT_RPKT_LOST (1 << 7)
+#define FTMAC100_INT_AHB_ERR (1 << 8)
+#define FTMAC100_INT_PHYSTS_CHG (1 << 9)
+
+/*
+ * Automatic polling timer control register
+ */
+#define FTMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0)
+#define FTMAC100_APTC_RXPOLL_TIME_SEL (1 << 4)
+#define FTMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8)
+#define FTMAC100_APTC_TXPOLL_TIME_SEL (1 << 12)
+
+/*
+ * MAC control register
+ */
+#define FTMAC100_MACCR_XDMA_EN (1 << 0)
+#define FTMAC100_MACCR_RDMA_EN (1 << 1)
+#define FTMAC100_MACCR_SW_RST (1 << 2)
+#define FTMAC100_MACCR_LOOP_EN (1 << 3)
+#define FTMAC100_MACCR_CRC_DIS (1 << 4)
+#define FTMAC100_MACCR_XMT_EN (1 << 5)
+#define FTMAC100_MACCR_ENRX_IN_HALFTX (1 << 6)
+#define FTMAC100_MACCR_RCV_EN (1 << 8)
+#define FTMAC100_MACCR_HT_MULTI_EN (1 << 9)
+#define FTMAC100_MACCR_RX_RUNT (1 << 10)
+#define FTMAC100_MACCR_RX_FTL (1 << 11)
+#define FTMAC100_MACCR_RCV_ALL (1 << 12)
+#define FTMAC100_MACCR_CRC_APD (1 << 14)
+#define FTMAC100_MACCR_FULLDUP (1 << 15)
+#define FTMAC100_MACCR_RX_MULTIPKT (1 << 16)
+#define FTMAC100_MACCR_RX_BROADPKT (1 << 17)
+
+/*
+ * Transmit descriptor, aligned to 16 bytes
+ */
+struct ftmac100_txdes {
+ unsigned int txdes0;
+ unsigned int txdes1;
+ unsigned int txdes2; /* TXBUF_BADR */
+ unsigned int txdes3; /* not used by HW */
+} __attribute__ ((aligned(16)));
+
+#define FTMAC100_TXDES0_TXPKT_LATECOL (1 << 0)
+#define FTMAC100_TXDES0_TXPKT_EXSCOL (1 << 1)
+#define FTMAC100_TXDES0_TXDMA_OWN (1 << 31)
+
+#define FTMAC100_TXDES1_TXBUF_SIZE(x) ((x) & 0x7ff)
+#define FTMAC100_TXDES1_LTS (1 << 27)
+#define FTMAC100_TXDES1_FTS (1 << 28)
+#define FTMAC100_TXDES1_TX2FIC (1 << 29)
+#define FTMAC100_TXDES1_TXIC (1 << 30)
+#define FTMAC100_TXDES1_EDOTR (1 << 31)
+
+/*
+ * Receive descriptor, aligned to 16 bytes
+ */
+struct ftmac100_rxdes {
+ unsigned int rxdes0;
+ unsigned int rxdes1;
+ unsigned int rxdes2; /* RXBUF_BADR */
+ unsigned int rxdes3; /* not used by HW */
+} __attribute__ ((aligned(16)));
+
+#define FTMAC100_RXDES0_RFL(des) ((des) & 0x7ff)
+#define FTMAC100_RXDES0_MULTICAST (1 << 16)
+#define FTMAC100_RXDES0_BROADCAST (1 << 17)
+#define FTMAC100_RXDES0_RX_ERR (1 << 18)
+#define FTMAC100_RXDES0_CRC_ERR (1 << 19)
+#define FTMAC100_RXDES0_FTL (1 << 20)
+#define FTMAC100_RXDES0_RUNT (1 << 21)
+#define FTMAC100_RXDES0_RX_ODD_NB (1 << 22)
+#define FTMAC100_RXDES0_LRS (1 << 28)
+#define FTMAC100_RXDES0_FRS (1 << 29)
+#define FTMAC100_RXDES0_RXDMA_OWN (1 << 31)
+
+#define FTMAC100_RXDES1_RXBUF_SIZE(x) ((x) & 0x7ff)
+#define FTMAC100_RXDES1_EDORR (1 << 31)
+
+#endif /* __FTMAC100_H */
diff --git a/drivers/net/kirkwood_egiga.c b/drivers/net/kirkwood_egiga.c
index 701812bf1c5..f31fefcb09f 100644
--- a/drivers/net/kirkwood_egiga.c
+++ b/drivers/net/kirkwood_egiga.c
@@ -592,7 +592,7 @@ int kirkwood_egiga_initialize(bd_t * bis)
struct kwgbe_device *dkwgbe;
struct eth_device *dev;
int devnum;
- char *s, buf[NAMESIZE * 2];
+ char *s;
u8 used_ports[MAX_KWGBE_DEVS] = CONFIG_KIRKWOOD_EGIGA_PORTS;
for (devnum = 0; devnum < MAX_KWGBE_DEVS; devnum++) {
@@ -650,11 +650,14 @@ int kirkwood_egiga_initialize(bd_t * bis)
}
while (!eth_getenv_enetaddr(s, dev->enetaddr)) {
- /* Generate Ramdom MAC addresses if not set */
- sprintf(buf, "00:50:43:%02x:%02x:%02x",
- get_random_hex(), get_random_hex(),
- get_random_hex());
- setenv(s, buf);
+ /* Generate Random Private MAC addr if not set */
+ dev->enetaddr[0] = 0x02;
+ dev->enetaddr[1] = 0x50;
+ dev->enetaddr[2] = 0x43;
+ dev->enetaddr[3] = get_random_hex();
+ dev->enetaddr[4] = get_random_hex();
+ dev->enetaddr[5] = get_random_hex();
+ eth_setenv_enetaddr(s, dev->enetaddr);
}
dev->init = (void *)kwgbe_init;
diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c
index 29630f5bf56..3754e8bdc43 100644
--- a/drivers/net/phy/mv88e61xx.c
+++ b/drivers/net/phy/mv88e61xx.c
@@ -38,7 +38,7 @@
*/
static int mv88e61xx_busychk_multic(char *name, u32 devaddr)
{
- u32 reg = 0;
+ u16 reg = 0;
u32 timeout = MV88E61XX_PHY_TIMEOUT;
/* Poll till SMIBusy bit is clear */
@@ -54,8 +54,7 @@ static int mv88e61xx_busychk_multic(char *name, u32 devaddr)
static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data)
{
- u16 reg;
- u32 mii_dev_addr;
+ u16 mii_dev_addr;
/* command to read PHY dev address */
if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
@@ -73,8 +72,7 @@ static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data)
static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data)
{
- u16 reg;
- u32 mii_dev_addr;
+ u16 mii_dev_addr;
/* command to read PHY dev address */
if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
@@ -357,15 +355,22 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig)
}
RD_PHY(name, MV88E61XX_PRT_OFST, PHY_PHYIDR2, &reg);
- reg &= 0xfff0;
- if (reg == 0x1610)
+ switch (reg &= 0xfff0) {
+ case 0x1610:
idstr = "88E6161";
- if (reg == 0x1650)
+ break;
+ case 0x1650:
idstr = "88E6165";
- if (reg == 0x1210) {
+ break;
+ case 0x1210:
idstr = "88E6123";
/* ports 2,3,4 not available */
swconfig->ports_enabled &= 0x023;
+ break;
+ default:
+ /* Could not detect switch id */
+ idstr = "88E61??";
+ break;
}
/* Port based VLANs configuration */
diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c
index d48d22b6121..db95adaeef9 100644
--- a/drivers/qe/uec.c
+++ b/drivers/qe/uec.c
@@ -31,6 +31,11 @@
#include "uec_phy.h"
#include "miiphy.h"
+/* Default UTBIPAR SMI address */
+#ifndef CONFIG_UTBIPAR_INIT_TBIPA
+#define CONFIG_UTBIPAR_INIT_TBIPA 0x1F
+#endif
+
static uec_info_t uec_info[] = {
#ifdef CONFIG_UEC_ETH1
STD_UEC_INFO(1), /* UEC1 */
@@ -1071,15 +1076,11 @@ static int uec_startup(uec_private_t *uec)
utbipar = in_be32(&uec_regs->utbipar);
utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
enet_interface = uec->uec_info->enet_interface;
- if (enet_interface == ENET_1000_TBI ||
- enet_interface == ENET_1000_RTBI) {
- utbipar |= (uec_info->phy_address + uec_info->uf_info.ucc_num)
- << UTBIPAR_PHY_ADDRESS_SHIFT;
- } else {
- utbipar |= (0x10 + uec_info->uf_info.ucc_num)
- << UTBIPAR_PHY_ADDRESS_SHIFT;
- }
+ /* Initialize UTBIPAR address to CONFIG_UTBIPAR_INIT_TBIPA for ALL UEC.
+ * This frees up the remaining SMI addresses for use.
+ */
+ utbipar |= CONFIG_UTBIPAR_INIT_TBIPA << UTBIPAR_PHY_ADDRESS_SHIFT;
out_be32(&uec_regs->utbipar, utbipar);
/* Configure the TBI for SGMII operation */
diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c
index d613f3e4cf2..aa4eb5e3893 100644
--- a/drivers/qe/uec_phy.c
+++ b/drivers/qe/uec_phy.c
@@ -51,27 +51,28 @@
*--------------------------------------------------------------------*/
/*
- * Some boards do not have a PHY for each ethernet port. These ports
- * are known as Fixed PHY (or PHY-less) ports. For such ports, set
- * the appropriate CONFIG_PHY_ADDR equal to CONFIG_FIXED_PHY and
- * then define CONFIG_SYS_FIXED_PHY_PORTS to define what the speed and
- * duplex should be for these ports in the board configuration
- * file.
+ * Some boards do not have a PHY for each ethernet port. These ports are known
+ * as Fixed PHY (or PHY-less) ports. For such ports, set the appropriate
+ * CONFIG_SYS_UECx_PHY_ADDR equal to CONFIG_FIXED_PHY_ADDR (an unused address)
+ * When the drver tries to identify the PHYs, CONFIG_FIXED_PHY will be returned
+ * and the driver will search CONFIG_SYS_FIXED_PHY_PORTS to find what network
+ * speed and duplex should be for the port.
*
- * For Example:
+ * Example board header configuration file:
* #define CONFIG_FIXED_PHY 0xFFFFFFFF
+ * #define CONFIG_SYS_FIXED_PHY_ADDR 0x1E (pick an unused phy address)
*
- * #define CONFIG_PHY_ADDR CONFIG_FIXED_PHY
- * #define CONFIG_PHY1_ADDR 1
- * #define CONFIG_PHY2_ADDR CONFIG_FIXED_PHY
- * #define CONFIG_PHY3_ADDR 3
+ * #define CONFIG_SYS_UEC1_PHY_ADDR CONFIG_SYS_FIXED_PHY_ADDR
+ * #define CONFIG_SYS_UEC2_PHY_ADDR 0x02
+ * #define CONFIG_SYS_UEC3_PHY_ADDR CONFIG_SYS_FIXED_PHY_ADDR
+ * #define CONFIG_SYS_UEC4_PHY_ADDR 0x04
*
- * #define CONFIG_SYS_FIXED_PHY_PORT(devnum,speed,duplex) \
- * {devnum, speed, duplex},
+ * #define CONFIG_SYS_FIXED_PHY_PORT(name,speed,duplex) \
+ * {name, speed, duplex},
*
* #define CONFIG_SYS_FIXED_PHY_PORTS \
- * CONFIG_SYS_FIXED_PHY_PORT(0,SPEED_100,DUPLEX_FULL) \
- * CONFIG_SYS_FIXED_PHY_PORT(2,SPEED_100,DUPLEX_HALF)
+ * CONFIG_SYS_FIXED_PHY_PORT("FSL UEC0",SPEED_100,DUPLEX_FULL) \
+ * CONFIG_SYS_FIXED_PHY_PORT("FSL UEC2",SPEED_100,DUPLEX_HALF)
*/
#ifndef CONFIG_FIXED_PHY
@@ -83,7 +84,7 @@
#endif
struct fixed_phy_port {
- unsigned int devnum; /* ethernet port */
+ char name[NAMESIZE]; /* ethernet port name */
unsigned int speed; /* specified speed 10,100 or 1000 */
unsigned int duplex; /* specified duplex FULL or HALF */
};
@@ -592,7 +593,8 @@ static int fixed_phy_read_status (struct uec_mii_info *mii_info)
int i = 0;
for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
- if (mii_info->mii_id == fixed_phy_port[i].devnum) {
+ if (strncmp(mii_info->dev->name, fixed_phy_port[i].name,
+ strlen(mii_info->dev->name)) == 0) {
mii_info->speed = fixed_phy_port[i].speed;
mii_info->duplex = fixed_phy_port[i].duplex;
mii_info->link = 1; /* Link is always UP */
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index a9f67a0ac0d..824d8e740ca 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -28,6 +28,7 @@ LIB := $(obj)libspi.a
COBJS-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o
COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o
+COBJS-$(CONFIG_CF_SPI) += cf_spi.o
COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
diff --git a/drivers/spi/cf_spi.c b/drivers/spi/cf_spi.c
new file mode 100644
index 00000000000..722aafc73c3
--- /dev/null
+++ b/drivers/spi/cf_spi.c
@@ -0,0 +1,357 @@
+/*
+ *
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2009 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <malloc.h>
+#include <asm/immap.h>
+
+struct cf_spi_slave {
+ struct spi_slave slave;
+ uint baudrate;
+ int charbit;
+};
+
+int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout,
+ void *din, ulong flags);
+struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave, uint mode);
+void cfspi_init(void);
+void cfspi_tx(u32 ctrl, u16 data);
+u16 cfspi_rx(void);
+
+extern void cfspi_port_conf(void);
+extern int cfspi_claim_bus(uint bus, uint cs);
+extern void cfspi_release_bus(uint bus, uint cs);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CF_DSPI)
+/* DSPI specific mode */
+#define SPI_MODE_MOD 0x00200000
+#define SPI_DBLRATE 0x00100000
+
+void cfspi_init(void)
+{
+ volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
+
+ cfspi_port_conf(); /* port configuration */
+
+ dspi->mcr = DSPI_MCR_MSTR | DSPI_MCR_CSIS7 | DSPI_MCR_CSIS6 |
+ DSPI_MCR_CSIS5 | DSPI_MCR_CSIS4 | DSPI_MCR_CSIS3 |
+ DSPI_MCR_CSIS2 | DSPI_MCR_CSIS1 | DSPI_MCR_CSIS0 |
+ DSPI_MCR_CRXF | DSPI_MCR_CTXF;
+
+ /* Default setting in platform configuration */
+#ifdef CONFIG_SYS_DSPI_CTAR0
+ dspi->ctar[0] = CONFIG_SYS_DSPI_CTAR0;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR1
+ dspi->ctar[1] = CONFIG_SYS_DSPI_CTAR1;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR2
+ dspi->ctar[2] = CONFIG_SYS_DSPI_CTAR2;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR3
+ dspi->ctar[3] = CONFIG_SYS_DSPI_CTAR3;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR4
+ dspi->ctar[4] = CONFIG_SYS_DSPI_CTAR4;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR5
+ dspi->ctar[5] = CONFIG_SYS_DSPI_CTAR5;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR6
+ dspi->ctar[6] = CONFIG_SYS_DSPI_CTAR6;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR7
+ dspi->ctar[7] = CONFIG_SYS_DSPI_CTAR7;
+#endif
+}
+
+void cfspi_tx(u32 ctrl, u16 data)
+{
+ volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
+
+ while ((dspi->sr & 0x0000F000) >= 4) ;
+
+ dspi->tfr = (ctrl | data);
+}
+
+u16 cfspi_rx(void)
+{
+ volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
+
+ while ((dspi->sr & 0x000000F0) == 0) ;
+
+ return (dspi->rfr & 0xFFFF);
+}
+
+int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout,
+ void *din, ulong flags)
+{
+ struct cf_spi_slave *cfslave = (struct cf_spi_slave *)slave;
+ u16 *spi_rd16 = NULL, *spi_wr16 = NULL;
+ u8 *spi_rd = NULL, *spi_wr = NULL;
+ static u32 ctrl = 0;
+ uint len = bitlen >> 3;
+
+ if (cfslave->charbit == 16) {
+ bitlen >>= 1;
+ spi_wr16 = (u16 *) dout;
+ spi_rd16 = (u16 *) din;
+ } else {
+ spi_wr = (u8 *) dout;
+ spi_rd = (u8 *) din;
+ }
+
+ if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN)
+ ctrl |= DSPI_TFR_CONT;
+
+ ctrl = (ctrl & 0xFF000000) | ((1 << slave->cs) << 16);
+
+ if (len > 1) {
+ int tmp_len = len - 1;
+ while (tmp_len--) {
+ if (dout != NULL) {
+ if (cfslave->charbit == 16)
+ cfspi_tx(ctrl, *spi_wr16++);
+ else
+ cfspi_tx(ctrl, *spi_wr++);
+ cfspi_rx();
+ }
+
+ if (din != NULL) {
+ cfspi_tx(ctrl, 0);
+ if (cfslave->charbit == 16)
+ *spi_rd16++ = cfspi_rx();
+ else
+ *spi_rd++ = cfspi_rx();
+ }
+ }
+
+ len = 1; /* remaining byte */
+ }
+
+ if ((flags & SPI_XFER_END) == SPI_XFER_END)
+ ctrl &= ~DSPI_TFR_CONT;
+
+ if (len) {
+ if (dout != NULL) {
+ if (cfslave->charbit == 16)
+ cfspi_tx(ctrl, *spi_wr16);
+ else
+ cfspi_tx(ctrl, *spi_wr);
+ cfspi_rx();
+ }
+
+ if (din != NULL) {
+ cfspi_tx(ctrl, 0);
+ if (cfslave->charbit == 16)
+ *spi_rd16 = cfspi_rx();
+ else
+ *spi_rd = cfspi_rx();
+ }
+ } else {
+ /* dummy read */
+ cfspi_tx(ctrl, 0);
+ cfspi_rx();
+ }
+
+ return 0;
+}
+
+struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave, uint mode)
+{
+ /*
+ * bit definition for mode:
+ * bit 31 - 28: Transfer size 3 to 16 bits
+ * 27 - 26: PCS to SCK delay prescaler
+ * 25 - 24: After SCK delay prescaler
+ * 23 - 22: Delay after transfer prescaler
+ * 21 : Allow overwrite for bit 31-22 and bit 20-8
+ * 20 : Double baud rate
+ * 19 - 16: PCS to SCK delay scaler
+ * 15 - 12: After SCK delay scaler
+ * 11 - 8: Delay after transfer scaler
+ * 7 - 0: SPI_CPHA, SPI_CPOL, SPI_LSB_FIRST
+ */
+ volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
+ int prescaler[] = { 2, 3, 5, 7 };
+ int scaler[] = {
+ 2, 4, 6, 8,
+ 16, 32, 64, 128,
+ 256, 512, 1024, 2048,
+ 4096, 8192, 16384, 32768
+ };
+ int i, j, pbrcnt, brcnt, diff, tmp, dbr = 0;
+ int best_i, best_j, bestmatch = 0x7FFFFFFF, baud_speed;
+ u32 bus_setup = 0;
+
+ tmp = (prescaler[3] * scaler[15]);
+ /* Maximum and minimum baudrate it can handle */
+ if ((cfslave->baudrate > (gd->bus_clk >> 1)) ||
+ (cfslave->baudrate < (gd->bus_clk / tmp))) {
+ printf("Exceed baudrate limitation: Max %d - Min %d\n",
+ (int)(gd->bus_clk >> 1), (int)(gd->bus_clk / tmp));
+ return NULL;
+ }
+
+ /* Activate Double Baud when it exceed 1/4 the bus clk */
+ if ((CONFIG_SYS_DSPI_CTAR0 & DSPI_CTAR_DBR) ||
+ (cfslave->baudrate > (gd->bus_clk / (prescaler[0] * scaler[0])))) {
+ bus_setup |= DSPI_CTAR_DBR;
+ dbr = 1;
+ }
+
+ if (mode & SPI_CPOL)
+ bus_setup |= DSPI_CTAR_CPOL;
+ if (mode & SPI_CPHA)
+ bus_setup |= DSPI_CTAR_CPHA;
+ if (mode & SPI_LSB_FIRST)
+ bus_setup |= DSPI_CTAR_LSBFE;
+
+ /* Overwrite default value set in platform configuration file */
+ if (mode & SPI_MODE_MOD) {
+
+ if ((mode & 0xF0000000) == 0)
+ bus_setup |=
+ dspi->ctar[cfslave->slave.bus] & 0x78000000;
+ else
+ bus_setup |= ((mode & 0xF0000000) >> 1);
+
+ /*
+ * Check to see if it is enabled by default in platform
+ * config, or manual setting passed by mode parameter
+ */
+ if (mode & SPI_DBLRATE) {
+ bus_setup |= DSPI_CTAR_DBR;
+ dbr = 1;
+ }
+ bus_setup |= (mode & 0x0FC00000) >> 4; /* PSCSCK, PASC, PDT */
+ bus_setup |= (mode & 0x000FFF00) >> 4; /* CSSCK, ASC, DT */
+ } else
+ bus_setup |= (dspi->ctar[cfslave->slave.bus] & 0x78FCFFF0);
+
+ cfslave->charbit =
+ ((dspi->ctar[cfslave->slave.bus] & 0x78000000) ==
+ 0x78000000) ? 16 : 8;
+
+ pbrcnt = sizeof(prescaler) / sizeof(int);
+ brcnt = sizeof(scaler) / sizeof(int);
+
+ /* baudrate calculation - to closer value, may not be exact match */
+ for (best_i = 0, best_j = 0, i = 0; i < pbrcnt; i++) {
+ baud_speed = gd->bus_clk / prescaler[i];
+ for (j = 0; j < brcnt; j++) {
+ tmp = (baud_speed / scaler[j]) * (1 + dbr);
+
+ if (tmp > cfslave->baudrate)
+ diff = tmp - cfslave->baudrate;
+ else
+ diff = cfslave->baudrate - tmp;
+
+ if (diff < bestmatch) {
+ bestmatch = diff;
+ best_i = i;
+ best_j = j;
+ }
+ }
+ }
+ bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j));
+ dspi->ctar[cfslave->slave.bus] = bus_setup;
+
+ return &cfslave->slave;
+}
+#endif /* CONFIG_CF_DSPI */
+
+#ifdef CONFIG_CF_QSPI
+/* 52xx, 53xx */
+#endif /* CONFIG_CF_QSPI */
+
+#ifdef CONFIG_CMD_SPI
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
+ return 1;
+ else
+ return 0;
+}
+
+void spi_init_f(void)
+{
+}
+
+void spi_init_r(void)
+{
+}
+
+void spi_init(void)
+{
+ cfspi_init();
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct cf_spi_slave *cfslave;
+
+ if (!spi_cs_is_valid(bus, cs))
+ return NULL;
+
+ cfslave = malloc(sizeof(struct cf_spi_slave));
+ if (!cfslave)
+ return NULL;
+
+ cfslave->slave.bus = bus;
+ cfslave->slave.cs = cs;
+ cfslave->baudrate = max_hz;
+
+ /* specific setup */
+ return cfspi_setup_slave(cfslave, mode);
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ return cfspi_claim_bus(slave->bus, slave->cs);
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ cfspi_release_bus(slave->bus, slave->cs);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ return cfspi_xfer(slave, bitlen, dout, din, flags);
+}
+#endif /* CONFIG_CMD_SPI */
diff --git a/drivers/video/bus_vcxk.c b/drivers/video/bus_vcxk.c
index b3b53e12bc3..7726bb3193c 100644
--- a/drivers/video/bus_vcxk.c
+++ b/drivers/video/bus_vcxk.c
@@ -380,7 +380,6 @@ int vcxk_display_bitmap(ulong addr, int x, int y)
unsigned long c_width;
unsigned long c_height;
unsigned char *dataptr;
- unsigned char *lineptr;
bmp = (bmp_image_t *) addr;
if ((bmp->header.signature[0] == 'B') &&