summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-10-07 08:51:11 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-10-07 08:51:11 +0200
commitab7647dbd8aa54fcb0178829ac9e5fccb053d4ef (patch)
tree907492c209e5639af4faac074df9939f78aa078d /drivers
parentb06ef2e54303443d21dd98a773a13289e66812fb (diff)
parent6fb511fa62efe3faa8be67800cd934c143405fca (diff)
downloadbarebox-ab7647dbd8aa54fcb0178829ac9e5fccb053d4ef.tar.gz
barebox-ab7647dbd8aa54fcb0178829ac9e5fccb053d4ef.tar.xz
Merge branch 'for-next/misc'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mci/mci-bcm2835.c9
-rw-r--r--drivers/mci/mci-core.c2
-rw-r--r--drivers/mci/sdhci.c5
-rw-r--r--drivers/mtd/core.c22
-rw-r--r--drivers/net/Kconfig13
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/cpsw.c4
-rw-r--r--drivers/net/designware_eqos.c4
-rw-r--r--drivers/net/e1000/Makefile3
-rw-r--r--drivers/net/e1000/eeprom.c814
-rw-r--r--drivers/net/e1000/mtd.c835
-rw-r--r--drivers/net/virtio.c243
-rw-r--r--drivers/net/xgmac.c734
-rw-r--r--drivers/pinctrl/pinctrl-bcm2835.c24
-rw-r--r--drivers/serial/Kconfig8
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_sbi.c58
-rw-r--r--drivers/spi/ath79_spi.c6
-rw-r--r--drivers/usb/gadget/dfu.c163
-rw-r--r--drivers/video/simplefb-client.c27
20 files changed, 1226 insertions, 1753 deletions
diff --git a/drivers/mci/mci-bcm2835.c b/drivers/mci/mci-bcm2835.c
index 0450f899c6..f2cb65231e 100644
--- a/drivers/mci/mci-bcm2835.c
+++ b/drivers/mci/mci-bcm2835.c
@@ -84,16 +84,20 @@ static u32 bcm2835_sdhci_read32(struct sdhci *sdhci, int reg)
return readl(host->regs + reg);
}
-static u32 bcm2835_mci_wait_command_done(struct bcm2835_mci_host *host)
+static int bcm2835_mci_wait_command_done(struct bcm2835_mci_host *host)
{
u32 interrupt = 0;
+ uint64_t start;
+ start = get_time_ns();
while (true) {
interrupt = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
if (interrupt & SDHCI_INT_INDEX)
return -EPERM;
if (interrupt & SDHCI_INT_CMD_COMPLETE)
break;
+ if (is_timeout(start, SECOND))
+ return -ETIMEDOUT;
}
return 0;
}
@@ -127,7 +131,8 @@ static void bcm2835_mci_reset_emmc(struct bcm2835_mci_host *host, u32 reset,
*/
static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd,
struct mci_data *data) {
- u32 command, block_data = 0, ret = 0, transfer_mode = 0;
+ u32 command, block_data = 0, transfer_mode = 0;
+ int ret;
u32 wait_inhibit_mask = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
struct bcm2835_mci_host *host = to_bcm2835_host(mci);
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 92a73c8f1d..82e2f82f53 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1920,7 +1920,7 @@ int mci_register(struct mci_host *host)
host->supply = regulator_get(hw_dev, "vmmc");
if (IS_ERR(host->supply)) {
- dev_err(&mci->dev, "Failed to get 'vmmc' regulator.\n");
+ dev_warn(hw_dev, "Failed to get 'vmmc' regulator (ignored).\n");
host->supply = NULL;
}
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index aca4a5a6f9..8b5520d682 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -129,9 +129,8 @@ void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data)
if (!data)
return;
- sdhci_write16(sdhci, SDHCI_BLOCK_SIZE, sdhci->sdma_boundary |
- SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
- sdhci_write16(sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+ sdhci_write32(sdhci, SDHCI_BLOCK_SIZE, sdhci->sdma_boundary |
+ SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize) | data->blocks << 16);
}
void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data,
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 37fccda6be..c6c1e1e7cf 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -377,7 +377,7 @@ int mtd_block_markgood(struct mtd_info *mtd, loff_t ofs)
}
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
- u_char *buf)
+ u_char *buf)
{
struct mtd_oob_ops ops = {
.len = len,
@@ -420,23 +420,23 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
}
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
- const u_char *buf)
+ const u_char *buf)
{
- struct mtd_oob_ops ops = {
- .len = len,
- .datbuf = (u8 *)buf,
- };
- int ret;
+ struct mtd_oob_ops ops = {
+ .len = len,
+ .datbuf = (u8 *)buf,
+ };
+ int ret;
if (to < 0 || to >= mtd->size || len > mtd->size - to)
return -EINVAL;
if (!len)
return 0;
- ret = mtd_write_oob(mtd, to, &ops);
- *retlen = ops.retlen;
+ ret = mtd_write_oob(mtd, to, &ops);
+ *retlen = ops.retlen;
- return ret;
+ return ret;
}
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
@@ -757,7 +757,7 @@ err:
return ret;
}
-int del_mtd_device (struct mtd_info *mtd)
+int del_mtd_device(struct mtd_info *mtd)
{
struct mtddev_hook *hook;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 802169a86e..4947296f27 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -28,7 +28,7 @@ config DRIVER_NET_AR231X
config DRIVER_NET_ARC_EMAC
bool "ARC Ethernet MAC driver"
- depends on HAS_DMA
+ depends on HAS_DMA && 32BIT
select PHYLIB
help
This option enables support for the ARC EMAC ethernet
@@ -39,10 +39,6 @@ config DRIVER_NET_AT91_ETHER
depends on HAS_AT91_ETHER
select PHYLIB
-config DRIVER_NET_CALXEDA_XGMAC
- bool "Calxeda xgmac"
- depends on HAS_DMA
-
config DRIVER_NET_CS8900
bool "cs8900 ethernet driver"
depends on HAS_CS8900 || COMPILE_TEST
@@ -262,6 +258,13 @@ config DRIVER_NET_EFI_SNP
bool "EFI SNP ethernet driver"
depends on EFI_BOOTUP
+config DRIVER_NET_VIRTIO
+ bool "virtio net driver"
+ depends on VIRTIO
+ help
+ This is the virtual net driver for virtio. It can be used with
+ QEMU based targets.
+
config DRIVER_NET_AG71XX
bool "Atheros AG71xx ethernet driver"
depends on MACH_MIPS_ATH79
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index fb3e3bdee4..1921d0d9f9 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -4,7 +4,6 @@ obj-$(CONFIG_NET_USB) += usb/
obj-$(CONFIG_DRIVER_NET_AR231X) += ar231x.o
obj-$(CONFIG_DRIVER_NET_ARC_EMAC) += arc_emac.o
obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o
-obj-$(CONFIG_DRIVER_NET_CALXEDA_XGMAC) += xgmac.o
obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o
obj-$(CONFIG_DRIVER_NET_CPSW) += cpsw.o
obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC) += davinci_emac.o
@@ -17,7 +16,7 @@ obj-$(CONFIG_DRIVER_NET_DESIGNWARE_STM32) += designware_stm32.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE_TEGRA186) += designware_tegra186.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE_ROCKCHIP) += designware_rockchip.o
obj-$(CONFIG_DRIVER_NET_DM9K) += dm9k.o
-obj-$(CONFIG_DRIVER_NET_E1000) += e1000/regio.o e1000/main.o e1000/eeprom.o
+obj-$(CONFIG_DRIVER_NET_E1000) += e1000/
obj-$(CONFIG_DRIVER_NET_ENC28J60) += enc28j60.o
obj-$(CONFIG_DRIVER_NET_EP93XX) += ep93xx.o
obj-$(CONFIG_DRIVER_NET_ETHOC) += ethoc.o
@@ -37,4 +36,5 @@ obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
obj-$(CONFIG_DRIVER_NET_EFI_SNP) += efi-snp.o
+obj-$(CONFIG_DRIVER_NET_VIRTIO) += virtio.o
obj-$(CONFIG_DRIVER_NET_AG71XX) += ag71xx.o
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index b01e7ac7a8..4a8f9e67d6 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -901,13 +901,13 @@ static int cpsw_open(struct eth_device *edev)
dev_dbg(&slave->dev, "* %s\n", __func__);
+ cpsw_slave_init(slave, priv);
+
ret = phy_device_connect(edev, NULL, slave->phy_id,
cpsw_adjust_link, 0, slave->phy_if);
if (ret)
return ret;
- cpsw_slave_init(slave, priv);
-
return 0;
}
diff --git a/drivers/net/designware_eqos.c b/drivers/net/designware_eqos.c
index f83ec12714..f83e5d6d9b 100644
--- a/drivers/net/designware_eqos.c
+++ b/drivers/net/designware_eqos.c
@@ -362,6 +362,10 @@ static int phy_resume(struct phy_device *phydev)
{
int bmcr;
+ // Bus will be NULL if a fixed-link is used.
+ if (!phydev->bus)
+ return 0;
+
bmcr = phy_read(phydev, MII_BMCR);
if (bmcr < 0)
return bmcr;
diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
new file mode 100644
index 0000000000..91ef11cbe3
--- /dev/null
+++ b/drivers/net/e1000/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-y += regio.o main.o eeprom.o
+obj-$(CONFIG_MTD) += mtd.o
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 5a7d8675ce..6bdf9db553 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -731,250 +731,6 @@ static int32_t e1000_spi_eeprom_ready(struct e1000_hw *hw)
return E1000_SUCCESS;
}
-static int e1000_flash_mode_wait_for_idle(struct e1000_hw *hw)
-{
- const int ret = e1000_poll_reg(hw, E1000_FLSWCTL, E1000_FLSWCTL_DONE,
- E1000_FLSWCTL_DONE, SECOND);
- if (ret < 0)
- dev_err(hw->dev,
- "Timeout waiting for FLSWCTL.DONE to be set (wait)\n");
- return ret;
-}
-
-static int e1000_flash_mode_check_command_valid(struct e1000_hw *hw)
-{
- const uint32_t flswctl = e1000_read_reg(hw, E1000_FLSWCTL);
- if (!(flswctl & E1000_FLSWCTL_CMDV)) {
- dev_err(hw->dev, "FLSWCTL.CMDV was cleared\n");
- return -EIO;
- }
-
- return E1000_SUCCESS;
-}
-
-static void e1000_flash_cmd(struct e1000_hw *hw,
- uint32_t cmd, uint32_t offset)
-{
- uint32_t flswctl = e1000_read_reg(hw, E1000_FLSWCTL);
- flswctl &= ~E1000_FLSWCTL_CMD_ADDR_MASK;
- flswctl |= E1000_FLSWCTL_CMD(cmd) | E1000_FLSWCTL_ADDR(offset);
- e1000_write_reg(hw, E1000_FLSWCTL, flswctl);
-}
-
-static int e1000_flash_mode_read_chunk(struct e1000_hw *hw, loff_t offset,
- size_t size, void *data)
-{
- int ret;
- size_t chunk, residue = size;
- uint32_t flswdata;
-
- DEBUGFUNC();
-
- if (size > SZ_4K ||
- E1000_FLSWCTL_ADDR(offset) != offset)
- return -EINVAL;
-
- ret = e1000_flash_mode_wait_for_idle(hw);
- if (ret < 0)
- return ret;
-
- e1000_write_reg(hw, E1000_FLSWCNT, size);
- e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_READ, offset);
-
- do {
- ret = e1000_flash_mode_check_command_valid(hw);
- if (ret < 0)
- return -EIO;
-
- chunk = min(sizeof(flswdata), residue);
-
- ret = e1000_poll_reg(hw, E1000_FLSWCTL,
- E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
- SECOND);
- if (ret < 0) {
- dev_err(hw->dev,
- "Timeout waiting for FLSWCTL.DONE to be set (read)\n");
- return ret;
- }
-
- flswdata = e1000_read_reg(hw, E1000_FLSWDATA);
- /*
- * Readl does le32_to_cpu, so we need to undo that
- */
- flswdata = cpu_to_le32(flswdata);
- memcpy(data, &flswdata, chunk);
-
- data += chunk;
- residue -= chunk;
- } while (residue);
-
- return E1000_SUCCESS;
-}
-
-static int e1000_flash_mode_write_chunk(struct e1000_hw *hw, loff_t offset,
- size_t size, const void *data)
-{
- int ret;
- size_t chunk, residue = size;
- uint32_t flswdata;
-
- if (size > 256 ||
- E1000_FLSWCTL_ADDR(offset) != offset)
- return -EINVAL;
-
- ret = e1000_flash_mode_wait_for_idle(hw);
- if (ret < 0)
- return ret;
-
-
- e1000_write_reg(hw, E1000_FLSWCNT, size);
- e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_WRITE, offset);
-
- do {
- chunk = min(sizeof(flswdata), residue);
- memcpy(&flswdata, data, chunk);
- /*
- * writel does cpu_to_le32, so we do the inverse in
- * order to account for that
- */
- flswdata = le32_to_cpu(flswdata);
- e1000_write_reg(hw, E1000_FLSWDATA, flswdata);
-
- ret = e1000_flash_mode_check_command_valid(hw);
- if (ret < 0)
- return -EIO;
-
- ret = e1000_poll_reg(hw, E1000_FLSWCTL,
- E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
- SECOND);
- if (ret < 0) {
- dev_err(hw->dev,
- "Timeout waiting for FLSWCTL.DONE to be set (write)\n");
- return ret;
- }
-
- data += chunk;
- residue -= chunk;
-
- } while (residue);
-
- return E1000_SUCCESS;
-}
-
-
-static int e1000_flash_mode_erase_chunk(struct e1000_hw *hw, loff_t offset,
- size_t size)
-{
- int ret;
-
- ret = e1000_flash_mode_wait_for_idle(hw);
- if (ret < 0)
- return ret;
-
- if (!size && !offset)
- e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_ERASE_DEVICE, 0);
- else
- e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_ERASE_SECTOR, offset);
-
- ret = e1000_flash_mode_check_command_valid(hw);
- if (ret < 0)
- return -EIO;
-
- ret = e1000_poll_reg(hw, E1000_FLSWCTL,
- E1000_FLSWCTL_DONE | E1000_FLSWCTL_FLBUSY,
- E1000_FLSWCTL_DONE,
- 40 * SECOND);
- if (ret < 0) {
- dev_err(hw->dev,
- "Timeout waiting for FLSWCTL.DONE to be set (erase)\n");
- return ret;
- }
-
- return E1000_SUCCESS;
-}
-
-enum {
- E1000_FLASH_MODE_OP_READ = 0,
- E1000_FLASH_MODE_OP_WRITE = 1,
- E1000_FLASH_MODE_OP_ERASE = 2,
-};
-
-
-static int e1000_flash_mode_io(struct e1000_hw *hw, int op, size_t granularity,
- loff_t offset, size_t size, void *data)
-{
- int ret;
- size_t residue = size;
-
- do {
- const size_t chunk = min(granularity, residue);
-
- switch (op) {
- case E1000_FLASH_MODE_OP_READ:
- ret = e1000_flash_mode_read_chunk(hw, offset,
- chunk, data);
- break;
- case E1000_FLASH_MODE_OP_WRITE:
- ret = e1000_flash_mode_write_chunk(hw, offset,
- chunk, data);
- break;
- case E1000_FLASH_MODE_OP_ERASE:
- ret = e1000_flash_mode_erase_chunk(hw, offset,
- chunk);
- break;
- default:
- return -ENOTSUPP;
- }
-
- if (ret < 0)
- return ret;
-
- offset += chunk;
- residue -= chunk;
- data += chunk;
- } while (residue);
-
- return E1000_SUCCESS;
-}
-
-
-static int e1000_flash_mode_read(struct e1000_hw *hw, loff_t offset,
- size_t size, void *data)
-{
- return e1000_flash_mode_io(hw,
- E1000_FLASH_MODE_OP_READ, SZ_4K,
- offset, size, data);
-}
-
-static int e1000_flash_mode_write(struct e1000_hw *hw, loff_t offset,
- size_t size, const void *data)
-{
- int ret;
-
- ret = e1000_flash_mode_io(hw,
- E1000_FLASH_MODE_OP_WRITE, 256,
- offset, size, (void *)data);
- if (ret < 0)
- return ret;
-
- ret = e1000_poll_reg(hw, E1000_FLSWCTL,
- E1000_FLSWCTL_FLBUSY,
- 0, SECOND);
- if (ret < 0)
- dev_err(hw->dev, "Timout while waiting for FLSWCTL.FLBUSY\n");
-
- return ret;
-}
-
-static int e1000_flash_mode_erase(struct e1000_hw *hw, loff_t offset,
- size_t size)
-{
- return e1000_flash_mode_io(hw,
- E1000_FLASH_MODE_OP_ERASE, SZ_4K,
- offset, size, NULL);
-}
-
-
/******************************************************************************
* Reads a 16 bit word from the EEPROM.
*
@@ -1066,484 +822,6 @@ int e1000_validate_eeprom_checksum(struct e1000_hw *hw)
return -E1000_ERR_EEPROM;
}
-static ssize_t e1000_invm_cdev_read(struct cdev *cdev, void *buf,
- size_t count, loff_t offset, unsigned long flags)
-{
- uint8_t n, bnr;
- uint32_t line;
- size_t chunk, residue = count;
- struct e1000_hw *hw = container_of(cdev, struct e1000_hw, invm.cdev);
-
- n = offset / sizeof(line);
- if (n > E1000_INVM_DATA_MAX_N)
- return -EINVAL;
-
- bnr = offset % sizeof(line);
- if (bnr) {
- /*
- * if bnr in not zero it means we have a non 4-byte
- * aligned start and need to do a partial read
- */
- const uint8_t *bptr;
-
- bptr = (uint8_t *)&line + bnr;
- chunk = min(bnr - sizeof(line), count);
- line = e1000_read_reg(hw, E1000_INVM_DATA(n));
- line = cpu_to_le32(line); /* to account for readl */
- memcpy(buf, bptr, chunk);
-
- goto start_adjusted;
- }
-
- do {
- if (n > E1000_INVM_DATA_MAX_N)
- return -EINVAL;
-
- chunk = min(sizeof(line), residue);
- line = e1000_read_reg(hw, E1000_INVM_DATA(n));
- line = cpu_to_le32(line); /* to account for readl */
-
- /*
- * by using memcpy in conjunction with min should get
- * dangling tail reads as well as aligned reads
- */
- memcpy(buf, &line, chunk);
-
- start_adjusted:
- residue -= chunk;
- buf += chunk;
- n++;
- } while (residue);
-
- return count;
-}
-
-static int e1000_invm_program(struct e1000_hw *hw, u32 offset, u32 value,
- unsigned int delay)
-{
- int retries = 400;
- do {
- if ((e1000_read_reg(hw, offset) & value) == value)
- return E1000_SUCCESS;
-
- e1000_write_reg(hw, offset, value);
-
- if (delay) {
- udelay(delay);
- } else {
- int ret;
-
- if (e1000_read_reg(hw, E1000_INVM_PROTECT) &
- E1000_INVM_PROTECT_WRITE_ERROR) {
- dev_err(hw->dev, "Error while writing to %x\n", offset);
- return -EIO;
- }
-
- ret = e1000_poll_reg(hw, E1000_INVM_PROTECT,
- E1000_INVM_PROTECT_BUSY,
- 0, SECOND);
- if (ret < 0) {
- dev_err(hw->dev,
- "Timeout while waiting for INVM_PROTECT.BUSY\n");
- return ret;
- }
- }
- } while (retries--);
-
- return -ETIMEDOUT;
-}
-
-static int e1000_invm_set_lock(struct param_d *param, void *priv)
-{
- struct e1000_hw *hw = priv;
-
- if (hw->invm.line > 31)
- return -EINVAL;
-
- return e1000_invm_program(hw,
- E1000_INVM_LOCK(hw->invm.line),
- E1000_INVM_LOCK_BIT,
- 10);
-}
-
-static int e1000_invm_unlock(struct e1000_hw *hw)
-{
- e1000_write_reg(hw, E1000_INVM_PROTECT, E1000_INVM_PROTECT_CODE);
- /*
- * If we were successful at unlocking iNVM for programming we
- * should see ALLOW_WRITE bit toggle to 1
- */
- if (!(e1000_read_reg(hw, E1000_INVM_PROTECT) &
- E1000_INVM_PROTECT_ALLOW_WRITE))
- return -EIO;
- else
- return E1000_SUCCESS;
-}
-
-static void e1000_invm_lock(struct e1000_hw *hw)
-{
- e1000_write_reg(hw, E1000_INVM_PROTECT, 0);
-}
-
-static int e1000_invm_write_prepare(struct e1000_hw *hw)
-{
- int ret;
- /*
- * This needs to be done accorging to the datasheet p. 541 and
- * p. 79
- */
- e1000_write_reg(hw, E1000_PCIEMISC,
- E1000_PCIEMISC_RESERVED_PATTERN1 |
- E1000_PCIEMISC_DMA_IDLE |
- E1000_PCIEMISC_RESERVED_PATTERN2);
-
- /*
- * Needed for programming iNVM on devices with Flash with valid
- * contents attached
- */
- ret = e1000_poll_reg(hw, E1000_EEMNGCTL,
- E1000_EEMNGCTL_CFG_DONE,
- E1000_EEMNGCTL_CFG_DONE, SECOND);
- if (ret < 0) {
- dev_err(hw->dev,
- "Timeout while waiting for EEMNGCTL.CFG_DONE\n");
- return ret;
- }
-
- udelay(15);
-
- return E1000_SUCCESS;
-}
-
-static ssize_t e1000_invm_cdev_write(struct cdev *cdev, const void *buf,
- size_t count, loff_t offset, unsigned long flags)
-{
- int ret;
- uint8_t n, bnr;
- uint32_t line;
- size_t chunk, residue = count;
- struct e1000_hw *hw = container_of(cdev, struct e1000_hw, invm.cdev);
-
- ret = e1000_invm_write_prepare(hw);
- if (ret < 0)
- return ret;
-
- ret = e1000_invm_unlock(hw);
- if (ret < 0)
- goto exit;
-
- n = offset / sizeof(line);
- if (n > E1000_INVM_DATA_MAX_N) {
- ret = -EINVAL;
- goto exit;
- }
-
- bnr = offset % sizeof(line);
- if (bnr) {
- uint8_t *bptr;
- /*
- * if bnr in not zero it means we have a non 4-byte
- * aligned start and need to do a read-modify-write
- * sequence
- */
-
- /* Read */
- line = e1000_read_reg(hw, E1000_INVM_DATA(n));
-
- /* Modify */
- /*
- * We need to ensure that line is LE32 in order for
- * memcpy to copy byte from least significant to most
- * significant, since that's how i210 will write the
- * 32-bit word out to OTP
- */
- line = cpu_to_le32(line);
- bptr = (uint8_t *)&line + bnr;
- chunk = min(sizeof(line) - bnr, count);
- memcpy(bptr, buf, chunk);
- line = le32_to_cpu(line);
-
- /* Jumping inside of the loop to take care of the
- * Write */
- goto start_adjusted;
- }
-
- do {
- if (n > E1000_INVM_DATA_MAX_N) {
- ret = -EINVAL;
- goto exit;
- }
-
- chunk = min(sizeof(line), residue);
- if (chunk != sizeof(line)) {
- /*
- * If chunk is smaller that sizeof(line), which
- * should be 4 bytes, we have a "dangling"
- * chunk and we should read the unchanged
- * portion of the 4-byte word from iNVM and do
- * a read-modify-write sequence
- */
- line = e1000_read_reg(hw, E1000_INVM_DATA(n));
- }
-
- line = cpu_to_le32(line);
- memcpy(&line, buf, chunk);
- line = le32_to_cpu(line);
-
- start_adjusted:
- /*
- * iNVM is organized in 32 64-bit lines and each of
- * those lines can be locked to prevent any further
- * modification, so for every i-th 32-bit word we need
- * to check INVM_LINE[i/2] register to see if that word
- * can be modified
- */
- if (e1000_read_reg(hw, E1000_INVM_LOCK(n / 2)) &
- E1000_INVM_LOCK_BIT) {
- dev_err(hw->dev, "line %d is locked\n", n / 2);
- ret = -EIO;
- goto exit;
- }
-
- ret = e1000_invm_program(hw,
- E1000_INVM_DATA(n),
- line,
- 0);
- if (ret < 0)
- goto exit;
-
- residue -= chunk;
- buf += chunk;
- n++;
- } while (residue);
-
- ret = E1000_SUCCESS;
-exit:
- e1000_invm_lock(hw);
- return ret;
-}
-
-static struct cdev_operations e1000_invm_ops = {
- .read = e1000_invm_cdev_read,
- .write = e1000_invm_cdev_write,
-};
-
-static ssize_t e1000_eeprom_cdev_read(struct cdev *cdev, void *buf,
- size_t count, loff_t offset, unsigned long flags)
-{
- struct e1000_hw *hw = container_of(cdev, struct e1000_hw, eepromcdev);
- int32_t ret;
-
- /*
- * The eeprom interface works on 16 bit words which gives a nice excuse
- * for being lazy and not implementing unaligned reads.
- */
- if (offset & 1 || count == 1)
- return -EIO;
-
- ret = e1000_read_eeprom(hw, offset / 2, count / 2, buf);
- if (ret)
- return -EIO;
- else
- return (count / 2) * 2;
-};
-
-static struct cdev_operations e1000_eeprom_ops = {
- .read = e1000_eeprom_cdev_read,
-};
-
-static int e1000_mtd_read_or_write(bool read,
- struct mtd_info *mtd, loff_t off, size_t len,
- size_t *retlen, u_char *buf)
-{
- int ret;
- struct e1000_hw *hw = container_of(mtd, struct e1000_hw, mtd);
-
- DEBUGFUNC();
-
- if (e1000_acquire_eeprom(hw) == E1000_SUCCESS) {
- if (read)
- ret = e1000_flash_mode_read(hw, off,
- len, buf);
- else
- ret = e1000_flash_mode_write(hw, off,
- len, buf);
- if (ret == E1000_SUCCESS)
- *retlen = len;
-
- e1000_release_eeprom(hw);
- } else {
- ret = -E1000_ERR_EEPROM;
- }
-
- return ret;
-
-}
-
-static int e1000_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- return e1000_mtd_read_or_write(true,
- mtd, from, len, retlen, buf);
-}
-
-static int e1000_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- return e1000_mtd_read_or_write(false,
- mtd, to, len, retlen, (u_char *)buf);
-}
-
-static int e1000_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
- uint32_t rem;
- struct e1000_hw *hw = container_of(mtd, struct e1000_hw, mtd);
- int ret;
-
- div_u64_rem(instr->len, mtd->erasesize, &rem);
- if (rem)
- return -EINVAL;
-
- ret = e1000_acquire_eeprom(hw);
- if (ret != E1000_SUCCESS)
- goto fail;
-
- /*
- * If mtd->size is 4096 it means we are dealing with
- * unprogrammed flash and we don't really know its size to
- * make an informed decision wheither to erase the whole chip or
- * just a number of its sectors
- */
- if (mtd->size > SZ_4K &&
- instr->len == mtd->size)
- ret = e1000_flash_mode_erase(hw, 0, 0);
- else
- ret = e1000_flash_mode_erase(hw,
- instr->addr, instr->len);
-
- e1000_release_eeprom(hw);
-
- if (ret < 0)
- goto fail;
-
- return 0;
-
-fail:
- return ret;
-}
-
-static int e1000_mtd_sr_rmw(struct mtd_info *mtd, u8 mask, u8 val)
-{
- struct e1000_hw *hw = container_of(mtd, struct e1000_hw, mtd);
- uint32_t flswdata;
- int ret;
-
- ret = e1000_flash_mode_wait_for_idle(hw);
- if (ret < 0)
- return ret;
-
- e1000_write_reg(hw, E1000_FLSWCNT, 1);
- e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_RDSR, 0);
-
- ret = e1000_flash_mode_check_command_valid(hw);
- if (ret < 0)
- return -EIO;
-
- ret = e1000_poll_reg(hw, E1000_FLSWCTL,
- E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
- SECOND);
- if (ret < 0) {
- dev_err(hw->dev,
- "Timeout waiting for FLSWCTL.DONE to be set (RDSR)\n");
- return ret;
- }
-
- flswdata = e1000_read_reg(hw, E1000_FLSWDATA);
-
- flswdata = (flswdata & ~mask) | val;
-
- e1000_write_reg(hw, E1000_FLSWCNT, 1);
- e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_WRSR, 0);
-
- ret = e1000_flash_mode_check_command_valid(hw);
- if (ret < 0)
- return -EIO;
-
- e1000_write_reg(hw, E1000_FLSWDATA, flswdata);
-
- ret = e1000_poll_reg(hw, E1000_FLSWCTL,
- E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
- SECOND);
- if (ret < 0) {
- dev_err(hw->dev,
- "Timeout waiting for FLSWCTL.DONE to be set (WRSR)\n");
- }
-
- return ret;
-}
-
-/*
- * The available spi nor devices are very different in how the block protection
- * bits affect which sectors to be protected. So take the simple approach and
- * only use BP[012] = b000 (unprotected) and BP[012] = b111 (protected).
- */
-#define SR_BPALL (SR_BP0 | SR_BP1 | SR_BP2)
-
-static int e1000_mtd_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
- return e1000_mtd_sr_rmw(mtd, SR_BPALL, SR_BPALL);
-}
-
-static int e1000_mtd_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
- return e1000_mtd_sr_rmw(mtd, SR_BPALL, 0x0);
-}
-
-static int e1000_register_invm(struct e1000_hw *hw)
-{
- int ret;
- u16 word;
- struct param_d *p;
-
- if (e1000_eeprom_valid(hw)) {
- ret = e1000_read_eeprom(hw, 0x0a, 1, &word);
- if (ret < 0)
- return ret;
-
- if (word & (1 << 15))
- dev_warn(hw->dev, "iNVM lockout mechanism is active\n");
- }
-
- hw->invm.cdev.dev = hw->dev;
- hw->invm.cdev.ops = &e1000_invm_ops;
- hw->invm.cdev.priv = hw;
- hw->invm.cdev.name = xasprintf("e1000-invm%d", hw->dev->id);
- hw->invm.cdev.size = 4 * (E1000_INVM_DATA_MAX_N + 1);
-
- ret = devfs_create(&hw->invm.cdev);
- if (ret < 0)
- return ret;
-
- dev_set_name(&hw->invm.dev, "invm");
- hw->invm.dev.id = hw->dev->id;
- hw->invm.dev.parent = hw->dev;
- ret = register_device(&hw->invm.dev);
- if (ret < 0) {
- devfs_remove(&hw->invm.cdev);
- return ret;
- }
-
- p = dev_add_param_int(&hw->invm.dev, "lock", e1000_invm_set_lock,
- NULL, &hw->invm.line, "%u", hw);
- if (IS_ERR(p)) {
- unregister_device(&hw->invm.dev);
- devfs_remove(&hw->invm.cdev);
- ret = PTR_ERR(p);
- }
-
- return ret;
-}
-
int e1000_eeprom_valid(struct e1000_hw *hw)
{
uint32_t valid_mask = E1000_EECD_FLASH_IN_USE |
@@ -1562,95 +840,3 @@ int e1000_eeprom_valid(struct e1000_hw *hw)
return 1;
}
-
-/*
- * This function has a wrong name for historic reasons, it doesn't add an
- * eeprom, but the flash (if available) that is used to simulate the eeprom.
- * Also a device that represents the invm is registered here (if available).
- */
-int e1000_register_eeprom(struct e1000_hw *hw)
-{
- struct e1000_eeprom_info *eeprom = &hw->eeprom;
- uint32_t eecd;
- int ret;
-
- if (hw->mac_type != e1000_igb)
- return E1000_SUCCESS;
-
- eecd = e1000_read_reg(hw, E1000_EECD);
-
- if (eecd & E1000_EECD_AUTO_RD) {
- if (eecd & E1000_EECD_EE_PRES) {
- if (eecd & E1000_EECD_FLASH_IN_USE) {
- uint32_t fla = e1000_read_reg(hw, E1000_FLA);
- dev_info(hw->dev,
- "Hardware programmed from flash (%ssecure)\n",
- fla & E1000_FLA_LOCKED ? "" : "un");
- } else {
- dev_info(hw->dev, "Hardware programmed from iNVM\n");
- }
- } else {
- dev_warn(hw->dev, "Shadow RAM invalid\n");
- }
- } else {
- /*
- * I never saw this case in practise and I'm unsure how
- * to handle that. Maybe just wait until the hardware is
- * up enough that this bit is set?
- */
- dev_err(hw->dev, "Flash Auto-Read not done\n");
- }
-
- if (e1000_eeprom_valid(hw)) {
- hw->eepromcdev.dev = hw->dev;
- hw->eepromcdev.ops = &e1000_eeprom_ops;
- hw->eepromcdev.name = xasprintf("e1000-eeprom%d",
- hw->dev->id);
- hw->eepromcdev.size = 0x1000;
-
- ret = devfs_create(&hw->eepromcdev);
- if (ret < 0)
- return ret;
- }
-
- if (eecd & E1000_EECD_I210_FLASH_DETECTED) {
- hw->mtd.dev.parent = hw->dev;
- hw->mtd._read = e1000_mtd_read;
- hw->mtd._write = e1000_mtd_write;
- hw->mtd._erase = e1000_mtd_erase;
- hw->mtd._lock = e1000_mtd_lock;
- hw->mtd._unlock = e1000_mtd_unlock;
- hw->mtd.size = eeprom->word_size * 2;
- hw->mtd.writesize = 1;
- hw->mtd.subpage_sft = 0;
-
- hw->mtd.eraseregions = xzalloc(sizeof(struct mtd_erase_region_info));
- hw->mtd.erasesize = SZ_4K;
- hw->mtd.eraseregions[0].erasesize = SZ_4K;
- hw->mtd.eraseregions[0].numblocks = hw->mtd.size / SZ_4K;
- hw->mtd.numeraseregions = 1;
-
- hw->mtd.flags = MTD_CAP_NORFLASH;
- hw->mtd.type = MTD_NORFLASH;
-
- ret = add_mtd_device(&hw->mtd, "e1000-nor",
- DEVICE_ID_DYNAMIC);
- if (ret)
- goto out_eeprom;
- }
-
- ret = e1000_register_invm(hw);
- if (ret < 0)
- goto out_mtd;
-
- return E1000_SUCCESS;
-
-out_mtd:
- if (eecd & E1000_EECD_I210_FLASH_DETECTED)
- del_mtd_device(&hw->mtd);
-out_eeprom:
- if (e1000_eeprom_valid(hw))
- devfs_remove(&hw->eepromcdev);
-
- return ret;
-}
diff --git a/drivers/net/e1000/mtd.c b/drivers/net/e1000/mtd.c
new file mode 100644
index 0000000000..93595cc88d
--- /dev/null
+++ b/drivers/net/e1000/mtd.c
@@ -0,0 +1,835 @@
+#include <common.h>
+#include <init.h>
+#include <malloc.h>
+#include <linux/math64.h>
+#include <linux/sizes.h>
+#include <of_device.h>
+#include <linux/pci.h>
+#include <linux/mtd/spi-nor.h>
+
+#include "e1000.h"
+
+static int32_t e1000_acquire_eeprom(struct e1000_hw *hw)
+{
+ if (hw->eeprom.acquire)
+ return hw->eeprom.acquire(hw);
+ else
+ return E1000_SUCCESS;
+}
+
+static void e1000_release_eeprom(struct e1000_hw *hw)
+{
+ if (hw->eeprom.release)
+ hw->eeprom.release(hw);
+}
+
+static int e1000_flash_mode_wait_for_idle(struct e1000_hw *hw)
+{
+ const int ret = e1000_poll_reg(hw, E1000_FLSWCTL, E1000_FLSWCTL_DONE,
+ E1000_FLSWCTL_DONE, SECOND);
+ if (ret < 0)
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set (wait)\n");
+ return ret;
+}
+
+static int e1000_flash_mode_check_command_valid(struct e1000_hw *hw)
+{
+ const uint32_t flswctl = e1000_read_reg(hw, E1000_FLSWCTL);
+ if (!(flswctl & E1000_FLSWCTL_CMDV)) {
+ dev_err(hw->dev, "FLSWCTL.CMDV was cleared\n");
+ return -EIO;
+ }
+
+ return E1000_SUCCESS;
+}
+
+static void e1000_flash_cmd(struct e1000_hw *hw,
+ uint32_t cmd, uint32_t offset)
+{
+ uint32_t flswctl = e1000_read_reg(hw, E1000_FLSWCTL);
+ flswctl &= ~E1000_FLSWCTL_CMD_ADDR_MASK;
+ flswctl |= E1000_FLSWCTL_CMD(cmd) | E1000_FLSWCTL_ADDR(offset);
+ e1000_write_reg(hw, E1000_FLSWCTL, flswctl);
+}
+
+static int e1000_flash_mode_read_chunk(struct e1000_hw *hw, loff_t offset,
+ size_t size, void *data)
+{
+ int ret;
+ size_t chunk, residue = size;
+ uint32_t flswdata;
+
+ DEBUGFUNC();
+
+ if (size > SZ_4K ||
+ E1000_FLSWCTL_ADDR(offset) != offset)
+ return -EINVAL;
+
+ ret = e1000_flash_mode_wait_for_idle(hw);
+ if (ret < 0)
+ return ret;
+
+ e1000_write_reg(hw, E1000_FLSWCNT, size);
+ e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_READ, offset);
+
+ do {
+ ret = e1000_flash_mode_check_command_valid(hw);
+ if (ret < 0)
+ return -EIO;
+
+ chunk = min(sizeof(flswdata), residue);
+
+ ret = e1000_poll_reg(hw, E1000_FLSWCTL,
+ E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
+ SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set (read)\n");
+ return ret;
+ }
+
+ flswdata = e1000_read_reg(hw, E1000_FLSWDATA);
+ /*
+ * Readl does le32_to_cpu, so we need to undo that
+ */
+ flswdata = cpu_to_le32(flswdata);
+ memcpy(data, &flswdata, chunk);
+
+ data += chunk;
+ residue -= chunk;
+ } while (residue);
+
+ return E1000_SUCCESS;
+}
+
+static int e1000_flash_mode_write_chunk(struct e1000_hw *hw, loff_t offset,
+ size_t size, const void *data)
+{
+ int ret;
+ size_t chunk, residue = size;
+ uint32_t flswdata;
+
+ if (size > 256 ||
+ E1000_FLSWCTL_ADDR(offset) != offset)
+ return -EINVAL;
+
+ ret = e1000_flash_mode_wait_for_idle(hw);
+ if (ret < 0)
+ return ret;
+
+
+ e1000_write_reg(hw, E1000_FLSWCNT, size);
+ e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_WRITE, offset);
+
+ do {
+ chunk = min(sizeof(flswdata), residue);
+ memcpy(&flswdata, data, chunk);
+ /*
+ * writel does cpu_to_le32, so we do the inverse in
+ * order to account for that
+ */
+ flswdata = le32_to_cpu(flswdata);
+ e1000_write_reg(hw, E1000_FLSWDATA, flswdata);
+
+ ret = e1000_flash_mode_check_command_valid(hw);
+ if (ret < 0)
+ return -EIO;
+
+ ret = e1000_poll_reg(hw, E1000_FLSWCTL,
+ E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
+ SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set (write)\n");
+ return ret;
+ }
+
+ data += chunk;
+ residue -= chunk;
+
+ } while (residue);
+
+ return E1000_SUCCESS;
+}
+
+static int e1000_flash_mode_erase_chunk(struct e1000_hw *hw, loff_t offset,
+ size_t size)
+{
+ int ret;
+
+ ret = e1000_flash_mode_wait_for_idle(hw);
+ if (ret < 0)
+ return ret;
+
+ if (!size && !offset)
+ e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_ERASE_DEVICE, 0);
+ else
+ e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_ERASE_SECTOR, offset);
+
+ ret = e1000_flash_mode_check_command_valid(hw);
+ if (ret < 0)
+ return -EIO;
+
+ ret = e1000_poll_reg(hw, E1000_FLSWCTL,
+ E1000_FLSWCTL_DONE | E1000_FLSWCTL_FLBUSY,
+ E1000_FLSWCTL_DONE,
+ 40 * SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set (erase)\n");
+ return ret;
+ }
+
+ return E1000_SUCCESS;
+}
+
+enum {
+ E1000_FLASH_MODE_OP_READ = 0,
+ E1000_FLASH_MODE_OP_WRITE = 1,
+ E1000_FLASH_MODE_OP_ERASE = 2,
+};
+
+
+static int e1000_flash_mode_io(struct e1000_hw *hw, int op, size_t granularity,
+ loff_t offset, size_t size, void *data)
+{
+ int ret;
+ size_t residue = size;
+
+ do {
+ const size_t chunk = min(granularity, residue);
+
+ switch (op) {
+ case E1000_FLASH_MODE_OP_READ:
+ ret = e1000_flash_mode_read_chunk(hw, offset,
+ chunk, data);
+ break;
+ case E1000_FLASH_MODE_OP_WRITE:
+ ret = e1000_flash_mode_write_chunk(hw, offset,
+ chunk, data);
+ break;
+ case E1000_FLASH_MODE_OP_ERASE:
+ ret = e1000_flash_mode_erase_chunk(hw, offset,
+ chunk);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ offset += chunk;
+ residue -= chunk;
+ data += chunk;
+ } while (residue);
+
+ return E1000_SUCCESS;
+}
+
+static int e1000_flash_mode_read(struct e1000_hw *hw, loff_t offset,
+ size_t size, void *data)
+{
+ return e1000_flash_mode_io(hw,
+ E1000_FLASH_MODE_OP_READ, SZ_4K,
+ offset, size, data);
+}
+
+static int e1000_flash_mode_write(struct e1000_hw *hw, loff_t offset,
+ size_t size, const void *data)
+{
+ int ret;
+
+ ret = e1000_flash_mode_io(hw,
+ E1000_FLASH_MODE_OP_WRITE, 256,
+ offset, size, (void *)data);
+ if (ret < 0)
+ return ret;
+
+ ret = e1000_poll_reg(hw, E1000_FLSWCTL,
+ E1000_FLSWCTL_FLBUSY,
+ 0, SECOND);
+ if (ret < 0)
+ dev_err(hw->dev, "Timout while waiting for FLSWCTL.FLBUSY\n");
+
+ return ret;
+}
+
+static int e1000_flash_mode_erase(struct e1000_hw *hw, loff_t offset,
+ size_t size)
+{
+ return e1000_flash_mode_io(hw,
+ E1000_FLASH_MODE_OP_ERASE, SZ_4K,
+ offset, size, NULL);
+}
+
+static ssize_t e1000_invm_cdev_read(struct cdev *cdev, void *buf,
+ size_t count, loff_t offset, unsigned long flags)
+{
+ uint8_t n, bnr;
+ uint32_t line;
+ size_t chunk, residue = count;
+ struct e1000_hw *hw = container_of(cdev, struct e1000_hw, invm.cdev);
+
+ n = offset / sizeof(line);
+ if (n > E1000_INVM_DATA_MAX_N)
+ return -EINVAL;
+
+ bnr = offset % sizeof(line);
+ if (bnr) {
+ /*
+ * if bnr in not zero it means we have a non 4-byte
+ * aligned start and need to do a partial read
+ */
+ const uint8_t *bptr;
+
+ bptr = (uint8_t *)&line + bnr;
+ chunk = min(bnr - sizeof(line), count);
+ line = e1000_read_reg(hw, E1000_INVM_DATA(n));
+ line = cpu_to_le32(line); /* to account for readl */
+ memcpy(buf, bptr, chunk);
+
+ goto start_adjusted;
+ }
+
+ do {
+ if (n > E1000_INVM_DATA_MAX_N)
+ return -EINVAL;
+
+ chunk = min(sizeof(line), residue);
+ line = e1000_read_reg(hw, E1000_INVM_DATA(n));
+ line = cpu_to_le32(line); /* to account for readl */
+
+ /*
+ * by using memcpy in conjunction with min should get
+ * dangling tail reads as well as aligned reads
+ */
+ memcpy(buf, &line, chunk);
+
+ start_adjusted:
+ residue -= chunk;
+ buf += chunk;
+ n++;
+ } while (residue);
+
+ return count;
+}
+
+static int e1000_invm_program(struct e1000_hw *hw, u32 offset, u32 value,
+ unsigned int delay)
+{
+ int retries = 400;
+ do {
+ if ((e1000_read_reg(hw, offset) & value) == value)
+ return E1000_SUCCESS;
+
+ e1000_write_reg(hw, offset, value);
+
+ if (delay) {
+ udelay(delay);
+ } else {
+ int ret;
+
+ if (e1000_read_reg(hw, E1000_INVM_PROTECT) &
+ E1000_INVM_PROTECT_WRITE_ERROR) {
+ dev_err(hw->dev, "Error while writing to %x\n", offset);
+ return -EIO;
+ }
+
+ ret = e1000_poll_reg(hw, E1000_INVM_PROTECT,
+ E1000_INVM_PROTECT_BUSY,
+ 0, SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout while waiting for INVM_PROTECT.BUSY\n");
+ return ret;
+ }
+ }
+ } while (retries--);
+
+ return -ETIMEDOUT;
+}
+
+static int e1000_invm_set_lock(struct param_d *param, void *priv)
+{
+ struct e1000_hw *hw = priv;
+
+ if (hw->invm.line > 31)
+ return -EINVAL;
+
+ return e1000_invm_program(hw,
+ E1000_INVM_LOCK(hw->invm.line),
+ E1000_INVM_LOCK_BIT,
+ 10);
+}
+
+static int e1000_invm_unlock(struct e1000_hw *hw)
+{
+ e1000_write_reg(hw, E1000_INVM_PROTECT, E1000_INVM_PROTECT_CODE);
+ /*
+ * If we were successful at unlocking iNVM for programming we
+ * should see ALLOW_WRITE bit toggle to 1
+ */
+ if (!(e1000_read_reg(hw, E1000_INVM_PROTECT) &
+ E1000_INVM_PROTECT_ALLOW_WRITE))
+ return -EIO;
+ else
+ return E1000_SUCCESS;
+}
+
+static void e1000_invm_lock(struct e1000_hw *hw)
+{
+ e1000_write_reg(hw, E1000_INVM_PROTECT, 0);
+}
+
+static int e1000_invm_write_prepare(struct e1000_hw *hw)
+{
+ int ret;
+ /*
+ * This needs to be done accorging to the datasheet p. 541 and
+ * p. 79
+ */
+ e1000_write_reg(hw, E1000_PCIEMISC,
+ E1000_PCIEMISC_RESERVED_PATTERN1 |
+ E1000_PCIEMISC_DMA_IDLE |
+ E1000_PCIEMISC_RESERVED_PATTERN2);
+
+ /*
+ * Needed for programming iNVM on devices with Flash with valid
+ * contents attached
+ */
+ ret = e1000_poll_reg(hw, E1000_EEMNGCTL,
+ E1000_EEMNGCTL_CFG_DONE,
+ E1000_EEMNGCTL_CFG_DONE, SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout while waiting for EEMNGCTL.CFG_DONE\n");
+ return ret;
+ }
+
+ udelay(15);
+
+ return E1000_SUCCESS;
+}
+
+static ssize_t e1000_invm_cdev_write(struct cdev *cdev, const void *buf,
+ size_t count, loff_t offset, unsigned long flags)
+{
+ int ret;
+ uint8_t n, bnr;
+ uint32_t line;
+ size_t chunk, residue = count;
+ struct e1000_hw *hw = container_of(cdev, struct e1000_hw, invm.cdev);
+
+ ret = e1000_invm_write_prepare(hw);
+ if (ret < 0)
+ return ret;
+
+ ret = e1000_invm_unlock(hw);
+ if (ret < 0)
+ goto exit;
+
+ n = offset / sizeof(line);
+ if (n > E1000_INVM_DATA_MAX_N) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ bnr = offset % sizeof(line);
+ if (bnr) {
+ uint8_t *bptr;
+ /*
+ * if bnr in not zero it means we have a non 4-byte
+ * aligned start and need to do a read-modify-write
+ * sequence
+ */
+
+ /* Read */
+ line = e1000_read_reg(hw, E1000_INVM_DATA(n));
+
+ /* Modify */
+ /*
+ * We need to ensure that line is LE32 in order for
+ * memcpy to copy byte from least significant to most
+ * significant, since that's how i210 will write the
+ * 32-bit word out to OTP
+ */
+ line = cpu_to_le32(line);
+ bptr = (uint8_t *)&line + bnr;
+ chunk = min(sizeof(line) - bnr, count);
+ memcpy(bptr, buf, chunk);
+ line = le32_to_cpu(line);
+
+ /* Jumping inside of the loop to take care of the
+ * Write */
+ goto start_adjusted;
+ }
+
+ do {
+ if (n > E1000_INVM_DATA_MAX_N) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ chunk = min(sizeof(line), residue);
+ if (chunk != sizeof(line)) {
+ /*
+ * If chunk is smaller that sizeof(line), which
+ * should be 4 bytes, we have a "dangling"
+ * chunk and we should read the unchanged
+ * portion of the 4-byte word from iNVM and do
+ * a read-modify-write sequence
+ */
+ line = e1000_read_reg(hw, E1000_INVM_DATA(n));
+ }
+
+ line = cpu_to_le32(line);
+ memcpy(&line, buf, chunk);
+ line = le32_to_cpu(line);
+
+ start_adjusted:
+ /*
+ * iNVM is organized in 32 64-bit lines and each of
+ * those lines can be locked to prevent any further
+ * modification, so for every i-th 32-bit word we need
+ * to check INVM_LINE[i/2] register to see if that word
+ * can be modified
+ */
+ if (e1000_read_reg(hw, E1000_INVM_LOCK(n / 2)) &
+ E1000_INVM_LOCK_BIT) {
+ dev_err(hw->dev, "line %d is locked\n", n / 2);
+ ret = -EIO;
+ goto exit;
+ }
+
+ ret = e1000_invm_program(hw,
+ E1000_INVM_DATA(n),
+ line,
+ 0);
+ if (ret < 0)
+ goto exit;
+
+ residue -= chunk;
+ buf += chunk;
+ n++;
+ } while (residue);
+
+ ret = E1000_SUCCESS;
+exit:
+ e1000_invm_lock(hw);
+ return ret;
+}
+
+static struct cdev_operations e1000_invm_ops = {
+ .read = e1000_invm_cdev_read,
+ .write = e1000_invm_cdev_write,
+};
+
+static ssize_t e1000_eeprom_cdev_read(struct cdev *cdev, void *buf,
+ size_t count, loff_t offset, unsigned long flags)
+{
+ struct e1000_hw *hw = container_of(cdev, struct e1000_hw, eepromcdev);
+ int32_t ret;
+
+ /*
+ * The eeprom interface works on 16 bit words which gives a nice excuse
+ * for being lazy and not implementing unaligned reads.
+ */
+ if (offset & 1 || count == 1)
+ return -EIO;
+
+ ret = e1000_read_eeprom(hw, offset / 2, count / 2, buf);
+ if (ret)
+ return -EIO;
+ else
+ return (count / 2) * 2;
+};
+
+static struct cdev_operations e1000_eeprom_ops = {
+ .read = e1000_eeprom_cdev_read,
+};
+
+static int e1000_mtd_read_or_write(bool read,
+ struct mtd_info *mtd, loff_t off, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ int ret;
+ struct e1000_hw *hw = container_of(mtd, struct e1000_hw, mtd);
+
+ DEBUGFUNC();
+
+ if (e1000_acquire_eeprom(hw) == E1000_SUCCESS) {
+ if (read)
+ ret = e1000_flash_mode_read(hw, off,
+ len, buf);
+ else
+ ret = e1000_flash_mode_write(hw, off,
+ len, buf);
+ if (ret == E1000_SUCCESS)
+ *retlen = len;
+
+ e1000_release_eeprom(hw);
+ } else {
+ ret = -E1000_ERR_EEPROM;
+ }
+
+ return ret;
+
+}
+
+static int e1000_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ return e1000_mtd_read_or_write(true,
+ mtd, from, len, retlen, buf);
+}
+
+static int e1000_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ return e1000_mtd_read_or_write(false,
+ mtd, to, len, retlen, (u_char *)buf);
+}
+
+static int e1000_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ uint32_t rem;
+ struct e1000_hw *hw = container_of(mtd, struct e1000_hw, mtd);
+ int ret;
+
+ div_u64_rem(instr->len, mtd->erasesize, &rem);
+ if (rem)
+ return -EINVAL;
+
+ ret = e1000_acquire_eeprom(hw);
+ if (ret != E1000_SUCCESS)
+ goto fail;
+
+ /*
+ * If mtd->size is 4096 it means we are dealing with
+ * unprogrammed flash and we don't really know its size to
+ * make an informed decision wheither to erase the whole chip or
+ * just a number of its sectors
+ */
+ if (mtd->size > SZ_4K &&
+ instr->len == mtd->size)
+ ret = e1000_flash_mode_erase(hw, 0, 0);
+ else
+ ret = e1000_flash_mode_erase(hw,
+ instr->addr, instr->len);
+
+ e1000_release_eeprom(hw);
+
+ if (ret < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int e1000_mtd_sr_rmw(struct mtd_info *mtd, u8 mask, u8 val)
+{
+ struct e1000_hw *hw = container_of(mtd, struct e1000_hw, mtd);
+ uint32_t flswdata;
+ int ret;
+
+ ret = e1000_flash_mode_wait_for_idle(hw);
+ if (ret < 0)
+ return ret;
+
+ e1000_write_reg(hw, E1000_FLSWCNT, 1);
+ e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_RDSR, 0);
+
+ ret = e1000_flash_mode_check_command_valid(hw);
+ if (ret < 0)
+ return -EIO;
+
+ ret = e1000_poll_reg(hw, E1000_FLSWCTL,
+ E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
+ SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set (RDSR)\n");
+ return ret;
+ }
+
+ flswdata = e1000_read_reg(hw, E1000_FLSWDATA);
+
+ flswdata = (flswdata & ~mask) | val;
+
+ e1000_write_reg(hw, E1000_FLSWCNT, 1);
+ e1000_flash_cmd(hw, E1000_FLSWCTL_CMD_WRSR, 0);
+
+ ret = e1000_flash_mode_check_command_valid(hw);
+ if (ret < 0)
+ return -EIO;
+
+ e1000_write_reg(hw, E1000_FLSWDATA, flswdata);
+
+ ret = e1000_poll_reg(hw, E1000_FLSWCTL,
+ E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
+ SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set (WRSR)\n");
+ }
+
+ return ret;
+}
+
+/*
+ * The available spi nor devices are very different in how the block protection
+ * bits affect which sectors to be protected. So take the simple approach and
+ * only use BP[012] = b000 (unprotected) and BP[012] = b111 (protected).
+ */
+#define SR_BPALL (SR_BP0 | SR_BP1 | SR_BP2)
+
+static int e1000_mtd_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ return e1000_mtd_sr_rmw(mtd, SR_BPALL, SR_BPALL);
+}
+
+static int e1000_mtd_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ return e1000_mtd_sr_rmw(mtd, SR_BPALL, 0x0);
+}
+
+static int e1000_register_invm(struct e1000_hw *hw)
+{
+ int ret;
+ u16 word;
+ struct param_d *p;
+
+ if (e1000_eeprom_valid(hw)) {
+ ret = e1000_read_eeprom(hw, 0x0a, 1, &word);
+ if (ret < 0)
+ return ret;
+
+ if (word & (1 << 15))
+ dev_warn(hw->dev, "iNVM lockout mechanism is active\n");
+ }
+
+ hw->invm.cdev.dev = hw->dev;
+ hw->invm.cdev.ops = &e1000_invm_ops;
+ hw->invm.cdev.priv = hw;
+ hw->invm.cdev.name = xasprintf("e1000-invm%d", hw->dev->id);
+ hw->invm.cdev.size = 4 * (E1000_INVM_DATA_MAX_N + 1);
+
+ ret = devfs_create(&hw->invm.cdev);
+ if (ret < 0)
+ return ret;
+
+ dev_set_name(&hw->invm.dev, "invm");
+ hw->invm.dev.id = hw->dev->id;
+ hw->invm.dev.parent = hw->dev;
+ ret = register_device(&hw->invm.dev);
+ if (ret < 0) {
+ devfs_remove(&hw->invm.cdev);
+ return ret;
+ }
+
+ p = dev_add_param_int(&hw->invm.dev, "lock", e1000_invm_set_lock,
+ NULL, &hw->invm.line, "%u", hw);
+ if (IS_ERR(p)) {
+ unregister_device(&hw->invm.dev);
+ devfs_remove(&hw->invm.cdev);
+ ret = PTR_ERR(p);
+ }
+
+ return ret;
+}
+
+/*
+ * This function has a wrong name for historic reasons, it doesn't add an
+ * eeprom, but the flash (if available) that is used to simulate the eeprom.
+ * Also a device that represents the invm is registered here (if available).
+ */
+int e1000_register_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd;
+ int ret;
+
+ if (hw->mac_type != e1000_igb)
+ return E1000_SUCCESS;
+
+ eecd = e1000_read_reg(hw, E1000_EECD);
+
+ if (eecd & E1000_EECD_AUTO_RD) {
+ if (eecd & E1000_EECD_EE_PRES) {
+ if (eecd & E1000_EECD_FLASH_IN_USE) {
+ uint32_t fla = e1000_read_reg(hw, E1000_FLA);
+ dev_info(hw->dev,
+ "Hardware programmed from flash (%ssecure)\n",
+ fla & E1000_FLA_LOCKED ? "" : "un");
+ } else {
+ dev_info(hw->dev, "Hardware programmed from iNVM\n");
+ }
+ } else {
+ dev_warn(hw->dev, "Shadow RAM invalid\n");
+ }
+ } else {
+ /*
+ * I never saw this case in practise and I'm unsure how
+ * to handle that. Maybe just wait until the hardware is
+ * up enough that this bit is set?
+ */
+ dev_err(hw->dev, "Flash Auto-Read not done\n");
+ }
+
+ if (e1000_eeprom_valid(hw)) {
+ hw->eepromcdev.dev = hw->dev;
+ hw->eepromcdev.ops = &e1000_eeprom_ops;
+ hw->eepromcdev.name = xasprintf("e1000-eeprom%d",
+ hw->dev->id);
+ hw->eepromcdev.size = 0x1000;
+
+ ret = devfs_create(&hw->eepromcdev);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (eecd & E1000_EECD_I210_FLASH_DETECTED) {
+ hw->mtd.dev.parent = hw->dev;
+ hw->mtd._read = e1000_mtd_read;
+ hw->mtd._write = e1000_mtd_write;
+ hw->mtd._erase = e1000_mtd_erase;
+ hw->mtd._lock = e1000_mtd_lock;
+ hw->mtd._unlock = e1000_mtd_unlock;
+ hw->mtd.size = eeprom->word_size * 2;
+ hw->mtd.writesize = 1;
+ hw->mtd.subpage_sft = 0;
+
+ hw->mtd.eraseregions = xzalloc(sizeof(struct mtd_erase_region_info));
+ hw->mtd.erasesize = SZ_4K;
+ hw->mtd.eraseregions[0].erasesize = SZ_4K;
+ hw->mtd.eraseregions[0].numblocks = hw->mtd.size / SZ_4K;
+ hw->mtd.numeraseregions = 1;
+
+ hw->mtd.flags = MTD_CAP_NORFLASH;
+ hw->mtd.type = MTD_NORFLASH;
+
+ ret = add_mtd_device(&hw->mtd, "e1000-nor",
+ DEVICE_ID_DYNAMIC);
+ if (ret)
+ goto out_eeprom;
+ }
+
+ ret = e1000_register_invm(hw);
+ if (ret < 0)
+ goto out_mtd;
+
+ return E1000_SUCCESS;
+
+out_mtd:
+ if (eecd & E1000_EECD_I210_FLASH_DETECTED)
+ del_mtd_device(&hw->mtd);
+out_eeprom:
+ if (e1000_eeprom_valid(hw))
+ devfs_remove(&hw->eepromcdev);
+
+ return ret;
+}
diff --git a/drivers/net/virtio.c b/drivers/net/virtio.c
new file mode 100644
index 0000000000..ea4d552903
--- /dev/null
+++ b/drivers/net/virtio.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <net.h>
+#include <init.h>
+#include <net.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ring.h>
+#include <uapi/linux/virtio_net.h>
+
+/* Amount of buffers to keep in the RX virtqueue */
+#define VIRTIO_NET_NUM_RX_BUFS 32
+
+/*
+ * This value comes from the VirtIO spec: 1500 for maximum packet size,
+ * 14 for the Ethernet header, 12 for virtio_net_hdr. In total 1526 bytes.
+ */
+#define VIRTIO_NET_RX_BUF_SIZE 1526
+
+struct virtio_net_priv {
+ union {
+ struct virtqueue *vqs[2];
+ struct {
+ struct virtqueue *rx_vq;
+ struct virtqueue *tx_vq;
+ };
+ };
+
+ char rx_buff[VIRTIO_NET_NUM_RX_BUFS][VIRTIO_NET_RX_BUF_SIZE];
+ bool rx_running;
+ int net_hdr_len;
+ struct eth_device edev;
+ struct virtio_device *vdev;
+};
+
+static inline struct virtio_net_priv *to_priv(struct eth_device *edev)
+{
+ return container_of(edev, struct virtio_net_priv, edev);
+}
+
+static int virtio_net_start(struct eth_device *edev)
+{
+ struct virtio_net_priv *priv = to_priv(edev);
+ struct virtio_sg sg;
+ struct virtio_sg *sgs[] = { &sg };
+ int i;
+
+ if (!priv->rx_running) {
+ /* receive buffer length is always 1526 */
+ sg.length = VIRTIO_NET_RX_BUF_SIZE;
+
+ /* setup the receive buffer address */
+ for (i = 0; i < VIRTIO_NET_NUM_RX_BUFS; i++) {
+ sg.addr = priv->rx_buff[i];
+ virtqueue_add(priv->rx_vq, sgs, 0, 1);
+ }
+
+ virtqueue_kick(priv->rx_vq);
+
+ /* setup the receive queue only once */
+ priv->rx_running = true;
+ }
+
+ return 0;
+}
+
+static int virtio_net_send(struct eth_device *edev, void *packet, int length)
+{
+ struct virtio_net_priv *priv = to_priv(edev);
+ struct virtio_net_hdr_v1 hdr_v1;
+ struct virtio_net_hdr hdr;
+ struct virtio_sg hdr_sg;
+ struct virtio_sg data_sg = { packet, length };
+ struct virtio_sg *sgs[] = { &hdr_sg, &data_sg };
+ int ret;
+
+ if (priv->net_hdr_len == sizeof(struct virtio_net_hdr))
+ hdr_sg.addr = &hdr;
+ else
+ hdr_sg.addr = &hdr_v1;
+
+ hdr_sg.length = priv->net_hdr_len;
+ memset(hdr_sg.addr, 0, priv->net_hdr_len);
+
+ ret = virtqueue_add(priv->tx_vq, sgs, 2, 0);
+ if (ret)
+ return ret;
+
+ virtqueue_kick(priv->tx_vq);
+
+ while (1) {
+ if (virtqueue_get_buf(priv->tx_vq, NULL))
+ break;
+ }
+
+ return 0;
+}
+
+static int virtio_net_recv(struct eth_device *edev)
+{
+ struct virtio_net_priv *priv = to_priv(edev);
+ struct virtio_sg sg;
+ struct virtio_sg *sgs[] = { &sg };
+ unsigned int len;
+ void *buf;
+
+ sg.addr = virtqueue_get_buf(priv->rx_vq, &len);
+ if (!sg.addr)
+ return -EAGAIN;
+
+ sg.length = VIRTIO_NET_RX_BUF_SIZE;
+
+ buf = sg.addr + priv->net_hdr_len;
+ len -= priv->net_hdr_len;
+
+ net_receive(edev, buf, len);
+
+ /* Put the buffer back to the rx ring */
+ virtqueue_add(priv->rx_vq, sgs, 0, 1);
+
+ return 0;
+}
+
+static void virtio_net_stop(struct eth_device *dev)
+{
+ /*
+ * There is no way to stop the queue from running, unless we issue
+ * a reset to the virtio device, and re-do the queue initialization
+ * from the beginning.
+ */
+}
+
+static int virtio_net_write_hwaddr(struct eth_device *edev, const unsigned char *adr)
+{
+ struct virtio_net_priv *priv = to_priv(edev);
+ int i;
+
+ /*
+ * v1.0 compliant device's MAC address is set through control channel,
+ * which we don't support for now.
+ */
+ if (virtio_has_feature(priv->vdev, VIRTIO_F_VERSION_1))
+ return -ENOSYS;
+
+ for (i = 0; i < 6; i++)
+ virtio_cwrite8(priv->vdev, offsetof(struct virtio_net_config, mac) + i, adr[i]);
+
+ return 0;
+}
+
+static int virtio_net_read_rom_hwaddr(struct eth_device *edev, unsigned char *adr)
+{
+ struct virtio_net_priv *priv = to_priv(edev);
+
+ virtio_cread_bytes(priv->vdev, offsetof(struct virtio_net_config, mac), adr, 6);
+
+ return 0;
+}
+
+static int virtio_net_probe(struct virtio_device *vdev)
+{
+ struct virtio_net_priv *priv;
+ struct eth_device *edev;
+ int ret;
+
+ priv = xzalloc(sizeof(*priv));
+
+ vdev->priv = priv;
+
+ /*
+ * For v1.0 compliant device, it always assumes the member
+ * 'num_buffers' exists in the struct virtio_net_hdr while
+ * the legacy driver only presented 'num_buffers' when
+ * VIRTIO_NET_F_MRG_RXBUF was negotiated. Without that feature
+ * the structure was 2 bytes shorter.
+ */
+ if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+ priv->net_hdr_len = sizeof(struct virtio_net_hdr_v1);
+ else
+ priv->net_hdr_len = sizeof(struct virtio_net_hdr);
+
+ ret = virtio_find_vqs(vdev, 2, priv->vqs);
+ if (ret < 0)
+ return ret;
+
+ priv->vdev = vdev;
+
+ edev = &priv->edev;
+ edev->priv = priv;
+ edev->parent = &vdev->dev;
+
+ edev->open = virtio_net_start;
+ edev->send = virtio_net_send;
+ edev->recv = virtio_net_recv;
+ edev->halt = virtio_net_stop;
+ edev->get_ethaddr = virtio_net_read_rom_hwaddr;
+ edev->set_ethaddr = virtio_net_write_hwaddr;
+
+ return eth_register(edev);
+}
+
+static void virtio_net_remove(struct virtio_device *vdev)
+{
+ struct virtio_net_priv *priv = vdev->priv;
+
+ vdev->config->reset(vdev);
+ eth_unregister(&priv->edev);
+ vdev->config->del_vqs(vdev);
+
+ free(priv);
+}
+
+/*
+ * For simplicity, the driver only negotiates the VIRTIO_NET_F_MAC feature.
+ * For the VIRTIO_NET_F_STATUS feature, we don't negotiate it, hence per spec
+ * we should assume the link is always active.
+ */
+static const u32 features[] = {
+ VIRTIO_NET_F_MAC
+};
+
+static const struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_net = {
+ .driver.name = "virtio_net",
+ .id_table = id_table,
+ .probe = virtio_net_probe,
+ .remove = virtio_net_remove,
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
+ .feature_table_legacy = features,
+ .feature_table_size_legacy = ARRAY_SIZE(features),
+};
+device_virtio_driver(virtio_net);
diff --git a/drivers/net/xgmac.c b/drivers/net/xgmac.c
deleted file mode 100644
index 136d788043..0000000000
--- a/drivers/net/xgmac.c
+++ /dev/null
@@ -1,734 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright 2010-2011 Calxeda, Inc.
- */
-
-#include <common.h>
-#include <dma.h>
-#include <net.h>
-#include <clock.h>
-#include <malloc.h>
-#include <xfuncs.h>
-#include <init.h>
-#include <errno.h>
-#include <io.h>
-#include <linux/err.h>
-
-#define TX_NUM_DESC 1
-#define RX_NUM_DESC 32
-
-#define ETH_BUF_SZ 2048
-#define TX_BUF_SZ (ETH_BUF_SZ * TX_NUM_DESC)
-#define RX_BUF_SZ (ETH_BUF_SZ * RX_NUM_DESC)
-
-/* XGMAC Register definitions */
-#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */
-#define XGMAC_FRAME_FILTER 0x00000004 /* MAC Frame Filter */
-#define XGMAC_FLOW_CTRL 0x00000018 /* MAC Flow Control */
-#define XGMAC_VLAN_TAG 0x0000001C /* VLAN Tags */
-#define XGMAC_VERSION 0x00000020 /* Version */
-#define XGMAC_VLAN_INCL 0x00000024 /* VLAN tag for tx frames */
-#define XGMAC_LPI_CTRL 0x00000028 /* LPI Control and Status */
-#define XGMAC_LPI_TIMER 0x0000002C /* LPI Timers Control */
-#define XGMAC_TX_PACE 0x00000030 /* Transmit Pace and Stretch */
-#define XGMAC_VLAN_HASH 0x00000034 /* VLAN Hash Table */
-#define XGMAC_DEBUG 0x00000038 /* Debug */
-#define XGMAC_INT_STAT 0x0000003C /* Interrupt and Control */
-#define XGMAC_ADDR_HIGH(reg) (0x00000040 + ((reg) * 8))
-#define XGMAC_ADDR_LOW(reg) (0x00000044 + ((reg) * 8))
-#define XGMAC_HASH(n) (0x00000300 + (n) * 4) /* HASH table regs */
-#define XGMAC_NUM_HASH 16
-#define XGMAC_OMR 0x00000400
-#define XGMAC_REMOTE_WAKE 0x00000700 /* Remote Wake-Up Frm Filter */
-#define XGMAC_PMT 0x00000704 /* PMT Control and Status */
-#define XGMAC_MMC_CTRL 0x00000800 /* XGMAC MMC Control */
-#define XGMAC_MMC_INTR_RX 0x00000804 /* Recieve Interrupt */
-#define XGMAC_MMC_INTR_TX 0x00000808 /* Transmit Interrupt */
-#define XGMAC_MMC_INTR_MASK_RX 0x0000080c /* Recieve Interrupt Mask */
-#define XGMAC_MMC_INTR_MASK_TX 0x00000810 /* Transmit Interrupt Mask */
-
-
-/* Hardware TX Statistics Counters */
-#define XGMAC_MMC_TXOCTET_GB_LO 0x00000814
-#define XGMAC_MMC_TXOCTET_GB_HI 0x00000818
-#define XGMAC_MMC_TXFRAME_GB_LO 0x0000081C
-#define XGMAC_MMC_TXFRAME_GB_HI 0x00000820
-#define XGMAC_MMC_TXBCFRAME_G 0x00000824
-#define XGMAC_MMC_TXMCFRAME_G 0x0000082C
-#define XGMAC_MMC_TXUCFRAME_GB 0x00000864
-#define XGMAC_MMC_TXMCFRAME_GB 0x0000086C
-#define XGMAC_MMC_TXBCFRAME_GB 0x00000874
-#define XGMAC_MMC_TXUNDERFLOW 0x0000087C
-#define XGMAC_MMC_TXOCTET_G_LO 0x00000884
-#define XGMAC_MMC_TXOCTET_G_HI 0x00000888
-#define XGMAC_MMC_TXFRAME_G_LO 0x0000088C
-#define XGMAC_MMC_TXFRAME_G_HI 0x00000890
-#define XGMAC_MMC_TXPAUSEFRAME 0x00000894
-#define XGMAC_MMC_TXVLANFRAME 0x0000089C
-
-/* Hardware RX Statistics Counters */
-#define XGMAC_MMC_RXFRAME_GB_LO 0x00000900
-#define XGMAC_MMC_RXFRAME_GB_HI 0x00000904
-#define XGMAC_MMC_RXOCTET_GB_LO 0x00000908
-#define XGMAC_MMC_RXOCTET_GB_HI 0x0000090C
-#define XGMAC_MMC_RXOCTET_G_LO 0x00000910
-#define XGMAC_MMC_RXOCTET_G_HI 0x00000914
-#define XGMAC_MMC_RXBCFRAME_G 0x00000918
-#define XGMAC_MMC_RXMCFRAME_G 0x00000920
-#define XGMAC_MMC_RXCRCERR 0x00000928
-#define XGMAC_MMC_RXRUNT 0x00000930
-#define XGMAC_MMC_RXJABBER 0x00000934
-#define XGMAC_MMC_RXUCFRAME_G 0x00000970
-#define XGMAC_MMC_RXLENGTHERR 0x00000978
-#define XGMAC_MMC_RXPAUSEFRAME 0x00000988
-#define XGMAC_MMC_RXOVERFLOW 0x00000990
-#define XGMAC_MMC_RXVLANFRAME 0x00000998
-#define XGMAC_MMC_RXWATCHDOG 0x000009a0
-
-/* DMA Control and Status Registers */
-#define XGMAC_DMA_BUS_MODE 0x00000f00 /* Bus Mode */
-#define XGMAC_DMA_TX_POLL 0x00000f04 /* Transmit Poll Demand */
-#define XGMAC_DMA_RX_POLL 0x00000f08 /* Received Poll Demand */
-#define XGMAC_DMA_RX_BASE_ADDR 0x00000f0c /* Receive List Base */
-#define XGMAC_DMA_TX_BASE_ADDR 0x00000f10 /* Transmit List Base */
-#define XGMAC_DMA_STATUS 0x00000f14 /* Status Register */
-#define XGMAC_DMA_CONTROL 0x00000f18 /* Ctrl (Operational Mode) */
-#define XGMAC_DMA_INTR_ENA 0x00000f1c /* Interrupt Enable */
-#define XGMAC_DMA_MISS_FRAME_CTR 0x00000f20 /* Missed Frame Counter */
-#define XGMAC_DMA_RI_WDOG_TIMER 0x00000f24 /* RX Intr Watchdog Timer */
-#define XGMAC_DMA_AXI_BUS 0x00000f28 /* AXI Bus Mode */
-#define XGMAC_DMA_AXI_STATUS 0x00000f2C /* AXI Status */
-#define XGMAC_DMA_HW_FEATURE 0x00000f58 /* Enabled Hardware Features */
-
-#define XGMAC_ADDR_AE 0x80000000
-#define XGMAC_MAX_FILTER_ADDR 31
-
-/* PMT Control and Status */
-#define XGMAC_PMT_POINTER_RESET 0x80000000
-#define XGMAC_PMT_GLBL_UNICAST 0x00000200
-#define XGMAC_PMT_WAKEUP_RX_FRM 0x00000040
-#define XGMAC_PMT_MAGIC_PKT 0x00000020
-#define XGMAC_PMT_WAKEUP_FRM_EN 0x00000004
-#define XGMAC_PMT_MAGIC_PKT_EN 0x00000002
-#define XGMAC_PMT_POWERDOWN 0x00000001
-
-#define XGMAC_CONTROL_SPD 0x40000000 /* Speed control */
-#define XGMAC_CONTROL_SPD_MASK 0x60000000
-#define XGMAC_CONTROL_SPD_1G 0x60000000
-#define XGMAC_CONTROL_SPD_2_5G 0x40000000
-#define XGMAC_CONTROL_SPD_10G 0x00000000
-#define XGMAC_CONTROL_SARC 0x10000000 /* Source Addr Insert/Replace */
-#define XGMAC_CONTROL_SARK_MASK 0x18000000
-#define XGMAC_CONTROL_CAR 0x04000000 /* CRC Addition/Replacement */
-#define XGMAC_CONTROL_CAR_MASK 0x06000000
-#define XGMAC_CONTROL_DP 0x01000000 /* Disable Padding */
-#define XGMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on rx */
-#define XGMAC_CONTROL_JD 0x00400000 /* Jabber disable */
-#define XGMAC_CONTROL_JE 0x00100000 /* Jumbo frame */
-#define XGMAC_CONTROL_LM 0x00001000 /* Loop-back mode */
-#define XGMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
-#define XGMAC_CONTROL_ACS 0x00000080 /* Automatic Pad/FCS Strip */
-#define XGMAC_CONTROL_DDIC 0x00000010 /* Disable Deficit Idle Count */
-#define XGMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
-#define XGMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
-
-/* XGMAC Frame Filter defines */
-#define XGMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
-#define XGMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */
-#define XGMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */
-#define XGMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */
-#define XGMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */
-#define XGMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */
-#define XGMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
-#define XGMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
-#define XGMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
-#define XGMAC_FRAME_FILTER_VHF 0x00000800 /* VLAN Hash Filter */
-#define XGMAC_FRAME_FILTER_VPF 0x00001000 /* VLAN Perfect Filter */
-#define XGMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
-
-#define FIFO_MINUS_1K 0x0
-#define FIFO_MINUS_2K 0x1
-#define FIFO_MINUS_3K 0x2
-#define FIFO_MINUS_4K 0x3
-#define FIFO_MINUS_6K 0x4
-#define FIFO_MINUS_8K 0x5
-#define FIFO_MINUS_12K 0x6
-#define FIFO_MINUS_16K 0x7
-
-/* XGMAC FLOW CTRL defines */
-#define XGMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
-#define XGMAC_FLOW_CTRL_PT_SHIFT 16
-#define XGMAC_FLOW_CTRL_DZQP 0x00000080 /* Disable Zero-Quanta Phase */
-#define XGMAC_FLOW_CTRL_PLT 0x00000020 /* Pause Low Threshhold */
-#define XGMAC_FLOW_CTRL_PLT_SHIFT 4
-#define XGMAC_FLOW_CTRL_PLT_MASK 0x00000030 /* PLT MASK */
-#define XGMAC_FLOW_CTRL_UP 0x00000008 /* Unicast Pause Frame Detect */
-#define XGMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
-#define XGMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
-#define XGMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
-
-/* XGMAC_INT_STAT reg */
-#define XGMAC_INT_STAT_PMT 0x0080 /* PMT Interrupt Status */
-#define XGMAC_INT_STAT_LPI 0x0040 /* LPI Interrupt Status */
-
-/* DMA Bus Mode register defines */
-#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
-#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
-#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
-#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
-
-/* Programmable burst length */
-#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
-#define DMA_BUS_MODE_PBL_SHIFT 8
-#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */
-#define DMA_BUS_MODE_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */
-#define DMA_BUS_MODE_RPBL_SHIFT 17
-#define DMA_BUS_MODE_USP 0x00800000
-#define DMA_BUS_MODE_8PBL 0x01000000
-#define DMA_BUS_MODE_AAL 0x02000000
-
-#define DMA_AXIMODE_ENLPI 0x80000000
-#define DMA_AXIMODE_MGK 0x40000000
-#define DMA_AXIMODE_WROSR 0x00100000
-#define DMA_AXIMODE_WROSR_MASK 0x00F00000
-#define DMA_AXIMODE_WROSR_SHIFT 20
-#define DMA_AXIMODE_RDOSR 0x00010000
-#define DMA_AXIMODE_RDOSR_MASK 0x000F0000
-#define DMA_AXIMODE_RDOSR_SHIFT 16
-#define DMA_AXIMODE_AAL 0x00001000
-#define DMA_AXIMODE_BLEN256 0x00000080
-#define DMA_AXIMODE_BLEN128 0x00000040
-#define DMA_AXIMODE_BLEN64 0x00000020
-#define DMA_AXIMODE_BLEN32 0x00000010
-#define DMA_AXIMODE_BLEN16 0x00000008
-#define DMA_AXIMODE_BLEN8 0x00000004
-#define DMA_AXIMODE_BLEN4 0x00000002
-#define DMA_AXIMODE_UNDEF 0x00000001
-
-/* DMA Bus Mode register defines */
-#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */
-#define DMA_BUS_PR_RATIO_SHIFT 14
-#define DMA_BUS_FB 0x00010000 /* Fixed Burst */
-
-/* DMA Control register defines */
-#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
-#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
-#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */
-
-/* DMA Normal interrupt */
-#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */
-#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */
-#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */
-#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */
-#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */
-#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */
-#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */
-#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */
-#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */
-#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */
-#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */
-#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */
-#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavail */
-#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */
-#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */
-
-#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
- DMA_INTR_ENA_TUE)
-
-#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
- DMA_INTR_ENA_RWE | DMA_INTR_ENA_RSE | \
- DMA_INTR_ENA_RUE | DMA_INTR_ENA_UNE | \
- DMA_INTR_ENA_OVE | DMA_INTR_ENA_TJE | \
- DMA_INTR_ENA_TSE)
-
-/* DMA default interrupt mask */
-#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
-
-/* DMA Status register defines */
-#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
-#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
-#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
-#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
-#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
-#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
-#define DMA_STATUS_TS_SHIFT 20
-#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
-#define DMA_STATUS_RS_SHIFT 17
-#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
-#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
-#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
-#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
-#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
-#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
-#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
-#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
-#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
-#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
-#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
-#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
-#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavail */
-#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
-#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
-
-/* Common MAC defines */
-#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
-#define MAC_ENABLE_RX 0x00000004 /* Receiver Enable */
-
-/* XGMAC Operation Mode Register */
-#define XGMAC_OMR_TSF 0x00200000 /* TX FIFO Store and Forward */
-#define XGMAC_OMR_FTF 0x00100000 /* Flush Transmit FIFO */
-#define XGMAC_OMR_TTC 0x00020000 /* Transmit Threshhold Ctrl */
-#define XGMAC_OMR_TTC_SHIFT 16
-#define XGMAC_OMR_TTC_MASK 0x00030000
-#define XGMAC_OMR_RFD 0x00006000 /* FC Deactivation Threshhold */
-#define XGMAC_OMR_RFD_SHIFT 12
-#define XGMAC_OMR_RFD_MASK 0x00007000 /* FC Deact Threshhold MASK */
-#define XGMAC_OMR_RFA 0x00000600 /* FC Activation Threshhold */
-#define XGMAC_OMR_RFA_SHIFT 9
-#define XGMAC_OMR_RFA_MASK 0x00000E00 /* FC Act Threshhold MASK */
-#define XGMAC_OMR_EFC 0x00000100 /* Enable Hardware FC */
-#define XGMAC_OMR_FEF 0x00000080 /* Forward Error Frames */
-#define XGMAC_OMR_DT 0x00000040 /* Drop TCP/IP csum Errors */
-#define XGMAC_OMR_RSF 0x00000020 /* RX FIFO Store and Forward */
-#define XGMAC_OMR_RTC_256 0x00000018 /* RX Threshhold Ctrl */
-#define XGMAC_OMR_RTC_MASK 0x00000018 /* RX Threshhold Ctrl MASK */
-
-/* XGMAC HW Features Register */
-#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* TX Checksum offload */
-
-#define XGMAC_MMC_CTRL_CNT_FRZ 0x00000008
-
-/* XGMAC Descriptor Defines */
-#define MAX_DESC_BUF_SZ (0x2000 - 8)
-
-#define RXDESC_EXT_STATUS 0x00000001
-#define RXDESC_CRC_ERR 0x00000002
-#define RXDESC_RX_ERR 0x00000008
-#define RXDESC_RX_WDOG 0x00000010
-#define RXDESC_FRAME_TYPE 0x00000020
-#define RXDESC_GIANT_FRAME 0x00000080
-#define RXDESC_LAST_SEG 0x00000100
-#define RXDESC_FIRST_SEG 0x00000200
-#define RXDESC_VLAN_FRAME 0x00000400
-#define RXDESC_OVERFLOW_ERR 0x00000800
-#define RXDESC_LENGTH_ERR 0x00001000
-#define RXDESC_SA_FILTER_FAIL 0x00002000
-#define RXDESC_DESCRIPTOR_ERR 0x00004000
-#define RXDESC_ERROR_SUMMARY 0x00008000
-#define RXDESC_FRAME_LEN_OFFSET 16
-#define RXDESC_FRAME_LEN_MASK 0x3fff0000
-#define RXDESC_DA_FILTER_FAIL 0x40000000
-
-#define RXDESC1_END_RING 0x00008000
-
-#define RXDESC_IP_PAYLOAD_MASK 0x00000003
-#define RXDESC_IP_PAYLOAD_UDP 0x00000001
-#define RXDESC_IP_PAYLOAD_TCP 0x00000002
-#define RXDESC_IP_PAYLOAD_ICMP 0x00000003
-#define RXDESC_IP_HEADER_ERR 0x00000008
-#define RXDESC_IP_PAYLOAD_ERR 0x00000010
-#define RXDESC_IPV4_PACKET 0x00000040
-#define RXDESC_IPV6_PACKET 0x00000080
-#define TXDESC_UNDERFLOW_ERR 0x00000001
-#define TXDESC_JABBER_TIMEOUT 0x00000002
-#define TXDESC_LOCAL_FAULT 0x00000004
-#define TXDESC_REMOTE_FAULT 0x00000008
-#define TXDESC_VLAN_FRAME 0x00000010
-#define TXDESC_FRAME_FLUSHED 0x00000020
-#define TXDESC_IP_HEADER_ERR 0x00000040
-#define TXDESC_PAYLOAD_CSUM_ERR 0x00000080
-#define TXDESC_ERROR_SUMMARY 0x00008000
-#define TXDESC_SA_CTRL_INSERT 0x00040000
-#define TXDESC_SA_CTRL_REPLACE 0x00080000
-#define TXDESC_2ND_ADDR_CHAINED 0x00100000
-#define TXDESC_END_RING 0x00200000
-#define TXDESC_CSUM_IP 0x00400000
-#define TXDESC_CSUM_IP_PAYLD 0x00800000
-#define TXDESC_CSUM_ALL 0x00C00000
-#define TXDESC_CRC_EN_REPLACE 0x01000000
-#define TXDESC_CRC_EN_APPEND 0x02000000
-#define TXDESC_DISABLE_PAD 0x04000000
-#define TXDESC_FIRST_SEG 0x10000000
-#define TXDESC_LAST_SEG 0x20000000
-#define TXDESC_INTERRUPT 0x40000000
-
-#define DESC_OWN 0x80000000
-#define DESC_BUFFER1_SZ_MASK 0x00001fff
-#define DESC_BUFFER2_SZ_MASK 0x1fff0000
-#define DESC_BUFFER2_SZ_OFFSET 16
-
-struct xgmac_dma_desc {
- __le32 flags;
- __le32 buf_size;
- __le32 buf1_addr; /* Buffer 1 Address Pointer */
- __le32 buf2_addr; /* Buffer 2 Address Pointer */
- __le32 ext_status;
- __le32 res[3];
-};
-
-struct xgmac_priv {
- struct xgmac_dma_desc *rx_chain;
- struct xgmac_dma_desc *tx_chain;
- char *rxbuffer;
-
- u32 tx_currdesc;
- u32 rx_currdesc;
-
- void __iomem *base;
-
- struct eth_device edev;
- struct device_d *dev;
-};
-
-/* XGMAC Descriptor Access Helpers */
-static inline void desc_set_buf_len(struct xgmac_dma_desc *p, u32 buf_sz)
-{
- if (buf_sz > MAX_DESC_BUF_SZ)
- p->buf_size = cpu_to_le32(MAX_DESC_BUF_SZ |
- (buf_sz - MAX_DESC_BUF_SZ) << DESC_BUFFER2_SZ_OFFSET);
- else
- p->buf_size = cpu_to_le32(buf_sz);
-}
-
-static inline int desc_get_buf_len(struct xgmac_dma_desc *p)
-{
- u32 len = le32_to_cpu(p->buf_size);
- return (len & DESC_BUFFER1_SZ_MASK) +
- ((len & DESC_BUFFER2_SZ_MASK) >> DESC_BUFFER2_SZ_OFFSET);
-}
-
-static inline void desc_init_rx_desc(struct xgmac_dma_desc *p, int ring_size,
- int buf_sz)
-{
- struct xgmac_dma_desc *end = p + ring_size - 1;
-
- memset(p, 0, sizeof(*p) * ring_size);
-
- for (; p <= end; p++)
- desc_set_buf_len(p, buf_sz);
-
- end->buf_size |= cpu_to_le32(RXDESC1_END_RING);
-}
-
-static inline void desc_init_tx_desc(struct xgmac_dma_desc *p, u32 ring_size)
-{
- memset(p, 0, sizeof(*p) * ring_size);
- p[ring_size - 1].flags = cpu_to_le32(TXDESC_END_RING);
-}
-
-static inline int desc_get_owner(struct xgmac_dma_desc *p)
-{
- return le32_to_cpu(p->flags) & DESC_OWN;
-}
-
-static inline void desc_set_rx_owner(struct xgmac_dma_desc *p)
-{
- /* Clear all fields and set the owner */
- p->flags = cpu_to_le32(DESC_OWN);
-}
-
-static inline void desc_set_tx_owner(struct xgmac_dma_desc *p, u32 flags)
-{
- u32 tmpflags = le32_to_cpu(p->flags);
- tmpflags &= TXDESC_END_RING;
- tmpflags |= flags | DESC_OWN;
- p->flags = cpu_to_le32(tmpflags);
-}
-
-static inline void *desc_get_buf_addr(struct xgmac_dma_desc *p)
-{
- return (void *)le32_to_cpu(p->buf1_addr);
-}
-
-static inline void desc_set_buf_addr(struct xgmac_dma_desc *p,
- void *paddr, int len)
-{
- p->buf1_addr = cpu_to_le32(paddr);
- if (len > MAX_DESC_BUF_SZ)
- p->buf2_addr = cpu_to_le32(paddr + MAX_DESC_BUF_SZ);
-}
-
-static inline void desc_set_buf_addr_and_size(struct xgmac_dma_desc *p,
- void *paddr, int len)
-{
- desc_set_buf_len(p, len);
- desc_set_buf_addr(p, paddr, len);
-}
-
-static inline int desc_get_rx_frame_len(struct xgmac_dma_desc *p)
-{
- u32 data = le32_to_cpu(p->flags);
- u32 len = (data & RXDESC_FRAME_LEN_MASK) >> RXDESC_FRAME_LEN_OFFSET;
- if (data & RXDESC_FRAME_TYPE)
- len -= 4;
-
- return len;
-}
-
-/*
- * Initialize a descriptor ring. Calxeda XGMAC is configured to use
- * advanced descriptors.
- */
-
-static void init_rx_desc(struct xgmac_priv *priv)
-{
- struct xgmac_dma_desc *rxdesc = priv->rx_chain;
- void *rxbuffer = priv->rxbuffer;
- int i;
-
- desc_init_rx_desc(rxdesc, RX_NUM_DESC, ETH_BUF_SZ);
- writel((ulong)rxdesc, priv->base + XGMAC_DMA_RX_BASE_ADDR);
-
- for (i = 0; i < RX_NUM_DESC; i++) {
- desc_set_buf_addr(rxdesc + i, rxbuffer + (i * ETH_BUF_SZ),
- ETH_BUF_SZ);
- desc_set_rx_owner(rxdesc + i);
- }
-}
-
-static void init_tx_desc(struct xgmac_priv *priv)
-{
- desc_init_tx_desc(priv->tx_chain, TX_NUM_DESC);
- writel((ulong)priv->tx_chain, priv->base + XGMAC_DMA_TX_BASE_ADDR);
-}
-
-static int xgmac_reset(struct eth_device *dev)
-{
- struct xgmac_priv *priv = dev->priv;
- int ret;
- u32 value;
-
- value = readl(priv->base + XGMAC_CONTROL) & XGMAC_CONTROL_SPD_MASK;
-
- writel(DMA_BUS_MODE_SFT_RESET, priv->base + XGMAC_DMA_BUS_MODE);
-
- ret = wait_on_timeout(100 * MSECOND,
- !(readl(priv->base + XGMAC_DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
-
- writel(value, priv->base + XGMAC_CONTROL);
-
- return ret;
-}
-
-static int xgmac_open(struct eth_device *edev)
-{
- struct xgmac_priv *priv = edev->priv;
- int value;
- int ret;
-
- ret = xgmac_reset(edev);
- if (ret)
- return ret;
-
- /* set the AXI bus modes */
- value = DMA_BUS_MODE_ATDS |
- (16 << DMA_BUS_MODE_PBL_SHIFT) |
- DMA_BUS_MODE_FB | DMA_BUS_MODE_AAL;
- writel(value, priv->base + XGMAC_DMA_BUS_MODE);
-
- value = DMA_AXIMODE_AAL | DMA_AXIMODE_BLEN16 |
- DMA_AXIMODE_BLEN8 | DMA_AXIMODE_BLEN4;
- writel(value, priv->base + XGMAC_DMA_AXI_BUS);
-
- /* set flow control parameters and store and forward mode */
- value = (FIFO_MINUS_12K << XGMAC_OMR_RFD_SHIFT) |
- (FIFO_MINUS_4K << XGMAC_OMR_RFA_SHIFT) |
- XGMAC_OMR_EFC | XGMAC_OMR_TSF | XGMAC_OMR_RSF;
- writel(value, priv->base + XGMAC_OMR);
-
- /* enable pause frames */
- value = (1024 << XGMAC_FLOW_CTRL_PT_SHIFT) |
- (1 << XGMAC_FLOW_CTRL_PLT_SHIFT) |
- XGMAC_FLOW_CTRL_UP | XGMAC_FLOW_CTRL_RFE | XGMAC_FLOW_CTRL_TFE;
- writel(value, priv->base + XGMAC_FLOW_CTRL);
-
- /* Initialize the descriptor chains */
- init_rx_desc(priv);
- init_tx_desc(priv);
-
- /* must set to 0, or when started up will cause issues */
- priv->tx_currdesc = 0;
- priv->rx_currdesc = 0;
-
- /* set default core values */
- value = readl(priv->base + XGMAC_CONTROL);
- value &= XGMAC_CONTROL_SPD_MASK;
- value |= XGMAC_CONTROL_DDIC | XGMAC_CONTROL_ACS |
- XGMAC_CONTROL_IPC | XGMAC_CONTROL_CAR;
-
- /* Everything is ready enable both mac and DMA */
- value |= XGMAC_CONTROL_RE | XGMAC_CONTROL_TE;
- writel(value, priv->base + XGMAC_CONTROL);
-
- value = readl(priv->base + XGMAC_DMA_CONTROL);
- value |= DMA_CONTROL_SR | DMA_CONTROL_ST;
- writel(value, priv->base + XGMAC_DMA_CONTROL);
-
- return 0;
-}
-
-static int xgmac_send(struct eth_device *edev, void *packet, int length)
-{
- struct xgmac_priv *priv = edev->priv;
- u32 currdesc = priv->tx_currdesc;
- struct xgmac_dma_desc *txdesc = &priv->tx_chain[currdesc];
- int ret;
-
- dma_sync_single_for_device((unsigned long)packet, length, DMA_TO_DEVICE);
- desc_set_buf_addr_and_size(txdesc, packet, length);
- desc_set_tx_owner(txdesc, TXDESC_FIRST_SEG |
- TXDESC_LAST_SEG | TXDESC_CRC_EN_APPEND);
-
- /* write poll demand */
- writel(1, priv->base + XGMAC_DMA_TX_POLL);
-
- ret = wait_on_timeout(1 * SECOND, !desc_get_owner(txdesc));
- dma_sync_single_for_cpu((unsigned long)packet, length, DMA_TO_DEVICE);
- if (ret) {
- dev_err(priv->dev, "TX timeout\n");
- return ret;
- }
-
- priv->tx_currdesc = (currdesc + 1) & (TX_NUM_DESC - 1);
- return 0;
-}
-
-static int xgmac_recv(struct eth_device *edev)
-{
- struct xgmac_priv *priv = edev->priv;
- u32 currdesc = priv->rx_currdesc;
- struct xgmac_dma_desc *rxdesc = &priv->rx_chain[currdesc];
- int length = 0;
- void *buf_addr;
-
- /* check if the host has the desc */
- if (desc_get_owner(rxdesc))
- return -1; /* something bad happened */
-
- length = desc_get_rx_frame_len(rxdesc);
- buf_addr = desc_get_buf_addr(rxdesc);
-
- dma_sync_single_for_cpu((unsigned long)buf_addr, length, DMA_FROM_DEVICE);
- net_receive(edev, buf_addr, length);
- dma_sync_single_for_device((unsigned long)buf_addr, length,
- DMA_FROM_DEVICE);
-
- /* set descriptor back to owned by XGMAC */
- desc_set_rx_owner(rxdesc);
- writel(1, priv->base + XGMAC_DMA_RX_POLL);
-
- priv->rx_currdesc = (currdesc + 1) & (RX_NUM_DESC - 1);
-
- return length;
-}
-
-static void xgmac_halt(struct eth_device *edev)
-{
- struct xgmac_priv *priv = edev->priv;
- int value;
-
- /* Disable TX/RX */
- value = readl(priv->base + XGMAC_CONTROL);
- value &= ~(XGMAC_CONTROL_RE | XGMAC_CONTROL_TE);
- writel(value, priv->base + XGMAC_CONTROL);
-
- /* Disable DMA */
- value = readl(priv->base + XGMAC_DMA_CONTROL);
- value &= ~(DMA_CONTROL_SR | DMA_CONTROL_ST);
- writel(value, priv->base + XGMAC_DMA_CONTROL);
-
- /* must set to 0, or when started up will cause issues */
- priv->tx_currdesc = 0;
- priv->rx_currdesc = 0;
-}
-
-static int xgmac_get_ethaddr(struct eth_device *edev, unsigned char *addr)
-{
- struct xgmac_priv *priv = edev->priv;
- u32 hi_addr, lo_addr;
-
- /* Read the MAC address from the hardware */
- hi_addr = readl(priv->base + XGMAC_ADDR_HIGH(0));
- lo_addr = readl(priv->base + XGMAC_ADDR_LOW(0));
-
- /* Extract the MAC address from the high and low words */
- addr[0] = lo_addr & 0xff;
- addr[1] = (lo_addr >> 8) & 0xff;
- addr[2] = (lo_addr >> 16) & 0xff;
- addr[3] = (lo_addr >> 24) & 0xff;
- addr[4] = hi_addr & 0xff;
- addr[5] = (hi_addr >> 8) & 0xff;
-
- return 0;
-}
-
-static int xgmac_set_ethaddr(struct eth_device *dev, const unsigned char *addr)
-{
- struct xgmac_priv *priv = dev->priv;
- u32 data;
-
- data = (addr[5] << 8) | addr[4];
- writel(data, priv->base + XGMAC_ADDR_HIGH(0));
- data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
- writel(data, priv->base + XGMAC_ADDR_LOW(0));
-
- return 0;
-}
-
-static int hb_xgmac_probe(struct device_d *dev)
-{
- struct resource *iores;
- struct eth_device *edev;
- struct xgmac_priv *priv;
- void __iomem *base;
-
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- base = IOMEM(iores->start);
-
- /* check hardware version */
- if (readl(base + XGMAC_VERSION) != 0x1012)
- return -EINVAL;
-
- priv = xzalloc(sizeof(*priv));
-
- priv->dev = dev;
- priv->base = base;
-
- priv->rxbuffer = dma_alloc_coherent(RX_BUF_SZ, DMA_ADDRESS_BROKEN);
- priv->rx_chain = dma_alloc_coherent(RX_NUM_DESC * sizeof(struct xgmac_dma_desc),
- DMA_ADDRESS_BROKEN);
- priv->tx_chain = dma_alloc_coherent(TX_NUM_DESC * sizeof(struct xgmac_dma_desc),
- DMA_ADDRESS_BROKEN);
-
- edev = &priv->edev;
- edev->priv = priv;
-
- edev->open = xgmac_open;
- edev->send = xgmac_send;
- edev->recv = xgmac_recv;
- edev->halt = xgmac_halt;
- edev->get_ethaddr = xgmac_get_ethaddr;
- edev->set_ethaddr = xgmac_set_ethaddr;
- edev->parent = dev;
-
- eth_register(edev);
-
- return 0;
-}
-
-static __maybe_unused struct of_device_id xgmac_dt_ids[] = {
- {
- .compatible = "calxeda,hb-xgmac",
- }, {
- /* sentinel */
- }
-};
-
-static struct driver_d hb_xgmac_driver = {
- .name = "hb-xgmac",
- .probe = hb_xgmac_probe,
- .of_compatible = DRV_OF_COMPAT(xgmac_dt_ids),
-};
-device_platform_driver(hb_xgmac_driver);
diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c
index d62c735181..684ead2f8e 100644
--- a/drivers/pinctrl/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/pinctrl-bcm2835.c
@@ -52,6 +52,10 @@ struct bcm2835_gpio_chip {
struct pinctrl_device pctl;
};
+struct plat_data {
+ unsigned ngpios;
+};
+
static int bcm2835_set_function(struct gpio_chip *chip, unsigned gpio, int function)
{
struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip);
@@ -149,10 +153,13 @@ static struct pinctrl_ops bcm2835_pinctrl_ops = {
static int bcm2835_gpio_probe(struct device_d *dev)
{
+ const struct plat_data *plat_data;
struct resource *iores;
struct bcm2835_gpio_chip *bcmgpio;
int ret;
+ plat_data = device_get_match_data(dev);
+
bcmgpio = xzalloc(sizeof(*bcmgpio));
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
@@ -160,7 +167,8 @@ static int bcm2835_gpio_probe(struct device_d *dev)
bcmgpio->base = IOMEM(iores->start);
bcmgpio->chip.ops = &bcm2835_gpio_ops;
bcmgpio->chip.base = 0;
- bcmgpio->chip.ngpio = 54;
+ bcmgpio->chip.ngpio = plat_data->ngpios;
+
bcmgpio->chip.dev = dev;
bcmgpio->pctl.ops = &bcm2835_pinctrl_ops;
bcmgpio->pctl.dev = dev;
@@ -191,9 +199,21 @@ err:
return ret;
}
+static const struct plat_data bcm2835_plat_data = {
+ .ngpios = 54,
+};
+
+static const struct plat_data bcm2711_plat_data = {
+ .ngpios = 58,
+};
+
static __maybe_unused struct of_device_id bcm2835_gpio_dt_ids[] = {
{
.compatible = "brcm,bcm2835-gpio",
+ .data = &bcm2835_plat_data,
+ }, {
+ .compatible = "brcm,bcm2711-gpio",
+ .data = &bcm2711_plat_data,
}, {
/* sentinel */
}
@@ -205,4 +225,4 @@ static struct driver_d bcm2835_gpio_driver = {
.of_compatible = DRV_OF_COMPAT(bcm2835_gpio_dt_ids),
};
-coredevice_platform_driver(bcm2835_gpio_driver);
+core_platform_driver(bcm2835_gpio_driver);
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b9750d1774..5e30ea388b 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -173,4 +173,12 @@ config SERIAL_SIFIVE
contains a SiFive UART IP block. This type of UART is present on
SiFive FU540 SoCs, among others.
+config SERIAL_SBI
+ tristate "RISCV Serial support over SBI's HTIF"
+ depends on OFDEVICE
+ depends on RISCV_SBI
+ help
+ Select this option if you are building barebox for a RISCV platform
+ that implements a serial over SBI.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 5120b17376..b1de436ed6 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_DRIVER_SERIAL_DIGIC) += serial_digic.o
obj-$(CONFIG_DRIVER_SERIAL_LPUART) += serial_lpuart.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_SERIAL_SIFIVE) += serial_sifive.o
+obj-$(CONFIG_SERIAL_SBI) += serial_sbi.o
diff --git a/drivers/serial/serial_sbi.c b/drivers/serial/serial_sbi.c
new file mode 100644
index 0000000000..2ea28fea5b
--- /dev/null
+++ b/drivers/serial/serial_sbi.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Marcelo Politzer <marcelo.politzer@cartesi.io>
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <asm/sbi.h>
+
+struct sbi_serial_priv {
+ struct console_device cdev;
+ uint8_t b[2], head, tail;
+};
+
+static int sbi_serial_getc(struct console_device *cdev)
+{
+ struct sbi_serial_priv *priv = cdev->dev->priv;
+ if (priv->head == priv->tail)
+ return -1;
+ return priv->b[priv->head++ & 0x1];
+}
+
+static void sbi_serial_putc(struct console_device *cdev, const char ch)
+{
+ sbi_console_putchar(ch);
+}
+
+static int sbi_serial_tstc(struct console_device *cdev)
+{
+ struct sbi_serial_priv *priv = cdev->dev->priv;
+ int c = sbi_console_getchar();
+
+ if (c != -1)
+ priv->b[priv->tail++ & 0x1] = c;
+ return priv->head != priv->tail;
+}
+
+static int sbi_serial_probe(struct device_d *dev)
+{
+ struct sbi_serial_priv *priv;
+
+ priv = dev->priv = xzalloc(sizeof(*priv));
+ priv->cdev.dev = dev;
+ priv->cdev.putc = sbi_serial_putc;
+ priv->cdev.getc = sbi_serial_getc;
+ priv->cdev.tstc = sbi_serial_tstc;
+ priv->cdev.flush = 0;
+ priv->cdev.setbrg = 0;
+
+ return console_register(&priv->cdev);
+}
+
+static struct driver_d serial_sbi_driver = {
+ .name = "riscv-serial-sbi",
+ .probe = sbi_serial_probe,
+};
+postcore_platform_driver(serial_sbi_driver);
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
index e47896be62..2a4e32a4cc 100644
--- a/drivers/spi/ath79_spi.c
+++ b/drivers/spi/ath79_spi.c
@@ -55,7 +55,7 @@ static inline void ath79_spi_wr(struct ath79_spi *sp, u32 val, int reg)
__raw_writel(val, sp->regs + reg);
}
-static inline void setbits(struct ath79_spi *sp, int bits, int on)
+static inline void ath79_spi_setbits(struct ath79_spi *sp, int bits, int on)
{
/*
* We are the only user of SCSPTR so no locking is required.
@@ -82,14 +82,14 @@ static inline void setsck(struct spi_device *spi, int on)
{
struct ath79_spi *sc = ath79_spidev_to_sp(spi);
- setbits(sc, AR71XX_SPI_IOC_CLK, on);
+ ath79_spi_setbits(sc, AR71XX_SPI_IOC_CLK, on);
}
static inline void setmosi(struct spi_device *spi, int on)
{
struct ath79_spi *sc = ath79_spidev_to_sp(spi);
- setbits(sc, AR71XX_SPI_IOC_DO, on);
+ ath79_spi_setbits(sc, AR71XX_SPI_IOC_DO, on);
}
static inline u32 getmiso(struct spi_device *spi)
diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c
index fd0ec505dc..ba5fdd5b74 100644
--- a/drivers/usb/gadget/dfu.c
+++ b/drivers/usb/gadget/dfu.c
@@ -817,168 +817,9 @@ static void dfu_disable(struct usb_function *f)
dfu_abort(dfu);
}
-#define STRING_MANUFACTURER_IDX 0
-#define STRING_PRODUCT_IDX 1
-#define STRING_DESCRIPTION_IDX 2
-
-static struct usb_string strings_dev[] = {
- [STRING_MANUFACTURER_IDX].s = NULL,
- [STRING_PRODUCT_IDX].s = NULL,
- [STRING_DESCRIPTION_IDX].s = "USB Device Firmware Upgrade",
- { } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
- .language = 0x0409, /* en-us */
- .strings = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
- &stringtab_dev,
- NULL,
-};
-
-static void dfu_unbind_config(struct usb_configuration *c)
-{
- free(dfu_string_defs);
-}
-
-static struct usb_configuration dfu_config_driver = {
- .label = "USB DFU",
- .unbind = dfu_unbind_config,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};
-
-static struct usb_device_descriptor dfu_dev_descriptor = {
- .bLength = USB_DT_DEVICE_SIZE,
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = 0x0100,
- .bDeviceClass = 0x00,
- .bDeviceSubClass = 0x00,
- .bDeviceProtocol = 0x00,
-/* .idVendor = dynamic */
-/* .idProduct = dynamic */
- .bcdDevice = 0x0000,
- .bNumConfigurations = 0x01,
-};
-
-static struct usb_function_instance *fi_dfu;
-static struct usb_function *f_dfu;
-
-static int dfu_driver_bind(struct usb_composite_dev *cdev)
+int usb_dfu_detached(void)
{
- struct usb_gadget *gadget = cdev->gadget;
- int status;
-
- if (gadget->vendor_id && gadget->product_id) {
- dfu_dev_descriptor.idVendor = cpu_to_le16(gadget->vendor_id);
- dfu_dev_descriptor.idProduct = cpu_to_le16(gadget->product_id);
- } else {
- dfu_dev_descriptor.idVendor = cpu_to_le16(0x1d50); /* Openmoko, Inc */
- dfu_dev_descriptor.idProduct = cpu_to_le16(0x60a2); /* barebox bootloader USB DFU Mode */
- }
-
- strings_dev[STRING_MANUFACTURER_IDX].s = gadget->manufacturer;
- strings_dev[STRING_PRODUCT_IDX].s = gadget->productname;
-
- status = usb_string_id(cdev);
- if (status < 0)
- goto fail;
- strings_dev[STRING_MANUFACTURER_IDX].id = status;
- dfu_dev_descriptor.iManufacturer = status;
-
- status = usb_string_id(cdev);
- if (status < 0)
- goto fail;
- strings_dev[STRING_PRODUCT_IDX].id = status;
- dfu_dev_descriptor.iProduct = status;
-
- /* config description */
- status = usb_string_id(cdev);
- if (status < 0)
- goto fail;
- strings_dev[STRING_DESCRIPTION_IDX].id = status;
- dfu_config_driver.iConfiguration = status;
-
- status = usb_add_config_only(cdev, &dfu_config_driver);
- if (status < 0)
- goto fail;
-
- fi_dfu = usb_get_function_instance("dfu");
- if (IS_ERR(fi_dfu)) {
- status = PTR_ERR(fi_dfu);
- goto fail;
- }
-
- f_dfu = usb_get_function(fi_dfu);
- if (IS_ERR(f_dfu)) {
- status = PTR_ERR(f_dfu);
- goto fail;
- }
-
- status = usb_add_function(&dfu_config_driver, f_dfu);
- if (status)
- goto fail;
-
- return 0;
-fail:
- return status;
-}
-
-static int dfu_driver_unbind(struct usb_composite_dev *cdev)
-{
- usb_put_function(f_dfu);
- usb_put_function_instance(fi_dfu);
-
- return 0;
-}
-
-static struct usb_composite_driver dfu_driver = {
- .name = "g_dfu",
- .dev = &dfu_dev_descriptor,
- .strings = dev_strings,
- .max_speed = USB_SPEED_HIGH,
- .bind = dfu_driver_bind,
- .unbind = dfu_driver_unbind,
-};
-
-int usb_dfu_register(struct f_dfu_opts *opts)
-{
- int ret;
-
- if (dfu_files)
- return -EBUSY;
-
- dfu_files = opts->files;
-
- ret = usb_composite_probe(&dfu_driver);
- if (ret)
- goto out;
-
- while (1) {
- ret = usb_gadget_poll();
- if (ret < 0)
- goto out1;
-
- if (dfudetach) {
- ret = 0;
- goto out1;
- }
-
- if (ctrlc()) {
- ret = -EINTR;
- goto out1;
- }
- }
-
-out1:
- dfudetach = 0;
- usb_composite_unregister(&dfu_driver);
-out:
- dfu_files = NULL;
-
- return ret;
+ return dfudetach;
}
static void dfu_free_func(struct usb_function *f)
diff --git a/drivers/video/simplefb-client.c b/drivers/video/simplefb-client.c
index 1f26ac5067..2367713ba4 100644
--- a/drivers/video/simplefb-client.c
+++ b/drivers/video/simplefb-client.c
@@ -30,6 +30,11 @@ struct simplefb_params {
struct simplefb_format *format;
};
+struct simplefb {
+ struct fb_info info;
+ struct fb_videomode mode;
+};
+
static int simplefb_parse_dt(struct device_d *dev,
struct simplefb_params *params)
{
@@ -80,6 +85,7 @@ static int simplefb_probe(struct device_d *dev)
{
int ret;
struct simplefb_params params;
+ struct simplefb *simplefb;
struct fb_info *info;
struct resource *mem;
@@ -96,17 +102,19 @@ static int simplefb_probe(struct device_d *dev)
return PTR_ERR(mem);
}
- info = xzalloc(sizeof(*info));
- dev->priv = info;
+ simplefb = xzalloc(sizeof(*simplefb));
- info->xres = params.width;
- info->yres = params.height;
+ simplefb->mode.name = params.format->name;
+ simplefb->mode.xres = params.width;
+ simplefb->mode.yres = params.height;
+
+ info = &simplefb->info;
+ info->mode = &simplefb->mode;
info->bits_per_pixel = params.format->bits_per_pixel;
info->red = params.format->red;
info->green = params.format->green;
info->blue = params.format->blue;
info->transp = params.format->transp;
- info->line_length = params.stride;
info->screen_base = (void *)mem->start;
info->screen_size = resource_size(mem);
@@ -114,13 +122,6 @@ static int simplefb_probe(struct device_d *dev)
info->fbops = &simplefb_ops;
- dev_info(dev, "framebuffer at 0x%p, 0x%lx bytes\n",
- info->screen_base, info->screen_size);
- dev_info(dev, "format=%s, mode=%dx%dx%d, linelength=%d\n",
- params.format->name,
- info->xres, info->yres,
- info->bits_per_pixel, info->line_length);
-
info->dev.parent = dev;
ret = register_framebuffer(info);
if (ret < 0) {
@@ -128,7 +129,7 @@ static int simplefb_probe(struct device_d *dev)
return ret;
}
- dev_info(dev, "simplefb registered!\n");
+ dev_info(dev, "size %s registered\n", size_human_readable(info->screen_size));
return 0;
}