summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/ahci.c2
-rw-r--r--drivers/dfu/dfu_nand.c2
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/lpc32xx_gpio.c293
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ds620.c65
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/lpc32xx_i2c.c249
-rw-r--r--drivers/mmc/bcm2835_sdhci.c4
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/atmel_nand.c6
-rw-r--r--drivers/mtd/nand/davinci_nand.c12
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c38
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c38
-rw-r--r--drivers/mtd/nand/fsl_upm.c18
-rw-r--r--drivers/mtd/nand/lpc32xx_nand_mlc.c764
-rw-r--r--drivers/mtd/nand/mpc5121_nfc.c26
-rw-r--r--drivers/mtd/nand/mxc_nand.c33
-rw-r--r--drivers/mtd/nand/mxs_nand.c4
-rw-r--r--drivers/mtd/nand/nand_base.c65
-rw-r--r--drivers/mtd/nand/nand_util.c156
-rw-r--r--drivers/mtd/nand/ndfc.c18
-rw-r--r--drivers/mtd/nand/vf610_nfc.c28
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/e1000.h7
-rw-r--r--drivers/net/lpc32xx_eth.c637
-rw-r--r--drivers/net/pch_gbe.c466
-rw-r--r--drivers/net/pch_gbe.h300
-rw-r--r--drivers/power/axp209.c2
-rw-r--r--drivers/rtc/mc146818.c1
-rw-r--r--drivers/serial/serial-uclass.c2
-rw-r--r--drivers/serial/serial_arc.c103
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/cf_qspi.c2
-rw-r--r--drivers/spi/cf_spi.c31
-rw-r--r--drivers/spi/davinci_spi.c3
-rw-r--r--drivers/spi/designware_spi.c4
-rw-r--r--drivers/spi/ftssp010_spi.c4
-rw-r--r--drivers/spi/lpc32xx_ssp.c144
-rw-r--r--drivers/spi/ti_qspi.c7
-rw-r--r--drivers/usb/gadget/ether.c1
-rw-r--r--drivers/usb/gadget/rndis.c1
-rw-r--r--drivers/usb/musb-new/musb_uboot.c14
-rw-r--r--drivers/usb/musb-new/sunxi.c2
-rw-r--r--drivers/video/exynos_fb.c21
-rw-r--r--drivers/video/mpc8xx_lcd.c1
-rw-r--r--drivers/video/parade.c11
-rw-r--r--drivers/video/pxa_lcd.c1
49 files changed, 3211 insertions, 389 deletions
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index c908fab450..88b90e0203 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -785,7 +785,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
/* Read/Write from ahci */
if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis),
- user_buffer, user_buffer_size,
+ user_buffer, transfer_size,
is_write)) {
debug("scsi_ahci: SCSI %s10 command failure.\n",
is_write ? "WRITE" : "READ");
diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c
index f9ee18999a..a9754922e8 100644
--- a/drivers/dfu/dfu_nand.c
+++ b/drivers/dfu/dfu_nand.c
@@ -64,7 +64,7 @@ static int nand_block_op(enum dfu_op op, struct dfu_entity *dfu,
return ret;
/* then write */
ret = nand_write_skip_bad(nand, start, &count, &actual,
- lim, buf, 0);
+ lim, buf, WITH_WR_VERIFY);
}
if (ret != 0) {
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b609e73bba..7b5178a23a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -7,3 +7,10 @@ config DM_GPIO
the GPIO uclass. Drivers provide methods to query the
particular GPIOs that they provide. The uclass interface
is defined in include/asm-generic/gpio.h.
+
+config LPC32XX_GPIO
+ bool "LPC32XX GPIO driver"
+ depends on DM
+ default n
+ help
+ Support for the LPC32XX GPIO driver.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fe9a3b2396..85f71c5d4a 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -41,3 +41,4 @@ obj-$(CONFIG_ADI_GPIO2) += adi_gpio2.o
obj-$(CONFIG_TCA642X) += tca642x.o
oby-$(CONFIG_SX151X) += sx151x.o
obj-$(CONFIG_SUNXI_GPIO) += sunxi_gpio.o
+obj-$(CONFIG_LPC32XX_GPIO) += lpc32xx_gpio.o
diff --git a/drivers/gpio/lpc32xx_gpio.c b/drivers/gpio/lpc32xx_gpio.c
new file mode 100644
index 0000000000..96b312592b
--- /dev/null
+++ b/drivers/gpio/lpc32xx_gpio.c
@@ -0,0 +1,293 @@
+/*
+ * LPC32xxGPIO driver
+ *
+ * (C) Copyright 2014 DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/io.h>
+#include <asm/arch-lpc32xx/cpu.h>
+#include <asm/arch-lpc32xx/gpio.h>
+#include <asm-generic/gpio.h>
+#include <dm.h>
+
+/**
+ * LPC32xx GPIOs work in banks but are non-homogeneous:
+ * - each bank holds a different number of GPIOs
+ * - some GPIOs are input/ouput, some input only, some output only;
+ * - some GPIOs have different meanings as an input and as an output;
+ * - some GPIOs are controlled on a given port and bit index, but
+ * read on another one.
+*
+ * In order to keep this code simple, GPIOS are considered here as
+ * homogeneous and linear, from 0 to 127.
+ *
+ * ** WARNING #1 **
+ *
+ * Client code is responsible for properly using valid GPIO numbers,
+ * including cases where a single physical GPIO has differing numbers
+ * for setting its direction, reading it and/or writing to it.
+ *
+ * ** WARNING #2 **
+ *
+ * Please read NOTE in description of lpc32xx_gpio_get_function().
+ */
+
+#define LPC32XX_GPIOS 128
+
+struct lpc32xx_gpio_platdata {
+ struct gpio_regs *regs;
+ /* GPIO FUNCTION: SEE WARNING #2 */
+ signed char function[LPC32XX_GPIOS];
+};
+
+/**
+ * We have 4 GPIO ports of 32 bits each
+ */
+
+#define MAX_GPIO 128
+
+#define GPIO_TO_PORT(gpio) ((gpio / 32) & 3)
+#define GPIO_TO_RANK(gpio) (gpio % 32)
+#define GPIO_TO_MASK(gpio) (1 << (gpio % 32))
+
+/**
+ * Configure a GPIO number 'offset' as input
+ */
+
+static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ int port, mask;
+ struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+ struct gpio_regs *regs = gpio_platdata->regs;
+
+ port = GPIO_TO_PORT(offset);
+ mask = GPIO_TO_MASK(offset);
+
+ switch (port) {
+ case 0:
+ writel(mask, &regs->p0_dir_clr);
+ break;
+ case 1:
+ writel(mask, &regs->p1_dir_clr);
+ break;
+ case 2:
+ /* ports 2 and 3 share a common direction */
+ case 3:
+ writel(mask, &regs->p2_p3_dir_clr);
+ break;
+ default:
+ return -1;
+ }
+
+ /* GPIO FUNCTION: SEE WARNING #2 */
+ gpio_platdata->function[offset] = GPIOF_INPUT;
+
+ return 0;
+}
+
+/**
+ * Get the value of a GPIO
+ */
+
+static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ int port, rank, mask, value;
+ struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+ struct gpio_regs *regs = gpio_platdata->regs;
+
+ port = GPIO_TO_PORT(offset);
+
+ switch (port) {
+ case 0:
+ value = readl(&regs->p0_inp_state);
+ break;
+ case 1:
+ value = readl(&regs->p1_inp_state);
+ break;
+ case 2:
+ value = readl(&regs->p2_inp_state);
+ break;
+ case 3:
+ value = readl(&regs->p3_inp_state);
+ break;
+ default:
+ return -1;
+ }
+
+ rank = GPIO_TO_RANK(offset);
+ mask = GPIO_TO_MASK(offset);
+
+ return (value & mask) >> rank;
+}
+
+/**
+ * Set a GPIO
+ */
+
+static int gpio_set(struct udevice *dev, unsigned gpio)
+{
+ int port, mask;
+ struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+ struct gpio_regs *regs = gpio_platdata->regs;
+
+ port = GPIO_TO_PORT(gpio);
+ mask = GPIO_TO_MASK(gpio);
+
+ switch (port) {
+ case 0:
+ writel(mask, &regs->p0_outp_set);
+ break;
+ case 1:
+ writel(mask, &regs->p1_outp_set);
+ break;
+ case 2:
+ writel(mask, &regs->p2_outp_set);
+ break;
+ case 3:
+ writel(mask, &regs->p3_outp_set);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Clear a GPIO
+ */
+
+static int gpio_clr(struct udevice *dev, unsigned gpio)
+{
+ int port, mask;
+ struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+ struct gpio_regs *regs = gpio_platdata->regs;
+
+ port = GPIO_TO_PORT(gpio);
+ mask = GPIO_TO_MASK(gpio);
+
+ switch (port) {
+ case 0:
+ writel(mask, &regs->p0_outp_clr);
+ break;
+ case 1:
+ writel(mask, &regs->p1_outp_clr);
+ break;
+ case 2:
+ writel(mask, &regs->p2_outp_clr);
+ break;
+ case 3:
+ writel(mask, &regs->p3_outp_clr);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Set the value of a GPIO
+ */
+
+static int lpc32xx_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ if (value)
+ return gpio_set(dev, offset);
+ else
+ return gpio_clr(dev, offset);
+}
+
+/**
+ * Configure a GPIO number 'offset' as output with given initial value.
+ */
+
+static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ int port, mask;
+ struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+ struct gpio_regs *regs = gpio_platdata->regs;
+
+ port = GPIO_TO_PORT(offset);
+ mask = GPIO_TO_MASK(offset);
+
+ switch (port) {
+ case 0:
+ writel(mask, &regs->p0_dir_set);
+ break;
+ case 1:
+ writel(mask, &regs->p1_dir_set);
+ break;
+ case 2:
+ /* ports 2 and 3 share a common direction */
+ case 3:
+ writel(mask, &regs->p2_p3_dir_set);
+ break;
+ default:
+ return -1;
+ }
+
+ /* GPIO FUNCTION: SEE WARNING #2 */
+ gpio_platdata->function[offset] = GPIOF_OUTPUT;
+
+ return lpc32xx_gpio_set_value(dev, offset, value);
+}
+
+/**
+ * GPIO functions are supposed to be computed from their current
+ * configuration, but that's way too complicated in LPC32XX. A simpler
+ * approach is used, where the GPIO functions are cached in an array.
+ * When the GPIO is in use, its function is either "input" or "output"
+ * depending on its direction, otherwise its function is "unknown".
+ *
+ * ** NOTE **
+ *
+ * THIS APPROACH WAS CHOSEN DU TO THE COMPLEX NATURE OF THE LPC32XX
+ * GPIOS; DO NOT TAKE THIS AS AN EXAMPLE FOR NEW CODE.
+ */
+
+static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+ return gpio_platdata->function[offset];
+}
+
+static const struct dm_gpio_ops gpio_lpc32xx_ops = {
+ .direction_input = lpc32xx_gpio_direction_input,
+ .direction_output = lpc32xx_gpio_direction_output,
+ .get_value = lpc32xx_gpio_get_value,
+ .set_value = lpc32xx_gpio_set_value,
+ .get_function = lpc32xx_gpio_get_function,
+};
+
+static int lpc32xx_gpio_probe(struct udevice *dev)
+{
+ struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+ struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+ if (dev->of_offset == -1) {
+ /* Tell the uclass how many GPIOs we have */
+ uc_priv->gpio_count = LPC32XX_GPIOS;
+ }
+
+ /* set base address for GPIO registers */
+ gpio_platdata->regs = (struct gpio_regs *)GPIO_BASE;
+
+ /* all GPIO functions are unknown until requested */
+ /* GPIO FUNCTION: SEE WARNING #2 */
+ memset(gpio_platdata->function, GPIOF_UNKNOWN,
+ sizeof(gpio_platdata->function));
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_lpc32xx) = {
+ .name = "gpio_lpc32xx",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_lpc32xx_ops,
+ .probe = lpc32xx_gpio_probe,
+ .priv_auto_alloc_size = sizeof(struct lpc32xx_gpio_platdata),
+};
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 25b8e8a2d7..b4fb057c16 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_DTT_ADT7460) += adt7460.o
obj-$(CONFIG_DTT_DS1621) += ds1621.o
obj-$(CONFIG_DTT_DS1722) += ds1722.o
obj-$(CONFIG_DTT_DS1775) += ds1775.o
+obj-$(CONFIG_DTT_DS620) += ds620.o
obj-$(CONFIG_DTT_LM63) += lm63.o
obj-$(CONFIG_DTT_LM73) += lm73.o
obj-$(CONFIG_DTT_LM75) += lm75.o
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
new file mode 100644
index 0000000000..1ecc3da799
--- /dev/null
+++ b/drivers/hwmon/ds620.c
@@ -0,0 +1,65 @@
+/*
+ * DS620 DTT support
+ *
+ * (C) Copyright 2014 3ADEV <http://www.3adev.com>
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Dallas Semiconductor's DS1621/1631 Digital Thermometer and Thermostat.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <dtt.h>
+
+/*
+ * Device code
+ */
+#define DTT_I2C_DEV_CODE 0x48
+#define DTT_START_CONVERT 0x51
+#define DTT_TEMP 0xAA
+#define DTT_CONFIG 0xAC
+
+/*
+ * Config register MSB bits
+ */
+#define DTT_CONFIG_1SHOT 0x01
+#define DTT_CONFIG_AUTOC 0x02
+#define DTT_CONFIG_R0 0x04 /* always 1 */
+#define DTT_CONFIG_R1 0x08 /* always 1 */
+#define DTT_CONFIG_TLF 0x10
+#define DTT_CONFIG_THF 0x20
+#define DTT_CONFIG_NVB 0x40
+#define DTT_CONFIG_DONE 0x80
+
+#define CHIP(sensor) (DTT_I2C_DEV_CODE + (sensor & 0x07))
+
+int dtt_init_one(int sensor)
+{
+ uint8_t config = DTT_CONFIG_1SHOT
+ | DTT_CONFIG_R0
+ | DTT_CONFIG_R1;
+ return i2c_write(CHIP(sensor), DTT_CONFIG, 1, &config, 1);
+}
+
+int dtt_get_temp(int sensor)
+{
+ uint8_t status;
+ uint8_t temp[2];
+
+ /* Start a conversion, may take up to 1 second. */
+ i2c_write(CHIP(sensor), DTT_START_CONVERT, 1, NULL, 0);
+ do {
+ if (i2c_read(CHIP(sensor), DTT_CONFIG, 1, &status, 1))
+ /* bail out if I2C error */
+ status |= DTT_CONFIG_DONE;
+ } while (!(status & DTT_CONFIG_DONE));
+ if (i2c_read(CHIP(sensor), DTT_TEMP, 1, temp, 2))
+ /* bail out if I2C error */
+ return -274; /* below absolute zero == error */
+
+ return ((int16_t)(temp[1] | (temp[0] << 8))) >> 7;
+}
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 774bc94a4a..26ea854ec8 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o
obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o
+obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
obj-$(CONFIG_SYS_I2C_MXS) += mxs_i2c.o
diff --git a/drivers/i2c/lpc32xx_i2c.c b/drivers/i2c/lpc32xx_i2c.c
new file mode 100644
index 0000000000..78d26e48c3
--- /dev/null
+++ b/drivers/i2c/lpc32xx_i2c.c
@@ -0,0 +1,249 @@
+/*
+ * LPC32xx I2C interface driver
+ *
+ * (C) Copyright 2014 DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include <asm/errno.h>
+#include <asm/arch/clk.h>
+
+/*
+ * Provide default speed and slave if target did not
+ */
+
+#if !defined(CONFIG_SYS_I2C_LPC32XX_SPEED)
+#define CONFIG_SYS_I2C_LPC32XX_SPEED 350000
+#endif
+
+#if !defined(CONFIG_SYS_I2C_LPC32XX_SLAVE)
+#define CONFIG_SYS_I2C_LPC32XX_SLAVE 0
+#endif
+
+/* i2c register set */
+struct lpc32xx_i2c_registers {
+ union {
+ u32 rx;
+ u32 tx;
+ };
+ u32 stat;
+ u32 ctrl;
+ u32 clk_hi;
+ u32 clk_lo;
+ u32 adr;
+ u32 rxfl;
+ u32 txfl;
+ u32 rxb;
+ u32 txb;
+ u32 stx;
+ u32 stxfl;
+};
+
+/* TX register fields */
+#define LPC32XX_I2C_TX_START 0x00000100
+#define LPC32XX_I2C_TX_STOP 0x00000200
+
+/* Control register values */
+#define LPC32XX_I2C_SOFT_RESET 0x00000100
+
+/* Status register values */
+#define LPC32XX_I2C_STAT_TFF 0x00000400
+#define LPC32XX_I2C_STAT_RFE 0x00000200
+#define LPC32XX_I2C_STAT_DRMI 0x00000008
+#define LPC32XX_I2C_STAT_NAI 0x00000004
+#define LPC32XX_I2C_STAT_TDI 0x00000001
+
+static struct lpc32xx_i2c_registers *lpc32xx_i2c[] = {
+ (struct lpc32xx_i2c_registers *)I2C1_BASE,
+ (struct lpc32xx_i2c_registers *)I2C2_BASE
+};
+
+/* Set I2C bus speed */
+static unsigned int lpc32xx_i2c_set_bus_speed(struct i2c_adapter *adap,
+ unsigned int speed)
+{
+ int half_period;
+
+ if (speed == 0)
+ return -EINVAL;
+
+ half_period = (105000000 / speed) / 2;
+
+ if ((half_period > 255) || (half_period < 0))
+ return -EINVAL;
+
+ writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_hi);
+ writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_lo);
+ return 0;
+}
+
+/* I2C init called by cmd_i2c when doing 'i2c reset'. */
+static void _i2c_init(struct i2c_adapter *adap,
+ int requested_speed, int slaveadd)
+{
+ struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
+
+ /* soft reset (auto-clears) */
+ writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
+ /* set HI and LO periods for about 350 kHz */
+ lpc32xx_i2c_set_bus_speed(adap, requested_speed);
+}
+
+/* I2C probe called by cmd_i2c when doing 'i2c probe'. */
+static int lpc32xx_i2c_probe(struct i2c_adapter *adap, u8 dev)
+{
+ struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
+ int stat;
+
+ /* Soft-reset the controller */
+ writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
+ while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
+ ;
+ /* Addre slave for write with start before and stop after */
+ writel((dev<<1) | LPC32XX_I2C_TX_START | LPC32XX_I2C_TX_STOP,
+ &i2c->tx);
+ /* wait for end of transation */
+ while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
+ ;
+ /* was there no acknowledge? */
+ return (stat & LPC32XX_I2C_STAT_NAI) ? -1 : 0;
+}
+
+/*
+ * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
+ * Begin write, send address byte(s), begin read, receive data bytes, end.
+ */
+static int lpc32xx_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
+ int alen, u8 *data, int length)
+{
+ struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
+ int stat, wlen;
+
+ /* Soft-reset the controller */
+ writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
+ while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
+ ;
+ /* do we need to write an address at all? */
+ if (alen) {
+ /* Address slave in write mode */
+ writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
+ /* write address bytes */
+ while (alen--) {
+ /* compute address byte + stop for the last one */
+ int a = (addr >> (8 * alen)) & 0xff;
+ if (!alen)
+ a |= LPC32XX_I2C_TX_STOP;
+ /* Send address byte */
+ writel(a, &i2c->tx);
+ }
+ /* wait for end of transation */
+ while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
+ ;
+ /* clear end-of-transaction flag */
+ writel(1, &i2c->stat);
+ }
+ /* do we have to read data at all? */
+ if (length) {
+ /* Address slave in read mode */
+ writel(1 | (dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
+ wlen = length;
+ /* get data */
+ while (length | wlen) {
+ /* read status for TFF and RFE */
+ stat = readl(&i2c->stat);
+ /* must we, can we write a trigger byte? */
+ if ((wlen > 0)
+ & (!(stat & LPC32XX_I2C_STAT_TFF))) {
+ wlen--;
+ /* write trigger byte + stop if last */
+ writel(wlen ? 0 :
+ LPC32XX_I2C_TX_STOP, &i2c->tx);
+ }
+ /* must we, can we read a data byte? */
+ if ((length > 0)
+ & (!(stat & LPC32XX_I2C_STAT_RFE))) {
+ length--;
+ /* read byte */
+ *(data++) = readl(&i2c->rx);
+ }
+ }
+ }
+ /* wait for end of transation */
+ while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
+ ;
+ /* clear end-of-transaction flag */
+ writel(1, &i2c->stat);
+ /* success */
+ return 0;
+}
+
+/*
+ * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
+ * Begin write, send address byte(s), send data bytes, end.
+ */
+static int lpc32xx_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
+ int alen, u8 *data, int length)
+{
+ struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
+ int stat;
+
+ /* Soft-reset the controller */
+ writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
+ while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
+ ;
+ /* do we need to write anything at all? */
+ if (alen | length)
+ /* Address slave in write mode */
+ writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
+ /* write address bytes */
+ while (alen) {
+ /* wait for transmit fifo not full */
+ stat = readl(&i2c->stat);
+ if (!(stat & LPC32XX_I2C_STAT_TFF)) {
+ alen--;
+ int a = (addr >> (8 * alen)) & 0xff;
+ if (!(alen | length))
+ a |= LPC32XX_I2C_TX_STOP;
+ /* Send address byte */
+ writel(a, &i2c->tx);
+ }
+ }
+ while (length) {
+ /* wait for transmit fifo not full */
+ stat = readl(&i2c->stat);
+ if (!(stat & LPC32XX_I2C_STAT_TFF)) {
+ /* compute data byte, add stop if length==0 */
+ length--;
+ int d = *(data++);
+ if (!length)
+ d |= LPC32XX_I2C_TX_STOP;
+ /* Send data byte */
+ writel(d, &i2c->tx);
+ }
+ }
+ /* wait for end of transation */
+ while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
+ ;
+ /* clear end-of-transaction flag */
+ writel(1, &i2c->stat);
+ return 0;
+}
+
+U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_0, _i2c_init, lpc32xx_i2c_probe,
+ lpc32xx_i2c_read, lpc32xx_i2c_write,
+ lpc32xx_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_LPC32XX_SPEED,
+ CONFIG_SYS_I2C_LPC32XX_SLAVE,
+ 0)
+
+U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_1, _i2c_init, lpc32xx_i2c_probe,
+ lpc32xx_i2c_read, lpc32xx_i2c_write,
+ lpc32xx_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_LPC32XX_SPEED,
+ CONFIG_SYS_I2C_LPC32XX_SLAVE,
+ 1)
diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c
index 92f7d8942f..4ec2968ece 100644
--- a/drivers/mmc/bcm2835_sdhci.c
+++ b/drivers/mmc/bcm2835_sdhci.c
@@ -39,8 +39,8 @@
#include <common.h>
#include <malloc.h>
#include <sdhci.h>
-#include <asm/arch/timer.h>
-#include <asm/arch-bcm2835/sdhci.h>
+#include <mach/timer.h>
+#include <mach/sdhci.h>
/* 400KHz is max freq for card ID etc. Use that as min */
#define MIN_FREQ 400000
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 1f02bfc35f..347ea62e0b 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
+obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o
obj-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o
obj-$(CONFIG_NAND_MXC) += mxc_nand.o
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index b16e3aa157..a2016e7945 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -1456,6 +1456,9 @@ int board_nand_init(struct nand_chip *nand)
nand->dev_ready = at91_nand_wait_ready;
#endif
nand->chip_delay = 20;
+#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
+ nand->bbt_options |= NAND_BBT_USE_FLASH;
+#endif
#ifdef CONFIG_ATMEL_NAND_HWECC
#ifdef CONFIG_ATMEL_NAND_HW_PMECC
@@ -1522,6 +1525,9 @@ int atmel_nand_chip_init(int devnum, ulong base_addr)
nand->dev_ready = at91_nand_ready;
#endif
nand->chip_delay = 75;
+#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
+ nand->bbt_options |= NAND_BBT_USE_FLASH;
+#endif
ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);
if (ret)
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 41689b5165..a3970745c9 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -405,18 +405,6 @@ static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip,
goto err;
}
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /* Send command to read back the data */
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- if (chip->verify_buf(mtd, buf, mtd->writesize)) {
- ret = -EIO;
- goto err;
- }
-
- /* Make sure the next page prog is preceded by a status read */
- chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-#endif
err:
/* restore ECC layout */
if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) {
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 3372b64212..e85832d319 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -561,41 +561,6 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
len, avail);
}
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
-/*
- * Verify buffer against the FCM Controller Data Buffer
- */
-static int fsl_elbc_verify_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
- int i;
-
- if (len < 0) {
- printf("write_buf of %d bytes", len);
- return -EINVAL;
- }
-
- if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
- printf("verify_buf beyond end of buffer "
- "(%d requested, %u available)\n",
- len, ctrl->read_bytes - ctrl->index);
-
- ctrl->index = ctrl->read_bytes;
- return -EINVAL;
- }
-
- for (i = 0; i < len; i++)
- if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
- break;
-
- ctrl->index += len;
- return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
-}
-#endif
-
/* This function is called after Program and Erase Operations to
* check for success or failure.
*/
@@ -727,9 +692,6 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
nand->read_byte = fsl_elbc_read_byte;
nand->write_buf = fsl_elbc_write_buf;
nand->read_buf = fsl_elbc_read_buf;
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- nand->verify_buf = fsl_elbc_verify_buf;
-#endif
nand->select_chip = fsl_elbc_select_chip;
nand->cmdfunc = fsl_elbc_cmdfunc;
nand->waitfunc = fsl_elbc_wait;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index b283eaea34..7903eebd53 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -683,41 +683,6 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
__func__, len, avail);
}
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
-/*
- * Verify buffer against the IFC Controller Data Buffer
- */
-static int fsl_ifc_verify_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
- struct fsl_ifc_ctrl *ctrl = priv->ctrl;
- int i;
-
- if (len < 0) {
- printf("%s of %d bytes", __func__, len);
- return -EINVAL;
- }
-
- if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
- printf("%s beyond end of buffer "
- "(%d requested, %u available)\n",
- __func__, len, ctrl->read_bytes - ctrl->index);
-
- ctrl->index = ctrl->read_bytes;
- return -EINVAL;
- }
-
- for (i = 0; i < len; i++)
- if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
- break;
-
- ctrl->index += len;
- return i == len && ctrl->status == IFC_NAND_EVTER_STAT_OPC ? 0 : -EIO;
-}
-#endif
-
/* This function is called after Program and Erase Operations to
* check for success or failure.
*/
@@ -940,9 +905,6 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
nand->write_buf = fsl_ifc_write_buf;
nand->read_buf = fsl_ifc_read_buf;
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- nand->verify_buf = fsl_ifc_verify_buf;
-#endif
nand->select_chip = fsl_ifc_select_chip;
nand->cmdfunc = fsl_ifc_cmdfunc;
nand->waitfunc = fsl_ifc_wait;
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index 65ce98ad5e..5426c32114 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -153,21 +153,6 @@ static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
buf[i] = in_8(chip->IO_ADDR_R);
}
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
-static int upm_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
- struct nand_chip *chip = mtd->priv;
-
- for (i = 0; i < len; i++) {
- if (buf[i] != in_8(chip->IO_ADDR_R))
- return -EFAULT;
- }
-
- return 0;
-}
-#endif
-
static int nand_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
@@ -193,9 +178,6 @@ int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun)
chip->read_byte = upm_nand_read_byte;
chip->read_buf = upm_nand_read_buf;
chip->write_buf = upm_nand_write_buf;
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- chip->verify_buf = upm_nand_verify_buf;
-#endif
if (fun->dev_ready)
chip->dev_ready = nand_dev_ready;
diff --git a/drivers/mtd/nand/lpc32xx_nand_mlc.c b/drivers/mtd/nand/lpc32xx_nand_mlc.c
new file mode 100644
index 0000000000..8156fe9613
--- /dev/null
+++ b/drivers/mtd/nand/lpc32xx_nand_mlc.c
@@ -0,0 +1,764 @@
+/*
+ * LPC32xx MLC NAND flash controller driver
+ *
+ * (C) Copyright 2014 3ADEV <http://3adev.com>
+ * Written by Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * NOTE:
+ *
+ * The MLC NAND flash controller provides hardware Reed-Solomon ECC
+ * covering in- and out-of-band data together. Therefore, in- and out-
+ * of-band data must be written together in order to have a valid ECC.
+ *
+ * Consequently, pages with meaningful in-band data are written with
+ * blank (all-ones) out-of-band data and a valid ECC, and any later
+ * out-of-band data write will void the ECC.
+ *
+ * Therefore, code which reads such late-written out-of-band data
+ * should not rely on the ECC validity.
+ */
+
+#include <common.h>
+#include <nand.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <nand.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/sys_proto.h>
+
+/*
+ * MLC NAND controller registers.
+ */
+struct lpc32xx_nand_mlc_registers {
+ u8 buff[32768]; /* controller's serial data buffer */
+ u8 data[32768]; /* NAND's raw data buffer */
+ u32 cmd;
+ u32 addr;
+ u32 ecc_enc_reg;
+ u32 ecc_dec_reg;
+ u32 ecc_auto_enc_reg;
+ u32 ecc_auto_dec_reg;
+ u32 rpr;
+ u32 wpr;
+ u32 rubp;
+ u32 robp;
+ u32 sw_wp_add_low;
+ u32 sw_wp_add_hig;
+ u32 icr;
+ u32 time_reg;
+ u32 irq_mr;
+ u32 irq_sr;
+ u32 lock_pr;
+ u32 isr;
+ u32 ceh;
+};
+
+/* LOCK_PR register defines */
+#define LOCK_PR_UNLOCK_KEY 0x0000A25E /* Magic unlock value */
+
+/* ICR defines */
+#define ICR_LARGE_BLOCKS 0x00000004 /* configure for 2KB blocks */
+#define ICR_ADDR4 0x00000002 /* configure for 4-word addrs */
+
+/* CEH defines */
+#define CEH_NORMAL_CE 0x00000001 /* do not force CE ON */
+
+/* ISR register defines */
+#define ISR_NAND_READY 0x00000001
+#define ISR_CONTROLLER_READY 0x00000002
+#define ISR_ECC_READY 0x00000004
+#define ISR_DECODER_ERRORS(s) ((((s) >> 4) & 3)+1)
+#define ISR_DECODER_FAILURE 0x00000040
+#define ISR_DECODER_ERROR 0x00000008
+
+/* time-out for NAND chip / controller loops, in us */
+#define LPC32X_NAND_TIMEOUT 5000
+
+/*
+ * There is a single instance of the NAND MLC controller
+ */
+
+static struct lpc32xx_nand_mlc_registers __iomem *lpc32xx_nand_mlc_registers
+ = (struct lpc32xx_nand_mlc_registers __iomem *)MLC_NAND_BASE;
+
+#define clkdiv(v, w, o) (((1+(clk/v)) & w) << o)
+
+/**
+ * OOB data in each small page are 6 'free' then 10 ECC bytes.
+ * To make things easier, when reading large pages, the four pages'
+ * 'free' OOB bytes are grouped in the first 24 bytes of the OOB buffer,
+ * while the the four ECC bytes are groupe in its last 40 bytes.
+ *
+ * The struct below represents how free vs ecc oob bytes are stored
+ * in the buffer.
+ *
+ * Note: the OOB bytes contain the bad block marker at offsets 0 and 1.
+ */
+
+struct lpc32xx_oob {
+ struct {
+ uint8_t free_oob_bytes[6];
+ } free[4];
+ struct {
+ uint8_t ecc_oob_bytes[10];
+ } ecc[4];
+};
+
+/*
+ * Initialize the controller
+ */
+
+static void lpc32xx_nand_init(void)
+{
+ unsigned int clk;
+
+ /* Configure controller for no software write protection, x8 bus
+ width, large block device, and 4 address words */
+
+ /* unlock controller registers with magic key */
+ writel(LOCK_PR_UNLOCK_KEY,
+ &lpc32xx_nand_mlc_registers->lock_pr);
+
+ /* enable large blocks and large NANDs */
+ writel(ICR_LARGE_BLOCKS | ICR_ADDR4,
+ &lpc32xx_nand_mlc_registers->icr);
+
+ /* Make sure MLC interrupts are disabled */
+ writel(0, &lpc32xx_nand_mlc_registers->irq_mr);
+
+ /* Normal chip enable operation */
+ writel(CEH_NORMAL_CE,
+ &lpc32xx_nand_mlc_registers->ceh);
+
+ /* Setup NAND timing */
+ clk = get_hclk_clk_rate();
+
+ writel(
+ clkdiv(CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY, 0x03, 24) |
+ clkdiv(CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY, 0x1F, 19) |
+ clkdiv(CONFIG_LPC32XX_NAND_MLC_NAND_TA, 0x07, 16) |
+ clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_HIGH, 0x0F, 12) |
+ clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_LOW, 0x0F, 8) |
+ clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_HIGH, 0x0F, 4) |
+ clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_LOW, 0x0F, 0),
+ &lpc32xx_nand_mlc_registers->time_reg);
+}
+
+#if !defined(CONFIG_SPL_BUILD)
+
+/**
+ * lpc32xx_cmd_ctrl - write command to either cmd or data register
+ */
+
+static void lpc32xx_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_CLE)
+ writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->cmd);
+ else if (ctrl & NAND_ALE)
+ writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->addr);
+}
+
+/**
+ * lpc32xx_read_byte - read a byte from the NAND
+ * @mtd: MTD device structure
+ */
+
+static uint8_t lpc32xx_read_byte(struct mtd_info *mtd)
+{
+ return readb(&lpc32xx_nand_mlc_registers->data);
+}
+
+/**
+ * lpc32xx_dev_ready - test if NAND device (actually controller) is ready
+ * @mtd: MTD device structure
+ * @mode: mode to set the ECC HW to.
+ */
+
+static int lpc32xx_dev_ready(struct mtd_info *mtd)
+{
+ /* means *controller* ready for us */
+ int status = readl(&lpc32xx_nand_mlc_registers->isr);
+ return status & ISR_CONTROLLER_READY;
+}
+
+/**
+ * ECC layout -- this is needed whatever ECC mode we are using.
+ * In a 2KB (4*512B) page, R/S codes occupy 40 (4*10) bytes.
+ * To make U-Boot's life easier, we pack 'useable' OOB at the
+ * front and R/S ECC at the back.
+ */
+
+static struct nand_ecclayout lpc32xx_largepage_ecclayout = {
+ .eccbytes = 40,
+ .eccpos = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 48, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ },
+ .oobfree = {
+ /* bytes 0 and 1 are used for the bad block marker */
+ {
+ .offset = 2,
+ .length = 22
+ },
+ }
+};
+
+/**
+ * lpc32xx_read_page_hwecc - read in- and out-of-band data with ECC
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Use large block Auto Decode Read Mode(1) as described in User Manual
+ * section 8.6.2.1.
+ *
+ * The initial Read Mode and Read Start commands are sent by the caller.
+ *
+ * ECC will be false if out-of-band data has been updated since in-band
+ * data was initially written.
+ */
+
+static int lpc32xx_read_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int oob_required,
+ int page)
+{
+ unsigned int i, status, timeout, err, max_bitflips = 0;
+ struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+ /* go through all four small pages */
+ for (i = 0; i < 4; i++) {
+ /* start auto decode (reads 528 NAND bytes) */
+ writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+ /* wait for controller to return to ready state */
+ for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+ status = readl(&lpc32xx_nand_mlc_registers->isr);
+ if (status & ISR_CONTROLLER_READY)
+ break;
+ udelay(1);
+ }
+ /* if decoder failed, return failure */
+ if (status & ISR_DECODER_FAILURE)
+ return -1;
+ /* keep count of maximum bitflips performed */
+ if (status & ISR_DECODER_ERROR) {
+ err = ISR_DECODER_ERRORS(status);
+ if (err > max_bitflips)
+ max_bitflips = err;
+ }
+ /* copy first 512 bytes into buffer */
+ memcpy(buf+512*i, lpc32xx_nand_mlc_registers->buff, 512);
+ /* copy next 6 bytes at front of OOB buffer */
+ memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+ /* copy last 10 bytes (R/S ECC) at back of OOB buffer */
+ memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10);
+ }
+ return max_bitflips;
+}
+
+/**
+ * lpc32xx_read_page_raw - read raw (in-band, out-of-band and ECC) data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Read NAND directly; can read pages with invalid ECC.
+ */
+
+static int lpc32xx_read_page_raw(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int oob_required,
+ int page)
+{
+ unsigned int i, status, timeout;
+ struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+ /* when we get here we've already had the Read Mode(1) */
+
+ /* go through all four small pages */
+ for (i = 0; i < 4; i++) {
+ /* wait for NAND to return to ready state */
+ for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+ status = readl(&lpc32xx_nand_mlc_registers->isr);
+ if (status & ISR_NAND_READY)
+ break;
+ udelay(1);
+ }
+ /* if NAND stalled, return failure */
+ if (!(status & ISR_NAND_READY))
+ return -1;
+ /* copy first 512 bytes into buffer */
+ memcpy(buf+512*i, lpc32xx_nand_mlc_registers->data, 512);
+ /* copy next 6 bytes at front of OOB buffer */
+ memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->data, 6);
+ /* copy last 10 bytes (R/S ECC) at back of OOB buffer */
+ memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->data, 10);
+ }
+ return 0;
+}
+
+/**
+ * lpc32xx_read_oob - read out-of-band data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ *
+ * Read out-of-band data. User Manual section 8.6.4 suggests using Read
+ * Mode(3) which the controller will turn into a Read Mode(1) internally
+ * but nand_base.c will turn Mode(3) into Mode(0), so let's use Mode(0)
+ * directly.
+ *
+ * ECC covers in- and out-of-band data and was written when out-of-band
+ * data was blank. Therefore, if the out-of-band being read here is not
+ * blank, then the ECC will be false and the read will return bitflips,
+ * even in case of ECC failure where we will return 5 bitflips. The
+ * caller should be prepared to handle this.
+ */
+
+static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ unsigned int i, status, timeout, err, max_bitflips = 0;
+ struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+ /* No command was sent before calling read_oob() so send one */
+
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+ /* go through all four small pages */
+ for (i = 0; i < 4; i++) {
+ /* start auto decode (reads 528 NAND bytes) */
+ writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+ /* wait for controller to return to ready state */
+ for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+ status = readl(&lpc32xx_nand_mlc_registers->isr);
+ if (status & ISR_CONTROLLER_READY)
+ break;
+ udelay(1);
+ }
+ /* if decoder failure, count 'one too many' bitflips */
+ if (status & ISR_DECODER_FAILURE)
+ max_bitflips = 5;
+ /* keep count of maximum bitflips performed */
+ if (status & ISR_DECODER_ERROR) {
+ err = ISR_DECODER_ERRORS(status);
+ if (err > max_bitflips)
+ max_bitflips = err;
+ }
+ /* set read pointer to OOB area */
+ writel(0, &lpc32xx_nand_mlc_registers->robp);
+ /* copy next 6 bytes at front of OOB buffer */
+ memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+ /* copy next 10 bytes (R/S ECC) at back of OOB buffer */
+ memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10);
+ }
+ return max_bitflips;
+}
+
+/**
+ * lpc32xx_write_page_hwecc - write in- and out-of-band data with ECC
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ *
+ * Use large block Auto Encode as per User Manual section 8.6.4.
+ *
+ * The initial Write Serial Input and final Auto Program commands are
+ * sent by the caller.
+ */
+
+static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+ unsigned int i, status, timeout;
+ struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+ /* when we get here we've already had the SEQIN */
+ for (i = 0; i < 4; i++) {
+ /* start encode (expects 518 writes to buff) */
+ writel(0, &lpc32xx_nand_mlc_registers->ecc_enc_reg);
+ /* copy first 512 bytes from buffer */
+ memcpy(&lpc32xx_nand_mlc_registers->buff, buf+512*i, 512);
+ /* copy next 6 bytes from OOB buffer -- excluding ECC */
+ memcpy(&lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6);
+ /* wait for ECC to return to ready state */
+ for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+ status = readl(&lpc32xx_nand_mlc_registers->isr);
+ if (status & ISR_ECC_READY)
+ break;
+ udelay(1);
+ }
+ /* if ECC stalled, return failure */
+ if (!(status & ISR_ECC_READY))
+ return -1;
+ /* Trigger auto encode (writes 528 bytes to NAND) */
+ writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_enc_reg);
+ /* wait for controller to return to ready state */
+ for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+ status = readl(&lpc32xx_nand_mlc_registers->isr);
+ if (status & ISR_CONTROLLER_READY)
+ break;
+ udelay(1);
+ }
+ /* if controller stalled, return error */
+ if (!(status & ISR_CONTROLLER_READY))
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * lpc32xx_write_page_raw - write raw (in-band, out-of-band and ECC) data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Use large block write but without encode.
+ *
+ * The initial Write Serial Input and final Auto Program commands are
+ * sent by the caller.
+ *
+ * This function will write the full out-of-band data, including the
+ * ECC area. Therefore, it can write pages with valid *or* invalid ECC.
+ */
+
+static int lpc32xx_write_page_raw(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+ unsigned int i;
+ struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+ /* when we get here we've already had the Read Mode(1) */
+ for (i = 0; i < 4; i++) {
+ /* copy first 512 bytes from buffer */
+ memcpy(lpc32xx_nand_mlc_registers->buff, buf+512*i, 512);
+ /* copy next 6 bytes into OOB buffer -- excluding ECC */
+ memcpy(lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6);
+ /* copy next 10 bytes into OOB buffer -- that is 'ECC' */
+ memcpy(lpc32xx_nand_mlc_registers->buff, &oob->ecc[i], 10);
+ }
+ return 0;
+}
+
+/**
+ * lpc32xx_write_oob - write out-of-band data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ *
+ * Since ECC covers in- and out-of-band data, writing out-of-band data
+ * with ECC will render the page ECC wrong -- or, if the page was blank,
+ * then it will produce a good ECC but a later in-band data write will
+ * render it wrong.
+ *
+ * Therefore, do not compute or write any ECC, and always return success.
+ *
+ * This implies that we do four writes, since non-ECC out-of-band data
+ * are not contiguous in a large page.
+ */
+
+static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ /* update oob on all 4 subpages in sequence */
+ unsigned int i, status, timeout;
+ struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+ for (i = 0; i < 4; i++) {
+ /* start data input */
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x200+0x210*i, page);
+ /* copy 6 non-ECC out-of-band bytes directly into NAND */
+ memcpy(lpc32xx_nand_mlc_registers->data, &oob->free[i], 6);
+ /* program page */
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ /* wait for NAND to return to ready state */
+ for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+ status = readl(&lpc32xx_nand_mlc_registers->isr);
+ if (status & ISR_NAND_READY)
+ break;
+ udelay(1);
+ }
+ /* if NAND stalled, return error */
+ if (!(status & ISR_NAND_READY))
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * lpc32xx_waitfunc - wait until a command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
+ *
+ * Wait for controller and FLASH to both be ready.
+ */
+
+static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ int status;
+ unsigned int timeout;
+ /* wait until both controller and NAND are ready */
+ for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+ status = readl(&lpc32xx_nand_mlc_registers->isr);
+ if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY))
+ == (ISR_CONTROLLER_READY || ISR_NAND_READY))
+ break;
+ udelay(1);
+ }
+ /* if controller or NAND stalled, return error */
+ if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY))
+ != (ISR_CONTROLLER_READY || ISR_NAND_READY))
+ return -1;
+ /* write NAND status command */
+ writel(NAND_CMD_STATUS, &lpc32xx_nand_mlc_registers->cmd);
+ /* read back status and return it */
+ return readb(&lpc32xx_nand_mlc_registers->data);
+}
+
+/*
+ * We are self-initializing, so we need our own chip struct
+ */
+
+static struct nand_chip lpc32xx_chip;
+
+/*
+ * Initialize the controller
+ */
+
+void board_nand_init(void)
+{
+ /* we have only one device anyway */
+ struct mtd_info *mtd = &nand_info[0];
+ /* chip is struct nand_chip, and is now provided by the driver. */
+ mtd->priv = &lpc32xx_chip;
+ /* to store return status in case we need to print it */
+ int ret;
+
+ /* Set all BOARDSPECIFIC (actually core-specific) fields */
+
+ lpc32xx_chip.IO_ADDR_R = &lpc32xx_nand_mlc_registers->buff;
+ lpc32xx_chip.IO_ADDR_W = &lpc32xx_nand_mlc_registers->buff;
+ lpc32xx_chip.cmd_ctrl = lpc32xx_cmd_ctrl;
+ /* do not set init_size: nand_base.c will read sizes from chip */
+ lpc32xx_chip.dev_ready = lpc32xx_dev_ready;
+ /* do not set setup_read_retry: this is NAND-chip-specific */
+ /* do not set chip_delay: we have dev_ready defined. */
+ lpc32xx_chip.options |= NAND_NO_SUBPAGE_WRITE;
+
+ /* Set needed ECC fields */
+
+ lpc32xx_chip.ecc.mode = NAND_ECC_HW;
+ lpc32xx_chip.ecc.layout = &lpc32xx_largepage_ecclayout;
+ lpc32xx_chip.ecc.size = 512;
+ lpc32xx_chip.ecc.bytes = 10;
+ lpc32xx_chip.ecc.strength = 4;
+ lpc32xx_chip.ecc.read_page = lpc32xx_read_page_hwecc;
+ lpc32xx_chip.ecc.read_page_raw = lpc32xx_read_page_raw;
+ lpc32xx_chip.ecc.write_page = lpc32xx_write_page_hwecc;
+ lpc32xx_chip.ecc.write_page_raw = lpc32xx_write_page_raw;
+ lpc32xx_chip.ecc.read_oob = lpc32xx_read_oob;
+ lpc32xx_chip.ecc.write_oob = lpc32xx_write_oob;
+ lpc32xx_chip.waitfunc = lpc32xx_waitfunc;
+
+ lpc32xx_chip.read_byte = lpc32xx_read_byte; /* FIXME: NEEDED? */
+
+ /* BBT options: read from last two pages */
+ lpc32xx_chip.bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_LASTBLOCK
+ | NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE
+ | NAND_BBT_WRITE;
+
+ /* Initialize NAND interface */
+ lpc32xx_nand_init();
+
+ /* identify chip */
+ ret = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL);
+ if (ret) {
+ error("nand_scan_ident returned %i", ret);
+ return;
+ }
+
+ /* finish scanning the chip */
+ ret = nand_scan_tail(mtd);
+ if (ret) {
+ error("nand_scan_tail returned %i", ret);
+ return;
+ }
+
+ /* chip is good, register it */
+ ret = nand_register(0);
+ if (ret)
+ error("nand_register returned %i", ret);
+}
+
+#else /* defined(CONFIG_SPL_BUILD) */
+
+void nand_init(void)
+{
+ /* enable NAND controller */
+ lpc32xx_mlc_nand_init();
+ /* initialize NAND controller */
+ lpc32xx_nand_init();
+}
+
+void nand_deselect(void)
+{
+ /* nothing to do, but SPL requires this function */
+}
+
+static int read_single_page(uint8_t *dest, int page,
+ struct lpc32xx_oob *oob)
+{
+ int status, i, timeout, err, max_bitflips = 0;
+
+ /* enter read mode */
+ writel(NAND_CMD_READ0, &lpc32xx_nand_mlc_registers->cmd);
+ /* send column (lsb then MSB) and page (lsb to MSB) */
+ writel(0, &lpc32xx_nand_mlc_registers->addr);
+ writel(0, &lpc32xx_nand_mlc_registers->addr);
+ writel(page & 0xff, &lpc32xx_nand_mlc_registers->addr);
+ writel((page>>8) & 0xff, &lpc32xx_nand_mlc_registers->addr);
+ writel((page>>16) & 0xff, &lpc32xx_nand_mlc_registers->addr);
+ /* start reading */
+ writel(NAND_CMD_READSTART, &lpc32xx_nand_mlc_registers->cmd);
+
+ /* large page auto decode read */
+ for (i = 0; i < 4; i++) {
+ /* start auto decode (reads 528 NAND bytes) */
+ writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+ /* wait for controller to return to ready state */
+ for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+ status = readl(&lpc32xx_nand_mlc_registers->isr);
+ if (status & ISR_CONTROLLER_READY)
+ break;
+ udelay(1);
+ }
+ /* if controller stalled, return error */
+ if (!(status & ISR_CONTROLLER_READY))
+ return -1;
+ /* if decoder failure, return error */
+ if (status & ISR_DECODER_FAILURE)
+ return -1;
+ /* keep count of maximum bitflips performed */
+ if (status & ISR_DECODER_ERROR) {
+ err = ISR_DECODER_ERRORS(status);
+ if (err > max_bitflips)
+ max_bitflips = err;
+ }
+ /* copy first 512 bytes into buffer */
+ memcpy(dest+i*512, lpc32xx_nand_mlc_registers->buff, 512);
+ /* copy next 6 bytes bytes into OOB buffer */
+ memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+ }
+ return max_bitflips;
+}
+
+/*
+ * Load U-Boot signed image.
+ * This loads an image from NAND, skipping bad blocks.
+ * A block is declared bad if at least one of its readable pages has
+ * a bad block marker in its OOB at position 0.
+ * If all pages ion a block are unreadable, the block is considered
+ * bad (i.e., assumed not to be part of the image) and skipped.
+ *
+ * IMPORTANT NOTE:
+ *
+ * If the first block of the image is fully unreadable, it will be
+ * ignored and skipped as if it had been marked bad. If it was not
+ * actually marked bad at the time of writing the image, the resulting
+ * image loaded will lack a header and magic number. It could thus be
+ * considered as a raw, headerless, image and SPL might erroneously
+ * jump into it.
+ *
+ * In order to avoid this risk, LPC32XX-based boards which use this
+ * driver MUST define CONFIG_SPL_PANIC_ON_RAW_IMAGE.
+ */
+
+#define BYTES_PER_PAGE 2048
+#define PAGES_PER_BLOCK 64
+#define BYTES_PER_BLOCK (BYTES_PER_PAGE * PAGES_PER_BLOCK)
+#define PAGES_PER_CHIP_MAX 524288
+
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+ int bytes_left = size;
+ int pages_left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
+ int blocks_left = DIV_ROUND_UP(size, BYTES_PER_BLOCK);
+ int block = 0;
+ int page = offs / BYTES_PER_PAGE;
+ /* perform reads block by block */
+ while (blocks_left) {
+ /* compute first page number to read */
+ void *block_page_dst = dst;
+ /* read at most one block, possibly less */
+ int block_bytes_left = bytes_left;
+ if (block_bytes_left > BYTES_PER_BLOCK)
+ block_bytes_left = BYTES_PER_BLOCK;
+ /* keep track of good, failed, and "bad" pages */
+ int block_pages_good = 0;
+ int block_pages_bad = 0;
+ int block_pages_err = 0;
+ /* we shall read a full block of pages, maybe less */
+ int block_pages_left = pages_left;
+ if (block_pages_left > PAGES_PER_BLOCK)
+ block_pages_left = PAGES_PER_BLOCK;
+ int block_pages = block_pages_left;
+ int block_page = page;
+ /* while pages are left and the block is not known as bad */
+ while ((block_pages > 0) && (block_pages_bad == 0)) {
+ /* we will read OOB, too, for bad block markers */
+ struct lpc32xx_oob oob;
+ /* read page */
+ int res = read_single_page(block_page_dst, block_page,
+ &oob);
+ /* count readable pages */
+ if (res >= 0) {
+ /* this page is good */
+ block_pages_good++;
+ /* this page is bad */
+ if ((oob.free[0].free_oob_bytes[0] != 0xff)
+ | (oob.free[0].free_oob_bytes[1] != 0xff))
+ block_pages_bad++;
+ } else
+ /* count errors */
+ block_pages_err++;
+ /* we're done with this page */
+ block_page++;
+ block_page_dst += BYTES_PER_PAGE;
+ if (block_pages)
+ block_pages--;
+ }
+ /* a fully unreadable block is considered bad */
+ if (block_pages_good == 0)
+ block_pages_bad = block_pages_err;
+ /* errors are fatal only in good blocks */
+ if ((block_pages_err > 0) && (block_pages_bad == 0))
+ return -1;
+ /* we keep reads only of good blocks */
+ if (block_pages_bad == 0) {
+ dst += block_bytes_left;
+ bytes_left -= block_bytes_left;
+ pages_left -= block_pages_left;
+ blocks_left--;
+ }
+ /* good or bad, we're done with this block */
+ block++;
+ page += PAGES_PER_BLOCK;
+ }
+
+ /* report success */
+ return 0;
+}
+
+#endif /* CONFIG_SPL_BUILD */
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 7233bfc127..e621c3665e 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -459,29 +459,6 @@ static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
mpc5121_nfc_buf_copy(mtd, (u_char *) buf, len, 1);
}
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
-/* Compare buffer with NAND flash */
-static int mpc5121_nfc_verify_buf(struct mtd_info *mtd,
- const u_char * buf, int len)
-{
- u_char tmp[256];
- uint bsize;
-
- while (len) {
- bsize = min(len, 256);
- mpc5121_nfc_read_buf(mtd, tmp, bsize);
-
- if (memcmp(buf, tmp, bsize))
- return 1;
-
- buf += bsize;
- len -= bsize;
- }
-
- return 0;
-}
-#endif
-
/* Read byte from NFC buffers */
static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
{
@@ -609,9 +586,6 @@ int board_nand_init(struct nand_chip *chip)
chip->read_word = mpc5121_nfc_read_word;
chip->read_buf = mpc5121_nfc_read_buf;
chip->write_buf = mpc5121_nfc_write_buf;
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- chip->verify_buf = mpc5121_nfc_verify_buf;
-#endif
chip->select_chip = mpc5121_nfc_select_chip;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->ecc.mode = NAND_ECC_SOFT;
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 2e5b5b9bf9..f12b07e7ad 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -949,34 +949,6 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
host->col_addr = col;
}
-#ifdef __UBOOT__
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
-/*
- * Used by the upper layer to verify the data in NAND Flash
- * with the data in the buf.
- */
-static int mxc_nand_verify_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
-{
- u_char tmp[256];
- uint bsize;
-
- while (len) {
- bsize = min(len, 256);
- mxc_nand_read_buf(mtd, tmp, bsize);
-
- if (memcmp(buf, tmp, bsize))
- return 1;
-
- buf += bsize;
- len -= bsize;
- }
-
- return 0;
-}
-#endif
-#endif
-
/*
* This function is used by upper layer for select and
* deselect of the NAND chip
@@ -1207,11 +1179,6 @@ int board_nand_init(struct nand_chip *this)
this->read_word = mxc_nand_read_word;
this->write_buf = mxc_nand_write_buf;
this->read_buf = mxc_nand_read_buf;
-#ifdef __UBOOT__
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- this->verify_buf = mxc_nand_verify_buf;
-#endif
-#endif
host->regs = (struct mxc_nand_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE;
#ifdef MXC_NFC_V3_2
diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c
index 7a064ab1bf..2d2b938633 100644
--- a/drivers/mtd/nand/mxs_nand.c
+++ b/drivers/mtd/nand/mxs_nand.c
@@ -453,7 +453,7 @@ static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length)
d->cmd.data =
MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ |
MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_DEC_SEM |
- MXS_DMA_DESC_WAIT4END | (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET);
+ MXS_DMA_DESC_WAIT4END | (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET);
d->cmd.address = 0;
@@ -510,7 +510,7 @@ static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
d->cmd.data =
MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ |
MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END |
- (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
+ (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
(length << MXS_DMA_DESC_BYTES_OFFSET);
d->cmd.address = (dma_addr_t)nand_info->data_buf;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 6db6566e73..c0e381ad2d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -361,51 +361,6 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
ioread8_rep(chip->IO_ADDR_R, buf, len);
}
-#ifdef __UBOOT__
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
-/**
- * nand_verify_buf - [DEFAULT] Verify chip data against buffer
- * @mtd: MTD device structure
- * @buf: buffer containing the data to compare
- * @len: number of bytes to compare
- *
- * Default verify function for 8bit buswidth.
- */
-static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *chip = mtd->priv;
-
- for (i = 0; i < len; i++)
- if (buf[i] != readb(chip->IO_ADDR_R))
- return -EFAULT;
- return 0;
-}
-
-/**
- * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
- * @mtd: MTD device structure
- * @buf: buffer containing the data to compare
- * @len: number of bytes to compare
- *
- * Default verify function for 16bit buswidth.
- */
-static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *chip = mtd->priv;
- u16 *p = (u16 *) buf;
- len >>= 1;
-
- for (i = 0; i < len; i++)
- if (p[i] != readw(chip->IO_ADDR_R))
- return -EFAULT;
-
- return 0;
-}
-#endif
-#endif
-
/**
* nand_write_buf16 - [DEFAULT] write buffer to chip
* @mtd: MTD device structure
@@ -2435,20 +2390,6 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
status = chip->waitfunc(mtd, chip);
}
-
-#ifdef __UBOOT__
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- /* Send command to read back the data */
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- if (chip->verify_buf(mtd, buf, mtd->writesize))
- return -EIO;
-
- /* Make sure the next page prog is preceded by a status read */
- chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-#endif
-#endif
-
return 0;
}
@@ -3139,12 +3080,6 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
-#ifdef __UBOOT__
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- if (!chip->verify_buf)
- chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
-#endif
-#endif
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index afdd160d81..12dd26a33f 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -464,6 +464,87 @@ static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
#endif
/**
+ * nand_verify_page_oob:
+ *
+ * Verify a page of NAND flash, including the OOB.
+ * Reads page of NAND and verifies the contents and OOB against the
+ * values in ops.
+ *
+ * @param nand NAND device
+ * @param ops MTD operations, including data to verify
+ * @param ofs offset in flash
+ * @return 0 in case of success
+ */
+int nand_verify_page_oob(nand_info_t *nand, struct mtd_oob_ops *ops, loff_t ofs)
+{
+ int rval;
+ struct mtd_oob_ops vops;
+ size_t verlen = nand->writesize + nand->oobsize;
+
+ memcpy(&vops, ops, sizeof(vops));
+
+ vops.datbuf = malloc(verlen);
+
+ if (!vops.datbuf)
+ return -ENOMEM;
+
+ vops.oobbuf = vops.datbuf + nand->writesize;
+
+ rval = mtd_read_oob(nand, ofs, &vops);
+ if (!rval)
+ rval = memcmp(ops->datbuf, vops.datbuf, vops.len);
+ if (!rval)
+ rval = memcmp(ops->oobbuf, vops.oobbuf, vops.ooblen);
+
+ free(vops.datbuf);
+
+ return rval ? -EIO : 0;
+}
+
+/**
+ * nand_verify:
+ *
+ * Verify a region of NAND flash.
+ * Reads NAND in page-sized chunks and verifies the contents against
+ * the contents of a buffer. The offset into the NAND must be
+ * page-aligned, and the function doesn't handle skipping bad blocks.
+ *
+ * @param nand NAND device
+ * @param ofs offset in flash
+ * @param len buffer length
+ * @param buf buffer to read from
+ * @return 0 in case of success
+ */
+int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf)
+{
+ int rval = 0;
+ size_t verofs;
+ size_t verlen = nand->writesize;
+ uint8_t *verbuf = malloc(verlen);
+
+ if (!verbuf)
+ return -ENOMEM;
+
+ /* Read the NAND back in page-size groups to limit malloc size */
+ for (verofs = ofs; verofs < ofs + len;
+ verofs += verlen, buf += verlen) {
+ verlen = min(nand->writesize, (uint32_t)(ofs + len - verofs));
+ rval = nand_read(nand, verofs, &verlen, verbuf);
+ if (!rval || (rval == -EUCLEAN))
+ rval = memcmp(buf, verbuf, verlen);
+
+ if (rval)
+ break;
+ }
+
+ free(verbuf);
+
+ return rval ? -EIO : 0;
+}
+
+
+
+/**
* nand_write_skip_bad:
*
* Write image to NAND flash.
@@ -499,24 +580,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
if (actual)
*actual = 0;
-#ifdef CONFIG_CMD_NAND_YAFFS
- if (flags & WITH_YAFFS_OOB) {
- if (flags & ~WITH_YAFFS_OOB)
- return -EINVAL;
-
- int pages;
- pages = nand->erasesize / nand->writesize;
- blocksize = (pages * nand->oobsize) + nand->erasesize;
- if (*length % (nand->writesize + nand->oobsize)) {
- printf("Attempt to write incomplete page"
- " in yaffs mode\n");
- return -EINVAL;
- }
- } else
-#endif
- {
- blocksize = nand->erasesize;
- }
+ blocksize = nand->erasesize;
/*
* nand_write() handles unaligned, partial page writes.
@@ -554,6 +618,10 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
if (!need_skip && !(flags & WITH_DROP_FFS)) {
rval = nand_write(nand, offset, length, buffer);
+
+ if ((flags & WITH_WR_VERIFY) && !rval)
+ rval = nand_verify(nand, offset, *length, buffer);
+
if (rval == 0)
return 0;
@@ -581,48 +649,22 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
else
write_size = blocksize - block_offset;
-#ifdef CONFIG_CMD_NAND_YAFFS
- if (flags & WITH_YAFFS_OOB) {
- int page, pages;
- size_t pagesize = nand->writesize;
- size_t pagesize_oob = pagesize + nand->oobsize;
- struct mtd_oob_ops ops;
-
- ops.len = pagesize;
- ops.ooblen = nand->oobsize;
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.ooboffs = 0;
-
- pages = write_size / pagesize_oob;
- for (page = 0; page < pages; page++) {
- WATCHDOG_RESET();
-
- ops.datbuf = p_buffer;
- ops.oobbuf = ops.datbuf + pagesize;
-
- rval = mtd_write_oob(nand, offset, &ops);
- if (rval != 0)
- break;
-
- offset += pagesize;
- p_buffer += pagesize_oob;
- }
- }
- else
-#endif
- {
- truncated_write_size = write_size;
+ truncated_write_size = write_size;
#ifdef CONFIG_CMD_NAND_TRIMFFS
- if (flags & WITH_DROP_FFS)
- truncated_write_size = drop_ffs(nand, p_buffer,
- &write_size);
+ if (flags & WITH_DROP_FFS)
+ truncated_write_size = drop_ffs(nand, p_buffer,
+ &write_size);
#endif
- rval = nand_write(nand, offset, &truncated_write_size,
- p_buffer);
- offset += write_size;
- p_buffer += write_size;
- }
+ rval = nand_write(nand, offset, &truncated_write_size,
+ p_buffer);
+
+ if ((flags & WITH_WR_VERIFY) && !rval)
+ rval = nand_verify(nand, offset,
+ truncated_write_size, p_buffer);
+
+ offset += write_size;
+ p_buffer += write_size;
if (rval != 0) {
printf("NAND write to offset %llx failed %d\n",
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 265959502d..8a68cb0a67 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -118,21 +118,6 @@ static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len
out_be32((u32 *)(base + NDFC_DATA), *p++);
}
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
-static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
-{
- struct nand_chip *this = mtdinfo->priv;
- ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
- uint32_t *p = (uint32_t *) buf;
-
- for (; len > 0; len -= 4)
- if (*p++ != in_be32((u32 *)(base + NDFC_DATA)))
- return -1;
-
- return 0;
-}
-#endif
-
/*
* Read a byte from the NDFC.
*/
@@ -207,9 +192,6 @@ int board_nand_init(struct nand_chip *nand)
#endif
nand->write_buf = ndfc_write_buf;
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- nand->verify_buf = ndfc_verify_buf;
-#endif
nand->read_byte = ndfc_read_byte;
chip++;
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 928d58b3a7..d98dd28800 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -146,6 +146,7 @@ struct vf610_nfc {
void __iomem *regs;
uint column;
int spareonly;
+ int page_sz;
int page;
/* Status and ID are in alternate locations. */
int alt_buf;
@@ -329,6 +330,11 @@ static void vf610_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
ROW_ADDR_SHIFT, page);
}
+static inline void vf610_nfc_transfer_size(void __iomem *regbase, int size)
+{
+ __raw_writel(size, regbase + NFC_SECTOR_SIZE);
+}
+
/* Send command to NAND chip */
static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
int column, int page)
@@ -342,12 +348,14 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
switch (command) {
case NAND_CMD_PAGEPROG:
nfc->page = -1;
+ vf610_nfc_transfer_size(nfc->regs, nfc->page_sz);
vf610_nfc_send_commands(nfc->regs, NAND_CMD_SEQIN,
command, PROGRAM_PAGE_CMD_CODE);
vf610_nfc_addr_cycle(mtd, column, page);
break;
case NAND_CMD_RESET:
+ vf610_nfc_transfer_size(nfc->regs, 0);
vf610_nfc_send_command(nfc->regs, command, RESET_CMD_CODE);
break;
/*
@@ -363,14 +371,15 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
if (nfc->page == page)
return;
nfc->page = page;
+ vf610_nfc_transfer_size(nfc->regs, nfc->page_sz);
vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0,
NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
vf610_nfc_addr_cycle(mtd, column, page);
break;
case NAND_CMD_ERASE1:
- if (nfc->page == page)
- nfc->page = -1;
+ nfc->page = -1;
+ vf610_nfc_transfer_size(nfc->regs, 0);
vf610_nfc_send_commands(nfc->regs, command,
NAND_CMD_ERASE2, ERASE_CMD_CODE);
vf610_nfc_addr_cycle(mtd, column, page);
@@ -378,11 +387,13 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
case NAND_CMD_READID:
nfc->alt_buf = ALT_BUF_ID;
+ vf610_nfc_transfer_size(nfc->regs, 0);
vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE);
break;
case NAND_CMD_STATUS:
nfc->alt_buf = ALT_BUF_STAT;
+ vf610_nfc_transfer_size(nfc->regs, 0);
vf610_nfc_send_command(nfc->regs, command,
STATUS_READ_CMD_CODE);
break;
@@ -580,7 +591,6 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
struct nand_chip *chip;
struct vf610_nfc *nfc;
int err = 0;
- int page_sz;
struct vf610_nfc_config cfg = {
.hardware_ecc = 1,
#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
@@ -634,9 +644,8 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
- page_sz = PAGE_2K + OOB_64;
- page_sz += cfg.width == 16 ? 1 : 0;
- vf610_nfc_write(mtd, NFC_SECTOR_SIZE, page_sz);
+ nfc->page_sz = PAGE_2K + OOB_64;
+ nfc->page_sz += cfg.width == 16 ? 1 : 0;
/* Set configuration register. */
vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
@@ -665,16 +674,15 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
chip->ecc.mode = NAND_ECC_SOFT; /* default */
- page_sz = mtd->writesize + mtd->oobsize;
+ nfc->page_sz = mtd->writesize + mtd->oobsize;
/* Single buffer only, max 256 OOB minus ECC status */
- if (page_sz > PAGE_2K + 256 - 8) {
+ if (nfc->page_sz > PAGE_2K + 256 - 8) {
dev_err(nfc->dev, "Unsupported flash size\n");
err = -ENXIO;
goto error;
}
- page_sz += cfg.width == 16 ? 1 : 0;
- vf610_nfc_write(mtd, NFC_SECTOR_SIZE, page_sz);
+ nfc->page_sz += cfg.width == 16 ? 1 : 0;
if (cfg.hardware_ecc) {
if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b8b08034eb..5a5269aa06 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_GRETH) += greth.o
obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
obj-$(CONFIG_LAN91C96) += lan91c96.o
+obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o
obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
obj-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_DRIVER_NE2000) += ne2000.o ne2000_base.o
obj-$(CONFIG_DRIVER_AX88796L) += ax88796.o ne2000_base.o
obj-$(CONFIG_NETCONSOLE) += netconsole.o
obj-$(CONFIG_NS8382X) += ns8382x.o
+obj-$(CONFIG_PCH_GBE) += pch_gbe.o
obj-$(CONFIG_PCNET) += pcnet.o
obj-$(CONFIG_RTL8139) += rtl8139.o
obj-$(CONFIG_RTL8169) += rtl8169.o
diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h
index 6d110eb5d5..f3b77b1d97 100644
--- a/drivers/net/e1000.h
+++ b/drivers/net/e1000.h
@@ -430,12 +430,11 @@ struct e1000_phy_stats {
#define ENET_HEADER_SIZE 14
#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */
#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */
-#define ETHERNET_FCS_SIZE 4
#define MAXIMUM_ETHERNET_PACKET_SIZE \
- (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+ (MAXIMUM_ETHERNET_FRAME_SIZE - ETH_FCS_LEN)
#define MINIMUM_ETHERNET_PACKET_SIZE \
- (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
-#define CRC_LENGTH ETHERNET_FCS_SIZE
+ (MINIMUM_ETHERNET_FRAME_SIZE - ETH_FCS_LEN)
+#define CRC_LENGTH ETH_FCS_LEN
#define MAX_JUMBO_FRAME_SIZE 0x3F00
/* 802.1q VLAN Packet Sizes */
diff --git a/drivers/net/lpc32xx_eth.c b/drivers/net/lpc32xx_eth.c
new file mode 100644
index 0000000000..fcadf0c77f
--- /dev/null
+++ b/drivers/net/lpc32xx_eth.c
@@ -0,0 +1,637 @@
+/*
+ * LPC32xx Ethernet MAC interface driver
+ *
+ * (C) Copyright 2014 DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/types.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/config.h>
+
+/*
+ * Notes:
+ *
+ * 1. Unless specified otherwise, all references to tables or paragraphs
+ * are to UM10326, "LPC32x0 and LPC32x0/01 User manual".
+ *
+ * 2. Only bitfield masks/values which are actually used by the driver
+ * are defined.
+ */
+
+/* a single RX descriptor. The controller has an array of these */
+struct lpc32xx_eth_rxdesc {
+ u32 packet; /* Receive packet pointer */
+ u32 control; /* Descriptor command status */
+};
+
+#define LPC32XX_ETH_RX_DESC_SIZE (sizeof(struct lpc32xx_eth_rxdesc))
+
+/* RX control bitfields/masks (see Table 330) */
+#define LPC32XX_ETH_RX_CTRL_SIZE_MASK 0x000007FF
+#define LPC32XX_ETH_RX_CTRL_UNUSED 0x7FFFF800
+#define LPC32XX_ETH_RX_CTRL_INTERRUPT 0x80000000
+
+/* a single RX status. The controller has an array of these */
+struct lpc32xx_eth_rxstat {
+ u32 statusinfo; /* Transmit Descriptor status */
+ u32 statushashcrc; /* Transmit Descriptor CRCs */
+};
+
+#define LPC32XX_ETH_RX_STAT_SIZE (sizeof(struct lpc32xx_eth_rxstat))
+
+/* RX statusinfo bitfields/masks (see Table 333) */
+#define RX_STAT_RXSIZE 0x000007FF
+/* Helper: OR of all errors except RANGE */
+#define RX_STAT_ERRORS 0x1B800000
+
+/* a single TX descriptor. The controller has an array of these */
+struct lpc32xx_eth_txdesc {
+ u32 packet; /* Transmit packet pointer */
+ u32 control; /* Descriptor control */
+};
+
+#define LPC32XX_ETH_TX_DESC_SIZE (sizeof(struct lpc32xx_eth_txdesc))
+
+/* TX control bitfields/masks (see Table 335) */
+#define TX_CTRL_TXSIZE 0x000007FF
+#define TX_CTRL_LAST 0x40000000
+
+/* a single TX status. The controller has an array of these */
+struct lpc32xx_eth_txstat {
+ u32 statusinfo; /* Transmit Descriptor status */
+};
+
+#define LPC32XX_ETH_TX_STAT_SIZE (sizeof(struct lpc32xx_eth_txstat))
+
+/* Ethernet MAC interface registers (see Table 283) */
+struct lpc32xx_eth_registers {
+ /* MAC registers - 0x3106_0000 to 0x3106_01FC */
+ u32 mac1; /* MAC configuration register 1 */
+ u32 mac2; /* MAC configuration register 2 */
+ u32 ipgt; /* Back-to-back Inter-Packet Gap reg. */
+ u32 ipgr; /* Non-back-to-back IPG register */
+ u32 clrt; /* Collision Window / Retry register */
+ u32 maxf; /* Maximum Frame register */
+ u32 supp; /* Phy Support register */
+ u32 test;
+ u32 mcfg; /* MII management configuration reg. */
+ u32 mcmd; /* MII management command register */
+ u32 madr; /* MII management address register */
+ u32 mwtd; /* MII management wite data register */
+ u32 mrdd; /* MII management read data register */
+ u32 mind; /* MII management indicators register */
+ u32 reserved1[2];
+ u32 sa0; /* Station address register 0 */
+ u32 sa1; /* Station address register 1 */
+ u32 sa2; /* Station address register 2 */
+ u32 reserved2[45];
+ /* Control registers */
+ u32 command;
+ u32 status;
+ u32 rxdescriptor;
+ u32 rxstatus;
+ u32 rxdescriptornumber; /* actually, number MINUS ONE */
+ u32 rxproduceindex; /* head of rx desc fifo */
+ u32 rxconsumeindex; /* tail of rx desc fifo */
+ u32 txdescriptor;
+ u32 txstatus;
+ u32 txdescriptornumber; /* actually, number MINUS ONE */
+ u32 txproduceindex; /* head of rx desc fifo */
+ u32 txconsumeindex; /* tail of rx desc fifo */
+ u32 reserved3[10];
+ u32 tsv0; /* Transmit status vector register 0 */
+ u32 tsv1; /* Transmit status vector register 1 */
+ u32 rsv; /* Receive status vector register */
+ u32 reserved4[3];
+ u32 flowcontrolcounter;
+ u32 flowcontrolstatus;
+ u32 reserved5[34];
+ /* RX filter registers - 0x3106_0200 to 0x3106_0FDC */
+ u32 rxfilterctrl;
+ u32 rxfilterwolstatus;
+ u32 rxfilterwolclear;
+ u32 reserved6;
+ u32 hashfilterl;
+ u32 hashfilterh;
+ u32 reserved7[882];
+ /* Module control registers - 0x3106_0FE0 to 0x3106_0FF8 */
+ u32 intstatus; /* Interrupt status register */
+ u32 intenable;
+ u32 intclear;
+ u32 intset;
+ u32 reserved8;
+ u32 powerdown;
+ u32 reserved9;
+};
+
+/* MAC1 register bitfields/masks and offsets (see Table 283) */
+#define MAC1_RECV_ENABLE 0x00000001
+#define MAC1_PASS_ALL_RX_FRAMES 0x00000002
+#define MAC1_SOFT_RESET 0x00008000
+/* Helper: general reset */
+#define MAC1_RESETS 0x0000CF00
+
+/* MAC2 register bitfields/masks and offsets (see Table 284) */
+#define MAC2_FULL_DUPLEX 0x00000001
+#define MAC2_CRC_ENABLE 0x00000010
+#define MAC2_PAD_CRC_ENABLE 0x00000020
+
+/* SUPP register bitfields/masks and offsets (see Table 290) */
+#define SUPP_SPEED 0x00000100
+
+/* MCFG register bitfields/masks and offsets (see Table 292) */
+#define MCFG_CLOCK_SELECT_MASK 0x0000001C
+/* divide clock by 28 (see Table 293) */
+#define MCFG_CLOCK_SELECT_DIV28 0x0000001C
+
+/* MADR register bitfields/masks and offsets (see Table 295) */
+#define MADR_REG_MASK 0x0000001F
+#define MADR_PHY_MASK 0x00001F00
+#define MADR_REG_OFFSET 0
+#define MADR_PHY_OFFSET 8
+
+/* MIND register bitfields/masks (see Table 298) */
+#define MIND_BUSY 0x00000001
+
+/* COMMAND register bitfields/masks and offsets (see Table 283) */
+#define COMMAND_RXENABLE 0x00000001
+#define COMMAND_TXENABLE 0x00000002
+#define COMMAND_PASSRUNTFRAME 0x00000040
+#define COMMAND_FULL_DUPLEX 0x00000400
+/* Helper: general reset */
+#define COMMAND_RESETS 0x0000001C
+
+/* STATUS register bitfields/masks and offsets (see Table 283) */
+#define STATUS_RXSTATUS 0x00000001
+#define STATUS_TXSTATUS 0x00000002
+
+/* RXFILTERCTRL register bitfields/masks (see Table 319) */
+#define RXFILTERCTRL_ACCEPTBROADCAST 0x00000002
+#define RXFILTERCTRL_ACCEPTPERFECT 0x00000020
+
+/* Buffers and descriptors */
+
+#define ATTRS(n) __aligned(n)
+
+#define TX_BUF_COUNT 4
+#define RX_BUF_COUNT 4
+
+struct lpc32xx_eth_buffers {
+ ATTRS(4) struct lpc32xx_eth_txdesc tx_desc[TX_BUF_COUNT];
+ ATTRS(4) struct lpc32xx_eth_txstat tx_stat[TX_BUF_COUNT];
+ ATTRS(PKTALIGN) u8 tx_buf[TX_BUF_COUNT*PKTSIZE_ALIGN];
+ ATTRS(4) struct lpc32xx_eth_rxdesc rx_desc[RX_BUF_COUNT];
+ ATTRS(8) struct lpc32xx_eth_rxstat rx_stat[RX_BUF_COUNT];
+ ATTRS(PKTALIGN) u8 rx_buf[RX_BUF_COUNT*PKTSIZE_ALIGN];
+};
+
+/* port device data struct */
+struct lpc32xx_eth_device {
+ struct eth_device dev;
+ struct lpc32xx_eth_registers *regs;
+ struct lpc32xx_eth_buffers *bufs;
+};
+
+#define LPC32XX_ETH_DEVICE_SIZE (sizeof(struct lpc32xx_eth_device))
+
+/* generic macros */
+#define to_lpc32xx_eth(_d) container_of(_d, struct lpc32xx_eth_device, dev)
+
+/* timeout for MII polling */
+#define MII_TIMEOUT 10000000
+
+/* limits for PHY and register addresses */
+#define MII_MAX_REG (MADR_REG_MASK >> MADR_REG_OFFSET)
+
+#define MII_MAX_PHY (MADR_PHY_MASK >> MADR_PHY_OFFSET)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+/*
+ * mii_reg_read - miiphy_read callback function.
+ *
+ * Returns 16bit phy register value, or 0xffff on error
+ */
+static int mii_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 *data)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev);
+ struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs;
+ u32 mind_reg;
+ u32 timeout;
+
+ /* check parameters */
+ if (phy_adr > MII_MAX_PHY) {
+ printf("%s:%u: Invalid PHY address %d\n",
+ __func__, __LINE__, phy_adr);
+ return -EFAULT;
+ }
+ if (reg_ofs > MII_MAX_REG) {
+ printf("%s:%u: Invalid register offset %d\n",
+ __func__, __LINE__, reg_ofs);
+ return -EFAULT;
+ }
+
+ /* write the phy and reg addressse into the MII address reg */
+ writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET),
+ &regs->madr);
+
+ /* write 1 to the MII command register to cause a read */
+ writel(1, &regs->mcmd);
+
+ /* wait till the MII is not busy */
+ timeout = MII_TIMEOUT;
+ do {
+ /* read MII indicators register */
+ mind_reg = readl(&regs->mind);
+ if (--timeout == 0)
+ break;
+ } while (mind_reg & MIND_BUSY);
+
+ /* write 0 to the MII command register to finish the read */
+ writel(0, &regs->mcmd);
+
+ if (timeout == 0) {
+ printf("%s:%u: MII busy timeout\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ *data = (u16) readl(&regs->mrdd);
+
+ debug("%s:(adr %d, off %d) => %04x\n", __func__, phy_adr,
+ reg_ofs, *data);
+
+ return 0;
+}
+
+/*
+ * mii_reg_write - imiiphy_write callback function.
+ *
+ * Returns 0 if write succeed, -EINVAL on bad parameters
+ * -ETIME on timeout
+ */
+static int mii_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev);
+ struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs;
+ u32 mind_reg;
+ u32 timeout;
+
+ /* check parameters */
+ if (phy_adr > MII_MAX_PHY) {
+ printf("%s:%u: Invalid PHY address %d\n",
+ __func__, __LINE__, phy_adr);
+ return -EFAULT;
+ }
+ if (reg_ofs > MII_MAX_REG) {
+ printf("%s:%u: Invalid register offset %d\n",
+ __func__, __LINE__, reg_ofs);
+ return -EFAULT;
+ }
+
+ /* wait till the MII is not busy */
+ timeout = MII_TIMEOUT;
+ do {
+ /* read MII indicators register */
+ mind_reg = readl(&regs->mind);
+ if (--timeout == 0)
+ break;
+ } while (mind_reg & MIND_BUSY);
+
+ if (timeout == 0) {
+ printf("%s:%u: MII busy timeout\n", __func__,
+ __LINE__);
+ return -EFAULT;
+ }
+
+ /* write the phy and reg addressse into the MII address reg */
+ writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET),
+ &regs->madr);
+
+ /* write data to the MII write register */
+ writel(data, &regs->mwtd);
+
+ /*debug("%s:(adr %d, off %d) <= %04x\n", __func__, phy_adr,
+ reg_ofs, data);*/
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_PHYLIB)
+int lpc32xx_eth_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr)
+{
+ u16 data;
+ int ret;
+ ret = mii_reg_read(bus->name, phy_addr, reg_addr, &data);
+ if (ret)
+ return ret;
+ return data;
+}
+
+int lpc32xx_eth_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr, u16 data)
+{
+ return mii_reg_write(bus->name, phy_addr, reg_addr, data);
+}
+#endif
+
+/*
+ * Locate buffers in SRAM at 0x00001000 to avoid cache issues and
+ * maximize throughput.
+ */
+
+#define LPC32XX_ETH_BUFS 0x00001000
+
+static struct lpc32xx_eth_device lpc32xx_eth = {
+ .regs = (struct lpc32xx_eth_registers *)LPC32XX_ETH_BASE,
+ .bufs = (struct lpc32xx_eth_buffers *)LPC32XX_ETH_BUFS
+};
+
+#define TX_TIMEOUT 10000
+
+static int lpc32xx_eth_send(struct eth_device *dev, void *dataptr, int datasize)
+{
+ struct lpc32xx_eth_device *lpc32xx_eth_device =
+ container_of(dev, struct lpc32xx_eth_device, dev);
+ struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+ struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs;
+ int timeout, tx_index;
+
+ /* time out if transmit descriptor array remains full too long */
+ timeout = TX_TIMEOUT;
+ while ((readl(&regs->status) & STATUS_TXSTATUS) &&
+ (readl(&regs->txconsumeindex)
+ == readl(&regs->txproduceindex))) {
+ if (timeout-- == 0)
+ return -1;
+ }
+
+ /* determine next transmit packet index to use */
+ tx_index = readl(&regs->txproduceindex);
+
+ /* set up transmit packet */
+ writel((u32)dataptr, &bufs->tx_desc[tx_index].packet);
+ writel(TX_CTRL_LAST | ((datasize - 1) & TX_CTRL_TXSIZE),
+ &bufs->tx_desc[tx_index].control);
+ writel(0, &bufs->tx_stat[tx_index].statusinfo);
+
+ /* pass transmit packet to DMA engine */
+ tx_index = (tx_index + 1) % TX_BUF_COUNT;
+ writel(tx_index, &regs->txproduceindex);
+
+ /* transmission succeeded */
+ return 0;
+}
+
+#define RX_TIMEOUT 1000000
+
+static int lpc32xx_eth_recv(struct eth_device *dev)
+{
+ struct lpc32xx_eth_device *lpc32xx_eth_device =
+ container_of(dev, struct lpc32xx_eth_device, dev);
+ struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+ struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs;
+ int timeout, rx_index;
+
+ /* time out if receive descriptor array remains empty too long */
+ timeout = RX_TIMEOUT;
+ while (readl(&regs->rxproduceindex) == readl(&regs->rxconsumeindex)) {
+ if (timeout-- == 0)
+ return -1;
+ }
+
+ /* determine next receive packet index to use */
+ rx_index = readl(&regs->rxconsumeindex);
+
+ /* if data was valid, pass it on */
+ if (!(bufs->rx_stat[rx_index].statusinfo & RX_STAT_ERRORS))
+ NetReceive(&(bufs->rx_buf[rx_index*PKTSIZE_ALIGN]),
+ (bufs->rx_stat[rx_index].statusinfo
+ & RX_STAT_RXSIZE) + 1);
+
+ /* pass receive slot back to DMA engine */
+ rx_index = (rx_index + 1) % RX_BUF_COUNT;
+ writel(rx_index, &regs->rxconsumeindex);
+
+ /* reception successful */
+ return 0;
+}
+
+static int lpc32xx_eth_write_hwaddr(struct eth_device *dev)
+{
+ struct lpc32xx_eth_device *lpc32xx_eth_device =
+ container_of(dev, struct lpc32xx_eth_device, dev);
+ struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+
+ /* Save station address */
+ writel((unsigned long) (dev->enetaddr[0] |
+ (dev->enetaddr[1] << 8)), &regs->sa2);
+ writel((unsigned long) (dev->enetaddr[2] |
+ (dev->enetaddr[3] << 8)), &regs->sa1);
+ writel((unsigned long) (dev->enetaddr[4] |
+ (dev->enetaddr[5] << 8)), &regs->sa0);
+
+ return 0;
+}
+
+static int lpc32xx_eth_init(struct eth_device *dev)
+{
+ struct lpc32xx_eth_device *lpc32xx_eth_device =
+ container_of(dev, struct lpc32xx_eth_device, dev);
+ struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+ struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs;
+ int index;
+
+ /* Release SOFT reset to let MII talk to PHY */
+ clrbits_le32(&regs->mac1, MAC1_SOFT_RESET);
+
+ /* Configure Full/Half Duplex mode */
+ if (miiphy_duplex(dev->name, CONFIG_PHY_ADDR) == FULL) {
+ setbits_le32(&regs->mac2, MAC2_FULL_DUPLEX);
+ setbits_le32(&regs->command, COMMAND_FULL_DUPLEX);
+ writel(0x15, &regs->ipgt);
+ } else {
+ writel(0x12, &regs->ipgt);
+ }
+
+ /* Configure 100MBit/10MBit mode */
+ if (miiphy_speed(dev->name, CONFIG_PHY_ADDR) == _100BASET)
+ writel(SUPP_SPEED, &regs->supp);
+ else
+ writel(0, &regs->supp);
+
+ /* Initial MAC initialization */
+ writel(MAC1_PASS_ALL_RX_FRAMES, &regs->mac1);
+ writel(MAC2_PAD_CRC_ENABLE | MAC2_CRC_ENABLE, &regs->mac2);
+ writel(PKTSIZE_ALIGN, &regs->maxf);
+
+ /* Retries: 15 (0xF). Collision window: 57 (0x37). */
+ writel(0x370F, &regs->clrt);
+
+ /* Set IP gap pt 2 to default 0x12 but pt 1 to non-default 0 */
+ writel(0x0012, &regs->ipgr);
+
+ /* pass runt (smaller than 64 bytes) frames */
+ writel(COMMAND_PASSRUNTFRAME, &regs->command);
+
+ /* Save station address */
+ writel((unsigned long) (dev->enetaddr[0] |
+ (dev->enetaddr[1] << 8)), &regs->sa2);
+ writel((unsigned long) (dev->enetaddr[2] |
+ (dev->enetaddr[3] << 8)), &regs->sa1);
+ writel((unsigned long) (dev->enetaddr[4] |
+ (dev->enetaddr[5] << 8)), &regs->sa0);
+
+ /* set up transmit buffers */
+ for (index = 0; index < TX_BUF_COUNT; index++) {
+ bufs->tx_desc[index].control = 0;
+ bufs->tx_stat[index].statusinfo = 0;
+ }
+ writel((u32)(&bufs->tx_desc), (u32 *)&regs->txdescriptor);
+ writel((u32)(&bufs->tx_stat), &regs->txstatus);
+ writel(TX_BUF_COUNT-1, &regs->txdescriptornumber);
+
+ /* set up receive buffers */
+ for (index = 0; index < RX_BUF_COUNT; index++) {
+ bufs->rx_desc[index].packet =
+ (u32) (bufs->rx_buf+index*PKTSIZE_ALIGN);
+ bufs->rx_desc[index].control = PKTSIZE_ALIGN - 1;
+ bufs->rx_stat[index].statusinfo = 0;
+ bufs->rx_stat[index].statushashcrc = 0;
+ }
+ writel((u32)(&bufs->rx_desc), &regs->rxdescriptor);
+ writel((u32)(&bufs->rx_stat), &regs->rxstatus);
+ writel(RX_BUF_COUNT-1, &regs->rxdescriptornumber);
+
+ /* Enable broadcast and matching address packets */
+ writel(RXFILTERCTRL_ACCEPTBROADCAST |
+ RXFILTERCTRL_ACCEPTPERFECT, &regs->rxfilterctrl);
+
+ /* Clear and disable interrupts */
+ writel(0xFFFF, &regs->intclear);
+ writel(0, &regs->intenable);
+
+ /* Enable receive and transmit mode of MAC ethernet core */
+ setbits_le32(&regs->command, COMMAND_RXENABLE | COMMAND_TXENABLE);
+ setbits_le32(&regs->mac1, MAC1_RECV_ENABLE);
+
+ /*
+ * Perform a 'dummy' first send to work around Ethernet.1
+ * erratum (see ES_LPC3250 rev. 9 dated 1 June 2011).
+ * Use zeroed "index" variable as the dummy.
+ */
+
+ index = 0;
+ lpc32xx_eth_send(dev, &index, 4);
+
+ return 0;
+}
+
+static int lpc32xx_eth_halt(struct eth_device *dev)
+{
+ struct lpc32xx_eth_device *lpc32xx_eth_device =
+ container_of(dev, struct lpc32xx_eth_device, dev);
+ struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+
+ /* Reset all MAC logic */
+ writel(MAC1_RESETS, &regs->mac1);
+ writel(COMMAND_RESETS, &regs->command);
+ /* Let reset condition settle */
+ udelay(2000);
+
+ return 0;
+}
+
+#if defined(CONFIG_PHYLIB)
+int lpc32xx_eth_phylib_init(struct eth_device *dev, int phyid)
+{
+ struct mii_dev *bus;
+ struct phy_device *phydev;
+ int ret;
+
+ bus = mdio_alloc();
+ if (!bus) {
+ printf("mdio_alloc failed\n");
+ return -ENOMEM;
+ }
+ bus->read = lpc32xx_eth_phy_read;
+ bus->write = lpc32xx_eth_phy_write;
+ sprintf(bus->name, dev->name);
+
+ ret = mdio_register(bus);
+ if (ret) {
+ printf("mdio_register failed\n");
+ free(bus);
+ return -ENOMEM;
+ }
+
+ phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_MII);
+ if (!phydev) {
+ printf("phy_connect failed\n");
+ return -ENODEV;
+ }
+
+ phy_config(phydev);
+ phy_startup(phydev);
+
+ return 0;
+}
+#endif
+
+int lpc32xx_eth_initialize(bd_t *bis)
+{
+ struct eth_device *dev = &lpc32xx_eth.dev;
+ struct lpc32xx_eth_registers *regs = lpc32xx_eth.regs;
+
+ /*
+ * Set RMII management clock rate. With HCLK at 104 MHz and
+ * a divider of 28, this will be 3.72 MHz.
+ */
+
+ writel(MCFG_CLOCK_SELECT_DIV28, &regs->mcfg);
+
+ /* Reset all MAC logic */
+ writel(MAC1_RESETS, &regs->mac1);
+ writel(COMMAND_RESETS, &regs->command);
+
+ /* wait 10 ms for the whole I/F to reset */
+ udelay(10000);
+
+ /* must be less than sizeof(dev->name) */
+ strcpy(dev->name, "eth0");
+
+ dev->init = (void *)lpc32xx_eth_init;
+ dev->halt = (void *)lpc32xx_eth_halt;
+ dev->send = (void *)lpc32xx_eth_send;
+ dev->recv = (void *)lpc32xx_eth_recv;
+ dev->write_hwaddr = (void *)lpc32xx_eth_write_hwaddr;
+
+ /* Release SOFT reset to let MII talk to PHY */
+ clrbits_le32(&regs->mac1, MAC1_SOFT_RESET);
+
+ /* register driver before talking to phy */
+ eth_register(dev);
+
+#if defined(CONFIG_PHYLIB)
+ lpc32xx_eth_phylib_init(dev, 0);
+#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name, mii_reg_read, mii_reg_write);
+#endif
+
+ return 0;
+}
diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c
new file mode 100644
index 0000000000..976848df4d
--- /dev/null
+++ b/drivers/net/pch_gbe.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Intel Platform Controller Hub EG20T (codename Topcliff) GMAC Driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include "pch_gbe.h"
+
+#if !defined(CONFIG_PHYLIB)
+# error "PCH Gigabit Ethernet driver requires PHYLIB - missing CONFIG_PHYLIB"
+#endif
+
+static struct pci_device_id supported[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_GBE },
+ { }
+};
+
+static void pch_gbe_mac_read(struct pch_gbe_regs *mac_regs, u8 *addr)
+{
+ u32 macid_hi, macid_lo;
+
+ macid_hi = readl(&mac_regs->mac_adr[0].high);
+ macid_lo = readl(&mac_regs->mac_adr[0].low) & 0xffff;
+ debug("pch_gbe: macid_hi %#x macid_lo %#x\n", macid_hi, macid_lo);
+
+ addr[0] = (u8)(macid_hi & 0xff);
+ addr[1] = (u8)((macid_hi >> 8) & 0xff);
+ addr[2] = (u8)((macid_hi >> 16) & 0xff);
+ addr[3] = (u8)((macid_hi >> 24) & 0xff);
+ addr[4] = (u8)(macid_lo & 0xff);
+ addr[5] = (u8)((macid_lo >> 8) & 0xff);
+}
+
+static int pch_gbe_mac_write(struct pch_gbe_regs *mac_regs, u8 *addr)
+{
+ u32 macid_hi, macid_lo;
+ ulong start;
+
+ macid_hi = addr[0] + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
+ macid_lo = addr[4] + (addr[5] << 8);
+
+ writel(macid_hi, &mac_regs->mac_adr[0].high);
+ writel(macid_lo, &mac_regs->mac_adr[0].low);
+ writel(0xfffe, &mac_regs->addr_mask);
+
+ start = get_timer(0);
+ while (get_timer(start) < PCH_GBE_TIMEOUT) {
+ if (!(readl(&mac_regs->addr_mask) & PCH_GBE_BUSY))
+ return 0;
+
+ udelay(10);
+ }
+
+ return -ETIME;
+}
+
+static int pch_gbe_reset(struct eth_device *dev)
+{
+ struct pch_gbe_priv *priv = dev->priv;
+ struct pch_gbe_regs *mac_regs = priv->mac_regs;
+ ulong start;
+
+ priv->rx_idx = 0;
+ priv->tx_idx = 0;
+
+ writel(PCH_GBE_ALL_RST, &mac_regs->reset);
+
+ /*
+ * Configure the MAC to RGMII mode after reset
+ *
+ * For some unknown reason, we must do the configuration here right
+ * after resetting the whole MAC, otherwise the reset bit in the RESET
+ * register will never be cleared by the hardware. And there is another
+ * way of having the same magic, that is to configure the MODE register
+ * to have the MAC work in MII/GMII mode, which is how current Linux
+ * pch_gbe driver does. Since anyway we need program the MAC to RGMII
+ * mode in the driver, we just do it here.
+ *
+ * Note: this behavior is not documented in the hardware manual.
+ */
+ writel(PCH_GBE_RGMII_MODE_RGMII | PCH_GBE_CHIP_TYPE_INTERNAL,
+ &mac_regs->rgmii_ctrl);
+
+ start = get_timer(0);
+ while (get_timer(start) < PCH_GBE_TIMEOUT) {
+ if (!(readl(&mac_regs->reset) & PCH_GBE_ALL_RST)) {
+ /*
+ * Soft reset clears hardware MAC address registers,
+ * so we have to reload MAC address here in order to
+ * make linux pch_gbe driver happy.
+ */
+ return pch_gbe_mac_write(mac_regs, dev->enetaddr);
+ }
+
+ udelay(10);
+ }
+
+ debug("pch_gbe: reset timeout\n");
+ return -ETIME;
+}
+
+static void pch_gbe_rx_descs_init(struct eth_device *dev)
+{
+ struct pch_gbe_priv *priv = dev->priv;
+ struct pch_gbe_regs *mac_regs = priv->mac_regs;
+ struct pch_gbe_rx_desc *rx_desc = &priv->rx_desc[0];
+ int i;
+
+ memset(rx_desc, 0, sizeof(struct pch_gbe_rx_desc) * PCH_GBE_DESC_NUM);
+ for (i = 0; i < PCH_GBE_DESC_NUM; i++)
+ rx_desc->buffer_addr = pci_phys_to_mem(priv->bdf,
+ (u32)(priv->rx_buff[i]));
+
+ writel(pci_phys_to_mem(priv->bdf, (u32)rx_desc),
+ &mac_regs->rx_dsc_base);
+ writel(sizeof(struct pch_gbe_rx_desc) * (PCH_GBE_DESC_NUM - 1),
+ &mac_regs->rx_dsc_size);
+
+ writel(pci_phys_to_mem(priv->bdf, (u32)(rx_desc + 1)),
+ &mac_regs->rx_dsc_sw_p);
+}
+
+static void pch_gbe_tx_descs_init(struct eth_device *dev)
+{
+ struct pch_gbe_priv *priv = dev->priv;
+ struct pch_gbe_regs *mac_regs = priv->mac_regs;
+ struct pch_gbe_tx_desc *tx_desc = &priv->tx_desc[0];
+
+ memset(tx_desc, 0, sizeof(struct pch_gbe_tx_desc) * PCH_GBE_DESC_NUM);
+
+ writel(pci_phys_to_mem(priv->bdf, (u32)tx_desc),
+ &mac_regs->tx_dsc_base);
+ writel(sizeof(struct pch_gbe_tx_desc) * (PCH_GBE_DESC_NUM - 1),
+ &mac_regs->tx_dsc_size);
+ writel(pci_phys_to_mem(priv->bdf, (u32)(tx_desc + 1)),
+ &mac_regs->tx_dsc_sw_p);
+}
+
+static void pch_gbe_adjust_link(struct pch_gbe_regs *mac_regs,
+ struct phy_device *phydev)
+{
+ if (!phydev->link) {
+ printf("%s: No link.\n", phydev->dev->name);
+ return;
+ }
+
+ clrbits_le32(&mac_regs->rgmii_ctrl,
+ PCH_GBE_RGMII_RATE_2_5M | PCH_GBE_CRS_SEL);
+ clrbits_le32(&mac_regs->mode,
+ PCH_GBE_MODE_GMII_ETHER | PCH_GBE_MODE_FULL_DUPLEX);
+
+ switch (phydev->speed) {
+ case 1000:
+ setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_125M);
+ setbits_le32(&mac_regs->mode, PCH_GBE_MODE_GMII_ETHER);
+ break;
+ case 100:
+ setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_25M);
+ setbits_le32(&mac_regs->mode, PCH_GBE_MODE_MII_ETHER);
+ break;
+ case 10:
+ setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_2_5M);
+ setbits_le32(&mac_regs->mode, PCH_GBE_MODE_MII_ETHER);
+ break;
+ }
+
+ if (phydev->duplex) {
+ setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_CRS_SEL);
+ setbits_le32(&mac_regs->mode, PCH_GBE_MODE_FULL_DUPLEX);
+ }
+
+ printf("Speed: %d, %s duplex\n", phydev->speed,
+ (phydev->duplex) ? "full" : "half");
+
+ return;
+}
+
+static int pch_gbe_init(struct eth_device *dev, bd_t *bis)
+{
+ struct pch_gbe_priv *priv = dev->priv;
+ struct pch_gbe_regs *mac_regs = priv->mac_regs;
+
+ if (pch_gbe_reset(dev))
+ return -1;
+
+ pch_gbe_rx_descs_init(dev);
+ pch_gbe_tx_descs_init(dev);
+
+ /* Enable frame bursting */
+ writel(PCH_GBE_MODE_FR_BST, &mac_regs->mode);
+ /* Disable TCP/IP accelerator */
+ writel(PCH_GBE_RX_TCPIPACC_OFF, &mac_regs->tcpip_acc);
+ /* Disable RX flow control */
+ writel(0, &mac_regs->rx_fctrl);
+ /* Configure RX/TX mode */
+ writel(PCH_GBE_RH_ALM_EMP_16 | PCH_GBE_RH_ALM_FULL_16 |
+ PCH_GBE_RH_RD_TRG_32, &mac_regs->rx_mode);
+ writel(PCH_GBE_TM_TH_TX_STRT_32 | PCH_GBE_TM_TH_ALM_EMP_16 |
+ PCH_GBE_TM_TH_ALM_FULL_32 | PCH_GBE_TM_ST_AND_FD |
+ PCH_GBE_TM_SHORT_PKT, &mac_regs->tx_mode);
+
+ /* Start up the PHY */
+ if (phy_startup(priv->phydev)) {
+ printf("Could not initialize PHY %s\n",
+ priv->phydev->dev->name);
+ return -1;
+ }
+
+ pch_gbe_adjust_link(mac_regs, priv->phydev);
+
+ if (!priv->phydev->link)
+ return -1;
+
+ /* Enable TX & RX */
+ writel(PCH_GBE_RX_DMA_EN | PCH_GBE_TX_DMA_EN, &mac_regs->dma_ctrl);
+ writel(PCH_GBE_MRE_MAC_RX_EN, &mac_regs->mac_rx_en);
+
+ return 0;
+}
+
+static void pch_gbe_halt(struct eth_device *dev)
+{
+ struct pch_gbe_priv *priv = dev->priv;
+
+ pch_gbe_reset(dev);
+
+ phy_shutdown(priv->phydev);
+}
+
+static int pch_gbe_send(struct eth_device *dev, void *packet, int length)
+{
+ struct pch_gbe_priv *priv = dev->priv;
+ struct pch_gbe_regs *mac_regs = priv->mac_regs;
+ struct pch_gbe_tx_desc *tx_head, *tx_desc;
+ u16 frame_ctrl = 0;
+ u32 int_st;
+ ulong start;
+
+ tx_head = &priv->tx_desc[0];
+ tx_desc = &priv->tx_desc[priv->tx_idx];
+
+ if (length < 64)
+ frame_ctrl |= PCH_GBE_TXD_CTRL_APAD;
+
+ tx_desc->buffer_addr = pci_phys_to_mem(priv->bdf, (u32)packet);
+ tx_desc->length = length;
+ tx_desc->tx_words_eob = length + 3;
+ tx_desc->tx_frame_ctrl = frame_ctrl;
+ tx_desc->dma_status = 0;
+ tx_desc->gbec_status = 0;
+
+ /* Test the wrap-around condition */
+ if (++priv->tx_idx >= PCH_GBE_DESC_NUM)
+ priv->tx_idx = 0;
+
+ writel(pci_phys_to_mem(priv->bdf, (u32)(tx_head + priv->tx_idx)),
+ &mac_regs->tx_dsc_sw_p);
+
+ start = get_timer(0);
+ while (get_timer(start) < PCH_GBE_TIMEOUT) {
+ int_st = readl(&mac_regs->int_st);
+ if (int_st & PCH_GBE_INT_TX_CMPLT)
+ return 0;
+
+ udelay(10);
+ }
+
+ debug("pch_gbe: sent failed\n");
+ return -ETIME;
+}
+
+static int pch_gbe_recv(struct eth_device *dev)
+{
+ struct pch_gbe_priv *priv = dev->priv;
+ struct pch_gbe_regs *mac_regs = priv->mac_regs;
+ struct pch_gbe_rx_desc *rx_head, *rx_desc;
+ u32 hw_desc, buffer_addr, length;
+ int rx_swp;
+
+ rx_head = &priv->rx_desc[0];
+ rx_desc = &priv->rx_desc[priv->rx_idx];
+
+ readl(&mac_regs->int_st);
+ hw_desc = readl(&mac_regs->rx_dsc_hw_p_hld);
+
+ /* Just return if not receiving any packet */
+ if ((u32)rx_desc == hw_desc)
+ return 0;
+
+ buffer_addr = pci_mem_to_phys(priv->bdf, rx_desc->buffer_addr);
+ length = rx_desc->rx_words_eob - 3 - ETH_FCS_LEN;
+ NetReceive((uchar *)buffer_addr, length);
+
+ /* Test the wrap-around condition */
+ if (++priv->rx_idx >= PCH_GBE_DESC_NUM)
+ priv->rx_idx = 0;
+ rx_swp = priv->rx_idx;
+ if (++rx_swp >= PCH_GBE_DESC_NUM)
+ rx_swp = 0;
+
+ writel(pci_phys_to_mem(priv->bdf, (u32)(rx_head + rx_swp)),
+ &mac_regs->rx_dsc_sw_p);
+
+ return length;
+}
+
+static int pch_gbe_mdio_ready(struct pch_gbe_regs *mac_regs)
+{
+ ulong start = get_timer(0);
+
+ while (get_timer(start) < PCH_GBE_TIMEOUT) {
+ if (readl(&mac_regs->miim) & PCH_GBE_MIIM_OPER_READY)
+ return 0;
+
+ udelay(10);
+ }
+
+ return -ETIME;
+}
+
+static int pch_gbe_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct pch_gbe_regs *mac_regs = bus->priv;
+ u32 miim;
+
+ if (pch_gbe_mdio_ready(mac_regs))
+ return -ETIME;
+
+ miim = (addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) |
+ (reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) |
+ PCH_GBE_MIIM_OPER_READ;
+ writel(miim, &mac_regs->miim);
+
+ if (pch_gbe_mdio_ready(mac_regs))
+ return -ETIME;
+
+ return readl(&mac_regs->miim) & 0xffff;
+}
+
+static int pch_gbe_mdio_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 val)
+{
+ struct pch_gbe_regs *mac_regs = bus->priv;
+ u32 miim;
+
+ if (pch_gbe_mdio_ready(mac_regs))
+ return -ETIME;
+
+ miim = (addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) |
+ (reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) |
+ PCH_GBE_MIIM_OPER_WRITE | val;
+ writel(miim, &mac_regs->miim);
+
+ if (pch_gbe_mdio_ready(mac_regs))
+ return -ETIME;
+ else
+ return 0;
+}
+
+static int pch_gbe_mdio_init(char *name, struct pch_gbe_regs *mac_regs)
+{
+ struct mii_dev *bus;
+
+ bus = mdio_alloc();
+ if (!bus) {
+ debug("pch_gbe: failed to allocate MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ bus->read = pch_gbe_mdio_read;
+ bus->write = pch_gbe_mdio_write;
+ sprintf(bus->name, name);
+
+ bus->priv = (void *)mac_regs;
+
+ return mdio_register(bus);
+}
+
+static int pch_gbe_phy_init(struct eth_device *dev)
+{
+ struct pch_gbe_priv *priv = dev->priv;
+ struct phy_device *phydev;
+ int mask = 0xffffffff;
+
+ phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
+ if (!phydev) {
+ printf("pch_gbe: cannot find the phy\n");
+ return -1;
+ }
+
+ phy_connect_dev(phydev, dev);
+
+ phydev->supported &= PHY_GBIT_FEATURES;
+ phydev->advertising = phydev->supported;
+
+ priv->phydev = phydev;
+ phy_config(phydev);
+
+ return 1;
+}
+
+int pch_gbe_register(bd_t *bis)
+{
+ struct eth_device *dev;
+ struct pch_gbe_priv *priv;
+ pci_dev_t devno;
+ u32 iobase;
+
+ devno = pci_find_devices(supported, 0);
+ if (devno == -1)
+ return -ENODEV;
+
+ dev = (struct eth_device *)malloc(sizeof(*dev));
+ if (!dev)
+ return -ENOMEM;
+ memset(dev, 0, sizeof(*dev));
+
+ /*
+ * The priv structure contains the descriptors and frame buffers which
+ * need a strict buswidth alignment (64 bytes)
+ */
+ priv = (struct pch_gbe_priv *)memalign(PCH_GBE_ALIGN_SIZE,
+ sizeof(*priv));
+ if (!priv) {
+ free(dev);
+ return -ENOMEM;
+ }
+ memset(priv, 0, sizeof(*priv));
+
+ dev->priv = priv;
+ priv->dev = dev;
+ priv->bdf = devno;
+
+ pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+ iobase &= PCI_BASE_ADDRESS_MEM_MASK;
+ iobase = pci_mem_to_phys(devno, iobase);
+
+ dev->iobase = iobase;
+ priv->mac_regs = (struct pch_gbe_regs *)iobase;
+
+ sprintf(dev->name, "pch_gbe.%x", iobase);
+
+ /* Read MAC address from SROM and initialize dev->enetaddr with it */
+ pch_gbe_mac_read(priv->mac_regs, dev->enetaddr);
+
+ dev->init = pch_gbe_init;
+ dev->halt = pch_gbe_halt;
+ dev->send = pch_gbe_send;
+ dev->recv = pch_gbe_recv;
+
+ eth_register(dev);
+
+ priv->interface = PHY_INTERFACE_MODE_RGMII;
+ pch_gbe_mdio_init(dev->name, priv->mac_regs);
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+
+ return pch_gbe_phy_init(dev);
+}
diff --git a/drivers/net/pch_gbe.h b/drivers/net/pch_gbe.h
new file mode 100644
index 0000000000..11329d4834
--- /dev/null
+++ b/drivers/net/pch_gbe.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Intel Platform Controller Hub EG20T (codename Topcliff) GMAC Driver
+ * Adapted from linux drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _PCH_GBE_H_
+#define _PCH_GBE_H_
+
+#define PCH_GBE_TIMEOUT (3 * CONFIG_SYS_HZ)
+
+#define PCH_GBE_DESC_NUM 4
+#define PCH_GBE_ALIGN_SIZE 64
+
+/*
+ * Topcliff GBE MAC supports receiving ethernet frames with normal frame size
+ * (64-1518 bytes) as well as up to 10318 bytes, however it does not have a
+ * register bit to turn off receiving 'jumbo frame', so we have to allocate
+ * our own buffer to store the received frames instead of using U-Boot's own.
+ */
+#define PCH_GBE_RX_FRAME_LEN ROUND(10318, PCH_GBE_ALIGN_SIZE)
+
+/* Interrupt Status */
+/* Interrupt Status Hold */
+/* Interrupt Enable */
+#define PCH_GBE_INT_RX_DMA_CMPLT 0x00000001
+#define PCH_GBE_INT_RX_VALID 0x00000002
+#define PCH_GBE_INT_RX_FRAME_ERR 0x00000004
+#define PCH_GBE_INT_RX_FIFO_ERR 0x00000008
+#define PCH_GBE_INT_RX_DMA_ERR 0x00000010
+#define PCH_GBE_INT_RX_DSC_EMP 0x00000020
+#define PCH_GBE_INT_TX_CMPLT 0x00000100
+#define PCH_GBE_INT_TX_DMA_CMPLT 0x00000200
+#define PCH_GBE_INT_TX_FIFO_ERR 0x00000400
+#define PCH_GBE_INT_TX_DMA_ERR 0x00000800
+#define PCH_GBE_INT_PAUSE_CMPLT 0x00001000
+#define PCH_GBE_INT_MIIM_CMPLT 0x00010000
+#define PCH_GBE_INT_PHY_INT 0x00100000
+#define PCH_GBE_INT_WOL_DET 0x01000000
+#define PCH_GBE_INT_TCPIP_ERR 0x10000000
+
+/* Mode */
+#define PCH_GBE_MODE_MII_ETHER 0x00000000
+#define PCH_GBE_MODE_GMII_ETHER 0x80000000
+#define PCH_GBE_MODE_HALF_DUPLEX 0x00000000
+#define PCH_GBE_MODE_FULL_DUPLEX 0x40000000
+#define PCH_GBE_MODE_FR_BST 0x04000000
+
+/* Reset */
+#define PCH_GBE_ALL_RST 0x80000000
+#define PCH_GBE_TX_RST 0x00008000
+#define PCH_GBE_RX_RST 0x00004000
+
+/* TCP/IP Accelerator Control */
+#define PCH_GBE_EX_LIST_EN 0x00000008
+#define PCH_GBE_RX_TCPIPACC_OFF 0x00000004
+#define PCH_GBE_TX_TCPIPACC_EN 0x00000002
+#define PCH_GBE_RX_TCPIPACC_EN 0x00000001
+
+/* MAC RX Enable */
+#define PCH_GBE_MRE_MAC_RX_EN 0x00000001
+
+/* RX Flow Control */
+#define PCH_GBE_FL_CTRL_EN 0x80000000
+
+/* RX Mode */
+#define PCH_GBE_ADD_FIL_EN 0x80000000
+#define PCH_GBE_MLT_FIL_EN 0x40000000
+#define PCH_GBE_RH_ALM_EMP_4 0x00000000
+#define PCH_GBE_RH_ALM_EMP_8 0x00004000
+#define PCH_GBE_RH_ALM_EMP_16 0x00008000
+#define PCH_GBE_RH_ALM_EMP_32 0x0000c000
+#define PCH_GBE_RH_ALM_FULL_4 0x00000000
+#define PCH_GBE_RH_ALM_FULL_8 0x00001000
+#define PCH_GBE_RH_ALM_FULL_16 0x00002000
+#define PCH_GBE_RH_ALM_FULL_32 0x00003000
+#define PCH_GBE_RH_RD_TRG_4 0x00000000
+#define PCH_GBE_RH_RD_TRG_8 0x00000200
+#define PCH_GBE_RH_RD_TRG_16 0x00000400
+#define PCH_GBE_RH_RD_TRG_32 0x00000600
+#define PCH_GBE_RH_RD_TRG_64 0x00000800
+#define PCH_GBE_RH_RD_TRG_128 0x00000a00
+#define PCH_GBE_RH_RD_TRG_256 0x00000c00
+#define PCH_GBE_RH_RD_TRG_512 0x00000e00
+
+/* TX Mode */
+#define PCH_GBE_TM_NO_RTRY 0x80000000
+#define PCH_GBE_TM_LONG_PKT 0x40000000
+#define PCH_GBE_TM_ST_AND_FD 0x20000000
+#define PCH_GBE_TM_SHORT_PKT 0x10000000
+#define PCH_GBE_TM_LTCOL_RETX 0x08000000
+#define PCH_GBE_TM_TH_TX_STRT_4 0x00000000
+#define PCH_GBE_TM_TH_TX_STRT_8 0x00004000
+#define PCH_GBE_TM_TH_TX_STRT_16 0x00008000
+#define PCH_GBE_TM_TH_TX_STRT_32 0x0000c000
+#define PCH_GBE_TM_TH_ALM_EMP_4 0x00000000
+#define PCH_GBE_TM_TH_ALM_EMP_8 0x00000800
+#define PCH_GBE_TM_TH_ALM_EMP_16 0x00001000
+#define PCH_GBE_TM_TH_ALM_EMP_32 0x00001800
+#define PCH_GBE_TM_TH_ALM_EMP_64 0x00002000
+#define PCH_GBE_TM_TH_ALM_EMP_128 0x00002800
+#define PCH_GBE_TM_TH_ALM_EMP_256 0x00003000
+#define PCH_GBE_TM_TH_ALM_EMP_512 0x00003800
+#define PCH_GBE_TM_TH_ALM_FULL_4 0x00000000
+#define PCH_GBE_TM_TH_ALM_FULL_8 0x00000200
+#define PCH_GBE_TM_TH_ALM_FULL_16 0x00000400
+#define PCH_GBE_TM_TH_ALM_FULL_32 0x00000600
+
+/* MAC Address Mask */
+#define PCH_GBE_BUSY 0x80000000
+
+/* MIIM */
+#define PCH_GBE_MIIM_OPER_WRITE 0x04000000
+#define PCH_GBE_MIIM_OPER_READ 0x00000000
+#define PCH_GBE_MIIM_OPER_READY 0x04000000
+#define PCH_GBE_MIIM_PHY_ADDR_SHIFT 21
+#define PCH_GBE_MIIM_REG_ADDR_SHIFT 16
+
+/* RGMII Control */
+#define PCH_GBE_CRS_SEL 0x00000010
+#define PCH_GBE_RGMII_RATE_125M 0x00000000
+#define PCH_GBE_RGMII_RATE_25M 0x00000008
+#define PCH_GBE_RGMII_RATE_2_5M 0x0000000c
+#define PCH_GBE_RGMII_MODE_GMII 0x00000000
+#define PCH_GBE_RGMII_MODE_RGMII 0x00000002
+#define PCH_GBE_CHIP_TYPE_EXTERNAL 0x00000000
+#define PCH_GBE_CHIP_TYPE_INTERNAL 0x00000001
+
+/* DMA Control */
+#define PCH_GBE_RX_DMA_EN 0x00000002
+#define PCH_GBE_TX_DMA_EN 0x00000001
+
+/* Receive Descriptor bit definitions */
+#define PCH_GBE_RXD_ACC_STAT_BCAST 0x00000400
+#define PCH_GBE_RXD_ACC_STAT_MCAST 0x00000200
+#define PCH_GBE_RXD_ACC_STAT_UCAST 0x00000100
+#define PCH_GBE_RXD_ACC_STAT_TCPIPOK 0x000000c0
+#define PCH_GBE_RXD_ACC_STAT_IPOK 0x00000080
+#define PCH_GBE_RXD_ACC_STAT_TCPOK 0x00000040
+#define PCH_GBE_RXD_ACC_STAT_IP6ERR 0x00000020
+#define PCH_GBE_RXD_ACC_STAT_OFLIST 0x00000010
+#define PCH_GBE_RXD_ACC_STAT_TYPEIP 0x00000008
+#define PCH_GBE_RXD_ACC_STAT_MACL 0x00000004
+#define PCH_GBE_RXD_ACC_STAT_PPPOE 0x00000002
+#define PCH_GBE_RXD_ACC_STAT_VTAGT 0x00000001
+#define PCH_GBE_RXD_GMAC_STAT_PAUSE 0x0200
+#define PCH_GBE_RXD_GMAC_STAT_MARBR 0x0100
+#define PCH_GBE_RXD_GMAC_STAT_MARMLT 0x0080
+#define PCH_GBE_RXD_GMAC_STAT_MARIND 0x0040
+#define PCH_GBE_RXD_GMAC_STAT_MARNOTMT 0x0020
+#define PCH_GBE_RXD_GMAC_STAT_TLONG 0x0010
+#define PCH_GBE_RXD_GMAC_STAT_TSHRT 0x0008
+#define PCH_GBE_RXD_GMAC_STAT_NOTOCTAL 0x0004
+#define PCH_GBE_RXD_GMAC_STAT_NBLERR 0x0002
+#define PCH_GBE_RXD_GMAC_STAT_CRCERR 0x0001
+
+/* Transmit Descriptor bit definitions */
+#define PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF 0x0008
+#define PCH_GBE_TXD_CTRL_ITAG 0x0004
+#define PCH_GBE_TXD_CTRL_ICRC 0x0002
+#define PCH_GBE_TXD_CTRL_APAD 0x0001
+#define PCH_GBE_TXD_WORDS_SHIFT 2
+#define PCH_GBE_TXD_GMAC_STAT_CMPLT 0x2000
+#define PCH_GBE_TXD_GMAC_STAT_ABT 0x1000
+#define PCH_GBE_TXD_GMAC_STAT_EXCOL 0x0800
+#define PCH_GBE_TXD_GMAC_STAT_SNGCOL 0x0400
+#define PCH_GBE_TXD_GMAC_STAT_MLTCOL 0x0200
+#define PCH_GBE_TXD_GMAC_STAT_CRSER 0x0100
+#define PCH_GBE_TXD_GMAC_STAT_TLNG 0x0080
+#define PCH_GBE_TXD_GMAC_STAT_TSHRT 0x0040
+#define PCH_GBE_TXD_GMAC_STAT_LTCOL 0x0020
+#define PCH_GBE_TXD_GMAC_STAT_TFUNDFLW 0x0010
+
+/**
+ * struct pch_gbe_rx_desc - Receive Descriptor
+ * @buffer_addr: RX Frame Buffer Address
+ * @tcp_ip_status: TCP/IP Accelerator Status
+ * @rx_words_eob: RX word count and Byte position
+ * @gbec_status: GMAC Status
+ * @dma_status: DMA Status
+ * @reserved1: Reserved
+ * @reserved2: Reserved
+ */
+struct pch_gbe_rx_desc {
+ u32 buffer_addr;
+ u32 tcp_ip_status;
+ u16 rx_words_eob;
+ u16 gbec_status;
+ u8 dma_status;
+ u8 reserved1;
+ u16 reserved2;
+};
+
+/**
+ * struct pch_gbe_tx_desc - Transmit Descriptor
+ * @buffer_addr: TX Frame Buffer Address
+ * @length: Data buffer length
+ * @reserved1: Reserved
+ * @tx_words_eob: TX word count and Byte position
+ * @tx_frame_ctrl: TX Frame Control
+ * @dma_status: DMA Status
+ * @reserved2: Reserved
+ * @gbec_status: GMAC Status
+ */
+struct pch_gbe_tx_desc {
+ u32 buffer_addr;
+ u16 length;
+ u16 reserved1;
+ u16 tx_words_eob;
+ u16 tx_frame_ctrl;
+ u8 dma_status;
+ u8 reserved2;
+ u16 gbec_status;
+};
+
+/**
+ * pch_gbe_regs_mac_adr - structure holding values of mac address registers
+ *
+ * @high Denotes the 1st to 4th byte from the initial of MAC address
+ * @low Denotes the 5th to 6th byte from the initial of MAC address
+ */
+struct pch_gbe_regs_mac_adr {
+ u32 high;
+ u32 low;
+};
+
+/**
+ * pch_gbe_regs - structure holding values of MAC registers
+ */
+struct pch_gbe_regs {
+ u32 int_st;
+ u32 int_en;
+ u32 mode;
+ u32 reset;
+ u32 tcpip_acc;
+ u32 ex_list;
+ u32 int_st_hold;
+ u32 phy_int_ctrl;
+ u32 mac_rx_en;
+ u32 rx_fctrl;
+ u32 pause_req;
+ u32 rx_mode;
+ u32 tx_mode;
+ u32 rx_fifo_st;
+ u32 tx_fifo_st;
+ u32 tx_fid;
+ u32 tx_result;
+ u32 pause_pkt1;
+ u32 pause_pkt2;
+ u32 pause_pkt3;
+ u32 pause_pkt4;
+ u32 pause_pkt5;
+ u32 reserve[2];
+ struct pch_gbe_regs_mac_adr mac_adr[16];
+ u32 addr_mask;
+ u32 miim;
+ u32 mac_addr_load;
+ u32 rgmii_st;
+ u32 rgmii_ctrl;
+ u32 reserve3[3];
+ u32 dma_ctrl;
+ u32 reserve4[3];
+ u32 rx_dsc_base;
+ u32 rx_dsc_size;
+ u32 rx_dsc_hw_p;
+ u32 rx_dsc_hw_p_hld;
+ u32 rx_dsc_sw_p;
+ u32 reserve5[3];
+ u32 tx_dsc_base;
+ u32 tx_dsc_size;
+ u32 tx_dsc_hw_p;
+ u32 tx_dsc_hw_p_hld;
+ u32 tx_dsc_sw_p;
+ u32 reserve6[3];
+ u32 rx_dma_st;
+ u32 tx_dma_st;
+ u32 reserve7[2];
+ u32 wol_st;
+ u32 wol_ctrl;
+ u32 wol_addr_mask;
+};
+
+struct pch_gbe_priv {
+ struct pch_gbe_rx_desc rx_desc[PCH_GBE_DESC_NUM];
+ struct pch_gbe_tx_desc tx_desc[PCH_GBE_DESC_NUM];
+ char rx_buff[PCH_GBE_DESC_NUM][PCH_GBE_RX_FRAME_LEN];
+ struct eth_device *dev;
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+ struct pch_gbe_regs *mac_regs;
+ pci_dev_t bdf;
+ u32 interface;
+ int rx_idx;
+ int tx_idx;
+};
+
+#endif /* _PCH_GBE_H_ */
diff --git a/drivers/power/axp209.c b/drivers/power/axp209.c
index 4565398b0b..f8c9b77be0 100644
--- a/drivers/power/axp209.c
+++ b/drivers/power/axp209.c
@@ -119,7 +119,7 @@ int axp209_set_ldo3(int mvolt)
if (mvolt == -1)
cfg = 0x80; /* determined by LDO3IN pin */
else
- cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
+ cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
return axp209_write(AXP209_LDO3_VOLTAGE, cfg);
}
diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c
index c9d318c0a7..44857a6e41 100644
--- a/drivers/rtc/mc146818.c
+++ b/drivers/rtc/mc146818.c
@@ -14,7 +14,6 @@
#include <common.h>
#include <command.h>
#include <rtc.h>
-#include <version.h>
#if defined(__I386__) || defined(CONFIG_MALTA)
#include <asm/io.h>
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 3fc7104359..2de3737739 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -16,8 +16,6 @@
#include <dm/lists.h>
#include <dm/device-internal.h>
-#include <ns16550.h>
-
DECLARE_GLOBAL_DATA_PTR;
/*
diff --git a/drivers/serial/serial_arc.c b/drivers/serial/serial_arc.c
index 2ddbf32a50..54e596c4ed 100644
--- a/drivers/serial/serial_arc.c
+++ b/drivers/serial/serial_arc.c
@@ -8,6 +8,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <serial.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -23,21 +24,23 @@ struct arc_serial_regs {
unsigned int baudh;
};
+
+struct arc_serial_platdata {
+ struct arc_serial_regs *reg;
+ unsigned int uartclk;
+};
+
/* Bit definitions of STATUS register */
#define UART_RXEMPTY (1 << 5)
#define UART_OVERFLOW_ERR (1 << 1)
#define UART_TXEMPTY (1 << 7)
-struct arc_serial_regs *regs;
-
-static void arc_serial_setbrg(void)
+static int arc_serial_setbrg(struct udevice *dev, int baudrate)
{
- int arc_console_baud;
+ struct arc_serial_platdata *plat = dev->platdata;
+ struct arc_serial_regs *const regs = plat->reg;
+ int arc_console_baud = gd->cpu_clk / (baudrate * 4) - 1;
- if (!gd->baudrate)
- gd->baudrate = CONFIG_BAUDRATE;
-
- arc_console_baud = gd->cpu_clk / (gd->baudrate * 4) - 1;
writeb(arc_console_baud & 0xff, &regs->baudl);
#ifdef CONFIG_ARC
@@ -56,34 +59,49 @@ static void arc_serial_setbrg(void)
#else
writeb((arc_console_baud & 0xff00) >> 8, &regs->baudh);
#endif
-}
-static int arc_serial_init(void)
-{
- regs = (struct arc_serial_regs *)CONFIG_ARC_UART_BASE;
- serial_setbrg();
return 0;
}
-static void arc_serial_putc(const char c)
+static int arc_serial_putc(struct udevice *dev, const char c)
{
+ struct arc_serial_platdata *plat = dev->platdata;
+ struct arc_serial_regs *const regs = plat->reg;
+
if (c == '\n')
- arc_serial_putc('\r');
+ arc_serial_putc(dev, '\r');
while (!(readb(&regs->status) & UART_TXEMPTY))
;
writeb(c, &regs->data);
+
+ return 0;
}
-static int arc_serial_tstc(void)
+static int arc_serial_tstc(struct arc_serial_regs *const regs)
{
return !(readb(&regs->status) & UART_RXEMPTY);
}
-static int arc_serial_getc(void)
+static int arc_serial_pending(struct udevice *dev, bool input)
+{
+ struct arc_serial_platdata *plat = dev->platdata;
+ struct arc_serial_regs *const regs = plat->reg;
+ uint32_t status = readb(&regs->status);
+
+ if (input)
+ return status & UART_RXEMPTY ? 0 : 1;
+ else
+ return status & UART_TXEMPTY ? 0 : 1;
+}
+
+static int arc_serial_getc(struct udevice *dev)
{
- while (!arc_serial_tstc())
+ struct arc_serial_platdata *plat = dev->platdata;
+ struct arc_serial_regs *const regs = plat->reg;
+
+ while (!arc_serial_tstc(regs))
;
/* Check for overflow errors */
@@ -93,23 +111,42 @@ static int arc_serial_getc(void)
return readb(&regs->data) & 0xFF;
}
-static struct serial_device arc_serial_drv = {
- .name = "arc_serial",
- .start = arc_serial_init,
- .stop = NULL,
- .setbrg = arc_serial_setbrg,
- .putc = arc_serial_putc,
- .puts = default_serial_puts,
- .getc = arc_serial_getc,
- .tstc = arc_serial_tstc,
-};
-
-void arc_serial_initialize(void)
+static int arc_serial_probe(struct udevice *dev)
{
- serial_register(&arc_serial_drv);
+ return 0;
}
-__weak struct serial_device *default_serial_console(void)
+static const struct dm_serial_ops arc_serial_ops = {
+ .putc = arc_serial_putc,
+ .pending = arc_serial_pending,
+ .getc = arc_serial_getc,
+ .setbrg = arc_serial_setbrg,
+};
+
+static const struct udevice_id arc_serial_ids[] = {
+ { .compatible = "snps,arc-uart" },
+ { }
+};
+
+static int arc_serial_ofdata_to_platdata(struct udevice *dev)
{
- return &arc_serial_drv;
+ struct arc_serial_platdata *plat = dev_get_platdata(dev);
+ DECLARE_GLOBAL_DATA_PTR;
+
+ plat->reg = (struct arc_serial_regs *)fdtdec_get_addr(gd->fdt_blob,
+ dev->of_offset, "reg");
+ plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "clock-frequency", 0);
+
+ return 0;
}
+
+U_BOOT_DRIVER(serial_arc) = {
+ .name = "serial_arc",
+ .id = UCLASS_SERIAL,
+ .of_match = arc_serial_ids,
+ .ofdata_to_platdata = arc_serial_ofdata_to_platdata,
+ .probe = arc_serial_probe,
+ .ops = &arc_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index edbd520141..ce6f1cc74e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
obj-$(CONFIG_ICH_SPI) += ich.o
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
+obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o
obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
obj-$(CONFIG_MXC_SPI) += mxc_spi.o
diff --git a/drivers/spi/cf_qspi.c b/drivers/spi/cf_qspi.c
index 6b8563366b..834c5bd259 100644
--- a/drivers/spi/cf_qspi.c
+++ b/drivers/spi/cf_qspi.c
@@ -20,7 +20,7 @@
DECLARE_GLOBAL_DATA_PTR;
#define clamp(x, low, high) (min(max(low, x), high))
-#define to_cf_qspi_slave(s) container_of(s, struct cf_qspi_slave, s)
+#define to_cf_qspi_slave(s) container_of(s, struct cf_qspi_slave, slave)
struct cf_qspi_slave {
struct spi_slave slave; /* Specific bus:cs ID for each device */
diff --git a/drivers/spi/cf_spi.c b/drivers/spi/cf_spi.c
index 879a809cba..6ce11012e8 100644
--- a/drivers/spi/cf_spi.c
+++ b/drivers/spi/cf_spi.c
@@ -20,13 +20,6 @@ struct cf_spi_slave {
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);
@@ -46,7 +39,12 @@ DECLARE_GLOBAL_DATA_PTR;
#define SPI_MODE_MOD 0x00200000
#define SPI_DBLRATE 0x00100000
-void cfspi_init(void)
+static inline struct cf_spi_slave *to_cf_spi_slave(struct spi_slave *slave)
+{
+ return container_of(slave, struct cf_spi_slave, slave);
+}
+
+static void cfspi_init(void)
{
volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
@@ -84,7 +82,7 @@ void cfspi_init(void)
#endif
}
-void cfspi_tx(u32 ctrl, u16 data)
+static void cfspi_tx(u32 ctrl, u16 data)
{
volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
@@ -93,7 +91,7 @@ void cfspi_tx(u32 ctrl, u16 data)
dspi->tfr = (ctrl | data);
}
-u16 cfspi_rx(void)
+static u16 cfspi_rx(void)
{
volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
@@ -102,10 +100,10 @@ u16 cfspi_rx(void)
return (dspi->rfr & 0xFFFF);
}
-int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout,
- void *din, ulong flags)
+static 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;
+ struct cf_spi_slave *cfslave = to_cf_spi_slave(slave);
u16 *spi_rd16 = NULL, *spi_wr16 = NULL;
u8 *spi_rd = NULL, *spi_wr = NULL;
static u32 ctrl = 0;
@@ -176,7 +174,8 @@ int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout,
return 0;
}
-struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave, uint mode)
+static struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave,
+ uint mode)
{
/*
* bit definition for mode:
@@ -326,7 +325,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
void spi_free_slave(struct spi_slave *slave)
{
- free(slave);
+ struct cf_spi_slave *cfslave = to_cf_spi_slave(slave);
+
+ free(cfslave);
}
int spi_claim_bus(struct spi_slave *slave)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 0ec5b9d859..bf18362baa 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -32,9 +32,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!ds)
return NULL;
- ds->slave.bus = bus;
- ds->slave.cs = cs;
-
switch (bus) {
case SPI0_BUS:
ds->regs = (struct davinci_spi_regs *)SPI0_BASE;
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 2624844d52..8f5c0fc802 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -164,13 +164,13 @@ static void spi_hw_init(struct dw_spi_priv *priv)
if (!priv->fifo_len) {
u32 fifo;
- for (fifo = 2; fifo <= 256; fifo++) {
+ for (fifo = 1; fifo < 256; fifo++) {
dw_writew(priv, DW_SPI_TXFLTR, fifo);
if (fifo != dw_readw(priv, DW_SPI_TXFLTR))
break;
}
- priv->fifo_len = (fifo == 2) ? 0 : fifo - 1;
+ priv->fifo_len = (fifo == 1) ? 0 : fifo;
dw_writew(priv, DW_SPI_TXFLTR, 0);
}
debug("%s: fifo_len=%d\n", __func__, priv->fifo_len);
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
index 267e4d83bd..c7d6480478 100644
--- a/drivers/spi/ftssp010_spi.c
+++ b/drivers/spi/ftssp010_spi.c
@@ -431,7 +431,9 @@ free_out:
void spi_free_slave(struct spi_slave *slave)
{
- free(slave);
+ struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+
+ free(chip);
}
int spi_claim_bus(struct spi_slave *slave)
diff --git a/drivers/spi/lpc32xx_ssp.c b/drivers/spi/lpc32xx_ssp.c
new file mode 100644
index 0000000000..c5b766c0dd
--- /dev/null
+++ b/drivers/spi/lpc32xx_ssp.c
@@ -0,0 +1,144 @@
+/*
+ * LPC32xx SSP interface (SPI mode)
+ *
+ * (C) Copyright 2014 DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compat.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/arch/clk.h>
+
+/* SSP chip registers */
+struct ssp_regs {
+ u32 cr0;
+ u32 cr1;
+ u32 data;
+ u32 sr;
+ u32 cpsr;
+ u32 imsc;
+ u32 ris;
+ u32 mis;
+ u32 icr;
+ u32 dmacr;
+};
+
+/* CR1 register defines */
+#define SSP_CR1_SSP_ENABLE 0x0002
+
+/* SR register defines */
+#define SSP_SR_TNF 0x0002
+/* SSP status RX FIFO not empty bit */
+#define SSP_SR_RNE 0x0004
+
+/* lpc32xx spi slave */
+struct lpc32xx_spi_slave {
+ struct spi_slave slave;
+ struct ssp_regs *regs;
+};
+
+static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave(
+ struct spi_slave *slave)
+{
+ return container_of(slave, struct lpc32xx_spi_slave, slave);
+}
+
+/* spi_init is called during boot when CONFIG_CMD_SPI is defined */
+void spi_init(void)
+{
+ /*
+ * nothing to do: clocking was enabled in lpc32xx_ssp_enable()
+ * and configuration will be done in spi_setup_slave()
+ */
+}
+
+/* the following is called in sequence by do_spi_xfer() */
+
+struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
+{
+ struct lpc32xx_spi_slave *lslave;
+
+ /* we only set up SSP0 for now, so ignore bus */
+
+ if (mode & SPI_3WIRE) {
+ error("3-wire mode not supported");
+ return NULL;
+ }
+
+ if (mode & SPI_SLAVE) {
+ error("slave mode not supported\n");
+ return NULL;
+ }
+
+ if (mode & SPI_PREAMBLE) {
+ error("preamble byte skipping not supported\n");
+ return NULL;
+ }
+
+ lslave = spi_alloc_slave(struct lpc32xx_spi_slave, bus, cs);
+ if (!lslave) {
+ printf("SPI_error: Fail to allocate lpc32xx_spi_slave\n");
+ return NULL;
+ }
+
+ lslave->regs = (struct ssp_regs *)SSP0_BASE;
+
+ /*
+ * 8 bit frame, SPI fmt, 500kbps -> clock divider is 26.
+ * Set SCR to 0 and CPSDVSR to 26.
+ */
+
+ writel(0x7, &lslave->regs->cr0); /* 8-bit chunks, SPI, 1 clk/bit */
+ writel(26, &lslave->regs->cpsr); /* SSP clock = HCLK/26 = 500kbps */
+ writel(0, &lslave->regs->imsc); /* do not raise any interrupts */
+ writel(0, &lslave->regs->icr); /* clear any pending interrupt */
+ writel(0, &lslave->regs->dmacr); /* do not do DMAs */
+ writel(SSP_CR1_SSP_ENABLE, &lslave->regs->cr1); /* enable SSP0 */
+ return &lslave->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave);
+
+ debug("(lpc32xx) spi_free_slave: 0x%08x\n", (u32)lslave);
+ free(lslave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ /* only one bus and slave so far, always available */
+ return 0;
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave);
+ int bytelen = bitlen >> 3;
+ int idx_out = 0;
+ int idx_in = 0;
+ int start_time;
+
+ start_time = get_timer(0);
+ while ((idx_out < bytelen) || (idx_in < bytelen)) {
+ int status = readl(&lslave->regs->sr);
+ if ((idx_out < bytelen) && (status & SSP_SR_TNF))
+ writel(((u8 *)dout)[idx_out++], &lslave->regs->data);
+ if ((idx_in < bytelen) && (status & status & SSP_SR_RNE))
+ ((u8 *)din)[idx_in++] = readl(&lslave->regs->data);
+ if (get_timer(start_time) >= CONFIG_LPC32XX_SSP_TIMEOUT)
+ return -1;
+ }
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ /* do nothing */
+}
diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c
index 857b60455a..3356c0f072 100644
--- a/drivers/spi/ti_qspi.c
+++ b/drivers/spi/ti_qspi.c
@@ -109,10 +109,17 @@ static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave)
slave->op_mode_rx = 8;
#endif
+#ifdef CONFIG_QSPI_QUAD_SUPPORT
+ memval |= (QSPI_CMD_READ_QUAD | QSPI_SETUP0_NUM_A_BYTES |
+ QSPI_SETUP0_NUM_D_BYTES_8_BITS |
+ QSPI_SETUP0_READ_QUAD | QSPI_CMD_WRITE |
+ QSPI_NUM_DUMMY_BITS);
+#else
memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES |
QSPI_SETUP0_NUM_D_BYTES_NO_BITS |
QSPI_SETUP0_READ_NORMAL | QSPI_CMD_WRITE |
QSPI_NUM_DUMMY_BITS;
+#endif
writel(memval, &qslave->base->setup0);
}
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index ba442d5ed5..8f03a6bb9d 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -68,7 +68,6 @@ unsigned packet_received, packet_sent;
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */
-#define ETH_FCS_LEN 4 /* Octets in the FCS */
#define DRIVER_DESC "Ethernet Gadget"
/* Based on linux 2.6.27 version */
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 404a7b96f8..62c9b2ead7 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -43,7 +43,6 @@
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */
-#define ETH_FCS_LEN 4 /* Octets in the FCS */
#define ENOTSUPP 524 /* Operation is not supported */
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index 6e58ddf02c..51fb3fd7e2 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -1,5 +1,8 @@
#include <common.h>
#include <watchdog.h>
+#ifdef CONFIG_ARCH_SUNXI
+#include <asm/arch/usbc.h>
+#endif
#include <asm/errno.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -186,8 +189,19 @@ void usb_reset_root_port(void)
power &= 0xf0;
musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
mdelay(50);
+#ifdef CONFIG_ARCH_SUNXI
+ /*
+ * sunxi phy has a bug and it will wrongly detect high speed squelch
+ * when clearing reset on low-speed devices, temporary disable
+ * squelch detection to work around this.
+ */
+ sunxi_usbc_enable_squelch_detect(0, 0);
+#endif
power = musb_readb(mbase, MUSB_POWER);
musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
+#ifdef CONFIG_ARCH_SUNXI
+ sunxi_usbc_enable_squelch_detect(0, 1);
+#endif
host->isr(0, host);
host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
USB_SPEED_HIGH :
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 4d8c15a5e0..90aaec60d5 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -261,7 +261,7 @@ static int sunxi_musb_init(struct musb *musb)
}
err = gpio_get_value(vbus_det);
- if (err) {
+ if (err < 0) {
gpio_free(vbus_det);
return -EIO;
}
diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c
index c5d7330804..8f3b8263da 100644
--- a/drivers/video/exynos_fb.c
+++ b/drivers/video/exynos_fb.c
@@ -19,6 +19,7 @@
#include <asm/arch/mipi_dsim.h>
#include <asm/arch/dp_info.h>
#include <asm/arch/system.h>
+#include <asm/gpio.h>
#include <asm-generic/errno.h>
#include "exynos_fb.h"
@@ -102,6 +103,10 @@ __weak int exynos_lcd_misc_init(vidinfo_t *vid)
static void lcd_panel_on(vidinfo_t *vid)
{
+ struct gpio_desc pwm_out_gpio;
+ struct gpio_desc bl_en_gpio;
+ unsigned int node;
+
udelay(vid->init_delay);
exynos_backlight_reset();
@@ -121,6 +126,22 @@ static void lcd_panel_on(vidinfo_t *vid)
exynos_backlight_on(1);
+#ifdef CONFIG_OF_CONTROL
+ node = fdtdec_next_compatible(gd->fdt_blob, 0,
+ COMPAT_SAMSUNG_EXYNOS_FIMD);
+ if (node <= 0) {
+ debug("FIMD: Can't get device node for FIMD\n");
+ return;
+ }
+ gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,pwm-out-gpio",
+ 0, &pwm_out_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+ gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,bl-en-gpio", 0,
+ &bl_en_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+#endif
exynos_cfg_ldo();
exynos_enable_ldo(1);
diff --git a/drivers/video/mpc8xx_lcd.c b/drivers/video/mpc8xx_lcd.c
index faa58c020b..b08576eab2 100644
--- a/drivers/video/mpc8xx_lcd.c
+++ b/drivers/video/mpc8xx_lcd.c
@@ -15,7 +15,6 @@
#include <common.h>
#include <command.h>
#include <watchdog.h>
-#include <version.h>
#include <stdarg.h>
#include <lcdvideo.h>
#include <linux/types.h>
diff --git a/drivers/video/parade.c b/drivers/video/parade.c
index 0f543f653c..ae5097160f 100644
--- a/drivers/video/parade.c
+++ b/drivers/video/parade.c
@@ -12,6 +12,7 @@
#include <common.h>
#include <i2c.h>
#include <fdtdec.h>
+#include <asm/gpio.h>
/*
* Initialization of the chip is a process of writing certaing values into
@@ -180,6 +181,8 @@ static int parade_write_regs(int base_addr, const struct reg_data *table)
int parade_init(const void *blob)
{
+ struct gpio_desc rst_gpio;
+ struct gpio_desc slp_gpio;
int bus, old_bus;
int parent;
int node;
@@ -201,6 +204,14 @@ int parade_init(const void *blob)
return -1;
}
+ gpio_request_by_name_nodev(blob, node, "sleep-gpio", 0, &slp_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+ mdelay(10);
+
+ gpio_request_by_name_nodev(blob, node, "reset-gpio", 0, &rst_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
bus = i2c_get_bus_num_fdt(parent);
old_bus = i2c_get_bus_num();
diff --git a/drivers/video/pxa_lcd.c b/drivers/video/pxa_lcd.c
index 04105d4eaa..64cef37bc9 100644
--- a/drivers/video/pxa_lcd.c
+++ b/drivers/video/pxa_lcd.c
@@ -13,7 +13,6 @@
#include <config.h>
#include <common.h>
-#include <version.h>
#include <stdarg.h>
#include <linux/types.h>
#include <stdio_dev.h>