summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/ahci.c11
-rw-r--r--drivers/block/dwc_ahsata.c2
-rw-r--r--drivers/core/device-remove.c4
-rw-r--r--drivers/core/device.c85
-rw-r--r--drivers/core/lists.c2
-rw-r--r--drivers/core/uclass.c10
-rw-r--r--drivers/demo/demo-simple.c1
-rw-r--r--drivers/gpio/Kconfig21
-rw-r--r--drivers/gpio/at91_gpio.c2
-rw-r--r--drivers/gpio/bcm2835_gpio.c2
-rw-r--r--drivers/gpio/gpio-uclass.c40
-rw-r--r--drivers/gpio/intel_ich6_gpio.c18
-rw-r--r--drivers/gpio/mxc_gpio.c2
-rw-r--r--drivers/gpio/omap_gpio.c2
-rw-r--r--drivers/gpio/s5p_gpio.c2
-rw-r--r--drivers/gpio/sandbox.c6
-rw-r--r--drivers/gpio/sunxi_gpio.c2
-rw-r--r--drivers/gpio/tegra_gpio.c2
-rw-r--r--drivers/i2c/Kconfig56
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/i2c-gpio.c346
-rw-r--r--drivers/i2c/i2c-uclass.c6
-rw-r--r--drivers/i2c/i2c-uniphier-f.c1
-rw-r--r--drivers/i2c/i2c-uniphier.c1
-rw-r--r--drivers/i2c/s3c24x0_i2c.c2
-rw-r--r--drivers/i2c/sandbox_i2c.c2
-rw-r--r--drivers/i2c/tegra_i2c.c6
-rw-r--r--drivers/input/cros_ec_keyb.c2
-rw-r--r--drivers/input/i8042.c7
-rw-r--r--drivers/misc/Kconfig19
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/cros_ec.c254
-rw-r--r--drivers/misc/cros_ec_i2c.c6
-rw-r--r--drivers/misc/cros_ec_lpc.c29
-rw-r--r--drivers/misc/cros_ec_sandbox.c79
-rw-r--r--drivers/misc/cros_ec_spi.c8
-rw-r--r--drivers/misc/swap_case.c285
-rw-r--r--drivers/mtd/spi/Kconfig12
-rw-r--r--drivers/mtd/spi/sf-uclass.c18
-rw-r--r--drivers/mtd/spi/sf_probe.c9
-rw-r--r--drivers/net/4xx_enet.c21
-rw-r--r--drivers/net/Kconfig49
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/altera_tse.c15
-rw-r--r--drivers/net/armada100_fec.c7
-rw-r--r--drivers/net/at91_emac.c4
-rw-r--r--drivers/net/ax88180.c6
-rw-r--r--drivers/net/bcm-sf2-eth.c6
-rw-r--r--drivers/net/bfin_mac.c4
-rw-r--r--drivers/net/calxedaxgmac.c2
-rw-r--r--drivers/net/cpsw.c17
-rw-r--r--drivers/net/cs8900.c5
-rw-r--r--drivers/net/davinci_emac.c5
-rw-r--r--drivers/net/dc2114x.c9
-rw-r--r--drivers/net/designware.c250
-rw-r--r--drivers/net/designware.h3
-rw-r--r--drivers/net/dm9000x.c9
-rw-r--r--drivers/net/dnet.c5
-rw-r--r--drivers/net/e1000.c4
-rw-r--r--drivers/net/eepro100.c3
-rw-r--r--drivers/net/enc28j60.c13
-rw-r--r--drivers/net/ep93xx_eth.c11
-rw-r--r--drivers/net/ethoc.c4
-rw-r--r--drivers/net/fec_mxc.c4
-rw-r--r--drivers/net/fm/eth.c2
-rw-r--r--drivers/net/fsl_mcdmafec.c23
-rw-r--r--drivers/net/ftgmac100.c4
-rw-r--r--drivers/net/ftmac100.c4
-rw-r--r--drivers/net/ftmac110.c4
-rw-r--r--drivers/net/greth.c2
-rw-r--r--drivers/net/keystone_net.c2
-rw-r--r--drivers/net/ks8851_mll.c6
-rw-r--r--drivers/net/lan91c96.c19
-rw-r--r--drivers/net/lpc32xx_eth.c10
-rw-r--r--drivers/net/macb.c10
-rw-r--r--drivers/net/mcffec.c5
-rw-r--r--drivers/net/mpc512x_fec.c3
-rw-r--r--drivers/net/mpc5xxx_fec.c2
-rw-r--r--drivers/net/mvgbe.c41
-rw-r--r--drivers/net/mvneta.c2
-rw-r--r--drivers/net/natsemi.c3
-rw-r--r--drivers/net/ne2000_base.c2
-rw-r--r--drivers/net/netconsole.c98
-rw-r--r--drivers/net/ns8382x.c6
-rw-r--r--drivers/net/pch_gbe.c2
-rw-r--r--drivers/net/pcnet.c2
-rw-r--r--drivers/net/phy/phy.c22
-rw-r--r--drivers/net/rtl8139.c4
-rw-r--r--drivers/net/rtl8169.c2
-rw-r--r--drivers/net/sandbox-raw.c165
-rw-r--r--drivers/net/sandbox.c208
-rw-r--r--drivers/net/sh_eth.c2
-rw-r--r--drivers/net/smc91111.c18
-rw-r--r--drivers/net/smc911x.c4
-rw-r--r--drivers/net/sunxi_emac.c4
-rw-r--r--drivers/net/tsec.c7
-rw-r--r--drivers/net/tsi108_eth.c8
-rw-r--r--drivers/net/uli526x.c5
-rw-r--r--drivers/net/xilinx_axi_emac.c2
-rw-r--r--drivers/net/xilinx_emaclite.c2
-rw-r--r--drivers/net/xilinx_ll_temac_fifo.c4
-rw-r--r--drivers/net/xilinx_ll_temac_sdma.c4
-rw-r--r--drivers/net/zynq_gem.c2
-rw-r--r--drivers/pci/Kconfig22
-rw-r--r--drivers/pci/Makefile11
-rw-r--r--drivers/pci/pci-emul-uclass.c67
-rw-r--r--drivers/pci/pci-uclass.c639
-rw-r--r--drivers/pci/pci.c281
-rw-r--r--drivers/pci/pci_auto.c16
-rw-r--r--drivers/pci/pci_common.c292
-rw-r--r--drivers/pci/pci_compat.c43
-rw-r--r--drivers/pci/pci_sandbox.c79
-rw-r--r--drivers/pci/pci_x86.c24
-rw-r--r--drivers/qe/uec.c2
-rw-r--r--drivers/serial/ns16550.c1
-rw-r--r--drivers/serial/serial-uclass.c4
-rw-r--r--drivers/serial/serial_uniphier.c1
-rw-r--r--drivers/sound/Kconfig55
-rw-r--r--drivers/spi/Kconfig25
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/fsl_dspi.c737
-rw-r--r--drivers/spi/fsl_qspi.c985
-rw-r--r--drivers/spi/ich.c522
-rw-r--r--drivers/spi/spi-uclass.c4
-rw-r--r--drivers/tpm/Kconfig7
-rw-r--r--drivers/usb/Kconfig16
-rw-r--r--drivers/usb/emul/Kconfig8
-rw-r--r--drivers/usb/emul/Makefile10
-rw-r--r--drivers/usb/emul/sandbox_flash.c423
-rw-r--r--drivers/usb/emul/sandbox_hub.c303
-rw-r--r--drivers/usb/emul/usb-emul-uclass.c263
-rw-r--r--drivers/usb/eth/asix.c3
-rw-r--r--drivers/usb/eth/asix88179.c2
-rw-r--r--drivers/usb/eth/mcs7830.c2
-rw-r--r--drivers/usb/eth/smsc95xx.c5
-rw-r--r--drivers/usb/eth/usb_ether.c52
-rw-r--r--drivers/usb/gadget/ci_udc.c4
-rw-r--r--drivers/usb/gadget/ether.c13
-rw-r--r--drivers/usb/host/Makefile5
-rw-r--r--drivers/usb/host/ehci-exynos.c112
-rw-r--r--drivers/usb/host/ehci-faraday.c112
-rw-r--r--drivers/usb/host/ehci-hcd.c385
-rw-r--r--drivers/usb/host/ehci-mx5.c12
-rw-r--r--drivers/usb/host/ehci-tegra.c322
-rw-r--r--drivers/usb/host/ehci.h47
-rw-r--r--drivers/usb/host/usb-sandbox.c117
-rw-r--r--drivers/usb/host/usb-uclass.c645
-rw-r--r--drivers/usb/host/xhci-exynos5.c120
-rw-r--r--drivers/usb/host/xhci-mem.c24
-rw-r--r--drivers/usb/host/xhci-ring.c8
-rw-r--r--drivers/usb/host/xhci.c312
-rw-r--r--drivers/usb/host/xhci.h31
-rw-r--r--drivers/usb/musb-new/musb_uboot.c4
-rw-r--r--drivers/video/cfb_console.c29
154 files changed, 7831 insertions, 1915 deletions
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 88b90e0203..65086484ee 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -137,10 +137,10 @@ static void sunxi_dma_init(volatile u8 *port_mmio)
}
#endif
-int ahci_reset(u32 base)
+int ahci_reset(void __iomem *base)
{
int i = 1000;
- u32 host_ctl_reg = base + HOST_CTL;
+ u32 __iomem *host_ctl_reg = base + HOST_CTL;
u32 tmp = readl(host_ctl_reg); /* global controller reset */
if ((tmp & HOST_RESET) == 0)
@@ -419,8 +419,9 @@ static int ahci_init_one(pci_dev_t pdev)
probe_ent->pio_mask = 0x1f;
probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &probe_ent->mmio_base);
- debug("ahci mmio_base=0x%08x\n", probe_ent->mmio_base);
+ probe_ent->mmio_base = pci_map_bar(pdev, PCI_BASE_ADDRESS_5,
+ PCI_REGION_MEM);
+ debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base);
/* Take from kernel:
* JMicron-specific fixup:
@@ -939,7 +940,7 @@ void scsi_low_level_init(int busdevfunc)
}
#ifdef CONFIG_SCSI_AHCI_PLAT
-int ahci_init(u32 base)
+int ahci_init(void __iomem *base)
{
int i, rc = 0;
u32 linkmap;
diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c
index 01a4148a52..cf3ef6be62 100644
--- a/drivers/block/dwc_ahsata.c
+++ b/drivers/block/dwc_ahsata.c
@@ -343,7 +343,7 @@ static int ahci_init_one(int pdev)
| ATA_FLAG_PIO_DMA
| ATA_FLAG_NO_ATAPI;
- probe_ent->mmio_base = CONFIG_DWC_AHSATA_BASE_ADDR;
+ probe_ent->mmio_base = (void __iomem *)CONFIG_DWC_AHSATA_BASE_ADDR;
/* initialize adapter */
rc = ahci_host_init(probe_ent);
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 3a5f48df7a..7fee1c001e 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -66,7 +66,7 @@ static int device_chld_remove(struct udevice *dev)
int device_unbind(struct udevice *dev)
{
- struct driver *drv;
+ const struct driver *drv;
int ret;
if (!dev)
@@ -139,7 +139,7 @@ void device_free(struct udevice *dev)
int device_remove(struct udevice *dev)
{
- struct driver *drv;
+ const struct driver *drv;
int ret;
if (!dev)
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 73c3e07c28..ccaa99ca63 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -24,8 +24,9 @@
DECLARE_GLOBAL_DATA_PTR;
-int device_bind(struct udevice *parent, struct driver *drv, const char *name,
- void *platdata, int of_offset, struct udevice **devp)
+int device_bind(struct udevice *parent, const struct driver *drv,
+ const char *name, void *platdata, int of_offset,
+ struct udevice **devp)
{
struct udevice *dev;
struct uclass *uc;
@@ -164,9 +165,24 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
-1, devp);
}
+static void *alloc_priv(int size, uint flags)
+{
+ void *priv;
+
+ if (flags & DM_FLAG_ALLOC_PRIV_DMA) {
+ priv = memalign(ARCH_DMA_MINALIGN, size);
+ if (priv)
+ memset(priv, '\0', size);
+ } else {
+ priv = calloc(1, size);
+ }
+
+ return priv;
+}
+
int device_probe_child(struct udevice *dev, void *parent_priv)
{
- struct driver *drv;
+ const struct driver *drv;
int size = 0;
int ret;
int seq;
@@ -182,7 +198,7 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
/* Allocate private data if requested */
if (drv->priv_auto_alloc_size) {
- dev->priv = calloc(1, drv->priv_auto_alloc_size);
+ dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags);
if (!dev->priv) {
ret = -ENOMEM;
goto fail;
@@ -206,7 +222,7 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
per_child_auto_alloc_size;
}
if (size) {
- dev->parent_priv = calloc(1, size);
+ dev->parent_priv = alloc_priv(size, drv->flags);
if (!dev->parent_priv) {
ret = -ENOMEM;
goto fail;
@@ -227,7 +243,9 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
}
dev->seq = seq;
- ret = uclass_pre_probe_child(dev);
+ dev->flags |= DM_FLAG_ACTIVATED;
+
+ ret = uclass_pre_probe_device(dev);
if (ret)
goto fail;
@@ -243,19 +261,18 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
goto fail;
}
+ dev->flags |= DM_FLAG_ACTIVATED;
if (drv->probe) {
ret = drv->probe(dev);
- if (ret)
+ if (ret) {
+ dev->flags &= ~DM_FLAG_ACTIVATED;
goto fail;
+ }
}
- dev->flags |= DM_FLAG_ACTIVATED;
-
ret = uclass_post_probe_device(dev);
- if (ret) {
- dev->flags &= ~DM_FLAG_ACTIVATED;
+ if (ret)
goto fail_uclass;
- }
return 0;
fail_uclass:
@@ -264,6 +281,8 @@ fail_uclass:
__func__, dev->name);
}
fail:
+ dev->flags &= ~DM_FLAG_ACTIVATED;
+
dev->seq = -1;
device_free(dev);
@@ -305,6 +324,16 @@ void *dev_get_priv(struct udevice *dev)
return dev->priv;
}
+void *dev_get_uclass_priv(struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device\n", __func__);
+ return NULL;
+ }
+
+ return dev->uclass_priv;
+}
+
void *dev_get_parentdata(struct udevice *dev)
{
if (!dev) {
@@ -440,9 +469,9 @@ struct udevice *dev_get_parent(struct udevice *child)
return child->parent;
}
-ulong dev_get_of_data(struct udevice *dev)
+ulong dev_get_driver_data(struct udevice *dev)
{
- return dev->of_id->data;
+ return dev->driver_data;
}
enum uclass_id device_get_uclass_id(struct udevice *dev)
@@ -461,3 +490,31 @@ fdt_addr_t dev_get_addr(struct udevice *dev)
return FDT_ADDR_T_NONE;
}
#endif
+
+bool device_has_children(struct udevice *dev)
+{
+ return !list_empty(&dev->child_head);
+}
+
+bool device_has_active_children(struct udevice *dev)
+{
+ struct udevice *child;
+
+ for (device_find_first_child(dev, &child);
+ child;
+ device_find_next_child(&child)) {
+ if (device_active(child))
+ return true;
+ }
+
+ return false;
+}
+
+bool device_is_last_sibling(struct udevice *dev)
+{
+ struct udevice *parent = dev->parent;
+
+ if (!parent)
+ return false;
+ return list_is_last(&dev->sibling_node, &parent->child_head);
+}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index ff115c4723..647e390bfe 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -168,7 +168,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
dm_warn("Error binding driver '%s'\n", entry->name);
return ret;
} else {
- dev->of_id = id;
+ dev->driver_data = id->data;
found = true;
if (devp)
*devp = dev;
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 289a5d2d53..98c15e585d 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -391,9 +391,17 @@ int uclass_resolve_seq(struct udevice *dev)
return seq;
}
-int uclass_pre_probe_child(struct udevice *dev)
+int uclass_pre_probe_device(struct udevice *dev)
{
struct uclass_driver *uc_drv;
+ int ret;
+
+ uc_drv = dev->uclass->uc_drv;
+ if (uc_drv->pre_probe) {
+ ret = uc_drv->pre_probe(dev);
+ if (ret)
+ return ret;
+ }
if (!dev->parent)
return 0;
diff --git a/drivers/demo/demo-simple.c b/drivers/demo/demo-simple.c
index 2bcb7dfb47..f069748e05 100644
--- a/drivers/demo/demo-simple.c
+++ b/drivers/demo/demo-simple.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <dm.h>
#include <dm-demo.h>
+#include <mapmem.h>
#include <asm/io.h>
static int simple_hello(struct udevice *dev, int ch)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 7b5178a23a..0840a30fba 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -14,3 +14,24 @@ config LPC32XX_GPIO
default n
help
Support for the LPC32XX GPIO driver.
+
+config SANDBOX_GPIO
+ bool "Enable sandbox GPIO driver"
+ depends on SANDBOX && DM && DM_GPIO
+ help
+ This driver supports some simulated GPIOs which can be adjusted
+ using 'back door' functions like sandbox_gpio_set_value(). Then the
+ GPIOs can be inspected through the normal get_get_value()
+ interface. The purpose of this is to allow GPIOs to be used as
+ normal in sandbox, perhaps with test code actually driving the
+ behaviour of those GPIOs.
+
+config SANDBOX_GPIO_COUNT
+ int "Number of sandbox GPIOs"
+ depends on SANDBOX_GPIO
+ default 128
+ help
+ The sandbox driver can support any number of GPIOs. Generally these
+ are specified using the device tree. But you can also have a number
+ of 'anonymous' GPIOs that do not belong to any device or bank.
+ Select a suitable value depending on your needs.
diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 22fbd63098..75a32ee815 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -511,7 +511,7 @@ static int at91_gpio_probe(struct udevice *dev)
{
struct at91_port_priv *port = dev_get_priv(dev);
struct at91_port_platdata *plat = dev_get_platdata(dev);
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = plat->bank_name;
uc_priv->gpio_count = GPIO_PER_BANK;
diff --git a/drivers/gpio/bcm2835_gpio.c b/drivers/gpio/bcm2835_gpio.c
index 0244c01882..fbc641d662 100644
--- a/drivers/gpio/bcm2835_gpio.c
+++ b/drivers/gpio/bcm2835_gpio.c
@@ -105,7 +105,7 @@ static int bcm2835_gpio_probe(struct udevice *dev)
{
struct bcm2835_gpios *gpios = dev_get_priv(dev);
struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev);
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = "GPIO";
uc_priv->gpio_count = BCM2835_GPIO_COUNT;
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index a69bbd2002..381868bfb1 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -34,7 +34,7 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
for (ret = uclass_first_device(UCLASS_GPIO, &dev);
dev;
ret = uclass_next_device(&dev)) {
- uc_priv = dev->uclass_priv;
+ uc_priv = dev_get_uclass_priv(dev);
if (gpio >= uc_priv->gpio_base &&
gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
desc->dev = dev;
@@ -65,7 +65,7 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
ret = uclass_next_device(&dev)) {
int len;
- uc_priv = dev->uclass_priv;
+ uc_priv = dev_get_uclass_priv(dev);
if (numeric != -1) {
offset = numeric - uc_priv->gpio_base;
/* Allow GPIOs to be numbered from 0 */
@@ -116,7 +116,7 @@ static int dm_gpio_request(struct gpio_desc *desc, const char *label)
char *str;
int ret;
- uc_priv = dev->uclass_priv;
+ uc_priv = dev_get_uclass_priv(dev);
if (uc_priv->name[desc->offset])
return -EBUSY;
str = strdup(label);
@@ -195,7 +195,7 @@ int _dm_gpio_free(struct udevice *dev, uint offset)
struct gpio_dev_priv *uc_priv;
int ret;
- uc_priv = dev->uclass_priv;
+ uc_priv = dev_get_uclass_priv(dev);
if (!uc_priv->name[offset])
return -ENXIO;
if (gpio_get_ops(dev)->free) {
@@ -232,7 +232,7 @@ int gpio_free(unsigned gpio)
static int check_reserved(struct gpio_desc *desc, const char *func)
{
- struct gpio_dev_priv *uc_priv = desc->dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc->dev);
if (!uc_priv->name[desc->offset]) {
printf("%s: %s: error: gpio %s%d not reserved\n",
@@ -402,7 +402,7 @@ const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
struct gpio_dev_priv *priv;
/* Must be called on an active device */
- priv = dev->uclass_priv;
+ priv = dev_get_uclass_priv(dev);
assert(priv);
*bit_count = priv->gpio_count;
@@ -420,7 +420,7 @@ static const char * const gpio_function[GPIOF_COUNT] = {
int get_function(struct udevice *dev, int offset, bool skip_unused,
const char **namep)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct dm_gpio_ops *ops = gpio_get_ops(dev);
BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
@@ -468,7 +468,7 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
*buf = 0;
- priv = dev->uclass_priv;
+ priv = dev_get_uclass_priv(dev);
ret = gpio_get_raw_function(dev, offset, NULL);
if (ret < 0)
return ret;
@@ -590,11 +590,7 @@ int gpio_request_list_by_name_nodev(const void *blob, int node,
int count;
int ret;
- for (count = 0; ; count++) {
- if (count >= max_count) {
- ret = -ENOSPC;
- goto err;
- }
+ for (count = 0; count < max_count; count++) {
ret = _gpio_request_by_name_nodev(blob, node, list_name, count,
&desc[count], flags, true);
if (ret == -ENOENT)
@@ -680,7 +676,7 @@ static int gpio_renumber(struct udevice *removed_dev)
base = 0;
uclass_foreach_dev(dev, uc) {
if (device_active(dev) && dev != removed_dev) {
- uc_priv = dev->uclass_priv;
+ uc_priv = dev_get_uclass_priv(dev);
uc_priv->gpio_base = base;
base += uc_priv->gpio_count;
}
@@ -689,9 +685,21 @@ static int gpio_renumber(struct udevice *removed_dev)
return 0;
}
+int gpio_get_number(struct gpio_desc *desc)
+{
+ struct udevice *dev = desc->dev;
+ struct gpio_dev_priv *uc_priv;
+
+ if (!dev)
+ return -1;
+ uc_priv = dev->uclass_priv;
+
+ return uc_priv->gpio_base + desc->offset;
+}
+
static int gpio_post_probe(struct udevice *dev)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
uc_priv->name = calloc(uc_priv->gpio_count, sizeof(char *));
if (!uc_priv->name)
@@ -702,7 +710,7 @@ static int gpio_post_probe(struct udevice *dev)
static int gpio_pre_remove(struct udevice *dev)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
int i;
for (i = 0; i < uc_priv->gpio_count; i++) {
diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c
index 7720cc3dad..7e679a086e 100644
--- a/drivers/gpio/intel_ich6_gpio.c
+++ b/drivers/gpio/intel_ich6_gpio.c
@@ -64,13 +64,13 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
pci_dev = PCI_BDF(0, 0x1f, 0);
/* Is the device present? */
- tmpword = pci_read_config16(pci_dev, PCI_VENDOR_ID);
+ tmpword = x86_pci_read_config16(pci_dev, PCI_VENDOR_ID);
if (tmpword != PCI_VENDOR_ID_INTEL) {
debug("%s: wrong VendorID\n", __func__);
return -ENODEV;
}
- tmpword = pci_read_config16(pci_dev, PCI_DEVICE_ID);
+ tmpword = x86_pci_read_config16(pci_dev, PCI_DEVICE_ID);
debug("Found %04x:%04x\n", PCI_VENDOR_ID_INTEL, tmpword);
/*
* We'd like to validate the Device ID too, but pretty much any
@@ -80,34 +80,34 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
*/
/* I/O should already be enabled (it's a RO bit). */
- tmpword = pci_read_config16(pci_dev, PCI_COMMAND);
+ tmpword = x86_pci_read_config16(pci_dev, PCI_COMMAND);
if (!(tmpword & PCI_COMMAND_IO)) {
debug("%s: device IO not enabled\n", __func__);
return -ENODEV;
}
/* Header Type must be normal (bits 6-0 only; see spec.) */
- tmpbyte = pci_read_config8(pci_dev, PCI_HEADER_TYPE);
+ tmpbyte = x86_pci_read_config8(pci_dev, PCI_HEADER_TYPE);
if ((tmpbyte & 0x7f) != PCI_HEADER_TYPE_NORMAL) {
debug("%s: invalid Header type\n", __func__);
return -ENODEV;
}
/* Base Class must be a bridge device */
- tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_CODE);
+ tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_CODE);
if (tmpbyte != PCI_CLASS_CODE_BRIDGE) {
debug("%s: invalid class\n", __func__);
return -ENODEV;
}
/* Sub Class must be ISA */
- tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_SUB_CODE);
+ tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_SUB_CODE);
if (tmpbyte != PCI_CLASS_SUB_CODE_BRIDGE_ISA) {
debug("%s: invalid subclass\n", __func__);
return -ENODEV;
}
/* Programming Interface must be 0x00 (no others exist) */
- tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_PROG);
+ tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_PROG);
if (tmpbyte != 0x00) {
debug("%s: invalid interface type\n", __func__);
return -ENODEV;
@@ -123,7 +123,7 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
* while on the Ivybridge the bit0 is used to indicate it is an
* I/O space.
*/
- tmplong = pci_read_config32(pci_dev, PCI_CFG_GPIOBASE);
+ tmplong = x86_pci_read_config32(pci_dev, PCI_CFG_GPIOBASE);
if (tmplong == 0x00000000 || tmplong == 0xffffffff) {
debug("%s: unexpected GPIOBASE value\n", __func__);
return -ENODEV;
@@ -151,7 +151,7 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
static int ich6_gpio_probe(struct udevice *dev)
{
struct ich6_bank_platdata *plat = dev_get_platdata(dev);
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct ich6_bank_priv *bank = dev_get_priv(dev);
if (gd->arch.gpio_map) {
diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index 815407bb03..2012f994c8 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -266,7 +266,7 @@ static int mxc_gpio_probe(struct udevice *dev)
{
struct mxc_bank_info *bank = dev_get_priv(dev);
struct mxc_gpio_plat *plat = dev_get_platdata(dev);
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
int banknum;
char name[18], *str;
diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c
index 19fc451079..0a1e12419b 100644
--- a/drivers/gpio/omap_gpio.c
+++ b/drivers/gpio/omap_gpio.c
@@ -309,7 +309,7 @@ static int omap_gpio_probe(struct udevice *dev)
{
struct gpio_bank *bank = dev_get_priv(dev);
struct omap_gpio_platdata *plat = dev_get_platdata(dev);
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
char name[18], *str;
sprintf(name, "GPIO%d_", plat->bank_index);
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 0a245ba18a..49b1054660 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -296,7 +296,7 @@ static const struct dm_gpio_ops gpio_exynos_ops = {
static int gpio_exynos_probe(struct udevice *dev)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct exynos_bank_info *priv = dev->priv;
struct exynos_gpio_platdata *plat = dev->platdata;
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index d564c252c7..a9b1efcd06 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -24,7 +24,7 @@ struct gpio_state {
/* Access routines for GPIO state */
static u8 *get_gpio_flags(struct udevice *dev, unsigned offset)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct gpio_state *state = dev_get_priv(dev);
if (offset >= uc_priv->gpio_count) {
@@ -160,7 +160,7 @@ static const struct dm_gpio_ops gpio_sandbox_ops = {
static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"num-gpios", 0);
@@ -172,7 +172,7 @@ static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
static int gpio_sandbox_probe(struct udevice *dev)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
if (dev->of_offset == -1) {
/* Tell the uclass how many GPIOs we have */
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index 510123fdf8..cf5c62463e 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -261,7 +261,7 @@ static char *gpio_bank_name(int bank)
static int gpio_sunxi_probe(struct udevice *dev)
{
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
/* Tell the uclass how many GPIOs we have */
if (plat) {
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index f870cdbddf..8017e359f5 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -295,7 +295,7 @@ static const struct udevice_id tegra_gpio_ids[] = {
static int gpio_tegra_probe(struct udevice *dev)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct tegra_port_info *priv = dev->priv;
struct tegra_gpio_platdata *plat = dev->platdata;
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 692810d057..ba43019ab9 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -2,16 +2,13 @@ config DM_I2C
bool "Enable Driver Model for I2C drivers"
depends on DM
help
- Enable driver model for I2C. This SPI flash interface
- (spi_flash_probe(), spi_flash_write(), etc.) is then
- implemented by the SPI flash uclass. There is one standard
- SPI flash driver which knows how to probe most chips
- supported by U-Boot. The uclass interface is defined in
- include/spi_flash.h, but is currently fully compatible
- with the old interface to avoid confusion and duplication
- during the transition parent. SPI and SPI flash must be
- enabled together (it is not possible to use driver model
- for one and not the other).
+ Enable driver model for I2C. The I2C uclass interface: probe, read,
+ write and speed, is implemented with the bus drivers operations,
+ which provide methods for bus setting and data transfer. Each chip
+ device (bus child) info is kept as parent platdata. The interface
+ is defined in include/i2c.h. When i2c bus driver supports the i2c
+ uclass, but the device drivers not, then DM_I2C_COMPAT config can
+ be used as compatibility layer.
config DM_I2C_COMPAT
bool "Enable I2C compatibility layer"
@@ -22,6 +19,45 @@ config DM_I2C_COMPAT
to convert all code for a board in a single commit. It should not
be enabled for any board in an official release.
+config DM_I2C_GPIO
+ bool "Enable Driver Model for software emulated I2C bus driver"
+ depends on DM_I2C && DM_GPIO
+ help
+ Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO
+ configuration is given by the device tree. Kernel-style device tree
+ bindings are supported.
+ Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
+
+config SYS_I2C_SANDBOX
+ bool "Sandbox I2C driver"
+ depends on SANDBOX && DM_I2C
+ help
+ Enable I2C support for sandbox. This is an emulation of a real I2C
+ bus. Devices can be attached to the bus using the device tree
+ which specifies the driver to use. As an example, see this device
+ tree fragment from sandbox.dts. It shows that the I2C bus has a
+ single EEPROM at address 0x2c (7-bit address) which is emulated by
+ the driver for "sandbox,i2c-eeprom", which is in
+ drivers/misc/i2c_eeprom_emul.c.
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ compatible = "sandbox,i2c";
+ clock-frequency = <400000>;
+ eeprom@2c {
+ reg = <0x2c>;
+ compatible = "i2c-eeprom";
+ emul {
+ compatible = "sandbox,i2c-eeprom";
+ sandbox,filename = "i2c.bin";
+ sandbox,size = <128>;
+ };
+ };
+ };
+
+
config SYS_I2C_UNIPHIER
bool "UniPhier I2C driver"
depends on ARCH_UNIPHIER && DM_I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 26ea854ec8..d9e912f786 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -6,6 +6,7 @@
#
obj-$(CONFIG_DM_I2C) += i2c-uclass.o
obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
+obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_I2C_MV) += mv_i2c.o
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
new file mode 100644
index 0000000000..ed899d4777
--- /dev/null
+++ b/drivers/i2c/i2c-gpio.c
@@ -0,0 +1,346 @@
+/*
+ * (C) Copyright 2015, Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * This file is based on: drivers/i2c/soft-i2c.c,
+ * with added driver-model support and code cleanup.
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm/gpio.h>
+
+#define DEFAULT_UDELAY 5
+#define RETRIES 0
+#define I2C_ACK 0
+#define I2C_NOACK 1
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+ PIN_SDA = 0,
+ PIN_SCL,
+ PIN_COUNT,
+};
+
+struct i2c_gpio_bus {
+ /**
+ * udelay - delay [us] between GPIO toggle operations,
+ * which is 1/4 of I2C speed clock period.
+ */
+ int udelay;
+ /* sda, scl */
+ struct gpio_desc gpios[PIN_COUNT];
+};
+
+static int i2c_gpio_sda_get(struct gpio_desc *sda)
+{
+ return dm_gpio_get_value(sda);
+}
+
+static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit)
+{
+ if (bit) {
+ dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
+ } else {
+ dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
+ dm_gpio_set_value(sda, 0);
+ }
+}
+
+static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
+{
+ dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
+ dm_gpio_set_value(scl, bit);
+}
+
+static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay, uchar bit)
+{
+ i2c_gpio_scl_set(scl, 0);
+ udelay(delay);
+ i2c_gpio_sda_set(sda, bit);
+ udelay(delay);
+ i2c_gpio_scl_set(scl, 1);
+ udelay(2 * delay);
+}
+
+static int i2c_gpio_read_bit(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay)
+{
+ int value;
+
+ i2c_gpio_scl_set(scl, 1);
+ udelay(delay);
+ value = i2c_gpio_sda_get(sda);
+ udelay(delay);
+ i2c_gpio_scl_set(scl, 0);
+ udelay(2 * delay);
+
+ return value;
+}
+
+/* START: High -> Low on SDA while SCL is High */
+static void i2c_gpio_send_start(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay)
+{
+ udelay(delay);
+ i2c_gpio_sda_set(sda, 1);
+ udelay(delay);
+ i2c_gpio_scl_set(scl, 1);
+ udelay(delay);
+ i2c_gpio_sda_set(sda, 0);
+ udelay(delay);
+}
+
+/* STOP: Low -> High on SDA while SCL is High */
+static void i2c_gpio_send_stop(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay)
+{
+ i2c_gpio_scl_set(scl, 0);
+ udelay(delay);
+ i2c_gpio_sda_set(sda, 0);
+ udelay(delay);
+ i2c_gpio_scl_set(scl, 1);
+ udelay(delay);
+ i2c_gpio_sda_set(sda, 1);
+ udelay(delay);
+}
+
+/* ack should be I2C_ACK or I2C_NOACK */
+static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay, int ack)
+{
+ i2c_gpio_write_bit(scl, sda, delay, ack);
+ i2c_gpio_scl_set(scl, 0);
+ udelay(delay);
+}
+
+/**
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state. Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void i2c_gpio_send_reset(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay)
+{
+ int j;
+
+ for (j = 0; j < 9; j++)
+ i2c_gpio_write_bit(scl, sda, delay, 1);
+
+ i2c_gpio_send_stop(scl, sda, delay);
+}
+
+/* Set sda high with low clock, before reading slave data */
+static void i2c_gpio_sda_high(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay)
+{
+ i2c_gpio_scl_set(scl, 0);
+ udelay(delay);
+ i2c_gpio_sda_set(sda, 1);
+ udelay(delay);
+}
+
+/* Send 8 bits and look for an acknowledgement */
+static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay, uchar data)
+{
+ int j;
+ int nack;
+
+ for (j = 0; j < 8; j++) {
+ i2c_gpio_write_bit(scl, sda, delay, data & 0x80);
+ data <<= 1;
+ }
+
+ udelay(delay);
+
+ /* Look for an <ACK>(negative logic) and return it */
+ i2c_gpio_sda_high(scl, sda, delay);
+ nack = i2c_gpio_read_bit(scl, sda, delay);
+
+ return nack; /* not a nack is an ack */
+}
+
+/**
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar i2c_gpio_read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
+ int delay, int ack)
+{
+ int data;
+ int j;
+
+ i2c_gpio_sda_high(scl, sda, delay);
+ data = 0;
+ for (j = 0; j < 8; j++) {
+ data <<= 1;
+ data |= i2c_gpio_read_bit(scl, sda, delay);
+ }
+ i2c_gpio_send_ack(scl, sda, delay, ack);
+
+ return data;
+}
+
+/* send start and the slave chip address */
+int i2c_send_slave_addr(struct gpio_desc *scl, struct gpio_desc *sda, int delay,
+ uchar chip)
+{
+ i2c_gpio_send_start(scl, sda, delay);
+
+ if (i2c_gpio_write_byte(scl, sda, delay, chip)) {
+ i2c_gpio_send_stop(scl, sda, delay);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip,
+ uchar *buffer, int len,
+ bool end_with_repeated_start)
+{
+ struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+ struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+ unsigned int delay = bus->udelay;
+ int failures = 0;
+
+ debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
+
+ if (i2c_send_slave_addr(scl, sda, delay, chip << 1)) {
+ debug("i2c_write, no chip responded %02X\n", chip);
+ return -EIO;
+ }
+
+ while (len-- > 0) {
+ if (i2c_gpio_write_byte(scl, sda, delay, *buffer++))
+ failures++;
+ }
+
+ if (!end_with_repeated_start) {
+ i2c_gpio_send_stop(scl, sda, delay);
+ return failures;
+ }
+
+ if (i2c_send_slave_addr(scl, sda, delay, (chip << 1) | 0x1)) {
+ debug("i2c_write, no chip responded %02X\n", chip);
+ return -EIO;
+ }
+
+ return failures;
+}
+
+static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip,
+ uchar *buffer, int len)
+{
+ struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+ struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+ unsigned int delay = bus->udelay;
+
+ debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len);
+
+ while (len-- > 0)
+ *buffer++ = i2c_gpio_read_byte(scl, sda, delay, len == 0);
+
+ i2c_gpio_send_stop(scl, sda, delay);
+
+ return 0;
+}
+
+static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+ int ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+
+ if (msg->flags & I2C_M_RD) {
+ ret = i2c_gpio_read_data(bus, msg->addr, msg->buf,
+ msg->len);
+ } else {
+ ret = i2c_gpio_write_data(bus, msg->addr, msg->buf,
+ msg->len, next_is_read);
+ }
+
+ if (ret)
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
+{
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+ struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+ struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+ unsigned int delay = bus->udelay;
+ int ret;
+
+ i2c_gpio_send_start(scl, sda, delay);
+ ret = i2c_gpio_write_byte(scl, sda, delay, (chip << 1) | 0);
+ i2c_gpio_send_stop(scl, sda, delay);
+
+ debug("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
+ __func__, dev->seq, dev->name, chip, chip_flags, ret);
+
+ return ret;
+}
+
+static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz)
+{
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+ struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+ struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+
+ bus->udelay = 1000000 / (speed_hz << 2);
+
+ i2c_gpio_send_reset(scl, sda, bus->udelay);
+
+ return 0;
+}
+
+static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
+ int ret;
+
+ ret = gpio_request_list_by_name(dev, "gpios", bus->gpios,
+ ARRAY_SIZE(bus->gpios), 0);
+ if (ret < 0)
+ goto error;
+
+ bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
+ DEFAULT_UDELAY);
+
+ return 0;
+error:
+ error("Can't get %s gpios! Error: %d", dev->name, ret);
+ return ret;
+}
+
+static const struct dm_i2c_ops i2c_gpio_ops = {
+ .xfer = i2c_gpio_xfer,
+ .probe_chip = i2c_gpio_probe,
+ .set_bus_speed = i2c_gpio_set_bus_speed,
+};
+
+static const struct udevice_id i2c_gpio_ids[] = {
+ { .compatible = "i2c-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_gpio) = {
+ .name = "i2c-gpio",
+ .id = UCLASS_I2C,
+ .of_match = i2c_gpio_ids,
+ .ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
+ .ops = &i2c_gpio_ops,
+};
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index b890806a44..f2e95c0881 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -330,7 +330,7 @@ int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
int dm_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
- struct dm_i2c_bus *i2c = bus->uclass_priv;
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
int ret;
/*
@@ -351,7 +351,7 @@ int dm_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
int dm_i2c_get_bus_speed(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
- struct dm_i2c_bus *i2c = bus->uclass_priv;
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
if (!ops->get_bus_speed)
return i2c->speed_hz;
@@ -432,7 +432,7 @@ int i2c_chip_ofdata_to_platdata(const void *blob, int node,
static int i2c_post_probe(struct udevice *dev)
{
- struct dm_i2c_bus *i2c = dev->uclass_priv;
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"clock-frequency", 100000);
diff --git a/drivers/i2c/i2c-uniphier-f.c b/drivers/i2c/i2c-uniphier-f.c
index fd28c17399..d29dd4565d 100644
--- a/drivers/i2c/i2c-uniphier-f.c
+++ b/drivers/i2c/i2c-uniphier-f.c
@@ -14,6 +14,7 @@
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
+#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/i2c/i2c-uniphier.c b/drivers/i2c/i2c-uniphier.c
index 666272dd0d..c4972ff501 100644
--- a/drivers/i2c/i2c-uniphier.c
+++ b/drivers/i2c/i2c-uniphier.c
@@ -14,6 +14,7 @@
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
+#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index b4ee33f7da..27ff587440 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -1348,7 +1348,7 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
int node, flags;
- i2c_bus->is_highspeed = dev->of_id->data;
+ i2c_bus->is_highspeed = dev_get_driver_data(dev);
node = dev->of_offset;
if (i2c_bus->is_highspeed) {
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
index a943aa6382..d6adc0f721 100644
--- a/drivers/i2c/sandbox_i2c.c
+++ b/drivers/i2c/sandbox_i2c.c
@@ -50,7 +50,7 @@ static int get_emul(struct udevice *dev, struct udevice **devp,
static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
- struct dm_i2c_bus *i2c = bus->uclass_priv;
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
struct dm_i2c_ops *ops;
struct udevice *emul, *dev;
bool is_read;
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index f4142870b3..fc95646994 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -338,7 +338,7 @@ static int tegra_i2c_probe(struct udevice *dev)
bool is_dvc;
i2c_bus->id = dev->seq;
- i2c_bus->type = dev_get_of_data(dev);
+ i2c_bus->type = dev_get_driver_data(dev);
i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
/*
@@ -360,7 +360,7 @@ static int tegra_i2c_probe(struct udevice *dev)
if (i2c_bus->periph_id == -1)
return -EINVAL;
- is_dvc = dev_get_of_data(dev) == TYPE_DVC;
+ is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
if (is_dvc) {
i2c_bus->control =
&((struct dvc_ctlr *)i2c_bus->regs)->control;
@@ -469,7 +469,7 @@ int tegra_i2c_get_dvc_bus(struct udevice **busp)
for (uclass_first_device(UCLASS_I2C, &bus);
bus;
uclass_next_device(&bus)) {
- if (dev_get_of_data(bus) == TYPE_DVC) {
+ if (dev_get_driver_data(bus) == TYPE_DVC) {
*busp = bus;
return 0;
}
diff --git a/drivers/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c
index 49ee7b2c9b..a31aa77102 100644
--- a/drivers/input/cros_ec_keyb.c
+++ b/drivers/input/cros_ec_keyb.c
@@ -198,7 +198,7 @@ static int cros_ec_keyb_decode_fdt(const void *blob, int node,
return -1;
}
config->ghost_filter = fdtdec_get_bool(blob, node,
- "google,ghost-filter");
+ "google,needs-ghost-filter");
return 0;
}
diff --git a/drivers/input/i8042.c b/drivers/input/i8042.c
index ca1604c540..1769c5e80b 100644
--- a/drivers/input/i8042.c
+++ b/drivers/input/i8042.c
@@ -698,7 +698,14 @@ static int kbd_reset(void)
/* Enable Keyboard */
out8(I8042_COMMAND_REG, 0xae);
+ if (kbd_input_empty() == 0)
+ return -1;
+
+ out8(I8042_COMMAND_REG, 0x60);
+ if (kbd_input_empty() == 0)
+ return -1;
+ out8(I8042_DATA_REG, 0xf4);
if (kbd_input_empty() == 0)
return -1;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 36a8f0d098..0e571d91ea 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -35,6 +35,15 @@ config CROS_EC_LPC
through a legacy port interface, so on x86 machines the main
function of the EC is power and thermal management.
+config CROS_EC_SANDBOX
+ bool "Enable Chrome OS EC sandbox driver"
+ depends on CROS_EC && SANDBOX
+ help
+ Enable a sandbox emulation of the Chrome OS EC. This supports
+ keyboard (use the -l flag to enable the LCD), verified boot context,
+ EC flash read/write/erase support and a few other things. It is
+ enough to perform a Chrome OS verified boot on sandbox.
+
config CROS_EC_SPI
bool "Enable Chrome OS EC SPI driver"
depends on CROS_EC
@@ -44,16 +53,6 @@ config CROS_EC_SPI
provides a faster and more robust interface than I2C but the bugs
are less interesting.
-config DM_CROS_EC
- bool "Enable Driver Model for Chrome OS EC"
- depends on DM
- help
- Enable driver model for the Chrome OS EC interface. This
- allows the cros_ec SPI driver to operate with CONFIG_DM_SPI
- but otherwise makes few changes. Since cros_ec also supports
- LPC (which doesn't support driver model yet), a full
- conversion is not yet possible.
-
config CONFIG_FSL_SEC_MON
bool "Enable FSL SEC_MON Driver"
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6028cd43fb..842209a2ec 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
endif
obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
obj-$(CONFIG_STATUS_LED) += status_led.o
+obj-$(CONFIG_SANDBOX) += swap_case.o
obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 5846e76c49..982bac788d 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -41,10 +41,6 @@ enum {
CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
};
-#ifndef CONFIG_DM_CROS_EC
-static struct cros_ec_dev static_dev, *last_dev;
-#endif
-
DECLARE_GLOBAL_DATA_PTR;
/* Note: depends on enum ec_current_image */
@@ -211,9 +207,7 @@ static int send_command_proto3(struct cros_ec_dev *dev,
const void *dout, int dout_len,
uint8_t **dinp, int din_len)
{
-#ifdef CONFIG_DM_CROS_EC
struct dm_cros_ec_ops *ops;
-#endif
int out_bytes, in_bytes;
int rv;
@@ -228,28 +222,8 @@ static int send_command_proto3(struct cros_ec_dev *dev,
if (in_bytes < 0)
return in_bytes;
-#ifdef CONFIG_DM_CROS_EC
ops = dm_cros_ec_get_ops(dev->dev);
rv = ops->packet ? ops->packet(dev->dev, out_bytes, in_bytes) : -ENOSYS;
-#else
- switch (dev->interface) {
-#ifdef CONFIG_CROS_EC_SPI
- case CROS_EC_IF_SPI:
- rv = cros_ec_spi_packet(dev, out_bytes, in_bytes);
- break;
-#endif
-#ifdef CONFIG_CROS_EC_SANDBOX
- case CROS_EC_IF_SANDBOX:
- rv = cros_ec_sandbox_packet(dev, out_bytes, in_bytes);
- break;
-#endif
- case CROS_EC_IF_NONE:
- /* TODO: support protocol 3 for LPC, I2C; for now fall through */
- default:
- debug("%s: Unsupported interface\n", __func__);
- rv = -1;
- }
-#endif
if (rv < 0)
return rv;
@@ -261,9 +235,7 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
const void *dout, int dout_len,
uint8_t **dinp, int din_len)
{
-#ifdef CONFIG_DM_CROS_EC
struct dm_cros_ec_ops *ops;
-#endif
int ret = -1;
/* Handle protocol version 3 support */
@@ -272,38 +244,9 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
dout, dout_len, dinp, din_len);
}
-#ifdef CONFIG_DM_CROS_EC
ops = dm_cros_ec_get_ops(dev->dev);
ret = ops->command(dev->dev, cmd, cmd_version,
(const uint8_t *)dout, dout_len, dinp, din_len);
-#else
- switch (dev->interface) {
-#ifdef CONFIG_CROS_EC_SPI
- case CROS_EC_IF_SPI:
- ret = cros_ec_spi_command(dev, cmd, cmd_version,
- (const uint8_t *)dout, dout_len,
- dinp, din_len);
- break;
-#endif
-#ifdef CONFIG_CROS_EC_I2C
- case CROS_EC_IF_I2C:
- ret = cros_ec_i2c_command(dev, cmd, cmd_version,
- (const uint8_t *)dout, dout_len,
- dinp, din_len);
- break;
-#endif
-#ifdef CONFIG_CROS_EC_LPC
- case CROS_EC_IF_LPC:
- ret = cros_ec_lpc_command(dev, cmd, cmd_version,
- (const uint8_t *)dout, dout_len,
- dinp, din_len);
- break;
-#endif
- case CROS_EC_IF_NONE:
- default:
- ret = -1;
- }
-#endif
return ret;
}
@@ -681,11 +624,15 @@ static int cros_ec_check_version(struct cros_ec_dev *dev)
struct ec_params_hello req;
struct ec_response_hello *resp;
-#ifdef CONFIG_CROS_EC_LPC
- /* LPC has its own way of doing this */
- if (dev->interface == CROS_EC_IF_LPC)
- return cros_ec_lpc_check_version(dev);
-#endif
+ struct dm_cros_ec_ops *ops;
+ int ret;
+
+ ops = dm_cros_ec_get_ops(dev->dev);
+ if (ops->check_version) {
+ ret = ops->check_version(dev->dev);
+ if (ret)
+ return ret;
+ }
/*
* TODO(sjg@chromium.org).
@@ -1015,79 +962,9 @@ int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
return 0;
}
-#ifndef CONFIG_DM_CROS_EC
-/**
- * Decode EC interface details from the device tree and allocate a suitable
- * device.
- *
- * @param blob Device tree blob
- * @param node Node to decode from
- * @param devp Returns a pointer to the new allocated device
- * @return 0 if ok, -1 on error
- */
-static int cros_ec_decode_fdt(const void *blob, int node,
- struct cros_ec_dev **devp)
-{
- enum fdt_compat_id compat;
- struct cros_ec_dev *dev;
- int parent;
-
- /* See what type of parent we are inside (this is expensive) */
- parent = fdt_parent_offset(blob, node);
- if (parent < 0) {
- debug("%s: Cannot find node parent\n", __func__);
- return -1;
- }
-
- dev = &static_dev;
- dev->node = node;
- dev->parent_node = parent;
-
- compat = fdtdec_lookup(blob, parent);
- switch (compat) {
-#ifdef CONFIG_CROS_EC_SPI
- case COMPAT_SAMSUNG_EXYNOS_SPI:
- dev->interface = CROS_EC_IF_SPI;
- if (cros_ec_spi_decode_fdt(dev, blob))
- return -1;
- break;
-#endif
-#ifdef CONFIG_CROS_EC_I2C
- case COMPAT_SAMSUNG_S3C2440_I2C:
- dev->interface = CROS_EC_IF_I2C;
- if (cros_ec_i2c_decode_fdt(dev, blob))
- return -1;
- break;
-#endif
-#ifdef CONFIG_CROS_EC_LPC
- case COMPAT_INTEL_LPC:
- dev->interface = CROS_EC_IF_LPC;
- break;
-#endif
-#ifdef CONFIG_CROS_EC_SANDBOX
- case COMPAT_SANDBOX_HOST_EMULATION:
- dev->interface = CROS_EC_IF_SANDBOX;
- break;
-#endif
- default:
- debug("%s: Unknown compat id %d\n", __func__, compat);
- return -1;
- }
-
- gpio_request_by_name_nodev(blob, node, "ec-interrupt", 0, &dev->ec_int,
- GPIOD_IS_IN);
- dev->optimise_flash_write = fdtdec_get_bool(blob, node,
- "optimise-flash-write");
- *devp = dev;
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_DM_CROS_EC
int cros_ec_register(struct udevice *dev)
{
- struct cros_ec_dev *cdev = dev->uclass_priv;
+ struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
char id[MSG_BYTES];
@@ -1113,94 +990,6 @@ int cros_ec_register(struct udevice *dev)
return 0;
}
-#else
-int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
-{
- struct cros_ec_dev *dev;
- char id[MSG_BYTES];
-#ifdef CONFIG_DM_CROS_EC
- struct udevice *udev;
- int ret;
-
- ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev);
- if (!ret)
- device_remove(udev);
- ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
- if (ret)
- return ret;
- dev = udev->uclass_priv;
- return 0;
-#else
- int node = 0;
-
- *cros_ecp = NULL;
- do {
- node = fdtdec_next_compatible(blob, node,
- COMPAT_GOOGLE_CROS_EC);
- if (node < 0) {
- debug("%s: Node not found\n", __func__);
- return 0;
- }
- } while (!fdtdec_get_is_enabled(blob, node));
-
- if (cros_ec_decode_fdt(blob, node, &dev)) {
- debug("%s: Failed to decode device.\n", __func__);
- return -CROS_EC_ERR_FDT_DECODE;
- }
-
- switch (dev->interface) {
-#ifdef CONFIG_CROS_EC_SPI
- case CROS_EC_IF_SPI:
- if (cros_ec_spi_init(dev, blob)) {
- debug("%s: Could not setup SPI interface\n", __func__);
- return -CROS_EC_ERR_DEV_INIT;
- }
- break;
-#endif
-#ifdef CONFIG_CROS_EC_I2C
- case CROS_EC_IF_I2C:
- if (cros_ec_i2c_init(dev, blob))
- return -CROS_EC_ERR_DEV_INIT;
- break;
-#endif
-#ifdef CONFIG_CROS_EC_LPC
- case CROS_EC_IF_LPC:
- if (cros_ec_lpc_init(dev, blob))
- return -CROS_EC_ERR_DEV_INIT;
- break;
-#endif
-#ifdef CONFIG_CROS_EC_SANDBOX
- case CROS_EC_IF_SANDBOX:
- if (cros_ec_sandbox_init(dev, blob))
- return -CROS_EC_ERR_DEV_INIT;
- break;
-#endif
- case CROS_EC_IF_NONE:
- default:
- return 0;
- }
-#endif
-
- if (cros_ec_check_version(dev)) {
- debug("%s: Could not detect CROS-EC version\n", __func__);
- return -CROS_EC_ERR_CHECK_VERSION;
- }
-
- if (cros_ec_read_id(dev, id, sizeof(id))) {
- debug("%s: Could not read KBC ID\n", __func__);
- return -CROS_EC_ERR_READ_ID;
- }
-
- /* Remember this device for use by the cros_ec command */
- *cros_ecp = dev;
-#ifndef CONFIG_DM_CROS_EC
- last_dev = dev;
-#endif
- debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
-
- return 0;
-}
-#endif
int cros_ec_decode_region(int argc, char * const argv[])
{
@@ -1583,9 +1372,7 @@ static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag,
static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct cros_ec_dev *dev;
-#ifdef CONFIG_DM_CROS_EC
struct udevice *udev;
-#endif
const char *cmd;
int ret = 0;
@@ -1594,31 +1381,24 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
cmd = argv[1];
if (0 == strcmp("init", cmd)) {
-#ifndef CONFIG_DM_CROS_EC
- ret = cros_ec_init(gd->fdt_blob, &dev);
+ /* Remove any existing device */
+ ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev);
+ if (!ret)
+ device_remove(udev);
+ ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
if (ret) {
printf("Could not init cros_ec device (err %d)\n", ret);
return 1;
}
-#endif
return 0;
}
-#ifdef CONFIG_DM_CROS_EC
ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
if (ret) {
printf("Cannot get cros-ec device (err=%d)\n", ret);
return 1;
}
- dev = udev->uclass_priv;
-#else
- /* Just use the last allocated device; there should be only one */
- if (!last_dev) {
- printf("No CROS-EC device available\n");
- return 1;
- }
- dev = last_dev;
-#endif
+ dev = dev_get_uclass_priv(udev);
if (0 == strcmp("id", cmd)) {
char id[MSG_BYTES];
@@ -1876,10 +1656,8 @@ U_BOOT_CMD(
);
#endif
-#ifdef CONFIG_DM_CROS_EC
UCLASS_DRIVER(cros_ec) = {
.id = UCLASS_CROS_EC,
.name = "cros_ec",
.per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
};
-#endif
diff --git a/drivers/misc/cros_ec_i2c.c b/drivers/misc/cros_ec_i2c.c
index f9bc9750d4..3de18b2d2a 100644
--- a/drivers/misc/cros_ec_i2c.c
+++ b/drivers/misc/cros_ec_i2c.c
@@ -28,7 +28,7 @@ static int cros_ec_i2c_command(struct udevice *udev, uint8_t cmd,
int cmd_version, const uint8_t *dout,
int dout_len, uint8_t **dinp, int din_len)
{
- struct cros_ec_dev *dev = udev->uclass_priv;
+ struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
/* version8, cmd8, arglen8, out8[dout_len], csum8 */
int out_bytes = dout_len + 4;
/* response8, arglen8, in8[din_len], checksum8 */
@@ -139,12 +139,12 @@ static struct dm_cros_ec_ops cros_ec_ops = {
};
static const struct udevice_id cros_ec_ids[] = {
- { .compatible = "google,cros-ec" },
+ { .compatible = "google,cros-ec-i2c" },
{ }
};
U_BOOT_DRIVER(cros_ec_i2c) = {
- .name = "cros_ec",
+ .name = "cros_ec_i2c",
.id = UCLASS_CROS_EC,
.of_match = cros_ec_ids,
.probe = cros_ec_probe,
diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c
index 07624a136f..78378410f4 100644
--- a/drivers/misc/cros_ec_lpc.c
+++ b/drivers/misc/cros_ec_lpc.c
@@ -14,6 +14,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <command.h>
#include <cros_ec.h>
#include <asm/io.h>
@@ -40,10 +41,11 @@ static int wait_for_sync(struct cros_ec_dev *dev)
return 0;
}
-int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+int cros_ec_lpc_command(struct udevice *udev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len)
{
+ struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
const int cmd_addr = EC_LPC_ADDR_HOST_CMD;
const int data_addr = EC_LPC_ADDR_HOST_DATA;
const int args_addr = EC_LPC_ADDR_HOST_ARGS;
@@ -178,7 +180,7 @@ int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob)
* seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag
* in args when it responds.
*/
-int cros_ec_lpc_check_version(struct cros_ec_dev *dev)
+static int cros_ec_lpc_check_version(struct udevice *dev)
{
if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) == 'E' &&
inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1)
@@ -192,3 +194,26 @@ int cros_ec_lpc_check_version(struct cros_ec_dev *dev)
printf("%s: ERROR: old EC interface not supported\n", __func__);
return -1;
}
+
+static int cros_ec_probe(struct udevice *dev)
+{
+ return cros_ec_register(dev);
+}
+
+static struct dm_cros_ec_ops cros_ec_ops = {
+ .command = cros_ec_lpc_command,
+ .check_version = cros_ec_lpc_check_version,
+};
+
+static const struct udevice_id cros_ec_ids[] = {
+ { .compatible = "google,cros-ec-lpc" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_lpc) = {
+ .name = "cros_ec_lpc",
+ .id = UCLASS_CROS_EC,
+ .of_match = cros_ec_ids,
+ .probe = cros_ec_probe,
+ .ops = &cros_ec_ops,
+};
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index 99cc5297cf..df41e82bc9 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -467,17 +467,10 @@ static int process_cmd(struct ec_state *ec,
return len;
}
-#ifdef CONFIG_DM_CROS_EC
int cros_ec_sandbox_packet(struct udevice *udev, int out_bytes, int in_bytes)
{
- struct cros_ec_dev *dev = udev->uclass_priv;
+ struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
struct ec_state *ec = dev_get_priv(dev->dev);
-#else
-int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes,
- int in_bytes)
-{
- struct ec_state *ec = &s_state;
-#endif
struct ec_host_request *req_hdr = (struct ec_host_request *)dev->dout;
const void *req_data = req_hdr + 1;
struct ec_host_response *resp_hdr = (struct ec_host_response *)dev->din;
@@ -500,18 +493,9 @@ int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes,
return in_bytes;
}
-int cros_ec_sandbox_decode_fdt(struct cros_ec_dev *dev, const void *blob)
-{
- return 0;
-}
-
void cros_ec_check_keyboard(struct cros_ec_dev *dev)
{
-#ifdef CONFIG_DM_CROS_EC
struct ec_state *ec = dev_get_priv(dev->dev);
-#else
- struct ec_state *ec = &s_state;
-#endif
ulong start;
printf("Press keys for EC to detect on reset (ESC=recovery)...");
@@ -525,7 +509,6 @@ void cros_ec_check_keyboard(struct cros_ec_dev *dev)
}
}
-#ifdef CONFIG_DM_CROS_EC
int cros_ec_probe(struct udevice *dev)
{
struct ec_state *ec = dev->priv;
@@ -569,76 +552,20 @@ int cros_ec_probe(struct udevice *dev)
return cros_ec_register(dev);
}
-#else
-
-/**
- * Initialize sandbox EC emulation.
- *
- * @param dev CROS_EC device
- * @param blob Device tree blob
- * @return 0 if ok, -1 on error
- */
-int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob)
-{
- struct ec_state *ec = &s_state;
- int node;
- int err;
-
- node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC);
- if (node < 0) {
- debug("Failed to find chrome-ec node'\n");
- return -1;
- }
-
- err = cros_ec_decode_ec_flash(blob, node, &ec->ec_config);
- if (err)
- return err;
-
- node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB);
- if (node < 0) {
- debug("%s: No cros_ec keyboard found\n", __func__);
- } else if (keyscan_read_fdt_matrix(ec, blob, node)) {
- debug("%s: Could not read key matrix\n", __func__);
- return -1;
- }
-
- /* If we loaded EC data, check that the length matches */
- if (ec->flash_data &&
- ec->flash_data_len != ec->ec_config.flash.length) {
- printf("EC data length is %x, expected %x, discarding data\n",
- ec->flash_data_len, ec->ec_config.flash.length);
- os_free(ec->flash_data);
- ec->flash_data = NULL;
- }
-
- /* Otherwise allocate the memory */
- if (!ec->flash_data) {
- ec->flash_data_len = ec->ec_config.flash.length;
- ec->flash_data = os_malloc(ec->flash_data_len);
- if (!ec->flash_data)
- return -ENOMEM;
- }
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_DM_CROS_EC
struct dm_cros_ec_ops cros_ec_ops = {
.packet = cros_ec_sandbox_packet,
};
static const struct udevice_id cros_ec_ids[] = {
- { .compatible = "google,cros-ec" },
+ { .compatible = "google,cros-ec-sandbox" },
{ }
};
U_BOOT_DRIVER(cros_ec_sandbox) = {
- .name = "cros_ec",
+ .name = "cros_ec_sandbox",
.id = UCLASS_CROS_EC,
.of_match = cros_ec_ids,
.probe = cros_ec_probe,
.priv_auto_alloc_size = sizeof(struct ec_state),
.ops = &cros_ec_ops,
};
-#endif
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index 9359c56e87..ac2ee86eda 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -23,7 +23,7 @@ DECLARE_GLOBAL_DATA_PTR;
int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
{
- struct cros_ec_dev *dev = udev->uclass_priv;
+ struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
struct spi_slave *slave = dev_get_parentdata(dev->dev);
int rv;
@@ -66,7 +66,7 @@ int cros_ec_spi_command(struct udevice *udev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len)
{
- struct cros_ec_dev *dev = udev->uclass_priv;
+ struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
struct spi_slave *slave = dev_get_parentdata(dev->dev);
int in_bytes = din_len + 4; /* status, length, checksum, trailer */
uint8_t *out;
@@ -165,12 +165,12 @@ static struct dm_cros_ec_ops cros_ec_ops = {
};
static const struct udevice_id cros_ec_ids[] = {
- { .compatible = "google,cros-ec" },
+ { .compatible = "google,cros-ec-spi" },
{ }
};
U_BOOT_DRIVER(cros_ec_spi) = {
- .name = "cros_ec",
+ .name = "cros_ec_spi",
.id = UCLASS_CROS_EC,
.of_match = cros_ec_ids,
.probe = cros_ec_probe,
diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c
new file mode 100644
index 0000000000..f6028ba332
--- /dev/null
+++ b/drivers/misc/swap_case.c
@@ -0,0 +1,285 @@
+/*
+ * PCI emulation device which swaps the case of text
+ *
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/test.h>
+#include <linux/ctype.h>
+
+/**
+ * struct swap_case_platdata - platform data for this device
+ *
+ * @command: Current PCI command value
+ * @bar: Current base address values
+ */
+struct swap_case_platdata {
+ u16 command;
+ u32 bar[2];
+};
+
+#define offset_to_barnum(offset) \
+ (((offset) - PCI_BASE_ADDRESS_0) / sizeof(u32))
+
+enum {
+ MEM_TEXT_SIZE = 0x100,
+};
+
+enum swap_case_op {
+ OP_TO_LOWER,
+ OP_TO_UPPER,
+ OP_SWAP,
+};
+
+static struct pci_bar {
+ int type;
+ u32 size;
+} barinfo[] = {
+ { PCI_BASE_ADDRESS_SPACE_IO, 1 },
+ { PCI_BASE_ADDRESS_MEM_TYPE_32, MEM_TEXT_SIZE },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+};
+
+struct swap_case_priv {
+ enum swap_case_op op;
+ char mem_text[MEM_TEXT_SIZE];
+};
+
+static int sandbox_swap_case_get_devfn(struct udevice *dev)
+{
+ struct pci_child_platdata *plat = dev_get_parent_platdata(dev);
+
+ return plat->devfn;
+}
+
+static int sandbox_swap_case_read_config(struct udevice *emul, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ struct swap_case_platdata *plat = dev_get_platdata(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ *valuep = plat->command;
+ break;
+ case PCI_HEADER_TYPE:
+ *valuep = 0;
+ break;
+ case PCI_VENDOR_ID:
+ *valuep = SANDBOX_PCI_VENDOR_ID;
+ break;
+ case PCI_DEVICE_ID:
+ *valuep = SANDBOX_PCI_DEVICE_ID;
+ break;
+ case PCI_CLASS_DEVICE:
+ if (size == PCI_SIZE_8) {
+ *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
+ } else {
+ *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
+ SANDBOX_PCI_CLASS_SUB_CODE;
+ }
+ break;
+ case PCI_CLASS_CODE:
+ *valuep = SANDBOX_PCI_CLASS_CODE;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1:
+ case PCI_BASE_ADDRESS_2:
+ case PCI_BASE_ADDRESS_3:
+ case PCI_BASE_ADDRESS_4:
+ case PCI_BASE_ADDRESS_5: {
+ int barnum;
+ u32 *bar, result;
+
+ barnum = offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ result = *bar;
+ if (*bar == 0xffffffff) {
+ if (barinfo[barnum].type) {
+ result = (~(barinfo[barnum].size - 1) &
+ PCI_BASE_ADDRESS_IO_MASK) |
+ PCI_BASE_ADDRESS_SPACE_IO;
+ } else {
+ result = (~(barinfo[barnum].size - 1) &
+ PCI_BASE_ADDRESS_MEM_MASK) |
+ PCI_BASE_ADDRESS_MEM_TYPE_32;
+ }
+ }
+ debug("r bar %d=%x\n", barnum, result);
+ *valuep = result;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_swap_case_write_config(struct udevice *emul, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ struct swap_case_platdata *plat = dev_get_platdata(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ plat->command = value;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1: {
+ int barnum;
+ u32 *bar;
+
+ barnum = offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ debug("w bar %d=%lx\n", barnum, value);
+ *bar = value;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_swap_case_find_bar(struct udevice *emul, unsigned int addr,
+ int *barnump, unsigned int *offsetp)
+{
+ struct swap_case_platdata *plat = dev_get_platdata(emul);
+ int barnum;
+
+ for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
+ unsigned int size = barinfo[barnum].size;
+
+ if (addr >= plat->bar[barnum] &&
+ addr < plat->bar[barnum] + size) {
+ *barnump = barnum;
+ *offsetp = addr - plat->bar[barnum];
+ return 0;
+ }
+ }
+ *barnump = -1;
+
+ return -ENOENT;
+}
+
+static void sandbox_swap_case_do_op(enum swap_case_op op, char *str, int len)
+{
+ for (; len > 0; len--, str++) {
+ switch (op) {
+ case OP_TO_UPPER:
+ *str = toupper(*str);
+ break;
+ case OP_TO_LOWER:
+ *str = tolower(*str);
+ break;
+ case OP_SWAP:
+ if (isupper(*str))
+ *str = tolower(*str);
+ else
+ *str = toupper(*str);
+ break;
+ }
+ }
+}
+
+int sandbox_swap_case_read_io(struct udevice *dev, unsigned int addr,
+ ulong *valuep, enum pci_size_t size)
+{
+ struct swap_case_priv *priv = dev_get_priv(dev);
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ if (barnum == 0 && offset == 0)
+ *valuep = (*valuep & ~0xff) | priv->op;
+
+ return 0;
+}
+
+int sandbox_swap_case_write_io(struct udevice *dev, unsigned int addr,
+ ulong value, enum pci_size_t size)
+{
+ struct swap_case_priv *priv = dev_get_priv(dev);
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+ if (barnum == 0 && offset == 0)
+ priv->op = value;
+
+ return 0;
+}
+
+static int sandbox_swap_case_map_physmem(struct udevice *dev,
+ phys_addr_t addr, unsigned long *lenp, void **ptrp)
+{
+ struct swap_case_priv *priv = dev_get_priv(dev);
+ unsigned int offset, avail;
+ int barnum;
+ int ret;
+
+ ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+ if (barnum == 1) {
+ *ptrp = priv->mem_text + offset;
+ avail = barinfo[1].size - offset;
+ if (avail > barinfo[1].size)
+ *lenp = 0;
+ else
+ *lenp = min(*lenp, (ulong)avail);
+
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static int sandbox_swap_case_unmap_physmem(struct udevice *dev,
+ const void *vaddr, unsigned long len)
+{
+ struct swap_case_priv *priv = dev_get_priv(dev);
+
+ sandbox_swap_case_do_op(priv->op, (void *)vaddr, len);
+
+ return 0;
+}
+
+struct dm_pci_emul_ops sandbox_swap_case_emul_ops = {
+ .get_devfn = sandbox_swap_case_get_devfn,
+ .read_config = sandbox_swap_case_read_config,
+ .write_config = sandbox_swap_case_write_config,
+ .read_io = sandbox_swap_case_read_io,
+ .write_io = sandbox_swap_case_write_io,
+ .map_physmem = sandbox_swap_case_map_physmem,
+ .unmap_physmem = sandbox_swap_case_unmap_physmem,
+};
+
+static const struct udevice_id sandbox_swap_case_ids[] = {
+ { .compatible = "sandbox,swap-case" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_swap_case_emul) = {
+ .name = "sandbox_swap_case_emul",
+ .id = UCLASS_PCI_EMUL,
+ .of_match = sandbox_swap_case_ids,
+ .ops = &sandbox_swap_case_emul_ops,
+ .priv_auto_alloc_size = sizeof(struct swap_case_priv),
+ .platdata_auto_alloc_size = sizeof(struct swap_case_platdata),
+};
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 2dc46b4b34..ac6d09f928 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -1,6 +1,6 @@
config DM_SPI_FLASH
bool "Enable Driver Model for SPI flash"
- depends on DM && SPI
+ depends on DM && DM_SPI
help
Enable driver model for SPI flash. This SPI flash interface
(spi_flash_probe(), spi_flash_write(), etc.) is then
@@ -12,3 +12,13 @@ config DM_SPI_FLASH
during the transition parent. SPI and SPI flash must be
enabled together (it is not possible to use driver model
for one and not the other).
+
+config SPI_FLASH_SANDBOX
+ bool "Support sandbox SPI flash device"
+ depends on SANDBOX && DM_SPI_FLASH
+ help
+ Since sandbox cannot access real devices, an emulation mechanism is
+ provided instead. Drivers can be connected up to the sandbox SPI
+ bus (see CONFIG_SANDBOX_SPI) and SPI traffic will be routed to this
+ device. Typically the contents of the emulated SPI flash device is
+ stored in a file on the host filesystem.
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
index 376d815026..4b25902b8d 100644
--- a/drivers/mtd/spi/sf-uclass.c
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -11,6 +11,22 @@
#include <dm/device-internal.h>
#include "sf_internal.h"
+int spi_flash_read_dm(struct udevice *dev, u32 offset, size_t len, void *buf)
+{
+ return sf_get_ops(dev)->read(dev, offset, len, buf);
+}
+
+int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len,
+ const void *buf)
+{
+ return sf_get_ops(dev)->write(dev, offset, len, buf);
+}
+
+int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len)
+{
+ return sf_get_ops(dev)->erase(dev, offset, len);
+}
+
/*
* TODO(sjg@chromium.org): This is an old-style function. We should remove
* it when all SPI flash drivers use dm
@@ -23,7 +39,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
if (spi_flash_probe_bus_cs(bus, cs, max_hz, spi_mode, &dev))
return NULL;
- return dev->uclass_priv;
+ return dev_get_uclass_priv(dev);
}
void spi_flash_free(struct spi_flash *flash)
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 4103723859..d19138d907 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -13,6 +13,7 @@
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
+#include <mapmem.h>
#include <spi.h>
#include <spi_flash.h>
#include <asm/io.h>
@@ -458,7 +459,7 @@ void spi_flash_free(struct spi_flash *flash)
static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
void *buf)
{
- struct spi_flash *flash = dev->uclass_priv;
+ struct spi_flash *flash = dev_get_uclass_priv(dev);
return spi_flash_cmd_read_ops(flash, offset, len, buf);
}
@@ -466,14 +467,14 @@ static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
const void *buf)
{
- struct spi_flash *flash = dev->uclass_priv;
+ struct spi_flash *flash = dev_get_uclass_priv(dev);
return spi_flash_cmd_write_ops(flash, offset, len, buf);
}
int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
{
- struct spi_flash *flash = dev->uclass_priv;
+ struct spi_flash *flash = dev_get_uclass_priv(dev);
return spi_flash_cmd_erase_ops(flash, offset, len);
}
@@ -484,7 +485,7 @@ int spi_flash_std_probe(struct udevice *dev)
struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
struct spi_flash *flash;
- flash = dev->uclass_priv;
+ flash = dev_get_uclass_priv(dev);
flash->dev = dev;
debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs);
return spi_flash_probe_slave(slave, flash);
diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c
index 381ec42864..3c30f42b42 100644
--- a/drivers/net/4xx_enet.c
+++ b/drivers/net/4xx_enet.c
@@ -1350,7 +1350,7 @@ get_speed:
for (i = 0; i < NUM_RX_BUFF; i++) {
hw_p->rx[i].ctrl = 0;
hw_p->rx[i].data_len = 0;
- hw_p->rx[i].data_ptr = (char *)NetRxPackets[i];
+ hw_p->rx[i].data_ptr = (char *)net_rx_packets[i];
if ((NUM_RX_BUFF - 1) == i)
hw_p->rx[i].ctrl |= MAL_RX_CTRL_WRAP;
hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
@@ -1719,8 +1719,6 @@ static void mal_err (struct eth_device *dev, unsigned long isr,
unsigned long uic, unsigned long maldef,
unsigned long mal_errr)
{
- EMAC_4XX_HW_PST hw_p = dev->priv;
-
mtdcr (MAL0_ESR, isr); /* clear interrupt */
/* clear DE interrupt */
@@ -1728,10 +1726,11 @@ static void mal_err (struct eth_device *dev, unsigned long isr,
mtdcr (MAL0_RXDEIR, 0x80000000);
#ifdef INFO_4XX_ENET
- printf ("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx \n", isr, uic, maldef, mal_errr);
+ printf("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx\n",
+ isr, uic, maldef, mal_errr);
#endif
- eth_init (hw_p->bis); /* start again... */
+ eth_init(); /* start again... */
}
/*-----------------------------------------------------------------------------+
@@ -1859,13 +1858,17 @@ static int ppc_4xx_eth_rx (struct eth_device *dev)
length = hw_p->rx[user_index].data_len & 0x0fff;
- /* Pass the packet up to the protocol layers. */
- /* NetReceive(NetRxPackets[rxIdx], length - 4); */
- /* NetReceive(NetRxPackets[i], length); */
+ /*
+ * Pass the packet up to the protocol layers.
+ * net_process_received_packet(net_rx_packets[rxIdx],
+ * length - 4);
+ * net_process_received_packet(net_rx_packets[i], length);
+ */
invalidate_dcache_range((u32)hw_p->rx[user_index].data_ptr,
(u32)hw_p->rx[user_index].data_ptr +
length - 4);
- NetReceive (NetRxPackets[user_index], length - 4);
+ net_process_received_packet(net_rx_packets[user_index],
+ length - 4);
/* Free Recv Buffer */
hw_p->rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY;
/* Free rx buffer descriptor queue */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index e69de29bb2..973258a80c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -0,0 +1,49 @@
+config DM_ETH
+ bool "Enable Driver Model for Ethernet drivers"
+ depends on DM
+ help
+ Enable driver model for Ethernet.
+
+ The eth_*() interface will be implemented by the UC_ETH class
+ This is currently implemented in net/eth.c
+ Look in include/net.h for details.
+
+menuconfig NETDEVICES
+ bool "Network device support"
+ depends on NET
+ help
+ You must select Y to enable any network device support
+ Generally if you have any networking support this is a given
+
+ If unsure, say Y
+
+if NETDEVICES
+
+config ETH_SANDBOX
+ depends on DM_ETH && SANDBOX
+ default y
+ bool "Sandbox: Mocked Ethernet driver"
+ help
+ This driver simply responds with fake ARP replies and ping
+ replies that are used to verify network stack functionality
+
+ This driver is particularly useful in the test/dm/eth.c tests
+
+config ETH_SANDBOX_RAW
+ depends on DM_ETH && SANDBOX
+ default y
+ bool "Sandbox: Bridge to Linux Raw Sockets"
+ help
+ This driver is a bridge from the bottom of the network stack
+ in U-Boot to the RAW AF_PACKET API in Linux. This allows real
+ network traffic to be tested from within sandbox. See
+ board/sandbox/README.sandbox for more details.
+
+config ETH_DESIGNWARE
+ bool "Synopsys Designware Ethernet MAC"
+ help
+ This MAC is present in SoCs from various vendors. It supports
+ 100Mbit and 1 Gbit operation. You must enable CONFIG_PHYLIB to
+ provide the PHY (physical media interface).
+
+endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 5a5269aa06..f24443df71 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -16,7 +16,7 @@ obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
obj-$(CONFIG_CS8900) += cs8900.o
obj-$(CONFIG_TULIP) += dc2114x.o
-obj-$(CONFIG_DESIGNWARE_ETH) += designware.o
+obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
obj-$(CONFIG_DNET) += dnet.o
obj-$(CONFIG_E1000) += e1000.o
@@ -51,6 +51,8 @@ obj-$(CONFIG_PCH_GBE) += pch_gbe.o
obj-$(CONFIG_PCNET) += pcnet.o
obj-$(CONFIG_RTL8139) += rtl8139.o
obj-$(CONFIG_RTL8169) += rtl8169.o
+obj-$(CONFIG_ETH_SANDBOX) += sandbox.o
+obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o
obj-$(CONFIG_SH_ETHER) += sh_eth.o
obj-$(CONFIG_SMC91111) += smc91111.o
obj-$(CONFIG_SMC911X) += smc911x.o
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c
index de517f8dab..c4fd6ec2e9 100644
--- a/drivers/net/altera_tse.c
+++ b/drivers/net/altera_tse.c
@@ -303,16 +303,17 @@ static int tse_eth_rx(struct eth_device *dev)
ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) {
debug("got packet\n");
packet_length = rx_desc->actual_bytes_transferred;
- NetReceive(NetRxPackets[0], packet_length);
+ net_process_received_packet(net_rx_packets[0], packet_length);
/* start descriptor again */
- flush_dcache_range((unsigned long)(NetRxPackets[0]),
- (unsigned long)(NetRxPackets[0]) + PKTSIZE_ALIGN);
+ flush_dcache_range((unsigned long)(net_rx_packets[0]),
+ (unsigned long)(net_rx_packets[0] +
+ PKTSIZE_ALIGN));
alt_sgdma_construct_descriptor_burst(
(volatile struct alt_sgdma_descriptor *)&rx_desc[0],
(volatile struct alt_sgdma_descriptor *)&rx_desc[1],
(unsigned int)0x0, /* read addr */
- (unsigned int *)NetRxPackets[0],
+ (unsigned int *)net_rx_packets[0],
0x0, /* length or EOP */
0x0, /* gen eop */
0x0, /* read fixed */
@@ -835,13 +836,13 @@ static int tse_eth_init(struct eth_device *dev, bd_t * bd)
0x0 /* channel */
);
debug("Configuring rx desc\n");
- flush_dcache_range((unsigned long)(NetRxPackets[0]),
- (unsigned long)(NetRxPackets[0]) + PKTSIZE_ALIGN);
+ flush_dcache_range((unsigned long)(net_rx_packets[0]),
+ (unsigned long)(net_rx_packets[0]) + PKTSIZE_ALIGN);
alt_sgdma_construct_descriptor_burst(
(volatile struct alt_sgdma_descriptor *)&rx_desc[0],
(volatile struct alt_sgdma_descriptor *)&rx_desc[1],
(unsigned int)0x0, /* read addr */
- (unsigned int *)NetRxPackets[0],
+ (unsigned int *)net_rx_packets[0],
0x0, /* length or EOP */
0x0, /* gen eop */
0x0, /* read fixed */
diff --git a/drivers/net/armada100_fec.c b/drivers/net/armada100_fec.c
index a8da6b17d0..e6a62525be 100644
--- a/drivers/net/armada100_fec.c
+++ b/drivers/net/armada100_fec.c
@@ -639,15 +639,16 @@ static int armdfec_recv(struct eth_device *dev)
} else {
/* !!! call higher layer processing */
debug("ARMD100 FEC: (%s) Sending Received packet to"
- " upper layer (NetReceive)\n", __func__);
+ " upper layer (net_process_received_packet)\n", __func__);
/*
* let the upper layer handle the packet, subtract offset
* as two dummy bytes are added in received buffer see
* PORT_CONFIG_EXT register bit TWO_Byte_Stuff_Mode bit.
*/
- NetReceive((p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET),
- (int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET));
+ net_process_received_packet(
+ p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET,
+ (int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET));
}
/*
* free these descriptors and point next in the ring
diff --git a/drivers/net/at91_emac.c b/drivers/net/at91_emac.c
index 64d4c56ac5..d51e098c56 100644
--- a/drivers/net/at91_emac.c
+++ b/drivers/net/at91_emac.c
@@ -352,7 +352,7 @@ static int at91emac_init(struct eth_device *netdev, bd_t *bd)
/* Init Ethernet buffers */
for (i = 0; i < RBF_FRAMEMAX; i++) {
- dev->rbfdt[i].addr = (unsigned long) NetRxPackets[i];
+ dev->rbfdt[i].addr = (unsigned long) net_rx_packets[i];
dev->rbfdt[i].size = 0;
}
dev->rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP;
@@ -420,7 +420,7 @@ static int at91emac_recv(struct eth_device *netdev)
rbfp = &dev->rbfdt[dev->rbindex];
while (rbfp->addr & RBF_OWNER) {
size = rbfp->size & RBF_SIZE;
- NetReceive(NetRxPackets[dev->rbindex], size);
+ net_process_received_packet(net_rx_packets[dev->rbindex], size);
debug_cond(DEBUG_AT91EMAC, "Recv[%ld]: %d bytes @ %lx\n",
dev->rbindex, size, rbfp->addr);
diff --git a/drivers/net/ax88180.c b/drivers/net/ax88180.c
index 7f0cfe5940..ded9e064e5 100644
--- a/drivers/net/ax88180.c
+++ b/drivers/net/ax88180.c
@@ -192,9 +192,9 @@ static void ax88180_rx_handler (struct eth_device *dev)
unsigned short rxcurt_ptr, rxbound_ptr, next_ptr;
int i;
#if defined (CONFIG_DRIVER_AX88180_16BIT)
- unsigned short *rxdata = (unsigned short *)NetRxPackets[0];
+ unsigned short *rxdata = (unsigned short *)net_rx_packets[0];
#else
- unsigned long *rxdata = (unsigned long *)NetRxPackets[0];
+ unsigned long *rxdata = (unsigned long *)net_rx_packets[0];
#endif
unsigned short count;
@@ -237,7 +237,7 @@ static void ax88180_rx_handler (struct eth_device *dev)
OUTW (dev, RX_STOP_READ, RXINDICATOR);
/* Pass the packet up to the protocol layers. */
- NetReceive (NetRxPackets[0], data_size);
+ net_process_received_packet(net_rx_packets[0], data_size);
OUTW (dev, rxbound_ptr, RXBOUND);
diff --git a/drivers/net/bcm-sf2-eth.c b/drivers/net/bcm-sf2-eth.c
index 5252d49de9..51d5146363 100644
--- a/drivers/net/bcm-sf2-eth.c
+++ b/drivers/net/bcm-sf2-eth.c
@@ -103,7 +103,7 @@ static int bcm_sf2_eth_send(struct eth_device *dev, void *packet, int length)
static int bcm_sf2_eth_receive(struct eth_device *dev)
{
struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
- uint8_t *buf = (uint8_t *)NetRxPackets[0];
+ uint8_t *buf = (uint8_t *)net_rx_packets[0];
int rcvlen;
int rc = 0;
int i = 0;
@@ -124,11 +124,11 @@ static int bcm_sf2_eth_receive(struct eth_device *dev)
debug("recieved\n");
/* Forward received packet to uboot network handler */
- NetReceive(buf, rcvlen);
+ net_process_received_packet(buf, rcvlen);
if (++i >= PKTBUFSRX)
i = 0;
- buf = NetRxPackets[i];
+ buf = net_rx_packets[i];
}
}
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 0c2d2ef1a9..61cb1b0cda 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -189,8 +189,8 @@ static int bfin_EMAC_recv(struct eth_device *dev)
debug("%s: len = %d\n", __func__, length - 4);
- NetRxPackets[rxIdx] = rxbuf[rxIdx]->FrmData->Dest;
- NetReceive(NetRxPackets[rxIdx], length - 4);
+ net_rx_packets[rxIdx] = rxbuf[rxIdx]->FrmData->Dest;
+ net_process_received_packet(net_rx_packets[rxIdx], length - 4);
bfin_write_DMA1_IRQ_STATUS(DMA_DONE | DMA_ERR);
rxbuf[rxIdx]->StatusWord = 0x00000000;
if ((rxIdx + 1) >= PKTBUFSRX)
diff --git a/drivers/net/calxedaxgmac.c b/drivers/net/calxedaxgmac.c
index ff94865c5d..c02b397fa1 100644
--- a/drivers/net/calxedaxgmac.c
+++ b/drivers/net/calxedaxgmac.c
@@ -466,7 +466,7 @@ static int xgmac_rx(struct eth_device *dev)
length = desc_get_rx_frame_len(rxdesc);
- NetReceive(desc_get_buf_addr(rxdesc), length);
+ net_process_received_packet(desc_get_buf_addr(rxdesc), length);
/* set descriptor back to owned by XGMAC */
desc_set_rx_owner(rxdesc);
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index 52f8da67e1..fb4d621a88 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -289,7 +289,7 @@ static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
}
-static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr)
+static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr)
{
int i;
@@ -321,7 +321,7 @@ static int cpsw_ale_write(struct cpsw_priv *priv, int idx, u32 *ale_entry)
return idx;
}
-static int cpsw_ale_match_addr(struct cpsw_priv *priv, u8* addr)
+static int cpsw_ale_match_addr(struct cpsw_priv *priv, const u8 *addr)
{
u32 ale_entry[ALE_ENTRY_WORDS];
int type, idx;
@@ -374,7 +374,7 @@ static int cpsw_ale_find_ageable(struct cpsw_priv *priv)
return -ENOENT;
}
-static int cpsw_ale_add_ucast(struct cpsw_priv *priv, u8 *addr,
+static int cpsw_ale_add_ucast(struct cpsw_priv *priv, const u8 *addr,
int port, int flags)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
@@ -399,7 +399,8 @@ static int cpsw_ale_add_ucast(struct cpsw_priv *priv, u8 *addr,
return 0;
}
-static int cpsw_ale_add_mcast(struct cpsw_priv *priv, u8 *addr, int port_mask)
+static int cpsw_ale_add_mcast(struct cpsw_priv *priv, const u8 *addr,
+ int port_mask)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx, mask;
@@ -644,7 +645,7 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
slave_port = cpsw_get_slave_port(priv, slave->slave_num);
cpsw_ale_port_state(priv, slave_port, ALE_PORT_STATE_FORWARD);
- cpsw_ale_add_mcast(priv, NetBcastAddr, 1 << slave_port);
+ cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << slave_port);
priv->phy_mask |= 1 << slave->data->phy_addr;
}
@@ -773,7 +774,7 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis)
cpsw_ale_add_ucast(priv, priv->dev->enetaddr, priv->host_port,
ALE_SECURE);
- cpsw_ale_add_mcast(priv, NetBcastAddr, 1 << priv->host_port);
+ cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << priv->host_port);
for_active_slave(slave, priv)
cpsw_slave_init(slave, priv);
@@ -845,7 +846,7 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis)
/* submit rx descs */
for (i = 0; i < PKTBUFSRX; i++) {
- ret = cpdma_submit(priv, &priv->rx_chan, NetRxPackets[i],
+ ret = cpdma_submit(priv, &priv->rx_chan, net_rx_packets[i],
PKTSIZE);
if (ret < 0) {
printf("error %d submitting rx desc\n", ret);
@@ -904,7 +905,7 @@ static int cpsw_recv(struct eth_device *dev)
while (cpdma_process(priv, &priv->rx_chan, &buffer, &len) >= 0) {
invalidate_dcache_range((unsigned long)buffer,
(unsigned long)buffer + PKTSIZE_ALIGN);
- NetReceive(buffer, len);
+ net_process_received_packet(buffer, len);
cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE);
}
diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c
index 84963c1f22..0713464c77 100644
--- a/drivers/net/cs8900.c
+++ b/drivers/net/cs8900.c
@@ -188,14 +188,13 @@ static int cs8900_recv(struct eth_device *dev)
if (rxlen > PKTSIZE_ALIGN + PKTALIGN)
debug("packet too big!\n");
- for (addr = (u16 *) NetRxPackets[0], i = rxlen >> 1; i > 0;
- i--)
+ for (addr = (u16 *)net_rx_packets[0], i = rxlen >> 1; i > 0; i--)
*addr++ = REG_READ(&priv->regs->rtdata);
if (rxlen & 1)
*addr++ = REG_READ(&priv->regs->rtdata);
/* Pass the packet up to the protocol layers. */
- NetReceive (NetRxPackets[0], rxlen);
+ net_process_received_packet(net_rx_packets[0], rxlen);
return rxlen;
}
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 08bc1afcf6..427ad3e6fa 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -700,8 +700,9 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
unsigned long tmp = (unsigned long)rx_curr_desc->buffer;
invalidate_dcache_range(tmp, tmp + EMAC_RXBUF_SIZE);
- NetReceive (rx_curr_desc->buffer,
- (rx_curr_desc->buff_off_len & 0xffff));
+ net_process_received_packet(
+ rx_curr_desc->buffer,
+ rx_curr_desc->buff_off_len & 0xffff);
ret = rx_curr_desc->buff_off_len & 0xffff;
}
diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
index 799839c4f1..8245cf51cc 100644
--- a/drivers/net/dc2114x.c
+++ b/drivers/net/dc2114x.c
@@ -333,9 +333,11 @@ static int dc21x4x_init(struct eth_device* dev, bd_t* bis)
for (i = 0; i < NUM_RX_DESC; i++) {
rx_ring[i].status = cpu_to_le32(R_OWN);
rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
- rx_ring[i].buf = cpu_to_le32(phys_to_bus((u32) NetRxPackets[i]));
+ rx_ring[i].buf = cpu_to_le32(
+ phys_to_bus((u32)net_rx_packets[i]));
#ifdef CONFIG_TULIP_FIX_DAVICOM
- rx_ring[i].next = cpu_to_le32(phys_to_bus((u32) &rx_ring[(i+1) % NUM_RX_DESC]));
+ rx_ring[i].next = cpu_to_le32(
+ phys_to_bus((u32)&rx_ring[(i + 1) % NUM_RX_DESC]));
#else
rx_ring[i].next = 0;
#endif
@@ -448,7 +450,8 @@ static int dc21x4x_recv(struct eth_device* dev)
/* Pass the packet up to the protocol
* layers.
*/
- NetReceive(NetRxPackets[rx_new], length - 4);
+ net_process_received_packet(
+ net_rx_packets[rx_new], length - 4);
}
/* Change buffer ownership for this frame, back
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index cc01604e60..07281a6ce9 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -6,10 +6,12 @@
*/
/*
- * Designware ethernet IP driver for u-boot
+ * Designware ethernet IP driver for U-Boot
*/
#include <common.h>
+#include <dm.h>
+#include <errno.h>
#include <miiphy.h>
#include <malloc.h>
#include <linux/compiler.h>
@@ -17,6 +19,8 @@
#include <asm/io.h>
#include "designware.h"
+DECLARE_GLOBAL_DATA_PTR;
+
#if !defined(CONFIG_PHYLIB)
# error "DesignWare Ether MAC requires PHYLIB - missing CONFIG_PHYLIB"
#endif
@@ -40,7 +44,7 @@ static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
udelay(10);
};
- return -1;
+ return -ETIMEDOUT;
}
static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
@@ -49,7 +53,7 @@ static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
struct eth_mac_regs *mac_p = bus->priv;
ulong start;
u16 miiaddr;
- int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
+ int ret = -ETIMEDOUT, timeout = CONFIG_MDIO_TIMEOUT;
writel(val, &mac_p->miidata);
miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
@@ -69,27 +73,26 @@ static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
return ret;
}
-static int dw_mdio_init(char *name, struct eth_mac_regs *mac_regs_p)
+static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p)
{
struct mii_dev *bus = mdio_alloc();
if (!bus) {
printf("Failed to allocate MDIO bus\n");
- return -1;
+ return -ENOMEM;
}
bus->read = dw_mdio_read;
bus->write = dw_mdio_write;
- sprintf(bus->name, name);
+ snprintf(bus->name, sizeof(bus->name), name);
bus->priv = (void *)mac_regs_p;
return mdio_register(bus);
}
-static void tx_descs_init(struct eth_device *dev)
+static void tx_descs_init(struct dw_eth_dev *priv)
{
- struct dw_eth_dev *priv = dev->priv;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
char *txbuffs = &priv->txbuffs[0];
@@ -128,9 +131,8 @@ static void tx_descs_init(struct eth_device *dev)
priv->tx_currdescnum = 0;
}
-static void rx_descs_init(struct eth_device *dev)
+static void rx_descs_init(struct dw_eth_dev *priv)
{
- struct dw_eth_dev *priv = dev->priv;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
char *rxbuffs = &priv->rxbuffs[0];
@@ -170,12 +172,10 @@ static void rx_descs_init(struct eth_device *dev)
priv->rx_currdescnum = 0;
}
-static int dw_write_hwaddr(struct eth_device *dev)
+static int _dw_write_hwaddr(struct dw_eth_dev *priv, u8 *mac_id)
{
- struct dw_eth_dev *priv = dev->priv;
struct eth_mac_regs *mac_p = priv->mac_regs_p;
u32 macid_lo, macid_hi;
- u8 *mac_id = &dev->enetaddr[0];
macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
(mac_id[3] << 24);
@@ -213,9 +213,8 @@ static void dw_adjust_link(struct eth_mac_regs *mac_p,
(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
}
-static void dw_eth_halt(struct eth_device *dev)
+static void _dw_eth_halt(struct dw_eth_dev *priv)
{
- struct dw_eth_dev *priv = dev->priv;
struct eth_mac_regs *mac_p = priv->mac_regs_p;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
@@ -225,12 +224,12 @@ static void dw_eth_halt(struct eth_device *dev)
phy_shutdown(priv->phydev);
}
-static int dw_eth_init(struct eth_device *dev, bd_t *bis)
+static int _dw_eth_init(struct dw_eth_dev *priv, u8 *enetaddr)
{
- struct dw_eth_dev *priv = dev->priv;
struct eth_mac_regs *mac_p = priv->mac_regs_p;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
unsigned int start;
+ int ret;
writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode);
@@ -238,7 +237,7 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
while (readl(&dma_p->busmode) & DMAMAC_SRST) {
if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT) {
printf("DMA reset timeout\n");
- return -1;
+ return -ETIMEDOUT;
}
mdelay(100);
@@ -246,10 +245,10 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
/* Soft reset above clears HW address registers.
* So we have to set it here once again */
- dw_write_hwaddr(dev);
+ _dw_write_hwaddr(priv, enetaddr);
- rx_descs_init(dev);
- tx_descs_init(dev);
+ rx_descs_init(priv);
+ tx_descs_init(priv);
writel(FIXEDBURST | PRIORXTX_41 | DMA_PBL, &dma_p->busmode);
@@ -268,25 +267,25 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
#endif
/* Start up the PHY */
- if (phy_startup(priv->phydev)) {
+ ret = phy_startup(priv->phydev);
+ if (ret) {
printf("Could not initialize PHY %s\n",
priv->phydev->dev->name);
- return -1;
+ return ret;
}
dw_adjust_link(mac_p, priv->phydev);
if (!priv->phydev->link)
- return -1;
+ return -EIO;
writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
return 0;
}
-static int dw_eth_send(struct eth_device *dev, void *packet, int length)
+static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
{
- struct dw_eth_dev *priv = dev->priv;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
u32 desc_num = priv->tx_currdescnum;
struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
@@ -309,7 +308,7 @@ static int dw_eth_send(struct eth_device *dev, void *packet, int length)
/* Check if the descriptor is owned by CPU */
if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
printf("CPU not owner of tx frame\n");
- return -1;
+ return -EPERM;
}
memcpy(desc_p->dmamac_addr, packet, length);
@@ -347,12 +346,11 @@ static int dw_eth_send(struct eth_device *dev, void *packet, int length)
return 0;
}
-static int dw_eth_recv(struct eth_device *dev)
+static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp)
{
- struct dw_eth_dev *priv = dev->priv;
u32 status, desc_num = priv->rx_currdescnum;
struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
- int length = 0;
+ int length = -EAGAIN;
uint32_t desc_start = (uint32_t)desc_p;
uint32_t desc_end = desc_start +
roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
@@ -373,31 +371,39 @@ static int dw_eth_recv(struct eth_device *dev)
/* Invalidate received data */
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start, data_end);
+ *packetp = desc_p->dmamac_addr;
+ }
- NetReceive(desc_p->dmamac_addr, length);
+ return length;
+}
- /*
- * Make the current descriptor valid again and go to
- * the next one
- */
- desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
+static int _dw_free_pkt(struct dw_eth_dev *priv)
+{
+ u32 desc_num = priv->rx_currdescnum;
+ struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
+ uint32_t desc_start = (uint32_t)desc_p;
+ uint32_t desc_end = desc_start +
+ roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
- /* Flush only status field - others weren't changed */
- flush_dcache_range(desc_start, desc_end);
+ /*
+ * Make the current descriptor valid again and go to
+ * the next one
+ */
+ desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
- /* Test the wrap-around condition. */
- if (++desc_num >= CONFIG_RX_DESCR_NUM)
- desc_num = 0;
- }
+ /* Flush only status field - others weren't changed */
+ flush_dcache_range(desc_start, desc_end);
+ /* Test the wrap-around condition. */
+ if (++desc_num >= CONFIG_RX_DESCR_NUM)
+ desc_num = 0;
priv->rx_currdescnum = desc_num;
- return length;
+ return 0;
}
-static int dw_phy_init(struct eth_device *dev)
+static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
{
- struct dw_eth_dev *priv = dev->priv;
struct phy_device *phydev;
int mask = 0xffffffff;
@@ -407,7 +413,7 @@ static int dw_phy_init(struct eth_device *dev)
phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
if (!phydev)
- return -1;
+ return -ENODEV;
phy_connect_dev(phydev, dev);
@@ -417,7 +423,43 @@ static int dw_phy_init(struct eth_device *dev)
priv->phydev = phydev;
phy_config(phydev);
- return 1;
+ return 0;
+}
+
+#ifndef CONFIG_DM_ETH
+static int dw_eth_init(struct eth_device *dev, bd_t *bis)
+{
+ return _dw_eth_init(dev->priv, dev->enetaddr);
+}
+
+static int dw_eth_send(struct eth_device *dev, void *packet, int length)
+{
+ return _dw_eth_send(dev->priv, packet, length);
+}
+
+static int dw_eth_recv(struct eth_device *dev)
+{
+ uchar *packet;
+ int length;
+
+ length = _dw_eth_recv(dev->priv, &packet);
+ if (length == -EAGAIN)
+ return 0;
+ net_process_received_packet(packet, length);
+
+ _dw_free_pkt(dev->priv);
+
+ return 0;
+}
+
+static void dw_eth_halt(struct eth_device *dev)
+{
+ return _dw_eth_halt(dev->priv);
+}
+
+static int dw_write_hwaddr(struct eth_device *dev)
+{
+ return _dw_write_hwaddr(dev->priv, dev->enetaddr);
}
int designware_initialize(ulong base_addr, u32 interface)
@@ -465,5 +507,117 @@ int designware_initialize(ulong base_addr, u32 interface)
dw_mdio_init(dev->name, priv->mac_regs_p);
priv->bus = miiphy_get_dev_by_name(dev->name);
- return dw_phy_init(dev);
+ return dw_phy_init(priv, dev);
+}
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int designware_eth_start(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ return _dw_eth_init(dev->priv, pdata->enetaddr);
+}
+
+static int designware_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct dw_eth_dev *priv = dev_get_priv(dev);
+
+ return _dw_eth_send(priv, packet, length);
+}
+
+static int designware_eth_recv(struct udevice *dev, uchar **packetp)
+{
+ struct dw_eth_dev *priv = dev_get_priv(dev);
+
+ return _dw_eth_recv(priv, packetp);
+}
+
+static int designware_eth_free_pkt(struct udevice *dev, uchar *packet,
+ int length)
+{
+ struct dw_eth_dev *priv = dev_get_priv(dev);
+
+ return _dw_free_pkt(priv);
+}
+
+static void designware_eth_stop(struct udevice *dev)
+{
+ struct dw_eth_dev *priv = dev_get_priv(dev);
+
+ return _dw_eth_halt(priv);
+}
+
+static int designware_eth_write_hwaddr(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct dw_eth_dev *priv = dev_get_priv(dev);
+
+ return _dw_write_hwaddr(priv, pdata->enetaddr);
+}
+
+static int designware_eth_probe(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct dw_eth_dev *priv = dev_get_priv(dev);
+ int ret;
+
+ debug("%s, iobase=%lx, priv=%p\n", __func__, pdata->iobase, priv);
+ priv->mac_regs_p = (struct eth_mac_regs *)pdata->iobase;
+ priv->dma_regs_p = (struct eth_dma_regs *)(pdata->iobase +
+ DW_DMA_BASE_OFFSET);
+ priv->interface = pdata->phy_interface;
+
+ dw_mdio_init(dev->name, priv->mac_regs_p);
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+
+ ret = dw_phy_init(priv, dev);
+ debug("%s, ret=%d\n", __func__, ret);
+
+ return ret;
}
+
+static const struct eth_ops designware_eth_ops = {
+ .start = designware_eth_start,
+ .send = designware_eth_send,
+ .recv = designware_eth_recv,
+ .free_pkt = designware_eth_free_pkt,
+ .stop = designware_eth_stop,
+ .write_hwaddr = designware_eth_write_hwaddr,
+};
+
+static int designware_eth_ofdata_to_platdata(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ const char *phy_mode;
+
+ pdata->iobase = dev_get_addr(dev);
+ pdata->phy_interface = -1;
+ phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
+ if (phy_mode)
+ pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+ if (pdata->phy_interface == -1) {
+ debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id designware_eth_ids[] = {
+ { .compatible = "allwinner,sun7i-a20-gmac" },
+ { }
+};
+
+U_BOOT_DRIVER(eth_sandbox) = {
+ .name = "eth_designware",
+ .id = UCLASS_ETH,
+ .of_match = designware_eth_ids,
+ .ofdata_to_platdata = designware_eth_ofdata_to_platdata,
+ .probe = designware_eth_probe,
+ .ops = &designware_eth_ops,
+ .priv_auto_alloc_size = sizeof(struct dw_eth_dev),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index 49d900cb3f..4b9ec39cc8 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -228,8 +228,9 @@ struct dw_eth_dev {
struct eth_mac_regs *mac_regs_p;
struct eth_dma_regs *dma_regs_p;
-
+#ifndef CONFIG_DM_ETH
struct eth_device *dev;
+#endif
struct phy_device *phydev;
struct mii_dev *bus;
};
diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c
index 4de9d41642..ccd2131f88 100644
--- a/drivers/net/dm9000x.c
+++ b/drivers/net/dm9000x.c
@@ -342,10 +342,10 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
printf("MAC: %pM\n", dev->enetaddr);
- if (!is_valid_ether_addr(dev->enetaddr)) {
+ if (!is_valid_ethaddr(dev->enetaddr)) {
#ifdef CONFIG_RANDOM_MACADDR
printf("Bad MAC address (uninitialized EEPROM?), randomizing\n");
- eth_random_addr(dev->enetaddr);
+ net_random_ethaddr(dev->enetaddr);
printf("MAC: %pM\n", dev->enetaddr);
#else
printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
@@ -464,7 +464,8 @@ static void dm9000_halt(struct eth_device *netdev)
*/
static int dm9000_rx(struct eth_device *netdev)
{
- u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
+ u8 rxbyte;
+ u8 *rdptr = (u8 *)net_rx_packets[0];
u16 RxStatus, RxLen = 0;
struct board_info *db = &dm9000_info;
@@ -525,7 +526,7 @@ static int dm9000_rx(struct eth_device *netdev)
DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
DM9000_DBG("passing packet to upper layer\n");
- NetReceive(NetRxPackets[0], RxLen);
+ net_process_received_packet(net_rx_packets[0], RxLen);
}
}
return 0;
diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c
index 944a0c046f..933d1fc2f1 100644
--- a/drivers/net/dnet.c
+++ b/drivers/net/dnet.c
@@ -188,12 +188,13 @@ static int dnet_recv(struct eth_device *netdev)
if (cmd_word & 0xDF180000)
printf("%s packet receive error %x\n", __func__, cmd_word);
- data_ptr = (unsigned int *) NetRxPackets[0];
+ data_ptr = (unsigned int *)net_rx_packets[0];
for (i = 0; i < (pkt_len + 3) >> 2; i++)
*data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO);
- NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */
+ /* ok + 5 ?? */
+ net_process_received_packet(net_rx_packets[0], pkt_len + 5);
return 0;
}
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index cd4422215f..2d66690226 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -1197,7 +1197,7 @@ e1000_read_mac_addr(struct eth_device *nic)
nic->enetaddr[5] ^= 1;
#ifdef CONFIG_E1000_FALLBACK_MAC
- if (!is_valid_ether_addr(nic->enetaddr)) {
+ if (!is_valid_ethaddr(nic->enetaddr)) {
unsigned char fb_mac[NODE_ADDRESS_SIZE] = CONFIG_E1000_FALLBACK_MAC;
memcpy (nic->enetaddr, fb_mac, NODE_ADDRESS_SIZE);
@@ -5158,7 +5158,7 @@ e1000_poll(struct eth_device *nic)
invalidate_dcache_range((unsigned long)packet,
(unsigned long)packet +
roundup(len, ARCH_DMA_MINALIGN));
- NetReceive((uchar *)packet, len);
+ net_process_received_packet((uchar *)packet, len);
fill_rx(hw);
return 1;
}
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index a23a5852ee..f2cd32c548 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -674,7 +674,8 @@ static int eepro100_recv (struct eth_device *dev)
/* Pass the packet up to the protocol
* layers.
*/
- NetReceive((u8 *)rx_ring[rx_next].data, length);
+ net_process_received_packet((u8 *)rx_ring[rx_next].data,
+ length);
} else {
/* There was an error.
*/
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index ec33764f5e..59ea11cd6a 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -21,8 +21,8 @@
* enc_miiphy_read(), enc_miiphy_write(), enc_write_hwaddr(),
* enc_init(), enc_recv(), enc_send(), enc_halt()
* ALL other functions assume that the bus has already been claimed!
- * Since NetReceive() might call enc_send() in return, the bus must be
- * released, NetReceive() called and claimed again.
+ * Since net_process_received_packet() might call enc_send() in return, the bus
+ * must be released, net_process_received_packet() called and claimed again.
*/
/*
@@ -415,7 +415,7 @@ static void enc_reset_rx_call(enc_dev_t *enc)
*/
static void enc_receive(enc_dev_t *enc)
{
- u8 *packet = (u8 *)NetRxPackets[0];
+ u8 *packet = (u8 *)net_rx_packets[0];
u16 pkt_len;
u16 copy_len;
u16 status;
@@ -468,11 +468,12 @@ static void enc_receive(enc_dev_t *enc)
continue;
}
/*
- * Because NetReceive() might call enc_send(), we need to
- * release the SPI bus, call NetReceive(), reclaim the bus
+ * Because net_process_received_packet() might call enc_send(),
+ * we need to release the SPI bus, call
+ * net_process_received_packet(), reclaim the bus.
*/
enc_release_bus(enc);
- NetReceive(packet, pkt_len);
+ net_process_received_packet(packet, pkt_len);
if (enc_claim_bus(enc))
return;
(void)enc_r8(enc, CTL_REG_EIR);
diff --git a/drivers/net/ep93xx_eth.c b/drivers/net/ep93xx_eth.c
index 1c09f1004a..a3721c5513 100644
--- a/drivers/net/ep93xx_eth.c
+++ b/drivers/net/ep93xx_eth.c
@@ -53,7 +53,7 @@ static void dump_dev(struct eth_device *dev)
printf(" rx_sq.end %p\n", priv->rx_sq.end);
for (i = 0; i < NUMRXDESC; i++)
- printf(" rx_buffer[%2.d] %p\n", i, NetRxPackets[i]);
+ printf(" rx_buffer[%2.d] %p\n", i, net_rx_packets[i]);
printf(" tx_dq.base %p\n", priv->tx_dq.base);
printf(" tx_dq.current %p\n", priv->tx_dq.current);
@@ -237,7 +237,7 @@ static int ep93xx_eth_open(struct eth_device *dev, bd_t *bd)
*/
for (i = 0; i < NUMRXDESC; i++) {
/* set buffer address */
- (priv->rx_dq.base + i)->word1 = (uint32_t)NetRxPackets[i];
+ (priv->rx_dq.base + i)->word1 = (uint32_t)net_rx_packets[i];
/* set buffer length, clear buffer index and NSOF */
(priv->rx_dq.base + i)->word2 = PKTSIZE_ALIGN;
@@ -310,15 +310,16 @@ static int ep93xx_eth_rcv_packet(struct eth_device *dev)
/*
* We have a good frame. Extract the frame's length
* from the current rx_status_queue entry, and copy
- * the frame's data into NetRxPackets[] of the
+ * the frame's data into net_rx_packets[] of the
* protocol stack. We track the total number of
* bytes in the frame (nbytes_frame) which will be
* used when we pass the data off to the protocol
- * layer via NetReceive().
+ * layer via net_process_received_packet().
*/
len = RX_STATUS_FRAME_LEN(priv->rx_sq.current);
- NetReceive((uchar *)priv->rx_dq.current->word1, len);
+ net_process_received_packet(
+ (uchar *)priv->rx_dq.current->word1, len);
debug("reporting %d bytes...\n", len);
} else {
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index 46c82bbb40..edb3c808fa 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -267,7 +267,7 @@ static int ethoc_init_ring(struct eth_device *dev)
bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
for (i = 0; i < priv->num_rx; i++) {
- bd.addr = (u32)NetRxPackets[i];
+ bd.addr = (u32)net_rx_packets[i];
if (i == priv->num_rx - 1)
bd.stat |= RX_BD_WRAP;
@@ -372,7 +372,7 @@ static int ethoc_rx(struct eth_device *dev, int limit)
if (ethoc_update_rx_stats(&bd) == 0) {
int size = bd.stat >> 16;
size -= 4; /* strip the CRC */
- NetReceive((void *)bd.addr, size);
+ net_process_received_packet((void *)bd.addr, size);
}
/* clear the buffer descriptor so it can be reused */
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index b57247032f..9225d37285 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -357,7 +357,7 @@ static int fec_get_hwaddr(struct eth_device *dev, int dev_id,
unsigned char *mac)
{
imx_get_mac_from_fuse(dev_id, mac);
- return !is_valid_ether_addr(mac);
+ return !is_valid_ethaddr(mac);
}
static int fec_set_hwaddr(struct eth_device *dev)
@@ -852,7 +852,7 @@ static int fec_recv(struct eth_device *dev)
swap_packet((uint32_t *)frame->data, frame_length);
#endif
memcpy(buff, frame->data, frame_length);
- NetReceive(buff, frame_length);
+ net_process_received_packet(buff, frame_length);
len = frame_length;
} else {
if (bd_status & FEC_RBD_ERR)
diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c
index 1d1089d017..55e76a7d88 100644
--- a/drivers/net/fm/eth.c
+++ b/drivers/net/fm/eth.c
@@ -530,7 +530,7 @@ static int fm_eth_recv(struct eth_device *dev)
if (!(status & RxBD_ERROR)) {
data = (u8 *)rxbd->buf_ptr_lo;
len = rxbd->len;
- NetReceive(data, len);
+ net_process_received_packet(data, len);
} else {
printf("%s: Rx error\n", dev->name);
return 0;
diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c
index 6391f9b32f..792534b139 100644
--- a/drivers/net/fsl_mcdmafec.c
+++ b/drivers/net/fsl_mcdmafec.c
@@ -244,7 +244,7 @@ static int fec_recv(struct eth_device *dev)
struct fec_info_dma *info = dev->priv;
volatile fecdma_t *fecp = (fecdma_t *) (info->iobase);
- cbd_t *pRbd = &info->rxbd[info->rxIdx];
+ cbd_t *prbd = &info->rxbd[info->rxIdx];
u32 ievent;
int frame_length, len = 0;
@@ -276,26 +276,27 @@ static int fec_recv(struct eth_device *dev)
}
}
- if (!(pRbd->cbd_sc & BD_ENET_RX_EMPTY)) {
- if ((pRbd->cbd_sc & BD_ENET_RX_LAST)
- && !(pRbd->cbd_sc & BD_ENET_RX_ERR)
- && ((pRbd->cbd_datlen - 4) > 14)) {
+ if (!(prbd->cbd_sc & BD_ENET_RX_EMPTY)) {
+ if ((prbd->cbd_sc & BD_ENET_RX_LAST) &&
+ !(prbd->cbd_sc & BD_ENET_RX_ERR) &&
+ ((prbd->cbd_datlen - 4) > 14)) {
/* Get buffer address and size */
- frame_length = pRbd->cbd_datlen - 4;
+ frame_length = prbd->cbd_datlen - 4;
/* Fill the buffer and pass it to upper layers */
- NetReceive((uchar *)pRbd->cbd_bufaddr, frame_length);
+ net_process_received_packet((uchar *)prbd->cbd_bufaddr,
+ frame_length);
len = frame_length;
}
/* Reset buffer descriptor as empty */
if ((info->rxIdx) == (PKTBUFSRX - 1))
- pRbd->cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+ prbd->cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
else
- pRbd->cbd_sc = BD_ENET_RX_EMPTY;
+ prbd->cbd_sc = BD_ENET_RX_EMPTY;
- pRbd->cbd_datlen = PKTSIZE_ALIGN;
+ prbd->cbd_datlen = PKTSIZE_ALIGN;
/* Now, we have an empty RxBD, restart the DMA receive task */
MCD_continDma(info->rxTask);
@@ -399,7 +400,7 @@ static int fec_init(struct eth_device *dev, bd_t * bd)
for (i = 0; i < PKTBUFSRX; i++) {
info->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
info->rxbd[i].cbd_datlen = PKTSIZE_ALIGN;
- info->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
+ info->rxbd[i].cbd_bufaddr = (uint) net_rx_packets[i];
}
info->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 85193140af..515f0b2746 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -423,7 +423,7 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
for (i = 0; i < PKTBUFSRX; i++) {
/* RXBUF_BADR */
if (!rxdes[i].rxdes2) {
- buf = NetRxPackets[i];
+ buf = net_rx_packets[i];
rxdes[i].rxdes3 = virt_to_phys(buf);
rxdes[i].rxdes2 = (uint)buf;
}
@@ -493,7 +493,7 @@ static int ftgmac100_recv(struct eth_device *dev)
dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
/* pass the packet up to the protocol layers. */
- NetReceive((void *)curr_des->rxdes2, rxlen);
+ net_process_received_packet((void *)curr_des->rxdes2, rxlen);
/* release buffer to DMA */
curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c
index 3e148db5cd..bd94f83f04 100644
--- a/drivers/net/ftmac100.c
+++ b/drivers/net/ftmac100.c
@@ -102,7 +102,7 @@ static int ftmac100_init (struct eth_device *dev, bd_t *bd)
for (i = 0; i < PKTBUFSRX; i++) {
/* RXBUF_BADR */
- rxdes[i].rxdes2 = (unsigned int)NetRxPackets[i];
+ rxdes[i].rxdes2 = (unsigned int)net_rx_packets[i];
rxdes[i].rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE (PKTSIZE_ALIGN);
rxdes[i].rxdes0 = FTMAC100_RXDES0_RXDMA_OWN;
}
@@ -164,7 +164,7 @@ static int ftmac100_recv (struct eth_device *dev)
/* pass the packet up to the protocol layers. */
- NetReceive ((void *)curr_des->rxdes2, rxlen);
+ net_process_received_packet((void *)curr_des->rxdes2, rxlen);
/* release buffer to DMA */
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
index 98c4f09629..4bae9ad977 100644
--- a/drivers/net/ftmac110.c
+++ b/drivers/net/ftmac110.c
@@ -347,7 +347,7 @@ static int ftmac110_recv(struct eth_device *dev)
printf("ftmac110: rx error\n");
} else {
dma_map_single(buf, len, DMA_FROM_DEVICE);
- NetReceive(buf, len);
+ net_process_received_packet(buf, len);
rlen += len;
}
@@ -425,7 +425,7 @@ int ftmac110_initialize(bd_t *bis)
dev->recv = ftmac110_recv;
if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
- eth_random_addr(dev->enetaddr);
+ net_random_ethaddr(dev->enetaddr);
/* allocate tx descriptors (it must be 16 bytes aligned) */
chip->txd = dma_alloc_coherent(
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index c817af4dac..a93b37a5d7 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -533,7 +533,7 @@ int greth_recv(struct eth_device *dev)
sparc_dcache_flush_all();
/* pass packet on to network subsystem */
- NetReceive((void *)d, len);
+ net_process_received_packet((void *)d, len);
/* bump stats counters */
greth->stats.rx_packets++;
diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c
index 35f1a57331..0c5fdeefd7 100644
--- a/drivers/net/keystone_net.c
+++ b/drivers/net/keystone_net.c
@@ -505,7 +505,7 @@ static int keystone2_eth_rcv_packet(struct eth_device *dev)
if (hd == NULL)
return 0;
- NetReceive((uchar *)pkt, pkt_size);
+ net_process_received_packet((uchar *)pkt, pkt_size);
ksnav_release_rxhd(&netcp_pktdma, hd);
diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c
index 05e5b14d29..5b4c5b0df6 100644
--- a/drivers/net/ks8851_mll.c
+++ b/drivers/net/ks8851_mll.c
@@ -321,8 +321,8 @@ static void ks_rcv(struct eth_device *dev, uchar **pv_data)
/* read data block including CRC 4 bytes */
ks_read_qmu(dev, (u16 *)(*pv_data), frame_hdr->len);
- /* NetRxPackets buffer size is ok (*pv_data pointer) */
- NetReceive(*pv_data, frame_hdr->len);
+ /* net_rx_packets buffer size is ok (*pv_data) */
+ net_process_received_packet(*pv_data, frame_hdr->len);
pv_data++;
} else {
ks_wrreg16(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
@@ -573,7 +573,7 @@ static int ks8851_mll_recv(struct eth_device *dev)
ks_wrreg16(dev, KS_ISR, status);
if ((status & IRQ_RXI))
- ks_rcv(dev, (uchar **)NetRxPackets);
+ ks_rcv(dev, (uchar **)net_rx_packets);
if ((status & IRQ_LDI)) {
u16 pmecr = ks_rdreg16(dev, KS_PMECR);
diff --git a/drivers/net/lan91c96.c b/drivers/net/lan91c96.c
index 229658abc8..495c0886fa 100644
--- a/drivers/net/lan91c96.c
+++ b/drivers/net/lan91c96.c
@@ -568,29 +568,30 @@ static int smc_rcv(struct eth_device *dev)
to send the DWORDs or the bytes first, or some
mixture. A mixture might improve already slow PIO
performance */
- SMC_insl(dev, LAN91C96_DATA_HIGH, NetRxPackets[0],
- packet_length >> 2);
+ SMC_insl(dev, LAN91C96_DATA_HIGH, net_rx_packets[0],
+ packet_length >> 2);
/* read the left over bytes */
if (packet_length & 3) {
int i;
- byte *tail = (byte *) (NetRxPackets[0] + (packet_length & ~3));
+ byte *tail = (byte *)(net_rx_packets[0] +
+ (packet_length & ~3));
dword leftover = SMC_inl(dev, LAN91C96_DATA_HIGH);
for (i = 0; i < (packet_length & 3); i++)
*tail++ = (byte) (leftover >> (8 * i)) & 0xff;
}
#else
- PRINTK3 (" Reading %d words and %d byte(s) \n",
- (packet_length >> 1), packet_length & 1);
- SMC_insw(dev, LAN91C96_DATA_HIGH, NetRxPackets[0],
- packet_length >> 1);
+ PRINTK3(" Reading %d words and %d byte(s)\n",
+ (packet_length >> 1), packet_length & 1);
+ SMC_insw(dev, LAN91C96_DATA_HIGH, net_rx_packets[0],
+ packet_length >> 1);
#endif /* USE_32_BIT */
#if SMC_DEBUG > 2
printf ("Receiving Packet\n");
- print_packet((byte *)NetRxPackets[0], packet_length);
+ print_packet((byte *)net_rx_packets[0], packet_length);
#endif
} else {
/* error ... */
@@ -609,7 +610,7 @@ static int smc_rcv(struct eth_device *dev)
if (!is_error) {
/* Pass the packet up to the protocol layers. */
- NetReceive (NetRxPackets[0], packet_length);
+ net_process_received_packet(net_rx_packets[0], packet_length);
return packet_length;
} else {
return 0;
diff --git a/drivers/net/lpc32xx_eth.c b/drivers/net/lpc32xx_eth.c
index fcadf0c77f..8dcbb4a04a 100644
--- a/drivers/net/lpc32xx_eth.c
+++ b/drivers/net/lpc32xx_eth.c
@@ -419,10 +419,12 @@ static int lpc32xx_eth_recv(struct eth_device *dev)
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);
+ if (!(bufs->rx_stat[rx_index].statusinfo & RX_STAT_ERRORS)) {
+ net_process_received_packet(
+ &(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;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 170ff0646f..4e1a7fe583 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -347,14 +347,14 @@ static int macb_recv(struct eth_device *netdev)
headlen = 128 * (MACB_RX_RING_SIZE
- macb->rx_tail);
taillen = length - headlen;
- memcpy((void *)NetRxPackets[0],
+ memcpy((void *)net_rx_packets[0],
buffer, headlen);
- memcpy((void *)NetRxPackets[0] + headlen,
+ memcpy((void *)net_rx_packets[0] + headlen,
macb->rx_buffer, taillen);
- buffer = (void *)NetRxPackets[0];
+ buffer = (void *)net_rx_packets[0];
}
- NetReceive(buffer, length);
+ net_process_received_packet(buffer, length);
if (++rx_tail >= MACB_RX_RING_SIZE)
rx_tail = 0;
reclaim_rx_buffers(macb, rx_tail);
@@ -595,7 +595,7 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
}
/* update the ethaddr */
- if (is_valid_ether_addr(netdev->enetaddr)) {
+ if (is_valid_ethaddr(netdev->enetaddr)) {
macb_write_hwaddr(netdev);
} else {
printf("%s: mac address is not valid\n", netdev->name);
diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c
index 7c4b210b00..fd73099371 100644
--- a/drivers/net/mcffec.c
+++ b/drivers/net/mcffec.c
@@ -219,7 +219,8 @@ int fec_recv(struct eth_device *dev)
length -= 4;
/* Pass the packet up to the protocol layers. */
- NetReceive(NetRxPackets[info->rxIdx], length);
+ net_process_received_packet(net_rx_packets[info->rxIdx],
+ length);
fecp->eir |= FEC_EIR_RXF;
}
@@ -477,7 +478,7 @@ int fec_init(struct eth_device *dev, bd_t * bd)
for (i = 0; i < PKTBUFSRX; i++) {
info->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
info->rxbd[i].cbd_datlen = 0; /* Reset */
- info->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
+ info->rxbd[i].cbd_bufaddr = (uint) net_rx_packets[i];
}
info->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
diff --git a/drivers/net/mpc512x_fec.c b/drivers/net/mpc512x_fec.c
index 427e0b8b46..22ea114f01 100644
--- a/drivers/net/mpc512x_fec.c
+++ b/drivers/net/mpc512x_fec.c
@@ -591,7 +591,8 @@ static int mpc512x_fec_recv (struct eth_device *dev)
rx_buff_idx = frame_length;
if (pRbd->status & FEC_RBD_LAST) {
- NetReceive ((uchar*)rx_buff, frame_length);
+ net_process_received_packet((uchar *)rx_buff,
+ frame_length);
rx_buff_idx = 0;
}
}
diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c
index d2a8ae0868..2ebd1761c3 100644
--- a/drivers/net/mpc5xxx_fec.c
+++ b/drivers/net/mpc5xxx_fec.c
@@ -859,7 +859,7 @@ static int mpc5xxx_fec_recv(struct eth_device *dev)
*/
memcpy(buff, frame->head, 14);
memcpy(buff + 14, frame->data, frame_length);
- NetReceive(buff, frame_length);
+ net_process_received_packet(buff, frame_length);
len = frame_length;
}
/*
diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c
index 6b31a82ec4..ab5aa68fc8 100644
--- a/drivers/net/mvgbe.c
+++ b/drivers/net/mvgbe.c
@@ -66,12 +66,12 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
/* check parameters */
if (phy_adr > PHYADR_MASK) {
printf("Err..(%s) Invalid PHY address %d\n",
- __FUNCTION__, phy_adr);
+ __func__, phy_adr);
return -EFAULT;
}
if (reg_ofs > PHYREG_MASK) {
printf("Err..(%s) Invalid register offset %d\n",
- __FUNCTION__, reg_ofs);
+ __func__, reg_ofs);
return -EFAULT;
}
@@ -81,7 +81,7 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
/* read smi register */
smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
if (timeout-- == 0) {
- printf("Err..(%s) SMI busy timeout\n", __FUNCTION__);
+ printf("Err..(%s) SMI busy timeout\n", __func__);
return -EFAULT;
}
} while (smi_reg & MVGBE_PHY_SMI_BUSY_MASK);
@@ -102,7 +102,7 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
if (timeout-- == 0) {
printf("Err..(%s) SMI read ready timeout\n",
- __FUNCTION__);
+ __func__);
return -EFAULT;
}
} while (!(smi_reg & MVGBE_PHY_SMI_READ_VALID_MASK));
@@ -113,8 +113,8 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
*data = (u16) (MVGBE_REG_RD(MVGBE_SMI_REG) & MVGBE_PHY_SMI_DATA_MASK);
- debug("%s:(adr %d, off %d) value= %04x\n", __FUNCTION__, phy_adr,
- reg_ofs, *data);
+ debug("%s:(adr %d, off %d) value= %04x\n", __func__, phy_adr, reg_ofs,
+ *data);
return 0;
}
@@ -142,11 +142,11 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
/* check parameters */
if (phy_adr > PHYADR_MASK) {
- printf("Err..(%s) Invalid phy address\n", __FUNCTION__);
+ printf("Err..(%s) Invalid phy address\n", __func__);
return -EINVAL;
}
if (reg_ofs > PHYREG_MASK) {
- printf("Err..(%s) Invalid register offset\n", __FUNCTION__);
+ printf("Err..(%s) Invalid register offset\n", __func__);
return -EINVAL;
}
@@ -156,7 +156,7 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
/* read smi register */
smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
if (timeout-- == 0) {
- printf("Err..(%s) SMI busy timeout\n", __FUNCTION__);
+ printf("Err..(%s) SMI busy timeout\n", __func__);
return -ETIME;
}
} while (smi_reg & MVGBE_PHY_SMI_BUSY_MASK);
@@ -583,7 +583,7 @@ static int mvgbe_send(struct eth_device *dev, void *dataptr, int datasize)
if ((cmd_sts & (MVGBE_ERROR_SUMMARY | MVGBE_TX_LAST_FRAME)) ==
(MVGBE_ERROR_SUMMARY | MVGBE_TX_LAST_FRAME) &&
cmd_sts & (MVGBE_UR_ERROR | MVGBE_RL_ERROR)) {
- printf("Err..(%s) in xmit packet\n", __FUNCTION__);
+ printf("Err..(%s) in xmit packet\n", __func__);
return -1;
}
cmd_sts = readl(&p_txdesc->cmd_sts);
@@ -604,14 +604,14 @@ static int mvgbe_recv(struct eth_device *dev)
if (timeout < MVGBE_PHY_SMI_TIMEOUT)
timeout++;
else {
- debug("%s time out...\n", __FUNCTION__);
+ debug("%s time out...\n", __func__);
return -1;
}
} while (readl(&p_rxdesc_curr->cmd_sts) & MVGBE_BUFFER_OWNED_BY_DMA);
if (p_rxdesc_curr->byte_cnt != 0) {
debug("%s: Received %d byte Packet @ 0x%x (cmd_sts= %08x)\n",
- __FUNCTION__, (u32) p_rxdesc_curr->byte_cnt,
+ __func__, (u32) p_rxdesc_curr->byte_cnt,
(u32) p_rxdesc_curr->buf_ptr,
(u32) p_rxdesc_curr->cmd_sts);
}
@@ -628,21 +628,24 @@ static int mvgbe_recv(struct eth_device *dev)
!= (MVGBE_RX_FIRST_DESC | MVGBE_RX_LAST_DESC)) {
printf("Err..(%s) Dropping packet spread on"
- " multiple descriptors\n", __FUNCTION__);
+ " multiple descriptors\n", __func__);
} else if (cmd_sts & MVGBE_ERROR_SUMMARY) {
printf("Err..(%s) Dropping packet with errors\n",
- __FUNCTION__);
+ __func__);
} else {
/* !!! call higher layer processing */
debug("%s: Sending Received packet to"
- " upper layer (NetReceive)\n", __FUNCTION__);
+ " upper layer (net_process_received_packet)\n",
+ __func__);
/* let the upper layer handle the packet */
- NetReceive((p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET),
- (int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET));
+ net_process_received_packet((p_rxdesc_curr->buf_ptr +
+ RX_BUF_OFFSET),
+ (int)(p_rxdesc_curr->byte_cnt -
+ RX_BUF_OFFSET));
}
/*
* free these descriptors and point next in the ring
@@ -747,7 +750,7 @@ error2:
free(dmvgbe);
error1:
printf("Err.. %s Failed to allocate memory\n",
- __FUNCTION__);
+ __func__);
return -1;
}
@@ -767,7 +770,7 @@ error1:
#endif
default: /* this should never happen */
printf("Err..(%s) Invalid device number %d\n",
- __FUNCTION__, devnum);
+ __func__, devnum);
return -1;
}
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c
index a2a69b4219..efaae167fe 100644
--- a/drivers/net/mvneta.c
+++ b/drivers/net/mvneta.c
@@ -1572,7 +1572,7 @@ static int mvneta_recv(struct eth_device *dev)
* No cache invalidation needed here, since the rx_buffer's are
* located in a uncached memory region
*/
- NetReceive(data, rx_bytes);
+ net_process_received_packet(data, rx_bytes);
}
/* Update rxq management counters */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 04743bd2b3..0ed9bb5765 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -841,7 +841,8 @@ natsemi_poll(struct eth_device *dev)
rx_status);
retstat = 0;
} else { /* give packet to higher level routine */
- NetReceive((rxb + cur_rx * RX_BUF_SIZE), length);
+ net_process_received_packet((rxb + cur_rx * RX_BUF_SIZE),
+ length);
retstat = 1;
}
diff --git a/drivers/net/ne2000_base.c b/drivers/net/ne2000_base.c
index ef35922042..07a7cec2a8 100644
--- a/drivers/net/ne2000_base.c
+++ b/drivers/net/ne2000_base.c
@@ -665,7 +665,7 @@ void uboot_push_packet_len(int len) {
dp83902a_recv(&pbuf[0], len);
/*Just pass it to the upper layer*/
- NetReceive(&pbuf[0], len);
+ net_process_received_packet(&pbuf[0], len);
}
void uboot_push_tx_done(int key, int val) {
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 677c89f048..31042a6b6b 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -23,7 +23,7 @@ static int input_recursion;
static int output_recursion;
static int net_timeout;
static uchar nc_ether[6]; /* server enet address */
-static IPaddr_t nc_ip; /* server ip */
+static struct in_addr nc_ip; /* server ip */
static short nc_out_port; /* target output port */
static short nc_in_port; /* source input port */
static const char *output_packet; /* used by first send udp */
@@ -35,42 +35,43 @@ static int output_packet_len;
enum proto_t net_loop_last_protocol = BOOTP;
static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
- IPaddr_t sip, unsigned src,
+ struct in_addr sip, unsigned src,
unsigned len)
{
net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */
}
-static void nc_handler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
- unsigned len)
+static void nc_handler(uchar *pkt, unsigned dest, struct in_addr sip,
+ unsigned src, unsigned len)
{
if (input_size)
net_set_state(NETLOOP_SUCCESS); /* got input - quit net loop */
}
-static void nc_timeout(void)
+static void nc_timeout_handler(void)
{
net_set_state(NETLOOP_SUCCESS);
}
-static int is_broadcast(IPaddr_t ip)
+static int is_broadcast(struct in_addr ip)
{
- static IPaddr_t netmask;
- static IPaddr_t our_ip;
+ static struct in_addr netmask;
+ static struct in_addr our_ip;
static int env_changed_id;
int env_id = get_env_id();
/* update only when the environment has changed */
if (env_changed_id != env_id) {
- netmask = getenv_IPaddr("netmask");
- our_ip = getenv_IPaddr("ipaddr");
+ netmask = getenv_ip("netmask");
+ our_ip = getenv_ip("ipaddr");
env_changed_id = env_id;
}
- return (ip == ~0 || /* 255.255.255.255 */
- ((netmask & our_ip) == (netmask & ip) && /* on the same net */
- (netmask | ip) == ~0)); /* broadcast to our net */
+ return (ip.s_addr == ~0 || /* 255.255.255.255 (global bcast) */
+ ((netmask.s_addr & our_ip.s_addr) ==
+ (netmask.s_addr & ip.s_addr) && /* on the same net and */
+ (netmask.s_addr | ip.s_addr) == ~0)); /* bcast to our net */
}
static int refresh_settings_from_env(void)
@@ -82,16 +83,17 @@ static int refresh_settings_from_env(void)
/* update only when the environment has changed */
if (env_changed_id != env_id) {
if (getenv("ncip")) {
- nc_ip = getenv_IPaddr("ncip");
- if (!nc_ip)
+ nc_ip = getenv_ip("ncip");
+ if (!nc_ip.s_addr)
return -1; /* ncip is 0.0.0.0 */
p = strchr(getenv("ncip"), ':');
if (p != NULL) {
nc_out_port = simple_strtoul(p + 1, NULL, 10);
nc_in_port = nc_out_port;
}
- } else
- nc_ip = ~0; /* ncip is not set, so broadcast */
+ } else {
+ nc_ip.s_addr = ~0; /* ncip is not set, so broadcast */
+ }
p = getenv("ncoutport");
if (p != NULL)
@@ -111,27 +113,28 @@ static int refresh_settings_from_env(void)
}
/**
- * Called from NetLoop in net/net.c before each packet
+ * Called from net_loop in net/net.c before each packet
*/
-void NcStart(void)
+void nc_start(void)
{
refresh_settings_from_env();
- if (!output_packet_len || memcmp(nc_ether, NetEtherNullAddr, 6)) {
+ if (!output_packet_len || memcmp(nc_ether, net_null_ethaddr, 6)) {
/* going to check for input packet */
net_set_udp_handler(nc_handler);
- NetSetTimeout(net_timeout, nc_timeout);
+ net_set_timeout_handler(net_timeout, nc_timeout_handler);
} else {
/* send arp request */
uchar *pkt;
net_set_arp_handler(nc_wait_arp_handler);
- pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
+ pkt = (uchar *)net_tx_packet + net_eth_hdr_size() +
+ IP_UDP_HDR_SIZE;
memcpy(pkt, output_packet, output_packet_len);
- NetSendUDPPacket(nc_ether, nc_ip, nc_out_port, nc_in_port,
- output_packet_len);
+ net_send_udp_packet(nc_ether, nc_ip, nc_out_port, nc_in_port,
+ output_packet_len);
}
}
-int nc_input_packet(uchar *pkt, IPaddr_t src_ip, unsigned dest_port,
+int nc_input_packet(uchar *pkt, struct in_addr src_ip, unsigned dest_port,
unsigned src_port, unsigned len)
{
int end, chunk;
@@ -139,7 +142,7 @@ int nc_input_packet(uchar *pkt, IPaddr_t src_ip, unsigned dest_port,
if (dest_port != nc_in_port || !len)
return 0; /* not for us */
- if (src_ip != nc_ip && !is_broadcast(nc_ip))
+ if (src_ip.s_addr != nc_ip.s_addr && !is_broadcast(nc_ip))
return 0; /* not from our client */
debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt);
@@ -171,7 +174,7 @@ static void nc_send_packet(const char *buf, int len)
int inited = 0;
uchar *pkt;
uchar *ether;
- IPaddr_t ip;
+ struct in_addr ip;
debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf);
@@ -179,13 +182,13 @@ static void nc_send_packet(const char *buf, int len)
if (eth == NULL)
return;
- if (!memcmp(nc_ether, NetEtherNullAddr, 6)) {
+ if (!memcmp(nc_ether, net_null_ethaddr, 6)) {
if (eth->state == ETH_STATE_ACTIVE)
return; /* inside net loop */
output_packet = buf;
output_packet_len = len;
input_recursion = 1;
- NetLoop(NETCONS); /* wait for arp reply and send packet */
+ net_loop(NETCONS); /* wait for arp reply and send packet */
input_recursion = 0;
output_packet_len = 0;
return;
@@ -193,19 +196,20 @@ static void nc_send_packet(const char *buf, int len)
if (eth->state != ETH_STATE_ACTIVE) {
if (eth_is_on_demand_init()) {
- if (eth_init(gd->bd) < 0)
+ if (eth_init() < 0)
return;
eth_set_last_protocol(NETCONS);
- } else
- eth_init_state_only(gd->bd);
+ } else {
+ eth_init_state_only();
+ }
inited = 1;
}
- pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
+ pkt = (uchar *)net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
memcpy(pkt, buf, len);
ether = nc_ether;
ip = nc_ip;
- NetSendUDPPacket(ether, ip, nc_out_port, nc_in_port, len);
+ net_send_udp_packet(ether, ip, nc_out_port, nc_in_port, len);
if (inited) {
if (eth_is_on_demand_init())
@@ -215,7 +219,7 @@ static void nc_send_packet(const char *buf, int len)
}
}
-static int nc_start(struct stdio_dev *dev)
+static int nc_stdio_start(struct stdio_dev *dev)
{
int retval;
@@ -228,14 +232,14 @@ static int nc_start(struct stdio_dev *dev)
/*
* Initialize the static IP settings and buffer pointers
- * incase we call NetSendUDPPacket before NetLoop
+ * incase we call net_send_udp_packet before net_loop
*/
net_init();
return 0;
}
-static void nc_putc(struct stdio_dev *dev, char c)
+static void nc_stdio_putc(struct stdio_dev *dev, char c)
{
if (output_recursion)
return;
@@ -246,7 +250,7 @@ static void nc_putc(struct stdio_dev *dev, char c)
output_recursion = 0;
}
-static void nc_puts(struct stdio_dev *dev, const char *s)
+static void nc_stdio_puts(struct stdio_dev *dev, const char *s)
{
int len;
@@ -265,7 +269,7 @@ static void nc_puts(struct stdio_dev *dev, const char *s)
output_recursion = 0;
}
-static int nc_getc(struct stdio_dev *dev)
+static int nc_stdio_getc(struct stdio_dev *dev)
{
uchar c;
@@ -273,7 +277,7 @@ static int nc_getc(struct stdio_dev *dev)
net_timeout = 0; /* no timeout */
while (!input_size)
- NetLoop(NETCONS);
+ net_loop(NETCONS);
input_recursion = 0;
@@ -286,7 +290,7 @@ static int nc_getc(struct stdio_dev *dev)
return c;
}
-static int nc_tstc(struct stdio_dev *dev)
+static int nc_stdio_tstc(struct stdio_dev *dev)
{
struct eth_device *eth;
@@ -303,7 +307,7 @@ static int nc_tstc(struct stdio_dev *dev)
input_recursion = 1;
net_timeout = 1;
- NetLoop(NETCONS); /* kind of poll */
+ net_loop(NETCONS); /* kind of poll */
input_recursion = 0;
@@ -319,11 +323,11 @@ int drv_nc_init(void)
strcpy(dev.name, "nc");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
- dev.start = nc_start;
- dev.putc = nc_putc;
- dev.puts = nc_puts;
- dev.getc = nc_getc;
- dev.tstc = nc_tstc;
+ dev.start = nc_stdio_start;
+ dev.putc = nc_stdio_putc;
+ dev.puts = nc_stdio_puts;
+ dev.getc = nc_stdio_getc;
+ dev.tstc = nc_stdio_tstc;
rc = stdio_register(&dev);
diff --git a/drivers/net/ns8382x.c b/drivers/net/ns8382x.c
index cfe1f349db..f941c15b27 100644
--- a/drivers/net/ns8382x.c
+++ b/drivers/net/ns8382x.c
@@ -809,11 +809,13 @@ ns8382x_poll(struct eth_device *dev)
if ((rx_status & (DescMore | DescPktOK | DescRxLong)) != DescPktOK) {
/* corrupted packet received */
- printf("ns8382x_poll: Corrupted packet, status:%lx\n", rx_status);
+ printf("ns8382x_poll: Corrupted packet, status:%lx\n",
+ rx_status);
retstat = 0;
} else {
/* give packet to higher level routine */
- NetReceive((rxb + cur_rx * RX_BUF_SIZE), length);
+ net_process_received_packet((rxb + cur_rx * RX_BUF_SIZE),
+ length);
retstat = 1;
}
diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c
index 976848df4d..15c9cdcc3a 100644
--- a/drivers/net/pch_gbe.c
+++ b/drivers/net/pch_gbe.c
@@ -297,7 +297,7 @@ static int pch_gbe_recv(struct eth_device *dev)
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);
+ net_process_received_packet((uchar *)buffer_addr, length);
/* Test the wrap-around condition */
if (++priv->rx_idx >= PCH_GBE_DESC_NUM)
diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c
index 237fbba513..cfcb1b4e23 100644
--- a/drivers/net/pcnet.c
+++ b/drivers/net/pcnet.c
@@ -507,7 +507,7 @@ static int pcnet_recv (struct eth_device *dev)
buf = (*lp->rx_buf)[lp->cur_rx];
invalidate_dcache_range((unsigned long)buf,
(unsigned long)buf + pkt_len);
- NetReceive(buf, pkt_len);
+ net_process_received_packet(buf, pkt_len);
PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n",
lp->cur_rx, pkt_len, buf);
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index df7e9450c2..9d88afe8fc 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -11,6 +11,7 @@
#include <config.h>
#include <common.h>
+#include <dm.h>
#include <malloc.h>
#include <net.h>
#include <command.h>
@@ -754,7 +755,11 @@ struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask,
return get_phy_device_by_mask(bus, phy_mask, interface);
}
+#ifdef CONFIG_DM_ETH
+void phy_connect_dev(struct phy_device *phydev, struct udevice *dev)
+#else
void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
+#endif
{
/* Soft Reset the PHY */
phy_reset(phydev);
@@ -767,8 +772,13 @@ void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
debug("%s connected to %s\n", dev->name, phydev->drv->name);
}
+#ifdef CONFIG_DM_ETH
+struct phy_device *phy_connect(struct mii_dev *bus, int addr,
+ struct udevice *dev, phy_interface_t interface)
+#else
struct phy_device *phy_connect(struct mii_dev *bus, int addr,
struct eth_device *dev, phy_interface_t interface)
+#endif
{
struct phy_device *phydev;
@@ -813,3 +823,15 @@ int phy_shutdown(struct phy_device *phydev)
return 0;
}
+
+int phy_get_interface_by_name(const char *str)
+{
+ int i;
+
+ for (i = 0; i < PHY_INTERFACE_MODE_COUNT; i++) {
+ if (!strcmp(str, phy_interface_strings[i]))
+ return i;
+ }
+
+ return -1;
+}
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
index 208ce5ccc4..ea523435f0 100644
--- a/drivers/net/rtl8139.c
+++ b/drivers/net/rtl8139.c
@@ -504,11 +504,11 @@ static int rtl_poll(struct eth_device *dev)
memcpy(rxdata, rx_ring + ring_offs + 4, semi_count);
memcpy(&(rxdata[semi_count]), rx_ring, rx_size-4-semi_count);
- NetReceive(rxdata, length);
+ net_process_received_packet(rxdata, length);
debug_cond(DEBUG_RX, "rx packet %d+%d bytes",
semi_count, rx_size-4-semi_count);
} else {
- NetReceive(rx_ring + ring_offs + 4, length);
+ net_process_received_packet(rx_ring + ring_offs + 4, length);
debug_cond(DEBUG_RX, "rx packet %d bytes", rx_size-4);
}
flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index cea6701203..4a5371051b 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -538,7 +538,7 @@ static int rtl_recv(struct eth_device *dev)
cpu_to_le32(bus_to_phys(tpc->RxBufferRing[cur_rx]));
rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]);
- NetReceive(rxdata, length);
+ net_process_received_packet(rxdata, length);
} else {
puts("Error Rx");
}
diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c
new file mode 100644
index 0000000000..45c3b18bdf
--- /dev/null
+++ b/drivers/net/sandbox-raw.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015 National Instruments
+ *
+ * (C) Copyright 2015
+ * Joe Hershberger <joe.hershberger@ni.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <asm/eth-raw-os.h>
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <net.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int reply_arp;
+static struct in_addr arp_ip;
+
+static int sb_eth_raw_start(struct udevice *dev)
+{
+ struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ const char *interface;
+
+ debug("eth_sandbox_raw: Start\n");
+
+ interface = fdt_getprop(gd->fdt_blob, dev->of_offset,
+ "host-raw-interface", NULL);
+ if (interface == NULL)
+ return -EINVAL;
+
+ if (strcmp(interface, "lo") == 0) {
+ priv->local = 1;
+ setenv("ipaddr", "127.0.0.1");
+ setenv("serverip", "127.0.0.1");
+ }
+ return sandbox_eth_raw_os_start(interface, pdata->enetaddr, priv);
+}
+
+static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
+{
+ struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
+
+ debug("eth_sandbox_raw: Send packet %d\n", length);
+
+ if (priv->local) {
+ struct ethernet_hdr *eth = packet;
+
+ if (ntohs(eth->et_protlen) == PROT_ARP) {
+ struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
+
+ /**
+ * localhost works on a higher-level API in Linux than
+ * ARP packets, so fake it
+ */
+ arp_ip = net_read_ip(&arp->ar_tpa);
+ reply_arp = 1;
+ return 0;
+ }
+ packet += ETHER_HDR_SIZE;
+ length -= ETHER_HDR_SIZE;
+ }
+ return sandbox_eth_raw_os_send(packet, length, priv);
+}
+
+static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
+ int retval = 0;
+ int length;
+
+ if (reply_arp) {
+ struct arp_hdr *arp = (void *)net_rx_packets[0] +
+ ETHER_HDR_SIZE;
+
+ /*
+ * Fake an ARP response. The u-boot network stack is sending an
+ * ARP request (to find the MAC address to address the actual
+ * packet to) and requires an ARP response to continue. Since
+ * this is the localhost interface, there is no Etherent level
+ * traffic at all, so there is no way to send an ARP request or
+ * to get a response. For this reason we fake the response to
+ * make the u-boot network stack happy.
+ */
+ arp->ar_hrd = htons(ARP_ETHER);
+ arp->ar_pro = htons(PROT_IP);
+ arp->ar_hln = ARP_HLEN;
+ arp->ar_pln = ARP_PLEN;
+ arp->ar_op = htons(ARPOP_REPLY);
+ /* Any non-zero MAC address will work */
+ memset(&arp->ar_sha, 0x01, ARP_HLEN);
+ /* Use whatever IP we were looking for (always 127.0.0.1?) */
+ net_write_ip(&arp->ar_spa, arp_ip);
+ memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN);
+ net_write_ip(&arp->ar_tpa, net_ip);
+ length = ARP_HDR_SIZE;
+ } else {
+ /* If local, the Ethernet header won't be included; skip it */
+ uchar *pktptr = priv->local ?
+ net_rx_packets[0] + ETHER_HDR_SIZE : net_rx_packets[0];
+
+ retval = sandbox_eth_raw_os_recv(pktptr, &length, priv);
+ }
+
+ if (!retval && length) {
+ if (priv->local) {
+ struct ethernet_hdr *eth = (void *)net_rx_packets[0];
+
+ /* Fill in enough of the missing Ethernet header */
+ memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN);
+ memset(eth->et_src, 0x01, ARP_HLEN);
+ eth->et_protlen = htons(reply_arp ? PROT_ARP : PROT_IP);
+ reply_arp = 0;
+ length += ETHER_HDR_SIZE;
+ }
+
+ debug("eth_sandbox_raw: received packet %d\n",
+ length);
+ *packetp = net_rx_packets[0];
+ return length;
+ }
+ return retval;
+}
+
+static void sb_eth_raw_stop(struct udevice *dev)
+{
+ struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
+
+ debug("eth_sandbox_raw: Stop\n");
+
+ sandbox_eth_raw_os_stop(priv);
+}
+
+static const struct eth_ops sb_eth_raw_ops = {
+ .start = sb_eth_raw_start,
+ .send = sb_eth_raw_send,
+ .recv = sb_eth_raw_recv,
+ .stop = sb_eth_raw_stop,
+};
+
+static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ pdata->iobase = dev_get_addr(dev);
+ return 0;
+}
+
+static const struct udevice_id sb_eth_raw_ids[] = {
+ { .compatible = "sandbox,eth-raw" },
+ { }
+};
+
+U_BOOT_DRIVER(eth_sandbox_raw) = {
+ .name = "eth_sandbox_raw",
+ .id = UCLASS_ETH,
+ .of_match = sb_eth_raw_ids,
+ .ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata,
+ .ops = &sb_eth_raw_ops,
+ .priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c
new file mode 100644
index 0000000000..e239ff4447
--- /dev/null
+++ b/drivers/net/sandbox.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2015 National Instruments
+ *
+ * (C) Copyright 2015
+ * Joe Hershberger <joe.hershberger@ni.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <net.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct eth_sandbox_priv - memory for sandbox mock driver
+ *
+ * fake_host_hwaddr: MAC address of mocked machine
+ * fake_host_ipaddr: IP address of mocked machine
+ * recv_packet_buffer: buffer of the packet returned as received
+ * recv_packet_length: length of the packet returned as received
+ */
+struct eth_sandbox_priv {
+ uchar fake_host_hwaddr[ARP_HLEN];
+ struct in_addr fake_host_ipaddr;
+ uchar *recv_packet_buffer;
+ int recv_packet_length;
+};
+
+static bool disabled[8] = {false};
+
+/*
+ * sandbox_eth_disable_response()
+ *
+ * index - The alias index (also DM seq number)
+ * disable - If non-zero, ignore sent packets and don't send mock response
+ */
+void sandbox_eth_disable_response(int index, bool disable)
+{
+ disabled[index] = disable;
+}
+
+static int sb_eth_start(struct udevice *dev)
+{
+ struct eth_sandbox_priv *priv = dev_get_priv(dev);
+
+ debug("eth_sandbox: Start\n");
+
+ fdtdec_get_byte_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr",
+ priv->fake_host_hwaddr, ARP_HLEN);
+ priv->recv_packet_buffer = net_rx_packets[0];
+ return 0;
+}
+
+static int sb_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct eth_sandbox_priv *priv = dev_get_priv(dev);
+ struct ethernet_hdr *eth = packet;
+
+ debug("eth_sandbox: Send packet %d\n", length);
+
+ if (dev->seq >= 0 && dev->seq < ARRAY_SIZE(disabled) &&
+ disabled[dev->seq])
+ return 0;
+
+ if (ntohs(eth->et_protlen) == PROT_ARP) {
+ struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
+
+ if (ntohs(arp->ar_op) == ARPOP_REQUEST) {
+ struct ethernet_hdr *eth_recv;
+ struct arp_hdr *arp_recv;
+
+ /* store this as the assumed IP of the fake host */
+ priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa);
+ /* Formulate a fake response */
+ eth_recv = (void *)priv->recv_packet_buffer;
+ memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
+ memcpy(eth_recv->et_src, priv->fake_host_hwaddr,
+ ARP_HLEN);
+ eth_recv->et_protlen = htons(PROT_ARP);
+
+ arp_recv = (void *)priv->recv_packet_buffer +
+ ETHER_HDR_SIZE;
+ arp_recv->ar_hrd = htons(ARP_ETHER);
+ arp_recv->ar_pro = htons(PROT_IP);
+ arp_recv->ar_hln = ARP_HLEN;
+ arp_recv->ar_pln = ARP_PLEN;
+ arp_recv->ar_op = htons(ARPOP_REPLY);
+ memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr,
+ ARP_HLEN);
+ net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
+ memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN);
+ net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa);
+
+ priv->recv_packet_length = ETHER_HDR_SIZE +
+ ARP_HDR_SIZE;
+ }
+ } else if (ntohs(eth->et_protlen) == PROT_IP) {
+ struct ip_udp_hdr *ip = packet + ETHER_HDR_SIZE;
+
+ if (ip->ip_p == IPPROTO_ICMP) {
+ struct icmp_hdr *icmp = (struct icmp_hdr *)&ip->udp_src;
+
+ if (icmp->type == ICMP_ECHO_REQUEST) {
+ struct ethernet_hdr *eth_recv;
+ struct ip_udp_hdr *ipr;
+ struct icmp_hdr *icmpr;
+
+ /* reply to the ping */
+ memcpy(priv->recv_packet_buffer, packet,
+ length);
+ eth_recv = (void *)priv->recv_packet_buffer;
+ ipr = (void *)priv->recv_packet_buffer +
+ ETHER_HDR_SIZE;
+ icmpr = (struct icmp_hdr *)&ipr->udp_src;
+ memcpy(eth_recv->et_dest, eth->et_src,
+ ARP_HLEN);
+ memcpy(eth_recv->et_src, priv->fake_host_hwaddr,
+ ARP_HLEN);
+ ipr->ip_sum = 0;
+ ipr->ip_off = 0;
+ net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src);
+ net_write_ip((void *)&ipr->ip_src,
+ priv->fake_host_ipaddr);
+ ipr->ip_sum = compute_ip_checksum(ipr,
+ IP_HDR_SIZE);
+
+ icmpr->type = ICMP_ECHO_REPLY;
+ icmpr->checksum = 0;
+ icmpr->checksum = compute_ip_checksum(icmpr,
+ ICMP_HDR_SIZE);
+
+ priv->recv_packet_length = length;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int sb_eth_recv(struct udevice *dev, uchar **packetp)
+{
+ struct eth_sandbox_priv *priv = dev_get_priv(dev);
+
+ if (priv->recv_packet_length) {
+ int lcl_recv_packet_length = priv->recv_packet_length;
+
+ debug("eth_sandbox: received packet %d\n",
+ priv->recv_packet_length);
+ priv->recv_packet_length = 0;
+ *packetp = priv->recv_packet_buffer;
+ return lcl_recv_packet_length;
+ }
+ return 0;
+}
+
+static void sb_eth_stop(struct udevice *dev)
+{
+ debug("eth_sandbox: Stop\n");
+}
+
+static int sb_eth_write_hwaddr(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name,
+ pdata->enetaddr);
+ return 0;
+}
+
+static const struct eth_ops sb_eth_ops = {
+ .start = sb_eth_start,
+ .send = sb_eth_send,
+ .recv = sb_eth_recv,
+ .stop = sb_eth_stop,
+ .write_hwaddr = sb_eth_write_hwaddr,
+};
+
+static int sb_eth_remove(struct udevice *dev)
+{
+ return 0;
+}
+
+static int sb_eth_ofdata_to_platdata(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ pdata->iobase = dev_get_addr(dev);
+ return 0;
+}
+
+static const struct udevice_id sb_eth_ids[] = {
+ { .compatible = "sandbox,eth" },
+ { }
+};
+
+U_BOOT_DRIVER(eth_sandbox) = {
+ .name = "eth_sandbox",
+ .id = UCLASS_ETH,
+ .of_match = sb_eth_ids,
+ .ofdata_to_platdata = sb_eth_ofdata_to_platdata,
+ .remove = sb_eth_remove,
+ .ops = &sb_eth_ops,
+ .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 4bf493ed45..a320b4d75b 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -127,7 +127,7 @@ int sh_eth_recv(struct eth_device *dev)
packet = (uchar *)
ADDR_TO_P2(port_info->rx_desc_cur->rd2);
invalidate_cache(packet, len);
- NetReceive(packet, len);
+ net_process_received_packet(packet, len);
}
/* Make current descriptor available again */
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c
index 57c667a58a..ade14cd475 100644
--- a/drivers/net/smc91111.c
+++ b/drivers/net/smc91111.c
@@ -756,35 +756,35 @@ static int smc_rcv(struct eth_device *dev)
#ifdef USE_32_BIT
- PRINTK3(" Reading %d dwords (and %d bytes) \n",
+ PRINTK3(" Reading %d dwords (and %d bytes)\n",
packet_length >> 2, packet_length & 3 );
/* QUESTION: Like in the TX routine, do I want
to send the DWORDs or the bytes first, or some
mixture. A mixture might improve already slow PIO
performance */
- SMC_insl( dev, SMC91111_DATA_REG, NetRxPackets[0],
- packet_length >> 2 );
+ SMC_insl(dev, SMC91111_DATA_REG, net_rx_packets[0],
+ packet_length >> 2);
/* read the left over bytes */
if (packet_length & 3) {
int i;
- byte *tail = (byte *)(NetRxPackets[0] +
+ byte *tail = (byte *)(net_rx_packets[0] +
(packet_length & ~3));
dword leftover = SMC_inl(dev, SMC91111_DATA_REG);
for (i=0; i<(packet_length & 3); i++)
*tail++ = (byte) (leftover >> (8*i)) & 0xff;
}
#else
- PRINTK3(" Reading %d words and %d byte(s) \n",
+ PRINTK3(" Reading %d words and %d byte(s)\n",
(packet_length >> 1 ), packet_length & 1 );
- SMC_insw(dev, SMC91111_DATA_REG , NetRxPackets[0],
- packet_length >> 1);
+ SMC_insw(dev, SMC91111_DATA_REG , net_rx_packets[0],
+ packet_length >> 1);
#endif /* USE_32_BIT */
#if SMC_DEBUG > 2
printf("Receiving Packet\n");
- print_packet( NetRxPackets[0], packet_length );
+ print_packet(net_rx_packets[0], packet_length);
#endif
} else {
/* error ... */
@@ -815,7 +815,7 @@ static int smc_rcv(struct eth_device *dev)
if (!is_error) {
/* Pass the packet up to the protocol layers. */
- NetReceive(NetRxPackets[0], packet_length);
+ net_process_received_packet(net_rx_packets[0], packet_length);
return packet_length;
} else {
return 0;
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 5959672370..c85a178cd8 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -192,7 +192,7 @@ static void smc911x_halt(struct eth_device *dev)
static int smc911x_rx(struct eth_device *dev)
{
- u32 *data = (u32 *)NetRxPackets[0];
+ u32 *data = (u32 *)net_rx_packets[0];
u32 pktlen, tmplen;
u32 status;
@@ -211,7 +211,7 @@ static int smc911x_rx(struct eth_device *dev)
": dropped bad packet. Status: 0x%08x\n",
status);
else
- NetReceive(NetRxPackets[0], pktlen);
+ net_process_received_packet(net_rx_packets[0], pktlen);
}
return 0;
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
index 2a9fd56c95..7b31f8c1da 100644
--- a/drivers/net/sunxi_emac.c
+++ b/drivers/net/sunxi_emac.c
@@ -437,10 +437,10 @@ static int sunxi_emac_eth_recv(struct eth_device *dev)
printf("Received packet is too big (len=%d)\n", rx_len);
} else {
emac_inblk_32bit((void *)&regs->rx_io_data,
- NetRxPackets[0], rx_len);
+ net_rx_packets[0], rx_len);
/* Pass to upper layer */
- NetReceive(NetRxPackets[0], rx_len);
+ net_process_received_packet(net_rx_packets[0], rx_len);
return rx_len;
}
}
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index dcdba4ea82..42d037471f 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -287,7 +287,7 @@ void redundant_init(struct eth_device *dev)
}
}
- if (!memcmp(pkt, (void *)NetRxPackets[rx_idx], sizeof(pkt)))
+ if (!memcmp(pkt, (void *)net_rx_packets[rx_idx], sizeof(pkt)))
fail = 0;
out_be16(&rxbd[rx_idx].length, 0);
@@ -343,7 +343,7 @@ static void startup_tsec(struct eth_device *dev)
for (i = 0; i < PKTBUFSRX; i++) {
out_be16(&rxbd[i].status, RXBD_EMPTY);
out_be16(&rxbd[i].length, 0);
- out_be32(&rxbd[i].bufptr, (u32)NetRxPackets[i]);
+ out_be32(&rxbd[i].bufptr, (u32)net_rx_packets[i]);
}
status = in_be16(&rxbd[PKTBUFSRX - 1].status);
out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
@@ -430,7 +430,8 @@ static int tsec_recv(struct eth_device *dev)
/* Send the packet up if there were no errors */
if (!(status & RXBD_STATS))
- NetReceive(NetRxPackets[rx_idx], length - 4);
+ net_process_received_packet(net_rx_packets[rx_idx],
+ length - 4);
else
printf("Got error %x\n", (status & RXBD_STATS));
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 72b8159d82..9da59a018a 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -804,11 +804,11 @@ static int tsi108_eth_probe (struct eth_device *dev, bd_t * bis)
rx_descr_current = rx_descr;
for (index = 0; index < NUM_RX_DESC; index++) {
/* make sure the receive buffers are not in cache */
- invalidate_dcache_range((unsigned long)NetRxPackets[index],
- (unsigned long)NetRxPackets[index] +
+ invalidate_dcache_range((unsigned long)net_rx_packets[index],
+ (unsigned long)net_rx_packets[index] +
RX_BUFFER_SIZE);
rx_descr->start_addr0 =
- cpu_to_le32((vuint32) NetRxPackets[index]);
+ cpu_to_le32((vuint32) net_rx_packets[index]);
rx_descr->start_addr1 = 0;
rx_descr->next_descr_addr0 =
cpu_to_le32((vuint32) (rx_descr + 1));
@@ -966,7 +966,7 @@ static int tsi108_eth_recv (struct eth_device *dev)
/*** process packet ***/
buffer = (uchar *)(le32_to_cpu(rx_descr->start_addr0));
- NetReceive(buffer, length);
+ net_process_received_packet(buffer, length);
invalidate_dcache_range ((unsigned long)buffer,
(unsigned long)buffer +
diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c
index 9526faa4af..47cdb858c7 100644
--- a/drivers/net/uli526x.c
+++ b/drivers/net/uli526x.c
@@ -587,7 +587,8 @@ static int uli526x_rx_packet(struct eth_device *dev)
__FUNCTION__, i, rxptr->rx_buf_ptr[i]);
#endif
- NetReceive((uchar *)rxptr->rx_buf_ptr, rxlen);
+ net_process_received_packet(
+ (uchar *)rxptr->rx_buf_ptr, rxlen);
uli526x_reuse_buf(rxptr);
} else {
@@ -709,7 +710,7 @@ static void allocate_rx_buffer(struct uli526x_board_info *db)
u32 addr;
for (index = 0; index < RX_DESC_CNT; index++) {
- addr = (u32)NetRxPackets[index];
+ addr = (u32)net_rx_packets[index];
addr += (16 - (addr & 15));
rxptr->rx_buf_ptr = (char *) addr;
rxptr->rdes2 = cpu_to_le32(addr);
diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c
index 262b67b6cf..df053feee8 100644
--- a/drivers/net/xilinx_axi_emac.c
+++ b/drivers/net/xilinx_axi_emac.c
@@ -556,7 +556,7 @@ static int axiemac_recv(struct eth_device *dev)
#endif
/* Pass the received frame up for processing */
if (length)
- NetReceive(rxframe, length);
+ net_process_received_packet(rxframe, length);
#ifdef DEBUG
/* It is useful to clear buffer to be sure that it is consistent */
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 2a5cc44553..c9afa99690 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -322,7 +322,7 @@ static int emaclite_recv(struct eth_device *dev)
out_be32 (baseaddress + XEL_RSR_OFFSET, reg);
debug("Packet receive from 0x%x, length %dB\n", baseaddress, length);
- NetReceive((uchar *) etherrxbuff, length);
+ net_process_received_packet((uchar *)etherrxbuff, length);
return length;
}
diff --git a/drivers/net/xilinx_ll_temac_fifo.c b/drivers/net/xilinx_ll_temac_fifo.c
index b8993cdb29..78319d7d91 100644
--- a/drivers/net/xilinx_ll_temac_fifo.c
+++ b/drivers/net/xilinx_ll_temac_fifo.c
@@ -48,7 +48,7 @@ int ll_temac_reset_fifo(struct eth_device *dev)
int ll_temac_recv_fifo(struct eth_device *dev)
{
int i, length = 0;
- u32 *buf = (u32 *)NetRxPackets[0];
+ u32 *buf = (u32 *)net_rx_packets[0];
struct ll_temac *ll_temac = dev->priv;
struct fifo_ctrl *fifo_ctrl = (void *)ll_temac->ctrladdr;
@@ -93,7 +93,7 @@ int ll_temac_recv_fifo(struct eth_device *dev)
for (i = 0; i < length; i += 4)
*buf++ = in_be32(&fifo_ctrl->rdfd);
- NetReceive(NetRxPackets[0], length);
+ net_process_received_packet(net_rx_packets[0], length);
}
return 0;
diff --git a/drivers/net/xilinx_ll_temac_sdma.c b/drivers/net/xilinx_ll_temac_sdma.c
index 32a822eea5..07c5f6bf10 100644
--- a/drivers/net/xilinx_ll_temac_sdma.c
+++ b/drivers/net/xilinx_ll_temac_sdma.c
@@ -180,7 +180,7 @@ int ll_temac_init_sdma(struct eth_device *dev)
memset(rx_dp, 0, sizeof(*rx_dp));
rx_dp->next_p = rx_dp;
rx_dp->buf_len = PKTSIZE_ALIGN;
- rx_dp->phys_buf_p = (u8 *)NetRxPackets[i];
+ rx_dp->phys_buf_p = (u8 *)net_rx_packets[i];
flush_cache((u32)rx_dp->phys_buf_p, PKTSIZE_ALIGN);
}
flush_cache((u32)cdmac_bd.rx, sizeof(cdmac_bd.rx));
@@ -316,7 +316,7 @@ int ll_temac_recv_sdma(struct eth_device *dev)
ll_temac->out32(ra[RX_TAILDESC_PTR], (int)&cdmac_bd.rx[rx_idx]);
if (length > 0 && pb_idx != -1)
- NetReceive(NetRxPackets[pb_idx], length);
+ net_process_received_packet(net_rx_packets[pb_idx], length);
return 0;
}
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 430e22821c..74fda70abe 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -439,7 +439,7 @@ static int zynq_gem_recv(struct eth_device *dev)
u32 size = roundup(frame_len, ARCH_DMA_MINALIGN);
invalidate_dcache_range(addr, addr + size);
- NetReceive((u8 *)addr, frame_len);
+ net_process_received_packet((u8 *)addr, frame_len);
if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK)
priv->rx_first_buf = priv->rxbd_current;
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index e69de29bb2..167d405918 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -0,0 +1,22 @@
+menu "PCI"
+
+config DM_PCI
+ bool "Enable driver mode for PCI"
+ depends on DM
+ help
+ Use driver model for PCI. Driver model is the new method for
+ orgnising devices in U-Boot. For PCI, driver model keeps track of
+ available PCI devices, allows scanning of PCI buses and provides
+ device configuration support.
+
+config PCI_SANDBOX
+ bool "Sandbox PCI support"
+ depends on SANDBOX && DM_PCI
+ help
+ Support PCI on sandbox, as an emulated bus. This permits testing of
+ PCI feature such as bus scanning, device configuration and device
+ access. The available (emulated) devices are defined statically in
+ the device tree but the normal PCI scan technique is used to find
+ then.
+
+endmenu
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 50b7be53ca..adc238f0f0 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -5,8 +5,17 @@
# SPDX-License-Identifier: GPL-2.0+
#
+ifneq ($(CONFIG_DM_PCI),)
+obj-$(CONFIG_PCI) += pci-uclass.o pci_compat.o
+obj-$(CONFIG_PCI_SANDBOX) += pci_sandbox.o
+obj-$(CONFIG_SANDBOX) += pci-emul-uclass.o
+obj-$(CONFIG_X86) += pci_x86.o
+else
+obj-$(CONFIG_PCI) += pci.o
+endif
+obj-$(CONFIG_PCI) += pci_common.o pci_auto.o pci_rom.o
+
obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
-obj-$(CONFIG_PCI) += pci.o pci_auto.o pci_rom.o
obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c
new file mode 100644
index 0000000000..0f8e3c9fcb
--- /dev/null
+++ b/drivers/pci/pci-emul-uclass.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <pci.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sandbox_pci_priv {
+ int dev_count;
+};
+
+int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
+ struct udevice **emulp)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = pci_bus_find_devfn(bus, find_devfn, &dev);
+ if (ret) {
+ debug("%s: Could not find emulator for dev %x\n", __func__,
+ find_devfn);
+ return ret;
+ }
+
+ ret = device_find_first_child(dev, emulp);
+ if (ret)
+ return ret;
+
+ return *emulp ? 0 : -ENODEV;
+}
+
+static int sandbox_pci_emul_post_probe(struct udevice *dev)
+{
+ struct sandbox_pci_priv *priv = dev->uclass->priv;
+
+ priv->dev_count++;
+ sandbox_set_enable_pci_map(true);
+
+ return 0;
+}
+
+static int sandbox_pci_emul_pre_remove(struct udevice *dev)
+{
+ struct sandbox_pci_priv *priv = dev->uclass->priv;
+
+ priv->dev_count--;
+ sandbox_set_enable_pci_map(priv->dev_count > 0);
+
+ return 0;
+}
+
+UCLASS_DRIVER(pci_emul) = {
+ .id = UCLASS_PCI_EMUL,
+ .name = "pci_emul",
+ .post_probe = sandbox_pci_emul_post_probe,
+ .pre_remove = sandbox_pci_emul_pre_remove,
+ .priv_auto_alloc_size = sizeof(struct sandbox_pci_priv),
+};
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
new file mode 100644
index 0000000000..d48d865bac
--- /dev/null
+++ b/drivers/pci/pci-uclass.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <inttypes.h>
+#include <pci.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pci_controller *pci_bus_to_hose(int busnum)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, &bus);
+ if (ret) {
+ debug("%s: Cannot get bus %d: ret=%d\n", __func__, busnum, ret);
+ return NULL;
+ }
+ return dev_get_uclass_priv(bus);
+}
+
+/**
+ * pci_get_bus_max() - returns the bus number of the last active bus
+ *
+ * @return last bus number, or -1 if no active buses
+ */
+static int pci_get_bus_max(void)
+{
+ struct udevice *bus;
+ struct uclass *uc;
+ int ret = -1;
+
+ ret = uclass_get(UCLASS_PCI, &uc);
+ uclass_foreach_dev(bus, uc) {
+ if (bus->seq > ret)
+ ret = bus->seq;
+ }
+
+ debug("%s: ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int pci_last_busno(void)
+{
+ struct pci_controller *hose;
+ struct udevice *bus;
+ struct uclass *uc;
+ int ret;
+
+ debug("pci_last_busno\n");
+ ret = uclass_get(UCLASS_PCI, &uc);
+ if (ret || list_empty(&uc->dev_head))
+ return -1;
+
+ /* Probe the last bus */
+ bus = list_entry(uc->dev_head.prev, struct udevice, uclass_node);
+ debug("bus = %p, %s\n", bus, bus->name);
+ assert(bus);
+ ret = device_probe(bus);
+ if (ret)
+ return ret;
+
+ /* If that bus has bridges, we may have new buses now. Get the last */
+ bus = list_entry(uc->dev_head.prev, struct udevice, uclass_node);
+ hose = dev_get_uclass_priv(bus);
+ debug("bus = %s, hose = %p\n", bus->name, hose);
+
+ return hose->last_busno;
+}
+
+int pci_get_ff(enum pci_size_t size)
+{
+ switch (size) {
+ case PCI_SIZE_8:
+ return 0xff;
+ case PCI_SIZE_16:
+ return 0xffff;
+ default:
+ return 0xffffffff;
+ }
+}
+
+int pci_bus_find_devfn(struct udevice *bus, pci_dev_t find_devfn,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ for (device_find_first_child(bus, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ struct pci_child_platdata *pplat;
+
+ pplat = dev_get_parent_platdata(dev);
+ if (pplat && pplat->devfn == find_devfn) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int pci_bus_find_bdf(pci_dev_t bdf, struct udevice **devp)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+ return pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), devp);
+}
+
+static int pci_device_matches_ids(struct udevice *dev,
+ struct pci_device_id *ids)
+{
+ struct pci_child_platdata *pplat;
+ int i;
+
+ pplat = dev_get_parent_platdata(dev);
+ if (!pplat)
+ return -EINVAL;
+ for (i = 0; ids[i].vendor != 0; i++) {
+ if (pplat->vendor == ids[i].vendor &&
+ pplat->device == ids[i].device)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+int pci_bus_find_devices(struct udevice *bus, struct pci_device_id *ids,
+ int *indexp, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ /* Scan all devices on this bus */
+ for (device_find_first_child(bus, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ if (pci_device_matches_ids(dev, ids) >= 0) {
+ if ((*indexp)-- <= 0) {
+ *devp = dev;
+ return 0;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+
+int pci_find_device_id(struct pci_device_id *ids, int index,
+ struct udevice **devp)
+{
+ struct udevice *bus;
+
+ /* Scan all known buses */
+ for (uclass_first_device(UCLASS_PCI, &bus);
+ bus;
+ uclass_next_device(&bus)) {
+ if (!pci_bus_find_devices(bus, ids, &index, devp))
+ return 0;
+ }
+ *devp = NULL;
+
+ return -ENODEV;
+}
+
+int pci_bus_write_config(struct udevice *bus, pci_dev_t bdf, int offset,
+ unsigned long value, enum pci_size_t size)
+{
+ struct dm_pci_ops *ops;
+
+ ops = pci_get_ops(bus);
+ if (!ops->write_config)
+ return -ENOSYS;
+ return ops->write_config(bus, bdf, offset, value, size);
+}
+
+int pci_write_config(pci_dev_t bdf, int offset, unsigned long value,
+ enum pci_size_t size)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+
+ return pci_bus_write_config(bus, PCI_MASK_BUS(bdf), offset, value,
+ size);
+}
+
+int pci_write_config32(pci_dev_t bdf, int offset, u32 value)
+{
+ return pci_write_config(bdf, offset, value, PCI_SIZE_32);
+}
+
+int pci_write_config16(pci_dev_t bdf, int offset, u16 value)
+{
+ return pci_write_config(bdf, offset, value, PCI_SIZE_16);
+}
+
+int pci_write_config8(pci_dev_t bdf, int offset, u8 value)
+{
+ return pci_write_config(bdf, offset, value, PCI_SIZE_8);
+}
+
+int pci_bus_read_config(struct udevice *bus, pci_dev_t bdf, int offset,
+ unsigned long *valuep, enum pci_size_t size)
+{
+ struct dm_pci_ops *ops;
+
+ ops = pci_get_ops(bus);
+ if (!ops->read_config)
+ return -ENOSYS;
+ return ops->read_config(bus, bdf, offset, valuep, size);
+}
+
+int pci_read_config(pci_dev_t bdf, int offset, unsigned long *valuep,
+ enum pci_size_t size)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+
+ return pci_bus_read_config(bus, PCI_MASK_BUS(bdf), offset, valuep,
+ size);
+}
+
+int pci_read_config32(pci_dev_t bdf, int offset, u32 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_32);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int pci_read_config16(pci_dev_t bdf, int offset, u16 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_16);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int pci_read_config8(pci_dev_t bdf, int offset, u8 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_8);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int pci_auto_config_devices(struct udevice *bus)
+{
+ struct pci_controller *hose = bus->uclass_priv;
+ unsigned int sub_bus;
+ struct udevice *dev;
+ int ret;
+
+ sub_bus = bus->seq;
+ debug("%s: start\n", __func__);
+ pciauto_config_init(hose);
+ for (ret = device_find_first_child(bus, &dev);
+ !ret && dev;
+ ret = device_find_next_child(&dev)) {
+ struct pci_child_platdata *pplat;
+
+ pplat = dev_get_parent_platdata(dev);
+ unsigned int max_bus;
+ pci_dev_t bdf;
+
+ bdf = PCI_ADD_BUS(bus->seq, pplat->devfn);
+ debug("%s: device %s\n", __func__, dev->name);
+ max_bus = pciauto_config_device(hose, bdf);
+ sub_bus = max(sub_bus, max_bus);
+ }
+ debug("%s: done\n", __func__);
+
+ return sub_bus;
+}
+
+int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf)
+{
+ struct udevice *parent, *bus;
+ int sub_bus;
+ int ret;
+
+ debug("%s\n", __func__);
+ parent = hose->bus;
+
+ /* Find the bus within the parent */
+ ret = pci_bus_find_devfn(parent, bdf, &bus);
+ if (ret) {
+ debug("%s: Cannot find device %x on bus %s: %d\n", __func__,
+ bdf, parent->name, ret);
+ return ret;
+ }
+
+ sub_bus = pci_get_bus_max() + 1;
+ debug("%s: bus = %d/%s\n", __func__, sub_bus, bus->name);
+ pciauto_prescan_setup_bridge(hose, bdf, bus->seq);
+
+ ret = device_probe(bus);
+ if (ret) {
+ debug("%s: Cannot probe bus bus %s: %d\n", __func__, bus->name,
+ ret);
+ return ret;
+ }
+ if (sub_bus != bus->seq) {
+ printf("%s: Internal error, bus '%s' got seq %d, expected %d\n",
+ __func__, bus->name, bus->seq, sub_bus);
+ return -EPIPE;
+ }
+ sub_bus = pci_get_bus_max();
+ pciauto_postscan_setup_bridge(hose, bdf, sub_bus);
+
+ return sub_bus;
+}
+
+int pci_bind_bus_devices(struct udevice *bus)
+{
+ ulong vendor, device;
+ ulong header_type;
+ pci_dev_t devfn, end;
+ bool found_multi;
+ int ret;
+
+ found_multi = false;
+ end = PCI_DEVFN(PCI_MAX_PCI_DEVICES - 1, PCI_MAX_PCI_FUNCTIONS - 1);
+ for (devfn = PCI_DEVFN(0, 0); devfn < end; devfn += PCI_DEVFN(0, 1)) {
+ struct pci_child_platdata *pplat;
+ struct udevice *dev;
+ ulong class;
+
+ if (PCI_FUNC(devfn) && !found_multi)
+ continue;
+ /* Check only the first access, we don't expect problems */
+ ret = pci_bus_read_config(bus, devfn, PCI_HEADER_TYPE,
+ &header_type, PCI_SIZE_8);
+ if (ret)
+ goto error;
+ pci_bus_read_config(bus, devfn, PCI_VENDOR_ID, &vendor,
+ PCI_SIZE_16);
+ if (vendor == 0xffff || vendor == 0x0000)
+ continue;
+
+ if (!PCI_FUNC(devfn))
+ found_multi = header_type & 0x80;
+
+ debug("%s: bus %d/%s: found device %x, function %d\n", __func__,
+ bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));
+ pci_bus_read_config(bus, devfn, PCI_DEVICE_ID, &device,
+ PCI_SIZE_16);
+ pci_bus_read_config(bus, devfn, PCI_CLASS_DEVICE, &class,
+ PCI_SIZE_16);
+
+ /* Find this device in the device tree */
+ ret = pci_bus_find_devfn(bus, devfn, &dev);
+
+ /* If nothing in the device tree, bind a generic device */
+ if (ret == -ENODEV) {
+ char name[30], *str;
+ const char *drv;
+
+ sprintf(name, "pci_%x:%x.%x", bus->seq,
+ PCI_DEV(devfn), PCI_FUNC(devfn));
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ drv = class == PCI_CLASS_BRIDGE_PCI ?
+ "pci_bridge_drv" : "pci_generic_drv";
+ ret = device_bind_driver(bus, drv, str, &dev);
+ }
+ if (ret)
+ return ret;
+
+ /* Update the platform data */
+ pplat = dev_get_parent_platdata(dev);
+ pplat->devfn = devfn;
+ pplat->vendor = vendor;
+ pplat->device = device;
+ pplat->class = class;
+ }
+
+ return 0;
+error:
+ printf("Cannot read bus configuration: %d\n", ret);
+
+ return ret;
+}
+
+static int pci_uclass_post_bind(struct udevice *bus)
+{
+ /*
+ * Scan the device tree for devices. This does not probe the PCI bus,
+ * as this is not permitted while binding. It just finds devices
+ * mentioned in the device tree.
+ *
+ * Before relocation, only bind devices marked for pre-relocation
+ * use.
+ */
+ return dm_scan_fdt_node(bus, gd->fdt_blob, bus->of_offset,
+ gd->flags & GD_FLG_RELOC ? false : true);
+}
+
+static int decode_regions(struct pci_controller *hose, const void *blob,
+ int parent_node, int node)
+{
+ int pci_addr_cells, addr_cells, size_cells;
+ int cells_per_record;
+ const u32 *prop;
+ int len;
+ int i;
+
+ prop = fdt_getprop(blob, node, "ranges", &len);
+ if (!prop)
+ return -EINVAL;
+ pci_addr_cells = fdt_address_cells(blob, node);
+ addr_cells = fdt_address_cells(blob, parent_node);
+ size_cells = fdt_size_cells(blob, node);
+
+ /* PCI addresses are always 3-cells */
+ len /= sizeof(u32);
+ cells_per_record = pci_addr_cells + addr_cells + size_cells;
+ hose->region_count = 0;
+ debug("%s: len=%d, cells_per_record=%d\n", __func__, len,
+ cells_per_record);
+ for (i = 0; i < MAX_PCI_REGIONS; i++, len -= cells_per_record) {
+ u64 pci_addr, addr, size;
+ int space_code;
+ u32 flags;
+ int type;
+
+ if (len < cells_per_record)
+ break;
+ flags = fdt32_to_cpu(prop[0]);
+ space_code = (flags >> 24) & 3;
+ pci_addr = fdtdec_get_number(prop + 1, 2);
+ prop += pci_addr_cells;
+ addr = fdtdec_get_number(prop, addr_cells);
+ prop += addr_cells;
+ size = fdtdec_get_number(prop, size_cells);
+ prop += size_cells;
+ debug("%s: region %d, pci_addr=%" PRIx64 ", addr=%" PRIx64
+ ", size=%" PRIx64 ", space_code=%d\n", __func__,
+ hose->region_count, pci_addr, addr, size, space_code);
+ if (space_code & 2) {
+ type = flags & (1U << 30) ? PCI_REGION_PREFETCH :
+ PCI_REGION_MEM;
+ } else if (space_code & 1) {
+ type = PCI_REGION_IO;
+ } else {
+ continue;
+ }
+ debug(" - type=%d\n", type);
+ pci_set_region(hose->regions + hose->region_count++, pci_addr,
+ addr, size, type);
+ }
+
+ /* Add a region for our local memory */
+ pci_set_region(hose->regions + hose->region_count++, 0, 0,
+ gd->ram_size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ return 0;
+}
+
+static int pci_uclass_pre_probe(struct udevice *bus)
+{
+ struct pci_controller *hose;
+ int ret;
+
+ debug("%s, bus=%d/%s, parent=%s\n", __func__, bus->seq, bus->name,
+ bus->parent->name);
+ hose = bus->uclass_priv;
+
+ /* For bridges, use the top-level PCI controller */
+ if (device_get_uclass_id(bus->parent) == UCLASS_ROOT) {
+ hose->ctlr = bus;
+ ret = decode_regions(hose, gd->fdt_blob, bus->parent->of_offset,
+ bus->of_offset);
+ if (ret) {
+ debug("%s: Cannot decode regions\n", __func__);
+ return ret;
+ }
+ } else {
+ struct pci_controller *parent_hose;
+
+ parent_hose = dev_get_uclass_priv(bus->parent);
+ hose->ctlr = parent_hose->bus;
+ }
+ hose->bus = bus;
+ hose->first_busno = bus->seq;
+ hose->last_busno = bus->seq;
+
+ return 0;
+}
+
+static int pci_uclass_post_probe(struct udevice *bus)
+{
+ int ret;
+
+ /* Don't scan buses before relocation */
+ if (!(gd->flags & GD_FLG_RELOC))
+ return 0;
+
+ debug("%s: probing bus %d\n", __func__, bus->seq);
+ ret = pci_bind_bus_devices(bus);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_PCI_PNP
+ ret = pci_auto_config_devices(bus);
+#endif
+
+ return ret < 0 ? ret : 0;
+}
+
+static int pci_uclass_child_post_bind(struct udevice *dev)
+{
+ struct pci_child_platdata *pplat;
+ struct fdt_pci_addr addr;
+ int ret;
+
+ if (dev->of_offset == -1)
+ return 0;
+
+ /*
+ * We could read vendor, device, class if available. But for now we
+ * just check the address.
+ */
+ pplat = dev_get_parent_platdata(dev);
+ ret = fdtdec_get_pci_addr(gd->fdt_blob, dev->of_offset,
+ FDT_PCI_SPACE_CONFIG, "reg", &addr);
+
+ if (ret) {
+ if (ret != -ENOENT)
+ return -EINVAL;
+ } else {
+ /* extract the bdf from fdt_pci_addr */
+ pplat->devfn = addr.phys_hi & 0xffff00;
+ }
+
+ return 0;
+}
+
+int pci_bridge_read_config(struct udevice *bus, pci_dev_t devfn, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ struct pci_controller *hose = bus->uclass_priv;
+ pci_dev_t bdf = PCI_ADD_BUS(bus->seq, devfn);
+
+ return pci_bus_read_config(hose->ctlr, bdf, offset, valuep, size);
+}
+
+int pci_bridge_write_config(struct udevice *bus, pci_dev_t devfn, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ struct pci_controller *hose = bus->uclass_priv;
+ pci_dev_t bdf = PCI_ADD_BUS(bus->seq, devfn);
+
+ return pci_bus_write_config(hose->ctlr, bdf, offset, value, size);
+}
+
+UCLASS_DRIVER(pci) = {
+ .id = UCLASS_PCI,
+ .name = "pci",
+ .post_bind = pci_uclass_post_bind,
+ .pre_probe = pci_uclass_pre_probe,
+ .post_probe = pci_uclass_post_probe,
+ .child_post_bind = pci_uclass_child_post_bind,
+ .per_device_auto_alloc_size = sizeof(struct pci_controller),
+ .per_child_platdata_auto_alloc_size =
+ sizeof(struct pci_child_platdata),
+};
+
+static const struct dm_pci_ops pci_bridge_ops = {
+ .read_config = pci_bridge_read_config,
+ .write_config = pci_bridge_write_config,
+};
+
+static const struct udevice_id pci_bridge_ids[] = {
+ { .compatible = "pci-bridge" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_bridge_drv) = {
+ .name = "pci_bridge_drv",
+ .id = UCLASS_PCI,
+ .of_match = pci_bridge_ids,
+ .ops = &pci_bridge_ops,
+};
+
+UCLASS_DRIVER(pci_generic) = {
+ .id = UCLASS_PCI_GENERIC,
+ .name = "pci_generic",
+};
+
+static const struct udevice_id pci_generic_ids[] = {
+ { .compatible = "pci-generic" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_generic_drv) = {
+ .name = "pci_generic_drv",
+ .id = UCLASS_PCI_GENERIC,
+ .of_match = pci_generic_ids,
+};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e1296cab9e..3babd94805 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -101,25 +101,6 @@ PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02)
PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff)
PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff)
-/* Get a virtual address associated with a BAR region */
-void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
-{
- pci_addr_t pci_bus_addr;
- u32 bar_response;
-
- /* read BAR address */
- pci_read_config_dword(pdev, bar, &bar_response);
- pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
-
- /*
- * Pass "0" as the length argument to pci_bus_to_virt. The arg
- * isn't actualy used on any platform because u-boot assumes a static
- * linear mapping. In the future, this could read the BAR size
- * and pass that as the size if needed.
- */
- return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
-}
-
/*
*
*/
@@ -187,106 +168,22 @@ int pci_last_busno(void)
pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
{
struct pci_controller * hose;
- u16 vendor, device;
- u8 header_type;
pci_dev_t bdf;
- int i, bus, found_multi = 0;
+ int bus;
for (hose = pci_get_hose_head(); hose; hose = hose->next) {
#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
- for (bus = hose->last_busno; bus >= hose->first_busno; bus--)
+ for (bus = hose->last_busno; bus >= hose->first_busno; bus--) {
#else
- for (bus = hose->first_busno; bus <= hose->last_busno; bus++)
+ for (bus = hose->first_busno; bus <= hose->last_busno; bus++) {
#endif
- for (bdf = PCI_BDF(bus, 0, 0);
- bdf < PCI_BDF(bus + 1, 0, 0);
- bdf += PCI_BDF(0, 0, 1)) {
- if (pci_skip_dev(hose, bdf))
- continue;
-
- if (!PCI_FUNC(bdf)) {
- pci_read_config_byte(bdf,
- PCI_HEADER_TYPE,
- &header_type);
-
- found_multi = header_type & 0x80;
- } else {
- if (!found_multi)
- continue;
- }
-
- pci_read_config_word(bdf,
- PCI_VENDOR_ID,
- &vendor);
- pci_read_config_word(bdf,
- PCI_DEVICE_ID,
- &device);
-
- for (i = 0; ids[i].vendor != 0; i++) {
- if (vendor == ids[i].vendor &&
- device == ids[i].device) {
- if (index <= 0)
- return bdf;
-
- index--;
- }
- }
- }
- }
-
- return -1;
-}
-
-pci_dev_t pci_find_class(uint find_class, int index)
-{
- int bus;
- int devnum;
- pci_dev_t bdf;
- uint32_t class;
-
- for (bus = 0; bus <= pci_last_busno(); bus++) {
- for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) {
- pci_read_config_dword(PCI_BDF(bus, devnum, 0),
- PCI_CLASS_REVISION, &class);
- if (class >> 16 == 0xffff)
- continue;
-
- for (bdf = PCI_BDF(bus, devnum, 0);
- bdf <= PCI_BDF(bus, devnum,
- PCI_MAX_PCI_FUNCTIONS - 1);
- bdf += PCI_BDF(0, 0, 1)) {
- pci_read_config_dword(bdf, PCI_CLASS_REVISION,
- &class);
- class >>= 8;
-
- if (class != find_class)
- continue;
- /*
- * Decrement the index. We want to return the
- * correct device, so index is 0 for the first
- * matching device, 1 for the second, etc.
- */
- if (index) {
- index--;
- continue;
- }
- /* Return index'th controller. */
+ bdf = pci_hose_find_devices(hose, bus, ids, &index);
+ if (bdf != -1)
return bdf;
- }
}
}
- return -ENODEV;
-}
-
-pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
-{
- struct pci_device_id ids[2] = { {}, {0, 0} };
-
- ids[0].vendor = vendor;
- ids[0].device = device;
-
- return pci_find_devices(ids, index);
+ return -1;
}
/*
@@ -355,87 +252,6 @@ pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose,
return bus_addr;
}
-int __pci_hose_bus_to_phys(struct pci_controller *hose,
- pci_addr_t bus_addr,
- unsigned long flags,
- unsigned long skip_mask,
- phys_addr_t *pa)
-{
- struct pci_region *res;
- int i;
-
- for (i = 0; i < hose->region_count; i++) {
- res = &hose->regions[i];
-
- if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
- continue;
-
- if (res->flags & skip_mask)
- continue;
-
- if (bus_addr >= res->bus_start &&
- (bus_addr - res->bus_start) < res->size) {
- *pa = (bus_addr - res->bus_start + res->phys_start);
- return 0;
- }
- }
-
- return 1;
-}
-
-phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose,
- pci_addr_t bus_addr,
- unsigned long flags)
-{
- phys_addr_t phys_addr = 0;
- int ret;
-
- if (!hose) {
- puts("pci_hose_bus_to_phys: invalid hose\n");
- return phys_addr;
- }
-
- /*
- * if PCI_REGION_MEM is set we do a two pass search with preference
- * on matches that don't have PCI_REGION_SYS_MEMORY set
- */
- if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
- ret = __pci_hose_bus_to_phys(hose, bus_addr,
- flags, PCI_REGION_SYS_MEMORY, &phys_addr);
- if (!ret)
- return phys_addr;
- }
-
- ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
-
- if (ret)
- puts("pci_hose_bus_to_phys: invalid physical address\n");
-
- return phys_addr;
-}
-
-void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
- u32 addr_and_ctrl)
-{
- int bar;
-
- bar = PCI_BASE_ADDRESS_0 + barnum * 4;
- pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
-}
-
-u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
-{
- u32 addr;
- int bar;
-
- bar = PCI_BASE_ADDRESS_0 + barnum * 4;
- pci_hose_read_config_dword(hose, dev, bar, &addr);
- if (addr & PCI_BASE_ADDRESS_SPACE_IO)
- return addr & PCI_BASE_ADDRESS_IO_MASK;
- else
- return addr & PCI_BASE_ADDRESS_MEM_MASK;
-}
-
int pci_hose_config_device(struct pci_controller *hose,
pci_dev_t dev,
unsigned long io,
@@ -576,91 +392,6 @@ void pci_cfgfunc_do_nothing(struct pci_controller *hose,
*/
extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);
-#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI_SCAN_SHOW)
-const char * pci_class_str(u8 class)
-{
- switch (class) {
- case PCI_CLASS_NOT_DEFINED:
- return "Build before PCI Rev2.0";
- break;
- case PCI_BASE_CLASS_STORAGE:
- return "Mass storage controller";
- break;
- case PCI_BASE_CLASS_NETWORK:
- return "Network controller";
- break;
- case PCI_BASE_CLASS_DISPLAY:
- return "Display controller";
- break;
- case PCI_BASE_CLASS_MULTIMEDIA:
- return "Multimedia device";
- break;
- case PCI_BASE_CLASS_MEMORY:
- return "Memory controller";
- break;
- case PCI_BASE_CLASS_BRIDGE:
- return "Bridge device";
- break;
- case PCI_BASE_CLASS_COMMUNICATION:
- return "Simple comm. controller";
- break;
- case PCI_BASE_CLASS_SYSTEM:
- return "Base system peripheral";
- break;
- case PCI_BASE_CLASS_INPUT:
- return "Input device";
- break;
- case PCI_BASE_CLASS_DOCKING:
- return "Docking station";
- break;
- case PCI_BASE_CLASS_PROCESSOR:
- return "Processor";
- break;
- case PCI_BASE_CLASS_SERIAL:
- return "Serial bus controller";
- break;
- case PCI_BASE_CLASS_INTELLIGENT:
- return "Intelligent controller";
- break;
- case PCI_BASE_CLASS_SATELLITE:
- return "Satellite controller";
- break;
- case PCI_BASE_CLASS_CRYPT:
- return "Cryptographic device";
- break;
- case PCI_BASE_CLASS_SIGNAL_PROCESSING:
- return "DSP";
- break;
- case PCI_CLASS_OTHERS:
- return "Does not fit any class";
- break;
- default:
- return "???";
- break;
- };
-}
-#endif /* CONFIG_CMD_PCI || CONFIG_PCI_SCAN_SHOW */
-
-__weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
-{
- /*
- * Check if pci device should be skipped in configuration
- */
- if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
-#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
- /*
- * Only skip configuration if "pciconfighost" is not set
- */
- if (getenv("pciconfighost") == NULL)
- return 1;
-#else
- return 1;
-#endif
- }
-
- return 0;
-}
-
#ifdef CONFIG_PCI_SCAN_SHOW
__weak int pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
{
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index 378efbfd9f..e8da977673 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -432,13 +432,20 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
switch (class) {
case PCI_CLASS_BRIDGE_PCI:
- hose->current_busno++;
+ DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n",
+ PCI_DEV(dev));
+
pciauto_setup_device(hose, dev, 2, hose->pci_mem,
hose->pci_prefetch, hose->pci_io);
- DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev));
-
+#ifdef CONFIG_DM_PCI
+ n = dm_pci_hose_probe_bus(hose, dev);
+ if (n < 0)
+ return n;
+ sub_bus = (unsigned int)n;
+#else
/* Passing in current_busno allows for sibling P2P bridges */
+ hose->current_busno++;
pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
/*
* need to figure out if this is a subordinate bridge on the bus
@@ -451,6 +458,7 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
pciauto_postscan_setup_bridge(hose, dev, sub_bus);
sub_bus = hose->current_busno;
+#endif
break;
case PCI_CLASS_STORAGE_IDE:
@@ -475,7 +483,9 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n",
PCI_DEV(dev));
+#ifndef CONFIG_DM_PCI
hose->current_busno++;
+#endif
break;
#if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE)
diff --git a/drivers/pci/pci_common.c b/drivers/pci/pci_common.c
new file mode 100644
index 0000000000..24c66bbef2
--- /dev/null
+++ b/drivers/pci/pci_common.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <pci.h>
+#include <asm/io.h>
+
+const char *pci_class_str(u8 class)
+{
+ switch (class) {
+ case PCI_CLASS_NOT_DEFINED:
+ return "Build before PCI Rev2.0";
+ break;
+ case PCI_BASE_CLASS_STORAGE:
+ return "Mass storage controller";
+ break;
+ case PCI_BASE_CLASS_NETWORK:
+ return "Network controller";
+ break;
+ case PCI_BASE_CLASS_DISPLAY:
+ return "Display controller";
+ break;
+ case PCI_BASE_CLASS_MULTIMEDIA:
+ return "Multimedia device";
+ break;
+ case PCI_BASE_CLASS_MEMORY:
+ return "Memory controller";
+ break;
+ case PCI_BASE_CLASS_BRIDGE:
+ return "Bridge device";
+ break;
+ case PCI_BASE_CLASS_COMMUNICATION:
+ return "Simple comm. controller";
+ break;
+ case PCI_BASE_CLASS_SYSTEM:
+ return "Base system peripheral";
+ break;
+ case PCI_BASE_CLASS_INPUT:
+ return "Input device";
+ break;
+ case PCI_BASE_CLASS_DOCKING:
+ return "Docking station";
+ break;
+ case PCI_BASE_CLASS_PROCESSOR:
+ return "Processor";
+ break;
+ case PCI_BASE_CLASS_SERIAL:
+ return "Serial bus controller";
+ break;
+ case PCI_BASE_CLASS_INTELLIGENT:
+ return "Intelligent controller";
+ break;
+ case PCI_BASE_CLASS_SATELLITE:
+ return "Satellite controller";
+ break;
+ case PCI_BASE_CLASS_CRYPT:
+ return "Cryptographic device";
+ break;
+ case PCI_BASE_CLASS_SIGNAL_PROCESSING:
+ return "DSP";
+ break;
+ case PCI_CLASS_OTHERS:
+ return "Does not fit any class";
+ break;
+ default:
+ return "???";
+ break;
+ };
+}
+
+pci_dev_t pci_find_class(uint find_class, int index)
+{
+ int bus;
+ int devnum;
+ pci_dev_t bdf;
+ uint32_t class;
+
+ for (bus = 0; bus <= pci_last_busno(); bus++) {
+ for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) {
+ pci_read_config_dword(PCI_BDF(bus, devnum, 0),
+ PCI_CLASS_REVISION, &class);
+ if (class >> 16 == 0xffff)
+ continue;
+
+ for (bdf = PCI_BDF(bus, devnum, 0);
+ bdf <= PCI_BDF(bus, devnum,
+ PCI_MAX_PCI_FUNCTIONS - 1);
+ bdf += PCI_BDF(0, 0, 1)) {
+ pci_read_config_dword(bdf, PCI_CLASS_REVISION,
+ &class);
+ class >>= 8;
+
+ if (class != find_class)
+ continue;
+ /*
+ * Decrement the index. We want to return the
+ * correct device, so index is 0 for the first
+ * matching device, 1 for the second, etc.
+ */
+ if (index) {
+ index--;
+ continue;
+ }
+ /* Return index'th controller. */
+ return bdf;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+
+__weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ /*
+ * Check if pci device should be skipped in configuration
+ */
+ if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
+#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
+ /*
+ * Only skip configuration if "pciconfighost" is not set
+ */
+ if (getenv("pciconfighost") == NULL)
+ return 1;
+#else
+ return 1;
+#endif
+ }
+
+ return 0;
+}
+
+/* Get a virtual address associated with a BAR region */
+void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
+{
+ pci_addr_t pci_bus_addr;
+ u32 bar_response;
+
+ /* read BAR address */
+ pci_read_config_dword(pdev, bar, &bar_response);
+ pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
+
+ /*
+ * Pass "0" as the length argument to pci_bus_to_virt. The arg
+ * isn't actualy used on any platform because u-boot assumes a static
+ * linear mapping. In the future, this could read the BAR size
+ * and pass that as the size if needed.
+ */
+ return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+}
+
+void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
+ u32 addr_and_ctrl)
+{
+ int bar;
+
+ bar = PCI_BASE_ADDRESS_0 + barnum * 4;
+ pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
+}
+
+u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
+{
+ u32 addr;
+ int bar;
+
+ bar = PCI_BASE_ADDRESS_0 + barnum * 4;
+ pci_hose_read_config_dword(hose, dev, bar, &addr);
+ if (addr & PCI_BASE_ADDRESS_SPACE_IO)
+ return addr & PCI_BASE_ADDRESS_IO_MASK;
+ else
+ return addr & PCI_BASE_ADDRESS_MEM_MASK;
+}
+
+int __pci_hose_bus_to_phys(struct pci_controller *hose,
+ pci_addr_t bus_addr,
+ unsigned long flags,
+ unsigned long skip_mask,
+ phys_addr_t *pa)
+{
+ struct pci_region *res;
+ int i;
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ if (bus_addr >= res->bus_start &&
+ (bus_addr - res->bus_start) < res->size) {
+ *pa = (bus_addr - res->bus_start + res->phys_start);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+phys_addr_t pci_hose_bus_to_phys(struct pci_controller *hose,
+ pci_addr_t bus_addr,
+ unsigned long flags)
+{
+ phys_addr_t phys_addr = 0;
+ int ret;
+
+ if (!hose) {
+ puts("pci_hose_bus_to_phys: invalid hose\n");
+ return phys_addr;
+ }
+
+ /*
+ * if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set
+ */
+ if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
+ ret = __pci_hose_bus_to_phys(hose, bus_addr,
+ flags, PCI_REGION_SYS_MEMORY, &phys_addr);
+ if (!ret)
+ return phys_addr;
+ }
+
+ ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
+
+ if (ret)
+ puts("pci_hose_bus_to_phys: invalid physical address\n");
+
+ return phys_addr;
+}
+
+pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
+{
+ struct pci_device_id ids[2] = { {}, {0, 0} };
+
+ ids[0].vendor = vendor;
+ ids[0].device = device;
+
+ return pci_find_devices(ids, index);
+}
+
+pci_dev_t pci_hose_find_devices(struct pci_controller *hose, int busnum,
+ struct pci_device_id *ids, int *indexp)
+{
+ int found_multi = 0;
+ u16 vendor, device;
+ u8 header_type;
+ pci_dev_t bdf;
+ int i;
+
+ for (bdf = PCI_BDF(busnum, 0, 0);
+ bdf < PCI_BDF(busnum + 1, 0, 0);
+ bdf += PCI_BDF(0, 0, 1)) {
+ if (pci_skip_dev(hose, bdf))
+ continue;
+
+ if (!PCI_FUNC(bdf)) {
+ pci_read_config_byte(bdf, PCI_HEADER_TYPE,
+ &header_type);
+ found_multi = header_type & 0x80;
+ } else {
+ if (!found_multi)
+ continue;
+ }
+
+ pci_read_config_word(bdf, PCI_VENDOR_ID, &vendor);
+ pci_read_config_word(bdf, PCI_DEVICE_ID, &device);
+
+ for (i = 0; ids[i].vendor != 0; i++) {
+ if (vendor == ids[i].vendor &&
+ device == ids[i].device) {
+ if ((*indexp) <= 0)
+ return bdf;
+
+ (*indexp)--;
+ }
+ }
+ }
+
+ return -1;
+}
diff --git a/drivers/pci/pci_compat.c b/drivers/pci/pci_compat.c
new file mode 100644
index 0000000000..d6938c198f
--- /dev/null
+++ b/drivers/pci/pci_compat.c
@@ -0,0 +1,43 @@
+/*
+ * Compatibility functions for pre-driver-model code
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#define DEBUG
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <pci.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+#define PCI_HOSE_OP(rw, name, size, type) \
+int pci_hose_##rw##_config_##name(struct pci_controller *hose, \
+ pci_dev_t dev, \
+ int offset, type value) \
+{ \
+ return pci_##rw##_config##size(dev, offset, value); \
+}
+
+PCI_HOSE_OP(read, byte, 8, u8 *)
+PCI_HOSE_OP(read, word, 16, u16 *)
+PCI_HOSE_OP(read, dword, 32, u32 *)
+PCI_HOSE_OP(write, byte, 8, u8)
+PCI_HOSE_OP(write, word, 16, u16)
+PCI_HOSE_OP(write, dword, 32, u32)
+
+pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
+{
+ struct pci_child_platdata *pplat;
+ struct udevice *bus, *dev;
+
+ if (pci_find_device_id(ids, index, &dev))
+ return -1;
+ bus = dev->parent;
+ pplat = dev_get_parent_platdata(dev);
+
+ return PCI_ADD_BUS(bus->seq, pplat->devfn);
+}
diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c
new file mode 100644
index 0000000000..6de5130c2a
--- /dev/null
+++ b/drivers/pci/pci_sandbox.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <inttypes.h>
+#include <pci.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_pci_write_config(struct udevice *bus, pci_dev_t devfn,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct dm_pci_emul_ops *ops;
+ struct udevice *emul;
+ int ret;
+
+ ret = sandbox_pci_get_emul(bus, devfn, &emul);
+ if (ret)
+ return ret == -ENODEV ? 0 : ret;
+ ops = pci_get_emul_ops(emul);
+ if (!ops || !ops->write_config)
+ return -ENOSYS;
+
+ return ops->write_config(emul, offset, value, size);
+}
+
+static int sandbox_pci_read_config(struct udevice *bus, pci_dev_t devfn,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct dm_pci_emul_ops *ops;
+ struct udevice *emul;
+ int ret;
+
+ /* Prepare the default response */
+ *valuep = pci_get_ff(size);
+ ret = sandbox_pci_get_emul(bus, devfn, &emul);
+ if (ret)
+ return ret == -ENODEV ? 0 : ret;
+ ops = pci_get_emul_ops(emul);
+ if (!ops || !ops->read_config)
+ return -ENOSYS;
+
+ return ops->read_config(emul, offset, valuep, size);
+}
+
+static int sandbox_pci_child_post_bind(struct udevice *dev)
+{
+ /* Attach an emulator if we can */
+ return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+static const struct dm_pci_ops sandbox_pci_ops = {
+ .read_config = sandbox_pci_read_config,
+ .write_config = sandbox_pci_write_config,
+};
+
+static const struct udevice_id sandbox_pci_ids[] = {
+ { .compatible = "sandbox,pci" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_sandbox) = {
+ .name = "pci_sandbox",
+ .id = UCLASS_PCI,
+ .of_match = sandbox_pci_ids,
+ .ops = &sandbox_pci_ops,
+ .child_post_bind = sandbox_pci_child_post_bind,
+ .per_child_platdata_auto_alloc_size =
+ sizeof(struct pci_child_platdata),
+};
diff --git a/drivers/pci/pci_x86.c b/drivers/pci/pci_x86.c
new file mode 100644
index 0000000000..901bdcacce
--- /dev/null
+++ b/drivers/pci/pci_x86.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+
+static const struct dm_pci_ops x86_pci_ops = {
+};
+
+static const struct udevice_id x86_pci_ids[] = {
+ { .compatible = "x86,pci" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_x86) = {
+ .name = "pci_x86",
+ .id = UCLASS_PCI,
+ .of_match = x86_pci_ids,
+ .ops = &x86_pci_ops,
+};
diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c
index c91f084a7c..e0ab04abc2 100644
--- a/drivers/qe/uec.c
+++ b/drivers/qe/uec.c
@@ -1333,7 +1333,7 @@ static int uec_recv(struct eth_device* dev)
if (!(status & RxBD_ERROR)) {
data = BD_DATA(bd);
len = BD_LENGTH(bd);
- NetReceive(data, len);
+ net_process_received_packet(data, len);
} else {
printf("%s: Rx error\n", dev->name);
}
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 03beab5a14..67b1d60171 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -8,6 +8,7 @@
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
+#include <mapmem.h>
#include <ns16550.h>
#include <serial.h>
#include <watchdog.h>
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 2de3737739..b239691efe 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -251,7 +251,7 @@ static int serial_post_probe(struct udevice *dev)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
#ifdef CONFIG_DM_STDIO
- struct serial_dev_priv *upriv = dev->uclass_priv;
+ struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
struct stdio_dev sdev;
#endif
int ret;
@@ -299,7 +299,7 @@ static int serial_post_probe(struct udevice *dev)
static int serial_pre_remove(struct udevice *dev)
{
#ifdef CONFIG_SYS_STDIO_DEREGISTER
- struct serial_dev_priv *upriv = dev->uclass_priv;
+ struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
if (stdio_deregister_dev(upriv->sdev, 0))
return -EPERM;
diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c
index 98e3b812e0..74547eb692 100644
--- a/drivers/serial/serial_uniphier.c
+++ b/drivers/serial/serial_uniphier.c
@@ -11,6 +11,7 @@
#include <asm/errno.h>
#include <dm/device.h>
#include <dm/platform_data/serial-uniphier.h>
+#include <mapmem.h>
#include <serial.h>
#include <fdtdec.h>
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
index e69de29bb2..3b96e84480 100644
--- a/drivers/sound/Kconfig
+++ b/drivers/sound/Kconfig
@@ -0,0 +1,55 @@
+config SOUND
+ bool "Enable sound support"
+ help
+ Support making sounds through an audio codec. This is normally a
+ beep at a chosen frequency for a selected length of time. However
+ the drivers support playing arbitrary sound samples using a
+ PCM interface.
+
+ Note: At present the sound setup is somewhat tangled up in that the
+ audio codecs are called from the sound-i2s code. This could be
+ converted to driver model.
+
+config I2S
+ bool "Enable I2S support"
+ depends on SOUND
+ help
+ I2S is a serial bus often used to transmit audio data from the
+ SoC to the audio codec. This option enables sound support using
+ I2S. It calls either of the two supported codecs (no use is made
+ of driver model at present).
+
+config I2S_SAMSUNG
+ bool "Enable I2C support for Samsung SoCs"
+ depends on SOUND
+ help
+ Samsung Exynos SoCs support an I2S interface for sending audio
+ data to an audio codec. This option enables support for this,
+ using one of the available audio codec drivers. Enabling this
+ option provides an implementation for sound_init() and
+ sound_play().
+
+config SOUND_MAX98095
+ bool "Support Maxim max98095 audio codec"
+ depends on I2S_SAMSUNG
+ help
+ Enable the max98095 audio codec. This is connected via I2S for
+ audio data and I2C for codec control. At present it only works
+ with the Samsung I2S driver.
+
+config SOUND_SANDBOX
+ bool "Support sandbox emulated audio codec"
+ depends on SANDBOX && SOUND
+ help
+ U-Boot sandbox can emulate a sound device using SDL, playing the
+ sound on the host machine. This option implements the sound_init()
+ and sound_play() functions for sandbox. Note that you must install
+ the SDL libraries for this to work.
+
+config SOUND_WM8994
+ bool "Support Wolfson Micro wm8994 audio codec"
+ depends on I2S_SAMSUNG
+ help
+ Enable the wm8994 audio codec. This is connected via I2S for
+ audio data and I2C for codec control. At present it only works
+ with the Samsung I2S driver.
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7ae2727cf7..c4c112c5ae 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -10,3 +10,28 @@ config DM_SPI
as 'parent data' to every slave on each bus. Slaves
typically use driver-private data instead of extending the
spi_slave structure.
+
+config SANDBOX_SPI
+ bool "Sandbox SPI driver"
+ depends on SANDBOX && DM
+ help
+ Enable SPI support for sandbox. This is an emulation of a real SPI
+ bus. Devices can be attached to the bus using the device tree
+ which specifies the driver to use. As an example, see this device
+ tree fragment from sandbox.dts. It shows that the SPI bus has a
+ single flash device on chip select 0 which is emulated by the driver
+ for "sandbox,spi-flash", which is in drivers/mtd/spi/sandbox.c.
+
+ spi@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ compatible = "sandbox,spi";
+ cs-gpios = <0>, <&gpio_a 0>;
+ flash@0 {
+ reg = <0>;
+ compatible = "spansion,m25p16", "sandbox,spi-flash";
+ spi-max-frequency = <40000000>;
+ sandbox,filename = "spi.bin";
+ };
+ };
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index ce6f1cc74e..e288692f26 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -50,3 +50,4 @@ obj-$(CONFIG_TI_QSPI) += ti_qspi.o
obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
+obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c
new file mode 100644
index 0000000000..6476f913c8
--- /dev/null
+++ b/drivers/spi/fsl_dspi.c
@@ -0,0 +1,737 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2009, 2015 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ * Chao Fu (B44548@freescale.com)
+ * Haikun Wang (B53464@freescale.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <dm.h>
+#include <errno.h>
+#include <common.h>
+#include <spi.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <fdtdec.h>
+#ifndef CONFIG_M68K
+#include <asm/arch/clock.h>
+#endif
+#include <fsl_dspi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* fsl_dspi_platdata flags */
+#define DSPI_FLAG_REGMAP_ENDIAN_BIG (1 << 0)
+
+/* idle data value */
+#define DSPI_IDLE_VAL 0x0
+
+/* max chipselect signals number */
+#define FSL_DSPI_MAX_CHIPSELECT 6
+
+/* default SCK frequency, unit: HZ */
+#define FSL_DSPI_DEFAULT_SCK_FREQ 10000000
+
+/* tx/rx data wait timeout value, unit: us */
+#define DSPI_TXRX_WAIT_TIMEOUT 1000000
+
+/* CTAR register pre-configure value */
+#define DSPI_CTAR_DEFAULT_VALUE (DSPI_CTAR_TRSZ(7) | \
+ DSPI_CTAR_PCSSCK_1CLK | \
+ DSPI_CTAR_PASC(0) | \
+ DSPI_CTAR_PDT(0) | \
+ DSPI_CTAR_CSSCK(0) | \
+ DSPI_CTAR_ASC(0) | \
+ DSPI_CTAR_DT(0))
+
+/* CTAR register pre-configure mask */
+#define DSPI_CTAR_SET_MODE_MASK (DSPI_CTAR_TRSZ(15) | \
+ DSPI_CTAR_PCSSCK(3) | \
+ DSPI_CTAR_PASC(3) | \
+ DSPI_CTAR_PDT(3) | \
+ DSPI_CTAR_CSSCK(15) | \
+ DSPI_CTAR_ASC(15) | \
+ DSPI_CTAR_DT(15))
+
+/**
+ * struct fsl_dspi_platdata - platform data for Freescale DSPI
+ *
+ * @flags: Flags for DSPI DSPI_FLAG_...
+ * @speed_hz: Default SCK frequency
+ * @num_chipselect: Number of DSPI chipselect signals
+ * @regs_addr: Base address of DSPI registers
+ */
+struct fsl_dspi_platdata {
+ uint flags;
+ uint speed_hz;
+ uint num_chipselect;
+ fdt_addr_t regs_addr;
+};
+
+/**
+ * struct fsl_dspi_priv - private data for Freescale DSPI
+ *
+ * @flags: Flags for DSPI DSPI_FLAG_...
+ * @mode: SPI mode to use for slave device (see SPI mode flags)
+ * @mcr_val: MCR register configure value
+ * @bus_clk: DSPI input clk frequency
+ * @speed_hz: Default SCK frequency
+ * @charbit: How many bits in every transfer
+ * @num_chipselect: Number of DSPI chipselect signals
+ * @ctar_val: CTAR register configure value of per chipselect slave device
+ * @regs: Point to DSPI register structure for I/O access
+ */
+struct fsl_dspi_priv {
+ uint flags;
+ uint mode;
+ uint mcr_val;
+ uint bus_clk;
+ uint speed_hz;
+ uint charbit;
+ uint num_chipselect;
+ uint ctar_val[FSL_DSPI_MAX_CHIPSELECT];
+ struct dspi *regs;
+};
+
+#ifndef CONFIG_DM_SPI
+struct fsl_dspi {
+ struct spi_slave slave;
+ struct fsl_dspi_priv priv;
+};
+#endif
+
+__weak void cpu_dspi_port_conf(void)
+{
+}
+
+__weak int cpu_dspi_claim_bus(uint bus, uint cs)
+{
+ return 0;
+}
+
+__weak void cpu_dspi_release_bus(uint bus, uint cs)
+{
+}
+
+static uint dspi_read32(uint flags, uint *addr)
+{
+ return flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ?
+ in_be32(addr) : in_le32(addr);
+}
+
+static void dspi_write32(uint flags, uint *addr, uint val)
+{
+ flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ?
+ out_be32(addr, val) : out_le32(addr, val);
+}
+
+static void dspi_halt(struct fsl_dspi_priv *priv, u8 halt)
+{
+ uint mcr_val;
+
+ mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
+
+ if (halt)
+ mcr_val |= DSPI_MCR_HALT;
+ else
+ mcr_val &= ~DSPI_MCR_HALT;
+
+ dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+}
+
+static void fsl_dspi_init_mcr(struct fsl_dspi_priv *priv, uint cfg_val)
+{
+ /* halt DSPI module */
+ dspi_halt(priv, 1);
+
+ dspi_write32(priv->flags, &priv->regs->mcr, cfg_val);
+
+ /* resume module */
+ dspi_halt(priv, 0);
+
+ priv->mcr_val = cfg_val;
+}
+
+static void fsl_dspi_cfg_cs_active_state(struct fsl_dspi_priv *priv,
+ uint cs, uint state)
+{
+ uint mcr_val;
+
+ dspi_halt(priv, 1);
+
+ mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
+ if (state & SPI_CS_HIGH)
+ /* CSx inactive state is low */
+ mcr_val &= ~DSPI_MCR_PCSIS(cs);
+ else
+ /* CSx inactive state is high */
+ mcr_val |= DSPI_MCR_PCSIS(cs);
+ dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+
+ dspi_halt(priv, 0);
+}
+
+static int fsl_dspi_cfg_ctar_mode(struct fsl_dspi_priv *priv,
+ uint cs, uint mode)
+{
+ uint bus_setup;
+
+ bus_setup = dspi_read32(priv->flags, &priv->regs->ctar[0]);
+
+ bus_setup &= ~DSPI_CTAR_SET_MODE_MASK;
+ bus_setup |= priv->ctar_val[cs];
+ bus_setup &= ~(DSPI_CTAR_CPOL | DSPI_CTAR_CPHA | DSPI_CTAR_LSBFE);
+
+ if (mode & SPI_CPOL)
+ bus_setup |= DSPI_CTAR_CPOL;
+ if (mode & SPI_CPHA)
+ bus_setup |= DSPI_CTAR_CPHA;
+ if (mode & SPI_LSB_FIRST)
+ bus_setup |= DSPI_CTAR_LSBFE;
+
+ dspi_write32(priv->flags, &priv->regs->ctar[0], bus_setup);
+
+ priv->charbit =
+ ((dspi_read32(priv->flags, &priv->regs->ctar[0]) &
+ DSPI_CTAR_TRSZ(15)) == DSPI_CTAR_TRSZ(15)) ? 16 : 8;
+
+ return 0;
+}
+
+static void fsl_dspi_clr_fifo(struct fsl_dspi_priv *priv)
+{
+ uint mcr_val;
+
+ dspi_halt(priv, 1);
+ mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
+ /* flush RX and TX FIFO */
+ mcr_val |= (DSPI_MCR_CTXF | DSPI_MCR_CRXF);
+ dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+ dspi_halt(priv, 0);
+}
+
+static void dspi_tx(struct fsl_dspi_priv *priv, u32 ctrl, u16 data)
+{
+ int timeout = DSPI_TXRX_WAIT_TIMEOUT;
+
+ /* wait for empty entries in TXFIFO or timeout */
+ while (DSPI_SR_TXCTR(dspi_read32(priv->flags, &priv->regs->sr)) >= 4 &&
+ timeout--)
+ udelay(1);
+
+ if (timeout >= 0)
+ dspi_write32(priv->flags, &priv->regs->tfr, (ctrl | data));
+ else
+ debug("dspi_tx: waiting timeout!\n");
+}
+
+static u16 dspi_rx(struct fsl_dspi_priv *priv)
+{
+ int timeout = DSPI_TXRX_WAIT_TIMEOUT;
+
+ /* wait for valid entries in RXFIFO or timeout */
+ while (DSPI_SR_RXCTR(dspi_read32(priv->flags, &priv->regs->sr)) == 0 &&
+ timeout--)
+ udelay(1);
+
+ if (timeout >= 0)
+ return (u16)DSPI_RFR_RXDATA(
+ dspi_read32(priv->flags, &priv->regs->rfr));
+ else {
+ debug("dspi_rx: waiting timeout!\n");
+ return (u16)(~0);
+ }
+}
+
+static int dspi_xfer(struct fsl_dspi_priv *priv, uint cs, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ u16 *spi_rd16 = NULL, *spi_wr16 = NULL;
+ u8 *spi_rd = NULL, *spi_wr = NULL;
+ static u32 ctrl;
+ uint len = bitlen >> 3;
+
+ if (priv->charbit == 16) {
+ bitlen >>= 1;
+ spi_wr16 = (u16 *)dout;
+ spi_rd16 = (u16 *)din;
+ } else {
+ spi_wr = (u8 *)dout;
+ spi_rd = (u8 *)din;
+ }
+
+ if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN)
+ ctrl |= DSPI_TFR_CONT;
+
+ ctrl = ctrl & DSPI_TFR_CONT;
+ ctrl = ctrl | DSPI_TFR_CTAS(0) | DSPI_TFR_PCS(cs);
+
+ if (len > 1) {
+ int tmp_len = len - 1;
+ while (tmp_len--) {
+ if (dout != NULL) {
+ if (priv->charbit == 16)
+ dspi_tx(priv, ctrl, *spi_wr16++);
+ else
+ dspi_tx(priv, ctrl, *spi_wr++);
+ dspi_rx(priv);
+ }
+
+ if (din != NULL) {
+ dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
+ if (priv->charbit == 16)
+ *spi_rd16++ = dspi_rx(priv);
+ else
+ *spi_rd++ = dspi_rx(priv);
+ }
+ }
+
+ len = 1; /* remaining byte */
+ }
+
+ if ((flags & SPI_XFER_END) == SPI_XFER_END)
+ ctrl &= ~DSPI_TFR_CONT;
+
+ if (len) {
+ if (dout != NULL) {
+ if (priv->charbit == 16)
+ dspi_tx(priv, ctrl, *spi_wr16);
+ else
+ dspi_tx(priv, ctrl, *spi_wr);
+ dspi_rx(priv);
+ }
+
+ if (din != NULL) {
+ dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
+ if (priv->charbit == 16)
+ *spi_rd16 = dspi_rx(priv);
+ else
+ *spi_rd = dspi_rx(priv);
+ }
+ } else {
+ /* dummy read */
+ dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
+ dspi_rx(priv);
+ }
+
+ return 0;
+}
+
+/**
+ * Calculate the divide value between input clk frequency and expected SCK frequency
+ * Formula: SCK = (clkrate/pbr) x ((1+dbr)/br)
+ * Dbr: use default value 0
+ *
+ * @pbr: return Baud Rate Prescaler value
+ * @br: return Baud Rate Scaler value
+ * @speed_hz: expected SCK frequency
+ * @clkrate: input clk frequency
+ */
+static int fsl_dspi_hz_to_spi_baud(int *pbr, int *br,
+ int speed_hz, uint clkrate)
+{
+ /* Valid baud rate pre-scaler values */
+ int pbr_tbl[4] = {2, 3, 5, 7};
+ int brs[16] = {2, 4, 6, 8,
+ 16, 32, 64, 128,
+ 256, 512, 1024, 2048,
+ 4096, 8192, 16384, 32768};
+ int temp, i = 0, j = 0;
+
+ temp = clkrate / speed_hz;
+
+ for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++)
+ for (j = 0; j < ARRAY_SIZE(brs); j++) {
+ if (pbr_tbl[i] * brs[j] >= temp) {
+ *pbr = i;
+ *br = j;
+ return 0;
+ }
+ }
+
+ debug("Can not find valid baud rate,speed_hz is %d, ", speed_hz);
+ debug("clkrate is %d, we use the max prescaler value.\n", clkrate);
+
+ *pbr = ARRAY_SIZE(pbr_tbl) - 1;
+ *br = ARRAY_SIZE(brs) - 1;
+ return -EINVAL;
+}
+
+static int fsl_dspi_cfg_speed(struct fsl_dspi_priv *priv, uint speed)
+{
+ int ret;
+ uint bus_setup;
+ int best_i, best_j, bus_clk;
+
+ bus_clk = priv->bus_clk;
+
+ debug("DSPI set_speed: expected SCK speed %u, bus_clk %u.\n",
+ speed, bus_clk);
+
+ bus_setup = dspi_read32(priv->flags, &priv->regs->ctar[0]);
+ bus_setup &= ~(DSPI_CTAR_DBR | DSPI_CTAR_PBR(0x3) | DSPI_CTAR_BR(0xf));
+
+ ret = fsl_dspi_hz_to_spi_baud(&best_i, &best_j, speed, bus_clk);
+ if (ret) {
+ speed = priv->speed_hz;
+ debug("DSPI set_speed use default SCK rate %u.\n", speed);
+ fsl_dspi_hz_to_spi_baud(&best_i, &best_j, speed, bus_clk);
+ }
+
+ bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j));
+ dspi_write32(priv->flags, &priv->regs->ctar[0], bus_setup);
+
+ priv->speed_hz = speed;
+
+ return 0;
+}
+#ifndef CONFIG_DM_SPI
+void spi_init(void)
+{
+ /* Nothing to do */
+}
+
+void spi_init_f(void)
+{
+ /* Nothing to do */
+}
+
+void spi_init_r(void)
+{
+ /* Nothing to do */
+}
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
+ return 1;
+ else
+ return 0;
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct fsl_dspi *dspi;
+ uint mcr_cfg_val;
+
+ dspi = spi_alloc_slave(struct fsl_dspi, bus, cs);
+ if (!dspi)
+ return NULL;
+
+ cpu_dspi_port_conf();
+
+#ifdef CONFIG_SYS_FSL_DSPI_BE
+ dspi->priv.flags |= DSPI_FLAG_REGMAP_ENDIAN_BIG;
+#endif
+
+ dspi->priv.regs = (struct dspi *)MMAP_DSPI;
+
+#ifdef CONFIG_M68K
+ dspi->priv.bus_clk = gd->bus_clk;
+#else
+ dspi->priv.bus_clk = mxc_get_clock(MXC_DSPI_CLK);
+#endif
+ dspi->priv.speed_hz = FSL_DSPI_DEFAULT_SCK_FREQ;
+
+ /* default: all CS signals inactive state is high */
+ mcr_cfg_val = DSPI_MCR_MSTR | DSPI_MCR_PCSIS_MASK |
+ DSPI_MCR_CRXF | DSPI_MCR_CTXF;
+ fsl_dspi_init_mcr(&dspi->priv, mcr_cfg_val);
+
+ for (i = 0; i < FSL_DSPI_MAX_CHIPSELECT; i++)
+ dspi->priv.ctar_val[i] = DSPI_CTAR_DEFAULT_VALUE;
+
+#ifdef CONFIG_SYS_DSPI_CTAR0
+ if (FSL_DSPI_MAX_CHIPSELECT > 0)
+ dspi->priv.ctar_val[0] = CONFIG_SYS_DSPI_CTAR0;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR1
+ if (FSL_DSPI_MAX_CHIPSELECT > 1)
+ dspi->priv.ctar_val[1] = CONFIG_SYS_DSPI_CTAR1;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR2
+ if (FSL_DSPI_MAX_CHIPSELECT > 2)
+ dspi->priv.ctar_val[2] = CONFIG_SYS_DSPI_CTAR2;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR3
+ if (FSL_DSPI_MAX_CHIPSELECT > 3)
+ dspi->priv.ctar_val[3] = CONFIG_SYS_DSPI_CTAR3;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR4
+ if (FSL_DSPI_MAX_CHIPSELECT > 4)
+ dspi->priv.ctar_val[4] = CONFIG_SYS_DSPI_CTAR4;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR5
+ if (FSL_DSPI_MAX_CHIPSELECT > 5)
+ dspi->priv.ctar_val[5] = CONFIG_SYS_DSPI_CTAR5;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR6
+ if (FSL_DSPI_MAX_CHIPSELECT > 6)
+ dspi->priv.ctar_val[6] = CONFIG_SYS_DSPI_CTAR6;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR7
+ if (FSL_DSPI_MAX_CHIPSELECT > 7)
+ dspi->priv.ctar_val[7] = CONFIG_SYS_DSPI_CTAR7;
+#endif
+
+ fsl_dspi_cfg_speed(&dspi->priv, max_hz);
+
+ /* configure transfer mode */
+ fsl_dspi_cfg_ctar_mode(&dspi->priv, cs, mode);
+
+ /* configure active state of CSX */
+ fsl_dspi_cfg_cs_active_state(&dspi->priv, cs, mode);
+
+ return &dspi->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ uint sr_val;
+ struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
+
+ cpu_dspi_claim_bus(slave->bus, slave->cs);
+
+ fsl_dspi_clr_fifo(&dspi->priv);
+
+ /* check module TX and RX status */
+ sr_val = dspi_read32(dspi->priv.flags, &dspi->priv.regs->sr);
+ if ((sr_val & DSPI_SR_TXRXS) != DSPI_SR_TXRXS) {
+ debug("DSPI RX/TX not ready!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
+
+ dspi_halt(&dspi->priv, 1);
+ cpu_dspi_release_bus(slave->bus.slave->cs);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
+ return dspi_xfer(&dspi->priv, slave->cs, bitlen, dout, din, flags);
+}
+#else
+static int fsl_dspi_child_pre_probe(struct udevice *dev)
+{
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+ struct fsl_dspi_priv *priv = dev_get_priv(dev->parent);
+
+ if (slave_plat->cs >= priv->num_chipselect) {
+ debug("DSPI invalid chipselect number %d(max %d)!\n",
+ slave_plat->cs, priv->num_chipselect - 1);
+ return -EINVAL;
+ }
+
+ priv->ctar_val[slave_plat->cs] = DSPI_CTAR_DEFAULT_VALUE;
+
+ debug("DSPI pre_probe slave device on CS %u, max_hz %u, mode 0x%x.\n",
+ slave_plat->cs, slave_plat->max_hz, slave_plat->mode);
+
+ return 0;
+}
+
+static int fsl_dspi_probe(struct udevice *bus)
+{
+ struct fsl_dspi_platdata *plat = dev_get_platdata(bus);
+ struct fsl_dspi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_bus *dm_spi_bus;
+ uint mcr_cfg_val;
+
+ dm_spi_bus = bus->uclass_priv;
+
+ /* cpu speical pin muxing configure */
+ cpu_dspi_port_conf();
+
+ /* get input clk frequency */
+ priv->regs = (struct dspi *)plat->regs_addr;
+ priv->flags = plat->flags;
+#ifdef CONFIG_M68K
+ priv->bus_clk = gd->bus_clk;
+#else
+ priv->bus_clk = mxc_get_clock(MXC_DSPI_CLK);
+#endif
+ priv->num_chipselect = plat->num_chipselect;
+ priv->speed_hz = plat->speed_hz;
+ /* frame data length in bits, default 8bits */
+ priv->charbit = 8;
+
+ dm_spi_bus->max_hz = plat->speed_hz;
+
+ /* default: all CS signals inactive state is high */
+ mcr_cfg_val = DSPI_MCR_MSTR | DSPI_MCR_PCSIS_MASK |
+ DSPI_MCR_CRXF | DSPI_MCR_CTXF;
+ fsl_dspi_init_mcr(priv, mcr_cfg_val);
+
+ debug("%s probe done, bus-num %d.\n", bus->name, bus->seq);
+
+ return 0;
+}
+
+static int fsl_dspi_claim_bus(struct udevice *dev)
+{
+ uint sr_val;
+ struct fsl_dspi_priv *priv;
+ struct udevice *bus = dev->parent;
+ struct dm_spi_slave_platdata *slave_plat =
+ dev_get_parent_platdata(dev);
+
+ priv = dev_get_priv(bus);
+
+ /* processor special prepartion work */
+ cpu_dspi_claim_bus(bus->seq, slave_plat->cs);
+
+ /* configure transfer mode */
+ fsl_dspi_cfg_ctar_mode(priv, slave_plat->cs, priv->mode);
+
+ /* configure active state of CSX */
+ fsl_dspi_cfg_cs_active_state(priv, slave_plat->cs,
+ priv->mode);
+
+ fsl_dspi_clr_fifo(priv);
+
+ /* check module TX and RX status */
+ sr_val = dspi_read32(priv->flags, &priv->regs->sr);
+ if ((sr_val & DSPI_SR_TXRXS) != DSPI_SR_TXRXS) {
+ debug("DSPI RX/TX not ready!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int fsl_dspi_release_bus(struct udevice *dev)
+{
+ struct udevice *bus = dev->parent;
+ struct fsl_dspi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave_plat =
+ dev_get_parent_platdata(dev);
+
+ /* halt module */
+ dspi_halt(priv, 1);
+
+ /* processor special release work */
+ cpu_dspi_release_bus(bus->seq, slave_plat->cs);
+
+ return 0;
+}
+
+/**
+ * This function doesn't do anything except help with debugging
+ */
+static int fsl_dspi_bind(struct udevice *bus)
+{
+ debug("%s assigned req_seq %d.\n", bus->name, bus->req_seq);
+ return 0;
+}
+
+static int fsl_dspi_ofdata_to_platdata(struct udevice *bus)
+{
+ fdt_addr_t addr;
+ struct fsl_dspi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = bus->of_offset;
+
+ if (fdtdec_get_bool(blob, node, "big-endian"))
+ plat->flags |= DSPI_FLAG_REGMAP_ENDIAN_BIG;
+
+ plat->num_chipselect =
+ fdtdec_get_int(blob, node, "num-cs", FSL_DSPI_MAX_CHIPSELECT);
+
+ addr = fdtdec_get_addr(blob, node, "reg");
+ if (addr == FDT_ADDR_T_NONE) {
+ debug("DSPI: Can't get base address or size\n");
+ return -ENOMEM;
+ }
+ plat->regs_addr = addr;
+
+ plat->speed_hz = fdtdec_get_int(blob,
+ node, "spi-max-frequency", FSL_DSPI_DEFAULT_SCK_FREQ);
+
+ debug("DSPI: regs=0x%x, max-frequency=%d, endianess=%s, num-cs=%d\n",
+ plat->regs_addr, plat->speed_hz,
+ plat->flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le",
+ plat->num_chipselect);
+
+ return 0;
+}
+
+static int fsl_dspi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct fsl_dspi_priv *priv;
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+ struct udevice *bus;
+
+ bus = dev->parent;
+ priv = dev_get_priv(bus);
+
+ return dspi_xfer(priv, slave_plat->cs, bitlen, dout, din, flags);
+}
+
+static int fsl_dspi_set_speed(struct udevice *bus, uint speed)
+{
+ struct fsl_dspi_priv *priv = dev_get_priv(bus);
+
+ return fsl_dspi_cfg_speed(priv, speed);
+}
+
+static int fsl_dspi_set_mode(struct udevice *bus, uint mode)
+{
+ struct fsl_dspi_priv *priv = dev_get_priv(bus);
+
+ debug("DSPI set_mode: mode 0x%x.\n", mode);
+
+ /*
+ * We store some chipselect special configure value in priv->ctar_val,
+ * and we can't get the correct chipselect number here,
+ * so just store mode value.
+ * Do really configuration when claim_bus.
+ */
+ priv->mode = mode;
+
+ return 0;
+}
+
+static const struct dm_spi_ops fsl_dspi_ops = {
+ .claim_bus = fsl_dspi_claim_bus,
+ .release_bus = fsl_dspi_release_bus,
+ .xfer = fsl_dspi_xfer,
+ .set_speed = fsl_dspi_set_speed,
+ .set_mode = fsl_dspi_set_mode,
+};
+
+static const struct udevice_id fsl_dspi_ids[] = {
+ { .compatible = "fsl,vf610-dspi" },
+ { }
+};
+
+U_BOOT_DRIVER(fsl_dspi) = {
+ .name = "fsl_dspi",
+ .id = UCLASS_SPI,
+ .of_match = fsl_dspi_ids,
+ .ops = &fsl_dspi_ops,
+ .ofdata_to_platdata = fsl_dspi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct fsl_dspi_platdata),
+ .priv_auto_alloc_size = sizeof(struct fsl_dspi_priv),
+ .probe = fsl_dspi_probe,
+ .child_pre_probe = fsl_dspi_child_pre_probe,
+ .bind = fsl_dspi_bind,
+};
+#endif
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 5e0b069274..868df5f121 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ * Copyright 2013-2015 Freescale Semiconductor, Inc.
*
* Freescale Quad Serial Peripheral Interface (QSPI) driver
*
@@ -11,8 +11,12 @@
#include <spi.h>
#include <asm/io.h>
#include <linux/sizes.h>
+#include <dm.h>
+#include <errno.h>
#include "fsl_qspi.h"
+DECLARE_GLOBAL_DATA_PTR;
+
#define RX_BUFFER_SIZE 0x80
#ifdef CONFIG_MX6SX
#define TX_BUFFER_SIZE 0x200
@@ -63,35 +67,85 @@
#define QSPI_CMD_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define QSPI_CMD_SE_4B 0xdc /* Sector erase (usually 64KiB) */
-#ifdef CONFIG_SYS_FSL_QSPI_LE
-#define qspi_read32 in_le32
-#define qspi_write32 out_le32
-#elif defined(CONFIG_SYS_FSL_QSPI_BE)
-#define qspi_read32 in_be32
-#define qspi_write32 out_be32
-#endif
+/* fsl_qspi_platdata flags */
+#define QSPI_FLAG_REGMAP_ENDIAN_BIG (1 << 0)
-static unsigned long spi_bases[] = {
- QSPI0_BASE_ADDR,
-#ifdef CONFIG_MX6SX
- QSPI1_BASE_ADDR,
-#endif
-};
+/* default SCK frequency, unit: HZ */
+#define FSL_QSPI_DEFAULT_SCK_FREQ 50000000
-static unsigned long amba_bases[] = {
- QSPI0_AMBA_BASE,
-#ifdef CONFIG_MX6SX
- QSPI1_AMBA_BASE,
+/* QSPI max chipselect signals number */
+#define FSL_QSPI_MAX_CHIPSELECT_NUM 4
+
+#ifdef CONFIG_DM_SPI
+/**
+ * struct fsl_qspi_platdata - platform data for Freescale QSPI
+ *
+ * @flags: Flags for QSPI QSPI_FLAG_...
+ * @speed_hz: Default SCK frequency
+ * @reg_base: Base address of QSPI registers
+ * @amba_base: Base address of QSPI memory mapping
+ * @amba_total_size: size of QSPI memory mapping
+ * @flash_num: Number of active slave devices
+ * @num_chipselect: Number of QSPI chipselect signals
+ */
+struct fsl_qspi_platdata {
+ u32 flags;
+ u32 speed_hz;
+ u32 reg_base;
+ u32 amba_base;
+ u32 amba_total_size;
+ u32 flash_num;
+ u32 num_chipselect;
+};
#endif
+
+/**
+ * struct fsl_qspi_priv - private data for Freescale QSPI
+ *
+ * @flags: Flags for QSPI QSPI_FLAG_...
+ * @bus_clk: QSPI input clk frequency
+ * @speed_hz: Default SCK frequency
+ * @cur_seqid: current LUT table sequence id
+ * @sf_addr: flash access offset
+ * @amba_base: Base address of QSPI memory mapping of every CS
+ * @amba_total_size: size of QSPI memory mapping
+ * @cur_amba_base: Base address of QSPI memory mapping of current CS
+ * @flash_num: Number of active slave devices
+ * @num_chipselect: Number of QSPI chipselect signals
+ * @regs: Point to QSPI register structure for I/O access
+ */
+struct fsl_qspi_priv {
+ u32 flags;
+ u32 bus_clk;
+ u32 speed_hz;
+ u32 cur_seqid;
+ u32 sf_addr;
+ u32 amba_base[FSL_QSPI_MAX_CHIPSELECT_NUM];
+ u32 amba_total_size;
+ u32 cur_amba_base;
+ u32 flash_num;
+ u32 num_chipselect;
+ struct fsl_qspi_regs *regs;
};
+#ifndef CONFIG_DM_SPI
struct fsl_qspi {
struct spi_slave slave;
- unsigned long reg_base;
- unsigned long amba_base;
- u32 sf_addr;
- u8 cur_seqid;
+ struct fsl_qspi_priv priv;
};
+#endif
+
+static u32 qspi_read32(u32 flags, u32 *addr)
+{
+ return flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
+ in_be32(addr) : in_le32(addr);
+}
+
+static void qspi_write32(u32 flags, u32 *addr, u32 val)
+{
+ flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
+ out_be32(addr, val) : out_le32(addr, val);
+}
/* QSPI support swapping the flash read/write data
* in hardware for LS102xA, but not for VF610 */
@@ -104,131 +158,135 @@ static inline u32 qspi_endian_xchg(u32 data)
#endif
}
-static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct fsl_qspi, slave);
-}
-
-static void qspi_set_lut(struct fsl_qspi *qspi)
+static void qspi_set_lut(struct fsl_qspi_priv *priv)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 lut_base;
/* Unlock the LUT */
- qspi_write32(&regs->lutkey, LUT_KEY_VALUE);
- qspi_write32(&regs->lckcr, QSPI_LCKCR_UNLOCK);
+ qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
+ qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_UNLOCK);
/* Write Enable */
lut_base = SEQID_WREN * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_WREN) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREN) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Fast Read */
lut_base = SEQID_FAST_READ * 4;
#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_FAST_READ) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_FAST_READ) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base],
+ qspi_write32(priv->flags, &regs->lut[lut_base],
OPRND0(QSPI_CMD_FAST_READ_4B) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) |
OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) |
INSTR1(LUT_ADDR));
#endif
- qspi_write32(&regs->lut[lut_base + 1], OPRND0(8) | PAD0(LUT_PAD1) |
- INSTR0(LUT_DUMMY) | OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) |
- INSTR1(LUT_READ));
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1],
+ OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) |
+ OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) |
+ INSTR1(LUT_READ));
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Read Status */
lut_base = SEQID_RDSR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDSR) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDSR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Erase a sector */
lut_base = SEQID_SE * 4;
#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_SE) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE_4B) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_SE_4B) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#endif
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Erase the whole chip */
lut_base = SEQID_CHIP_ERASE * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_CHIP_ERASE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_CHIP_ERASE) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Page Program */
lut_base = SEQID_PP * 4;
#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_PP) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP_4B) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_PP_4B) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#endif
#ifdef CONFIG_MX6SX
/*
* To MX6SX, OPRND0(TX_BUFFER_SIZE) can not work correctly.
* So, Use IDATSZ in IPCR to determine the size and here set 0.
*/
- qspi_write32(&regs->lut[lut_base + 1], OPRND0(0) |
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], OPRND0(0) |
PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
#else
- qspi_write32(&regs->lut[lut_base + 1], OPRND0(TX_BUFFER_SIZE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1],
+ OPRND0(TX_BUFFER_SIZE) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
#endif
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* READ ID */
lut_base = SEQID_RDID * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDID) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDID) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* SUB SECTOR 4K ERASE */
lut_base = SEQID_BE_4K * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
@@ -239,28 +297,28 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
* initialization.
*/
lut_base = SEQID_BRRD * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BRRD) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BRRD) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
lut_base = SEQID_BRWR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BRWR) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BRWR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
lut_base = SEQID_RDEAR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
lut_base = SEQID_WREAR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_WREAR) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREAR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
#endif
/* Lock the LUT */
- qspi_write32(&regs->lutkey, LUT_KEY_VALUE);
- qspi_write32(&regs->lckcr, QSPI_LCKCR_LOCK);
+ qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
+ qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_LOCK);
}
#if defined(CONFIG_SYS_FSL_QSPI_AHB)
@@ -270,14 +328,14 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
* the wrong data. The spec tells us reset the AHB domain and Serial Flash
* domain at the same time.
*/
-static inline void qspi_ahb_invalid(struct fsl_qspi *q)
+static inline void qspi_ahb_invalid(struct fsl_qspi_priv *priv)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 reg;
- reg = qspi_read32(&regs->mcr);
+ reg = qspi_read32(priv->flags, &regs->mcr);
reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
- qspi_write32(&regs->mcr, reg);
+ qspi_write32(priv->flags, &regs->mcr, reg);
/*
* The minimum delay : 1 AHB + 2 SFCK clocks.
@@ -286,46 +344,48 @@ static inline void qspi_ahb_invalid(struct fsl_qspi *q)
udelay(1);
reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
- qspi_write32(&regs->mcr, reg);
+ qspi_write32(priv->flags, &regs->mcr, reg);
}
/* Read out the data from the AHB buffer. */
-static inline void qspi_ahb_read(struct fsl_qspi *q, u8 *rxbuf, int len)
+static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg;
- mcr_reg = qspi_read32(&regs->mcr);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
/* Read out the data directly from the AHB buffer. */
- memcpy(rxbuf, (u8 *)(q->amba_base + q->sf_addr), len);
+ memcpy(rxbuf, (u8 *)(priv->cur_amba_base + priv->sf_addr), len);
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs)
+static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv)
{
u32 reg, reg2;
+ struct fsl_qspi_regs *regs = priv->regs;
- reg = qspi_read32(&regs->mcr);
+ reg = qspi_read32(priv->flags, &regs->mcr);
/* Disable the module */
- qspi_write32(&regs->mcr, reg | QSPI_MCR_MDIS_MASK);
+ qspi_write32(priv->flags, &regs->mcr, reg | QSPI_MCR_MDIS_MASK);
/* Set the Sampling Register for DDR */
- reg2 = qspi_read32(&regs->smpr);
+ reg2 = qspi_read32(priv->flags, &regs->smpr);
reg2 &= ~QSPI_SMPR_DDRSMP_MASK;
reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT);
- qspi_write32(&regs->smpr, reg2);
+ qspi_write32(priv->flags, &regs->smpr, reg2);
/* Enable the module again (enable the DDR too) */
reg |= QSPI_MCR_DDR_EN_MASK;
/* Enable bit 29 for imx6sx */
reg |= (1 << 29);
- qspi_write32(&regs->mcr, reg);
+ qspi_write32(priv->flags, &regs->mcr, reg);
}
/*
@@ -341,180 +401,103 @@ static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs)
* causes the controller to clear the buffer, and use the sequence pointed
* by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
*/
-static void qspi_init_ahb_read(struct fsl_qspi_regs *regs)
+static void qspi_init_ahb_read(struct fsl_qspi_priv *priv)
{
+ struct fsl_qspi_regs *regs = priv->regs;
+
/* AHB configuration for access buffer 0/1/2 .*/
- qspi_write32(&regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(&regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(&regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(&regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
+ qspi_write32(priv->flags, &regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(priv->flags, &regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(priv->flags, &regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(priv->flags, &regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
(0x80 << QSPI_BUF3CR_ADATSZ_SHIFT));
/* We only use the buffer3 */
- qspi_write32(&regs->buf0ind, 0);
- qspi_write32(&regs->buf1ind, 0);
- qspi_write32(&regs->buf2ind, 0);
+ qspi_write32(priv->flags, &regs->buf0ind, 0);
+ qspi_write32(priv->flags, &regs->buf1ind, 0);
+ qspi_write32(priv->flags, &regs->buf2ind, 0);
/*
* Set the default lut sequence for AHB Read.
* Parallel mode is disabled.
*/
- qspi_write32(&regs->bfgencr,
+ qspi_write32(priv->flags, &regs->bfgencr,
SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT);
/*Enable DDR Mode*/
- qspi_enable_ddr_mode(regs);
+ qspi_enable_ddr_mode(priv);
}
#endif
-void spi_init()
-{
- /* do nothing */
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct fsl_qspi *qspi;
- struct fsl_qspi_regs *regs;
- u32 smpr_val;
- u32 total_size;
-
- if (bus >= ARRAY_SIZE(spi_bases))
- return NULL;
-
- if (cs >= FSL_QSPI_FLASH_NUM)
- return NULL;
-
- qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
- if (!qspi)
- return NULL;
-
- qspi->reg_base = spi_bases[bus];
- /*
- * According cs, use different amba_base to choose the
- * corresponding flash devices.
- *
- * If not, only one flash device is used even if passing
- * different cs using `sf probe`
- */
- qspi->amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE;
-
- qspi->slave.max_write_size = TX_BUFFER_SIZE;
-
- regs = (struct fsl_qspi_regs *)qspi->reg_base;
- qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
-
- smpr_val = qspi_read32(&regs->smpr);
- qspi_write32(&regs->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK |
- QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK));
- qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
-
- total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
- /*
- * Any read access to non-implemented addresses will provide
- * undefined results.
- *
- * In case single die flash devices, TOP_ADDR_MEMA2 and
- * TOP_ADDR_MEMB2 should be initialized/programmed to
- * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
- * setting the size of these devices to 0. This would ensure
- * that the complete memory map is assigned to only one flash device.
- */
- qspi_write32(&regs->sfa1ad, FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
- qspi_write32(&regs->sfa2ad, FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
- qspi_write32(&regs->sfb1ad, total_size | amba_bases[bus]);
- qspi_write32(&regs->sfb2ad, total_size | amba_bases[bus]);
-
- qspi_set_lut(qspi);
-
- smpr_val = qspi_read32(&regs->smpr);
- smpr_val &= ~QSPI_SMPR_DDRSMP_MASK;
- qspi_write32(&regs->smpr, smpr_val);
- qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
-
-#ifdef CONFIG_SYS_FSL_QSPI_AHB
- qspi_init_ahb_read(regs);
-#endif
- return &qspi->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct fsl_qspi *qspi = to_qspi_spi(slave);
-
- free(qspi);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- return 0;
-}
-
#ifdef CONFIG_SPI_FLASH_BAR
/* Bank register read/write, EAR register read/write */
-static void qspi_op_rdbank(struct fsl_qspi *qspi, u8 *rxbuf, u32 len)
+static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 reg, mcr_reg, data, seqid;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- qspi_write32(&regs->sfar, qspi->amba_base);
+ qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
- if (qspi->cur_seqid == QSPI_CMD_BRRD)
+ if (priv->cur_seqid == QSPI_CMD_BRRD)
seqid = SEQID_BRRD;
else
seqid = SEQID_RDEAR;
- qspi_write32(&regs->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
+ qspi_write32(priv->flags, &regs->ipcr,
+ (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
/* Wait previous command complete */
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
while (1) {
- reg = qspi_read32(&regs->rbsr);
+ reg = qspi_read32(priv->flags, &regs->rbsr);
if (reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(&regs->rbdr[0]);
+ data = qspi_read32(priv->flags, &regs->rbdr[0]);
data = qspi_endian_xchg(data);
memcpy(rxbuf, &data, len);
- qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
+ qspi_write32(priv->flags, &regs->mcr,
+ qspi_read32(priv->flags, &regs->mcr) |
QSPI_MCR_CLR_RXF_MASK);
break;
}
}
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
#endif
-static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
+static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg, rbsr_reg, data;
int i, size;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- qspi_write32(&regs->sfar, qspi->amba_base);
+ qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
- qspi_write32(&regs->ipcr, (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
i = 0;
size = len;
while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
- rbsr_reg = qspi_read32(&regs->rbsr);
+ rbsr_reg = qspi_read32(priv->flags, &regs->rbsr);
if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(&regs->rbdr[i]);
+ data = qspi_read32(priv->flags, &regs->rbdr[i]);
data = qspi_endian_xchg(data);
memcpy(rxbuf, &data, 4);
rxbuf++;
@@ -523,34 +506,36 @@ static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
}
}
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
#ifndef CONFIG_SYS_FSL_QSPI_AHB
/* If not use AHB read, read data from ip interface */
-static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
+static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg, data;
int i, size;
u32 to_or_from;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- to_or_from = qspi->sf_addr + qspi->amba_base;
+ to_or_from = priv->sf_addr + priv->cur_amba_base;
while (len > 0) {
- qspi_write32(&regs->sfar, to_or_from);
+ qspi_write32(priv->flags, &regs->sfar, to_or_from);
size = (len > RX_BUFFER_SIZE) ?
RX_BUFFER_SIZE : len;
- qspi_write32(&regs->ipcr,
- (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | size);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) |
+ size);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
to_or_from += size;
@@ -558,66 +543,69 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
i = 0;
while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
- data = qspi_read32(&regs->rbdr[i]);
+ data = qspi_read32(priv->flags, &regs->rbdr[i]);
data = qspi_endian_xchg(data);
memcpy(rxbuf, &data, 4);
rxbuf++;
size -= 4;
i++;
}
- qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
+ qspi_write32(priv->flags, &regs->mcr,
+ qspi_read32(priv->flags, &regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
}
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
#endif
-static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
+static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg, data, reg, status_reg, seqid;
int i, size, tx_size;
u32 to_or_from = 0;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
status_reg = 0;
while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) {
- qspi_write32(&regs->ipcr,
- (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- qspi_write32(&regs->ipcr,
- (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- reg = qspi_read32(&regs->rbsr);
+ reg = qspi_read32(priv->flags, &regs->rbsr);
if (reg & QSPI_RBSR_RDBFL_MASK) {
- status_reg = qspi_read32(&regs->rbdr[0]);
+ status_reg = qspi_read32(priv->flags, &regs->rbdr[0]);
status_reg = qspi_endian_xchg(status_reg);
}
- qspi_write32(&regs->mcr,
- qspi_read32(&regs->mcr) | QSPI_MCR_CLR_RXF_MASK);
+ qspi_write32(priv->flags, &regs->mcr,
+ qspi_read32(priv->flags, &regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
}
/* Default is page programming */
seqid = SEQID_PP;
#ifdef CONFIG_SPI_FLASH_BAR
- if (qspi->cur_seqid == QSPI_CMD_BRWR)
+ if (priv->cur_seqid == QSPI_CMD_BRWR)
seqid = SEQID_BRWR;
- else if (qspi->cur_seqid == QSPI_CMD_WREAR)
+ else if (priv->cur_seqid == QSPI_CMD_WREAR)
seqid = SEQID_WREAR;
#endif
- to_or_from = qspi->sf_addr + qspi->amba_base;
+ to_or_from = priv->sf_addr + priv->cur_amba_base;
- qspi_write32(&regs->sfar, to_or_from);
+ qspi_write32(priv->flags, &regs->sfar, to_or_from);
tx_size = (len > TX_BUFFER_SIZE) ?
TX_BUFFER_SIZE : len;
@@ -626,7 +614,7 @@ static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
for (i = 0; i < size; i++) {
memcpy(&data, txbuf, 4);
data = qspi_endian_xchg(data);
- qspi_write32(&regs->tbdr, data);
+ qspi_write32(priv->flags, &regs->tbdr, data);
txbuf += 4;
}
@@ -635,146 +623,273 @@ static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
data = 0;
memcpy(&data, txbuf, size);
data = qspi_endian_xchg(data);
- qspi_write32(&regs->tbdr, data);
+ qspi_write32(priv->flags, &regs->tbdr, data);
}
- qspi_write32(&regs->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf)
+static void qspi_op_rdsr(struct fsl_qspi_priv *priv, u32 *rxbuf)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg, reg, data;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- qspi_write32(&regs->sfar, qspi->amba_base);
+ qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
- qspi_write32(&regs->ipcr,
- (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
while (1) {
- reg = qspi_read32(&regs->rbsr);
+ reg = qspi_read32(priv->flags, &regs->rbsr);
if (reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(&regs->rbdr[0]);
+ data = qspi_read32(priv->flags, &regs->rbdr[0]);
data = qspi_endian_xchg(data);
memcpy(rxbuf, &data, 4);
- qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
+ qspi_write32(priv->flags, &regs->mcr,
+ qspi_read32(priv->flags, &regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
break;
}
}
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-static void qspi_op_erase(struct fsl_qspi *qspi)
+static void qspi_op_erase(struct fsl_qspi_priv *priv)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg;
u32 to_or_from = 0;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- to_or_from = qspi->sf_addr + qspi->amba_base;
- qspi_write32(&regs->sfar, to_or_from);
+ to_or_from = priv->sf_addr + priv->cur_amba_base;
+ qspi_write32(priv->flags, &regs->sfar, to_or_from);
- qspi_write32(&regs->ipcr,
- (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- if (qspi->cur_seqid == QSPI_CMD_SE) {
- qspi_write32(&regs->ipcr,
+ if (priv->cur_seqid == QSPI_CMD_SE) {
+ qspi_write32(priv->flags, &regs->ipcr,
(SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0);
- } else if (qspi->cur_seqid == QSPI_CMD_BE_4K) {
- qspi_write32(&regs->ipcr,
+ } else if (priv->cur_seqid == QSPI_CMD_BE_4K) {
+ qspi_write32(priv->flags, &regs->ipcr,
(SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0);
}
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
- struct fsl_qspi *qspi = to_qspi_spi(slave);
u32 bytes = DIV_ROUND_UP(bitlen, 8);
static u32 wr_sfaddr;
u32 txbuf;
if (dout) {
if (flags & SPI_XFER_BEGIN) {
- qspi->cur_seqid = *(u8 *)dout;
+ priv->cur_seqid = *(u8 *)dout;
memcpy(&txbuf, dout, 4);
}
if (flags == SPI_XFER_END) {
- qspi->sf_addr = wr_sfaddr;
- qspi_op_write(qspi, (u8 *)dout, bytes);
+ priv->sf_addr = wr_sfaddr;
+ qspi_op_write(priv, (u8 *)dout, bytes);
return 0;
}
- if (qspi->cur_seqid == QSPI_CMD_FAST_READ) {
- qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
- } else if ((qspi->cur_seqid == QSPI_CMD_SE) ||
- (qspi->cur_seqid == QSPI_CMD_BE_4K)) {
- qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
- qspi_op_erase(qspi);
- } else if (qspi->cur_seqid == QSPI_CMD_PP)
+ if (priv->cur_seqid == QSPI_CMD_FAST_READ) {
+ priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+ } else if ((priv->cur_seqid == QSPI_CMD_SE) ||
+ (priv->cur_seqid == QSPI_CMD_BE_4K)) {
+ priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+ qspi_op_erase(priv);
+ } else if (priv->cur_seqid == QSPI_CMD_PP) {
wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
+ } else if ((priv->cur_seqid == QSPI_CMD_BRWR) ||
+ (priv->cur_seqid == QSPI_CMD_WREAR)) {
#ifdef CONFIG_SPI_FLASH_BAR
- else if ((qspi->cur_seqid == QSPI_CMD_BRWR) ||
- (qspi->cur_seqid == QSPI_CMD_WREAR)) {
wr_sfaddr = 0;
- }
#endif
+ }
}
if (din) {
- if (qspi->cur_seqid == QSPI_CMD_FAST_READ) {
+ if (priv->cur_seqid == QSPI_CMD_FAST_READ) {
#ifdef CONFIG_SYS_FSL_QSPI_AHB
- qspi_ahb_read(qspi, din, bytes);
+ qspi_ahb_read(priv, din, bytes);
#else
- qspi_op_read(qspi, din, bytes);
+ qspi_op_read(priv, din, bytes);
#endif
- }
- else if (qspi->cur_seqid == QSPI_CMD_RDID)
- qspi_op_rdid(qspi, din, bytes);
- else if (qspi->cur_seqid == QSPI_CMD_RDSR)
- qspi_op_rdsr(qspi, din);
+ } else if (priv->cur_seqid == QSPI_CMD_RDID)
+ qspi_op_rdid(priv, din, bytes);
+ else if (priv->cur_seqid == QSPI_CMD_RDSR)
+ qspi_op_rdsr(priv, din);
#ifdef CONFIG_SPI_FLASH_BAR
- else if ((qspi->cur_seqid == QSPI_CMD_BRRD) ||
- (qspi->cur_seqid == QSPI_CMD_RDEAR)) {
- qspi->sf_addr = 0;
- qspi_op_rdbank(qspi, din, bytes);
+ else if ((priv->cur_seqid == QSPI_CMD_BRRD) ||
+ (priv->cur_seqid == QSPI_CMD_RDEAR)) {
+ priv->sf_addr = 0;
+ qspi_op_rdbank(priv, din, bytes);
}
#endif
}
#ifdef CONFIG_SYS_FSL_QSPI_AHB
- if ((qspi->cur_seqid == QSPI_CMD_SE) ||
- (qspi->cur_seqid == QSPI_CMD_PP) ||
- (qspi->cur_seqid == QSPI_CMD_BE_4K) ||
- (qspi->cur_seqid == QSPI_CMD_WREAR) ||
- (qspi->cur_seqid == QSPI_CMD_BRWR))
- qspi_ahb_invalid(qspi);
+ if ((priv->cur_seqid == QSPI_CMD_SE) ||
+ (priv->cur_seqid == QSPI_CMD_PP) ||
+ (priv->cur_seqid == QSPI_CMD_BE_4K) ||
+ (priv->cur_seqid == QSPI_CMD_WREAR) ||
+ (priv->cur_seqid == QSPI_CMD_BRWR))
+ qspi_ahb_invalid(priv);
+#endif
+
+ return 0;
+}
+
+void qspi_module_disable(struct fsl_qspi_priv *priv, u8 disable)
+{
+ u32 mcr_val;
+
+ mcr_val = qspi_read32(priv->flags, &priv->regs->mcr);
+ if (disable)
+ mcr_val |= QSPI_MCR_MDIS_MASK;
+ else
+ mcr_val &= ~QSPI_MCR_MDIS_MASK;
+ qspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+}
+
+void qspi_cfg_smpr(struct fsl_qspi_priv *priv, u32 clear_bits, u32 set_bits)
+{
+ u32 smpr_val;
+
+ smpr_val = qspi_read32(priv->flags, &priv->regs->smpr);
+ smpr_val &= ~clear_bits;
+ smpr_val |= set_bits;
+ qspi_write32(priv->flags, &priv->regs->smpr, smpr_val);
+}
+#ifndef CONFIG_DM_SPI
+static unsigned long spi_bases[] = {
+ QSPI0_BASE_ADDR,
+#ifdef CONFIG_MX6SX
+ QSPI1_BASE_ADDR,
+#endif
+};
+
+static unsigned long amba_bases[] = {
+ QSPI0_AMBA_BASE,
+#ifdef CONFIG_MX6SX
+ QSPI1_AMBA_BASE,
+#endif
+};
+
+static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
+{
+ return container_of(slave, struct fsl_qspi, slave);
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct fsl_qspi *qspi;
+ struct fsl_qspi_regs *regs;
+ u32 total_size;
+
+ if (bus >= ARRAY_SIZE(spi_bases))
+ return NULL;
+
+ if (cs >= FSL_QSPI_FLASH_NUM)
+ return NULL;
+
+ qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
+ if (!qspi)
+ return NULL;
+
+#ifdef CONFIG_SYS_FSL_QSPI_BE
+ qspi->priv.flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG;
+#endif
+
+ regs = (struct fsl_qspi_regs *)spi_bases[bus];
+ qspi->priv.regs = regs;
+ /*
+ * According cs, use different amba_base to choose the
+ * corresponding flash devices.
+ *
+ * If not, only one flash device is used even if passing
+ * different cs using `sf probe`
+ */
+ qspi->priv.cur_amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE;
+
+ qspi->slave.max_write_size = TX_BUFFER_SIZE;
+
+ qspi_write32(qspi->priv.flags, &regs->mcr,
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+
+ qspi_cfg_smpr(&qspi->priv,
+ ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
+ QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
+
+ total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
+ /*
+ * Any read access to non-implemented addresses will provide
+ * undefined results.
+ *
+ * In case single die flash devices, TOP_ADDR_MEMA2 and
+ * TOP_ADDR_MEMB2 should be initialized/programmed to
+ * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
+ * setting the size of these devices to 0. This would ensure
+ * that the complete memory map is assigned to only one flash device.
+ */
+ qspi_write32(qspi->priv.flags, &regs->sfa1ad,
+ FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
+ qspi_write32(qspi->priv.flags, &regs->sfa2ad,
+ FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
+ qspi_write32(qspi->priv.flags, &regs->sfb1ad,
+ total_size | amba_bases[bus]);
+ qspi_write32(qspi->priv.flags, &regs->sfb2ad,
+ total_size | amba_bases[bus]);
+
+ qspi_set_lut(&qspi->priv);
+
+#ifdef CONFIG_SYS_FSL_QSPI_AHB
+ qspi_init_ahb_read(&qspi->priv);
#endif
+ qspi_module_disable(&qspi->priv, 0);
+
+ return &qspi->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct fsl_qspi *qspi = to_qspi_spi(slave);
+
+ free(qspi);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
return 0;
}
@@ -782,3 +897,215 @@ void spi_release_bus(struct spi_slave *slave)
{
/* Nothing to do */
}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct fsl_qspi *qspi = to_qspi_spi(slave);
+
+ return qspi_xfer(&qspi->priv, bitlen, dout, din, flags);
+}
+
+void spi_init(void)
+{
+ /* Nothing to do */
+}
+#else
+static int fsl_qspi_child_pre_probe(struct udevice *dev)
+{
+ struct spi_slave *slave = dev_get_parentdata(dev);
+
+ slave->max_write_size = TX_BUFFER_SIZE;
+
+ return 0;
+}
+
+static int fsl_qspi_probe(struct udevice *bus)
+{
+ u32 total_size;
+ struct fsl_qspi_platdata *plat = dev_get_platdata(bus);
+ struct fsl_qspi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_bus *dm_spi_bus;
+
+ dm_spi_bus = bus->uclass_priv;
+
+ dm_spi_bus->max_hz = plat->speed_hz;
+
+ priv->regs = (struct fsl_qspi_regs *)plat->reg_base;
+ priv->flags = plat->flags;
+
+ priv->speed_hz = plat->speed_hz;
+ priv->amba_base[0] = plat->amba_base;
+ priv->amba_total_size = plat->amba_total_size;
+ priv->flash_num = plat->flash_num;
+ priv->num_chipselect = plat->num_chipselect;
+
+ qspi_write32(priv->flags, &priv->regs->mcr,
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+
+ qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
+ QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
+
+ total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
+ /*
+ * Any read access to non-implemented addresses will provide
+ * undefined results.
+ *
+ * In case single die flash devices, TOP_ADDR_MEMA2 and
+ * TOP_ADDR_MEMB2 should be initialized/programmed to
+ * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
+ * setting the size of these devices to 0. This would ensure
+ * that the complete memory map is assigned to only one flash device.
+ */
+ qspi_write32(priv->flags, &priv->regs->sfa1ad,
+ FSL_QSPI_FLASH_SIZE | priv->amba_base[0]);
+ qspi_write32(priv->flags, &priv->regs->sfa2ad,
+ FSL_QSPI_FLASH_SIZE | priv->amba_base[0]);
+ qspi_write32(priv->flags, &priv->regs->sfb1ad,
+ total_size | priv->amba_base[0]);
+ qspi_write32(priv->flags, &priv->regs->sfb2ad,
+ total_size | priv->amba_base[0]);
+
+ qspi_set_lut(priv);
+
+#ifdef CONFIG_SYS_FSL_QSPI_AHB
+ qspi_init_ahb_read(priv);
+#endif
+
+ qspi_module_disable(priv, 0);
+
+ return 0;
+}
+
+static int fsl_qspi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct reg_data {
+ u32 addr;
+ u32 size;
+ } regs_data[2];
+ struct fsl_qspi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = bus->of_offset;
+ int ret, flash_num = 0, subnode;
+
+ if (fdtdec_get_bool(blob, node, "big-endian"))
+ plat->flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG;
+
+ ret = fdtdec_get_int_array(blob, node, "reg", (u32 *)regs_data,
+ sizeof(regs_data)/sizeof(u32));
+ if (ret) {
+ debug("Error: can't get base addresses (ret = %d)!\n", ret);
+ return -ENOMEM;
+ }
+
+ /* Count flash numbers */
+ fdt_for_each_subnode(blob, subnode, node)
+ ++flash_num;
+
+ if (flash_num == 0) {
+ debug("Error: Missing flashes!\n");
+ return -ENODEV;
+ }
+
+ plat->speed_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
+ FSL_QSPI_DEFAULT_SCK_FREQ);
+ plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs",
+ FSL_QSPI_MAX_CHIPSELECT_NUM);
+
+ plat->reg_base = regs_data[0].addr;
+ plat->amba_base = regs_data[1].addr;
+ plat->amba_total_size = regs_data[1].size;
+ plat->flash_num = flash_num;
+
+ debug("%s: regs=<0x%x> <0x%x, 0x%x>, max-frequency=%d, endianess=%s\n",
+ __func__,
+ plat->reg_base,
+ plat->amba_base,
+ plat->amba_total_size,
+ plat->speed_hz,
+ plat->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le"
+ );
+
+ return 0;
+}
+
+static int fsl_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct fsl_qspi_priv *priv;
+ struct udevice *bus;
+
+ bus = dev->parent;
+ priv = dev_get_priv(bus);
+
+ return qspi_xfer(priv, bitlen, dout, din, flags);
+}
+
+static int fsl_qspi_claim_bus(struct udevice *dev)
+{
+ struct fsl_qspi_priv *priv;
+ struct udevice *bus;
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+
+ bus = dev->parent;
+ priv = dev_get_priv(bus);
+
+ priv->cur_amba_base =
+ priv->amba_base[0] + FSL_QSPI_FLASH_SIZE * slave_plat->cs;
+
+ qspi_module_disable(priv, 0);
+
+ return 0;
+}
+
+static int fsl_qspi_release_bus(struct udevice *dev)
+{
+ struct fsl_qspi_priv *priv;
+ struct udevice *bus;
+
+ bus = dev->parent;
+ priv = dev_get_priv(bus);
+
+ qspi_module_disable(priv, 1);
+
+ return 0;
+}
+
+static int fsl_qspi_set_speed(struct udevice *bus, uint speed)
+{
+ /* Nothing to do */
+ return 0;
+}
+
+static int fsl_qspi_set_mode(struct udevice *bus, uint mode)
+{
+ /* Nothing to do */
+ return 0;
+}
+
+static const struct dm_spi_ops fsl_qspi_ops = {
+ .claim_bus = fsl_qspi_claim_bus,
+ .release_bus = fsl_qspi_release_bus,
+ .xfer = fsl_qspi_xfer,
+ .set_speed = fsl_qspi_set_speed,
+ .set_mode = fsl_qspi_set_mode,
+};
+
+static const struct udevice_id fsl_qspi_ids[] = {
+ { .compatible = "fsl,vf610-qspi" },
+ { .compatible = "fsl,imx6sx-qspi" },
+ { }
+};
+
+U_BOOT_DRIVER(fsl_qspi) = {
+ .name = "fsl_qspi",
+ .id = UCLASS_SPI,
+ .of_match = fsl_qspi_ids,
+ .ops = &fsl_qspi_ops,
+ .ofdata_to_platdata = fsl_qspi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct fsl_qspi_platdata),
+ .priv_auto_alloc_size = sizeof(struct fsl_qspi_priv),
+ .probe = fsl_qspi_probe,
+ .child_pre_probe = fsl_qspi_child_pre_probe,
+};
+#endif
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index 194e882302..50354fdde1 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -7,6 +7,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <spi.h>
@@ -19,154 +20,99 @@
#define SPI_OPCODE_WREN 0x06
#define SPI_OPCODE_FAST_READ 0x0b
-struct ich_ctlr {
+struct ich_spi_platdata {
pci_dev_t dev; /* PCI device number */
int ich_version; /* Controller version, 7 or 9 */
bool use_sbase; /* Use SBASE instead of RCB */
+};
+
+struct ich_spi_priv {
int ichspi_lock;
int locked;
- uint8_t *opmenu;
+ int opmenu;
int menubytes;
void *base; /* Base of register set */
- uint16_t *preop;
- uint16_t *optype;
- uint32_t *addr;
- uint8_t *data;
+ int preop;
+ int optype;
+ int addr;
+ int data;
unsigned databytes;
- uint8_t *status;
- uint16_t *control;
- uint32_t *bbar;
+ int status;
+ int control;
+ int bbar;
uint32_t *pr; /* only for ich9 */
- uint8_t *speed; /* pointer to speed control */
+ int speed; /* pointer to speed control */
ulong max_speed; /* Maximum bus speed in MHz */
+ ulong cur_speed; /* Current bus speed */
+ struct spi_trans trans; /* current transaction in progress */
};
-struct ich_ctlr ctlr;
-
-static inline struct ich_spi_slave *to_ich_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct ich_spi_slave, slave);
-}
-
-static unsigned int ich_reg(const void *addr)
-{
- return (unsigned)(addr - ctlr.base) & 0xffff;
-}
-
-static u8 ich_readb(const void *addr)
+static u8 ich_readb(struct ich_spi_priv *priv, int reg)
{
- u8 value = readb(addr);
+ u8 value = readb(priv->base + reg);
- debug("read %2.2x from %4.4x\n", value, ich_reg(addr));
+ debug("read %2.2x from %4.4x\n", value, reg);
return value;
}
-static u16 ich_readw(const void *addr)
+static u16 ich_readw(struct ich_spi_priv *priv, int reg)
{
- u16 value = readw(addr);
+ u16 value = readw(priv->base + reg);
- debug("read %4.4x from %4.4x\n", value, ich_reg(addr));
+ debug("read %4.4x from %4.4x\n", value, reg);
return value;
}
-static u32 ich_readl(const void *addr)
+static u32 ich_readl(struct ich_spi_priv *priv, int reg)
{
- u32 value = readl(addr);
+ u32 value = readl(priv->base + reg);
- debug("read %8.8x from %4.4x\n", value, ich_reg(addr));
+ debug("read %8.8x from %4.4x\n", value, reg);
return value;
}
-static void ich_writeb(u8 value, void *addr)
+static void ich_writeb(struct ich_spi_priv *priv, u8 value, int reg)
{
- writeb(value, addr);
- debug("wrote %2.2x to %4.4x\n", value, ich_reg(addr));
+ writeb(value, priv->base + reg);
+ debug("wrote %2.2x to %4.4x\n", value, reg);
}
-static void ich_writew(u16 value, void *addr)
+static void ich_writew(struct ich_spi_priv *priv, u16 value, int reg)
{
- writew(value, addr);
- debug("wrote %4.4x to %4.4x\n", value, ich_reg(addr));
+ writew(value, priv->base + reg);
+ debug("wrote %4.4x to %4.4x\n", value, reg);
}
-static void ich_writel(u32 value, void *addr)
+static void ich_writel(struct ich_spi_priv *priv, u32 value, int reg)
{
- writel(value, addr);
- debug("wrote %8.8x to %4.4x\n", value, ich_reg(addr));
+ writel(value, priv->base + reg);
+ debug("wrote %8.8x to %4.4x\n", value, reg);
}
-static void write_reg(const void *value, void *dest, uint32_t size)
+static void write_reg(struct ich_spi_priv *priv, const void *value,
+ int dest_reg, uint32_t size)
{
- memcpy_toio(dest, value, size);
+ memcpy_toio(priv->base + dest_reg, value, size);
}
-static void read_reg(const void *src, void *value, uint32_t size)
+static void read_reg(struct ich_spi_priv *priv, int src_reg, void *value,
+ uint32_t size)
{
- memcpy_fromio(value, src, size);
+ memcpy_fromio(value, priv->base + src_reg, size);
}
-static void ich_set_bbar(struct ich_ctlr *ctlr, uint32_t minaddr)
+static void ich_set_bbar(struct ich_spi_priv *ctlr, uint32_t minaddr)
{
const uint32_t bbar_mask = 0x00ffff00;
uint32_t ichspi_bbar;
minaddr &= bbar_mask;
- ichspi_bbar = ich_readl(ctlr->bbar) & ~bbar_mask;
+ ichspi_bbar = ich_readl(ctlr, ctlr->bbar) & ~bbar_mask;
ichspi_bbar |= minaddr;
- ich_writel(ichspi_bbar, ctlr->bbar);
-}
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- puts("spi_cs_is_valid used but not implemented\n");
- return 0;
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct ich_spi_slave *ich;
-
- ich = spi_alloc_slave(struct ich_spi_slave, bus, cs);
- if (!ich) {
- puts("ICH SPI: Out of memory\n");
- return NULL;
- }
-
- /*
- * Yes this controller can only write a small number of bytes at
- * once! The limit is typically 64 bytes.
- */
- ich->slave.max_write_size = ctlr.databytes;
- ich->speed = max_hz;
-
- /*
- * ICH 7 SPI controller only supports array read command
- * and byte program command for SST flash
- */
- if (ctlr.ich_version == 7 || ctlr.use_sbase) {
- ich->slave.op_mode_rx = SPI_OPM_RX_AS;
- ich->slave.op_mode_tx = SPI_OPM_TX_BP;
- }
-
- return &ich->slave;
-}
-
-struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
- int spi_node)
-{
- /* We only support a single SPI at present */
- return spi_setup_slave(0, 0, 20000000, 0);
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct ich_spi_slave *ich = to_ich_spi(slave);
-
- free(ich);
+ ich_writel(ctlr, ichspi_bbar, ctlr->bbar);
}
/*
@@ -185,7 +131,8 @@ static int get_ich_version(uint16_t device_id)
device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX) ||
(device_id >= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN &&
device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX) ||
- device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC)
+ device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC ||
+ device_id == PCI_DEVICE_ID_INTEL_LYNXPOINT_LPC)
return 9;
return 0;
@@ -208,7 +155,7 @@ static int ich9_can_do_33mhz(pci_dev_t dev)
return speed == 1;
}
-static int ich_find_spi_controller(struct ich_ctlr *ich)
+static int ich_find_spi_controller(struct ich_spi_platdata *ich)
{
int last_bus = pci_last_busno();
int bus;
@@ -241,131 +188,77 @@ static int ich_find_spi_controller(struct ich_ctlr *ich)
return -ENODEV;
}
-static int ich_init_controller(struct ich_ctlr *ctlr)
+static int ich_init_controller(struct ich_spi_platdata *plat,
+ struct ich_spi_priv *ctlr)
{
uint8_t *rcrb; /* Root Complex Register Block */
uint32_t rcba; /* Root Complex Base Address */
uint32_t sbase_addr;
uint8_t *sbase;
- pci_read_config_dword(ctlr->dev, 0xf0, &rcba);
+ pci_read_config_dword(plat->dev, 0xf0, &rcba);
/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */
rcrb = (uint8_t *)(rcba & 0xffffc000);
/* SBASE is similar */
- pci_read_config_dword(ctlr->dev, 0x54, &sbase_addr);
+ pci_read_config_dword(plat->dev, 0x54, &sbase_addr);
sbase = (uint8_t *)(sbase_addr & 0xfffffe00);
- if (ctlr->ich_version == 7) {
+ if (plat->ich_version == 7) {
struct ich7_spi_regs *ich7_spi;
ich7_spi = (struct ich7_spi_regs *)(rcrb + 0x3020);
- ctlr->ichspi_lock = ich_readw(&ich7_spi->spis) & SPIS_LOCK;
- ctlr->opmenu = ich7_spi->opmenu;
+ ctlr->ichspi_lock = readw(&ich7_spi->spis) & SPIS_LOCK;
+ ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu);
ctlr->menubytes = sizeof(ich7_spi->opmenu);
- ctlr->optype = &ich7_spi->optype;
- ctlr->addr = &ich7_spi->spia;
- ctlr->data = (uint8_t *)ich7_spi->spid;
+ ctlr->optype = offsetof(struct ich7_spi_regs, optype);
+ ctlr->addr = offsetof(struct ich7_spi_regs, spia);
+ ctlr->data = offsetof(struct ich7_spi_regs, spid);
ctlr->databytes = sizeof(ich7_spi->spid);
- ctlr->status = (uint8_t *)&ich7_spi->spis;
- ctlr->control = &ich7_spi->spic;
- ctlr->bbar = &ich7_spi->bbar;
- ctlr->preop = &ich7_spi->preop;
+ ctlr->status = offsetof(struct ich7_spi_regs, spis);
+ ctlr->control = offsetof(struct ich7_spi_regs, spic);
+ ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
+ ctlr->preop = offsetof(struct ich7_spi_regs, preop);
ctlr->base = ich7_spi;
- } else if (ctlr->ich_version == 9) {
+ } else if (plat->ich_version == 9) {
struct ich9_spi_regs *ich9_spi;
- if (ctlr->use_sbase)
+ if (plat->use_sbase)
ich9_spi = (struct ich9_spi_regs *)sbase;
else
ich9_spi = (struct ich9_spi_regs *)(rcrb + 0x3800);
- ctlr->ichspi_lock = ich_readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
- ctlr->opmenu = ich9_spi->opmenu;
+ ctlr->ichspi_lock = readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
+ ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu);
ctlr->menubytes = sizeof(ich9_spi->opmenu);
- ctlr->optype = &ich9_spi->optype;
- ctlr->addr = &ich9_spi->faddr;
- ctlr->data = (uint8_t *)ich9_spi->fdata;
+ ctlr->optype = offsetof(struct ich9_spi_regs, optype);
+ ctlr->addr = offsetof(struct ich9_spi_regs, faddr);
+ ctlr->data = offsetof(struct ich9_spi_regs, fdata);
ctlr->databytes = sizeof(ich9_spi->fdata);
- ctlr->status = &ich9_spi->ssfs;
- ctlr->control = (uint16_t *)ich9_spi->ssfc;
- ctlr->speed = ich9_spi->ssfc + 2;
- ctlr->bbar = &ich9_spi->bbar;
- ctlr->preop = &ich9_spi->preop;
+ ctlr->status = offsetof(struct ich9_spi_regs, ssfs);
+ ctlr->control = offsetof(struct ich9_spi_regs, ssfc);
+ ctlr->speed = ctlr->control + 2;
+ ctlr->bbar = offsetof(struct ich9_spi_regs, bbar);
+ ctlr->preop = offsetof(struct ich9_spi_regs, preop);
ctlr->pr = &ich9_spi->pr[0];
ctlr->base = ich9_spi;
} else {
- debug("ICH SPI: Unrecognized ICH version %d.\n",
- ctlr->ich_version);
- return -1;
+ debug("ICH SPI: Unrecognised ICH version %d\n",
+ plat->ich_version);
+ return -EINVAL;
}
/* Work out the maximum speed we can support */
ctlr->max_speed = 20000000;
- if (ctlr->ich_version == 9 && ich9_can_do_33mhz(ctlr->dev))
+ if (plat->ich_version == 9 && ich9_can_do_33mhz(plat->dev))
ctlr->max_speed = 33000000;
debug("ICH SPI: Version %d detected at %p, speed %ld\n",
- ctlr->ich_version, ctlr->base, ctlr->max_speed);
+ plat->ich_version, ctlr->base, ctlr->max_speed);
ich_set_bbar(ctlr, 0);
return 0;
}
-void spi_init(void)
-{
- uint8_t bios_cntl;
-
- if (ich_find_spi_controller(&ctlr)) {
- printf("ICH SPI: Cannot find device\n");
- return;
- }
-
- if (ich_init_controller(&ctlr)) {
- printf("ICH SPI: Cannot setup controller\n");
- return;
- }
-
- /*
- * Disable the BIOS write protect so write commands are allowed. On
- * v9, deassert SMM BIOS Write Protect Disable.
- */
- if (ctlr.use_sbase) {
- struct ich9_spi_regs *ich9_spi;
-
- ich9_spi = (struct ich9_spi_regs *)ctlr.base;
- bios_cntl = ich_readb(&ich9_spi->bcr);
- bios_cntl &= ~(1 << 5); /* clear Enable InSMM_STS (EISS) */
- bios_cntl |= 1; /* Write Protect Disable (WPD) */
- ich_writeb(bios_cntl, &ich9_spi->bcr);
- } else {
- pci_read_config_byte(ctlr.dev, 0xdc, &bios_cntl);
- if (ctlr.ich_version == 9)
- bios_cntl &= ~(1 << 5);
- pci_write_config_byte(ctlr.dev, 0xdc, bios_cntl | 0x1);
- }
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- /* Handled by ICH automatically. */
- return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
- /* Handled by ICH automatically. */
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
- /* Handled by ICH automatically. */
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- /* Handled by ICH automatically. */
-}
-
static inline void spi_use_out(struct spi_trans *trans, unsigned bytes)
{
trans->out += bytes;
@@ -411,19 +304,19 @@ static void spi_setup_type(struct spi_trans *trans, int data_bytes)
}
}
-static int spi_setup_opcode(struct spi_trans *trans)
+static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans)
{
uint16_t optypes;
- uint8_t opmenu[ctlr.menubytes];
+ uint8_t opmenu[ctlr->menubytes];
trans->opcode = trans->out[0];
spi_use_out(trans, 1);
- if (!ctlr.ichspi_lock) {
+ if (!ctlr->ichspi_lock) {
/* The lock is off, so just use index 0. */
- ich_writeb(trans->opcode, ctlr.opmenu);
- optypes = ich_readw(ctlr.optype);
+ ich_writeb(ctlr, trans->opcode, ctlr->opmenu);
+ optypes = ich_readw(ctlr, ctlr->optype);
optypes = (optypes & 0xfffc) | (trans->type & 0x3);
- ich_writew(optypes, ctlr.optype);
+ ich_writew(ctlr, optypes, ctlr->optype);
return 0;
} else {
/* The lock is on. See if what we need is on the menu. */
@@ -434,20 +327,20 @@ static int spi_setup_opcode(struct spi_trans *trans)
if (trans->opcode == SPI_OPCODE_WREN)
return 0;
- read_reg(ctlr.opmenu, opmenu, sizeof(opmenu));
- for (opcode_index = 0; opcode_index < ctlr.menubytes;
+ read_reg(ctlr, ctlr->opmenu, opmenu, sizeof(opmenu));
+ for (opcode_index = 0; opcode_index < ctlr->menubytes;
opcode_index++) {
if (opmenu[opcode_index] == trans->opcode)
break;
}
- if (opcode_index == ctlr.menubytes) {
+ if (opcode_index == ctlr->menubytes) {
printf("ICH SPI: Opcode %x not found\n",
trans->opcode);
- return -1;
+ return -EINVAL;
}
- optypes = ich_readw(ctlr.optype);
+ optypes = ich_readw(ctlr, ctlr->optype);
optype = (optypes >> (opcode_index * 2)) & 0x3;
if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS &&
optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS &&
@@ -458,7 +351,7 @@ static int spi_setup_opcode(struct spi_trans *trans)
if (optype != trans->type) {
printf("ICH SPI: Transaction doesn't fit type %d\n",
optype);
- return -1;
+ return -ENOSPC;
}
return opcode_index;
}
@@ -480,7 +373,7 @@ static int spi_setup_offset(struct spi_trans *trans)
return 1;
default:
printf("Unrecognized SPI transaction type %#x\n", trans->type);
- return -1;
+ return -EPROTO;
}
}
@@ -491,16 +384,19 @@ static int spi_setup_offset(struct spi_trans *trans)
*
* Return the last read status value on success or -1 on failure.
*/
-static int ich_status_poll(u16 bitmask, int wait_til_set)
+static int ich_status_poll(struct ich_spi_priv *ctlr, u16 bitmask,
+ int wait_til_set)
{
int timeout = 600000; /* This will result in 6s */
u16 status = 0;
while (timeout--) {
- status = ich_readw(ctlr.status);
+ status = ich_readw(ctlr, ctlr->status);
if (wait_til_set ^ ((status & bitmask) == 0)) {
- if (wait_til_set)
- ich_writew((status & bitmask), ctlr.status);
+ if (wait_til_set) {
+ ich_writew(ctlr, status & bitmask,
+ ctlr->status);
+ }
return status;
}
udelay(10);
@@ -508,30 +404,28 @@ static int ich_status_poll(u16 bitmask, int wait_til_set)
printf("ICH SPI: SCIP timeout, read %x, expected %x\n",
status, bitmask);
- return -1;
+ return -ETIMEDOUT;
}
-/*
-int spi_xfer(struct spi_slave *slave, const void *dout,
- unsigned int bitsout, void *din, unsigned int bitsin)
-*/
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
- void *din, unsigned long flags)
+static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
{
- struct ich_spi_slave *ich = to_ich_spi(slave);
+ struct udevice *bus = dev_get_parent(dev);
+ struct ich_spi_priv *ctlr = dev_get_priv(bus);
uint16_t control;
int16_t opcode_index;
int with_address;
int status;
int bytes = bitlen / 8;
- struct spi_trans *trans = &ich->trans;
+ struct spi_trans *trans = &ctlr->trans;
unsigned type = flags & (SPI_XFER_BEGIN | SPI_XFER_END);
int using_cmd = 0;
+ int ret;
/* Ee don't support writing partial bytes. */
if (bitlen % 8) {
debug("ICH SPI: Accessing partial bytes not supported\n");
- return -1;
+ return -EPROTONOSUPPORT;
}
/* An empty end transaction can be ignored */
@@ -545,7 +439,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
if (dout && type == SPI_XFER_BEGIN) {
if (bytes > ICH_MAX_CMD_LEN) {
debug("ICH SPI: Command length limit exceeded\n");
- return -1;
+ return -ENOSPC;
}
memcpy(trans->cmd, dout, bytes);
trans->cmd_len = bytes;
@@ -576,21 +470,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
/* There has to always at least be an opcode. */
if (!trans->bytesout) {
debug("ICH SPI: No opcode for transfer\n");
- return -1;
+ return -EPROTO;
}
- if (ich_status_poll(SPIS_SCIP, 0) == -1)
- return -1;
+ ret = ich_status_poll(ctlr, SPIS_SCIP, 0);
+ if (ret < 0)
+ return ret;
- ich_writew(SPIS_CDS | SPIS_FCERR, ctlr.status);
+ ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
spi_setup_type(trans, using_cmd ? bytes : 0);
- opcode_index = spi_setup_opcode(trans);
+ opcode_index = spi_setup_opcode(ctlr, trans);
if (opcode_index < 0)
- return -1;
+ return -EINVAL;
with_address = spi_setup_offset(trans);
if (with_address < 0)
- return -1;
+ return -EINVAL;
if (trans->opcode == SPI_OPCODE_WREN) {
/*
@@ -598,20 +493,20 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
* in order to prevent the Management Engine from
* issuing a transaction between WREN and DATA.
*/
- if (!ctlr.ichspi_lock)
- ich_writew(trans->opcode, ctlr.preop);
+ if (!ctlr->ichspi_lock)
+ ich_writew(ctlr, trans->opcode, ctlr->preop);
return 0;
}
- if (ctlr.speed && ctlr.max_speed >= 33000000) {
+ if (ctlr->speed && ctlr->max_speed >= 33000000) {
int byte;
- byte = ich_readb(ctlr.speed);
- if (ich->speed >= 33000000)
+ byte = ich_readb(ctlr, ctlr->speed);
+ if (ctlr->cur_speed >= 33000000)
byte |= SSFC_SCF_33MHZ;
else
byte &= ~SSFC_SCF_33MHZ;
- ich_writeb(byte, ctlr.speed);
+ ich_writeb(ctlr, byte, ctlr->speed);
}
/* See if we have used up the command data */
@@ -622,35 +517,36 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
/* Preset control fields */
- control = ich_readw(ctlr.control);
+ control = ich_readw(ctlr, ctlr->control);
control &= ~SSFC_RESERVED;
control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
/* Issue atomic preop cycle if needed */
- if (ich_readw(ctlr.preop))
+ if (ich_readw(ctlr, ctlr->preop))
control |= SPIC_ACS;
if (!trans->bytesout && !trans->bytesin) {
/* SPI addresses are 24 bit only */
- if (with_address)
- ich_writel(trans->offset & 0x00FFFFFF, ctlr.addr);
-
+ if (with_address) {
+ ich_writel(ctlr, trans->offset & 0x00FFFFFF,
+ ctlr->addr);
+ }
/*
* This is a 'no data' command (like Write Enable), its
* bitesout size was 1, decremented to zero while executing
* spi_setup_opcode() above. Tell the chip to send the
* command.
*/
- ich_writew(control, ctlr.control);
+ ich_writew(ctlr, control, ctlr->control);
/* wait for the result */
- status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
- if (status == -1)
- return -1;
+ status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1);
+ if (status < 0)
+ return status;
if (status & SPIS_FCERR) {
debug("ICH SPI: Command transaction error\n");
- return -1;
+ return -EIO;
}
return 0;
@@ -663,9 +559,9 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
* and followed by other SPI commands, and this sequence is controlled
* by the SPI chip driver.
*/
- if (trans->bytesout > ctlr.databytes) {
+ if (trans->bytesout > ctlr->databytes) {
debug("ICH SPI: Too much to write. This should be prevented by the driver's max_write_size?\n");
- return -1;
+ return -EPROTO;
}
/*
@@ -676,41 +572,41 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
uint32_t data_length;
/* SPI addresses are 24 bit only */
- ich_writel(trans->offset & 0x00FFFFFF, ctlr.addr);
+ ich_writel(ctlr, trans->offset & 0x00FFFFFF, ctlr->addr);
if (trans->bytesout)
- data_length = min(trans->bytesout, ctlr.databytes);
+ data_length = min(trans->bytesout, ctlr->databytes);
else
- data_length = min(trans->bytesin, ctlr.databytes);
+ data_length = min(trans->bytesin, ctlr->databytes);
/* Program data into FDATA0 to N */
if (trans->bytesout) {
- write_reg(trans->out, ctlr.data, data_length);
+ write_reg(ctlr, trans->out, ctlr->data, data_length);
spi_use_out(trans, data_length);
if (with_address)
trans->offset += data_length;
}
/* Add proper control fields' values */
- control &= ~((ctlr.databytes - 1) << 8);
+ control &= ~((ctlr->databytes - 1) << 8);
control |= SPIC_DS;
control |= (data_length - 1) << 8;
/* write it */
- ich_writew(control, ctlr.control);
+ ich_writew(ctlr, control, ctlr->control);
/* Wait for Cycle Done Status or Flash Cycle Error. */
- status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
- if (status == -1)
- return -1;
+ status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1);
+ if (status < 0)
+ return status;
if (status & SPIS_FCERR) {
debug("ICH SPI: Data transaction error\n");
- return -1;
+ return -EIO;
}
if (trans->bytesin) {
- read_reg(ctlr.data, trans->in, data_length);
+ read_reg(ctlr, ctlr->data, trans->in, data_length);
spi_use_in(trans, data_length);
if (with_address)
trans->offset += data_length;
@@ -718,7 +614,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
/* Clear atomic preop now that xfer is done */
- ich_writew(0, ctlr.preop);
+ ich_writew(ctlr, 0, ctlr->preop);
return 0;
}
@@ -730,15 +626,18 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
* don't actually take effect until the HSFS[FLOCKDN] bit is set, but that's
* done elsewhere.
*/
-int spi_write_protect_region(uint32_t lower_limit, uint32_t length, int hint)
+int spi_write_protect_region(struct udevice *dev, uint32_t lower_limit,
+ uint32_t length, int hint)
{
+ struct udevice *bus = dev->parent;
+ struct ich_spi_priv *ctlr = dev_get_priv(bus);
uint32_t tmplong;
uint32_t upper_limit;
- if (!ctlr.pr) {
+ if (!ctlr->pr) {
printf("%s: operation not supported on this chipset\n",
__func__);
- return -1;
+ return -ENOSYS;
}
if (length == 0 ||
@@ -746,7 +645,7 @@ int spi_write_protect_region(uint32_t lower_limit, uint32_t length, int hint)
hint < 0 || hint > 4) {
printf("%s(0x%x, 0x%x, %d): invalid args\n", __func__,
lower_limit, length, hint);
- return -1;
+ return -EPERM;
}
upper_limit = lower_limit + length - 1;
@@ -765,8 +664,121 @@ int spi_write_protect_region(uint32_t lower_limit, uint32_t length, int hint)
((lower_limit & 0x01fff000) >> 12);
printf("%s: writing 0x%08x to %p\n", __func__, tmplong,
- &ctlr.pr[hint]);
- ctlr.pr[hint] = tmplong;
+ &ctlr->pr[hint]);
+ ctlr->pr[hint] = tmplong;
+
+ return 0;
+}
+
+static int ich_spi_probe(struct udevice *bus)
+{
+ struct ich_spi_platdata *plat = dev_get_platdata(bus);
+ struct ich_spi_priv *priv = dev_get_priv(bus);
+ uint8_t bios_cntl;
+ int ret;
+
+ ret = ich_init_controller(plat, priv);
+ if (ret)
+ return ret;
+ /*
+ * Disable the BIOS write protect so write commands are allowed. On
+ * v9, deassert SMM BIOS Write Protect Disable.
+ */
+ if (plat->use_sbase) {
+ struct ich9_spi_regs *ich9_spi;
+
+ ich9_spi = priv->base;
+ bios_cntl = ich_readb(priv, ich9_spi->bcr);
+ bios_cntl &= ~(1 << 5); /* clear Enable InSMM_STS (EISS) */
+ bios_cntl |= 1; /* Write Protect Disable (WPD) */
+ ich_writeb(priv, bios_cntl, ich9_spi->bcr);
+ } else {
+ pci_read_config_byte(plat->dev, 0xdc, &bios_cntl);
+ if (plat->ich_version == 9)
+ bios_cntl &= ~(1 << 5);
+ pci_write_config_byte(plat->dev, 0xdc, bios_cntl | 0x1);
+ }
+
+ priv->cur_speed = priv->max_speed;
+
+ return 0;
+}
+
+static int ich_spi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct ich_spi_platdata *plat = dev_get_platdata(bus);
+ int ret;
+
+ ret = ich_find_spi_controller(plat);
+ if (ret)
+ return ret;
return 0;
}
+
+static int ich_spi_set_speed(struct udevice *bus, uint speed)
+{
+ struct ich_spi_priv *priv = dev_get_priv(bus);
+
+ priv->cur_speed = speed;
+
+ return 0;
+}
+
+static int ich_spi_set_mode(struct udevice *bus, uint mode)
+{
+ debug("%s: mode=%d\n", __func__, mode);
+
+ return 0;
+}
+
+static int ich_spi_child_pre_probe(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct ich_spi_platdata *plat = dev_get_platdata(bus);
+ struct ich_spi_priv *priv = dev_get_priv(bus);
+ struct spi_slave *slave = dev_get_parentdata(dev);
+
+ /*
+ * Yes this controller can only write a small number of bytes at
+ * once! The limit is typically 64 bytes.
+ */
+ slave->max_write_size = priv->databytes;
+ /*
+ * ICH 7 SPI controller only supports array read command
+ * and byte program command for SST flash
+ */
+ if (plat->ich_version == 7) {
+ slave->op_mode_rx = SPI_OPM_RX_AS;
+ slave->op_mode_tx = SPI_OPM_TX_BP;
+ }
+
+ return 0;
+}
+
+static const struct dm_spi_ops ich_spi_ops = {
+ .xfer = ich_spi_xfer,
+ .set_speed = ich_spi_set_speed,
+ .set_mode = ich_spi_set_mode,
+ /*
+ * cs_info is not needed, since we require all chip selects to be
+ * in the device tree explicitly
+ */
+};
+
+static const struct udevice_id ich_spi_ids[] = {
+ { .compatible = "intel,ich-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(ich_spi) = {
+ .name = "ich_spi",
+ .id = UCLASS_SPI,
+ .of_match = ich_spi_ids,
+ .ops = &ich_spi_ops,
+ .ofdata_to_platdata = ich_spi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct ich_spi_platdata),
+ .priv_auto_alloc_size = sizeof(struct ich_spi_priv),
+ .child_pre_probe = ich_spi_child_pre_probe,
+ .probe = ich_spi_probe,
+};
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 63a6217cc6..866c48f243 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -50,7 +50,7 @@ int spi_claim_bus(struct spi_slave *slave)
struct udevice *dev = slave->dev;
struct udevice *bus = dev->parent;
struct dm_spi_ops *ops = spi_get_ops(bus);
- struct dm_spi_bus *spi = bus->uclass_priv;
+ struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
int speed;
int ret;
@@ -110,7 +110,7 @@ int spi_child_post_bind(struct udevice *dev)
int spi_post_probe(struct udevice *bus)
{
- struct dm_spi_bus *spi = bus->uclass_priv;
+ struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
spi->max_hz = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"spi-max-frequency", 0);
diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
index e69de29bb2..f408b8a81d 100644
--- a/drivers/tpm/Kconfig
+++ b/drivers/tpm/Kconfig
@@ -0,0 +1,7 @@
+config TPM_TIS_SANDBOX
+ bool "Enable sandbox TPM driver"
+ help
+ This driver emulates a TPM, providing access to base functions
+ such as reading and writing TPM private data. This is enough to
+ support Chrome OS verified boot. Extend functionality is not
+ implemented.
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index b4a9442703..637ef3d567 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -35,8 +35,24 @@ config USB
if USB
+config DM_USB
+ bool "Enable driver model for USB"
+ depends on USB && DM
+ help
+ Enable driver model for USB. The USB interface is then implemented
+ by the USB uclass. Multiple USB controllers of different types
+ (XHCI, EHCI) can be attached and used. The 'usb' command works as
+ normal. OCHI is not supported at present.
+
+ Much of the code is shared but with this option enabled the USB
+ uclass takes care of device enumeration. USB devices can be
+ declared with the USB_DEVICE() macro and will be automatically
+ probed when found on the bus.
+
source "drivers/usb/host/Kconfig"
+source "drivers/usb/emul/Kconfig"
+
config USB_STORAGE
bool "USB Mass Storage support"
---help---
diff --git a/drivers/usb/emul/Kconfig b/drivers/usb/emul/Kconfig
new file mode 100644
index 0000000000..ae1ab23a3d
--- /dev/null
+++ b/drivers/usb/emul/Kconfig
@@ -0,0 +1,8 @@
+config USB_EMUL
+ bool "Support for USB device emulation"
+ depends on DM_USB && SANDBOX
+ help
+ Since sandbox does not have access to a real USB bus, it is possible
+ to use device emulators instead. This allows testing of the USB
+ stack on sandbox without needing a real device, or any host machine
+ USB resources.
diff --git a/drivers/usb/emul/Makefile b/drivers/usb/emul/Makefile
new file mode 100644
index 0000000000..8fd83d5d06
--- /dev/null
+++ b/drivers/usb/emul/Makefile
@@ -0,0 +1,10 @@
+#
+# (C) Copyright 2015 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_USB_EMUL) += sandbox_flash.o
+obj-$(CONFIG_USB_EMUL) += sandbox_hub.o
+obj-$(CONFIG_USB_EMUL) += usb-emul-uclass.o
diff --git a/drivers/usb/emul/sandbox_flash.c b/drivers/usb/emul/sandbox_flash.c
new file mode 100644
index 0000000000..6e0808ded8
--- /dev/null
+++ b/drivers/usb/emul/sandbox_flash.c
@@ -0,0 +1,423 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <os.h>
+#include <scsi.h>
+#include <usb.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This driver emulates a flash stick using the UFI command specification and
+ * the BBB (bulk/bulk/bulk) protocol. It supports only a single logical unit
+ * number (LUN 0).
+ */
+
+enum {
+ SANDBOX_FLASH_EP_OUT = 1, /* endpoints */
+ SANDBOX_FLASH_EP_IN = 2,
+ SANDBOX_FLASH_BLOCK_LEN = 512,
+};
+
+enum cmd_phase {
+ PHASE_START,
+ PHASE_DATA,
+ PHASE_STATUS,
+};
+
+/**
+ * struct sandbox_flash_priv - private state for this driver
+ *
+ * @error: true if there is an error condition
+ * @alloc_len: Allocation length from the last incoming command
+ * @transfer_len: Transfer length from CBW header
+ * @read_len: Number of blocks of data left in the current read command
+ * @tag: Tag value from last command
+ * @fd: File descriptor of backing file
+ * @file_size: Size of file in bytes
+ * @status_buff: Data buffer for outgoing status
+ * @buff_used: Number of bytes ready to transfer back to host
+ * @buff: Data buffer for outgoing data
+ */
+struct sandbox_flash_priv {
+ bool error;
+ int alloc_len;
+ int transfer_len;
+ int read_len;
+ enum cmd_phase phase;
+ u32 tag;
+ int fd;
+ loff_t file_size;
+ struct umass_bbb_csw status;
+ int buff_used;
+ u8 buff[512];
+};
+
+struct sandbox_flash_plat {
+ const char *pathname;
+};
+
+struct scsi_inquiry_resp {
+ u8 type;
+ u8 flags;
+ u8 version;
+ u8 data_format;
+ u8 additional_len;
+ u8 spare[3];
+ char vendor[8];
+ char product[16];
+ char revision[4];
+};
+
+struct scsi_read_capacity_resp {
+ u32 last_block_addr;
+ u32 block_len;
+};
+
+struct __packed scsi_read10_req {
+ u8 cmd;
+ u8 lun_flags;
+ u32 lba;
+ u8 spare;
+ u16 transfer_len;
+ u8 spare2[3];
+};
+
+enum {
+ STRINGID_MANUFACTURER = 1,
+ STRINGID_PRODUCT,
+ STRINGID_SERIAL,
+
+ STRINGID_COUNT,
+};
+
+static struct usb_string flash_strings[] = {
+ {STRINGID_MANUFACTURER, "sandbox"},
+ {STRINGID_PRODUCT, "flash"},
+ {STRINGID_SERIAL, "2345"},
+ {},
+};
+
+static struct usb_device_descriptor flash_device_desc = {
+ .bLength = sizeof(flash_device_desc),
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+
+ .bDeviceClass = 0,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+
+ .idVendor = __constant_cpu_to_le16(0x1234),
+ .idProduct = __constant_cpu_to_le16(0x5678),
+ .iManufacturer = STRINGID_MANUFACTURER,
+ .iProduct = STRINGID_PRODUCT,
+ .iSerialNumber = STRINGID_SERIAL,
+ .bNumConfigurations = 1,
+};
+
+static struct usb_config_descriptor flash_config0 = {
+ .bLength = sizeof(flash_config0),
+ .bDescriptorType = USB_DT_CONFIG,
+
+ /* wTotalLength is set up by usb-emul-uclass */
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 0,
+ .iConfiguration = 0,
+ .bmAttributes = 1 << 7,
+ .bMaxPower = 50,
+};
+
+static struct usb_interface_descriptor flash_interface0 = {
+ .bLength = sizeof(flash_interface0),
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = US_SC_UFI,
+ .bInterfaceProtocol = US_PR_BULK,
+ .iInterface = 0,
+};
+
+static struct usb_endpoint_descriptor flash_endpoint0_out = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = SANDBOX_FLASH_EP_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(1024),
+ .bInterval = 0,
+};
+
+static struct usb_endpoint_descriptor flash_endpoint1_in = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = SANDBOX_FLASH_EP_IN | USB_ENDPOINT_DIR_MASK,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(1024),
+ .bInterval = 0,
+};
+
+static void *flash_desc_list[] = {
+ &flash_device_desc,
+ &flash_config0,
+ &flash_interface0,
+ &flash_endpoint0_out,
+ &flash_endpoint1_in,
+ NULL,
+};
+
+static int sandbox_flash_control(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buff, int len,
+ struct devrequest *setup)
+{
+ struct sandbox_flash_priv *priv = dev_get_priv(dev);
+
+ if (pipe == usb_rcvctrlpipe(udev, 0)) {
+ switch (setup->request) {
+ case US_BBB_RESET:
+ priv->error = false;
+ return 0;
+ case US_BBB_GET_MAX_LUN:
+ *(char *)buff = '\0';
+ return 1;
+ default:
+ debug("request=%x\n", setup->request);
+ break;
+ }
+ }
+ debug("pipe=%lx\n", pipe);
+
+ return -EIO;
+}
+
+static void setup_fail_response(struct sandbox_flash_priv *priv)
+{
+ struct umass_bbb_csw *csw = &priv->status;
+
+ csw->dCSWSignature = CSWSIGNATURE;
+ csw->dCSWTag = priv->tag;
+ csw->dCSWDataResidue = 0;
+ csw->bCSWStatus = CSWSTATUS_FAILED;
+ priv->buff_used = 0;
+}
+
+/**
+ * setup_response() - set up a response to send back to the host
+ *
+ * @priv: Sandbox flash private data
+ * @resp: Response to send, or NULL if none
+ * @size: Size of response
+ */
+static void setup_response(struct sandbox_flash_priv *priv, void *resp,
+ int size)
+{
+ struct umass_bbb_csw *csw = &priv->status;
+
+ csw->dCSWSignature = CSWSIGNATURE;
+ csw->dCSWTag = priv->tag;
+ csw->dCSWDataResidue = 0;
+ csw->bCSWStatus = CSWSTATUS_GOOD;
+
+ assert(!resp || resp == priv->buff);
+ priv->buff_used = size;
+}
+
+static void handle_read(struct sandbox_flash_priv *priv, ulong lba,
+ ulong transfer_len)
+{
+ debug("%s: lba=%lx, transfer_len=%lx\n", __func__, lba, transfer_len);
+ if (priv->fd != -1) {
+ os_lseek(priv->fd, lba * SANDBOX_FLASH_BLOCK_LEN, OS_SEEK_SET);
+ priv->read_len = transfer_len;
+ setup_response(priv, priv->buff,
+ transfer_len * SANDBOX_FLASH_BLOCK_LEN);
+ } else {
+ setup_fail_response(priv);
+ }
+}
+
+static int handle_ufi_command(struct sandbox_flash_priv *priv, const void *buff,
+ int len)
+{
+ const struct SCSI_cmd_block *req = buff;
+
+ switch (*req->cmd) {
+ case SCSI_INQUIRY: {
+ struct scsi_inquiry_resp *resp = (void *)priv->buff;
+
+ priv->alloc_len = req->cmd[4];
+ memset(resp, '\0', sizeof(*resp));
+ resp->data_format = 1;
+ resp->additional_len = 0x1f;
+ strncpy(resp->vendor,
+ flash_strings[STRINGID_MANUFACTURER - 1].s,
+ sizeof(resp->vendor));
+ strncpy(resp->product, flash_strings[STRINGID_PRODUCT - 1].s,
+ sizeof(resp->product));
+ strncpy(resp->revision, "1.0", sizeof(resp->revision));
+ setup_response(priv, resp, sizeof(*resp));
+ break;
+ }
+ case SCSI_TST_U_RDY:
+ setup_response(priv, NULL, 0);
+ break;
+ case SCSI_RD_CAPAC: {
+ struct scsi_read_capacity_resp *resp = (void *)priv->buff;
+ uint blocks;
+
+ if (priv->file_size)
+ blocks = priv->file_size / SANDBOX_FLASH_BLOCK_LEN - 1;
+ else
+ blocks = 0;
+ resp->last_block_addr = cpu_to_be32(blocks);
+ resp->block_len = cpu_to_be32(SANDBOX_FLASH_BLOCK_LEN);
+ setup_response(priv, resp, sizeof(*resp));
+ break;
+ }
+ case SCSI_READ10: {
+ struct scsi_read10_req *req = (void *)buff;
+
+ handle_read(priv, be32_to_cpu(req->lba),
+ be16_to_cpu(req->transfer_len));
+ break;
+ }
+ default:
+ debug("Command not supported: %x\n", req->cmd[0]);
+ return -EPROTONOSUPPORT;
+ }
+
+ priv->phase = priv->transfer_len ? PHASE_DATA : PHASE_STATUS;
+ return 0;
+}
+
+static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buff, int len)
+{
+ struct sandbox_flash_priv *priv = dev_get_priv(dev);
+ int ep = usb_pipeendpoint(pipe);
+ struct umass_bbb_cbw *cbw = buff;
+
+ debug("%s: dev=%s, pipe=%lx, ep=%x, len=%x, phase=%d\n", __func__,
+ dev->name, pipe, ep, len, priv->phase);
+ switch (ep) {
+ case SANDBOX_FLASH_EP_OUT:
+ switch (priv->phase) {
+ case PHASE_START:
+ priv->alloc_len = 0;
+ priv->read_len = 0;
+ if (priv->error || len != UMASS_BBB_CBW_SIZE ||
+ cbw->dCBWSignature != CBWSIGNATURE)
+ goto err;
+ if ((cbw->bCBWFlags & CBWFLAGS_SBZ) ||
+ cbw->bCBWLUN != 0)
+ goto err;
+ if (cbw->bCDBLength < 1 || cbw->bCDBLength >= 0x10)
+ goto err;
+ priv->transfer_len = cbw->dCBWDataTransferLength;
+ priv->tag = cbw->dCBWTag;
+ return handle_ufi_command(priv, cbw->CBWCDB,
+ cbw->bCDBLength);
+ case PHASE_DATA:
+ debug("data out\n");
+ break;
+ default:
+ break;
+ }
+ case SANDBOX_FLASH_EP_IN:
+ switch (priv->phase) {
+ case PHASE_DATA:
+ debug("data in, len=%x, alloc_len=%x, priv->read_len=%x\n",
+ len, priv->alloc_len, priv->read_len);
+ if (priv->read_len) {
+ ulong bytes_read;
+
+ bytes_read = os_read(priv->fd, buff, len);
+ if (bytes_read != len)
+ return -EIO;
+ priv->read_len -= len / SANDBOX_FLASH_BLOCK_LEN;
+ if (!priv->read_len)
+ priv->phase = PHASE_STATUS;
+ } else {
+ if (priv->alloc_len && len > priv->alloc_len)
+ len = priv->alloc_len;
+ memcpy(buff, priv->buff, len);
+ priv->phase = PHASE_STATUS;
+ }
+ return len;
+ case PHASE_STATUS:
+ debug("status in, len=%x\n", len);
+ if (len > sizeof(priv->status))
+ len = sizeof(priv->status);
+ memcpy(buff, &priv->status, len);
+ priv->phase = PHASE_START;
+ return len;
+ default:
+ break;
+ }
+ }
+err:
+ priv->error = true;
+ debug("%s: Detected transfer error\n", __func__);
+ return 0;
+}
+
+static int sandbox_flash_ofdata_to_platdata(struct udevice *dev)
+{
+ struct sandbox_flash_plat *plat = dev_get_platdata(dev);
+ const void *blob = gd->fdt_blob;
+
+ plat->pathname = fdt_getprop(blob, dev->of_offset, "sandbox,filepath",
+ NULL);
+
+ return 0;
+}
+
+static int sandbox_flash_bind(struct udevice *dev)
+{
+ return usb_emul_setup_device(dev, PACKET_SIZE_64, flash_strings,
+ flash_desc_list);
+}
+
+static int sandbox_flash_probe(struct udevice *dev)
+{
+ struct sandbox_flash_plat *plat = dev_get_platdata(dev);
+ struct sandbox_flash_priv *priv = dev_get_priv(dev);
+
+ priv->fd = os_open(plat->pathname, OS_O_RDONLY);
+ if (priv->fd != -1)
+ return os_get_filesize(plat->pathname, &priv->file_size);
+
+ return 0;
+}
+
+static const struct dm_usb_ops sandbox_usb_flash_ops = {
+ .control = sandbox_flash_control,
+ .bulk = sandbox_flash_bulk,
+};
+
+static const struct udevice_id sandbox_usb_flash_ids[] = {
+ { .compatible = "sandbox,usb-flash" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_sandbox_flash) = {
+ .name = "usb_sandbox_flash",
+ .id = UCLASS_USB_EMUL,
+ .of_match = sandbox_usb_flash_ids,
+ .bind = sandbox_flash_bind,
+ .probe = sandbox_flash_probe,
+ .ofdata_to_platdata = sandbox_flash_ofdata_to_platdata,
+ .ops = &sandbox_usb_flash_ops,
+ .priv_auto_alloc_size = sizeof(struct sandbox_flash_priv),
+ .platdata_auto_alloc_size = sizeof(struct sandbox_flash_plat),
+};
diff --git a/drivers/usb/emul/sandbox_hub.c b/drivers/usb/emul/sandbox_hub.c
new file mode 100644
index 0000000000..280c7080f2
--- /dev/null
+++ b/drivers/usb/emul/sandbox_hub.c
@@ -0,0 +1,303 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* We only support up to 8 */
+#define SANDBOX_NUM_PORTS 2
+
+struct sandbox_hub_platdata {
+ struct usb_dev_platdata plat;
+ int port; /* Port number (numbered from 0) */
+};
+
+enum {
+ STRING_MANUFACTURER = 1,
+ STRING_PRODUCT,
+ STRING_SERIAL,
+
+ STRING_count,
+};
+
+static struct usb_string hub_strings[] = {
+ {STRING_MANUFACTURER, "sandbox"},
+ {STRING_PRODUCT, "hub"},
+ {STRING_SERIAL, "2345"},
+};
+
+static struct usb_device_descriptor hub_device_desc = {
+ .bLength = sizeof(hub_device_desc),
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+
+ .bDeviceClass = USB_CLASS_HUB,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+
+ .idVendor = __constant_cpu_to_le16(0x1234),
+ .idProduct = __constant_cpu_to_le16(0x5678),
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .iSerialNumber = STRING_SERIAL,
+ .bNumConfigurations = 1,
+};
+
+static struct usb_config_descriptor hub_config1 = {
+ .bLength = sizeof(hub_config1),
+ .bDescriptorType = USB_DT_CONFIG,
+
+ /* wTotalLength is set up by usb-emul-uclass */
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 0,
+ .iConfiguration = 0,
+ .bmAttributes = 1 << 7,
+ .bMaxPower = 50,
+};
+
+static struct usb_interface_descriptor hub_interface0 = {
+ .bLength = sizeof(hub_interface0),
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HUB,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = US_PR_CB,
+ .iInterface = 0,
+};
+
+static struct usb_endpoint_descriptor hub_endpoint0_in = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = __constant_cpu_to_le16(1024),
+ .bInterval = 0,
+};
+
+static struct usb_hub_descriptor hub_desc = {
+ .bLength = sizeof(hub_desc),
+ .bDescriptorType = USB_DT_HUB,
+ .bNbrPorts = SANDBOX_NUM_PORTS,
+ .wHubCharacteristics = __constant_cpu_to_le16(1 << 0 | 1 << 3 |
+ 1 << 7),
+ .bPwrOn2PwrGood = 2,
+ .bHubContrCurrent = 5,
+ .DeviceRemovable = {0, 0xff}, /* all ports removeable */
+#if SANDBOX_NUM_PORTS > 8
+#error "This code sets up an incorrect mask"
+#endif
+};
+
+static void *hub_desc_list[] = {
+ &hub_device_desc,
+ &hub_config1,
+ &hub_interface0,
+ &hub_endpoint0_in,
+ &hub_desc,
+ NULL,
+};
+
+struct sandbox_hub_priv {
+ int status[SANDBOX_NUM_PORTS];
+ int change[SANDBOX_NUM_PORTS];
+};
+
+static struct udevice *hub_find_device(struct udevice *hub, int port)
+{
+ struct udevice *dev;
+
+ for (device_find_first_child(hub, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ struct sandbox_hub_platdata *plat;
+
+ plat = dev_get_parent_platdata(dev);
+ if (plat->port == port)
+ return dev;
+ }
+
+ return NULL;
+}
+
+static int clrset_post_state(struct udevice *hub, int port, int clear, int set)
+{
+ struct sandbox_hub_priv *priv = dev_get_priv(hub);
+ int *status = &priv->status[port];
+ int *change = &priv->change[port];
+ int ret = 0;
+
+ if ((clear | set) & USB_PORT_STAT_POWER) {
+ struct udevice *dev = hub_find_device(hub, port);
+
+ if (dev) {
+ if (set & USB_PORT_STAT_POWER) {
+ ret = device_probe(dev);
+ debug("%s: %s: power on, probed, ret=%d\n",
+ __func__, dev->name, ret);
+ if (!ret) {
+ set |= USB_PORT_STAT_CONNECTION |
+ USB_PORT_STAT_ENABLE;
+ }
+
+ } else if (clear & USB_PORT_STAT_POWER) {
+ debug("%s: %s: power off, removed, ret=%d\n",
+ __func__, dev->name, ret);
+ ret = device_remove(dev);
+ clear |= USB_PORT_STAT_CONNECTION;
+ }
+ }
+ }
+ *change |= *status & clear;
+ *change |= ~*status & set;
+ *change &= 0x1f;
+ *status = (*status & ~clear) | set;
+
+ return ret;
+}
+
+static int sandbox_hub_submit_control_msg(struct udevice *bus,
+ struct usb_device *udev,
+ unsigned long pipe,
+ void *buffer, int length,
+ struct devrequest *setup)
+{
+ struct sandbox_hub_priv *priv = dev_get_priv(bus);
+ int ret = 0;
+
+ if (pipe == usb_rcvctrlpipe(udev, 0)) {
+ switch (setup->requesttype) {
+ case USB_RT_HUB | USB_DIR_IN:
+ switch (setup->request) {
+ case USB_REQ_GET_STATUS: {
+ struct usb_hub_status *hubsts = buffer;
+
+ hubsts->wHubStatus = 0;
+ hubsts->wHubChange = 0;
+ udev->status = 0;
+ udev->act_len = sizeof(*hubsts);
+ return 0;
+ }
+ default:
+ debug("%s: rx ctl requesttype=%x, request=%x\n",
+ __func__, setup->requesttype,
+ setup->request);
+ break;
+ }
+ case USB_RT_PORT | USB_DIR_IN:
+ switch (setup->request) {
+ case USB_REQ_GET_STATUS: {
+ struct usb_port_status *portsts = buffer;
+ int port;
+
+ port = (setup->index & USB_HUB_PORT_MASK) - 1;
+ portsts->wPortStatus = priv->status[port];
+ portsts->wPortChange = priv->change[port];
+ udev->status = 0;
+ udev->act_len = sizeof(*portsts);
+ return 0;
+ }
+ }
+ default:
+ debug("%s: rx ctl requesttype=%x, request=%x\n",
+ __func__, setup->requesttype, setup->request);
+ break;
+ }
+ } else if (pipe == usb_sndctrlpipe(udev, 0)) {
+ switch (setup->requesttype) {
+ case USB_RT_PORT:
+ switch (setup->request) {
+ case USB_REQ_SET_FEATURE: {
+ int port;
+
+ port = (setup->index & USB_HUB_PORT_MASK) - 1;
+ debug("set feature port=%x, feature=%x\n",
+ port, setup->value);
+ if (setup->value < USB_PORT_FEAT_C_CONNECTION) {
+ ret = clrset_post_state(bus, port, 0,
+ 1 << setup->value);
+ } else {
+ debug(" ** Invalid feature\n");
+ }
+ return ret;
+ }
+ case USB_REQ_CLEAR_FEATURE: {
+ int port;
+
+ port = (setup->index & USB_HUB_PORT_MASK) - 1;
+ debug("clear feature port=%x, feature=%x\n",
+ port, setup->value);
+ if (setup->value < USB_PORT_FEAT_C_CONNECTION) {
+ ret = clrset_post_state(bus, port,
+ 1 << setup->value, 0);
+ } else {
+ priv->change[port] &= 1 <<
+ (setup->value - 16);
+ }
+ udev->status = 0;
+ return 0;
+ }
+ default:
+ debug("%s: tx ctl requesttype=%x, request=%x\n",
+ __func__, setup->requesttype,
+ setup->request);
+ break;
+ }
+ default:
+ debug("%s: tx ctl requesttype=%x, request=%x\n",
+ __func__, setup->requesttype, setup->request);
+ break;
+ }
+ }
+ debug("pipe=%lx\n", pipe);
+
+ return -EIO;
+}
+
+static int sandbox_hub_bind(struct udevice *dev)
+{
+ return usb_emul_setup_device(dev, PACKET_SIZE_64, hub_strings,
+ hub_desc_list);
+}
+
+static int sandbox_child_post_bind(struct udevice *dev)
+{
+ struct sandbox_hub_platdata *plat = dev_get_parent_platdata(dev);
+
+ plat->port = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1);
+
+ return 0;
+}
+
+static const struct dm_usb_ops sandbox_usb_hub_ops = {
+ .control = sandbox_hub_submit_control_msg,
+};
+
+static const struct udevice_id sandbox_usb_hub_ids[] = {
+ { .compatible = "sandbox,usb-hub" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_sandbox_hub) = {
+ .name = "usb_sandbox_hub",
+ .id = UCLASS_USB_EMUL,
+ .of_match = sandbox_usb_hub_ids,
+ .bind = sandbox_hub_bind,
+ .ops = &sandbox_usb_hub_ops,
+ .priv_auto_alloc_size = sizeof(struct sandbox_hub_priv),
+ .per_child_platdata_auto_alloc_size =
+ sizeof(struct sandbox_hub_platdata),
+ .child_post_bind = sandbox_child_post_bind,
+};
diff --git a/drivers/usb/emul/usb-emul-uclass.c b/drivers/usb/emul/usb-emul-uclass.c
new file mode 100644
index 0000000000..205f2c54df
--- /dev/null
+++ b/drivers/usb/emul/usb-emul-uclass.c
@@ -0,0 +1,263 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+#include <dm/root.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int copy_to_unicode(char *buff, int length, const char *str)
+{
+ int ptr;
+ int i;
+
+ if (length < 2)
+ return 0;
+ buff[1] = USB_DT_STRING;
+ for (ptr = 2, i = 0; ptr + 1 < length && *str; i++, ptr += 2) {
+ buff[ptr] = str[i];
+ buff[ptr + 1] = 0;
+ }
+ buff[0] = ptr;
+
+ return ptr;
+}
+
+static int usb_emul_get_string(struct usb_string *strings, int index,
+ char *buff, int length)
+{
+ if (index == 0) {
+ char *desc = buff;
+
+ desc[0] = 4;
+ desc[1] = USB_DT_STRING;
+ desc[2] = 0x09;
+ desc[3] = 0x14;
+ return 4;
+ } else if (strings) {
+ struct usb_string *ptr;
+
+ for (ptr = strings; ptr->s; ptr++) {
+ if (ptr->id == index)
+ return copy_to_unicode(buff, length, ptr->s);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static struct usb_generic_descriptor **find_descriptor(
+ struct usb_generic_descriptor **ptr, int type, int index)
+{
+ debug("%s: type=%x, index=%d\n", __func__, type, index);
+ for (; *ptr; ptr++) {
+ if ((*ptr)->bDescriptorType != type)
+ continue;
+ switch (type) {
+ case USB_DT_CONFIG: {
+ struct usb_config_descriptor *cdesc;
+
+ cdesc = (struct usb_config_descriptor *)*ptr;
+ if (cdesc && cdesc->bConfigurationValue == index)
+ return ptr;
+ break;
+ }
+ default:
+ return ptr;
+ }
+ }
+ debug("%s: config ptr=%p\n", __func__, *ptr);
+
+ return ptr;
+}
+
+static int usb_emul_get_descriptor(struct usb_dev_platdata *plat, int value,
+ void *buffer, int length)
+{
+ struct usb_generic_descriptor **ptr;
+ int type = value >> 8;
+ int index = value & 0xff;
+ int upto, todo;
+
+ debug("%s: type=%d, index=%d, plat=%p\n", __func__, type, index, plat);
+ if (type == USB_DT_STRING) {
+ return usb_emul_get_string(plat->strings, index, buffer,
+ length);
+ }
+
+ ptr = find_descriptor((struct usb_generic_descriptor **)plat->desc_list,
+ type, index);
+ if (!ptr) {
+ debug("%s: Could not find descriptor type %d, index %d\n",
+ __func__, type, index);
+ return -ENOENT;
+ }
+ for (upto = 0; *ptr && upto < length; ptr++, upto += todo) {
+ todo = min(length - upto, (int)(*ptr)->bLength);
+
+ memcpy(buffer + upto, *ptr, todo);
+ }
+
+ return upto ? upto : length ? -EIO : 0;
+}
+
+int usb_emul_find(struct udevice *bus, ulong pipe, struct udevice **emulp)
+{
+ int devnum = usb_pipedevice(pipe);
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ *emulp = NULL;
+ ret = uclass_get(UCLASS_USB_EMUL, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(dev, uc) {
+ struct usb_dev_platdata *udev = dev_get_parent_platdata(dev);
+
+ if (udev->devnum == devnum) {
+ debug("%s: Found emulator '%s', addr %d\n", __func__,
+ dev->name, udev->devnum);
+ *emulp = dev;
+ return 0;
+ }
+ }
+
+ debug("%s: No emulator found, addr %d\n", __func__, devnum);
+ return -ENOENT;
+}
+
+int usb_emul_control(struct udevice *emul, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length,
+ struct devrequest *setup)
+{
+ struct dm_usb_ops *ops = usb_get_emul_ops(emul);
+ struct usb_dev_platdata *plat;
+ int ret;
+
+ /* We permit getting the descriptor before we are probed */
+ plat = dev_get_parent_platdata(emul);
+ if (!ops->control)
+ return -ENOSYS;
+ debug("%s: dev=%s\n", __func__, emul->name);
+ if (pipe == usb_rcvctrlpipe(udev, 0)) {
+ switch (setup->request) {
+ case USB_REQ_GET_DESCRIPTOR: {
+ return usb_emul_get_descriptor(plat, setup->value,
+ buffer, length);
+ }
+ default:
+ ret = device_probe(emul);
+ if (ret)
+ return ret;
+ return ops->control(emul, udev, pipe, buffer, length,
+ setup);
+ }
+ } else if (pipe == usb_snddefctrl(udev)) {
+ switch (setup->request) {
+ case USB_REQ_SET_ADDRESS:
+ debug(" ** set address %s %d\n", emul->name,
+ setup->value);
+ plat->devnum = setup->value;
+ return 0;
+ default:
+ debug("requestsend =%x\n", setup->request);
+ break;
+ }
+ } else if (pipe == usb_sndctrlpipe(udev, 0)) {
+ switch (setup->request) {
+ case USB_REQ_SET_CONFIGURATION:
+ plat->configno = setup->value;
+ return 0;
+ default:
+ ret = device_probe(emul);
+ if (ret)
+ return ret;
+ return ops->control(emul, udev, pipe, buffer, length,
+ setup);
+ }
+ }
+ debug("pipe=%lx\n", pipe);
+
+ return -EIO;
+}
+
+int usb_emul_bulk(struct udevice *emul, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length)
+{
+ struct dm_usb_ops *ops = usb_get_emul_ops(emul);
+ int ret;
+
+ /* We permit getting the descriptor before we are probed */
+ if (!ops->bulk)
+ return -ENOSYS;
+ debug("%s: dev=%s\n", __func__, emul->name);
+ ret = device_probe(emul);
+ if (ret)
+ return ret;
+ return ops->bulk(emul, udev, pipe, buffer, length);
+}
+
+int usb_emul_setup_device(struct udevice *dev, int maxpacketsize,
+ struct usb_string *strings, void **desc_list)
+{
+ struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+ struct usb_generic_descriptor **ptr;
+ struct usb_config_descriptor *cdesc;
+ int upto;
+
+ plat->strings = strings;
+ plat->desc_list = (struct usb_generic_descriptor **)desc_list;
+
+ /* Fill in wTotalLength for each configuration descriptor */
+ ptr = plat->desc_list;
+ for (cdesc = NULL, upto = 0; *ptr; upto += (*ptr)->bLength, ptr++) {
+ debug(" - upto=%d, type=%d\n", upto, (*ptr)->bDescriptorType);
+ if ((*ptr)->bDescriptorType == USB_DT_CONFIG) {
+ if (cdesc) {
+ cdesc->wTotalLength = upto;
+ debug("%s: config %d length %d\n", __func__,
+ cdesc->bConfigurationValue,
+ cdesc->bLength);
+ }
+ cdesc = (struct usb_config_descriptor *)*ptr;
+ upto = 0;
+ }
+ }
+ if (cdesc) {
+ cdesc->wTotalLength = upto;
+ debug("%s: config %d length %d\n", __func__,
+ cdesc->bConfigurationValue, cdesc->wTotalLength);
+ }
+
+ return 0;
+}
+
+int usb_emul_post_bind(struct udevice *dev)
+{
+ /* Scan the bus for devices */
+ return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+void usb_emul_reset(struct udevice *dev)
+{
+ struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+
+ plat->devnum = 0;
+ plat->configno = 0;
+}
+
+UCLASS_DRIVER(usb_emul) = {
+ .id = UCLASS_USB_EMUL,
+ .name = "usb_emul",
+ .post_bind = usb_emul_post_bind,
+ .per_child_auto_alloc_size = sizeof(struct usb_device),
+ .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
+};
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c
index 1cd179baae..c8697ae78d 100644
--- a/drivers/usb/eth/asix.c
+++ b/drivers/usb/eth/asix.c
@@ -534,7 +534,8 @@ static int asix_recv(struct eth_device *eth)
}
/* Notify net stack */
- NetReceive(buf_ptr + sizeof(packet_len), packet_len);
+ net_process_received_packet(buf_ptr + sizeof(packet_len),
+ packet_len);
/* Adjust for next iteration. Packets are padded to 16-bits */
if (packet_len & 1)
diff --git a/drivers/usb/eth/asix88179.c b/drivers/usb/eth/asix88179.c
index 0ef85db7b5..94dfe85eff 100644
--- a/drivers/usb/eth/asix88179.c
+++ b/drivers/usb/eth/asix88179.c
@@ -558,7 +558,7 @@ static int asix_recv(struct eth_device *eth)
frame_pos += 2;
- NetReceive(recv_buf + frame_pos, pkt_len);
+ net_process_received_packet(recv_buf + frame_pos, pkt_len);
pkt_hdr++;
frame_pos += ((pkt_len + 7) & 0xFFF8)-2;
diff --git a/drivers/usb/eth/mcs7830.c b/drivers/usb/eth/mcs7830.c
index 8e738d40e3..c1b708600e 100644
--- a/drivers/usb/eth/mcs7830.c
+++ b/drivers/usb/eth/mcs7830.c
@@ -600,7 +600,7 @@ static int mcs7830_recv(struct eth_device *eth)
if (sts == STAT_RX_FRAME_CORRECT) {
debug("%s() got a frame, len=%d\n", __func__, gotlen);
- NetReceive(buf, gotlen);
+ net_process_received_packet(buf, gotlen);
return 0;
}
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index 6bca34dcf5..a7e50d6a6c 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -355,7 +355,7 @@ static int smsc95xx_init_mac_address(struct eth_device *eth,
/* try reading mac address from EEPROM */
if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
eth->enetaddr) == 0) {
- if (is_valid_ether_addr(eth->enetaddr)) {
+ if (is_valid_ethaddr(eth->enetaddr)) {
/* eeprom values are valid so use them */
debug("MAC address read from EEPROM\n");
return 0;
@@ -760,7 +760,8 @@ static int smsc95xx_recv(struct eth_device *eth)
}
/* Notify net stack */
- NetReceive(buf_ptr + sizeof(packet_len), packet_len - 4);
+ net_process_received_packet(buf_ptr + sizeof(packet_len),
+ packet_len - 4);
/* Adjust for next iteration */
actual_len -= sizeof(packet_len) + packet_len;
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c
index 7cb96e3bf6..c72b7e47c4 100644
--- a/drivers/usb/eth/usb_ether.c
+++ b/drivers/usb/eth/usb_ether.c
@@ -5,7 +5,9 @@
*/
#include <common.h>
+#include <dm.h>
#include <usb.h>
+#include <dm/device-internal.h>
#include "usb_ether.h"
@@ -118,8 +120,6 @@ static void probe_valid_drivers(struct usb_device *dev)
int usb_host_eth_scan(int mode)
{
int i, old_async;
- struct usb_device *dev;
-
if (mode == 1)
printf(" scanning usb for ethernet devices... ");
@@ -138,23 +138,59 @@ int usb_host_eth_scan(int mode)
}
usb_max_eth_dev = 0;
+#ifdef CONFIG_DM_USB
+ /*
+ * TODO: We should add USB_DEVICE() declarations to each USB ethernet
+ * driver and then most of this file can be removed.
+ */
+ struct udevice *bus;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_USB, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(bus, uc) {
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ struct usb_device *dev;
+
+ dev = usb_get_dev_index(bus, i); /* get device */
+ debug("i=%d, %s\n", i, dev ? dev->dev->name : "(done)");
+ if (!dev)
+ break; /* no more devices available */
+
+ /*
+ * find valid usb_ether driver for this device,
+ * if any
+ */
+ probe_valid_drivers(dev);
+
+ /* check limit */
+ if (usb_max_eth_dev == USB_MAX_ETH_DEV)
+ break;
+ } /* for */
+ }
+#else
for (i = 0; i < USB_MAX_DEVICE; i++) {
+ struct usb_device *dev;
+
dev = usb_get_dev_index(i); /* get device */
debug("i=%d\n", i);
- if (dev == NULL)
+ if (!dev)
break; /* no more devices available */
/* find valid usb_ether driver for this device, if any */
probe_valid_drivers(dev);
/* check limit */
- if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
- printf("max USB Ethernet Device reached: %d stopping\n",
- usb_max_eth_dev);
+ if (usb_max_eth_dev == USB_MAX_ETH_DEV)
break;
- }
} /* for */
-
+#endif
+ if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
+ printf("max USB Ethernet Device reached: %d stopping\n",
+ usb_max_eth_dev);
+ }
usb_disable_asynch(old_async); /* restore asynch value */
printf("%d Ethernet Device(s) found\n", usb_max_eth_dev);
if (usb_max_eth_dev > 0)
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 3b7024c498..22d288c711 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -883,7 +883,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
if (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH)
return -EINVAL;
+#ifdef CONFIG_DM_USB
+ ret = usb_setup_ehci_gadget(&controller.ctrl);
+#else
ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl);
+#endif
if (ret)
return ret;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 7e3b3ed859..141ff8be59 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -1522,7 +1522,7 @@ static int rx_submit(struct eth_dev *dev, struct usb_request *req,
* RNDIS headers involve variable numbers of LE32 values.
*/
- req->buf = (u8 *) NetRxPackets[0];
+ req->buf = (u8 *)net_rx_packets[0];
req->length = size;
req->complete = rx_complete;
@@ -1645,13 +1645,13 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
if (!eth_is_promisc (dev)) {
u8 *dest = skb->data;
- if (is_multicast_ether_addr(dest)) {
+ if (is_multicast_ethaddr(dest)) {
u16 type;
/* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
* SET_ETHERNET_MULTICAST_FILTERS requests
*/
- if (is_broadcast_ether_addr(dest))
+ if (is_broadcast_ethaddr(dest))
type = USB_CDC_PACKET_TYPE_BROADCAST;
else
type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
@@ -1942,7 +1942,7 @@ static int is_eth_addr_valid(char *str)
}
/* Now check the contents. */
- return is_valid_ether_addr(ea);
+ return is_valid_ethaddr(ea);
}
return 0;
}
@@ -1971,7 +1971,7 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
num |= (nibble(*str++));
dev_addr[i] = num;
}
- if (is_valid_ether_addr(dev_addr))
+ if (is_valid_ethaddr(dev_addr))
return 0;
}
return 1;
@@ -2446,7 +2446,8 @@ static int usb_eth_recv(struct eth_device *netdev)
if (packet_received) {
debug("%s: packet received\n", __func__);
if (dev->rx_req) {
- NetReceive(NetRxPackets[0], dev->rx_req->length);
+ net_process_received_packet(net_rx_packets[0],
+ dev->rx_req->length);
packet_received = 0;
rx_submit(dev, dev->rx_req, 0);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index eb6f34b53c..7658f873e0 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -5,6 +5,11 @@
# SPDX-License-Identifier: GPL-2.0+
#
+ifdef CONFIG_DM_USB
+obj-$(CONFIG_CMD_USB) += usb-uclass.o
+obj-$(CONFIG_SANDBOX) += usb-sandbox.o
+endif
+
# ohci
obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o
obj-$(CONFIG_USB_ATMEL) += ohci-at91.o
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index f3c077d82e..86cf6312fe 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -8,6 +8,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <fdtdec.h>
#include <libfdt.h>
#include <malloc.h>
@@ -24,19 +25,73 @@
/* Declare global data pointer */
DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_DM_USB
+struct exynos_ehci_platdata {
+ struct usb_platdata usb_plat;
+ fdt_addr_t hcd_base;
+ fdt_addr_t phy_base;
+ struct gpio_desc vbus_gpio;
+};
+#endif
+
/**
* Contains pointers to register base addresses
* for the usb controller.
*/
struct exynos_ehci {
+ struct ehci_ctrl ctrl;
struct exynos_usb_phy *usb;
struct ehci_hccr *hcd;
+#ifndef CONFIG_DM_USB
struct gpio_desc vbus_gpio;
+#endif
};
+#ifndef CONFIG_DM_USB
static struct exynos_ehci exynos;
+#endif
-#ifdef CONFIG_OF_CONTROL
+#ifdef CONFIG_DM_USB
+static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
+{
+ struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
+ const void *blob = gd->fdt_blob;
+ unsigned int node;
+ int depth;
+
+ /*
+ * Get the base address for XHCI controller from the device node
+ */
+ plat->hcd_base = dev_get_addr(dev);
+ if (plat->hcd_base == FDT_ADDR_T_NONE) {
+ debug("Can't get the XHCI register base address\n");
+ return -ENXIO;
+ }
+
+ depth = 0;
+ node = fdtdec_next_compatible_subnode(blob, dev->of_offset,
+ COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth);
+ if (node <= 0) {
+ debug("XHCI: Can't get device node for usb3-phy controller\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Get the base address for usbphy from the device node
+ */
+ plat->phy_base = fdtdec_get_addr(blob, node, "reg");
+ if (plat->phy_base == FDT_ADDR_T_NONE) {
+ debug("Can't get the usbphy register address\n");
+ return -ENXIO;
+ }
+
+ /* Vbus gpio */
+ gpio_request_by_name(dev, "samsung,vbus-gpio", 0,
+ &plat->vbus_gpio, GPIOD_IS_OUT);
+
+ return 0;
+}
+#else
static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
{
fdt_addr_t addr;
@@ -215,6 +270,7 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)
set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE);
}
+#ifndef CONFIG_DM_USB
/*
* EHCI-initialization
* Create the appropriate control structures to manage
@@ -268,3 +324,57 @@ int ehci_hcd_stop(int index)
return 0;
}
+#endif
+
+#ifdef CONFIG_DM_USB
+static int ehci_usb_probe(struct udevice *dev)
+{
+ struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
+ struct exynos_ehci *ctx = dev_get_priv(dev);
+ struct ehci_hcor *hcor;
+
+ ctx->hcd = (struct ehci_hccr *)plat->hcd_base;
+ ctx->usb = (struct exynos_usb_phy *)plat->phy_base;
+ hcor = (struct ehci_hcor *)((uint32_t)ctx->hcd +
+ HC_LENGTH(ehci_readl(&ctx->hcd->cr_capbase)));
+
+ /* setup the Vbus gpio here */
+ if (dm_gpio_is_valid(&plat->vbus_gpio))
+ dm_gpio_set_value(&plat->vbus_gpio, 1);
+
+ setup_usb_phy(ctx->usb);
+
+ return ehci_register(dev, ctx->hcd, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+ struct exynos_ehci *ctx = dev_get_priv(dev);
+ int ret;
+
+ ret = ehci_deregister(dev);
+ if (ret)
+ return ret;
+ reset_usb_phy(ctx->usb);
+
+ return 0;
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+ { .compatible = "samsung,exynos-ehci" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+ .name = "ehci_exynos",
+ .id = UCLASS_USB,
+ .of_match = ehci_usb_ids,
+ .ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+ .probe = ehci_usb_probe,
+ .remove = ehci_usb_remove,
+ .ops = &ehci_usb_ops,
+ .priv_auto_alloc_size = sizeof(struct exynos_ehci),
+ .platdata_auto_alloc_size = sizeof(struct exynos_ehci_platdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
index 3b761bc326..821222cc5d 100644
--- a/drivers/usb/host/ehci-faraday.c
+++ b/drivers/usb/host/ehci-faraday.c
@@ -29,6 +29,59 @@ static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
return !readl(&regs->usb.easstr);
}
+void faraday_ehci_set_usbmode(struct ehci_ctrl *ctrl)
+{
+ /* nothing needs to be done */
+}
+
+int faraday_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+{
+ int spd, ret = PORTSC_PSPD_HS;
+ union ehci_faraday_regs *regs;
+
+ ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
+ if (ehci_is_fotg2xx(regs))
+ spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+ else
+ spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+ switch (spd) {
+ case 0: /* full speed */
+ ret = PORTSC_PSPD_FS;
+ break;
+ case 1: /* low speed */
+ ret = PORTSC_PSPD_LS;
+ break;
+ case 2: /* high speed */
+ ret = PORTSC_PSPD_HS;
+ break;
+ default:
+ printf("ehci-faraday: invalid device speed\n");
+ break;
+ }
+
+ return ret;
+}
+
+uint32_t *faraday_ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
+{
+ /* Faraday EHCI has one and only one portsc register */
+ if (port) {
+ /* Printing the message would cause a scan failure! */
+ debug("The request port(%d) is not configured\n", port);
+ return NULL;
+ }
+
+ /* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+ return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
+}
+
+static const struct ehci_ops faraday_ehci_ops = {
+ .set_usb_mode = faraday_ehci_set_usbmode,
+ .get_port_speed = faraday_ehci_get_port_speed,
+ .get_portsc_register = faraday_ehci_get_portsc_register,
+};
+
/*
* Create the appropriate control structures to manage
* a new EHCI host controller.
@@ -43,6 +96,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
if (index < 0 || index >= ARRAY_SIZE(base_list))
return -1;
+ ehci_set_controller_priv(index, NULL, &faraday_ehci_ops);
regs = (void __iomem *)base_list[index];
hccr = (struct ehci_hccr *)&regs->usb.hccr;
hcor = (struct ehci_hcor *)&regs->usb.hcor;
@@ -87,61 +141,3 @@ int ehci_hcd_stop(int index)
{
return 0;
}
-
-/*
- * This ehci_set_usbmode() overrides the weak function
- * in "ehci-hcd.c".
- */
-void ehci_set_usbmode(int index)
-{
- /* nothing needs to be done */
-}
-
-/*
- * This ehci_get_port_speed() overrides the weak function
- * in "ehci-hcd.c".
- */
-int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
-{
- int spd, ret = PORTSC_PSPD_HS;
- union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
-
- if (ehci_is_fotg2xx(regs))
- spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
- else
- spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
-
- switch (spd) {
- case 0: /* full speed */
- ret = PORTSC_PSPD_FS;
- break;
- case 1: /* low speed */
- ret = PORTSC_PSPD_LS;
- break;
- case 2: /* high speed */
- ret = PORTSC_PSPD_HS;
- break;
- default:
- printf("ehci-faraday: invalid device speed\n");
- break;
- }
-
- return ret;
-}
-
-/*
- * This ehci_get_portsc_register() overrides the weak function
- * in "ehci-hcd.c".
- */
-uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
-{
- /* Faraday EHCI has one and only one portsc register */
- if (port) {
- /* Printing the message would cause a scan failure! */
- debug("The request port(%d) is not configured\n", port);
- return NULL;
- }
-
- /* Faraday EHCI PORTSC register offset is 0x20 from hcor */
- return (uint32_t *)((uint8_t *)hcor + 0x20);
-}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 86f1646596..bd9861dd68 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -21,6 +21,7 @@
* MA 02111-1307 USA
*/
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@@ -42,7 +43,9 @@
*/
#define HCHALT_TIMEOUT (8 * 1000)
+#ifndef CONFIG_DM_USB
static struct ehci_ctrl ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+#endif
#define ALIGN_END_ADDR(type, ptr, size) \
((unsigned long)(ptr) + roundup((size) * sizeof(type), USB_DMA_MINALIGN))
@@ -119,17 +122,33 @@ static struct descriptor {
#define ehci_is_TDI() (0)
#endif
-__weak int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev)
+{
+#ifdef CONFIG_DM_USB
+ struct udevice *dev;
+
+ /* Find the USB controller */
+ for (dev = udev->dev;
+ device_get_uclass_id(dev) != UCLASS_USB;
+ dev = dev->parent)
+ ;
+ return dev_get_priv(dev);
+#else
+ return udev->controller;
+#endif
+}
+
+static int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
{
return PORTSC_PSPD(reg);
}
-__weak void ehci_set_usbmode(int index)
+static void ehci_set_usbmode(struct ehci_ctrl *ctrl)
{
uint32_t tmp;
uint32_t *reg_ptr;
- reg_ptr = (uint32_t *)((u8 *)&ehcic[index].hcor->or_usbcmd + USBMODE);
+ reg_ptr = (uint32_t *)((u8 *)&ctrl->hcor->or_usbcmd + USBMODE);
tmp = ehci_readl(reg_ptr);
tmp |= USBMODE_CM_HC;
#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
@@ -138,11 +157,23 @@ __weak void ehci_set_usbmode(int index)
ehci_writel(reg_ptr, tmp);
}
-__weak void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+static void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+ uint32_t *reg)
{
mdelay(50);
}
+static uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
+{
+ if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+ /* Printing the message would cause a scan failure! */
+ debug("The request port(%u) is not configured\n", port);
+ return NULL;
+ }
+
+ return (uint32_t *)&ctrl->hcor->or_portsc[port];
+}
+
static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
{
uint32_t result;
@@ -159,15 +190,15 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
return -1;
}
-static int ehci_reset(int index)
+static int ehci_reset(struct ehci_ctrl *ctrl)
{
uint32_t cmd;
int ret = 0;
- cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
+ cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
cmd = (cmd & ~CMD_RUN) | CMD_RESET;
- ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);
- ret = handshake((uint32_t *)&ehcic[index].hcor->or_usbcmd,
+ ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+ ret = handshake((uint32_t *)&ctrl->hcor->or_usbcmd,
CMD_RESET, 0, 250 * 1000);
if (ret < 0) {
printf("EHCI fail to reset\n");
@@ -175,13 +206,13 @@ static int ehci_reset(int index)
}
if (ehci_is_TDI())
- ehci_set_usbmode(index);
+ ctrl->ops.set_usb_mode(ctrl);
#ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
- cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
+ cmd = ehci_readl(&ctrl->hcor->or_txfilltuning);
cmd &= ~TXFIFO_THRESH_MASK;
cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
- ehci_writel(&ehcic[index].hcor->or_txfilltuning, cmd);
+ ehci_writel(&ctrl->hcor->or_txfilltuning, cmd);
#endif
out:
return ret;
@@ -264,12 +295,13 @@ static inline u8 ehci_encode_speed(enum usb_device_speed speed)
return QH_FULL_SPEED;
}
-static void ehci_update_endpt2_dev_n_port(struct usb_device *dev,
+static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,
struct QH *qh)
{
struct usb_device *ttdev;
+ int parent_devnum;
- if (dev->speed != USB_SPEED_LOW && dev->speed != USB_SPEED_FULL)
+ if (udev->speed != USB_SPEED_LOW && udev->speed != USB_SPEED_FULL)
return;
/*
@@ -277,14 +309,35 @@ static void ehci_update_endpt2_dev_n_port(struct usb_device *dev,
* the tt, so of the first upstream usb-2 hub, there may be usb-1 hubs
* in the tree before that one!
*/
- ttdev = dev;
+#ifdef CONFIG_DM_USB
+ struct udevice *parent;
+
+ for (ttdev = udev; ; ) {
+ struct udevice *dev = ttdev->dev;
+
+ if (dev->parent &&
+ device_get_uclass_id(dev->parent) == UCLASS_USB_HUB)
+ parent = dev->parent;
+ else
+ parent = NULL;
+ if (!parent)
+ return;
+ ttdev = dev_get_parentdata(parent);
+ if (!ttdev->speed != USB_SPEED_HIGH)
+ break;
+ }
+ parent_devnum = ttdev->devnum;
+#else
+ ttdev = udev;
while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH)
ttdev = ttdev->parent;
if (!ttdev->parent)
return;
+ parent_devnum = ttdev->parent->devnum;
+#endif
qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(ttdev->portnr) |
- QH_ENDPT2_HUBADDR(ttdev->parent->devnum));
+ QH_ENDPT2_HUBADDR(parent_devnum));
}
static int
@@ -303,7 +356,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
uint32_t cmd;
int timeout;
int ret = 0;
- struct ehci_ctrl *ctrl = dev->controller;
+ struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
buffer, length, req);
@@ -649,20 +702,8 @@ fail:
return -1;
}
-__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
-{
- if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
- /* Printing the message would cause a scan failure! */
- debug("The request port(%u) is not configured\n", port);
- return NULL;
- }
-
- return (uint32_t *)&hcor->or_portsc[port];
-}
-
-int
-ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length, struct devrequest *req)
+static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int length, struct devrequest *req)
{
uint8_t tmpbuf[4];
u16 typeReq;
@@ -671,7 +712,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
uint32_t reg;
uint32_t *status_reg;
int port = le16_to_cpu(req->index) & 0xff;
- struct ehci_ctrl *ctrl = dev->controller;
+ struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
srclen = 0;
@@ -686,7 +727,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
- status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1);
+ status_reg = ctrl->ops.get_portsc_register(ctrl, port - 1);
if (!status_reg)
return -1;
break;
@@ -781,7 +822,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
if (ehci_is_TDI()) {
- switch (ehci_get_port_speed(ctrl->hcor, reg)) {
+ switch (ctrl->ops.get_port_speed(ctrl, reg)) {
case PORTSC_PSPD_FS:
break;
case PORTSC_PSPD_LS:
@@ -843,7 +884,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
* usb 2.0 specification say 50 ms resets on
* root
*/
- ehci_powerup_fixup(status_reg, &reg);
+ ctrl->ops.powerup_fixup(ctrl, status_reg, &reg);
ehci_writel(status_reg, reg & ~EHCI_PS_PR);
/*
@@ -930,41 +971,59 @@ unknown:
return -1;
}
-int usb_lowlevel_stop(int index)
+const struct ehci_ops default_ehci_ops = {
+ .set_usb_mode = ehci_set_usbmode,
+ .get_port_speed = ehci_get_port_speed,
+ .powerup_fixup = ehci_powerup_fixup,
+ .get_portsc_register = ehci_get_portsc_register,
+};
+
+static void ehci_setup_ops(struct ehci_ctrl *ctrl, const struct ehci_ops *ops)
{
- ehci_shutdown(&ehcic[index]);
- return ehci_hcd_stop(index);
+ if (!ops) {
+ ctrl->ops = default_ehci_ops;
+ } else {
+ ctrl->ops = *ops;
+ if (!ctrl->ops.set_usb_mode)
+ ctrl->ops.set_usb_mode = ehci_set_usbmode;
+ if (!ctrl->ops.get_port_speed)
+ ctrl->ops.get_port_speed = ehci_get_port_speed;
+ if (!ctrl->ops.powerup_fixup)
+ ctrl->ops.powerup_fixup = ehci_powerup_fixup;
+ if (!ctrl->ops.get_portsc_register)
+ ctrl->ops.get_portsc_register =
+ ehci_get_portsc_register;
+ }
}
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+#ifndef CONFIG_DM_USB
+void ehci_set_controller_priv(int index, void *priv, const struct ehci_ops *ops)
+{
+ struct ehci_ctrl *ctrl = &ehcic[index];
+
+ ctrl->priv = priv;
+ ehci_setup_ops(ctrl, ops);
+}
+
+void *ehci_get_controller_priv(int index)
+{
+ return ehcic[index].priv;
+}
+#endif
+
+static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
{
- uint32_t reg;
- uint32_t cmd;
struct QH *qh_list;
struct QH *periodic;
+ uint32_t reg;
+ uint32_t cmd;
int i;
- int rc;
-
- rc = ehci_hcd_init(index, init, &ehcic[index].hccr, &ehcic[index].hcor);
- if (rc)
- return rc;
- if (init == USB_INIT_DEVICE)
- goto done;
- /* EHCI spec section 4.1 */
- if (ehci_reset(index))
- return -1;
-
-#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
- rc = ehci_hcd_init(index, init, &ehcic[index].hccr, &ehcic[index].hcor);
- if (rc)
- return rc;
-#endif
/* Set the high address word (aka segment) for 64-bit controller */
- if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1)
- ehci_writel(&ehcic[index].hcor->or_ctrldssegment, 0);
+ if (ehci_readl(&ctrl->hccr->cr_hccparams) & 1)
+ ehci_writel(&ctrl->hcor->or_ctrldssegment, 0);
- qh_list = &ehcic[index].qh_list;
+ qh_list = &ctrl->qh_list;
/* Set head of reclaim list */
memset(qh_list, 0, sizeof(*qh_list));
@@ -980,14 +1039,14 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
ALIGN_END_ADDR(struct QH, qh_list, 1));
/* Set async. queue head pointer. */
- ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (unsigned long)qh_list);
+ ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)qh_list);
/*
* Set up periodic list
* Step 1: Parent QH for all periodic transfers.
*/
- ehcic[index].periodic_schedules = 0;
- periodic = &ehcic[index].periodic_queue;
+ ctrl->periodic_schedules = 0;
+ periodic = &ctrl->periodic_queue;
memset(periodic, 0, sizeof(*periodic));
periodic->qh_link = cpu_to_hc32(QH_LINK_TERMINATE);
periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
@@ -1005,25 +1064,25 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
* Split Transactions will be spread across microframes using
* S-mask and C-mask.
*/
- if (ehcic[index].periodic_list == NULL)
- ehcic[index].periodic_list = memalign(4096, 1024 * 4);
+ if (ctrl->periodic_list == NULL)
+ ctrl->periodic_list = memalign(4096, 1024 * 4);
- if (!ehcic[index].periodic_list)
+ if (!ctrl->periodic_list)
return -ENOMEM;
for (i = 0; i < 1024; i++) {
- ehcic[index].periodic_list[i] = cpu_to_hc32((unsigned long)periodic
+ ctrl->periodic_list[i] = cpu_to_hc32((unsigned long)periodic
| QH_LINK_TYPE_QH);
}
- flush_dcache_range((unsigned long)ehcic[index].periodic_list,
- ALIGN_END_ADDR(uint32_t, ehcic[index].periodic_list,
+ flush_dcache_range((unsigned long)ctrl->periodic_list,
+ ALIGN_END_ADDR(uint32_t, ctrl->periodic_list,
1024));
/* Set periodic list base address */
- ehci_writel(&ehcic[index].hcor->or_periodiclistbase,
- (unsigned long)ehcic[index].periodic_list);
+ ehci_writel(&ctrl->hcor->or_periodiclistbase,
+ (unsigned long)ctrl->periodic_list);
- reg = ehci_readl(&ehcic[index].hccr->cr_hcsparams);
+ reg = ehci_readl(&ctrl->hccr->cr_hcsparams);
descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
debug("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
/* Port Indicators */
@@ -1036,37 +1095,81 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
| 0x01, &descriptor.hub.wHubCharacteristics);
/* Start the host controller. */
- cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
+ cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
/*
* Philips, Intel, and maybe others need CMD_RUN before the
* root hub will detect new devices (why?); NEC doesn't
*/
cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
cmd |= CMD_RUN;
- ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);
+ ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
-#ifndef CONFIG_USB_EHCI_FARADAY
- /* take control over the ports */
- cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
- cmd |= FLAG_CF;
- ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
-#endif
+ if (!(tweaks & EHCI_TWEAK_NO_INIT_CF)) {
+ /* take control over the ports */
+ cmd = ehci_readl(&ctrl->hcor->or_configflag);
+ cmd |= FLAG_CF;
+ ehci_writel(&ctrl->hcor->or_configflag, cmd);
+ }
/* unblock posted write */
- cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
+ cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
mdelay(5);
- reg = HC_VERSION(ehci_readl(&ehcic[index].hccr->cr_capbase));
+ reg = HC_VERSION(ehci_readl(&ctrl->hccr->cr_capbase));
printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
- ehcic[index].rootdev = 0;
+ return 0;
+}
+
+#ifndef CONFIG_DM_USB
+int usb_lowlevel_stop(int index)
+{
+ ehci_shutdown(&ehcic[index]);
+ return ehci_hcd_stop(index);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+ struct ehci_ctrl *ctrl = &ehcic[index];
+ uint tweaks = 0;
+ int rc;
+
+ /**
+ * Set ops to default_ehci_ops, ehci_hcd_init should call
+ * ehci_set_controller_priv to change any of these function pointers.
+ */
+ ctrl->ops = default_ehci_ops;
+
+ rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
+ if (rc)
+ return rc;
+ if (init == USB_INIT_DEVICE)
+ goto done;
+
+ /* EHCI spec section 4.1 */
+ if (ehci_reset(ctrl))
+ return -1;
+
+#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
+ rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
+ if (rc)
+ return rc;
+#endif
+#ifdef CONFIG_USB_EHCI_FARADAY
+ tweaks |= EHCI_TWEAK_NO_INIT_CF;
+#endif
+ rc = ehci_common_init(ctrl, tweaks);
+ if (rc)
+ return rc;
+
+ ctrl->rootdev = 0;
done:
*controller = &ehcic[index];
return 0;
}
+#endif
-int
-submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length)
+static int _ehci_submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int length)
{
if (usb_pipetype(pipe) != PIPE_BULK) {
@@ -1076,11 +1179,11 @@ submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
return ehci_submit_async(dev, pipe, buffer, length, NULL);
}
-int
-submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length, struct devrequest *setup)
+static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int length,
+ struct devrequest *setup)
{
- struct ehci_ctrl *ctrl = dev->controller;
+ struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
if (usb_pipetype(pipe) != PIPE_CONTROL) {
debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
@@ -1150,7 +1253,7 @@ struct int_queue *
create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
int elementsize, void *buffer, int interval)
{
- struct ehci_ctrl *ctrl = dev->controller;
+ struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
struct int_queue *result = NULL;
int i;
@@ -1342,7 +1445,7 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
int
destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
{
- struct ehci_ctrl *ctrl = dev->controller;
+ struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
int result = -1;
unsigned long timeout;
@@ -1386,9 +1489,8 @@ out:
return result;
}
-int
-submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length, int interval)
+static int _ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int length, int interval)
{
void *backbuffer;
struct int_queue *queue;
@@ -1423,3 +1525,98 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
/* everything worked out fine */
return result;
}
+
+#ifndef CONFIG_DM_USB
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int length)
+{
+ return _ehci_submit_bulk_msg(dev, pipe, buffer, length);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, struct devrequest *setup)
+{
+ return _ehci_submit_control_msg(dev, pipe, buffer, length, setup);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int length, int interval)
+{
+ return _ehci_submit_int_msg(dev, pipe, buffer, length, interval);
+}
+#endif
+
+#ifdef CONFIG_DM_USB
+static int ehci_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length,
+ struct devrequest *setup)
+{
+ debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+ dev->name, udev, udev->dev->name, udev->portnr);
+
+ return _ehci_submit_control_msg(udev, pipe, buffer, length, setup);
+}
+
+static int ehci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length)
+{
+ debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+ return _ehci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+static int ehci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length,
+ int interval)
+{
+ debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+ return _ehci_submit_int_msg(udev, pipe, buffer, length, interval);
+}
+
+int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
+ struct ehci_hcor *hcor, const struct ehci_ops *ops,
+ uint tweaks, enum usb_init_type init)
+{
+ struct ehci_ctrl *ctrl = dev_get_priv(dev);
+ int ret;
+
+ debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p, init=%d\n", __func__,
+ dev->name, ctrl, hccr, hcor, init);
+
+ ehci_setup_ops(ctrl, ops);
+ ctrl->hccr = hccr;
+ ctrl->hcor = hcor;
+ ctrl->priv = ctrl;
+
+ if (init == USB_INIT_DEVICE)
+ goto done;
+ ret = ehci_reset(ctrl);
+ if (ret)
+ goto err;
+
+ ret = ehci_common_init(ctrl, tweaks);
+ if (ret)
+ goto err;
+done:
+ return 0;
+err:
+ free(ctrl);
+ debug("%s: failed, ret=%d\n", __func__, ret);
+ return ret;
+}
+
+int ehci_deregister(struct udevice *dev)
+{
+ struct ehci_ctrl *ctrl = dev_get_priv(dev);
+
+ ehci_shutdown(ctrl);
+
+ return 0;
+}
+
+struct dm_usb_ops ehci_usb_ops = {
+ .control = ehci_submit_control_msg,
+ .bulk = ehci_submit_bulk_msg,
+ .interrupt = ehci_submit_int_msg,
+};
+
+#endif
diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c
index 7566c61284..d3199622eb 100644
--- a/drivers/usb/host/ehci-mx5.c
+++ b/drivers/usb/host/ehci-mx5.c
@@ -218,11 +218,23 @@ void __weak board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
{
}
+__weak void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+ uint32_t *reg)
+{
+ mdelay(50);
+}
+
+static const struct ehci_ops mx5_ehci_ops = {
+ .powerup_fixup = mx5_ehci_powerup_fixup,
+};
+
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct usb_ehci *ehci;
+ /* The only user for this is efikamx-usb */
+ ehci_set_controller_priv(index, NULL, &mx5_ehci_ops);
set_usboh3_clk();
enable_usboh3_clk(true);
set_usb_phy_clk();
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index c6bfbe3999..27705d6627 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -7,6 +7,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm-generic/gpio.h>
@@ -20,6 +21,8 @@
#include "ehci.h"
+DECLARE_GLOBAL_DATA_PTR;
+
#define USB1_ADDR_MASK 0xFFFF0000
#define HOSTPC1_DEVLC 0x84
@@ -32,9 +35,11 @@
#endif
#endif
+#ifndef CONFIG_DM_USB
enum {
USB_PORTS_MAX = 3, /* Maximum ports we allow */
};
+#endif
/* Parameters we need for USB */
enum {
@@ -61,14 +66,26 @@ enum dr_mode {
DR_MODE_OTG, /* supports both */
};
+enum usb_ctlr_type {
+ USB_CTLR_T20,
+ USB_CTLR_T30,
+ USB_CTLR_T114,
+
+ USB_CTRL_COUNT,
+};
+
/* Information about a USB port */
struct fdt_usb {
+ struct ehci_ctrl ehci;
struct usb_ctlr *reg; /* address of registers in physical memory */
unsigned utmi:1; /* 1 if port has external tranceiver, else 0 */
unsigned ulpi:1; /* 1 if port has external ULPI transceiver */
unsigned enabled:1; /* 1 to enable, 0 to disable */
unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */
+#ifndef CONFIG_DM_USB
unsigned initialized:1; /* has this port already been initialized? */
+#endif
+ enum usb_ctlr_type type;
enum usb_init_type init_type;
enum dr_mode dr_mode; /* dual role mode */
enum periph_id periph_id;/* peripheral id */
@@ -76,10 +93,10 @@ struct fdt_usb {
struct gpio_desc phy_reset_gpio; /* GPIO to reset ULPI phy */
};
+#ifndef CONFIG_DM_USB
static struct fdt_usb port[USB_PORTS_MAX]; /* List of valid USB ports */
static unsigned port_count; /* Number of available ports */
-/* Port that needs to clear CSC after Port Reset */
-static u32 port_addr_clear_csc;
+#endif
/*
* This table has USB timing parameters for each Oscillator frequency we
@@ -156,13 +173,14 @@ static const u8 utmip_elastic_limit = 16;
static const u8 utmip_hs_sync_start_delay = 9;
struct fdt_usb_controller {
+ /* TODO(sjg@chromium.org): Remove when we only use driver model */
int compat;
/* flag to determine whether controller supports hostpc register */
u32 has_hostpc:1;
const unsigned *pll_parameter;
};
-static struct fdt_usb_controller fdt_usb_controllers[] = {
+static struct fdt_usb_controller fdt_usb_controllers[USB_CTRL_COUNT] = {
{
.compat = COMPAT_NVIDIA_TEGRA20_USB,
.has_hostpc = 0,
@@ -180,40 +198,36 @@ static struct fdt_usb_controller fdt_usb_controllers[] = {
},
};
-static struct fdt_usb_controller *controller;
-
/*
* A known hardware issue where Connect Status Change bit of PORTSC register
* of USB1 controller will be set after Port Reset.
* We have to clear it in order for later device enumeration to proceed.
- * This ehci_powerup_fixup overrides the weak function ehci_powerup_fixup
- * in "ehci-hcd.c".
*/
-void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
+ uint32_t *status_reg, uint32_t *reg)
{
+ struct fdt_usb *config = ctrl->priv;
+ struct fdt_usb_controller *controller;
+
+ controller = &fdt_usb_controllers[config->type];
mdelay(50);
/* This is to avoid PORT_ENABLE bit to be cleared in "ehci-hcd.c". */
if (controller->has_hostpc)
*reg |= EHCI_PS_PE;
- if (((unsigned long)status_reg & TEGRA_USB_ADDR_MASK) != port_addr_clear_csc)
+ if (!config->has_legacy_mode)
return;
/* For EHCI_PS_CSC to be cleared in ehci_hcd.c */
if (ehci_readl(status_reg) & EHCI_PS_CSC)
*reg |= EHCI_PS_CSC;
}
-/*
- * This ehci_set_usbmode overrides the weak function ehci_set_usbmode
- * in "ehci-hcd.c".
- */
-void ehci_set_usbmode(int index)
+static void tegra_ehci_set_usbmode(struct ehci_ctrl *ctrl)
{
- struct fdt_usb *config;
+ struct fdt_usb *config = ctrl->priv;
struct usb_ctlr *usbctlr;
uint32_t tmp;
- config = &port[index];
usbctlr = config->reg;
tmp = ehci_readl(&usbctlr->usb_mode);
@@ -221,17 +235,17 @@ void ehci_set_usbmode(int index)
ehci_writel(&usbctlr->usb_mode, tmp);
}
-/*
- * This ehci_get_port_speed overrides the weak function ehci_get_port_speed
- * in "ehci-hcd.c".
- */
-int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+static int tegra_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
{
+ struct fdt_usb *config = ctrl->priv;
+ struct fdt_usb_controller *controller;
uint32_t tmp;
uint32_t *reg_ptr;
+ controller = &fdt_usb_controllers[config->type];
if (controller->has_hostpc) {
- reg_ptr = (uint32_t *)((u8 *)&hcor->or_usbcmd + HOSTPC1_DEVLC);
+ reg_ptr = (uint32_t *)((u8 *)&ctrl->hcor->or_usbcmd +
+ HOSTPC1_DEVLC);
tmp = ehci_readl(reg_ptr);
return HOSTPC1_PSPD(tmp);
} else
@@ -263,7 +277,8 @@ static void set_up_vbus(struct fdt_usb *config, enum usb_init_type init)
}
}
-void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr)
+static void usbf_reset_controller(struct fdt_usb *config,
+ struct usb_ctlr *usbctlr)
{
/* Reset the USB controller with 2us delay */
reset_periph(config->periph_id, 2);
@@ -283,7 +298,7 @@ void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr)
setbits_le32(&usbctlr->susp_ctrl, UTMIP_PHY_ENB);
}
-static const unsigned *get_pll_timing(void)
+static const unsigned *get_pll_timing(struct fdt_usb_controller *controller)
{
const unsigned *timing;
@@ -330,6 +345,7 @@ static void init_phy_mux(struct fdt_usb *config, uint pts,
static int init_utmi_usb_controller(struct fdt_usb *config,
enum usb_init_type init)
{
+ struct fdt_usb_controller *controller;
u32 b_sess_valid_mask, val;
int loop_count;
const unsigned *timing;
@@ -362,11 +378,14 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
VBUS_SENSE_CTL_MASK,
VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT);
+ controller = &fdt_usb_controllers[config->type];
+ debug("controller=%p, type=%d\n", controller, config->type);
+
/*
* PLL Delay CONFIGURATION settings. The following parameters control
* the bring up of the plls.
*/
- timing = get_pll_timing();
+ timing = get_pll_timing(controller);
if (!controller->has_hostpc) {
val = readl(&usbctlr->utmip_misc_cfg1);
@@ -517,7 +536,7 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
udelay(1);
}
if (!loop_count)
- return -1;
+ return -ETIMEDOUT;
/* Disable ICUSB FS/LS transceiver */
clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
@@ -560,6 +579,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
int loop_count;
struct ulpi_viewport ulpi_vp;
struct usb_ctlr *usbctlr = config->reg;
+ int ret;
/* set up ULPI reference clock on pllp_out4 */
clock_enable(PERIPH_ID_DEV2_OUT);
@@ -605,9 +625,10 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
ulpi_vp.port_num = 0;
ulpi_vp.viewport_addr = (u32)&usbctlr->ulpi_viewport;
- if (ulpi_init(&ulpi_vp)) {
+ ret = ulpi_init(&ulpi_vp);
+ if (ret) {
printf("Tegra ULPI viewport init failed\n");
- return -1;
+ return ret;
}
ulpi_set_vbus(&ulpi_vp, 1, 1);
@@ -624,7 +645,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
udelay(1);
}
if (!loop_count)
- return -1;
+ return -ETIMEDOUT;
clrbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR);
return 0;
@@ -635,7 +656,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
{
printf("No code to set up ULPI controller, please enable"
"CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT");
- return -1;
+ return -ENOSYS;
}
#endif
@@ -662,7 +683,7 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
else {
debug("%s: Cannot decode dr_mode '%s'\n", __func__,
mode);
- return -FDT_ERR_NOTFOUND;
+ return -EINVAL;
}
} else {
config->dr_mode = DR_MODE_HOST;
@@ -674,12 +695,10 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
config->enabled = fdtdec_get_is_enabled(blob, node);
config->has_legacy_mode = fdtdec_get_bool(blob, node,
"nvidia,has-legacy-mode");
- if (config->has_legacy_mode)
- port_addr_clear_csc = (unsigned long)config->reg;
config->periph_id = clock_decode_periph_id(blob, node);
if (config->periph_id == PERIPH_ID_NONE) {
debug("%s: Missing/invalid peripheral ID\n", __func__);
- return -FDT_ERR_NOTFOUND;
+ return -EINVAL;
}
gpio_request_by_name_nodev(blob, node, "nvidia,vbus-gpio", 0,
&config->vbus_gpio, GPIOD_IS_OUT);
@@ -695,16 +714,101 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
return 0;
}
+int usb_common_init(struct fdt_usb *config, enum usb_init_type init)
+{
+ int ret = 0;
+
+ switch (init) {
+ case USB_INIT_HOST:
+ switch (config->dr_mode) {
+ case DR_MODE_HOST:
+ case DR_MODE_OTG:
+ break;
+ default:
+ printf("tegrausb: Invalid dr_mode %d for host mode\n",
+ config->dr_mode);
+ return -1;
+ }
+ break;
+ case USB_INIT_DEVICE:
+ if (config->periph_id != PERIPH_ID_USBD) {
+ printf("tegrausb: Device mode only supported on first USB controller\n");
+ return -1;
+ }
+ if (!config->utmi) {
+ printf("tegrausb: Device mode only supported with UTMI PHY\n");
+ return -1;
+ }
+ switch (config->dr_mode) {
+ case DR_MODE_DEVICE:
+ case DR_MODE_OTG:
+ break;
+ default:
+ printf("tegrausb: Invalid dr_mode %d for device mode\n",
+ config->dr_mode);
+ return -1;
+ }
+ break;
+ default:
+ printf("tegrausb: Unknown USB_INIT_* %d\n", init);
+ return -1;
+ }
+
+#ifndef CONFIG_DM_USB
+ /* skip init, if the port is already initialized */
+ if (config->initialized && config->init_type == init)
+ return 0;
+#endif
+
+ debug("%d, %d\n", config->utmi, config->ulpi);
+ if (config->utmi)
+ ret = init_utmi_usb_controller(config, init);
+ else if (config->ulpi)
+ ret = init_ulpi_usb_controller(config, init);
+ if (ret)
+ return ret;
+
+ set_up_vbus(config, init);
+
+ config->init_type = init;
+
+ return 0;
+}
+
+void usb_common_uninit(struct fdt_usb *priv)
+{
+ struct usb_ctlr *usbctlr;
+
+ usbctlr = priv->reg;
+
+ /* Stop controller */
+ writel(0, &usbctlr->usb_cmd);
+ udelay(1000);
+
+ /* Initiate controller reset */
+ writel(2, &usbctlr->usb_cmd);
+ udelay(1000);
+}
+
+static const struct ehci_ops tegra_ehci_ops = {
+ .set_usb_mode = tegra_ehci_set_usbmode,
+ .get_port_speed = tegra_ehci_get_port_speed,
+ .powerup_fixup = tegra_ehci_powerup_fixup,
+};
+
+#ifndef CONFIG_DM_USB
/*
* process_usb_nodes() - Process a list of USB nodes, adding them to our list
* of USB ports.
* @blob: fdt blob
* @node_list: list of nodes to process (any <=0 are ignored)
* @count: number of nodes to process
+ * @id: controller type (enum usb_ctlr_type)
*
* Return: 0 - ok, -1 - error
*/
-static int process_usb_nodes(const void *blob, int node_list[], int count)
+static int process_usb_nodes(const void *blob, int node_list[], int count,
+ enum usb_ctlr_type id)
{
struct fdt_usb config;
int node, i;
@@ -728,9 +832,11 @@ static int process_usb_nodes(const void *blob, int node_list[], int count)
return -1;
}
if (!clk_done) {
- config_clock(get_pll_timing());
+ config_clock(get_pll_timing(
+ &fdt_usb_controllers[id]));
clk_done = 1;
}
+ config.type = id;
config.initialized = 0;
/* add new USB port to the list of available ports */
@@ -747,20 +853,17 @@ int usb_process_devicetree(const void *blob)
int i;
for (i = 0; i < ARRAY_SIZE(fdt_usb_controllers); i++) {
- controller = &fdt_usb_controllers[i];
-
count = fdtdec_find_aliases_for_id(blob, "usb",
- controller->compat, node_list, USB_PORTS_MAX);
+ fdt_usb_controllers[i].compat, node_list,
+ USB_PORTS_MAX);
if (count) {
- err = process_usb_nodes(blob, node_list, count);
+ err = process_usb_nodes(blob, node_list, count, i);
if (err)
printf("%s: Error processing USB node!\n",
__func__);
return err;
}
}
- if (i == ARRAY_SIZE(fdt_usb_controllers))
- controller = NULL;
return err;
}
@@ -780,68 +883,22 @@ int ehci_hcd_init(int index, enum usb_init_type init,
{
struct fdt_usb *config;
struct usb_ctlr *usbctlr;
+ int ret;
if (index >= port_count)
return -1;
config = &port[index];
+ ehci_set_controller_priv(index, config, &tegra_ehci_ops);
- switch (init) {
- case USB_INIT_HOST:
- switch (config->dr_mode) {
- case DR_MODE_HOST:
- case DR_MODE_OTG:
- break;
- default:
- printf("tegrausb: Invalid dr_mode %d for host mode\n",
- config->dr_mode);
- return -1;
- }
- break;
- case USB_INIT_DEVICE:
- if (config->periph_id != PERIPH_ID_USBD) {
- printf("tegrausb: Device mode only supported on first USB controller\n");
- return -1;
- }
- if (!config->utmi) {
- printf("tegrausb: Device mode only supported with UTMI PHY\n");
- return -1;
- }
- switch (config->dr_mode) {
- case DR_MODE_DEVICE:
- case DR_MODE_OTG:
- break;
- default:
- printf("tegrausb: Invalid dr_mode %d for device mode\n",
- config->dr_mode);
- return -1;
- }
- break;
- default:
- printf("tegrausb: Unknown USB_INIT_* %d\n", init);
- return -1;
- }
-
- /* skip init, if the port is already initialized */
- if (config->initialized && config->init_type == init)
- goto success;
-
- if (config->utmi && init_utmi_usb_controller(config, init)) {
- printf("tegrausb: Cannot init port %d\n", index);
- return -1;
- }
-
- if (config->ulpi && init_ulpi_usb_controller(config, init)) {
+ ret = usb_common_init(config, init);
+ if (ret) {
printf("tegrausb: Cannot init port %d\n", index);
- return -1;
+ return ret;
}
- set_up_vbus(config, init);
-
config->initialized = 1;
- config->init_type = init;
-success:
usbctlr = config->reg;
*hccr = (struct ehci_hccr *)&usbctlr->cap_length;
*hcor = (struct ehci_hcor *)&usbctlr->usb_cmd;
@@ -854,19 +911,80 @@ success:
*/
int ehci_hcd_stop(int index)
{
- struct usb_ctlr *usbctlr;
+ usb_common_uninit(&port[index]);
- usbctlr = port[index].reg;
+ port[index].initialized = 0;
- /* Stop controller */
- writel(0, &usbctlr->usb_cmd);
- udelay(1000);
+ return 0;
+}
+#endif /* !CONFIG_DM_USB */
- /* Initiate controller reset */
- writel(2, &usbctlr->usb_cmd);
- udelay(1000);
+#ifdef CONFIG_DM_USB
+static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
+{
+ struct fdt_usb *priv = dev_get_priv(dev);
+ int ret;
- port[index].initialized = 0;
+ ret = fdt_decode_usb(gd->fdt_blob, dev->of_offset, priv);
+ if (ret)
+ return ret;
+
+ priv->type = dev_get_driver_data(dev);
+
+ return 0;
+}
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+ struct usb_platdata *plat = dev_get_platdata(dev);
+ struct fdt_usb *priv = dev_get_priv(dev);
+ struct ehci_hccr *hccr;
+ struct ehci_hcor *hcor;
+ static bool clk_done;
+ int ret;
+
+ ret = usb_common_init(priv, plat->init_type);
+ if (ret)
+ return ret;
+ hccr = (struct ehci_hccr *)&priv->reg->cap_length;
+ hcor = (struct ehci_hcor *)&priv->reg->usb_cmd;
+ if (!clk_done) {
+ config_clock(get_pll_timing(&fdt_usb_controllers[priv->type]));
+ clk_done = true;
+ }
+
+ return ehci_register(dev, hccr, hcor, &tegra_ehci_ops, 0,
+ plat->init_type);
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+ int ret;
+
+ ret = ehci_deregister(dev);
+ if (ret)
+ return ret;
return 0;
}
+
+static const struct udevice_id ehci_usb_ids[] = {
+ { .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
+ { .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
+ { .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
+ { }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+ .name = "ehci_tegra",
+ .id = UCLASS_USB,
+ .of_match = ehci_usb_ids,
+ .ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+ .probe = ehci_usb_probe,
+ .remove = ehci_usb_remove,
+ .ops = &ehci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+ .priv_auto_alloc_size = sizeof(struct fdt_usb),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 79aecd414e..774282d287 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -238,6 +238,22 @@ struct QH {
};
};
+/* Tweak flags for EHCI, used to control operation */
+enum {
+ /* don't use or_configflag in init */
+ EHCI_TWEAK_NO_INIT_CF = 1 << 0,
+};
+
+struct ehci_ctrl;
+
+struct ehci_ops {
+ void (*set_usb_mode)(struct ehci_ctrl *ctrl);
+ int (*get_port_speed)(struct ehci_ctrl *ctrl, uint32_t reg);
+ void (*powerup_fixup)(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+ uint32_t *reg);
+ uint32_t *(*get_portsc_register)(struct ehci_ctrl *ctrl, int port);
+};
+
struct ehci_ctrl {
struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
struct ehci_hcor *hcor;
@@ -248,11 +264,42 @@ struct ehci_ctrl {
uint32_t *periodic_list;
int periodic_schedules;
int ntds;
+ struct ehci_ops ops;
+ void *priv; /* client's private data */
};
+/**
+ * ehci_set_controller_info() - Set up private data for the controller
+ *
+ * This function can be called in ehci_hcd_init() to tell the EHCI layer
+ * about the controller's private data pointer. Then in the above functions
+ * this can be accessed given the struct ehci_ctrl pointer. Also special
+ * EHCI operation methods can be provided if required
+ *
+ * @index: Controller number to set
+ * @priv: Controller pointer
+ * @ops: Controller operations, or NULL to use default
+ */
+void ehci_set_controller_priv(int index, void *priv,
+ const struct ehci_ops *ops);
+
+/**
+ * ehci_get_controller_priv() - Get controller private data
+ *
+ * @index Controller number to get
+ * @return controller pointer for this index
+ */
+void *ehci_get_controller_priv(int index);
+
/* Low level init functions */
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor);
int ehci_hcd_stop(int index);
+int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
+ struct ehci_hcor *hcor, const struct ehci_ops *ops,
+ uint tweaks, enum usb_init_type init);
+int ehci_deregister(struct udevice *dev);
+extern struct dm_usb_ops ehci_usb_ops;
+
#endif /* USB_EHCI_H */
diff --git a/drivers/usb/host/usb-sandbox.c b/drivers/usb/host/usb-sandbox.c
new file mode 100644
index 0000000000..c5f9822040
--- /dev/null
+++ b/drivers/usb/host/usb-sandbox.c
@@ -0,0 +1,117 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void usbmon_trace(struct udevice *bus, ulong pipe,
+ struct devrequest *setup, struct udevice *emul)
+{
+ static const char types[] = "ZICB";
+ int type;
+
+ type = (pipe & USB_PIPE_TYPE_MASK) >> USB_PIPE_TYPE_SHIFT;
+ debug("0 0 S %c%c:%d:%03ld:%ld", types[type],
+ pipe & USB_DIR_IN ? 'i' : 'o',
+ bus->seq,
+ (pipe & USB_PIPE_DEV_MASK) >> USB_PIPE_DEV_SHIFT,
+ (pipe & USB_PIPE_EP_MASK) >> USB_PIPE_EP_SHIFT);
+ if (setup) {
+ debug(" s %02x %02x %04x %04x %04x", setup->requesttype,
+ setup->request, setup->value, setup->index,
+ setup->length);
+ }
+ debug(" %s", emul ? emul->name : "(no emul found)");
+
+ debug("\n");
+}
+
+static int sandbox_submit_control(struct udevice *bus,
+ struct usb_device *udev,
+ unsigned long pipe,
+ void *buffer, int length,
+ struct devrequest *setup)
+{
+ struct udevice *emul;
+ int ret;
+
+ /* Just use child of dev as emulator? */
+ debug("%s: bus=%s\n", __func__, bus->name);
+ ret = usb_emul_find(bus, pipe, &emul);
+ usbmon_trace(bus, pipe, setup, emul);
+ if (ret)
+ return ret;
+ ret = usb_emul_control(emul, udev, pipe, buffer, length, setup);
+ if (ret < 0) {
+ debug("ret=%d\n", ret);
+ udev->status = ret;
+ udev->act_len = 0;
+ } else {
+ udev->status = 0;
+ udev->act_len = ret;
+ }
+
+ return ret;
+}
+
+static int sandbox_submit_bulk(struct udevice *bus, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length)
+{
+ struct udevice *emul;
+ int ret;
+
+ /* Just use child of dev as emulator? */
+ debug("%s: bus=%s\n", __func__, bus->name);
+ ret = usb_emul_find(bus, pipe, &emul);
+ usbmon_trace(bus, pipe, NULL, emul);
+ if (ret)
+ return ret;
+ ret = usb_emul_bulk(emul, udev, pipe, buffer, length);
+ if (ret < 0) {
+ debug("ret=%d\n", ret);
+ udev->status = ret;
+ udev->act_len = 0;
+ } else {
+ udev->status = 0;
+ udev->act_len = ret;
+ }
+
+ return ret;
+}
+
+static int sandbox_alloc_device(struct udevice *dev, struct usb_device *udev)
+{
+ return 0;
+}
+
+static int sandbox_usb_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct dm_usb_ops sandbox_usb_ops = {
+ .control = sandbox_submit_control,
+ .bulk = sandbox_submit_bulk,
+ .alloc_device = sandbox_alloc_device,
+};
+
+static const struct udevice_id sandbox_usb_ids[] = {
+ { .compatible = "sandbox,usb" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_sandbox) = {
+ .name = "usb_sandbox",
+ .id = UCLASS_USB,
+ .of_match = sandbox_usb_ids,
+ .probe = sandbox_usb_probe,
+ .ops = &sandbox_usb_ops,
+};
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
new file mode 100644
index 0000000000..714bc0e958
--- /dev/null
+++ b/drivers/usb/host/usb-uclass.c
@@ -0,0 +1,645 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * usb_match_device() modified from Linux kernel v4.0.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <usb.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <dm/uclass-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern bool usb_started; /* flag for the started/stopped USB status */
+static bool asynch_allowed;
+
+int usb_disable_asynch(int disable)
+{
+ int old_value = asynch_allowed;
+
+ asynch_allowed = !disable;
+ return old_value;
+}
+
+int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+ int length, int interval)
+{
+ struct udevice *bus = udev->controller_dev;
+ struct dm_usb_ops *ops = usb_get_ops(bus);
+
+ if (!ops->interrupt)
+ return -ENOSYS;
+
+ return ops->interrupt(bus, udev, pipe, buffer, length, interval);
+}
+
+int submit_control_msg(struct usb_device *udev, unsigned long pipe,
+ void *buffer, int length, struct devrequest *setup)
+{
+ struct udevice *bus = udev->controller_dev;
+ struct dm_usb_ops *ops = usb_get_ops(bus);
+
+ if (!ops->control)
+ return -ENOSYS;
+
+ return ops->control(bus, udev, pipe, buffer, length, setup);
+}
+
+int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+ int length)
+{
+ struct udevice *bus = udev->controller_dev;
+ struct dm_usb_ops *ops = usb_get_ops(bus);
+
+ if (!ops->bulk)
+ return -ENOSYS;
+
+ return ops->bulk(bus, udev, pipe, buffer, length);
+}
+
+int usb_alloc_device(struct usb_device *udev)
+{
+ struct udevice *bus = udev->controller_dev;
+ struct dm_usb_ops *ops = usb_get_ops(bus);
+
+ /* This is only requird by some controllers - current XHCI */
+ if (!ops->alloc_device)
+ return 0;
+
+ return ops->alloc_device(bus, udev);
+}
+
+int usb_stop(void)
+{
+ struct udevice *bus;
+ struct uclass *uc;
+ int err = 0, ret;
+
+ /* De-activate any devices that have been activated */
+ ret = uclass_get(UCLASS_USB, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(bus, uc) {
+ ret = device_remove(bus);
+ if (ret && !err)
+ err = ret;
+ }
+
+#ifdef CONFIG_SANDBOX
+ struct udevice *dev;
+
+ /* Reset all enulation devices */
+ ret = uclass_get(UCLASS_USB_EMUL, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc)
+ usb_emul_reset(dev);
+#endif
+ usb_stor_reset();
+ usb_hub_reset();
+ usb_started = 0;
+
+ return err;
+}
+
+static int usb_scan_bus(struct udevice *bus, bool recurse)
+{
+ struct usb_bus_priv *priv;
+ struct udevice *dev;
+ int ret;
+
+ priv = dev_get_uclass_priv(bus);
+
+ assert(recurse); /* TODO: Support non-recusive */
+
+ ret = usb_scan_device(bus, 0, USB_SPEED_FULL, &dev);
+ if (ret)
+ return ret;
+
+ return priv->next_addr;
+}
+
+int usb_init(void)
+{
+ int controllers_initialized = 0;
+ struct udevice *bus;
+ struct uclass *uc;
+ int count = 0;
+ int ret;
+
+ asynch_allowed = 1;
+ usb_hub_reset();
+
+ ret = uclass_get(UCLASS_USB, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(bus, uc) {
+ /* init low_level USB */
+ count++;
+ printf("USB");
+ printf("%d: ", bus->seq);
+ ret = device_probe(bus);
+ if (ret == -ENODEV) { /* No such device. */
+ puts("Port not available.\n");
+ controllers_initialized++;
+ continue;
+ }
+
+ if (ret) { /* Other error. */
+ printf("probe failed, error %d\n", ret);
+ continue;
+ }
+ /*
+ * lowlevel init is OK, now scan the bus for devices
+ * i.e. search HUBs and configure them
+ */
+ controllers_initialized++;
+ printf("scanning bus %d for devices... ", bus->seq);
+ debug("\n");
+ ret = usb_scan_bus(bus, true);
+ if (ret < 0)
+ printf("failed, error %d\n", ret);
+ else if (!ret)
+ printf("No USB Device found\n");
+ else
+ printf("%d USB Device(s) found\n", ret);
+ usb_started = true;
+ }
+
+ debug("scan end\n");
+ /* if we were not able to find at least one working bus, bail out */
+ if (!count)
+ printf("No controllers found\n");
+ else if (controllers_initialized == 0)
+ printf("USB error: all controllers failed lowlevel init\n");
+
+ return usb_started ? 0 : -1;
+}
+
+int usb_reset_root_port(void)
+{
+ return -ENOSYS;
+}
+
+static struct usb_device *find_child_devnum(struct udevice *parent, int devnum)
+{
+ struct usb_device *udev;
+ struct udevice *dev;
+
+ if (!device_active(parent))
+ return NULL;
+ udev = dev_get_parentdata(parent);
+ if (udev->devnum == devnum)
+ return udev;
+
+ for (device_find_first_child(parent, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ udev = find_child_devnum(dev, devnum);
+ if (udev)
+ return udev;
+ }
+
+ return NULL;
+}
+
+struct usb_device *usb_get_dev_index(struct udevice *bus, int index)
+{
+ struct udevice *hub;
+ int devnum = index + 1; /* Addresses are allocated from 1 on USB */
+
+ device_find_first_child(bus, &hub);
+ if (device_get_uclass_id(hub) == UCLASS_USB_HUB)
+ return find_child_devnum(hub, devnum);
+
+ return NULL;
+}
+
+int usb_post_bind(struct udevice *dev)
+{
+ /* Scan the bus for devices */
+ return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+int usb_port_reset(struct usb_device *parent, int portnr)
+{
+ unsigned short portstatus;
+ int ret;
+
+ debug("%s: start\n", __func__);
+
+ if (parent) {
+ /* reset the port for the second time */
+ assert(portnr > 0);
+ debug("%s: reset %d\n", __func__, portnr - 1);
+ ret = legacy_hub_port_reset(parent, portnr - 1, &portstatus);
+ if (ret < 0) {
+ printf("\n Couldn't reset port %i\n", portnr);
+ return ret;
+ }
+ } else {
+ debug("%s: reset root\n", __func__);
+ usb_reset_root_port();
+ }
+
+ return 0;
+}
+
+int usb_legacy_port_reset(struct usb_device *parent, int portnr)
+{
+ return usb_port_reset(parent, portnr);
+}
+
+int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
+{
+ struct usb_platdata *plat;
+ struct udevice *dev;
+ int ret;
+
+ /* Find the old device and remove it */
+ ret = uclass_find_device_by_seq(UCLASS_USB, 0, true, &dev);
+ if (ret)
+ return ret;
+ ret = device_remove(dev);
+ if (ret)
+ return ret;
+
+ plat = dev_get_platdata(dev);
+ plat->init_type = USB_INIT_DEVICE;
+ ret = device_probe(dev);
+ if (ret)
+ return ret;
+ *ctlrp = dev_get_priv(dev);
+
+ return 0;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_device(const struct usb_device_descriptor *desc,
+ const struct usb_device_id *id)
+{
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ id->idVendor != le16_to_cpu(desc->idVendor))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+ id->idProduct != le16_to_cpu(desc->idProduct))
+ return 0;
+
+ /* No need to test id->bcdDevice_lo != 0, since 0 is never
+ greater than any unsigned number. */
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+ (id->bcdDevice_lo > le16_to_cpu(desc->bcdDevice)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+ (id->bcdDevice_hi < le16_to_cpu(desc->bcdDevice)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+ (id->bDeviceClass != desc->bDeviceClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+ (id->bDeviceSubClass != desc->bDeviceSubClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+ (id->bDeviceProtocol != desc->bDeviceProtocol))
+ return 0;
+
+ return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id_intf(const struct usb_device_descriptor *desc,
+ const struct usb_interface_descriptor *int_desc,
+ const struct usb_device_id *id)
+{
+ /* The interface class, subclass, protocol and number should never be
+ * checked for a match if the device class is Vendor Specific,
+ * unless the match record specifies the Vendor ID. */
+ if (desc->bDeviceClass == USB_CLASS_VENDOR_SPEC &&
+ !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+ USB_DEVICE_ID_MATCH_INT_NUMBER)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
+ (id->bInterfaceClass != int_desc->bInterfaceClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
+ (id->bInterfaceSubClass != int_desc->bInterfaceSubClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
+ (id->bInterfaceProtocol != int_desc->bInterfaceProtocol))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+ (id->bInterfaceNumber != int_desc->bInterfaceNumber))
+ return 0;
+
+ return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id(struct usb_device_descriptor *desc,
+ struct usb_interface_descriptor *int_desc,
+ const struct usb_device_id *id)
+{
+ if (!usb_match_device(desc, id))
+ return 0;
+
+ return usb_match_one_id_intf(desc, int_desc, id);
+}
+
+/**
+ * usb_find_and_bind_driver() - Find and bind the right USB driver
+ *
+ * This only looks at certain fields in the descriptor.
+ */
+static int usb_find_and_bind_driver(struct udevice *parent,
+ struct usb_device_descriptor *desc,
+ struct usb_interface_descriptor *iface,
+ int bus_seq, int devnum,
+ struct udevice **devp)
+{
+ struct usb_driver_entry *start, *entry;
+ int n_ents;
+ int ret;
+ char name[30], *str;
+
+ *devp = NULL;
+ debug("%s: Searching for driver\n", __func__);
+ start = ll_entry_start(struct usb_driver_entry, usb_driver_entry);
+ n_ents = ll_entry_count(struct usb_driver_entry, usb_driver_entry);
+ for (entry = start; entry != start + n_ents; entry++) {
+ const struct usb_device_id *id;
+ struct udevice *dev;
+ const struct driver *drv;
+ struct usb_dev_platdata *plat;
+
+ for (id = entry->match; id->match_flags; id++) {
+ if (!usb_match_one_id(desc, iface, id))
+ continue;
+
+ drv = entry->driver;
+ /*
+ * We could pass the descriptor to the driver as
+ * platdata (instead of NULL) and allow its bind()
+ * method to return -ENOENT if it doesn't support this
+ * device. That way we could continue the search to
+ * find another driver. For now this doesn't seem
+ * necesssary, so just bind the first match.
+ */
+ ret = device_bind(parent, drv, drv->name, NULL, -1,
+ &dev);
+ if (ret)
+ goto error;
+ debug("%s: Match found: %s\n", __func__, drv->name);
+ dev->driver_data = id->driver_info;
+ plat = dev_get_parent_platdata(dev);
+ plat->id = *id;
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ /* Bind a generic driver so that the device can be used */
+ snprintf(name, sizeof(name), "generic_bus_%x_dev_%x", bus_seq, devnum);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ ret = device_bind_driver(parent, "usb_dev_generic_drv", str, devp);
+
+error:
+ debug("%s: No match found: %d\n", __func__, ret);
+ return ret;
+}
+
+/**
+ * usb_find_child() - Find an existing device which matches our needs
+ *
+ *
+ */
+static int usb_find_child(struct udevice *parent,
+ struct usb_device_descriptor *desc,
+ struct usb_interface_descriptor *iface,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+ for (device_find_first_child(parent, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+
+ /* If this device is already in use, skip it */
+ if (device_active(dev))
+ continue;
+ debug(" %s: name='%s', plat=%d, desc=%d\n", __func__,
+ dev->name, plat->id.bDeviceClass, desc->bDeviceClass);
+ if (usb_match_one_id(desc, iface, &plat->id)) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int usb_scan_device(struct udevice *parent, int port,
+ enum usb_device_speed speed, struct udevice **devp)
+{
+ struct udevice *dev;
+ bool created = false;
+ struct usb_dev_platdata *plat;
+ struct usb_bus_priv *priv;
+ struct usb_device *parent_udev;
+ int ret;
+ ALLOC_CACHE_ALIGN_BUFFER(struct usb_device, udev, 1);
+ struct usb_interface_descriptor *iface = &udev->config.if_desc[0].desc;
+
+ *devp = NULL;
+ memset(udev, '\0', sizeof(*udev));
+ ret = usb_get_bus(parent, &udev->controller_dev);
+ if (ret)
+ return ret;
+ priv = dev_get_uclass_priv(udev->controller_dev);
+
+ /*
+ * Somewhat nasty, this. We create a local device and use the normal
+ * USB stack to read its descriptor. Then we know what type of device
+ * to create for real.
+ *
+ * udev->dev is set to the parent, since we don't have a real device
+ * yet. The USB stack should not access udev.dev anyway, except perhaps
+ * to find the controller, and the controller will either be @parent,
+ * or some parent of @parent.
+ *
+ * Another option might be to create the device as a generic USB
+ * device, then morph it into the correct one when we know what it
+ * should be. This means that a generic USB device would morph into
+ * a network controller, or a USB flash stick, for example. However,
+ * we don't support such morphing and it isn't clear that it would
+ * be easy to do.
+ *
+ * Yet another option is to split out the USB stack parts of udev
+ * into something like a 'struct urb' (as Linux does) which can exist
+ * independently of any device. This feels cleaner, but calls for quite
+ * a big change to the USB stack.
+ *
+ * For now, the approach is to set up an empty udev, read its
+ * descriptor and assign it an address, then bind a real device and
+ * stash the resulting information into the device's parent
+ * platform data. Then when we probe it, usb_child_pre_probe() is called
+ * and it will pull the information out of the stash.
+ */
+ udev->dev = parent;
+ udev->speed = speed;
+ udev->devnum = priv->next_addr + 1;
+ udev->portnr = port;
+ debug("Calling usb_setup_device(), portnr=%d\n", udev->portnr);
+ parent_udev = device_get_uclass_id(parent) == UCLASS_USB_HUB ?
+ dev_get_parentdata(parent) : NULL;
+ ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev, port);
+ debug("read_descriptor for '%s': ret=%d\n", parent->name, ret);
+ if (ret)
+ return ret;
+ ret = usb_find_child(parent, &udev->descriptor, iface, &dev);
+ debug("** usb_find_child returns %d\n", ret);
+ if (ret) {
+ if (ret != -ENOENT)
+ return ret;
+ ret = usb_find_and_bind_driver(parent, &udev->descriptor, iface,
+ udev->controller_dev->seq,
+ udev->devnum, &dev);
+ if (ret)
+ return ret;
+ created = true;
+ }
+ plat = dev_get_parent_platdata(dev);
+ debug("%s: Probing '%s', plat=%p\n", __func__, dev->name, plat);
+ plat->devnum = udev->devnum;
+ plat->speed = udev->speed;
+ plat->slot_id = udev->slot_id;
+ plat->portnr = port;
+ debug("** device '%s': stashing slot_id=%d\n", dev->name,
+ plat->slot_id);
+ priv->next_addr++;
+ ret = device_probe(dev);
+ if (ret) {
+ debug("%s: Device '%s' probe failed\n", __func__, dev->name);
+ priv->next_addr--;
+ if (created)
+ device_unbind(dev);
+ return ret;
+ }
+ *devp = dev;
+
+ return 0;
+}
+
+int usb_child_post_bind(struct udevice *dev)
+{
+ struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+ const void *blob = gd->fdt_blob;
+ int val;
+
+ if (dev->of_offset == -1)
+ return 0;
+
+ /* We only support matching a few things */
+ val = fdtdec_get_int(blob, dev->of_offset, "usb,device-class", -1);
+ if (val != -1) {
+ plat->id.match_flags |= USB_DEVICE_ID_MATCH_DEV_CLASS;
+ plat->id.bDeviceClass = val;
+ }
+ val = fdtdec_get_int(blob, dev->of_offset, "usb,interface-class", -1);
+ if (val != -1) {
+ plat->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
+ plat->id.bInterfaceClass = val;
+ }
+
+ return 0;
+}
+
+int usb_get_bus(struct udevice *dev, struct udevice **busp)
+{
+ struct udevice *bus;
+
+ *busp = NULL;
+ for (bus = dev; bus && device_get_uclass_id(bus) != UCLASS_USB; )
+ bus = bus->parent;
+ if (!bus) {
+ /* By design this cannot happen */
+ assert(bus);
+ debug("USB HUB '%s' does not have a controller\n", dev->name);
+ return -EXDEV;
+ }
+ *busp = bus;
+
+ return 0;
+}
+
+int usb_child_pre_probe(struct udevice *dev)
+{
+ struct udevice *bus;
+ struct usb_device *udev = dev_get_parentdata(dev);
+ struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+ int ret;
+
+ ret = usb_get_bus(dev, &bus);
+ if (ret)
+ return ret;
+ udev->controller_dev = bus;
+ udev->dev = dev;
+ udev->devnum = plat->devnum;
+ udev->slot_id = plat->slot_id;
+ udev->portnr = plat->portnr;
+ udev->speed = plat->speed;
+ debug("** device '%s': getting slot_id=%d\n", dev->name, plat->slot_id);
+
+ ret = usb_select_config(udev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+UCLASS_DRIVER(usb) = {
+ .id = UCLASS_USB,
+ .name = "usb",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .post_bind = usb_post_bind,
+ .per_child_auto_alloc_size = sizeof(struct usb_device),
+ .per_device_auto_alloc_size = sizeof(struct usb_bus_priv),
+ .child_post_bind = usb_child_post_bind,
+ .child_pre_probe = usb_child_pre_probe,
+ .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
+};
+
+UCLASS_DRIVER(usb_dev_generic) = {
+ .id = UCLASS_USB_DEV_GENERIC,
+ .name = "usb_dev_generic",
+};
+
+U_BOOT_DRIVER(usb_dev_generic_drv) = {
+ .id = UCLASS_USB_DEV_GENERIC,
+ .name = "usb_dev_generic_drv",
+};
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index 3f86fdca89..23c7ecc5d8 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -14,6 +14,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <fdtdec.h>
#include <libfdt.h>
#include <malloc.h>
@@ -32,20 +33,76 @@
/* Declare global data pointer */
DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_DM_USB
+struct exynos_xhci_platdata {
+ fdt_addr_t hcd_base;
+ fdt_addr_t phy_base;
+ struct gpio_desc vbus_gpio;
+};
+#endif
+
/**
* Contains pointers to register base addresses
* for the usb controller.
*/
struct exynos_xhci {
+#ifdef CONFIG_DM_USB
+ struct usb_platdata usb_plat;
+#endif
+ struct xhci_ctrl ctrl;
struct exynos_usb3_phy *usb3_phy;
struct xhci_hccr *hcd;
struct dwc3 *dwc3_reg;
+#ifndef CONFIG_DM_USB
struct gpio_desc vbus_gpio;
+#endif
};
+#ifndef CONFIG_DM_USB
static struct exynos_xhci exynos;
+#endif
-#ifdef CONFIG_OF_CONTROL
+#ifdef CONFIG_DM_USB
+static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
+{
+ struct exynos_xhci_platdata *plat = dev_get_platdata(dev);
+ const void *blob = gd->fdt_blob;
+ unsigned int node;
+ int depth;
+
+ /*
+ * Get the base address for XHCI controller from the device node
+ */
+ plat->hcd_base = fdtdec_get_addr(blob, dev->of_offset, "reg");
+ if (plat->hcd_base == FDT_ADDR_T_NONE) {
+ debug("Can't get the XHCI register base address\n");
+ return -ENXIO;
+ }
+
+ depth = 0;
+ node = fdtdec_next_compatible_subnode(blob, dev->of_offset,
+ COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth);
+ if (node <= 0) {
+ debug("XHCI: Can't get device node for usb3-phy controller\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Get the base address for usbphy from the device node
+ */
+ plat->phy_base = fdtdec_get_addr(blob, node, "reg");
+ if (plat->phy_base == FDT_ADDR_T_NONE) {
+ debug("Can't get the usbphy register address\n");
+ return -ENXIO;
+ }
+
+ /* Vbus gpio */
+ gpio_request_by_name(dev, "samsung,vbus-gpio", 0,
+ &plat->vbus_gpio, GPIOD_IS_OUT);
+
+ return 0;
+}
+#else
static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
{
fdt_addr_t addr;
@@ -283,6 +340,7 @@ static void exynos_xhci_core_exit(struct exynos_xhci *exynos)
exynos5_usb3_phy_exit(exynos->usb3_phy);
}
+#ifndef CONFIG_DM_USB
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
{
struct exynos_xhci *ctx = &exynos;
@@ -326,3 +384,63 @@ void xhci_hcd_stop(int index)
exynos_xhci_core_exit(ctx);
}
+#endif
+
+#ifdef CONFIG_DM_USB
+static int xhci_usb_probe(struct udevice *dev)
+{
+ struct exynos_xhci_platdata *plat = dev_get_platdata(dev);
+ struct exynos_xhci *ctx = dev_get_priv(dev);
+ struct xhci_hcor *hcor;
+ int ret;
+
+ ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
+ ctx->usb3_phy = (struct exynos_usb3_phy *)plat->phy_base;
+ ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
+ hcor = (struct xhci_hcor *)((uint32_t)ctx->hcd +
+ HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)));
+
+ /* setup the Vbus gpio here */
+ if (dm_gpio_is_valid(&plat->vbus_gpio))
+ dm_gpio_set_value(&plat->vbus_gpio, 1);
+
+ ret = exynos_xhci_core_init(ctx);
+ if (ret) {
+ puts("XHCI: failed to initialize controller\n");
+ return -EINVAL;
+ }
+
+ return xhci_register(dev, ctx->hcd, hcor);
+}
+
+static int xhci_usb_remove(struct udevice *dev)
+{
+ struct exynos_xhci *ctx = dev_get_priv(dev);
+ int ret;
+
+ ret = xhci_deregister(dev);
+ if (ret)
+ return ret;
+ exynos_xhci_core_exit(ctx);
+
+ return 0;
+}
+
+static const struct udevice_id xhci_usb_ids[] = {
+ { .compatible = "samsung,exynos5250-xhci" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+ .name = "xhci_exynos",
+ .id = UCLASS_USB,
+ .of_match = xhci_usb_ids,
+ .ofdata_to_platdata = xhci_usb_ofdata_to_platdata,
+ .probe = xhci_usb_probe,
+ .remove = xhci_usb_remove,
+ .ops = &xhci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct exynos_xhci_platdata),
+ .priv_auto_alloc_size = sizeof(struct exynos_xhci),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 10f11cd547..37444526f7 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -15,6 +15,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <asm/byteorder.h>
#include <usb.h>
#include <malloc.h>
@@ -352,12 +353,10 @@ static struct xhci_container_ctx
* @param udev pointer to USB deivce structure
* @return 0 on success else -1 on failure
*/
-int xhci_alloc_virt_device(struct usb_device *udev)
+int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
{
u64 byte_64 = 0;
- unsigned int slot_id = udev->slot_id;
struct xhci_virt_device *virt_dev;
- struct xhci_ctrl *ctrl = udev->controller;
/* Slot ID 0 is reserved */
if (ctrl->devs[slot_id]) {
@@ -627,17 +626,16 @@ void xhci_slot_copy(struct xhci_ctrl *ctrl, struct xhci_container_ctx *in_ctx,
* @param udev pointer to the Device Data Structure
* @return returns negative value on failure else 0 on success
*/
-void xhci_setup_addressable_virt_dev(struct usb_device *udev)
+void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
+ int speed, int hop_portnr)
{
- struct usb_device *hop = udev;
struct xhci_virt_device *virt_dev;
struct xhci_ep_ctx *ep0_ctx;
struct xhci_slot_ctx *slot_ctx;
u32 port_num = 0;
u64 trb_64 = 0;
- struct xhci_ctrl *ctrl = udev->controller;
- virt_dev = ctrl->devs[udev->slot_id];
+ virt_dev = ctrl->devs[slot_id];
BUG_ON(!virt_dev);
@@ -648,7 +646,7 @@ void xhci_setup_addressable_virt_dev(struct usb_device *udev)
/* Only the control endpoint is valid - one endpoint context */
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | 0);
- switch (udev->speed) {
+ switch (speed) {
case USB_SPEED_SUPER:
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
break;
@@ -666,11 +664,7 @@ void xhci_setup_addressable_virt_dev(struct usb_device *udev)
BUG();
}
- /* Extract the root hub port number */
- if (hop->parent)
- while (hop->parent->parent)
- hop = hop->parent;
- port_num = hop->portnr;
+ port_num = hop_portnr;
debug("port_num = %d\n", port_num);
slot_ctx->dev_info2 |=
@@ -680,9 +674,9 @@ void xhci_setup_addressable_virt_dev(struct usb_device *udev)
/* Step 4 - ring already allocated */
/* Step 5 */
ep0_ctx->ep_info2 = cpu_to_le32(CTRL_EP << EP_TYPE_SHIFT);
- debug("SPEED = %d\n", udev->speed);
+ debug("SPEED = %d\n", speed);
- switch (udev->speed) {
+ switch (speed) {
case USB_SPEED_SUPER:
ep0_ctx->ep_info2 |= cpu_to_le32(((512 & MAX_PACKET_MASK) <<
MAX_PACKET_SHIFT));
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index f3759d4036..5a1391fbe3 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -353,7 +353,7 @@ static void giveback_first_trb(struct usb_device *udev, int ep_index,
int start_cycle,
struct xhci_generic_trb *start_trb)
{
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
/*
* Pass all the TRBs to the hardware at once and make sure this write
@@ -477,7 +477,7 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
*/
static void abort_td(struct usb_device *udev, int ep_index)
{
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring;
union xhci_trb *event;
u32 field;
@@ -554,7 +554,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
int start_cycle;
u32 field = 0;
u32 length_field = 0;
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
int slot_id = udev->slot_id;
int ep_index;
struct xhci_virt_device *virt_dev;
@@ -748,7 +748,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
u32 length_field;
u64 buf_64 = 0;
struct xhci_generic_trb *start_trb;
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
int slot_id = udev->slot_id;
int ep_index;
u32 trb_fields[4];
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index f8b5ce4c36..0b09643e09 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -21,6 +21,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <asm/byteorder.h>
#include <usb.h>
#include <malloc.h>
@@ -108,7 +109,25 @@ static struct descriptor {
},
};
+#ifndef CONFIG_DM_USB
static struct xhci_ctrl xhcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+#endif
+
+struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev)
+{
+#ifdef CONFIG_DM_USB
+ struct udevice *dev;
+
+ /* Find the USB controller */
+ for (dev = udev->dev;
+ device_get_uclass_id(dev) != UCLASS_USB;
+ dev = dev->parent)
+ ;
+ return dev_get_priv(dev);
+#else
+ return udev->controller;
+#endif
+}
/**
* Waits for as per specified amount of time
@@ -250,7 +269,7 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change)
{
struct xhci_container_ctx *in_ctx;
struct xhci_virt_device *virt_dev;
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
union xhci_trb *event;
virt_dev = ctrl->devs[udev->slot_id];
@@ -298,7 +317,7 @@ static int xhci_set_configuration(struct usb_device *udev)
int ep_index;
unsigned int dir;
unsigned int ep_type;
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
int num_of_ep;
int ep_flag = 0;
u64 trb_64 = 0;
@@ -379,10 +398,10 @@ static int xhci_set_configuration(struct usb_device *udev)
* @param udev pointer to the Device Data Structure
* @return 0 if successful else error code on failure
*/
-static int xhci_address_device(struct usb_device *udev)
+static int xhci_address_device(struct usb_device *udev, int root_portnr)
{
int ret = 0;
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
struct xhci_slot_ctx *slot_ctx;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_virt_device *virt_dev;
@@ -395,8 +414,9 @@ static int xhci_address_device(struct usb_device *udev)
* This is the first Set Address since device plug-in
* so setting up the slot context.
*/
- debug("Setting up addressable devices\n");
- xhci_setup_addressable_virt_dev(udev);
+ debug("Setting up addressable devices %p\n", ctrl->dcbaa);
+ xhci_setup_addressable_virt_dev(ctrl, udev->slot_id, udev->speed,
+ root_portnr);
ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
@@ -461,10 +481,10 @@ static int xhci_address_device(struct usb_device *udev)
* @param udev pointer to the Device Data Structure
* @return Returns 0 on succes else return error code on failure
*/
-int usb_alloc_device(struct usb_device *udev)
+int _xhci_alloc_device(struct usb_device *udev)
{
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
union xhci_trb *event;
- struct xhci_ctrl *ctrl = udev->controller;
int ret;
/*
@@ -486,7 +506,7 @@ int usb_alloc_device(struct usb_device *udev)
xhci_acknowledge_event(ctrl);
- ret = xhci_alloc_virt_device(udev);
+ ret = xhci_alloc_virt_device(ctrl, udev->slot_id);
if (ret < 0) {
/*
* TODO: Unsuccessful Address Device command shall leave
@@ -499,6 +519,13 @@ int usb_alloc_device(struct usb_device *udev)
return 0;
}
+#ifndef CONFIG_DM_USB
+int usb_alloc_device(struct usb_device *udev)
+{
+ return _xhci_alloc_device(udev);
+}
+#endif
+
/*
* Full speed devices may have a max packet size greater than 8 bytes, but the
* USB core doesn't know that until it reads the first 8 bytes of the
@@ -510,7 +537,7 @@ int usb_alloc_device(struct usb_device *udev)
*/
int xhci_check_maxpacket(struct usb_device *udev)
{
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
unsigned int slot_id = udev->slot_id;
int ep_index = 0; /* control endpoint */
struct xhci_container_ctx *in_ctx;
@@ -640,7 +667,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe,
int len, srclen;
uint32_t reg;
volatile uint32_t *status_reg;
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
struct xhci_hcor *hcor = ctrl->hcor;
if ((req->requesttype & USB_RT_PORT) &&
@@ -677,7 +704,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe,
srclen = 4;
break;
case 1: /* Vendor String */
- srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
+ srcptr = "\16\3U\0-\0B\0o\0o\0t\0";
srclen = 14;
break;
case 2: /* Product Name */
@@ -858,9 +885,8 @@ unknown:
* @param interval interval of the interrupt
* @return 0
*/
-int
-submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
- int length, int interval)
+static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
+ void *buffer, int length, int interval)
{
/*
* TODO: Not addressing any interrupt type transfer requests
@@ -878,9 +904,8 @@ submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
* @param length length of the buffer
* @return returns 0 if successful else -1 on failure
*/
-int
-submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
- int length)
+static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
+ void *buffer, int length)
{
if (usb_pipetype(pipe) != PIPE_BULK) {
printf("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
@@ -898,13 +923,14 @@ submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
* @param buffer buffer to be read/written based on the request
* @param length length of the buffer
* @param setup Request type
+ * @param root_portnr Root port number that this device is on
* @return returns 0 if successful else -1 on failure
*/
-int
-submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
- int length, struct devrequest *setup)
+static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long pipe,
+ void *buffer, int length,
+ struct devrequest *setup, int root_portnr)
{
- struct xhci_ctrl *ctrl = udev->controller;
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
int ret = 0;
if (usb_pipetype(pipe) != PIPE_CONTROL) {
@@ -916,7 +942,7 @@ submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
return xhci_submit_root(udev, pipe, buffer, setup);
if (setup->request == USB_REQ_SET_ADDRESS)
- return xhci_address_device(udev);
+ return xhci_address_device(udev, root_portnr);
if (setup->request == USB_REQ_SET_CONFIGURATION) {
ret = xhci_set_configuration(udev);
@@ -929,33 +955,16 @@ submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
return xhci_ctrl_tx(udev, pipe, setup, length, buffer);
}
-/**
- * Intialises the XHCI host controller
- * and allocates the necessary data structures
- *
- * @param index index to the host controller data structure
- * @return pointer to the intialised controller
- */
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+static int xhci_lowlevel_init(struct xhci_ctrl *ctrl)
{
+ struct xhci_hccr *hccr;
+ struct xhci_hcor *hcor;
uint32_t val;
uint32_t val2;
uint32_t reg;
- struct xhci_hccr *hccr;
- struct xhci_hcor *hcor;
- struct xhci_ctrl *ctrl;
-
- if (xhci_hcd_init(index, &hccr, (struct xhci_hcor **)&hcor) != 0)
- return -ENODEV;
-
- if (xhci_reset(hcor) != 0)
- return -ENODEV;
-
- ctrl = &xhcic[index];
-
- ctrl->hccr = hccr;
- ctrl->hcor = hcor;
+ hccr = ctrl->hccr;
+ hcor = ctrl->hcor;
/*
* Program the Number of Device Slots Enabled field in the CONFIG
* register with the max value of slots the HC can handle.
@@ -997,11 +1006,82 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
reg = HC_VERSION(xhci_readl(&hccr->cr_capbase));
printf("USB XHCI %x.%02x\n", reg >> 8, reg & 0xff);
- *controller = &xhcic[index];
+ return 0;
+}
+
+static int xhci_lowlevel_stop(struct xhci_ctrl *ctrl)
+{
+ u32 temp;
+
+ xhci_reset(ctrl->hcor);
+
+ debug("// Disabling event ring interrupts\n");
+ temp = xhci_readl(&ctrl->hcor->or_usbsts);
+ xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT);
+ temp = xhci_readl(&ctrl->ir_set->irq_pending);
+ xhci_writel(&ctrl->ir_set->irq_pending, ER_IRQ_DISABLE(temp));
return 0;
}
+#ifndef CONFIG_DM_USB
+int submit_control_msg(struct usb_device *udev, unsigned long pipe,
+ void *buffer, int length, struct devrequest *setup)
+{
+ struct usb_device *hop = udev;
+
+ if (hop->parent)
+ while (hop->parent->parent)
+ hop = hop->parent;
+
+ return _xhci_submit_control_msg(udev, pipe, buffer, length, setup,
+ hop->portnr);
+}
+
+int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+ int length)
+{
+ return _xhci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+ int length, int interval)
+{
+ return _xhci_submit_int_msg(udev, pipe, buffer, length, interval);
+}
+
+/**
+ * Intialises the XHCI host controller
+ * and allocates the necessary data structures
+ *
+ * @param index index to the host controller data structure
+ * @return pointer to the intialised controller
+ */
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+ struct xhci_hccr *hccr;
+ struct xhci_hcor *hcor;
+ struct xhci_ctrl *ctrl;
+ int ret;
+
+ if (xhci_hcd_init(index, &hccr, (struct xhci_hcor **)&hcor) != 0)
+ return -ENODEV;
+
+ if (xhci_reset(hcor) != 0)
+ return -ENODEV;
+
+ ctrl = &xhcic[index];
+
+ ctrl->hccr = hccr;
+ ctrl->hcor = hcor;
+
+ ret = xhci_lowlevel_init(ctrl);
+
+ *controller = &xhcic[index];
+
+ return ret;
+}
+
/**
* Stops the XHCI host controller
* and cleans up all the related data structures
@@ -1012,19 +1092,143 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
int usb_lowlevel_stop(int index)
{
struct xhci_ctrl *ctrl = (xhcic + index);
- u32 temp;
- xhci_reset(ctrl->hcor);
+ xhci_lowlevel_stop(ctrl);
+ xhci_hcd_stop(index);
+ xhci_cleanup(ctrl);
- debug("// Disabling event ring interrupts\n");
- temp = xhci_readl(&ctrl->hcor->or_usbsts);
- xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT);
- temp = xhci_readl(&ctrl->ir_set->irq_pending);
- xhci_writel(&ctrl->ir_set->irq_pending, ER_IRQ_DISABLE(temp));
+ return 0;
+}
+#endif /* CONFIG_DM_USB */
- xhci_hcd_stop(index);
+#ifdef CONFIG_DM_USB
+/*
+static struct usb_device *get_usb_device(struct udevice *dev)
+{
+ struct usb_device *udev;
+ if (device_get_uclass_id(dev) == UCLASS_USB)
+ udev = dev_get_uclass_priv(dev);
+ else
+ udev = dev_get_parentdata(dev);
+
+ return udev;
+}
+*/
+static bool is_root_hub(struct udevice *dev)
+{
+ if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB)
+ return true;
+
+ return false;
+}
+
+static int xhci_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length,
+ struct devrequest *setup)
+{
+ struct usb_device *uhop;
+ struct udevice *hub;
+ int root_portnr = 0;
+
+ debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+ dev->name, udev, udev->dev->name, udev->portnr);
+ hub = udev->dev;
+ if (device_get_uclass_id(hub) == UCLASS_USB_HUB) {
+ /* Figure out our port number on the root hub */
+ if (is_root_hub(hub)) {
+ root_portnr = udev->portnr;
+ } else {
+ while (!is_root_hub(hub->parent))
+ hub = hub->parent;
+ uhop = dev_get_parentdata(hub);
+ root_portnr = uhop->portnr;
+ }
+ }
+/*
+ struct usb_device *hop = udev;
+
+ if (hop->parent)
+ while (hop->parent->parent)
+ hop = hop->parent;
+*/
+ return _xhci_submit_control_msg(udev, pipe, buffer, length, setup,
+ root_portnr);
+}
+
+static int xhci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length)
+{
+ debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+ return _xhci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+static int xhci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length,
+ int interval)
+{
+ debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+ return _xhci_submit_int_msg(udev, pipe, buffer, length, interval);
+}
+
+static int xhci_alloc_device(struct udevice *dev, struct usb_device *udev)
+{
+ debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+ return _xhci_alloc_device(udev);
+}
+
+int xhci_register(struct udevice *dev, struct xhci_hccr *hccr,
+ struct xhci_hcor *hcor)
+{
+ struct xhci_ctrl *ctrl = dev_get_priv(dev);
+ struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p\n", __func__, dev->name,
+ ctrl, hccr, hcor);
+
+ ctrl->dev = dev;
+
+ /*
+ * XHCI needs to issue a Address device command to setup
+ * proper device context structures, before it can interact
+ * with the device. So a get_descriptor will fail before any
+ * of that is done for XHCI unlike EHCI.
+ */
+ priv->desc_before_addr = false;
+
+ ret = xhci_reset(hcor);
+ if (ret)
+ goto err;
+
+ ctrl->hccr = hccr;
+ ctrl->hcor = hcor;
+ ret = xhci_lowlevel_init(ctrl);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ free(ctrl);
+ debug("%s: failed, ret=%d\n", __func__, ret);
+ return ret;
+}
+
+int xhci_deregister(struct udevice *dev)
+{
+ struct xhci_ctrl *ctrl = dev_get_priv(dev);
+
+ xhci_lowlevel_stop(ctrl);
xhci_cleanup(ctrl);
return 0;
}
+
+struct dm_usb_ops xhci_usb_ops = {
+ .control = xhci_submit_control_msg,
+ .bulk = xhci_submit_bulk_msg,
+ .interrupt = xhci_submit_int_msg,
+ .alloc_device = xhci_alloc_device,
+};
+
+#endif
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 0951e87436..2afa38694b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1209,6 +1209,9 @@ void xhci_hcd_stop(int index);
#define XHCI_STS_CNR (1 << 11)
struct xhci_ctrl {
+#ifdef CONFIG_DM_USB
+ struct udevice *dev;
+#endif
struct xhci_hccr *hccr; /* R/O registers, not need for volatile */
struct xhci_hcor *hcor;
struct xhci_doorbell_array *dba;
@@ -1241,7 +1244,8 @@ void xhci_endpoint_copy(struct xhci_ctrl *ctrl,
void xhci_slot_copy(struct xhci_ctrl *ctrl,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx);
-void xhci_setup_addressable_virt_dev(struct usb_device *udev);
+void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
+ int speed, int hop_portnr);
void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr,
u32 slot_id, u32 ep_index, trb_type cmd);
void xhci_acknowledge_event(struct xhci_ctrl *ctrl);
@@ -1255,8 +1259,31 @@ void xhci_flush_cache(uintptr_t addr, u32 type_len);
void xhci_inval_cache(uintptr_t addr, u32 type_len);
void xhci_cleanup(struct xhci_ctrl *ctrl);
struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs);
-int xhci_alloc_virt_device(struct usb_device *udev);
+int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id);
int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
struct xhci_hcor *hcor);
+/**
+ * xhci_deregister() - Unregister an XHCI controller
+ *
+ * @dev: Controller device
+ * @return 0 if registered, -ve on error
+ */
+int xhci_deregister(struct udevice *dev);
+
+/**
+ * xhci_register() - Register a new XHCI controller
+ *
+ * @dev: Controller device
+ * @hccr: Host controller control registers
+ * @hcor: Not sure what this means
+ * @return 0 if registered, -ve on error
+ */
+int xhci_register(struct udevice *dev, struct xhci_hccr *hccr,
+ struct xhci_hcor *hcor);
+
+extern struct dm_usb_ops xhci_usb_ops;
+
+struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev);
+
#endif /* HOST_XHCI_H_ */
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index 053d94560d..7d90ebc1f5 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -180,7 +180,7 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
return NULL; /* URB still pending */
}
-void usb_reset_root_port(void)
+int usb_reset_root_port(void)
{
void *mbase = host->mregs;
u8 power;
@@ -208,6 +208,8 @@ void usb_reset_root_port(void)
(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
USB_SPEED_FULL : USB_SPEED_LOW;
mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+
+ return 0;
}
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index a81affa333..f4231b8e62 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -87,6 +87,7 @@
*/
#include <common.h>
+#include <fdtdec.h>
#include <version.h>
#include <malloc.h>
#include <linux/compiler.h>
@@ -2251,6 +2252,7 @@ int drv_video_init(void)
{
int skip_dev_init;
struct stdio_dev console_dev;
+ bool have_keyboard;
/* Check if video initialization should be skipped */
if (board_video_skip())
@@ -2262,11 +2264,20 @@ int drv_video_init(void)
if (board_cfb_skip())
return 0;
+#if defined(CONFIG_VGA_AS_SINGLE_DEVICE)
+ have_keyboard = false;
+#elif defined(CONFIG_OF_CONTROL)
+ have_keyboard = !fdtdec_get_config_bool(gd->fdt_blob,
+ "u-boot,no-keyboard");
+#else
+ have_keyboard = true;
+#endif
+ if (have_keyboard) {
+ debug("KBD: Keyboard init ...\n");
#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
- debug("KBD: Keyboard init ...\n");
- skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
+ skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
#endif
-
+ }
if (skip_dev_init)
return 0;
@@ -2279,11 +2290,13 @@ int drv_video_init(void)
console_dev.puts = video_puts; /* 'puts' function */
#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
- /* Also init console device */
- console_dev.flags |= DEV_FLAGS_INPUT;
- console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */
- console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */
-#endif /* CONFIG_VGA_AS_SINGLE_DEVICE */
+ if (have_keyboard) {
+ /* Also init console device */
+ console_dev.flags |= DEV_FLAGS_INPUT;
+ console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */
+ console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */
+ }
+#endif
if (stdio_register(&console_dev) != 0)
return 0;
OpenPOWER on IntegriCloud