summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig1
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/amba/Makefile2
-rw-r--r--drivers/amba/bus.c210
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/bus.c37
-rw-r--r--drivers/base/driver.c63
-rw-r--r--drivers/base/platform.c36
-rw-r--r--drivers/eeprom/at25.c2
-rw-r--r--drivers/gpio/gpio-stmpe.c2
-rw-r--r--drivers/i2c/i2c.c30
-rw-r--r--drivers/mci/imx-esdhc.c24
-rw-r--r--drivers/mci/mci_spi.c10
-rw-r--r--drivers/mci/omap_hsmmc.c2
-rw-r--r--drivers/mfd/lp3972.c2
-rw-r--r--drivers/mfd/mc13xxx.c40
-rw-r--r--drivers/mfd/mc34704.c4
-rw-r--r--drivers/mfd/mc34708.c29
-rw-r--r--drivers/mfd/mc9sdz60.c2
-rw-r--r--drivers/mfd/stmpe-i2c.c2
-rw-r--r--drivers/mfd/twl4030.c2
-rw-r--r--drivers/mfd/twl6030.c2
-rw-r--r--drivers/mtd/mtdraw.c3
-rw-r--r--drivers/mtd/nand/nand_base.c97
-rw-r--r--drivers/mtd/nand/nand_ids.c30
-rw-r--r--drivers/net/Kconfig42
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/altera_tse.c48
-rw-r--r--drivers/net/altera_tse.h3
-rw-r--r--drivers/net/at91_ether.c49
-rw-r--r--drivers/net/davinci_emac.c618
-rw-r--r--drivers/net/davinci_emac.h289
-rw-r--r--drivers/net/designware.c62
-rw-r--r--drivers/net/dm9k.c50
-rw-r--r--drivers/net/ep93xx.c35
-rw-r--r--drivers/net/ep93xx.h2
-rw-r--r--drivers/net/fec_imx.c89
-rw-r--r--drivers/net/fec_imx.h6
-rw-r--r--drivers/net/fec_mpc5200.c58
-rw-r--r--drivers/net/fec_mpc5200.h4
-rw-r--r--drivers/net/gianfar.c61
-rw-r--r--drivers/net/gianfar.h2
-rw-r--r--drivers/net/ks8851_mll.c36
-rw-r--r--drivers/net/ksz8864rmn.c191
-rw-r--r--drivers/net/macb.c79
-rw-r--r--drivers/net/miidev.c313
-rw-r--r--drivers/net/netx_eth.c26
-rw-r--r--drivers/net/phy/Kconfig17
-rw-r--r--drivers/net/phy/Makefile2
-rw-r--r--drivers/net/phy/generic.c36
-rw-r--r--drivers/net/phy/mdio_bus.c250
-rw-r--r--drivers/net/phy/phy.c583
-rw-r--r--drivers/net/smc91111.c47
-rw-r--r--drivers/net/smc911x.c37
-rw-r--r--drivers/net/tap.c4
-rw-r--r--drivers/net/usb/Kconfig4
-rw-r--r--drivers/net/usb/asix.c29
-rw-r--r--drivers/net/usb/smsc95xx.c41
-rw-r--r--drivers/net/usb/usbnet.c11
-rw-r--r--drivers/nor/cfi_flash.c37
-rw-r--r--drivers/nor/cfi_flash.h2
-rw-r--r--drivers/nor/m25p80.c76
-rw-r--r--drivers/nor/m25p80.h2
-rw-r--r--drivers/of/Kconfig2
-rw-r--r--drivers/of/Makefile3
-rw-r--r--drivers/of/base.c802
-rw-r--r--drivers/of/gpio.c28
-rw-r--r--drivers/of/partition.c64
-rw-r--r--drivers/serial/amba-pl011.c74
-rw-r--r--drivers/serial/serial_imx.c17
-rw-r--r--drivers/spi/imx_spi.c49
-rw-r--r--drivers/spi/spi.c61
-rw-r--r--drivers/usb/core/usb.c5
-rw-r--r--drivers/video/fb.c31
74 files changed, 4187 insertions, 829 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 70797c182c..d0b5e3abdb 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -20,5 +20,6 @@ source "drivers/watchdog/Kconfig"
source "drivers/pwm/Kconfig"
source "drivers/dma/Kconfig"
source "drivers/gpio/Kconfig"
+source "drivers/of/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 28a5cb8f35..2a1f8b0f23 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,4 +1,5 @@
obj-y += base/
+obj-$(CONFIG_ARM_AMBA) += amba/
obj-y += net/
obj-y += serial/
obj-y += mtd/
@@ -19,3 +20,4 @@ obj-y += misc/
obj-y += dma/
obj-y += watchdog/
obj-y += gpio/
+obj-$(CONFIG_OFDEVICE) += of/
diff --git a/drivers/amba/Makefile b/drivers/amba/Makefile
new file mode 100644
index 0000000000..a4a511b322
--- /dev/null
+++ b/drivers/amba/Makefile
@@ -0,0 +1,2 @@
+
+obj-y += bus.o
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
new file mode 100644
index 0000000000..383c77ee13
--- /dev/null
+++ b/drivers/amba/bus.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
+ * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2.
+ */
+#include <common.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <linux/amba/bus.h>
+#include <io.h>
+
+#define to_amba_driver(d) container_of(d, struct amba_driver, drv)
+
+static const struct amba_id *
+amba_lookup(const struct amba_id *table, struct amba_device *dev)
+{
+ int ret = 0;
+
+ while (table->mask) {
+ ret = (dev->periphid & table->mask) == table->id;
+ if (ret)
+ break;
+ table++;
+ }
+
+ return ret ? table : NULL;
+}
+
+static int amba_match(struct device_d *dev, struct driver_d *drv)
+{
+ struct amba_device *pcdev = to_amba_device(dev);
+
+ struct amba_driver *pcdrv = to_amba_driver(drv);
+
+ return amba_lookup(pcdrv->id_table, pcdev) == NULL;
+}
+
+static int amba_get_enable_pclk(struct amba_device *pcdev)
+{
+ struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");
+ int ret;
+
+ pcdev->pclk = pclk;
+
+ if (IS_ERR(pclk))
+ return PTR_ERR(pclk);
+
+ ret = clk_enable(pclk);
+ if (ret) {
+ clk_put(pclk);
+ }
+
+ return ret;
+}
+
+static int amba_probe(struct device_d *dev)
+{
+ struct amba_device *pcdev = to_amba_device(dev);
+ struct amba_driver *pcdrv = to_amba_driver(dev->driver);
+ const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
+
+ return pcdrv->probe(pcdev, id);
+}
+
+static void amba_remove(struct device_d *dev)
+{
+ struct amba_device *pcdev = to_amba_device(dev);
+ struct amba_driver *drv = to_amba_driver(dev->driver);
+
+ drv->remove(pcdev);
+}
+
+struct bus_type amba_bustype = {
+ .name = "amba",
+ .match = amba_match,
+ .probe = amba_probe,
+ .remove = amba_remove,
+};
+
+int amba_driver_register(struct amba_driver *drv)
+{
+ drv->drv.bus = &amba_bustype;
+
+ if (drv->probe)
+ drv->drv.probe = amba_probe;
+ if (drv->remove)
+ drv->drv.remove = amba_remove;
+
+ return register_driver(&drv->drv);
+}
+
+/**
+ * amba_device_add - add a previously allocated AMBA device structure
+ * @dev: AMBA device allocated by amba_device_alloc
+ * @parent: resource parent for this devices resources
+ *
+ * Claim the resource, and read the device cell ID if not already
+ * initialized. Register the AMBA device with the Linux device
+ * manager.
+ */
+int amba_device_add(struct amba_device *dev)
+{
+ u32 size;
+ void __iomem *tmp;
+ int i, ret;
+ struct resource *res = NULL;
+
+ dev->dev.bus = &amba_bustype;
+
+ /*
+ * Dynamically calculate the size of the resource
+ * and use this for iomap
+ */
+ size = resource_size(&dev->res);
+ res = request_iomem_region("amba", dev->res.start, dev->res.end);
+ if (!res)
+ return -ENOMEM;
+ dev->base = tmp = (void __force __iomem *)res->start;
+ if (!tmp) {
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ /* Hard-coded primecell ID instead of plug-n-play */
+ if (dev->periphid != 0)
+ goto skip_probe;
+
+ ret = amba_get_enable_pclk(dev);
+ if (ret == 0) {
+ u32 pid, cid;
+
+ /*
+ * Read pid and cid based on size of resource
+ * they are located at end of region
+ */
+ for (pid = 0, i = 0; i < 4; i++)
+ pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
+ (i * 8);
+ for (cid = 0, i = 0; i < 4; i++)
+ cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
+ (i * 8);
+
+ if (cid == AMBA_CID)
+ dev->periphid = pid;
+
+ if (!dev->periphid)
+ ret = -ENODEV;
+ }
+
+ if (ret)
+ goto err_release;
+
+ skip_probe:
+ ret = register_device(&dev->dev);
+ if (ret)
+ goto err_release;
+
+ return ret;
+ err_release:
+ release_region(res);
+ return ret;
+}
+
+struct amba_device *
+amba_aphb_device_add(struct device_d *parent, const char *name, int id,
+ resource_size_t base, size_t size,
+ void *pdata, unsigned int periphid)
+{
+ struct amba_device *dev;
+ int ret;
+
+ dev = amba_device_alloc(name, id, base, size);
+
+ dev->periphid = periphid;
+ dev->dev.platform_data = pdata;
+ dev->dev.parent = parent;
+
+ ret = amba_device_add(dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return dev;
+}
+
+/**
+ * amba_device_alloc - allocate an AMBA device
+ * @name: sysfs name of the AMBA device
+ * @base: base of AMBA device
+ * @size: size of AMBA device
+ *
+ * Allocate and initialize an AMBA device structure. Returns %NULL
+ * on failure.
+ */
+struct amba_device *amba_device_alloc(const char *name, int id, resource_size_t base,
+ size_t size)
+{
+ struct amba_device *dev;
+
+ dev = xzalloc(sizeof(*dev));
+
+ strcpy(dev->dev.name, name);
+ dev->dev.id = id;
+ dev->res.start = base;
+ dev->res.end = base + size - 1;
+ dev->res.flags = IORESOURCE_MEM;
+
+ return dev;
+}
+
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 957ca5ac2a..e1f1c7a0ad 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -1,3 +1,4 @@
+obj-y += bus.o
obj-y += driver.o
obj-y += platform.o
obj-y += resource.o
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
new file mode 100644
index 0000000000..1dd139f7a3
--- /dev/null
+++ b/drivers/base/bus.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+
+LIST_HEAD(bus_list);
+EXPORT_SYMBOL(bus_list);
+
+struct bus_type *get_bus_by_name(const char *name)
+{
+ struct bus_type *bus;
+
+ for_each_bus(bus) {
+ if(!strcmp(bus->name, name))
+ return bus;
+ }
+
+ return NULL;
+}
+
+int bus_register(struct bus_type *bus)
+{
+ if (get_bus_by_name(bus->name))
+ return -EEXIST;
+
+ INIT_LIST_HEAD(&bus->device_list);
+ INIT_LIST_HEAD(&bus->driver_list);
+
+ list_add_tail(&bus->list, &bus_list);
+
+ return 0;
+}
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index dc29021738..1def2f85e7 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -82,8 +82,6 @@ static int match(struct driver_d *drv, struct device_d *dev)
dev->driver = drv;
- if (dev->bus != drv->bus)
- goto err_out;
if (dev->bus->match(dev, drv))
goto err_out;
if (dev->bus->probe(dev))
@@ -113,18 +111,29 @@ int register_device(struct device_d *new_device)
debug ("register_device: %s\n", dev_name(new_device));
- if (!new_device->bus) {
-// dev_err(new_device, "no bus type associated. Needs fixup\n");
+ if (!new_device->bus)
new_device->bus = &platform_bus;
+
+ if (new_device->bus == &platform_bus && new_device->resource) {
+ struct device_d *dev;
+
+ bus_for_each_device(new_device->bus, dev) {
+ if (!dev->resource)
+ continue;
+ if (dev->resource->start == new_device->resource->start) {
+ return -EBUSY;
+ }
+ }
}
list_add_tail(&new_device->list, &device_list);
+ list_add_tail(&new_device->bus_list, &new_device->bus->device_list);
INIT_LIST_HEAD(&new_device->children);
INIT_LIST_HEAD(&new_device->cdevs);
INIT_LIST_HEAD(&new_device->parameters);
INIT_LIST_HEAD(&new_device->active);
- for_each_driver(drv) {
+ bus_for_each_driver(new_device->bus, drv) {
if (!match(drv, new_device))
break;
}
@@ -156,6 +165,7 @@ int unregister_device(struct device_d *old_dev)
}
list_del(&old_dev->list);
+ list_del(&old_dev->bus_list);
list_del(&old_dev->active);
/* remove device from parents child list */
@@ -209,13 +219,14 @@ int register_driver(struct driver_d *drv)
}
list_add_tail(&drv->list, &driver_list);
+ list_add_tail(&drv->bus_list, &drv->bus->driver_list);
if (!drv->info)
drv->info = noinfo;
if (!drv->shortinfo)
drv->shortinfo = noshortinfo;
- for_each_device(dev)
+ bus_for_each_device(drv->bus, dev)
match(drv, dev);
return 0;
@@ -310,6 +321,25 @@ const char *dev_id(const struct device_d *dev)
return buf;
}
+int dev_printf(const struct device_d *dev, const char *format, ...)
+{
+ va_list args;
+ int ret = 0;
+
+ if (dev->driver && dev->driver->name)
+ ret += printf("%s ", dev->driver->name);
+
+ ret += printf("%s: ", dev_name(dev));
+
+ va_start(args, format);
+
+ ret += vprintf(format, args);
+
+ va_end(args);
+
+ return ret;
+}
+
void devices_shutdown(void)
{
struct device_d *dev;
@@ -354,6 +384,21 @@ static int do_devinfo_subtree(struct device_d *dev, int depth)
return 0;
}
+int dev_get_drvdata(struct device_d *dev, unsigned long *data)
+{
+ if (dev->of_id_entry) {
+ *data = dev->of_id_entry->data;
+ return 0;
+ }
+
+ if (dev->id_entry) {
+ *data = dev->id_entry->driver_data;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
static int do_devinfo(int argc, char *argv[])
{
struct device_d *dev;
@@ -403,6 +448,12 @@ static int do_devinfo(int argc, char *argv[])
list_for_each_entry(param, &dev->parameters, list)
printf("%16s = %s\n", param->name, dev_get_param(dev, param->name));
+#ifdef CONFIG_OFDEVICE
+ if (dev->device_node) {
+ printf("\ndevice node: %s\n", dev->device_node->full_name);
+ of_print_nodes(dev->device_node, 0);
+ }
+#endif
}
return 0;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index f1069bc899..d3021ab833 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -18,10 +18,31 @@
*/
#include <common.h>
#include <driver.h>
+#include <errno.h>
+#include <init.h>
static int platform_match(struct device_d *dev, struct driver_d *drv)
{
- return strcmp(dev->name, drv->name) ? -1 : 0;
+ if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node &&
+ drv->of_compatible)
+ return of_match(dev, drv);
+
+ if (!strcmp(dev->name, drv->name))
+ return 0;
+
+ if (drv->id_table) {
+ struct platform_device_id *id = drv->id_table;
+
+ while (id->name) {
+ if (!strcmp(id->name, dev->name)) {
+ dev->id_entry = id;
+ return 0;
+ }
+ id++;
+ }
+ }
+
+ return -1;
}
static int platform_probe(struct device_d *dev)
@@ -41,15 +62,8 @@ struct bus_type platform_bus = {
.remove = platform_remove,
};
-#if 0
-LIST_HEAD(bus_list);
-EXPORT_SYMBOL(bus_list);
-
-int bus_register(struct bus_type *bus)
+static int plarform_init(void)
{
- list_add_tail(&bus->list, &bus_list);
-
- return 0;
+ return bus_register(&platform_bus);
}
-#endif
-
+pure_initcall(plarform_init);
diff --git a/drivers/eeprom/at25.c b/drivers/eeprom/at25.c
index 03d191eb90..5578c783ad 100644
--- a/drivers/eeprom/at25.c
+++ b/drivers/eeprom/at25.c
@@ -312,7 +312,7 @@ static struct driver_d at25_driver = {
static int at25_init(void)
{
- register_driver(&at25_driver);
+ spi_register_driver(&at25_driver);
return 0;
}
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index fa3b041534..118135182d 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -145,7 +145,7 @@ static int stmpe_gpio_probe(struct device_d *dev)
return ret;
}
- dev_info(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base);
+ dev_dbg(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base);
return 0;
}
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index 3af2b3e66c..27fd256cf7 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -21,6 +21,7 @@
#include <errno.h>
#include <malloc.h>
#include <xfuncs.h>
+#include <init.h>
#include <i2c/i2c.h>
@@ -251,6 +252,7 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
strcpy(client->dev.name, chip->type);
client->dev.type_data = client;
client->dev.platform_data = chip->platform_data;
+ client->dev.bus = &i2c_bus;
client->adapter = adapter;
client->addr = chip->addr;
@@ -372,3 +374,31 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
return 0;
}
EXPORT_SYMBOL(i2c_add_numbered_adapter);
+
+static int i2c_match(struct device_d *dev, struct driver_d *drv)
+{
+ return strcmp(dev->name, drv->name) ? -1 : 0;
+}
+
+static int i2c_probe(struct device_d *dev)
+{
+ return dev->driver->probe(dev);
+}
+
+static void i2c_remove(struct device_d *dev)
+{
+ dev->driver->remove(dev);
+}
+
+struct bus_type i2c_bus = {
+ .name = "i2c",
+ .match = i2c_match,
+ .probe = i2c_probe,
+ .remove = i2c_remove,
+};
+
+static int i2c_bus_init(void)
+{
+ return bus_register(&i2c_bus);
+}
+pure_initcall(i2c_bus_init);
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index d78cc01a05..7c12eba5da 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -331,7 +331,7 @@ esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
esdhc_write32(&regs->irqstat, -1);
/* Wait for the bus to be idle */
- ret = wait_on_timeout(100 * MSECOND,
+ ret = wait_on_timeout(SECOND,
!(esdhc_read32(&regs->prsstat) &
(PRSSTAT_CICHB | PRSSTAT_CIDHB)));
if (ret) {
@@ -563,16 +563,28 @@ static int fsl_esdhc_probe(struct device_d *dev)
return 0;
}
+static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = {
+ {
+ .compatible = "fsl,imx51-esdhc",
+ }, {
+ .compatible = "fsl,imx53-esdhc",
+ }, {
+ .compatible = "fsl,imx6q-usdhc",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d fsl_esdhc_driver = {
- .name = "imx-esdhc",
- .probe = fsl_esdhc_probe,
+ .name = "imx-esdhc",
+ .probe = fsl_esdhc_probe,
+ .of_compatible = DRV_OF_COMPAT(fsl_esdhc_compatible),
};
static int fsl_esdhc_init_driver(void)
{
- register_driver(&fsl_esdhc_driver);
- return 0;
+ register_driver(&fsl_esdhc_driver);
+ return 0;
}
device_initcall(fsl_esdhc_init_driver);
-
diff --git a/drivers/mci/mci_spi.c b/drivers/mci/mci_spi.c
index 35b454751f..5894104231 100644
--- a/drivers/mci/mci_spi.c
+++ b/drivers/mci/mci_spi.c
@@ -178,7 +178,7 @@ static uint mmc_spi_readdata(struct mmc_spi_host *host, void *xbuf,
mmc_spi_readbytes(host, bsize, buf);
mmc_spi_readbytes(host, 2, &crc);
#ifdef CONFIG_MMC_SPI_CRC_ON
- if (swab16(cyg_crc16(buf, bsize)) != crc) {
+ if (be16_to_cpu(cyg_crc16(buf, bsize)) != crc) {
dev_dbg(host->dev, "%s: CRC error\n", __func__);
r1 = R1_SPI_COM_CRC;
break;
@@ -209,7 +209,7 @@ static uint mmc_spi_writedata(struct mmc_spi_host *host, const void *xbuf,
while (bcnt--) {
#ifdef CONFIG_MMC_SPI_CRC_ON
- crc = swab16(cyg_crc16((u8 *)buf, bsize));
+ crc = be16_to_cpu(cyg_crc16((u8 *)buf, bsize));
#endif
mmc_spi_writebytes(host, 2, tok);
mmc_spi_writebytes(host, bsize, (void *)buf);
@@ -288,7 +288,7 @@ static int mmc_spi_request(struct mci_host *mci, struct mci_cmd *cmd, struct mci
} else if (cmd->resp_type == MMC_RSP_R2) {
r1 = mmc_spi_readdata(host, cmd->response, 1, 16);
for (i = 0; i < 4; i++)
- cmd->response[i] = swab32(cmd->response[i]);
+ cmd->response[i] = be32_to_cpu(cmd->response[i]);
dev_dbg(host->dev, "MMC_RSP_R2 -> %x %x %x %x\n", cmd->response[0], cmd->response[1],
cmd->response[2], cmd->response[3]);
} else if (!data) {
@@ -296,7 +296,7 @@ static int mmc_spi_request(struct mci_host *mci, struct mci_cmd *cmd, struct mci
case SD_CMD_SEND_IF_COND:
case MMC_CMD_SPI_READ_OCR:
mmc_spi_readbytes(host, 4, cmd->response);
- cmd->response[0] = swab32(cmd->response[0]);
+ cmd->response[0] = be32_to_cpu(cmd->response[0]);
break;
}
} else {
@@ -420,7 +420,7 @@ static struct driver_d spi_mci_driver = {
static int spi_mci_init_driver(void)
{
- register_driver(&spi_mci_driver);
+ spi_register_driver(&spi_mci_driver);
return 0;
}
diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c
index 00bfc79765..eba1a6aedf 100644
--- a/drivers/mci/omap_hsmmc.c
+++ b/drivers/mci/omap_hsmmc.c
@@ -234,7 +234,7 @@ static int mmc_init_setup(struct mci_host *mci, struct device_d *dev)
start = get_time_ns();
while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for cc2!\n");
+ dev_dbg(hsmmc->dev, "timeout waiting for reset done\n");
return -ETIMEDOUT;
}
}
diff --git a/drivers/mfd/lp3972.c b/drivers/mfd/lp3972.c
index 9d12717b56..082ecaa54b 100644
--- a/drivers/mfd/lp3972.c
+++ b/drivers/mfd/lp3972.c
@@ -99,7 +99,7 @@ static struct driver_d lp_driver = {
static int lp_init(void)
{
- register_driver(&lp_driver);
+ i2c_register_driver(&lp_driver);
return 0;
}
diff --git a/drivers/mfd/mc13xxx.c b/drivers/mfd/mc13xxx.c
index a6a9655886..d6cf73cba8 100644
--- a/drivers/mfd/mc13xxx.c
+++ b/drivers/mfd/mc13xxx.c
@@ -332,31 +332,51 @@ static int mc_probe(struct device_d *dev, enum mc13xxx_mode mode)
return 0;
}
+static __maybe_unused struct of_device_id mc13892_dt_ids[] = {
+ {
+ .compatible = "fsl,mc13892",
+ }, {
+ .compatible = "fsl,mc13783",
+ }, {
+ /* sentinel */
+ }
+};
+
+#ifdef CONFIG_I2C
static int mc_i2c_probe(struct device_d *dev)
{
return mc_probe(dev, MC13XXX_MODE_I2C);
}
-static int mc_spi_probe(struct device_d *dev)
-{
- return mc_probe(dev, MC13XXX_MODE_SPI);
-}
-
static struct driver_d mc_i2c_driver = {
.name = "mc13xxx-i2c",
.probe = mc_i2c_probe,
+ .of_compatible = DRV_OF_COMPAT(mc13892_dt_ids),
};
+static int mc_i2c_init(void)
+{
+ return i2c_register_driver(&mc_i2c_driver);
+}
+device_initcall(mc_i2c_init);
+#endif
+
+#ifdef CONFIG_SPI
+static int mc_spi_probe(struct device_d *dev)
+{
+ return mc_probe(dev, MC13XXX_MODE_SPI);
+}
+
static struct driver_d mc_spi_driver = {
.name = "mc13xxx-spi",
.probe = mc_spi_probe,
+ .of_compatible = DRV_OF_COMPAT(mc13892_dt_ids),
};
-static int mc_init(void)
+static int mc_spi_init(void)
{
- register_driver(&mc_i2c_driver);
- register_driver(&mc_spi_driver);
- return 0;
+ return spi_register_driver(&mc_spi_driver);
}
-device_initcall(mc_init);
+device_initcall(mc_spi_init);
+#endif
diff --git a/drivers/mfd/mc34704.c b/drivers/mfd/mc34704.c
index 6dc04c7330..276b723b1b 100644
--- a/drivers/mfd/mc34704.c
+++ b/drivers/mfd/mc34704.c
@@ -130,7 +130,7 @@ static struct driver_d mc34704_driver = {
static int mc34704_init(void)
{
- register_driver(&mc34704_driver);
- return 0;
+ i2c_register_driver(&mc34704_driver);
+ return 0;
}
device_initcall(mc34704_init);
diff --git a/drivers/mfd/mc34708.c b/drivers/mfd/mc34708.c
index a3b3530082..b1166de6b8 100644
--- a/drivers/mfd/mc34708.c
+++ b/drivers/mfd/mc34708.c
@@ -262,31 +262,40 @@ static int mc_probe(struct device_d *dev, enum mc34708_mode mode)
return 0;
}
+#ifdef CONFIG_I2C
static int mc_i2c_probe(struct device_d *dev)
{
return mc_probe(dev, MC34708_MODE_I2C);
}
-static int mc_spi_probe(struct device_d *dev)
-{
- return mc_probe(dev, MC34708_MODE_SPI);
-}
-
static struct driver_d mc_i2c_driver = {
.name = "mc34708-i2c",
.probe = mc_i2c_probe,
};
+static int mc_i2c_init(void)
+{
+ return i2c_register_driver(&mc_i2c_driver);
+}
+
+device_initcall(mc_i2c_init);
+#endif
+
+#ifdef CONFIG_SPI
+static int mc_spi_probe(struct device_d *dev)
+{
+ return mc_probe(dev, MC34708_MODE_SPI);
+}
+
static struct driver_d mc_spi_driver = {
.name = "mc34708-spi",
.probe = mc_spi_probe,
};
-static int mc_init(void)
+static int mc_spi_init(void)
{
- register_driver(&mc_i2c_driver);
- register_driver(&mc_spi_driver);
- return 0;
+ return spi_register_driver(&mc_spi_driver);
}
-device_initcall(mc_init);
+device_initcall(mc_spi_init);
+#endif
diff --git a/drivers/mfd/mc9sdz60.c b/drivers/mfd/mc9sdz60.c
index 00ba0ffa87..76c62e331e 100644
--- a/drivers/mfd/mc9sdz60.c
+++ b/drivers/mfd/mc9sdz60.c
@@ -142,7 +142,7 @@ static struct driver_d mc_driver = {
static int mc_init(void)
{
- register_driver(&mc_driver);
+ i2c_register_driver(&mc_driver);
return 0;
}
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
index 4af8b7b88c..12e95c16b4 100644
--- a/drivers/mfd/stmpe-i2c.c
+++ b/drivers/mfd/stmpe-i2c.c
@@ -146,7 +146,7 @@ static struct driver_d stmpe_driver = {
static int stmpe_init(void)
{
- register_driver(&stmpe_driver);
+ i2c_register_driver(&stmpe_driver);
return 0;
}
diff --git a/drivers/mfd/twl4030.c b/drivers/mfd/twl4030.c
index 191c91f36a..93097659c6 100644
--- a/drivers/mfd/twl4030.c
+++ b/drivers/mfd/twl4030.c
@@ -53,7 +53,7 @@ static struct driver_d twl_driver = {
static int twl_init(void)
{
- register_driver(&twl_driver);
+ i2c_register_driver(&twl_driver);
return 0;
}
diff --git a/drivers/mfd/twl6030.c b/drivers/mfd/twl6030.c
index 7ecfed8062..01728fd317 100644
--- a/drivers/mfd/twl6030.c
+++ b/drivers/mfd/twl6030.c
@@ -49,7 +49,7 @@ static struct driver_d twl_driver = {
static int twl_init(void)
{
- register_driver(&twl_driver);
+ i2c_register_driver(&twl_driver);
return 0;
}
diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c
index d28ae0744e..f541802a84 100644
--- a/drivers/mtd/mtdraw.c
+++ b/drivers/mtd/mtdraw.c
@@ -128,7 +128,8 @@ static ssize_t mtdraw_read(struct cdev *cdev, void *buf, size_t count,
skip = offset % (mtd->writesize + mtd->oobsize);
while (ret > 0 && count > 0) {
- toread = min_t(int, count, mtd->writesize + mtd->oobsize);
+ toread = min_t(int, count,
+ mtd->writesize + mtd->oobsize - skip);
ret = mtdraw_read_unaligned(mtd, buf, toread,
skip, numpage++ * mtd->writesize);
buf += ret;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 37e57b32ce..fe9a6e7ab3 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1137,7 +1137,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
{
struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
- int tmp_id, tmp_manf;
+ int id_data[8];
int ret;
/* Select the device */
@@ -1166,13 +1166,13 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
/* Read manufacturer and device IDs */
- tmp_manf = chip->read_byte(mtd);
- tmp_id = chip->read_byte(mtd);
+ id_data[0] = chip->read_byte(mtd);
+ id_data[1] = chip->read_byte(mtd);
- if (tmp_manf != *maf_id || tmp_id != dev_id) {
+ if (id_data[0] != *maf_id || id_data[1] != dev_id) {
printk(KERN_ERR "%s: second ID read did not match "
"%02x,%02x against %02x,%02x\n", __func__,
- *maf_id, dev_id, tmp_manf, tmp_id);
+ *maf_id, dev_id, id_data[0], id_data[1]);
return ERR_PTR(-ENODEV);
}
@@ -1196,29 +1196,75 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
}
}
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+
+ /* Read entire ID string */
+
+ for (i = 0; i < 8; i++)
+ id_data[i] = chip->read_byte(mtd);
+
if (!mtd->name)
mtd->name = type->name;
chip->chipsize = type->chipsize << 20;
- /* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
int extid;
/* The 3rd id byte holds MLC / multichip data */
- chip->cellinfo = chip->read_byte(mtd);
+ chip->cellinfo = id_data[2];
/* The 4th id byte is the important one */
- extid = chip->read_byte(mtd);
- /* Calc pagesize */
- mtd->writesize = 1024 << (extid & 0x3);
- extid >>= 2;
- /* Calc oobsize */
- mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
- extid >>= 2;
- /* Calc blocksize. Blocksize is multiples of 64KiB */
- mtd->erasesize = (64 * 1024) << (extid & 0x03);
- extid >>= 2;
- /* Get buswidth information */
- busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ extid = id_data[3];
+
+ /*
+ * Field definitions are in the following datasheets:
+ * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
+ * New style (6 byte ID): Samsung K9GBG08U0M (p.40)
+ *
+ * Check for wraparound + Samsung ID + nonzero 6th byte
+ * to decide what to do.
+ */
+ if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
+ id_data[0] == NAND_MFR_SAMSUNG &&
+ (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ id_data[5] != 0x00) {
+ /* Calc pagesize */
+ mtd->writesize = 2048 << (extid & 0x03);
+ extid >>= 2;
+ /* Calc oobsize */
+ switch (extid & 0x03) {
+ case 1:
+ mtd->oobsize = 128;
+ break;
+ case 2:
+ mtd->oobsize = 218;
+ break;
+ case 3:
+ mtd->oobsize = 400;
+ break;
+ default:
+ mtd->oobsize = 436;
+ break;
+ }
+ extid >>= 2;
+ /* Calc blocksize */
+ mtd->erasesize = (128 * 1024) <<
+ (((extid >> 1) & 0x04) | (extid & 0x03));
+ busw = 0;
+ } else {
+ /* Calc pagesize */
+ mtd->writesize = 1024 << (extid & 0x03);
+ extid >>= 2;
+ /* Calc oobsize */
+ mtd->oobsize = (8 << (extid & 0x01)) *
+ (mtd->writesize >> 9);
+ extid >>= 2;
+ /* Calc blocksize. Blocksize is multiples of 64KiB */
+ mtd->erasesize = (64 * 1024) << (extid & 0x03);
+ extid >>= 2;
+ /* Get buswidth information */
+ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ }
+
} else {
/*
@@ -1228,6 +1274,19 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
busw = type->options & NAND_BUSWIDTH_16;
+
+ /*
+ * Check for Spansion/AMD ID + repeating 5th, 6th byte since
+ * some Spansion chips have erasesize that conflicts with size
+ * listed in nand_ids table
+ * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
+ */
+ if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 &&
+ id_data[5] == 0x00 && id_data[6] == 0x00 &&
+ id_data[7] == 0x00 && mtd->writesize == 512) {
+ mtd->erasesize = 128 * 1024;
+ mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
+ }
}
/* Try to identify manufacturer */
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index cb53fc61ca..72593d44a8 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -118,6 +118,36 @@ struct nand_flash_dev nand_flash_ids[] = {
{__NANDSTR("NAND 2GiB 1,8V 16-bit"), 0xB5, 0, 2048, 0, LP_OPTIONS16},
{__NANDSTR("NAND 2GiB 3,3V 16-bit"), 0xC5, 0, 2048, 0, LP_OPTIONS16},
+ /* 32 Gigabit */
+ {__NANDSTR("NAND 4GiB 1,8V 8-bit"), 0xA7, 0, 4096, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 4GiB 3,3V 8-bit"), 0xD7, 0, 4096, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 4GiB 1,8V 16-bit"), 0xB7, 0, 4096, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 4GiB 3,3V 16-bit"), 0xC7, 0, 4096, 0, LP_OPTIONS16},
+
+ /* 64 Gigabit */
+ {__NANDSTR("NAND 8GiB 1,8V 8-bit"), 0xAE, 0, 8192, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 8GiB 3,3V 8-bit"), 0xDE, 0, 8192, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 8GiB 1,8V 16-bit"), 0xBE, 0, 8192, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 8GiB 3,3V 16-bit"), 0xCE, 0, 8192, 0, LP_OPTIONS16},
+
+ /* 128 Gigabit */
+ {__NANDSTR("NAND 16GiB 1,8V 8-bit"), 0x1A, 0, 16384, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 16GiB 3,3V 8-bit"), 0x3A, 0, 16384, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 16GiB 1,8V 16-bit"), 0x2A, 0, 16384, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 16GiB 3,3V 16-bit"), 0x4A, 0, 16384, 0, LP_OPTIONS16},
+
+ /* 256 Gigabit */
+ {__NANDSTR("NAND 32GiB 1,8V 8-bit"), 0x1C, 0, 32768, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 32GiB 3,3V 8-bit"), 0x3C, 0, 32768, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 32GiB 1,8V 16-bit"), 0x2C, 0, 32768, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 32GiB 3,3V 16-bit"), 0x4C, 0, 32768, 0, LP_OPTIONS16},
+
+ /* 512 Gigabit */
+ {__NANDSTR("NAND 64GiB 1,8V 8-bit"), 0x1E, 0, 65536, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 64GiB 3,3V 8-bit"), 0x3E, 0, 65536, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 64GiB 1,8V 16-bit"), 0x2E, 0, 65536, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 64GiB 3,3V 16-bit"), 0x4E, 0, 65536, 0, LP_OPTIONS16},
+
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
* have a strange page/block layout ! The chosen minimum erasesize is
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 3c5f729db3..b3e5a83dc1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -19,64 +19,71 @@ config HAS_DESIGNWARE_ETH
config ARCH_HAS_FEC_IMX
bool
-config MIIDEV
+config PHYLIB
bool
menu "Network drivers "
depends on NET
+source "drivers/net/phy/Kconfig"
+
config DRIVER_NET_CS8900
bool "cs8900 ethernet driver"
depends on HAS_CS8900
config DRIVER_NET_SMC911X
bool "smc911x ethernet driver"
- select MIIDEV
+ select PHYLIB
help
This option enables support for the SMSC LAN9[12]1[567]
ethernet chip.
config DRIVER_NET_SMC91111
bool "smc91111 ethernet driver"
- select MIIDEV
+ select PHYLIB
help
This option enables support for the SMSC LAN91C111
ethernet chip.
+config DRIVER_NET_DAVINCI_EMAC
+ bool "TI Davinci/OMAP EMAC ethernet driver"
+ depends on ARCH_DAVINCI || ARCH_OMAP3
+ select PHYLIB
+
config DRIVER_NET_DM9K
bool "Davicom dm9k[E|A|B] ethernet driver"
depends on HAS_DM9000
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_NETX
bool "Hilscher Netx ethernet driver"
depends on HAS_NETX_ETHER
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_AT91_ETHER
bool "at91 ethernet driver"
depends on HAS_AT91_ETHER
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_MPC5200
bool "MPC5200 Ethernet driver"
depends on ARCH_MPC5200
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_FEC_IMX
bool "i.MX FEC Ethernet driver"
depends on ARCH_HAS_FEC_IMX
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_EP93XX
bool "EP93xx Ethernet driver"
depends on ARCH_EP93XX
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_MACB
bool "macb Ethernet driver"
depends on HAS_MACB
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_TAP
bool "tap Ethernet driver"
@@ -85,7 +92,7 @@ config DRIVER_NET_TAP
config DRIVER_NET_TSE
depends on NIOS2
bool "Altera TSE ethernet driver"
- select MIIDEV
+ select PHYLIB
help
This option enables support for the Altera TSE MAC.
@@ -100,14 +107,14 @@ config TSE_USE_DEDICATED_DESC_MEM
config DRIVER_NET_KS8851_MLL
bool "ks8851 mll ethernet driver"
- select MIIDEV
+ select PHYLIB
help
This option enables support for the Micrel KS8851 MLL
ethernet chip.
config DRIVER_NET_DESIGNWARE
bool "Designware Universal MAC ethernet driver"
- select MIIDEV
+ select PHYLIB
depends on HAS_DESIGNWARE_ETH
help
This option enables support for the Synopsys
@@ -121,9 +128,16 @@ config DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR
config DRIVER_NET_GIANFAR
bool "Gianfar Ethernet"
depends on ARCH_MPC85XX
- select MIIDEV
+ select PHYLIB
source "drivers/net/usb/Kconfig"
+config DRIVER_NET_MICREL
+ depends on SPI
+ bool "Micrel KSZ8864RMN Ethernet Switch driver"
+ help
+ This option enables support for enabling the Micrel
+ KSZ8864RMN Ethernet Switch over SPI.
+
endmenu
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4d960e856f..4e6b49b191 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o
obj-$(CONFIG_DRIVER_NET_SMC911X) += smc911x.o
obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o
+obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC) += davinci_emac.o
obj-$(CONFIG_DRIVER_NET_DM9K) += dm9k.o
obj-$(CONFIG_DRIVER_NET_NETX) += netx_eth.o
obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o
@@ -9,9 +10,10 @@ obj-$(CONFIG_DRIVER_NET_FEC_IMX) += fec_imx.o
obj-$(CONFIG_DRIVER_NET_EP93XX) += ep93xx.o
obj-$(CONFIG_DRIVER_NET_MACB) += macb.o
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
-obj-$(CONFIG_MIIDEV) += miidev.o
+obj-$(CONFIG_PHYLIB) += phy/
obj-$(CONFIG_NET_USB) += usb/
obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
obj-$(CONFIG_DRIVER_NET_KS8851_MLL) += ks8851_mll.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
obj-$(CONFIG_DRIVER_NET_GIANFAR) += gianfar.o
+obj-$(CONFIG_DRIVER_NET_MICREL) += ksz8864rmn.o
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c
index 4643f001b4..9323f38019 100644
--- a/drivers/net/altera_tse.c
+++ b/drivers/net/altera_tse.c
@@ -22,10 +22,10 @@
#include <common.h>
#include <net.h>
-#include <miidev.h>
#include <init.h>
#include <clock.h>
#include <linux/mii.h>
+#include <linux/phy.h>
#include <io.h>
#include <asm/dma-mapping.h>
@@ -243,10 +243,9 @@ static int tse_set_ethaddr(struct eth_device *edev, unsigned char *m)
return 0;
}
-static int tse_phy_read(struct mii_device *mdev, int phy_addr, int reg)
+static int tse_phy_read(struct mii_bus *bus, int phy_addr, int reg)
{
- struct eth_device *edev = mdev->edev;
- struct altera_tse_priv *priv = edev->priv;
+ struct altera_tse_priv *priv = bus->priv;
struct alt_tse_mac *mac_dev = priv->tse_regs;
uint32_t *mdio_regs;
@@ -257,10 +256,9 @@ static int tse_phy_read(struct mii_device *mdev, int phy_addr, int reg)
return readl(&mdio_regs[reg]) & 0xFFFF;
}
-static int tse_phy_write(struct mii_device *mdev, int phy_addr, int reg, int val)
+static int tse_phy_write(struct mii_bus *bus, int phy_addr, int reg, u16 val)
{
- struct eth_device *edev = mdev->edev;
- struct altera_tse_priv *priv = edev->priv;
+ struct altera_tse_priv *priv = bus->priv;
struct alt_tse_mac *mac_dev = priv->tse_regs;
uint32_t *mdio_regs;
@@ -343,9 +341,12 @@ static void tse_reset(struct eth_device *edev)
static int tse_eth_open(struct eth_device *edev)
{
struct altera_tse_priv *priv = edev->priv;
+ int ret;
- miidev_wait_aneg(priv->miidev);
- miidev_print_status(priv->miidev);
+ ret = phy_device_connect(edev, priv->miibus, priv->phy_addr, NULL, 0,
+ PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
return 0;
}
@@ -484,15 +485,13 @@ static int tse_init_dev(struct eth_device *edev)
/* enable MAC */
writel(ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK, &mac_dev->command_config);
- miidev_restart_aneg(priv->miidev);
-
return 0;
}
static int tse_probe(struct device_d *dev)
{
struct altera_tse_priv *priv;
- struct mii_device *miidev;
+ struct mii_bus *miibus;
struct eth_device *edev;
struct alt_sgdma_descriptor *rx_desc;
struct alt_sgdma_descriptor *tx_desc;
@@ -501,7 +500,7 @@ static int tse_probe(struct device_d *dev)
#endif
edev = xzalloc(sizeof(struct eth_device));
priv = xzalloc(sizeof(struct altera_tse_priv));
- miidev = xzalloc(sizeof(struct mii_device));
+ miibus = xzalloc(sizeof(struct mii_bus));
edev->priv = priv;
@@ -523,7 +522,7 @@ static int tse_probe(struct device_d *dev)
if (!tx_desc) {
free(edev);
- free(miidev);
+ free(miibus);
return 0;
}
#endif
@@ -537,22 +536,19 @@ static int tse_probe(struct device_d *dev)
priv->rx_desc = rx_desc;
priv->tx_desc = tx_desc;
- priv->miidev = miidev;
+ priv->miibus = miibus;
- miidev->read = tse_phy_read;
- miidev->write = tse_phy_write;
- miidev->flags = 0;
- miidev->edev = edev;
- miidev->parent = dev;
+ miibus->read = tse_phy_read;
+ miibus->write = tse_phy_write;
+ miibus->priv = priv;
+ miibus->parent = dev;
if (dev->platform_data != NULL)
- miidev->address = *((int8_t *)(dev->platform_data));
- else {
- printf("No PHY address specified.\n");
- return -ENODEV;
- }
+ priv->phy_addr = *((int8_t *)(dev->platform_data));
+ else
+ priv->phy_addr = -1;
- mii_register(miidev);
+ mdiobus_register(miibus);
return eth_register(edev);
}
diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h
index 866dbce8c3..5a66a7d289 100644
--- a/drivers/net/altera_tse.h
+++ b/drivers/net/altera_tse.h
@@ -292,7 +292,8 @@ struct altera_tse_priv {
void __iomem *sgdma_tx_regs;
void __iomem *rx_desc;
void __iomem *tx_desc;
- struct mii_device *miidev;
+ int phy_addr;
+ struct mii_bus *miibus;
};
#endif /* _ALTERA_TSE_H_ */
diff --git a/drivers/net/at91_ether.c b/drivers/net/at91_ether.c
index cd00dabf4a..dee2039b11 100644
--- a/drivers/net/at91_ether.c
+++ b/drivers/net/at91_ether.c
@@ -26,7 +26,6 @@
#include <driver.h>
#include <xfuncs.h>
#include <init.h>
-#include <miidev.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/at91rm9200_emac.h>
@@ -36,18 +35,18 @@
#include <linux/mii.h>
#include <errno.h>
#include <asm/mmu.h>
+#include <linux/phy.h>
#include "at91_ether.h"
-#define SPEED_100 1
-#define DUPLEX_FULL 1
-
struct ether_device {
struct eth_device netdev;
- struct mii_device miidev;
+ struct mii_bus miibus;
struct rbf_t *rbfp;
struct rbf_t *rbfdt;
unsigned char *rbf_framebuf;
+ int phy_addr;
+ phy_interface_t interface;
};
#define to_ether(_nd) container_of(_nd, struct ether_device, netdev)
@@ -94,7 +93,7 @@ static inline int at91_phy_wait(void)
return 0;
}
-static int at91_ether_mii_read(struct mii_device *dev, int addr, int reg)
+static int at91_ether_mii_read(struct mii_bus *dev, int addr, int reg)
{
int value;
@@ -116,7 +115,7 @@ out:
return value;
}
-static int at91_ether_mii_write(struct mii_device *dev, int addr, int reg, int val)
+static int at91_ether_mii_write(struct mii_bus *dev, int addr, int reg, u16 val)
{
int ret;
@@ -132,19 +131,19 @@ static int at91_ether_mii_write(struct mii_device *dev, int addr, int reg, int v
return ret;
}
-static void update_linkspeed(struct mii_device *dev, int speed, int duplex)
+static void update_linkspeed(struct eth_device *edev)
{
unsigned int mac_cfg;
/* Update the MAC */
mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
- if (speed == SPEED_100) {
- if (duplex == DUPLEX_FULL) /* 100 Full Duplex */
+ if (edev->phydev->speed == SPEED_100) {
+ if (edev->phydev->duplex)
mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
else /* 100 Half Duplex */
mac_cfg |= AT91_EMAC_SPD;
} else {
- if (duplex == DUPLEX_FULL) /* 10 Full Duplex */
+ if (edev->phydev->duplex)
mac_cfg |= AT91_EMAC_FD;
else {} /* 10 Half Duplex */
}
@@ -157,11 +156,12 @@ static int at91_ether_open(struct eth_device *edev)
unsigned long ctl;
struct ether_device *etdev = to_ether(edev);
unsigned char *rbf_framebuf = etdev->rbf_framebuf;
+ int ret;
- miidev_wait_aneg(&etdev->miidev);
- miidev_print_status(&etdev->miidev);
-
- update_linkspeed(&etdev->miidev, SPEED_100, DUPLEX_FULL);
+ ret = phy_device_connect(edev, &etdev->miibus, etdev->phy_addr,
+ update_linkspeed, 0, etdev->interface);
+ if (ret)
+ return ret;
/* Clear internal statistics */
ctl = at91_emac_read(AT91_EMAC_CTL);
@@ -295,7 +295,7 @@ static int at91_ether_probe(struct device_d *dev)
unsigned int mac_cfg;
struct ether_device *ether_dev;
struct eth_device *edev;
- struct mii_device *miidev;
+ struct mii_bus *miibus;
unsigned long ether_hz;
struct clk *pclk;
struct at91_ether_platform_data *pdata;
@@ -310,7 +310,7 @@ static int at91_ether_probe(struct device_d *dev)
ether_dev = xzalloc(sizeof(struct ether_device));
edev = &ether_dev->netdev;
- miidev = &ether_dev->miidev;
+ miibus = &ether_dev->miibus;
edev->priv = ether_dev;
edev->init = at91_ether_init;
@@ -323,10 +323,9 @@ static int at91_ether_probe(struct device_d *dev)
ether_dev->rbf_framebuf = dma_alloc_coherent(MAX_RX_DESCR * MAX_RBUFF_SZ);
ether_dev->rbfdt = dma_alloc_coherent(sizeof(struct rbf_t) * MAX_RX_DESCR);
- miidev->address = pdata->phy_addr;
- miidev->read = at91_ether_mii_read;
- miidev->write = at91_ether_mii_write;
- miidev->edev = edev;
+ ether_dev->phy_addr = pdata->phy_addr;
+ miibus->read = at91_ether_mii_read;
+ miibus->write = at91_ether_mii_write;
/* Sanitize the clocks */
mac_cfg = at91_emac_read(AT91_EMAC_CFG);
@@ -343,12 +342,16 @@ static int at91_ether_probe(struct device_d *dev)
mac_cfg |= AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG;
- if (pdata->flags & AT91SAM_ETHER_RMII)
+ if (pdata->flags & AT91SAM_ETHER_RMII) {
+ ether_dev->interface = PHY_INTERFACE_MODE_RGMII;
mac_cfg |= AT91_EMAC_RMII;
+ } else {
+ ether_dev->interface = PHY_INTERFACE_MODE_MII;
+ }
at91_emac_write(AT91_EMAC_CFG, mac_cfg);
- mii_register(miidev);
+ mdiobus_register(miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
new file mode 100644
index 0000000000..7d4dbdcdd9
--- /dev/null
+++ b/drivers/net/davinci_emac.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
+ *
+ * Ethernet driver for TI TMS320DM644x (DaVinci) chips.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
+ * follows:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.c
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+
+ * Modifications:
+ * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot.
+ * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors
+ *
+ */
+
+#include <common.h>
+#include <io.h>
+#include <clock.h>
+#include <net.h>
+#include <malloc.h>
+#include <init.h>
+#include <asm/mmu.h>
+#include <asm/system.h>
+#include <linux/phy.h>
+#include <mach/emac_defs.h>
+#include <net/davinci_emac.h>
+#include "davinci_emac.h"
+
+struct davinci_emac_priv {
+ struct device_d *dev;
+ struct eth_device edev;
+ struct mii_bus miibus;
+
+ /* EMAC Addresses */
+ void __iomem *adap_emac; /* = EMAC_BASE_ADDR */
+ void __iomem *adap_ewrap; /* = EMAC_WRAPPER_BASE_ADDR */
+ void __iomem *adap_mdio; /* = EMAC_MDIO_BASE_ADDR */
+
+ /* EMAC descriptors */
+ void __iomem *emac_desc_base; /* = EMAC_WRAPPER_RAM_ADDR */
+ void __iomem *emac_rx_desc; /* = EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE */
+ void __iomem *emac_tx_desc; /* = EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE */
+ void __iomem *emac_rx_active_head; /* = 0 */
+ void __iomem *emac_rx_active_tail; /* = 0 */
+ int emac_rx_queue_active; /* = 0 */
+
+ /* Receive packet buffers */
+ unsigned char *emac_rx_buffers; /* [EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)] */
+
+ /* PHY-specific information */
+ phy_interface_t interface;
+ uint8_t phy_addr;
+ uint32_t phy_flags;
+
+ /* mac_addr[0] goes out on the wire first */
+ uint8_t mac_addr[6];
+};
+
+#ifdef EMAC_HW_RAM_ADDR
+static inline uint32_t BD_TO_HW(void __iomem *x)
+{
+ if (x == 0)
+ return 0;
+
+ return (uint32_t)(x) - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR;
+}
+
+static inline void __iomem *HW_TO_BD(uint32_t x)
+{
+ if (x == 0)
+ return 0;
+
+ return (struct emac_desc*)(x - EMAC_HW_RAM_ADDR + EMAC_WRAPPER_RAM_ADDR);
+}
+#else
+#define BD_TO_HW(x) (x)
+#define HW_TO_BD(x) (x)
+#endif
+
+static void davinci_eth_mdio_enable(struct davinci_emac_priv *priv)
+{
+ uint32_t clkdiv;
+
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+
+ dev_dbg(priv->dev, "mdio_enable + 0x%08x\n",
+ readl(priv->adap_mdio + EMAC_MDIO_CONTROL));
+ writel((clkdiv & 0xff) |
+ MDIO_CONTROL_ENABLE |
+ MDIO_CONTROL_FAULT |
+ MDIO_CONTROL_FAULT_ENABLE,
+ priv->adap_mdio + EMAC_MDIO_CONTROL);
+ dev_dbg(priv->dev, "mdio_enable - 0x%08x\n",
+ readl(priv->adap_mdio + EMAC_MDIO_CONTROL));
+
+ while (readl(priv->adap_mdio + EMAC_MDIO_CONTROL) & MDIO_CONTROL_IDLE);
+}
+
+static int davinci_miibus_read(struct mii_bus *bus, int addr, int reg)
+{
+ struct davinci_emac_priv *priv = bus->priv;
+ uint16_t value;
+ int tmp;
+
+ while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ writel(MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_READ |
+ ((reg & 0x1f) << 21) |
+ ((addr & 0x1f) << 16),
+ priv->adap_mdio + EMAC_MDIO_USERACCESS0);
+
+ /* Wait for command to complete */
+ while ((tmp = readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0)) & MDIO_USERACCESS0_GO);
+
+ if (tmp & MDIO_USERACCESS0_ACK) {
+ value = tmp & 0xffff;
+ dev_dbg(priv->dev, "davinci_miibus_read: addr=0x%02x reg=0x%02x value=0x%04x\n",
+ addr, reg, value);
+ return value;
+ }
+
+ return -1;
+}
+
+static int davinci_miibus_write(struct mii_bus *bus, int addr, int reg, u16 value)
+{
+ struct davinci_emac_priv *priv = bus->priv;
+ while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ dev_dbg(priv->dev, "davinci_miibus_write: addr=0x%02x reg=0x%02x value=0x%04x\n",
+ addr, reg, value);
+ writel(MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_WRITE |
+ ((reg & 0x1f) << 21) |
+ ((addr & 0x1f) << 16) |
+ (value & 0xffff),
+ priv->adap_mdio + EMAC_MDIO_USERACCESS0);
+
+ /* Wait for command to complete */
+ while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ return 0;
+}
+
+static int davinci_emac_get_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+ return -1;
+}
+
+/*
+ * This function must be called before emac_open() if you want to override
+ * the default mac address.
+ */
+static int davinci_emac_set_ethaddr(struct eth_device *edev, unsigned char *addr)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+ int i;
+
+ for (i = 0; i < sizeof(priv->mac_addr); i++)
+ priv->mac_addr[i] = addr[i];
+ return 0;
+}
+
+static int davinci_emac_init(struct eth_device *edev)
+{
+ dev_dbg(&edev->dev, "* emac_init\n");
+ return 0;
+}
+
+static int davinci_emac_open(struct eth_device *edev)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+ uint32_t clkdiv, cnt;
+ void __iomem *rx_desc;
+ unsigned long mac_hi, mac_lo;
+ int ret;
+
+ dev_dbg(priv->dev, "+ emac_open\n");
+
+ dev_dbg(priv->dev, "emac->TXIDVER: 0x%08x\n",
+ readl(priv->adap_emac + EMAC_TXIDVER));
+ dev_dbg(priv->dev, "emac->RXIDVER: 0x%08x\n",
+ readl(priv->adap_emac + EMAC_RXIDVER));
+
+ /* Reset EMAC module and disable interrupts in wrapper */
+ writel(1, priv->adap_emac + EMAC_SOFTRESET);
+ while (readl(priv->adap_emac + EMAC_SOFTRESET) != 0);
+ writel(1, priv->adap_ewrap + EMAC_EWRAP_SOFTRESET);
+ while (readl(priv->adap_ewrap + EMAC_EWRAP_SOFTRESET) != 0);
+
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0MISCEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1MISCEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2MISCEN);
+
+ rx_desc = priv->emac_rx_desc;
+
+ /*
+ * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast
+ * receive)
+ * Use channel 0 only - other channels are disabled
+ */
+ writel(0, priv->adap_emac + EMAC_MACINDEX);
+ mac_hi = (priv->mac_addr[3] << 24) |
+ (priv->mac_addr[2] << 16) |
+ (priv->mac_addr[1] << 8) |
+ (priv->mac_addr[0]);
+ mac_lo = (priv->mac_addr[5] << 8) |
+ (priv->mac_addr[4]);
+
+ writel(mac_hi, priv->adap_emac + EMAC_MACADDRHI);
+ writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH,
+ priv->adap_emac + EMAC_MACADDRLO);
+
+ /* Set source MAC address - REQUIRED */
+ writel(mac_hi, priv->adap_emac + EMAC_MACSRCADDRHI);
+ writel(mac_lo, priv->adap_emac + EMAC_MACSRCADDRLO);
+
+ /* Set DMA head and completion pointers to 0 */
+ for(cnt = 0; cnt < 8; cnt++) {
+ writel(0, (void *)priv->adap_emac + EMAC_TX0HDP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_RX0HDP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_TX0CP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_RX0CP + 4 * cnt);
+ }
+
+ /* Clear Statistics (do this before setting MacControl register) */
+ for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
+ writel(0, (void *)priv->adap_emac + EMAC_RXGOODFRAMES + 4 * cnt);
+
+ /* No multicast addressing */
+ writel(0, priv->adap_emac + EMAC_MACHASH1);
+ writel(0, priv->adap_emac + EMAC_MACHASH2);
+
+ writel(0x01, priv->adap_emac + EMAC_TXCONTROL);
+ writel(0x01, priv->adap_emac + EMAC_RXCONTROL);
+
+ /* Create RX queue and set receive process in place */
+ priv->emac_rx_active_head = priv->emac_rx_desc;
+ for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
+ writel(BD_TO_HW(rx_desc + EMAC_DESC_SIZE), rx_desc + EMAC_DESC_NEXT);
+ writel(&priv->emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)], rx_desc + EMAC_DESC_BUFFER);
+ writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_desc + EMAC_DESC_BUFF_OFF_LEN);
+ writel(EMAC_CPPI_OWNERSHIP_BIT, rx_desc + EMAC_DESC_PKT_FLAG_LEN);
+ rx_desc += EMAC_DESC_SIZE;
+ }
+
+ /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
+ rx_desc -= EMAC_DESC_SIZE;
+ writel(0, rx_desc + EMAC_DESC_NEXT);
+ priv->emac_rx_active_tail = rx_desc;
+ priv->emac_rx_queue_active = 1;
+
+ /* Enable TX/RX */
+ writel(EMAC_MAX_ETHERNET_PKT_SIZE, priv->adap_emac + EMAC_RXMAXLEN);
+ writel(0, priv->adap_emac + EMAC_RXBUFFEROFFSET);
+
+ /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
+ writel(EMAC_RXMBPENABLE_RXBROADEN, priv->adap_emac + EMAC_RXMBPENABLE);
+
+ /* Enable ch 0 only */
+ writel(0x01, priv->adap_emac + EMAC_RXUNICASTSET);
+
+ /* Enable MII interface and full duplex mode (using RMMI) */
+ writel((EMAC_MACCONTROL_MIIEN_ENABLE |
+ EMAC_MACCONTROL_FULLDUPLEX_ENABLE |
+ EMAC_MACCONTROL_RMIISPEED_100),
+ priv->adap_emac + EMAC_MACCONTROL);
+
+ /* Init MDIO & get link state */
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+ writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
+ priv->adap_mdio + EMAC_MDIO_CONTROL);
+
+ /* Start receive process */
+ writel(BD_TO_HW(priv->emac_rx_desc), priv->adap_emac + EMAC_RX0HDP);
+
+ ret = phy_device_connect(edev, &priv->miibus, priv->phy_addr, NULL,
+ priv->phy_flags, priv->interface);
+ if (ret)
+ return ret;
+
+ dev_dbg(priv->dev, "- emac_open\n");
+
+ return 0;
+}
+
+/* EMAC Channel Teardown */
+static void davinci_eth_ch_teardown(struct davinci_emac_priv *priv, int ch)
+{
+ uint32_t dly = 0xff;
+ uint32_t cnt;
+
+ dev_dbg(priv->dev, "+ emac_ch_teardown\n");
+
+ if (ch == EMAC_CH_TX) {
+ /* Init TX channel teardown */
+ writel(0, priv->adap_emac + EMAC_TXTEARDOWN);
+ for(cnt = 0; cnt != 0xfffffffc; cnt = readl(priv->adap_emac + EMAC_TX0CP)) {
+ /* Wait here for Tx teardown completion interrupt to occur
+ * Note: A task delay can be called here to pend rather than
+ * occupying CPU cycles - anyway it has been found that teardown
+ * takes very few cpu cycles and does not affect functionality */
+ dly--;
+ udelay(1);
+ if (dly == 0)
+ break;
+ }
+ writel(cnt, priv->adap_emac + EMAC_TX0CP);
+ writel(0, priv->adap_emac + EMAC_TX0HDP);
+ } else {
+ /* Init RX channel teardown */
+ writel(0, priv->adap_emac + EMAC_RXTEARDOWN);
+ for(cnt = 0; cnt != 0xfffffffc; cnt = readl(priv->adap_emac + EMAC_RX0CP)) {
+ /* Wait here for Rx teardown completion interrupt to occur
+ * Note: A task delay can be called here to pend rather than
+ * occupying CPU cycles - anyway it has been found that teardown
+ * takes very few cpu cycles and does not affect functionality */
+ dly--;
+ udelay(1);
+ if (dly == 0)
+ break;
+ }
+ writel(cnt, priv->adap_emac + EMAC_RX0CP);
+ writel(0, priv->adap_emac + EMAC_RX0HDP);
+ }
+
+ dev_dbg(priv->dev, "- emac_ch_teardown\n");
+}
+
+static void davinci_emac_halt(struct eth_device *edev)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+
+ dev_dbg(priv->dev, "+ emac_halt\n");
+
+ davinci_eth_ch_teardown(priv, EMAC_CH_TX); /* TX Channel teardown */
+ davinci_eth_ch_teardown(priv, EMAC_CH_RX); /* RX Channel teardown */
+
+ /* Reset EMAC module and disable interrupts in wrapper */
+ writel(1, priv->adap_emac + EMAC_SOFTRESET);
+ writel(1, priv->adap_ewrap + EMAC_EWRAP_SOFTRESET);
+
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0MISCEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1MISCEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2MISCEN);
+
+ dev_dbg(priv->dev, "- emac_halt\n");
+}
+
+/*
+ * This function sends a single packet on the network and returns
+ * positive number (number of bytes transmitted) or negative for error
+ */
+static int davinci_emac_send(struct eth_device *edev, void *packet, int length)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+ uint64_t start;
+ int ret_status;
+
+ dev_dbg(priv->dev, "+ emac_send (length %d)\n", length);
+
+ /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
+ if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
+ length = EMAC_MIN_ETHERNET_PKT_SIZE;
+ }
+
+ /* Populate the TX descriptor */
+ writel(0, priv->emac_tx_desc + EMAC_DESC_NEXT);
+ writel((uint8_t *) packet, priv->emac_tx_desc + EMAC_DESC_BUFFER);
+ writel((length & 0xffff), priv->emac_tx_desc + EMAC_DESC_BUFF_OFF_LEN);
+ writel(((length & 0xffff) | EMAC_CPPI_SOP_BIT |
+ EMAC_CPPI_OWNERSHIP_BIT |
+ EMAC_CPPI_EOP_BIT),
+ priv->emac_tx_desc + EMAC_DESC_PKT_FLAG_LEN);
+ dma_flush_range((ulong) packet, (ulong)packet + length);
+ /* Send the packet */
+ writel(BD_TO_HW(priv->emac_tx_desc), priv->adap_emac + EMAC_TX0HDP);
+
+ /* Wait for packet to complete or link down */
+ start = get_time_ns();
+ while (1) {
+ if (readl(priv->adap_emac + EMAC_TXINTSTATRAW) & 0x01) {
+ /* Acknowledge the TX descriptor */
+ writel(BD_TO_HW(priv->emac_tx_desc), priv->adap_emac + EMAC_TX0CP);
+ ret_status = 0;
+ break;
+ }
+ if (is_timeout(start, 100 * MSECOND)) {
+ ret_status = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ dev_dbg(priv->dev, "- emac_send (ret_status %i)\n", ret_status);
+ return ret_status;
+}
+
+/*
+ * This function handles receipt of a packet from the network
+ */
+static int davinci_emac_recv(struct eth_device *edev)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+ void __iomem *rx_curr_desc, *curr_desc, *tail_desc;
+ unsigned char *pkt;
+ int status, len, ret = -1;
+
+ dev_dbg(priv->dev, "+ emac_recv\n");
+
+ rx_curr_desc = priv->emac_rx_active_head;
+ status = readl(rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN);
+ if (status & EMAC_CPPI_OWNERSHIP_BIT) {
+ ret = 0;
+ goto out;
+ }
+
+ if (status & EMAC_CPPI_RX_ERROR_FRAME) {
+ /* Error in packet - discard it and requeue desc */
+ dev_warn(priv->dev, "WARN: emac_rcv_pkt: Error in packet\n");
+ } else {
+ pkt = (unsigned char *)readl(rx_curr_desc + EMAC_DESC_BUFFER);
+ len = readl(rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN) & 0xffff;
+ dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len);
+ dma_inv_range((ulong)pkt,
+ (ulong)readl(rx_curr_desc + EMAC_DESC_BUFFER) + len);
+ net_receive(pkt, len);
+ ret = len;
+ }
+
+ /* Ack received packet descriptor */
+ writel(BD_TO_HW(rx_curr_desc), priv->adap_emac + EMAC_RX0CP);
+ curr_desc = rx_curr_desc;
+ priv->emac_rx_active_head = HW_TO_BD(readl(rx_curr_desc + EMAC_DESC_NEXT));
+
+ if (status & EMAC_CPPI_EOQ_BIT) {
+ if (priv->emac_rx_active_head) {
+ writel(BD_TO_HW(priv->emac_rx_active_head),
+ priv->adap_emac + EMAC_RX0HDP);
+ } else {
+ priv->emac_rx_queue_active = 0;
+ dev_info(priv->dev, "INFO:emac_rcv_packet: RX Queue not active\n");
+ }
+ }
+
+ /* Recycle RX descriptor */
+ writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN);
+ writel(EMAC_CPPI_OWNERSHIP_BIT, rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN);
+ writel(0, rx_curr_desc + EMAC_DESC_NEXT);
+
+ if (priv->emac_rx_active_head == 0) {
+ dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0\n");
+ priv->emac_rx_active_head = curr_desc;
+ priv->emac_rx_active_tail = curr_desc;
+ if (priv->emac_rx_queue_active != 0) {
+ writel(BD_TO_HW(priv->emac_rx_active_head), priv->adap_emac + EMAC_RX0HDP);
+ dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
+ priv->emac_rx_queue_active = 1;
+ }
+ } else {
+ tail_desc = priv->emac_rx_active_tail;
+ priv->emac_rx_active_tail = curr_desc;
+ writel(BD_TO_HW(curr_desc), tail_desc + EMAC_DESC_NEXT);
+ status = readl(tail_desc + EMAC_DESC_PKT_FLAG_LEN);
+ if (status & EMAC_CPPI_EOQ_BIT) {
+ writel(BD_TO_HW(curr_desc), priv->adap_emac + EMAC_RX0HDP);
+ status &= ~EMAC_CPPI_EOQ_BIT;
+ writel(status, tail_desc + EMAC_DESC_PKT_FLAG_LEN);
+ }
+ }
+
+out:
+ dev_dbg(priv->dev, "- emac_recv\n");
+
+ return ret;
+}
+
+static int davinci_emac_probe(struct device_d *dev)
+{
+ struct davinci_emac_platform_data *pdata;
+ struct davinci_emac_priv *priv;
+ uint64_t start;
+ uint32_t phy_mask;
+
+ dev_dbg(dev, "+ emac_probe\n");
+
+ if (!dev->platform_data) {
+ dev_err(dev, "no platform_data\n");
+ return -ENODEV;
+ }
+ pdata = dev->platform_data;
+
+ priv = xzalloc(sizeof(*priv));
+ dev->priv = priv;
+
+ priv->dev = dev;
+
+ priv->adap_emac = dev_request_mem_region(dev, 0);
+ priv->adap_ewrap = dev_request_mem_region(dev, 1);
+ priv->adap_mdio = dev_request_mem_region(dev, 2);
+ priv->emac_desc_base = dev_request_mem_region(dev, 3);
+
+ /* EMAC descriptors */
+ priv->emac_rx_desc = priv->emac_desc_base + EMAC_RX_DESC_BASE;
+ priv->emac_tx_desc = priv->emac_desc_base + EMAC_TX_DESC_BASE;
+ priv->emac_rx_active_head = NULL;
+ priv->emac_rx_active_tail = NULL;
+ priv->emac_rx_queue_active = 0;
+
+ /* Receive packet buffers */
+ priv->emac_rx_buffers = xmemalign(4096, EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN));
+
+ priv->edev.priv = priv;
+ priv->edev.init = davinci_emac_init;
+ priv->edev.open = davinci_emac_open;
+ priv->edev.halt = davinci_emac_halt;
+ priv->edev.send = davinci_emac_send;
+ priv->edev.recv = davinci_emac_recv;
+ priv->edev.get_ethaddr = davinci_emac_get_ethaddr;
+ priv->edev.set_ethaddr = davinci_emac_set_ethaddr;
+ priv->edev.parent = dev;
+
+ davinci_eth_mdio_enable(priv);
+
+ start = get_time_ns();
+ while (1) {
+ phy_mask = readl(priv->adap_mdio + EMAC_MDIO_ALIVE);
+ if (phy_mask) {
+ dev_info(dev, "detected phy mask 0x%x\n", phy_mask);
+ phy_mask = ~phy_mask;
+ break;
+ }
+ if (is_timeout(start, 256 * MSECOND)) {
+ dev_err(dev, "no live phy, scanning all\n");
+ phy_mask = 0;
+ break;
+ }
+ }
+
+ if (pdata->interface_rmii)
+ priv->interface = PHY_INTERFACE_MODE_RMII;
+ else
+ priv->interface = PHY_INTERFACE_MODE_MII;
+ priv->phy_addr = pdata->phy_addr;
+ priv->phy_flags = pdata->force_link ? PHYLIB_FORCE_LINK : 0;
+
+ priv->miibus.read = davinci_miibus_read;
+ priv->miibus.write = davinci_miibus_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
+ priv->miibus.phy_mask = phy_mask;
+
+ mdiobus_register(&priv->miibus);
+
+ eth_register(&priv->edev);
+
+ dev_dbg(dev, "- emac_probe\n");
+ return 0;
+}
+
+static void davinci_emac_remove(struct device_d *dev)
+{
+ struct davinci_emac_priv *priv = dev->priv;
+
+ davinci_emac_halt(&priv->edev);
+}
+
+static struct driver_d davinci_emac_driver = {
+ .name = "davinci_emac",
+ .probe = davinci_emac_probe,
+ .remove = davinci_emac_remove,
+};
+
+static int davinci_emac_register(void)
+{
+ register_driver(&davinci_emac_driver);
+ return 0;
+}
+
+device_initcall(davinci_emac_register);
diff --git a/drivers/net/davinci_emac.h b/drivers/net/davinci_emac.h
new file mode 100644
index 0000000000..c5fa018fb3
--- /dev/null
+++ b/drivers/net/davinci_emac.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Based on:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.h
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef _DAVINCI_EMAC_H_
+#define _DAVINCI_EMAC_H_
+
+/* PHY mask - set only those phy number bits where phy is/can be connected */
+#define EMAC_MDIO_PHY_NUM 1
+#define EMAC_MDIO_PHY_MASK (1 << EMAC_MDIO_PHY_NUM)
+
+/* Ethernet Min/Max packet size */
+#define EMAC_MIN_ETHERNET_PKT_SIZE 60
+#define EMAC_MAX_ETHERNET_PKT_SIZE 1518
+#define EMAC_PKT_ALIGN 18 /* 1518 + 18 = 1536 (packet aligned on 32 byte boundry) */
+
+/* Number of RX packet buffers
+ * NOTE: Only 1 buffer supported as of now
+ */
+#define EMAC_MAX_RX_BUFFERS 10
+
+/***********************************************
+ ******** Internally used macros ***************
+ ***********************************************/
+
+#define EMAC_CH_TX 1
+#define EMAC_CH_RX 0
+
+/* Each descriptor occupies 4 words, lets start RX desc's at 0 and
+ * reserve space for 64 descriptors max
+ */
+#define EMAC_RX_DESC_BASE 0x0
+#define EMAC_TX_DESC_BASE 0x1000
+
+/* EMAC Teardown value */
+#define EMAC_TEARDOWN_VALUE 0xfffffffc
+
+/* MII Status Register */
+#define MII_STATUS_REG 1
+
+/* Number of statistics registers */
+#define EMAC_NUM_STATS 36
+
+/* EMAC Descriptor Offsets */
+#define EMAC_DESC_NEXT 0x0 /* Pointer to next descriptor in chain */
+#define EMAC_DESC_BUFFER 0x4 /* Pointer to data buffer */
+#define EMAC_DESC_BUFF_OFF_LEN 0x8 /* Buffer Offset(MSW) and Length(LSW) */
+#define EMAC_DESC_PKT_FLAG_LEN 0xc /* Packet Flags(MSW) and Length(LSW) */
+#define EMAC_DESC_SIZE 0x10
+
+/* CPPI bit positions */
+#define EMAC_CPPI_SOP_BIT (0x80000000)
+#define EMAC_CPPI_EOP_BIT (0x40000000)
+#define EMAC_CPPI_OWNERSHIP_BIT (0x20000000)
+#define EMAC_CPPI_EOQ_BIT (0x10000000)
+#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (0x08000000)
+#define EMAC_CPPI_PASS_CRC_BIT (0x04000000)
+
+#define EMAC_CPPI_RX_ERROR_FRAME (0x03fc0000)
+
+#define EMAC_MACCONTROL_MIIEN_ENABLE (0x20)
+#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1)
+#define EMAC_MACCONTROL_GIGABIT_ENABLE (1 << 7)
+#define EMAC_MACCONTROL_GIGFORCE (1 << 17)
+#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15)
+
+#define EMAC_MAC_ADDR_MATCH (1 << 19)
+#define EMAC_MAC_ADDR_IS_VALID (1 << 20)
+
+#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000)
+#define EMAC_RXMBPENABLE_RXBROADEN (0x2000)
+
+#define MDIO_CONTROL_IDLE (0x80000000)
+#define MDIO_CONTROL_ENABLE (0x40000000)
+#define MDIO_CONTROL_FAULT_ENABLE (0x40000)
+#define MDIO_CONTROL_FAULT (0x80000)
+#define MDIO_USERACCESS0_GO (0x80000000)
+#define MDIO_USERACCESS0_WRITE_READ (0x0)
+#define MDIO_USERACCESS0_WRITE_WRITE (0x40000000)
+#define MDIO_USERACCESS0_ACK (0x20000000)
+
+/* Ethernet MAC Registers */
+#define EMAC_TXIDVER 0x000
+#define EMAC_TXCONTROL 0x004
+#define EMAC_TXTEARDOWN 0x008
+#define EMAC_RXIDVER 0x010
+#define EMAC_RXCONTROL 0x014
+#define EMAC_RXTEARDOWN 0x018
+#define EMAC_TXINTSTATRAW 0x080
+#define EMAC_TXINTSTATMASKED 0x084
+#define EMAC_TXINTMASKSET 0x088
+#define EMAC_TXINTMASKCLEAR 0x08c
+#define EMAC_MACINVECTOR 0x090
+#define EMAC_MACEOIVECTOR 0x094
+#define EMAC_RXINTSTATRAW 0x0a0
+#define EMAC_RXINTSTATMASKED 0x0a4
+#define EMAC_RXINTMASKSET 0x0a8
+#define EMAC_RXINTMASKCLEAR 0x0ac
+#define EMAC_MACINTSTATRAW 0x0b0
+#define EMAC_MACINTSTATMASKED 0x0b4
+#define EMAC_MACINTMASKSET 0x0b8
+#define EMAC_MACINTMASKCLEAR 0x0bc
+#define EMAC_RXMBPENABLE 0x100
+#define EMAC_RXUNICASTSET 0x104
+#define EMAC_RXUNICASTCLEAR 0x108
+#define EMAC_RXMAXLEN 0x10c
+#define EMAC_RXBUFFEROFFSET 0x110
+#define EMAC_RXFILTERLOWTHRESH 0x114
+#define EMAC_RX0FLOWTHRESH 0x120
+#define EMAC_RX1FLOWTHRESH 0x124
+#define EMAC_RX2FLOWTHRESH 0x128
+#define EMAC_RX3FLOWTHRESH 0x12c
+#define EMAC_RX4FLOWTHRESH 0x130
+#define EMAC_RX5FLOWTHRESH 0x134
+#define EMAC_RX6FLOWTHRESH 0x138
+#define EMAC_RX7FLOWTHRESH 0x13c
+#define EMAC_RX0FREEBUFFER 0x140
+#define EMAC_RX1FREEBUFFER 0x144
+#define EMAC_RX2FREEBUFFER 0x148
+#define EMAC_RX3FREEBUFFER 0x14c
+#define EMAC_RX4FREEBUFFER 0x150
+#define EMAC_RX5FREEBUFFER 0x154
+#define EMAC_RX6FREEBUFFER 0x158
+#define EMAC_RX7FREEBUFFER 0x15c
+#define EMAC_MACCONTROL 0x160
+#define EMAC_MACSTATUS 0x164
+#define EMAC_EMCONTROL 0x168
+#define EMAC_FIFOCONTROL 0x16c
+#define EMAC_MACCONFIG 0x170
+#define EMAC_SOFTRESET 0x174
+#define EMAC_MACSRCADDRLO 0x1d0
+#define EMAC_MACSRCADDRHI 0x1d4
+#define EMAC_MACHASH1 0x1d8
+#define EMAC_MACHASH2 0x1dc
+#define EMAC_BOFFTEST 0x1e0
+#define EMAC_TPACETEST 0x1e4
+#define EMAC_RXPAUSE 0x1e8
+#define EMAC_TXPAUSE 0x1ec
+#define EMAC_RXGOODFRAMES 0x200
+#define EMAC_RXBCASTFRAMES 0x204
+#define EMAC_RXMCASTFRAMES 0x208
+#define EMAC_RXPAUSEFRAMES 0x20c
+#define EMAC_RXCRCERRORS 0x210
+#define EMAC_RXALIGNCODEERRORS 0x214
+#define EMAC_RXOVERSIZED 0x218
+#define EMAC_RXJABBER 0x21c
+#define EMAC_RXUNDERSIZED 0x220
+#define EMAC_RXFRAGMENTS 0x224
+#define EMAC_RXFILTERED 0x228
+#define EMAC_RXQOSFILTERED 0x22c
+#define EMAC_RXOCTETS 0x230
+#define EMAC_TXGOODFRAMES 0x234
+#define EMAC_TXBCASTFRAMES 0x238
+#define EMAC_TXMCASTFRAMES 0x23c
+#define EMAC_TXPAUSEFRAMES 0x240
+#define EMAC_TXDEFERRED 0x244
+#define EMAC_TXCOLLISION 0x248
+#define EMAC_TXSINGLECOLL 0x24c
+#define EMAC_TXMULTICOLL 0x250
+#define EMAC_TXEXCESSIVECOLL 0x254
+#define EMAC_TXLATECOLL 0x258
+#define EMAC_TXUNDERRUN 0x25c
+#define EMAC_TXCARRIERSENSE 0x260
+#define EMAC_TXOCTETS 0x264
+#define EMAC_FRAME64 0x268
+#define EMAC_FRAME65T127 0x26c
+#define EMAC_FRAME128T255 0x270
+#define EMAC_FRAME256T511 0x274
+#define EMAC_FRAME512T1023 0x278
+#define EMAC_FRAME1024TUP 0x27c
+#define EMAC_NETOCTETS 0x280
+#define EMAC_RXSOFOVERRUNS 0x284
+#define EMAC_RXMOFOVERRUNS 0x288
+#define EMAC_RXDMAOVERRUNS 0x28c
+#define EMAC_MACADDRLO 0x500
+#define EMAC_MACADDRHI 0x504
+#define EMAC_MACINDEX 0x508
+#define EMAC_TX0HDP 0x600
+#define EMAC_TX1HDP 0x604
+#define EMAC_TX2HDP 0x608
+#define EMAC_TX3HDP 0x60c
+#define EMAC_TX4HDP 0x610
+#define EMAC_TX5HDP 0x614
+#define EMAC_TX6HDP 0x618
+#define EMAC_TX7HDP 0x61c
+#define EMAC_RX0HDP 0x620
+#define EMAC_RX1HDP 0x624
+#define EMAC_RX2HDP 0x628
+#define EMAC_RX3HDP 0x62c
+#define EMAC_RX4HDP 0x630
+#define EMAC_RX5HDP 0x634
+#define EMAC_RX6HDP 0x638
+#define EMAC_RX7HDP 0x63c
+#define EMAC_TX0CP 0x640
+#define EMAC_TX1CP 0x644
+#define EMAC_TX2CP 0x648
+#define EMAC_TX3CP 0x64c
+#define EMAC_TX4CP 0x650
+#define EMAC_TX5CP 0x654
+#define EMAC_TX6CP 0x658
+#define EMAC_TX7CP 0x65c
+#define EMAC_RX0CP 0x660
+#define EMAC_RX1CP 0x664
+#define EMAC_RX2CP 0x668
+#define EMAC_RX3CP 0x66c
+#define EMAC_RX4CP 0x670
+#define EMAC_RX5CP 0x674
+#define EMAC_RX6CP 0x678
+#define EMAC_RX7CP 0x67c
+
+/* EMAC Wrapper Registers */
+#define EMAC_EWRAP_IDVER 0x00
+#define EMAC_EWRAP_SOFTRESET 0x04
+#define EMAC_EWRAP_INTCTRL 0x0c
+#define EMAC_EWRAP_C0RXTHRESHEN 0x10
+#define EMAC_EWRAP_C0RXEN 0x14
+#define EMAC_EWRAP_C0TXEN 0x18
+#define EMAC_EWRAP_C0MISCEN 0x1c
+#define EMAC_EWRAP_C1RXTHRESHEN 0x20
+#define EMAC_EWRAP_C1RXEN 0x24
+#define EMAC_EWRAP_C1TXEN 0x28
+#define EMAC_EWRAP_C1MISCEN 0x2c
+#define EMAC_EWRAP_C2RXTHRESHEN 0x30
+#define EMAC_EWRAP_C2RXEN 0x34
+#define EMAC_EWRAP_C2TXEN 0x38
+#define EMAC_EWRAP_C2MISCEN 0x3c
+#define EMAC_EWRAP_C0RXTHRESHSTAT 0x40
+#define EMAC_EWRAP_C0RXSTAT 0x44
+#define EMAC_EWRAP_C0TXSTAT 0x48
+#define EMAC_EWRAP_C0MISCSTAT 0x4c
+#define EMAC_EWRAP_C1RXTHRESHSTAT 0x50
+#define EMAC_EWRAP_C1RXSTAT 0x54
+#define EMAC_EWRAP_C1TXSTAT 0x58
+#define EMAC_EWRAP_C1MISCSTAT 0x5c
+#define EMAC_EWRAP_C2RXTHRESHSTAT 0x60
+#define EMAC_EWRAP_C2RXSTAT 0x64
+#define EMAC_EWRAP_C2TXSTAT 0x68
+#define EMAC_EWRAP_C2MISCSTAT 0x6c
+#define EMAC_EWRAP_C0RXIMAX 0x70
+#define EMAC_EWRAP_C0TXIMAX 0x74
+#define EMAC_EWRAP_C1RXIMAX 0x78
+#define EMAC_EWRAP_C1TXIMAX 0x7c
+#define EMAC_EWRAP_C2RXIMAX 0x80
+#define EMAC_EWRAP_C2TXIMAX 0x84
+
+/* EMAC MDIO Registers */
+#define EMAC_MDIO_VERSION 0x00
+#define EMAC_MDIO_CONTROL 0x04
+#define EMAC_MDIO_ALIVE 0x08
+#define EMAC_MDIO_LINK 0x0c
+#define EMAC_MDIO_LINKINTRAW 0x10
+#define EMAC_MDIO_LINKINTMASKED 0x14
+#define EMAC_MDIO_USERINTRAW 0x20
+#define EMAC_MDIO_USERINTMASKED 0x24
+#define EMAC_MDIO_USERINTMASKSET 0x28
+#define EMAC_MDIO_USERINTMASKCLEAR 0x2c
+#define EMAC_MDIO_USERACCESS0 0x80
+#define EMAC_MDIO_USERPHYSEL0 0x84
+#define EMAC_MDIO_USERACCESS1 0x88
+#define EMAC_MDIO_USERPHYSEL1 0x8c
+
+#endif /* _DAVINCI_EMAC_H_ */
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 379b4e39a5..2a87d26a51 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -29,15 +29,15 @@
#include <init.h>
#include <io.h>
#include <net.h>
-#include <miidev.h>
#include <asm/mmu.h>
#include <net/designware.h>
+#include <linux/phy.h>
#include "designware.h"
struct dw_eth_dev {
struct eth_device netdev;
- struct mii_device miidev;
+ struct mii_bus miibus;
void (*fix_mac_speed)(int speed);
u8 macaddr[6];
@@ -52,6 +52,7 @@ struct dw_eth_dev {
struct eth_mac_regs *mac_regs_p;
struct eth_dma_regs *dma_regs_p;
+ int phy_addr;
};
/* Speed specific definitions */
@@ -64,9 +65,9 @@ struct dw_eth_dev {
#define FULL_DUPLEX 2
-static int dwc_ether_mii_read(struct mii_device *dev, int addr, int reg)
+static int dwc_ether_mii_read(struct mii_bus *dev, int addr, int reg)
{
- struct dw_eth_dev *priv = dev->edev->priv;
+ struct dw_eth_dev *priv = dev->priv;
struct eth_mac_regs *mac_p = priv->mac_regs_p;
u64 start;
u32 miiaddr;
@@ -86,9 +87,9 @@ static int dwc_ether_mii_read(struct mii_device *dev, int addr, int reg)
return readl(&mac_p->miidata) & 0xffff;
}
-static int dwc_ether_mii_write(struct mii_device *dev, int addr, int reg, int val)
+static int dwc_ether_mii_write(struct mii_bus *dev, int addr, int reg, u16 val)
{
- struct dw_eth_dev *priv = dev->edev->priv;
+ struct dw_eth_dev *priv = dev->priv;
struct eth_mac_regs *mac_p = priv->mac_regs_p;
u64 start;
u32 miiaddr;
@@ -222,34 +223,37 @@ static int dwc_ether_init(struct eth_device *dev)
return 0;
}
-static int dwc_ether_open(struct eth_device *dev)
+static void dwc_update_linkspeed(struct eth_device *edev)
{
- 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;
+ struct dw_eth_dev *priv = edev->priv;
u32 conf;
- int link, speed;
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
- link = miidev_get_status(&priv->miidev);
-
- if (priv->fix_mac_speed) {
- speed = link & MIIDEV_STATUS_IS_1000MBIT ? 1000 :
- (link & MIIDEV_STATUS_IS_100MBIT ? 100 : 10);
- priv->fix_mac_speed(speed);
- }
+ if (priv->fix_mac_speed)
+ priv->fix_mac_speed(edev->phydev->speed);
conf = readl(&mac_p->conf);
- if (link & MIIDEV_STATUS_IS_FULL_DUPLEX)
+ if (edev->phydev->duplex)
conf |= FULLDPLXMODE;
else
conf &= ~FULLDPLXMODE;
- if (link & MIIDEV_STATUS_IS_1000MBIT)
+ if (edev->phydev->speed == SPEED_1000)
conf &= ~MII_PORTSELECT;
else
conf |= MII_PORTSELECT;
writel(conf, &mac_p->conf);
+}
+
+static int dwc_ether_open(struct eth_device *dev)
+{
+ 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;
+ int ret;
+
+ ret = phy_device_connect(dev, &priv->miibus, priv->phy_addr,
+ 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
descs_init(dev);
@@ -373,7 +377,7 @@ static int dwc_ether_probe(struct device_d *dev)
{
struct dw_eth_dev *priv;
struct eth_device *edev;
- struct mii_device *miidev;
+ struct mii_bus *miibus;
void __iomem *base;
struct dwc_ether_platform_data *pdata = dev->platform_data;
@@ -397,7 +401,7 @@ static int dwc_ether_probe(struct device_d *dev)
priv->fix_mac_speed = pdata->fix_mac_speed;
edev = &priv->netdev;
- miidev = &priv->miidev;
+ miibus = &priv->miibus;
edev->priv = priv;
edev->init = dwc_ether_init;
@@ -408,12 +412,12 @@ static int dwc_ether_probe(struct device_d *dev)
edev->get_ethaddr = dwc_ether_get_ethaddr;
edev->set_ethaddr = dwc_ether_set_ethaddr;
- miidev->address = pdata->phy_addr;
- miidev->read = dwc_ether_mii_read;
- miidev->write = dwc_ether_mii_write;
- miidev->edev = edev;
+ priv->phy_addr = pdata->phy_addr;
+ miibus->read = dwc_ether_mii_read;
+ miibus->write = dwc_ether_mii_write;
+ miibus->priv = priv;
- mii_register(miidev);
+ mdiobus_register(miibus);
eth_register(edev);
return 0;
}
diff --git a/drivers/net/dm9k.c b/drivers/net/dm9k.c
index 0222d98f7b..ac18be26c0 100644
--- a/drivers/net/dm9k.c
+++ b/drivers/net/dm9k.c
@@ -26,12 +26,12 @@
#include <init.h>
#include <common.h>
#include <driver.h>
-#include <miidev.h>
#include <net.h>
#include <io.h>
#include <xfuncs.h>
#include <dm9000.h>
#include <errno.h>
+#include <linux/phy.h>
#define DM9K_ID 0x90000A46
#define CHIPR_DM9000A 0x19
@@ -160,7 +160,7 @@
struct dm9k {
void __iomem *iobase;
void __iomem *iodata;
- struct mii_device miidev;
+ struct mii_bus miibus;
int buswidth;
int srom;
uint8_t pckt[2048];
@@ -353,12 +353,11 @@ static void dm9k_wd(int b_width, void __iomem *port, const void *src, int length
/* ----------------- end of data move functions -------------------------- */
-static int dm9k_phy_read(struct mii_device *mdev, int addr, int reg)
+static int dm9k_phy_read(struct mii_bus *bus, int addr, int reg)
{
unsigned val;
- struct eth_device *edev = mdev->edev;
- struct device_d *dev = edev->parent;
- struct dm9k *priv = edev->priv;
+ struct dm9k *priv = bus->priv;
+ struct device_d *dev = &bus->dev;
/* Fill the phyxcer register into REG_0C */
dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg);
@@ -374,11 +373,10 @@ static int dm9k_phy_read(struct mii_device *mdev, int addr, int reg)
return val;
}
-static int dm9k_phy_write(struct mii_device *mdev, int addr, int reg, int val)
+static int dm9k_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
{
- struct eth_device *edev = mdev->edev;
- struct device_d *dev = edev->parent;
- struct dm9k *priv = edev->priv;
+ struct dm9k *priv = bus->priv;
+ struct device_d *dev = &bus->dev;
/* Fill the phyxcer register into REG_0C */
dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg);
@@ -397,7 +395,7 @@ static int dm9k_phy_write(struct mii_device *mdev, int addr, int reg, int val)
static int dm9k_check_id(struct dm9k *priv)
{
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
u32 id;
char c;
@@ -461,7 +459,7 @@ static void dm9k_enable(struct dm9k *priv)
static void dm9k_reset(struct dm9k *priv)
{
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
dev_dbg(dev, "%s\n", __func__);
dm9k_iow(priv, DM9K_NCR, NCR_RST);
@@ -472,9 +470,8 @@ static int dm9k_eth_open(struct eth_device *edev)
{
struct dm9k *priv = (struct dm9k *)edev->priv;
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
- return 0;
+ return phy_device_connect(edev, &priv->miibus, 0, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
}
static void dm9k_write_length(struct dm9k *priv, unsigned length)
@@ -485,7 +482,7 @@ static void dm9k_write_length(struct dm9k *priv, unsigned length)
static int dm9k_wait_for_trans_end(struct dm9k *priv)
{
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
static const uint64_t toffs = 1 * SECOND;
uint8_t status;
uint64_t start = get_time_ns();
@@ -511,7 +508,7 @@ static int dm9k_wait_for_trans_end(struct dm9k *priv)
static int dm9k_eth_send(struct eth_device *edev, void *packet, int length)
{
struct dm9k *priv = (struct dm9k *)edev->priv;
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
dev_dbg(dev, "%s: %d bytes\n", __func__, length);
@@ -537,7 +534,7 @@ static int dm9k_eth_send(struct eth_device *edev, void *packet, int length)
static int dm9k_check_for_rx_packet(struct dm9k *priv)
{
uint8_t status;
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
status = dm9k_ior(priv, DM9K_ISR);
if (!(status & ISR_PR))
@@ -550,7 +547,7 @@ static int dm9k_check_for_rx_packet(struct dm9k *priv)
static int dm9k_validate_entry(struct dm9k *priv)
{
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
uint8_t p_stat;
/*
@@ -696,9 +693,6 @@ static int dm9k_set_ethaddr(struct eth_device *edev, unsigned char *adr)
static int dm9k_init_dev(struct eth_device *edev)
{
- struct dm9k *priv = (struct dm9k *)edev->priv;
-
- miidev_restart_aneg(&priv->miidev);
return 0;
}
@@ -740,12 +734,10 @@ static int dm9k_probe(struct device_d *dev)
edev->get_ethaddr = dm9k_get_ethaddr;
edev->parent = dev;
- priv->miidev.read = dm9k_phy_read;
- priv->miidev.write = dm9k_phy_write;
- priv->miidev.address = 0;
- priv->miidev.flags = 0;
- priv->miidev.edev = edev;
- priv->miidev.parent = dev;
+ priv->miibus.read = dm9k_phy_read;
+ priv->miibus.write = dm9k_phy_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
/* RESET device */
dm9k_reset(priv);
@@ -778,7 +770,7 @@ static int dm9k_probe(struct device_d *dev)
dm9k_enable(priv);
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/ep93xx.c b/drivers/net/ep93xx.c
index c28fb79e45..a14c0ea8e3 100644
--- a/drivers/net/ep93xx.c
+++ b/drivers/net/ep93xx.c
@@ -34,17 +34,17 @@
#include <command.h>
#include <init.h>
#include <malloc.h>
-#include <miidev.h>
#include <io.h>
#include <linux/types.h>
#include <mach/ep93xx-regs.h>
+#include <linux/phy.h>
#include "ep93xx.h"
#define EP93XX_MAX_PKT_SIZE 1536
-static int ep93xx_phy_read(struct mii_device *mdev, int phy_addr, int phy_reg);
-static int ep93xx_phy_write(struct mii_device *mdev, int phy_addr, int phy_reg,
- int value);
+static int ep93xx_phy_read(struct mii_bus *bus, int phy_addr, int phy_reg);
+static int ep93xx_phy_write(struct mii_bus *bus, int phy_addr, int phy_reg,
+ u16 value);
static inline struct ep93xx_eth_priv *ep93xx_get_priv(struct eth_device *edev)
{
@@ -199,9 +199,15 @@ static int ep93xx_eth_open(struct eth_device *edev)
struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev);
struct mac_regs *regs = ep93xx_get_regs(edev);
int i;
+ int ret;
pr_debug("+ep93xx_eth_open\n");
+ ret = phy_device_connect(edev, &priv->miibus, 0, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
+
ep93xx_eth_reset(edev);
/* Reset the descriptor queues' current and end address values */
@@ -498,11 +504,10 @@ static int ep93xx_eth_probe(struct device_d *dev)
edev->set_ethaddr = ep93xx_eth_set_ethaddr;
edev->parent = dev;
- priv->miidev.read = ep93xx_phy_read;
- priv->miidev.write = ep93xx_phy_write;
- priv->miidev.address = 0;
- priv->miidev.flags = 0;
- priv->miidev.parent = dev;
+ priv->miibus.read = ep93xx_phy_read;
+ priv->miibus.write = ep93xx_phy_write;
+ priv->miibus.parent = dev;
+ priv->miibus.priv = edev;
priv->tx_dq.base = calloc(NUMTXDESC,
sizeof(struct tx_descriptor));
@@ -532,7 +537,7 @@ static int ep93xx_eth_probe(struct device_d *dev)
goto eth_probe_failed_3;
}
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
ret = 0;
@@ -575,9 +580,9 @@ eth_probe_done:
/**
* Read a 16-bit value from an MII register.
*/
-static int ep93xx_phy_read(struct mii_device *mdev, int phy_addr, int phy_reg)
+static int ep93xx_phy_read(struct mii_bus *bus, int phy_addr, int phy_reg)
{
- struct mac_regs *regs = ep93xx_get_regs(mdev->edev);
+ struct mac_regs *regs = ep93xx_get_regs(bus->priv);
int value = -1;
uint32_t self_ctl;
@@ -618,10 +623,10 @@ static int ep93xx_phy_read(struct mii_device *mdev, int phy_addr, int phy_reg)
/**
* Write a 16-bit value to an MII register.
*/
-static int ep93xx_phy_write(struct mii_device *mdev, int phy_addr,
- int phy_reg, int value)
+static int ep93xx_phy_write(struct mii_bus *bus, int phy_addr,
+ int phy_reg, u16 value)
{
- struct mac_regs *regs = ep93xx_get_regs(mdev->edev);
+ struct mac_regs *regs = ep93xx_get_regs(bus->priv);
uint32_t self_ctl;
pr_debug("+ep93xx_phy_write\n");
diff --git a/drivers/net/ep93xx.h b/drivers/net/ep93xx.h
index 47622d6a24..89451b8a5f 100644
--- a/drivers/net/ep93xx.h
+++ b/drivers/net/ep93xx.h
@@ -137,7 +137,7 @@ struct ep93xx_eth_priv {
struct tx_descriptor_queue tx_dq;
struct tx_status_queue tx_sq;
- struct mii_device miidev;
+ struct mii_bus miibus;
};
#endif
diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c
index c80cdc96a5..6acf6bdee4 100644
--- a/drivers/net/fec_imx.c
+++ b/drivers/net/fec_imx.c
@@ -19,11 +19,11 @@
#include <net.h>
#include <init.h>
#include <driver.h>
-#include <miidev.h>
#include <fec.h>
#include <io.h>
#include <clock.h>
#include <xfuncs.h>
+#include <linux/phy.h>
#include <asm/mmu.h>
@@ -46,10 +46,9 @@ struct fec_frame {
/*
* MII-interface related functions
*/
-static int fec_miidev_read(struct mii_device *mdev, int phyAddr, int regAddr)
+static int fec_miibus_read(struct mii_bus *bus, int phyAddr, int regAddr)
{
- struct eth_device *edev = mdev->edev;
- struct fec_priv *fec = (struct fec_priv *)edev->priv;
+ struct fec_priv *fec = (struct fec_priv *)bus->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
@@ -89,11 +88,10 @@ static int fec_miidev_read(struct mii_device *mdev, int phyAddr, int regAddr)
return readl(fec->regs + FEC_MII_DATA);
}
-static int fec_miidev_write(struct mii_device *mdev, int phyAddr,
- int regAddr, int data)
+static int fec_miibus_write(struct mii_bus *bus, int phyAddr,
+ int regAddr, u16 data)
{
- struct eth_device *edev = mdev->edev;
- struct fec_priv *fec = (struct fec_priv *)edev->priv;
+ struct fec_priv *fec = (struct fec_priv *)bus->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
@@ -343,12 +341,20 @@ static int fec_init(struct eth_device *dev)
/* size of each buffer */
writel(FEC_MAX_PKT_SIZE, fec->regs + FEC_EMRBR);
- if (fec->xcv_type != SEVENWIRE)
- miidev_restart_aneg(&fec->miidev);
-
return 0;
}
+static void fec_update_linkspeed(struct eth_device *edev)
+{
+ struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+ if (edev->phydev->speed == SPEED_10) {
+ u32 rcntl = readl(fec->regs + FEC_R_CNTRL);
+ rcntl |= FEC_R_CNTRL_RMII_10T;
+ writel(rcntl, fec->regs + FEC_R_CNTRL);
+ }
+}
+
/**
* Start the FEC engine
* @param[in] edev Our device to handle
@@ -359,6 +365,17 @@ static int fec_open(struct eth_device *edev)
int ret;
u32 ecr;
+ if (fec->xcv_type != SEVENWIRE) {
+ ret = phy_device_connect(edev, &fec->miibus, fec->phy_addr,
+ fec_update_linkspeed, fec->phy_flags,
+ fec->interface);
+ if (ret)
+ return ret;
+
+ if (fec->phy_init)
+ fec->phy_init(edev->phydev);
+ }
+
/*
* Initialize RxBD/TxBD rings
*/
@@ -384,24 +401,6 @@ static int fec_open(struct eth_device *edev)
*/
fec_rx_task_enable(fec);
- if (fec->xcv_type != SEVENWIRE) {
- ret = miidev_wait_aneg(&fec->miidev);
- if (ret)
- return ret;
-
- ret = miidev_get_status(&fec->miidev);
- if (ret < 0)
- return ret;
-
- if (ret & MIIDEV_STATUS_IS_10MBIT) {
- u32 rcntl = readl(fec->regs + FEC_R_CNTRL);
- rcntl |= FEC_R_CNTRL_RMII_10T;
- writel(rcntl, fec->regs + FEC_R_CNTRL);
- }
-
- miidev_print_status(&fec->miidev);
- }
-
return 0;
}
@@ -655,14 +654,30 @@ static int fec_probe(struct device_d *dev)
fec->xcv_type = pdata->xcv_type;
if (fec->xcv_type != SEVENWIRE) {
- fec->miidev.read = fec_miidev_read;
- fec->miidev.write = fec_miidev_write;
- fec->miidev.address = pdata->phy_addr;
- fec->miidev.flags = pdata->xcv_type == MII10 ? MIIDEV_FORCE_10 : 0;
- fec->miidev.edev = edev;
- fec->miidev.parent = dev;
-
- mii_register(&fec->miidev);
+ fec->phy_init = pdata->phy_init;
+ fec->miibus.read = fec_miibus_read;
+ fec->miibus.write = fec_miibus_write;
+ fec->phy_addr = pdata->phy_addr;
+ switch (pdata->xcv_type) {
+ case RMII:
+ fec->interface = PHY_INTERFACE_MODE_RMII;
+ break;
+ case RGMII:
+ fec->interface = PHY_INTERFACE_MODE_RGMII;
+ break;
+ case MII10:
+ fec->phy_flags = PHYLIB_FORCE_10;
+ case MII100:
+ fec->interface = PHY_INTERFACE_MODE_MII;
+ break;
+ case SEVENWIRE:
+ fec->interface = PHY_INTERFACE_MODE_NA;
+ break;
+ }
+ fec->miibus.priv = fec;
+ fec->miibus.parent = dev;
+
+ mdiobus_register(&fec->miibus);
}
eth_register(edev);
diff --git a/drivers/net/fec_imx.h b/drivers/net/fec_imx.h
index b979f12a5b..d10385a531 100644
--- a/drivers/net/fec_imx.h
+++ b/drivers/net/fec_imx.h
@@ -133,7 +133,11 @@ struct fec_priv {
int rbd_index; /* next receive BD to read */
struct buffer_descriptor __iomem *tbd_base; /* TBD ring */
int tbd_index; /* next transmit BD to write */
- struct mii_device miidev;
+ int phy_addr;
+ phy_interface_t interface;
+ u32 phy_flags;
+ struct mii_bus miibus;
+ void (*phy_init)(struct phy_device *dev);
};
/**
diff --git a/drivers/net/fec_mpc5200.c b/drivers/net/fec_mpc5200.c
index c3f2099b0f..c42d86f513 100644
--- a/drivers/net/fec_mpc5200.c
+++ b/drivers/net/fec_mpc5200.c
@@ -10,13 +10,12 @@
#include <mach/mpc5xxx.h>
#include <malloc.h>
#include <net.h>
+#include <fec.h>
#include <init.h>
-#include <miidev.h>
#include <driver.h>
#include <mach/sdma.h>
-#include <mach/fec.h>
#include <mach/clocks.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include "fec_mpc5200.h"
#define CONFIG_PHY_ADDR 1 /* FIXME */
@@ -31,10 +30,9 @@ typedef struct {
/*
* MII-interface related functions
*/
-static int fec5xxx_miidev_read(struct mii_device *mdev, int phyAddr, int regAddr)
+static int fec5xxx_miibus_read(struct mii_bus *bus, int phyAddr, int regAddr)
{
- struct eth_device *edev = mdev->edev;
- mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)edev->priv;
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)bus->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
@@ -70,11 +68,10 @@ static int fec5xxx_miidev_read(struct mii_device *mdev, int phyAddr, int regAddr
return fec->eth->mii_data;
}
-static int fec5xxx_miidev_write(struct mii_device *mdev, int phyAddr,
- int regAddr, int data)
+static int fec5xxx_miibus_write(struct mii_bus *bus, int phyAddr,
+ int regAddr, u16 data)
{
- struct eth_device *edev = mdev->edev;
- mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)edev->priv;
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)bus->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
@@ -381,9 +378,6 @@ static int mpc5xxx_fec_init(struct eth_device *dev)
debug("mpc5xxx_fec_init... Done \n");
- if (fec->xcv_type != SEVENWIRE)
- miidev_restart_aneg(&fec->miidev);
-
return 0;
}
@@ -413,8 +407,8 @@ static int mpc5xxx_fec_open(struct eth_device *edev)
SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
if (fec->xcv_type != SEVENWIRE) {
- miidev_wait_aneg(&fec->miidev);
- miidev_print_status(&fec->miidev);
+ return phy_device_connect(edev, &fec->miibus, CONFIG_PHY_ADDR,
+ NULL, fec->phy_flags, fec->interface);
}
return 0;
@@ -556,7 +550,7 @@ static int mpc5xxx_fec_send(struct eth_device *dev, void *eth_data,
*/
if (fec->xcv_type != SEVENWIRE) {
uint16_t phyStatus;
- phyStatus = fec5xxx_miidev_read(&fec->miidev, 0, 0x1);
+ phyStatus = fec5xxx_miibus_read(&fec->miibus, 0, 0x1);
}
/*
@@ -657,7 +651,7 @@ static int mpc5xxx_fec_recv(struct eth_device *dev)
int mpc5xxx_fec_probe(struct device_d *dev)
{
- struct mpc5xxx_fec_platform_data *pdata = (struct mpc5xxx_fec_platform_data *)dev->platform_data;
+ struct fec_platform_data *pdata = dev->platform_data;
struct eth_device *edev;
mpc5xxx_fec_priv *fec;
@@ -683,14 +677,28 @@ int mpc5xxx_fec_probe(struct device_d *dev)
loadtask(0, 2);
if (fec->xcv_type != SEVENWIRE) {
- fec->miidev.read = fec5xxx_miidev_read;
- fec->miidev.write = fec5xxx_miidev_write;
- fec->miidev.address = CONFIG_PHY_ADDR;
- fec->miidev.flags = pdata->xcv_type == MII10 ? MIIDEV_FORCE_10 : 0;
- fec->miidev.edev = edev;
- fec->miidev.parent = dev;
-
- mii_register(&fec->miidev);
+ fec->miibus.read = fec5xxx_miibus_read;
+ fec->miibus.write = fec5xxx_miibus_write;
+ switch (pdata->xcv_type) {
+ case RMII:
+ fec->interface = PHY_INTERFACE_MODE_RMII;
+ break;
+ case RGMII:
+ fec->interface = PHY_INTERFACE_MODE_RGMII;
+ break;
+ case MII10:
+ fec->phy_flags = PHYLIB_FORCE_10;
+ case MII100:
+ fec->interface = PHY_INTERFACE_MODE_MII;
+ break;
+ case SEVENWIRE:
+ fec->interface = PHY_INTERFACE_MODE_NA;
+ break;
+ }
+ fec->miibus.priv = fec;
+ fec->miibus.parent = dev;
+
+ mdiobus_register(&fec->miibus);
}
eth_register(edev);
diff --git a/drivers/net/fec_mpc5200.h b/drivers/net/fec_mpc5200.h
index f6da3e598f..20ac60731c 100644
--- a/drivers/net/fec_mpc5200.h
+++ b/drivers/net/fec_mpc5200.h
@@ -260,7 +260,9 @@ typedef struct {
uint16_t usedTbdIndex; /* next transmit BD to clean */
uint16_t cleanTbdNum; /* the number of available transmit BDs */
- struct mii_device miidev;
+ phy_interface_t interface;
+ u32 phy_flags;
+ struct mii_bus miibus;
} mpc5xxx_fec_priv;
/* Ethernet parameter area */
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 19544de261..20fd102c7e 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -17,10 +17,10 @@
#include <net.h>
#include <init.h>
#include <driver.h>
-#include <miidev.h>
#include <command.h>
#include <errno.h>
#include <asm/io.h>
+#include <linux/phy.h>
#include "gianfar.h"
/* 2 seems to be the minimum number of TX descriptors to make it work. */
@@ -80,22 +80,16 @@ static void gfar_init_registers(void __iomem *regs)
static void gfar_adjust_link(struct eth_device *edev)
{
struct gfar_private *priv = edev->priv;
- struct device_d *mdev = priv->miidev.parent;
void __iomem *regs = priv->regs;
u32 ecntrl, maccfg2;
uint32_t status;
- status = miidev_get_status(&priv->miidev);
+ priv->link = edev->phydev->link;
+ priv->duplexity =edev->phydev->duplex;
- priv->link = status & MIIDEV_STATUS_IS_UP;
- if (status & MIIDEV_STATUS_IS_FULL_DUPLEX)
- priv->duplexity = 1;
- else
- priv->duplexity = 0;
-
- if (status & MIIDEV_STATUS_IS_1000MBIT)
+ if (edev->phydev->speed == SPEED_1000)
priv->speed = 1000;
- else if (status & MIIDEV_STATUS_IS_100MBIT)
+ if (edev->phydev->speed == SPEED_100)
priv->speed = 100;
else
priv->speed = 10;
@@ -128,18 +122,18 @@ static void gfar_adjust_link(struct eth_device *edev)
ecntrl |= GFAR_ECNTRL_R100;
break;
default:
- dev_info(mdev, "Speed is unknown\n");
+ dev_info(&edev->dev, "Speed is unknown\n");
break;
}
out_be32(regs + GFAR_ECNTRL_OFFSET, ecntrl);
out_be32(regs + GFAR_MACCFG2_OFFSET, maccfg2);
- dev_info(mdev, "Speed: %d, %s duplex\n", priv->speed,
+ dev_info(&edev->dev, "Speed: %d, %s duplex\n", priv->speed,
(priv->duplexity) ? "full" : "half");
} else {
- dev_info(mdev, "No link.\n");
+ dev_info(&edev->dev, "No link.\n");
}
}
@@ -184,8 +178,6 @@ static int gfar_init(struct eth_device *edev)
gfar_init_registers(regs);
- miidev_restart_aneg(&priv->miidev);
-
return 0;
}
@@ -194,6 +186,12 @@ static int gfar_open(struct eth_device *edev)
int ix;
struct gfar_private *priv = edev->priv;
void __iomem *regs = priv->regs;
+ int ret;
+
+ ret = phy_device_connect(edev, &priv->miibus, priv->phyaddr,
+ gfar_adjust_link, 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
/* Point to the buffer descriptors */
out_be32(regs + GFAR_TBASE0_OFFSET, (unsigned int)priv->txbd);
@@ -215,9 +213,6 @@ static int gfar_open(struct eth_device *edev)
}
priv->txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
- miidev_wait_aneg(&priv->miidev);
- gfar_adjust_link(edev);
-
/* Enable Transmit and Receive */
setbits_be32(regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_RX_EN |
GFAR_MACCFG1_TX_EN);
@@ -437,11 +432,10 @@ static int gfar_recv(struct eth_device *edev)
}
/* Read a MII PHY register. */
-static int gfar_miiphy_read(struct mii_device *mdev, int addr, int reg)
+static int gfar_miiphy_read(struct mii_bus *bus, int addr, int reg)
{
- struct eth_device *edev = mdev->edev;
- struct device_d *dev = edev->parent;
- struct gfar_private *priv = edev->priv;
+ struct device_d *dev = bus->parent;
+ struct gfar_private *priv = bus->priv;
int ret;
ret = gfar_local_mdio_read(priv->phyregs, addr, reg);
@@ -452,12 +446,11 @@ static int gfar_miiphy_read(struct mii_device *mdev, int addr, int reg)
}
/* Write a MII PHY register. */
-static int gfar_miiphy_write(struct mii_device *mdev, int addr, int reg,
- int value)
+static int gfar_miiphy_write(struct mii_bus *bus, int addr, int reg,
+ u16 value)
{
- struct eth_device *edev = mdev->edev;
- struct device_d *dev = edev->parent;
- struct gfar_private *priv = edev->priv;
+ struct device_d *dev = bus->parent;
+ struct gfar_private *priv = bus->priv;
unsigned short val = value;
int ret;
@@ -520,16 +513,14 @@ static int gfar_probe(struct device_d *dev)
udelay(2);
clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
- priv->miidev.read = gfar_miiphy_read;
- priv->miidev.write = gfar_miiphy_write;
- priv->miidev.address = priv->phyaddr;
- priv->miidev.flags = 0;
- priv->miidev.edev = edev;
- priv->miidev.parent = dev;
+ priv->miibus.read = gfar_miiphy_read;
+ priv->miibus.write = gfar_miiphy_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
gfar_init_phy(edev);
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
return eth_register(edev);
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index a4ad99e3b7..b52cc5ab3b 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -269,7 +269,7 @@ struct gfar_private {
void __iomem *phyregs;
void __iomem *phyregs_sgmii;
struct phy_info *phyinfo;
- struct mii_device miidev;
+ struct mii_bus miibus;
volatile struct txbd8 *txbd;
volatile struct rxbd8 *rxbd;
uint txidx;
diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c
index ba4b8c3b14..c48e729dce 100644
--- a/drivers/net/ks8851_mll.c
+++ b/drivers/net/ks8851_mll.c
@@ -22,13 +22,13 @@
#include <command.h>
#include <net.h>
-#include <miidev.h>
#include <malloc.h>
#include <init.h>
#include <xfuncs.h>
#include <errno.h>
#include <clock.h>
#include <io.h>
+#include <linux/phy.h>
#define MAX_RECV_FRAMES 32
#define MAX_BUF_SIZE 2048
@@ -368,7 +368,7 @@
struct ks_net {
struct eth_device edev;
- struct mii_device miidev;
+ struct mii_bus miibus;
void __iomem *hw_addr;
void __iomem *hw_addr_cmd;
struct platform_device *pdev;
@@ -532,10 +532,9 @@ static int ks_phy_reg(int reg)
* caller. The mii-tool that the driver was tested with takes any -ve error
* as real PHY capabilities, thus displaying incorrect data to the user.
*/
-static int ks_phy_read(struct mii_device *mdev, int addr, int reg)
+static int ks_phy_read(struct mii_bus *bus, int addr, int reg)
{
- struct eth_device *edev = mdev->edev;
- struct ks_net *priv = (struct ks_net *)edev->priv;
+ struct ks_net *priv = (struct ks_net *)bus->priv;
int ksreg;
int result;
@@ -548,10 +547,9 @@ static int ks_phy_read(struct mii_device *mdev, int addr, int reg)
return result;
}
-static int ks_phy_write(struct mii_device *mdev, int addr, int reg, int val)
+static int ks_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
{
- struct eth_device *edev = mdev->edev;
- struct ks_net *priv = (struct ks_net *)edev->priv;
+ struct ks_net *priv = (struct ks_net *)bus->priv;
int ksreg;
ksreg = ks_phy_reg(reg);
@@ -779,11 +777,14 @@ static int ks8851_eth_open(struct eth_device *edev)
{
struct ks_net *priv = (struct ks_net *)edev->priv;
struct device_d *dev = &edev->dev;
+ int ret;
ks_enable_qmu(priv);
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
+ ret = phy_device_connect(edev, &priv->miibus, 1, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
dev_dbg(dev, "eth_open\n");
@@ -792,9 +793,6 @@ static int ks8851_eth_open(struct eth_device *edev)
static int ks8851_init_dev(struct eth_device *edev)
{
- struct ks_net *priv = (struct ks_net *)edev->priv;
-
- miidev_restart_aneg(&priv->miidev);
return 0;
}
@@ -838,12 +836,10 @@ static int ks8851_probe(struct device_d *dev)
edev->parent = dev;
/* setup mii state */
- ks->miidev.read = ks_phy_read;
- ks->miidev.write = ks_phy_write;
- ks->miidev.address = 1;
- ks->miidev.flags = 0;
- ks->miidev.edev = edev;
- ks->miidev.parent = dev;
+ ks->miibus.read = ks_phy_read;
+ ks->miibus.write = ks_phy_write;
+ ks->miibus.priv = ks;
+ ks->miibus.parent = dev;
/* simple check for a valid chip being connected to the bus */
@@ -864,7 +860,7 @@ static int ks8851_probe(struct device_d *dev)
ks_soft_reset(ks, GRR_GSR);
ks_setup(ks);
- mii_register(&ks->miidev);
+ mdiobus_register(&ks->miibus);
eth_register(edev);
dev_dbg(dev, "%s MARL 0x%04x MARM 0x%04x MARH 0x%04x\n", __func__,
ks_rdreg16(ks, KS_MARL), ks_rdreg16(ks, KS_MARM),
diff --git a/drivers/net/ksz8864rmn.c b/drivers/net/ksz8864rmn.c
new file mode 100644
index 0000000000..5845960f6c
--- /dev/null
+++ b/drivers/net/ksz8864rmn.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2012 Jan Luebbe, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <spi/spi.h>
+#include <errno.h>
+
+#define REG_ID0 0x00
+#define REG_ID1 0x01
+
+#define REG_GC00 0x02
+#define REG_GC01 0x03
+#define REG_GC02 0x04
+#define REG_GC03 0x05
+#define REG_GC04 0x06
+#define REG_GC05 0x07
+#define REG_GC06 0x08
+#define REG_GC07 0x09
+#define REG_GC08 0x0a
+#define REG_GC09 0x0b
+#define REG_GC10 0x0c
+#define REG_GC11 0x0d
+
+#define REG_PSTAT1(p) (0x10 * p + 0xe)
+#define REG_PSTAT2(p) (0x10 * p + 0xf)
+
+#define CMD_WRITE 0x02
+#define CMD_READ 0x03
+
+struct micrel_switch_priv {
+ struct cdev cdev;
+ struct spi_device *spi;
+};
+
+static int micrel_switch_read_reg(struct spi_device *spi, uint8_t reg)
+{
+ uint8_t tx[2];
+ uint8_t rx[1];
+ int ret;
+
+ tx[0] = CMD_READ;
+ tx[1] = reg;
+
+ ret = spi_write_then_read(spi, tx, 2, rx, 1);
+ if (ret < 0)
+ return ret;
+
+ return rx[0];
+}
+
+static void micrel_switch_write_reg(struct spi_device *spi, uint8_t reg, uint8_t val)
+{
+ uint8_t tx[3];
+
+ tx[0] = CMD_WRITE;
+ tx[1] = reg;
+ tx[2] = val;
+
+ spi_write_then_read(spi, tx, 3, NULL, 0);
+}
+
+static int micrel_switch_enable_set(struct device_d *dev, struct param_d *param,
+ const char *val)
+{
+ struct spi_device *spi = (struct spi_device *)dev->type_data;
+ int enable;
+ char *new;
+
+ if (!val)
+ return dev_param_set_generic(dev, param, NULL);
+
+ enable = simple_strtoul(val, NULL, 0);
+
+ if (enable) {
+ micrel_switch_write_reg(spi, REG_ID1, 1);
+ new = "1";
+ } else {
+ micrel_switch_write_reg(spi, REG_ID1, 0);
+ new = "0";
+ }
+
+ dev_param_set_generic(dev, param, new);
+
+ return 0;
+}
+
+static ssize_t micel_switch_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ int i, ret;
+ uint8_t *buf = _buf;
+ struct micrel_switch_priv *priv = cdev->priv;
+
+ for (i = 0; i < count; i++) {
+ ret = micrel_switch_read_reg(priv->spi, offset);
+ if (ret < 0)
+ return ret;
+ *buf = ret;
+ buf++;
+ offset++;
+ }
+
+ return count;
+}
+
+static ssize_t micel_switch_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ int i;
+ const uint8_t *buf = _buf;
+ struct micrel_switch_priv *priv = cdev->priv;
+
+ for (i = 0; i < count; i++) {
+ micrel_switch_write_reg(priv->spi, offset, *buf);
+ buf++;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations micrel_switch_ops = {
+ .read = micel_switch_read,
+ .write = micel_switch_write,
+ .lseek = dev_lseek_default,
+};
+
+static int micrel_switch_probe(struct device_d *dev)
+{
+ struct micrel_switch_priv *priv;
+ int ret = 0;
+
+ priv = xzalloc(sizeof(*priv));
+
+ dev->priv = priv;
+
+ priv->spi = (struct spi_device *)dev->type_data;
+ priv->spi->mode = SPI_MODE_0;
+ priv->spi->bits_per_word = 8;
+
+ ret = micrel_switch_read_reg(priv->spi, REG_ID0);
+ if (ret < 0) {
+ dev_err(&priv->spi->dev, "failed to read device id\n");
+ return ret;
+ }
+ if (ret != 0x95) {
+ dev_err(&priv->spi->dev, "unknown device id: %02x\n", ret);
+ return -ENODEV;
+ }
+
+ priv->cdev.name = asprintf("switch%d", dev->id);
+ priv->cdev.size = 256;
+ priv->cdev.ops = &micrel_switch_ops;
+ priv->cdev.priv = priv;
+ priv->cdev.dev = dev;
+ devfs_create(&priv->cdev);
+
+ dev_add_param(dev, "enable", micrel_switch_enable_set, NULL, 0);
+ dev_set_param(dev, "enable", "1");
+
+ return 0;
+}
+
+static struct driver_d micrel_switch_driver = {
+ .name = "ksz8864rmn",
+ .probe = micrel_switch_probe,
+};
+
+static int micrel_switch_init(void)
+{
+ spi_register_driver(&micrel_switch_driver);
+ return 0;
+}
+device_initcall(micrel_switch_init);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 53a3ed2ceb..64970ba09f 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -41,13 +41,13 @@
#include <malloc.h>
#include <xfuncs.h>
#include <init.h>
-#include <miidev.h>
#include <errno.h>
#include <io.h>
#include <mach/board.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <asm/mmu.h>
+#include <linux/phy.h>
#include "macb.h"
@@ -94,12 +94,16 @@ struct macb_device {
struct macb_dma_desc *rx_ring;
struct macb_dma_desc *tx_ring;
+ int phy_addr;
+
const struct device *dev;
struct eth_device netdev;
- struct mii_device miidev;
+ phy_interface_t interface;
+
+ struct mii_bus miibus;
- unsigned int flags;
+ unsigned int phy_flags;
};
static int macb_send(struct eth_device *edev, void *packet,
@@ -211,26 +215,32 @@ static int macb_recv(struct eth_device *edev)
return 0;
}
-static int macb_open(struct eth_device *edev)
+static void macb_adjust_link(struct eth_device *edev)
{
struct macb_device *macb = edev->priv;
- int duplex = 1, speed = 1;
- u32 ncfgr;
+ u32 reg;
- debug("%s\n", __func__);
+ reg = readl(macb->regs + MACB_NCFGR);
+ reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
- miidev_wait_aneg(&macb->miidev);
- miidev_print_status(&macb->miidev);
+ if (edev->phydev->duplex)
+ reg |= MACB_BIT(FD);
+ if (edev->phydev->speed == SPEED_100)
+ reg |= MACB_BIT(SPD);
- ncfgr = readl(macb->regs + MACB_NCFGR);
- ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
- if (speed)
- ncfgr |= MACB_BIT(SPD);
- if (duplex)
- ncfgr |= MACB_BIT(FD);
- writel(ncfgr, macb->regs + MACB_NCFGR);
+ writel(reg, macb->regs + MACB_NCFGR);
+}
- return 0;
+static int macb_open(struct eth_device *edev)
+{
+ struct macb_device *macb = edev->priv;
+
+ debug("%s\n", __func__);
+
+ /* Obtain the PHY's address/id */
+ return phy_device_connect(edev, &macb->miibus, macb->phy_addr,
+ macb_adjust_link, macb->phy_flags,
+ macb->interface);
}
static int macb_init(struct eth_device *edev)
@@ -264,7 +274,7 @@ static int macb_init(struct eth_device *edev)
writel((ulong)macb->rx_ring, macb->regs + MACB_RBQP);
writel((ulong)macb->tx_ring, macb->regs + MACB_TBQP);
- if (macb->flags & AT91SAM_ETHER_RMII)
+ if (macb->interface == PHY_INTERFACE_MODE_RMII)
val |= MACB_BIT(RMII);
else
val &= ~MACB_BIT(RMII);
@@ -298,10 +308,9 @@ static void macb_halt(struct eth_device *edev)
writel(MACB_BIT(CLRSTAT), macb->regs + MACB_NCR);
}
-static int macb_phy_read(struct mii_device *mdev, int addr, int reg)
+static int macb_phy_read(struct mii_bus *bus, int addr, int reg)
{
- struct eth_device *edev = mdev->edev;
- struct macb_device *macb = edev->priv;
+ struct macb_device *macb = bus->priv;
unsigned long netctl;
unsigned long netstat;
@@ -341,10 +350,9 @@ static int macb_phy_read(struct mii_device *mdev, int addr, int reg)
return value;
}
-static int macb_phy_write(struct mii_device *mdev, int addr, int reg, int value)
+static int macb_phy_write(struct mii_bus *bus, int addr, int reg, u16 value)
{
- struct eth_device *edev = mdev->edev;
- struct macb_device *macb = edev->priv;
+ struct macb_device *macb = bus->priv;
unsigned long netctl;
unsigned long netstat;
unsigned long frame;
@@ -425,14 +433,19 @@ static int macb_probe(struct device_d *dev)
edev->set_ethaddr = macb_set_ethaddr;
edev->parent = dev;
- macb->miidev.read = macb_phy_read;
- macb->miidev.write = macb_phy_write;
- macb->miidev.address = pdata->phy_addr;
- macb->miidev.flags = pdata->flags & AT91SAM_ETHER_FORCE_LINK ?
- MIIDEV_FORCE_LINK : 0;
- macb->miidev.edev = edev;
- macb->miidev.parent = dev;
- macb->flags = pdata->flags;
+ macb->miibus.read = macb_phy_read;
+ macb->miibus.write = macb_phy_write;
+ macb->phy_addr = pdata->phy_addr;
+ macb->miibus.priv = macb;
+ macb->miibus.parent = dev;
+
+ if (pdata->flags & AT91SAM_ETHER_RMII)
+ macb->interface = PHY_INTERFACE_MODE_RMII;
+ else
+ macb->interface = PHY_INTERFACE_MODE_MII;
+
+ macb->phy_flags = pdata->flags & AT91SAM_ETHER_FORCE_LINK ?
+ PHYLIB_FORCE_LINK : 0;
macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE);
macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE * sizeof(struct macb_dma_desc));
@@ -467,7 +480,7 @@ static int macb_probe(struct device_d *dev)
writel(ncfgr, macb->regs + MACB_NCFGR);
- mii_register(&macb->miidev);
+ mdiobus_register(&macb->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
deleted file mode 100644
index 5d73ff5597..0000000000
--- a/drivers/net/miidev.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * miidev.c - generic phy abstraction
- *
- * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <common.h>
-#include <driver.h>
-#include <init.h>
-#include <miidev.h>
-#include <clock.h>
-#include <net.h>
-#include <malloc.h>
-
-static LIST_HEAD(miidev_list);
-
-int miidev_restart_aneg(struct mii_device *mdev)
-{
- int status, timeout;
- uint64_t start;
-
- status = mii_write(mdev, mdev->address, MII_BMCR, BMCR_RESET);
- if (status)
- return status;
-
- start = get_time_ns();
- do {
- status = mii_read(mdev, mdev->address, MII_BMCR);
- if (status < 0)
- return status;
-
- if (is_timeout(start, SECOND))
- return -ETIMEDOUT;
-
- } while (status & BMCR_RESET);
-
- if (mdev->flags & MIIDEV_FORCE_LINK)
- return 0;
-
- if (mdev->flags & MIIDEV_FORCE_10) {
- printf("Forcing 10 Mbps ethernet link... ");
-
- status = mii_read(mdev, mdev->address, MII_BMSR);
- if (status < 0)
- return status;
-
- status = mii_write(mdev, mdev->address, MII_BMCR, BMCR_FULLDPLX | BMCR_CTST);
- if (status)
- return status;
-
- timeout = 20;
- do { /* wait for link status to go down */
- udelay(10000);
- if ((timeout--) == 0) {
- debug("hmmm, should not have waited...");
- break;
- }
- status = mii_read(mdev, mdev->address, MII_BMSR);
- if (status < 0)
- return status;
- } while (status & BMSR_LSTATUS);
-
- } else { /* MII100 */
- /*
- * Set the auto-negotiation advertisement register bits
- */
- status = mii_read(mdev, mdev->address, MII_ADVERTISE);
- if (status < 0)
- return status;
-
- status |= ADVERTISE_ALL;
-
- status = mii_write(mdev, mdev->address, MII_ADVERTISE, status);
- if (status)
- return status;
-
- status = mii_write(mdev, mdev->address, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
- if (status)
- return status;
- }
-
- return 0;
-}
-
-int miidev_wait_aneg(struct mii_device *mdev)
-{
- int status;
- uint64_t start = get_time_ns();
-
- if (mdev->flags & MIIDEV_FORCE_LINK)
- return 0;
-
- do {
- status = mii_read(mdev, mdev->address, MII_BMSR);
- if (status < 0)
- return status;
-
- if (is_timeout(start, 5 * SECOND)) {
- printf("%s: Autonegotiation timeout\n", mdev->cdev.name);
- return -ETIMEDOUT;
- }
-
- } while (!(status & BMSR_ANEGCOMPLETE));
-
- return 0;
-}
-
-int miidev_get_status(struct mii_device *mdev)
-{
- int ret, status, adv, lpa;
-
- ret = mii_read(mdev, mdev->address, MII_BMSR);
- if (ret < 0)
- goto err_out;
-
- status = ret & BMSR_LSTATUS ? MIIDEV_STATUS_IS_UP : 0;
-
- if (ret & BMSR_ESTATEN) {
- ret = mii_read(mdev, mdev->address, MII_ESTATUS);
- if (ret < 0)
- goto err_out;
- if (ret & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
- mdev->capabilities = MIIDEV_CAPABLE_1000M;
- }
-
- ret = mii_read(mdev, mdev->address, MII_BMCR);
- if (ret < 0)
- goto err_out;
-
- if (ret & BMCR_ANENABLE) {
- if (mdev->capabilities & MIIDEV_CAPABLE_1000M) {
- lpa = mii_read(mdev, mdev->address, MII_STAT1000);
- if (lpa < 0)
- goto err_out;
- adv = mii_read(mdev, mdev->address, MII_CTRL1000);
- if (adv < 0)
- goto err_out;
- lpa &= adv << 2;
- if (lpa & (LPA_1000FULL | LPA_1000HALF)) {
- if (lpa & LPA_1000FULL)
- status |= MIIDEV_STATUS_IS_FULL_DUPLEX;
- status |= MIIDEV_STATUS_IS_1000MBIT;
- return status;
- }
- }
- lpa = mii_read(mdev, mdev->address, MII_LPA);
- if (lpa < 0)
- goto err_out;
- adv = mii_read(mdev, mdev->address, MII_ADVERTISE);
- if (adv < 0)
- goto err_out;
- lpa &= adv;
- status |= lpa & LPA_DUPLEX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0;
- status |= lpa & LPA_100 ? MIIDEV_STATUS_IS_100MBIT :
- MIIDEV_STATUS_IS_10MBIT;
- } else {
- status |= ret & BMCR_FULLDPLX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0;
- status |= ret & BMCR_SPEED100 ? MIIDEV_STATUS_IS_100MBIT :
- MIIDEV_STATUS_IS_10MBIT;
- }
-
- return status;
-err_out:
- printf("%s: failed to read (%d)\n", mdev->cdev.name, ret);
- return ret;
-}
-
-int miidev_print_status(struct mii_device *mdev)
-{
- char *duplex;
- int speed, status;
-
- if (mdev->flags & MIIDEV_FORCE_LINK) {
- printf("Forcing link present...\n");
- return 0;
- }
-
- status = miidev_get_status(mdev);
- if (status < 0)
- return status;
-
- duplex = status & MIIDEV_STATUS_IS_FULL_DUPLEX ? "Full" : "Half";
- speed = status & MIIDEV_STATUS_IS_1000MBIT ? 1000 :
- (status & MIIDEV_STATUS_IS_100MBIT ? 100 : 10);
-
- printf("%s: Link is %s", mdev->cdev.name,
- status & MIIDEV_STATUS_IS_UP ? "up" : "down");
- printf(" - %d/%s\n", speed, duplex);
-
- return 0;
-}
-
-static ssize_t miidev_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
-{
- int i = count;
- uint16_t *buf = _buf;
- struct mii_device *mdev = cdev->priv;
-
- while (i > 0) {
- *buf = mii_read(mdev, mdev->address, offset / 2);
- buf++;
- i -= 2;
- offset += 2;
- }
-
- return count;
-}
-
-static ssize_t miidev_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
-{
- int i = count;
- const uint16_t *buf = _buf;
- struct mii_device *mdev = cdev->priv;
-
- while (i > 0) {
- mii_write(mdev, mdev->address, offset / 2, *buf);
- buf++;
- i -= 2;
- offset += 2;
- }
-
- return count;
-}
-
-static struct file_operations miidev_ops = {
- .read = miidev_read,
- .write = miidev_write,
- .lseek = dev_lseek_default,
-};
-
-static int miidev_probe(struct device_d *dev)
-{
- struct mii_device *mdev = dev->priv;
-
- mdev->capabilities = 0;
- mdev->cdev.name = asprintf("phy%d", dev->id);
- mdev->cdev.size = 64;
- mdev->cdev.ops = &miidev_ops;
- mdev->cdev.priv = mdev;
- mdev->cdev.dev = dev;
- devfs_create(&mdev->cdev);
- list_add_tail(&mdev->list, &miidev_list);
- return 0;
-}
-
-static void miidev_remove(struct device_d *dev)
-{
- struct mii_device *mdev = dev->priv;
-
- list_del(&mdev->list);
-
- free(mdev->cdev.name);
- devfs_remove(&mdev->cdev);
-}
-
-struct mii_device *mii_open(const char *name)
-{
- struct mii_device *mdev;
-
- list_for_each_entry(mdev, &miidev_list, list) {
- if (!strcmp(name, mdev->cdev.name))
- return mdev;
- }
- return NULL;
-}
-
-void mii_close(struct mii_device *mdev)
-{
-}
-
-static struct driver_d miidev_drv = {
- .name = "miidev",
- .probe = miidev_probe,
- .remove = miidev_remove,
-};
-
-int mii_register(struct mii_device *mdev)
-{
- mdev->dev.priv = mdev;
- mdev->dev.id = DEVICE_ID_DYNAMIC;
- strcpy(mdev->dev.name, "miidev");
- if (mdev->parent)
- dev_add_child(mdev->parent, &mdev->dev);
-
- return register_device(&mdev->dev);
-}
-
-void mii_unregister(struct mii_device *mdev)
-{
- unregister_device(&mdev->dev);
-}
-
-static int miidev_init(void)
-{
- register_driver(&miidev_drv);
- return 0;
-}
-
-device_initcall(miidev_init);
-
diff --git a/drivers/net/netx_eth.c b/drivers/net/netx_eth.c
index 2d92a2e4dc..a4764258c1 100644
--- a/drivers/net/netx_eth.c
+++ b/drivers/net/netx_eth.c
@@ -2,13 +2,13 @@
#include <command.h>
#include <net.h>
#include <io.h>
-#include <miidev.h>
#include <mach/netx-xc.h>
#include <mach/netx-eth.h>
#include <mach/netx-regs.h>
#include <xfuncs.h>
#include <init.h>
#include <driver.h>
+#include <linux/phy.h>
#define ETH_MAC_LOCAL_CONFIG 0x1560
#define ETH_MAC_4321 0x1564
@@ -47,7 +47,7 @@
#define CON_FIFO_PORT_LO(xcno) (6 + ((xcno) << 3)) /* Index of the FIFO where sent Data packages are confirmed */
struct netx_eth_priv {
- struct mii_device miidev;
+ struct mii_bus miibus;
int xcno;
};
@@ -118,7 +118,7 @@ static int netx_eth_rx (struct eth_device *edev)
return 0;
}
-static int netx_miidev_read(struct mii_device *mdev, int phy_addr, int reg)
+static int netx_miibus_read(struct mii_bus *bus, int phy_addr, int reg)
{
int value;
@@ -135,8 +135,8 @@ static int netx_miidev_read(struct mii_device *mdev, int phy_addr, int reg)
return value;
}
-static int netx_miidev_write(struct mii_device *mdev, int phy_addr,
- int reg, int val)
+static int netx_miibus_write(struct mii_bus *bus, int phy_addr,
+ int reg, u16 val)
{
debug("%s: addr: 0x%02x reg: 0x%02x val: 0x%04x\n",__func__,
phy_addr, reg, val);
@@ -189,13 +189,15 @@ static int netx_eth_init_dev(struct eth_device *edev)
for (i = 2; i <= 18; i++)
PFIFO_REG( PFIFO_BASE(EMPTY_PTR_FIFO(xcno)) ) = FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(xcno);
- miidev_restart_aneg(&priv->miidev);
return 0;
}
static int netx_eth_open(struct eth_device *edev)
{
- return 0;
+ struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
+
+ return phy_device_connect(edev, &priv->miibus, 0, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
}
static void netx_eth_halt (struct eth_device *edev)
@@ -259,14 +261,12 @@ static int netx_eth_probe(struct device_d *dev)
edev->set_ethaddr = netx_eth_set_ethaddr;
edev->parent = dev;
- priv->miidev.read = netx_miidev_read;
- priv->miidev.write = netx_miidev_write;
- priv->miidev.address = 0;
- priv->miidev.flags = 0;
- priv->miidev.parent = dev;
+ priv->miibus.read = netx_miibus_read;
+ priv->miibus.write = netx_miibus_write;
+ priv->miibus.parent = dev;
netx_eth_init_phy();
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
new file mode 100644
index 0000000000..b66261ae99
--- /dev/null
+++ b/drivers/net/phy/Kconfig
@@ -0,0 +1,17 @@
+#
+# PHY Layer Configuration
+#
+
+menu "phylib "
+
+if PHYLIB
+
+comment "MII PHY device drivers"
+
+config GENERIC_PHY
+ bool "Drivers for the Generic PHYs"
+ default y
+
+endif
+
+endmenu
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
new file mode 100644
index 0000000000..82e90d426a
--- /dev/null
+++ b/drivers/net/phy/Makefile
@@ -0,0 +1,2 @@
+obj-y += phy.o mdio_bus.o
+obj-$(CONFIG_GENERIC_PHY) += generic.o
diff --git a/drivers/net/phy/generic.c b/drivers/net/phy/generic.c
new file mode 100644
index 0000000000..3f5f127065
--- /dev/null
+++ b/drivers/net/phy/generic.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <linux/phy.h>
+#include <init.h>
+
+static struct phy_driver generic_phy = {
+ .drv.name = "Generic PHY",
+ .phy_id = PHY_ANY_UID,
+ .phy_id_mask = PHY_ANY_UID,
+ .features = 0,
+};
+
+static int generic_phy_register(void)
+{
+ return phy_driver_register(&generic_phy);
+}
+device_initcall(generic_phy_register);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
new file mode 100644
index 0000000000..93d6fe15e1
--- /dev/null
+++ b/drivers/net/phy/mdio_bus.c
@@ -0,0 +1,250 @@
+/*
+ * drivers/net/phy/mdio_bus.c
+ *
+ * MDIO Bus interface
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <clock.h>
+#include <net.h>
+#include <errno.h>
+#include <linux/phy.h>
+#include <linux/err.h>
+
+/**
+ * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+ * @bus: target mii_bus
+ *
+ * Description: Called by a bus driver to bring up all the PHYs
+ * on a given bus, and attach them to the bus.
+ *
+ * Returns 0 on success or < 0 on error.
+ */
+int mdiobus_register(struct mii_bus *bus)
+{
+ int i, err;
+
+ if (NULL == bus ||
+ NULL == bus->read ||
+ NULL == bus->write)
+ return -EINVAL;
+
+ bus->dev.priv = bus;
+ bus->dev.id = DEVICE_ID_DYNAMIC;
+ strcpy(bus->dev.name, "miibus");
+ bus->dev.parent = bus->parent;
+ if (bus->parent)
+ dev_add_child(bus->parent, &bus->dev);
+
+ err = register_device(&bus->dev);
+ if (err) {
+ pr_err("mii_bus %s failed to register\n", bus->dev.name);
+ return -EINVAL;
+ }
+
+ if (bus->reset)
+ bus->reset(bus);
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ if ((bus->phy_mask & (1 << i)) == 0) {
+ struct phy_device *phydev;
+
+ phydev = mdiobus_scan(bus, i);
+ if (IS_ERR(phydev)) {
+ err = PTR_ERR(phydev);
+ goto error;
+ }
+ }
+ }
+
+ pr_info("%s: probed\n", dev_name(&bus->dev));
+ return 0;
+
+error:
+ while (--i >= 0) {
+ if (bus->phy_map[i]) {
+ kfree(bus->phy_map[i]);
+ bus->phy_map[i] = NULL;
+ }
+ }
+ return err;
+}
+EXPORT_SYMBOL(mdiobus_register);
+
+void mdiobus_unregister(struct mii_bus *bus)
+{
+ int i;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ if (bus->phy_map[i])
+ unregister_device(&bus->phy_map[i]->dev);
+ bus->phy_map[i] = NULL;
+ }
+}
+EXPORT_SYMBOL(mdiobus_unregister);
+
+struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
+{
+ struct phy_device *phydev;
+
+ phydev = get_phy_device(bus, addr);
+ if (IS_ERR(phydev) || phydev == NULL)
+ return phydev;
+
+ bus->phy_map[addr] = phydev;
+
+ return phydev;
+}
+EXPORT_SYMBOL(mdiobus_scan);
+
+/**
+ * mdio_bus_match - determine if given PHY driver supports the given PHY device
+ * @dev: target PHY device
+ * @drv: given PHY driver
+ *
+ * Description: Given a PHY device, and a PHY driver, return 1 if
+ * the driver supports the device. Otherwise, return 0.
+ */
+static int mdio_bus_match(struct device_d *dev, struct driver_d *drv)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ struct phy_driver *phydrv = to_phy_driver(drv);
+
+ return ((phydrv->phy_id & phydrv->phy_id_mask) ==
+ (phydev->phy_id & phydrv->phy_id_mask));
+}
+
+static ssize_t phydev_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ int i = count;
+ uint16_t *buf = _buf;
+ struct phy_device *phydev = cdev->priv;
+
+ while (i > 0) {
+ *buf = phy_read(phydev, offset / 2);
+ buf++;
+ i -= 2;
+ offset += 2;
+ }
+
+ return count;
+}
+
+static ssize_t phydev_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ int i = count;
+ const uint16_t *buf = _buf;
+ struct phy_device *phydev = cdev->priv;
+
+ while (i > 0) {
+ phy_write(phydev, offset / 2, *buf);
+ buf++;
+ i -= 2;
+ offset += 2;
+ }
+
+ return count;
+}
+
+static struct file_operations phydev_ops = {
+ .read = phydev_read,
+ .write = phydev_write,
+ .lseek = dev_lseek_default,
+};
+
+static int mdio_bus_probe(struct device_d *_dev)
+{
+ struct phy_device *dev = to_phy_device(_dev);
+ struct phy_driver *drv = to_phy_driver(_dev->driver);
+
+ char str[16];
+
+ dev->attached_dev->phydev = dev;
+ dev->dev.parent = &dev->attached_dev->dev;
+ dev_add_child(dev->dev.parent, _dev);
+
+ if (drv->probe) {
+ int ret;
+
+ ret = drv->probe(dev);
+ if (ret) {
+ dev->attached_dev->phydev = NULL;
+ dev->attached_dev = NULL;
+ return ret;
+ }
+ }
+
+ if (dev->dev_flags) {
+ if (dev->dev_flags & PHYLIB_FORCE_10) {
+ dev->speed = SPEED_10;
+ dev->duplex = DUPLEX_FULL;
+ dev->autoneg = !AUTONEG_ENABLE;
+ }
+ }
+
+ /* Start out supporting everything. Eventually,
+ * a controller will attach, and may modify one
+ * or both of these values */
+ dev->supported = drv->features;
+ dev->advertising = drv->features;
+
+ drv->config_init(dev);
+
+ /* Sanitize settings based on PHY capabilities */
+ if ((dev->supported & SUPPORTED_Autoneg) == 0)
+ dev->autoneg = AUTONEG_DISABLE;
+
+ sprintf(str, "%d", dev->addr);
+ dev_add_param_fixed(&dev->dev, "phy_addr", str);
+
+ dev->cdev.name = asprintf("phy%d", _dev->id);
+ dev->cdev.size = 64;
+ dev->cdev.ops = &phydev_ops;
+ dev->cdev.priv = dev;
+ dev->cdev.dev = _dev;
+ devfs_create(&dev->cdev);
+
+ return 0;
+}
+
+static void mdio_bus_remove(struct device_d *_dev)
+{
+ struct phy_device *dev = to_phy_device(_dev);
+ struct phy_driver *drv = to_phy_driver(_dev->driver);
+
+ if (drv->remove)
+ drv->remove(dev);
+
+ free(dev->cdev.name);
+ devfs_remove(&dev->cdev);
+}
+
+struct bus_type mdio_bus_type = {
+ .name = "mdio_bus",
+ .match = mdio_bus_match,
+ .probe = mdio_bus_probe,
+ .remove = mdio_bus_remove,
+};
+EXPORT_SYMBOL(mdio_bus_type);
+
+#if 0
+static int mdio_bus_init(void)
+{
+ return bus_register(&mdio_bus_type);
+}
+pure_initcall(mdio_bus_init);
+#endif
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
new file mode 100644
index 0000000000..88c3ff7723
--- /dev/null
+++ b/drivers/net/phy/phy.c
@@ -0,0 +1,583 @@
+/*
+ * drivers/net/phy/phy.c
+ *
+ * Framework for finding and configuring PHYs.
+ * Also contains generic PHY driver
+ *
+ * Copyright (c) 2009-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <net.h>
+#include <malloc.h>
+#include <linux/phy.h>
+#include <linux/phy.h>
+#include <linux/err.h>
+
+#define PHY_AN_TIMEOUT 10
+
+static int genphy_config_init(struct phy_device *phydev);
+
+int phy_update_status(struct phy_device *dev)
+{
+ struct phy_driver *drv = to_phy_driver(dev->dev.driver);
+ struct eth_device *edev = dev->attached_dev;
+ int ret;
+ int oldspeed = dev->speed, oldduplex = dev->duplex;
+
+ ret = drv->read_status(dev);
+ if (ret)
+ return ret;
+
+ if (dev->speed == oldspeed && dev->duplex == oldduplex)
+ return 0;
+
+ if (dev->adjust_link)
+ dev->adjust_link(edev);
+
+ if (dev->link)
+ printf("%dMbps %s duplex link detected\n", dev->speed,
+ dev->duplex ? "full" : "half");
+
+ return 0;
+}
+
+struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id)
+{
+ struct phy_device *dev;
+
+ /* We allocate the device, and initialize the
+ * default values */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+ if (NULL == dev)
+ return (struct phy_device*) PTR_ERR((void*)-ENOMEM);
+
+ dev->speed = 0;
+ dev->duplex = -1;
+ dev->pause = dev->asym_pause = 0;
+ dev->link = 1;
+ dev->autoneg = AUTONEG_ENABLE;
+
+ dev->addr = addr;
+ dev->phy_id = phy_id;
+
+ dev->bus = bus;
+ dev->dev.parent = bus->parent;
+ dev->dev.bus = &mdio_bus_type;
+
+ strcpy(dev->dev.name, "phy");
+ dev->dev.id = DEVICE_ID_DYNAMIC;
+
+ return dev;
+}
+/**
+ * get_phy_id - reads the specified addr for its ID.
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ * @phy_id: where to store the ID retrieved.
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, stores it in @phy_id and returns zero on success.
+ */
+int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
+{
+ int phy_reg;
+
+ /* Grab the bits from PHYIR1, and put them
+ * in the upper half */
+ phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id = (phy_reg & 0xffff) << 16;
+
+ /* Grab the bits from PHYIR2, and put them in the lower half */
+ phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id |= (phy_reg & 0xffff);
+
+ return 0;
+}
+
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, then allocates and returns the phy_device to represent it.
+ */
+struct phy_device *get_phy_device(struct mii_bus *bus, int addr)
+{
+ struct phy_device *dev = NULL;
+ u32 phy_id = 0;
+ int r;
+
+ r = get_phy_id(bus, addr, &phy_id);
+ if (r)
+ return ERR_PTR(r);
+
+ /* If the phy_id is mostly Fs, there is no device there */
+ if ((phy_id & 0x1fffffff) == 0x1fffffff)
+ return NULL;
+
+ dev = phy_device_create(bus, addr, phy_id);
+
+ return dev;
+}
+
+/* Automatically gets and returns the PHY device */
+int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
+ void (*adjust_link) (struct eth_device *edev),
+ u32 flags, phy_interface_t interface)
+{
+ struct phy_driver* drv;
+ struct phy_device* dev = NULL;
+ unsigned int i;
+ int ret = -EINVAL;
+
+ if (!edev->phydev) {
+ if (addr >= 0) {
+ dev = bus->phy_map[addr];
+ if (!dev) {
+ ret = -EIO;
+ goto fail;
+ }
+
+ dev->attached_dev = edev;
+ dev->interface = interface;
+ dev->dev_flags = flags;
+
+ ret = register_device(&dev->dev);
+ if (ret)
+ goto fail;
+ } else {
+ for (i = 0; i < PHY_MAX_ADDR && !edev->phydev; i++) {
+ dev = bus->phy_map[i];
+ if (!dev || dev->attached_dev)
+ continue;
+
+ dev->attached_dev = edev;
+ dev->interface = interface;
+ dev->dev_flags = flags;
+
+ ret = register_device(&dev->dev);
+ if (ret)
+ goto fail;
+
+ break;
+ }
+ }
+
+ if (!edev->phydev) {
+ ret = -EIO;
+ goto fail;
+ }
+ }
+
+ dev = edev->phydev;
+ drv = to_phy_driver(dev->dev.driver);
+
+ drv->config_aneg(dev);
+
+ dev->adjust_link = adjust_link;
+
+ return 0;
+
+fail:
+ if (dev)
+ dev->attached_dev = NULL;
+ puts("Unable to find a PHY (unknown ID?)\n");
+ return ret;
+}
+
+/* Generic PHY support and helper functions */
+
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotiation parameters
+ * @phydev: target phy_device struct
+ *
+ * Description: Writes MII_ADVERTISE with the appropriate values,
+ * after sanitizing the values to make sure we only advertise
+ * what is supported. Returns < 0 on error, 0 if the PHY's advertisement
+ * hasn't changed, and > 0 if it has changed.
+ */
+int genphy_config_advert(struct phy_device *phydev)
+{
+ u32 advertise;
+ int oldadv, adv;
+ int err, changed = 0;
+
+ /* Only allow advertising what
+ * this PHY supports */
+ phydev->advertising &= phydev->supported;
+ advertise = phydev->advertising;
+
+ /* Setup standard advertisement */
+ oldadv = adv = phy_read(phydev, MII_ADVERTISE);
+
+ if (adv < 0)
+ return adv;
+
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+ adv |= ethtool_adv_to_mii_adv_t(advertise);
+
+ if (adv != oldadv) {
+ err = phy_write(phydev, MII_ADVERTISE, adv);
+
+ if (err < 0)
+ return err;
+ changed = 1;
+ }
+
+ /* Configure gigabit if it's supported */
+ if (phydev->supported & (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full)) {
+ oldadv = adv = phy_read(phydev, MII_CTRL1000);
+
+ if (adv < 0)
+ return adv;
+
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ adv |= ethtool_adv_to_mii_ctrl1000_t(advertise);
+
+ if (adv != oldadv) {
+ err = phy_write(phydev, MII_CTRL1000, adv);
+
+ if (err < 0)
+ return err;
+ changed = 1;
+ }
+ }
+
+ return changed;
+}
+
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Configures MII_BMCR to force speed/duplex
+ * to the values in phydev. Assumes that the values are valid.
+ * Please see phy_sanitize_settings().
+ */
+int genphy_setup_forced(struct phy_device *phydev)
+{
+ int err;
+ int ctl = 0;
+
+ phydev->pause = phydev->asym_pause = 0;
+
+ if (SPEED_1000 == phydev->speed)
+ ctl |= BMCR_SPEED1000;
+ else if (SPEED_100 == phydev->speed)
+ ctl |= BMCR_SPEED100;
+
+ if (DUPLEX_FULL == phydev->duplex)
+ ctl |= BMCR_FULLDPLX;
+
+ err = phy_write(phydev, MII_BMCR, ctl);
+
+ return err;
+}
+
+static int phy_aneg_done(struct phy_device *phydev)
+{
+ uint64_t start = get_time_ns();
+ int ctl;
+
+ while (!is_timeout(start, PHY_AN_TIMEOUT * SECOND)) {
+ ctl = phy_read(phydev, MII_BMSR);
+ if (ctl & BMSR_ANEGCOMPLETE) {
+ phydev->link = 1;
+ return 0;
+ }
+
+ /* Restart auto-negotiation if remote fault */
+ if (ctl & BMSR_RFAULT) {
+ puts("PHY remote fault detected\n"
+ "PHY restarting auto-negotiation\n");
+ phy_write(phydev, MII_BMCR,
+ BMCR_ANENABLE | BMCR_ANRESTART);
+ }
+ }
+
+ phydev->link = 0;
+ return -ETIMEDOUT;
+}
+
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
+int genphy_restart_aneg(struct phy_device *phydev)
+{
+ int ctl;
+
+ ctl = phy_read(phydev, MII_BMCR);
+
+ if (ctl < 0)
+ return ctl;
+
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+ /* Don't isolate the PHY if we're negotiating */
+ ctl &= ~(BMCR_ISOLATE);
+
+ ctl = phy_write(phydev, MII_BMCR, ctl);
+
+ if (ctl < 0)
+ return ctl;
+
+ return phy_aneg_done(phydev);
+}
+
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
+ *
+ * Description: If auto-negotiation is enabled, we configure the
+ * advertising, and then restart auto-negotiation. If it is not
+ * enabled, then we write the BMCR.
+ */
+int genphy_config_aneg(struct phy_device *phydev)
+{
+ int result;
+
+ if (AUTONEG_ENABLE != phydev->autoneg)
+ return genphy_setup_forced(phydev);
+
+ result = genphy_config_advert(phydev);
+
+ if (result < 0) /* error */
+ return result;
+
+ if (result == 0) {
+ /* Advertisement hasn't changed, but maybe aneg was never on to
+ * begin with? Or maybe phy was isolated? */
+ int ctl = phy_read(phydev, MII_BMCR);
+
+ if (ctl < 0)
+ return ctl;
+
+ if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
+ result = 1; /* do restart aneg */
+ }
+
+ /* Only restart aneg if we are advertising something different
+ * than we were before. */
+ if (result > 0)
+ result = genphy_restart_aneg(phydev);
+
+ return result;
+}
+
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Update the value in phydev->link to reflect the
+ * current link value. In order to do this, we need to read
+ * the status register twice, keeping the second value.
+ */
+int genphy_update_link(struct phy_device *phydev)
+{
+ int status;
+
+ /* Do a fake read */
+ status = phy_read(phydev, MII_BMSR);
+
+ if (status < 0)
+ return status;
+
+ /* wait phy status update in the phy */
+ udelay(1000);
+
+ /* Read link and autonegotiation status */
+ status = phy_read(phydev, MII_BMSR);
+
+ if (status < 0)
+ return status;
+
+ if ((status & BMSR_LSTATUS) == 0)
+ phydev->link = 0;
+ else
+ phydev->link = 1;
+
+ return 0;
+}
+
+/**
+ * genphy_read_status - check the link status and update current link state
+ * @phydev: target phy_device struct
+ *
+ * Description: Check the link, then figure out the current state
+ * by comparing what we advertise with what the link partner
+ * advertises. Start by checking the gigabit possibilities,
+ * then move on to 10/100.
+ */
+int genphy_read_status(struct phy_device *phydev)
+{
+ int adv;
+ int err;
+ int lpa;
+ int lpagb = 0;
+
+ /* Update the link, but return if there
+ * was an error */
+ err = genphy_update_link(phydev);
+ if (err)
+ return err;
+
+ if (AUTONEG_ENABLE == phydev->autoneg) {
+ if (phydev->supported & (SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full)) {
+ lpagb = phy_read(phydev, MII_STAT1000);
+
+ if (lpagb < 0)
+ return lpagb;
+
+ adv = phy_read(phydev, MII_CTRL1000);
+
+ if (adv < 0)
+ return adv;
+
+ lpagb &= adv << 2;
+ }
+
+ lpa = phy_read(phydev, MII_LPA);
+
+ if (lpa < 0)
+ return lpa;
+
+ adv = phy_read(phydev, MII_ADVERTISE);
+
+ if (adv < 0)
+ return adv;
+
+ lpa &= adv;
+
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+ phydev->pause = phydev->asym_pause = 0;
+
+ if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+ phydev->speed = SPEED_1000;
+
+ if (lpagb & LPA_1000FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ phydev->speed = SPEED_100;
+
+ if (lpa & LPA_100FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else
+ if (lpa & LPA_10FULL)
+ phydev->duplex = DUPLEX_FULL;
+
+ if (phydev->duplex == DUPLEX_FULL) {
+ phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+ phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+ }
+ } else {
+ int bmcr = phy_read(phydev, MII_BMCR);
+ if (bmcr < 0)
+ return bmcr;
+
+ if (bmcr & BMCR_FULLDPLX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ if (bmcr & BMCR_SPEED1000)
+ phydev->speed = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ phydev->speed = SPEED_100;
+ else
+ phydev->speed = SPEED_10;
+
+ phydev->pause = phydev->asym_pause = 0;
+ }
+
+ return 0;
+}
+
+static int genphy_config_init(struct phy_device *phydev)
+{
+ int val;
+ u32 features;
+
+ /* For now, I'll claim that the generic driver supports
+ * all possible port types */
+ features = (SUPPORTED_TP | SUPPORTED_MII
+ | SUPPORTED_AUI | SUPPORTED_FIBRE |
+ SUPPORTED_BNC);
+
+ /* Do we support autonegotiation? */
+ val = phy_read(phydev, MII_BMSR);
+
+ if (val < 0)
+ return val;
+
+ if (val & BMSR_ANEGCAPABLE)
+ features |= SUPPORTED_Autoneg;
+
+ if (val & BMSR_100FULL)
+ features |= SUPPORTED_100baseT_Full;
+ if (val & BMSR_100HALF)
+ features |= SUPPORTED_100baseT_Half;
+ if (val & BMSR_10FULL)
+ features |= SUPPORTED_10baseT_Full;
+ if (val & BMSR_10HALF)
+ features |= SUPPORTED_10baseT_Half;
+
+ if (val & BMSR_ESTATEN) {
+ val = phy_read(phydev, MII_ESTATUS);
+
+ if (val < 0)
+ return val;
+
+ if (val & ESTATUS_1000_TFULL)
+ features |= SUPPORTED_1000baseT_Full;
+ if (val & ESTATUS_1000_THALF)
+ features |= SUPPORTED_1000baseT_Half;
+ }
+
+ phydev->supported = features;
+ phydev->advertising = features;
+
+ return 0;
+}
+
+int phy_driver_register(struct phy_driver *phydrv)
+{
+ phydrv->drv.bus = &mdio_bus_type;
+
+ if (!phydrv->config_init)
+ phydrv->config_init = genphy_config_init;
+
+ if (!phydrv->config_aneg)
+ phydrv->config_aneg = genphy_config_aneg;
+
+ if (!phydrv->read_status)
+ phydrv->read_status = genphy_read_status;
+
+ return register_driver(&phydrv->drv);
+}
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c
index 66ca9bca19..1f5a43191a 100644
--- a/drivers/net/smc91111.c
+++ b/drivers/net/smc91111.c
@@ -63,13 +63,13 @@
#include <command.h>
#include <net.h>
-#include <miidev.h>
#include <malloc.h>
#include <init.h>
#include <xfuncs.h>
#include <errno.h>
#include <clock.h>
#include <io.h>
+#include <linux/phy.h>
/*---------------------------------------------------------------
.
@@ -447,7 +447,7 @@ struct accessors {
};
struct smc91c111_priv {
- struct mii_device miidev;
+ struct mii_bus miibus;
struct accessors a;
void __iomem *base;
};
@@ -617,11 +617,10 @@ static void smc_wait_mmu_release_complete(struct smc91c111_priv *priv)
}
}
-static int smc91c111_phy_write(struct mii_device *mdev, int phyaddr,
- int phyreg, int phydata)
+static int smc91c111_phy_write(struct mii_bus *bus, int phyaddr,
+ int phyreg, u16 phydata)
{
- struct eth_device *edev = mdev->edev;
- struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv;
+ struct smc91c111_priv *priv = (struct smc91c111_priv *)bus->priv;
int oldBank;
int i;
unsigned mask;
@@ -719,10 +718,9 @@ static int smc91c111_phy_write(struct mii_device *mdev, int phyaddr,
return 0;
}
-static int smc91c111_phy_read(struct mii_device *mdev, int phyaddr, int phyreg)
+static int smc91c111_phy_read(struct mii_bus *bus, int phyaddr, int phyreg)
{
- struct eth_device *edev = mdev->edev;
- struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv;
+ struct smc91c111_priv *priv = (struct smc91c111_priv *)bus->priv;
int oldBank;
int i;
unsigned char mask;
@@ -888,12 +886,15 @@ static void smc91c111_enable(struct eth_device *edev)
static int smc91c111_eth_open(struct eth_device *edev)
{
struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv;
- smc91c111_enable(edev);
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
+ /* Configure the Receive/Phy Control register */
+ SMC_SELECT_BANK(priv, 0);
+ SMC_outw(priv, RPC_DEFAULT, RPC_REG);
- return 0;
+ smc91c111_enable(edev);
+
+ return phy_device_connect(edev, &priv->miibus, 0, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
}
static int smc91c111_eth_send(struct eth_device *edev, void *packet,
@@ -1275,14 +1276,6 @@ static void print_packet( unsigned char * buf, int length )
static int smc91c111_init_dev(struct eth_device *edev)
{
- struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv;
-
- /* Configure the Receive/Phy Control register */
- SMC_SELECT_BANK(priv, 0);
- SMC_outw(priv, RPC_DEFAULT, RPC_REG);
-
- miidev_restart_aneg(&priv->miidev);
-
return 0;
}
@@ -1308,17 +1301,15 @@ static int smc91c111_probe(struct device_d *dev)
edev->set_ethaddr = smc91c111_set_ethaddr;
edev->parent = dev;
- priv->miidev.read = smc91c111_phy_read;
- priv->miidev.write = smc91c111_phy_write;
- priv->miidev.address = 0;
- priv->miidev.flags = 0;
- priv->miidev.edev = edev;
- priv->miidev.parent = dev;
+ priv->miibus.read = smc91c111_phy_read;
+ priv->miibus.write = smc91c111_phy_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
priv->base = dev_request_mem_region(dev, 0);
smc91c111_reset(edev);
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 9dc857ea97..8df6980363 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -26,7 +26,6 @@
#include <command.h>
#include <net.h>
-#include <miidev.h>
#include <malloc.h>
#include <init.h>
#include <xfuncs.h>
@@ -34,12 +33,13 @@
#include <clock.h>
#include <io.h>
#include <smc911x.h>
+#include <linux/phy.h>
#include "smc911x.h"
struct smc911x_priv {
struct eth_device edev;
- struct mii_device miidev;
+ struct mii_bus miibus;
void __iomem *base;
int shift;
@@ -194,9 +194,9 @@ static int smc911x_set_ethaddr(struct eth_device *edev, unsigned char *m)
return 0;
}
-static int smc911x_phy_read(struct mii_device *mdev, int phy_addr, int reg)
+static int smc911x_phy_read(struct mii_bus *bus, int phy_addr, int reg)
{
- struct eth_device *edev = mdev->edev;
+ struct eth_device *edev = bus->priv;
while (smc911x_get_mac_csr(edev, MII_ACC) & MII_ACC_MII_BUSY);
@@ -208,10 +208,10 @@ static int smc911x_phy_read(struct mii_device *mdev, int phy_addr, int reg)
return smc911x_get_mac_csr(edev, MII_DATA);
}
-static int smc911x_phy_write(struct mii_device *mdev, int phy_addr,
- int reg, int val)
+static int smc911x_phy_write(struct mii_bus *bus, int phy_addr,
+ int reg, u16 val)
{
- struct eth_device *edev = mdev->edev;
+ struct eth_device *edev = bus->priv;
while (smc911x_get_mac_csr(edev, MII_ACC) & MII_ACC_MII_BUSY);
@@ -304,9 +304,12 @@ static void smc911x_enable(struct eth_device *edev)
static int smc911x_eth_open(struct eth_device *edev)
{
struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
+ int ret;
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
+ ret = phy_device_connect(edev, &priv->miibus, 1, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
/* Turn on Tx + Rx */
smc911x_enable(edev);
@@ -401,13 +404,9 @@ static int smc911x_eth_rx(struct eth_device *edev)
static int smc911x_init_dev(struct eth_device *edev)
{
- struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
-
smc911x_set_mac_csr(edev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
MAC_CR_HBDIS);
- miidev_restart_aneg(&priv->miidev);
-
return 0;
}
@@ -532,17 +531,15 @@ static int smc911x_probe(struct device_d *dev)
edev->set_ethaddr = smc911x_set_ethaddr;
edev->parent = dev;
- priv->miidev.read = smc911x_phy_read;
- priv->miidev.write = smc911x_phy_write;
- priv->miidev.address = 1;
- priv->miidev.flags = 0;
- priv->miidev.edev = edev;
- priv->miidev.parent = dev;
+ priv->miibus.read = smc911x_phy_read;
+ priv->miibus.write = smc911x_phy_write;
+ priv->miibus.priv = edev;
+ priv->miibus.parent = dev;
smc911x_reset(edev);
smc911x_phy_reset(edev);
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 5c3a1e3f1c..d5c7031982 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -76,7 +76,7 @@ int tap_probe(struct device_d *dev)
struct tap_priv *priv;
int ret = 0;
- priv = xmalloc(sizeof(struct tap_priv));
+ priv = xzalloc(sizeof(struct tap_priv));
priv->name = "barebox";
priv->fd = tap_alloc(priv->name);
@@ -85,7 +85,7 @@ int tap_probe(struct device_d *dev)
goto out;
}
- edev = xmalloc(sizeof(struct eth_device));
+ edev = xzalloc(sizeof(struct eth_device));
edev->priv = priv;
edev->parent = dev;
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index b53dcc7c46..adb1b0b097 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -5,11 +5,11 @@ menuconfig NET_USB
if NET_USB
config NET_USB_ASIX
- select MIIDEV
+ select PHYLIB
bool "Asix compatible"
config NET_USB_SMSC95XX
- select MIIDEV
+ select PHYLIB
bool "SMSC95xx"
endif
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index be5a170d71..97680cfb54 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1,7 +1,7 @@
#include <common.h>
#include <init.h>
#include <net.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include <usb/usb.h>
#include <usb/usbnet.h>
#include <errno.h>
@@ -231,10 +231,9 @@ static inline int asix_set_hw_mii(struct usbnet *dev)
return ret;
}
-static int asix_mdio_read(struct mii_device *mdev, int phy_id, int loc)
+static int asix_mdio_read(struct mii_bus *bus, int phy_id, int loc)
{
- struct eth_device *eth = mdev->edev;
- struct usbnet *dev = eth->priv;
+ struct usbnet *dev = bus->priv;
__le16 res;
asix_set_sw_mii(dev);
@@ -248,10 +247,9 @@ static int asix_mdio_read(struct mii_device *mdev, int phy_id, int loc)
return le16_to_cpu(res);
}
-static int asix_mdio_write(struct mii_device *mdev, int phy_id, int loc, int val)
+static int asix_mdio_write(struct mii_bus *bus, int phy_id, int loc, u16 val)
{
- struct eth_device *eth = mdev->edev;
- struct usbnet *dev = eth->priv;
+ struct usbnet *dev = bus->priv;
__le16 res = cpu_to_le16(val);
dev_dbg(&dev->edev.dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
@@ -469,14 +467,13 @@ static int asix_tx_fixup(struct usbnet *dev,
static int asix_init_mii(struct usbnet *dev)
{
- dev->miidev.read = asix_mdio_read;
- dev->miidev.write = asix_mdio_write;
- dev->miidev.address = asix_get_phy_addr(dev);
- dev->miidev.flags = 0;
- dev->miidev.edev = &dev->edev;
- dev->miidev.parent = &dev->udev->dev;
-
- return mii_register(&dev->miidev);
+ dev->miibus.read = asix_mdio_read;
+ dev->miibus.write = asix_mdio_write;
+ dev->phy_addr = asix_get_phy_addr(dev);
+ dev->miibus.priv = dev;
+ dev->miibus.parent = &dev->udev->dev;
+
+ return mdiobus_register(&dev->miibus);
}
static int ax88172_link_reset(struct usbnet *dev)
@@ -631,7 +628,7 @@ out:
static void asix_unbind(struct usbnet *dev)
{
- mii_unregister(&dev->miidev);
+ mdiobus_unregister(&dev->miibus);
}
static struct driver_info ax8817x_info = {
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index d28a0dfe2b..38ca12f257 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -23,7 +23,7 @@
#include <malloc.h>
#include <asm/byteorder.h>
#include <errno.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include "smsc95xx.h"
#define SMSC_CHIPNAME "smsc95xx"
@@ -119,10 +119,9 @@ static int smsc95xx_phy_wait_not_busy(struct usbnet *dev)
return -EIO;
}
-static int smsc95xx_mdio_read(struct mii_device *mdev, int phy_id, int idx)
+static int smsc95xx_mdio_read(struct mii_bus *bus, int phy_id, int idx)
{
- struct eth_device *eth = mdev->edev;
- struct usbnet *dev = eth->priv;
+ struct usbnet *dev = bus->priv;
u32 val, addr;
/* confirm MII not busy */
@@ -145,11 +144,10 @@ static int smsc95xx_mdio_read(struct mii_device *mdev, int phy_id, int idx)
return val & 0xffff;
}
-static int smsc95xx_mdio_write(struct mii_device *mdev, int phy_id, int idx,
- int regval)
+static int smsc95xx_mdio_write(struct mii_bus *bus, int phy_id, int idx,
+ u16 regval)
{
- struct eth_device *eth = mdev->edev;
- struct usbnet *dev = eth->priv;
+ struct usbnet *dev = bus->priv;
u32 val, addr;
/* confirm MII not busy */
@@ -435,20 +433,19 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
uint16_t val, bmcr;
/* Initialize MII structure */
- dev->miidev.read = smsc95xx_mdio_read;
- dev->miidev.write = smsc95xx_mdio_write;
- dev->miidev.address = 1; /* FIXME: asix_get_phy_addr(dev); */
- dev->miidev.flags = 0;
- dev->miidev.edev = &dev->edev;
- dev->miidev.parent = &dev->udev->dev;
-// dev->miidev.name = dev->edev.name;
+ dev->miibus.read = smsc95xx_mdio_read;
+ dev->miibus.write = smsc95xx_mdio_write;
+ dev->phy_addr = 1; /* FIXME: asix_get_phy_addr(dev); */
+ dev->miibus.priv = dev;
+ dev->miibus.parent = &dev->udev->dev;
+// dev->miibus.name = dev->edev.name;
/* reset phy and wait for reset to complete */
- smsc95xx_mdio_write(&dev->miidev, phy_id, MII_BMCR, BMCR_RESET);
+ smsc95xx_mdio_write(&dev->miibus, phy_id, MII_BMCR, BMCR_RESET);
do {
udelay(10 * 1000);
- bmcr = smsc95xx_mdio_read(&dev->miidev, phy_id, MII_BMCR);
+ bmcr = smsc95xx_mdio_read(&dev->miibus, phy_id, MII_BMCR);
timeout++;
} while ((bmcr & MII_BMCR) && (timeout < 100));
@@ -457,14 +454,14 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
return -EIO;
}
- smsc95xx_mdio_write(&dev->miidev, phy_id, MII_ADVERTISE,
+ smsc95xx_mdio_write(&dev->miibus, phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
/* read to clear */
- val = smsc95xx_mdio_read(&dev->miidev, phy_id, PHY_INT_SRC);
+ val = smsc95xx_mdio_read(&dev->miibus, phy_id, PHY_INT_SRC);
- smsc95xx_mdio_write(&dev->miidev, phy_id, PHY_INT_MASK,
+ smsc95xx_mdio_write(&dev->miibus, phy_id, PHY_INT_MASK,
PHY_INT_MASK_DEFAULT_);
netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n");
@@ -747,7 +744,7 @@ static int smsc95xx_bind(struct usbnet *dev)
dev->edev.get_ethaddr = smsc95xx_get_ethaddr;
dev->edev.set_ethaddr = smsc95xx_set_ethaddr;
- mii_register(&dev->miidev);
+ mdiobus_register(&dev->miibus);
return 0;
}
@@ -756,7 +753,7 @@ static void smsc95xx_unbind(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
- mii_unregister(&dev->miidev);
+ mdiobus_unregister(&dev->miibus);
if (pdata) {
netif_dbg(dev, ifdown, dev->net, "free pdata\n");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index c7e360690e..80b4ae7b9e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -4,6 +4,7 @@
#include <asm/byteorder.h>
#include <errno.h>
#include <malloc.h>
+#include <linux/phy.h>
static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
{
@@ -160,8 +161,6 @@ static int usbnet_init(struct eth_device *edev)
return ret;
}
- miidev_restart_aneg(&dev->miidev);
-
return 0;
}
@@ -171,12 +170,8 @@ static int usbnet_open(struct eth_device *edev)
dev_dbg(&edev->dev, "%s\n",__func__);
- if (miidev_wait_aneg(&dev->miidev))
- return -1;
-
- miidev_print_status(&dev->miidev);
-
- return 0;
+ return phy_device_connect(edev, &dev->miibus, dev->phy_addr, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
}
static void usbnet_halt(struct eth_device *edev)
diff --git a/drivers/nor/cfi_flash.c b/drivers/nor/cfi_flash.c
index 7ca36380a9..f65763a6e6 100644
--- a/drivers/nor/cfi_flash.c
+++ b/drivers/nor/cfi_flash.c
@@ -913,7 +913,6 @@ struct file_operations cfi_ops = {
.memmap = generic_memmap_ro,
};
-#ifdef CONFIG_PARTITION_NEED_MTD
static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
@@ -973,11 +972,11 @@ static void cfi_init_mtd(struct flash_info *info)
mtd->flags = MTD_CAP_NORFLASH;
info->cdev.mtd = mtd;
}
-#endif
static int cfi_probe (struct device_d *dev)
{
struct flash_info *info = xzalloc(sizeof(*info));
+ int cfinum;
dev->priv = (void *)info;
@@ -996,30 +995,46 @@ static int cfi_probe (struct device_d *dev)
dev_info(dev, "found cfi flash at %p, size %ld\n",
info->base, info->size);
- info->cdev.name = asprintf("nor%d", dev->id);
+ if (dev->id < 0)
+ cfinum = cdev_find_free_index("nor");
+ else
+ cfinum = dev->id;
+
+ info->cdev.name = asprintf("nor%d", cfinum);
info->cdev.size = info->size;
info->cdev.dev = dev;
info->cdev.ops = &cfi_ops;
info->cdev.priv = info;
-#ifdef CONFIG_PARTITION_NEED_MTD
- cfi_init_mtd(info);
-#endif
+ if (IS_ENABLED(CONFIG_PARTITION_NEED_MTD))
+ cfi_init_mtd(info);
+
devfs_create(&info->cdev);
+ if (dev->device_node)
+ of_parse_partitions(info->cdev.name, dev->device_node);
+
return 0;
}
+static __maybe_unused struct of_device_id cfi_dt_ids[] = {
+ {
+ .compatible = "cfi-flash",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d cfi_driver = {
- .name = "cfi_flash",
- .probe = cfi_probe,
- .info = cfi_info,
+ .name = "cfi_flash",
+ .probe = cfi_probe,
+ .info = cfi_info,
+ .of_compatible = DRV_OF_COMPAT(cfi_dt_ids),
};
static int cfi_init(void)
{
- return register_driver(&cfi_driver);
+ return register_driver(&cfi_driver);
}
device_initcall(cfi_init);
-
diff --git a/drivers/nor/cfi_flash.h b/drivers/nor/cfi_flash.h
index ee4ea38297..8f818ba4aa 100644
--- a/drivers/nor/cfi_flash.h
+++ b/drivers/nor/cfi_flash.h
@@ -71,9 +71,7 @@ struct flash_info {
ulong addr_unlock2; /* unlock address 2 for AMD flash roms */
struct cfi_cmd_set *cfi_cmd_set;
struct cdev cdev;
-#ifdef CONFIG_PARTITION_NEED_MTD
struct mtd_info mtd;
-#endif
int numeraseregions;
struct mtd_erase_region_info *eraseregions;
void *base;
diff --git a/drivers/nor/m25p80.c b/drivers/nor/m25p80.c
index 5713ad58fe..e3b5b95443 100644
--- a/drivers/nor/m25p80.c
+++ b/drivers/nor/m25p80.c
@@ -648,6 +648,9 @@ static const struct spi_device_id m25p_ids[] = {
{ "cat25c09", CAT25_INFO( 128, 8, 32, 2) },
{ "cat25c17", CAT25_INFO( 256, 8, 32, 2) },
{ "cat25128", CAT25_INFO(2048, 8, 64, 2) },
+
+ /* Micron */
+ { "n25q128", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
{ },
};
@@ -694,6 +697,74 @@ static struct file_operations m25p80_ops = {
.lseek = dev_lseek_default,
};
+static int m25p_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct m25p *flash = container_of(mtd, struct m25p, mtd);
+ ssize_t ret;
+
+ ret = flash->cdev.ops->read(&flash->cdev, buf, len, from, 0);
+ if (ret < 0) {
+ *retlen = 0;
+ return ret;
+ }
+
+ *retlen = ret;
+ return 0;
+}
+
+static int m25p_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct m25p *flash = container_of(mtd, struct m25p, mtd);
+ ssize_t ret;
+
+ ret = flash->cdev.ops->write(&flash->cdev, buf, len, to, 0);
+ if (ret < 0) {
+ *retlen = 0;
+ return ret;
+ }
+
+ *retlen = ret;
+ return 0;
+}
+
+static int m25p_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct m25p *flash = container_of(mtd, struct m25p, mtd);
+ ssize_t ret;
+
+ ret = flash->cdev.ops->erase(&flash->cdev, instr->len, instr->addr);
+
+ if (ret) {
+ instr->state = MTD_ERASE_FAILED;
+ return -EIO;
+ }
+
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
+}
+
+static void m25p_init_mtd(struct m25p *flash)
+{
+ struct mtd_info *mtd = &flash->mtd;
+
+ mtd->read = m25p_mtd_read;
+ mtd->write = m25p_mtd_write;
+ mtd->erase = m25p_mtd_erase;
+ mtd->size = flash->size;
+ mtd->name = flash->cdev.name;
+ mtd->erasesize = flash->erasesize;
+ mtd->writesize = 1;
+ mtd->subpage_sft = 0;
+ mtd->eraseregions = NULL;
+ mtd->numeraseregions = 0;
+ mtd->flags = MTD_CAP_NORFLASH;
+ flash->cdev.mtd = mtd;
+}
+
/*
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
@@ -825,6 +896,9 @@ static int m25p_probe(struct device_d *dev)
dev_info(dev, "%s (%lld Kbytes)\n", id->name, (long long)flash->size >> 10);
+ if (IS_ENABLED(CONFIG_PARTITION_NEED_MTD))
+ m25p_init_mtd(flash);
+
devfs_create(&flash->cdev);
return 0;
@@ -838,7 +912,7 @@ static struct driver_d epcs_flash_driver = {
static int epcs_init(void)
{
- register_driver(&epcs_flash_driver);
+ spi_register_driver(&epcs_flash_driver);
return 0;
}
diff --git a/drivers/nor/m25p80.h b/drivers/nor/m25p80.h
index 34bf2e259a..957900e3a2 100644
--- a/drivers/nor/m25p80.h
+++ b/drivers/nor/m25p80.h
@@ -46,7 +46,7 @@ struct spi_device_id {
struct m25p {
struct spi_device *spi;
struct flash_info *info;
- struct mtd_info mtd;
+ struct mtd_info mtd;
struct cdev cdev;
char *name;
u32 erasesize;
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644
index 0000000000..95f10d025c
--- /dev/null
+++ b/drivers/of/Kconfig
@@ -0,0 +1,2 @@
+config OFDEVICE
+ bool
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644
index 0000000000..c14aaec79f
--- /dev/null
+++ b/drivers/of/Makefile
@@ -0,0 +1,3 @@
+obj-y += base.o
+obj-y += gpio.o
+obj-y += partition.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644
index 0000000000..ebbaef85c1
--- /dev/null
+++ b/drivers/of/base.c
@@ -0,0 +1,802 @@
+/*
+ * base.c - basic devicetree functions
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * based on Linux devicetree support
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <common.h>
+#include <of.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <init.h>
+#include <linux/ctype.h>
+
+/**
+ * struct alias_prop - Alias property in 'aliases' node
+ * @link: List node to link the structure in aliases_lookup list
+ * @alias: Alias property name
+ * @np: Pointer to device_node that the alias stands for
+ * @id: Index value from end of alias name
+ * @stem: Alias string without the index
+ *
+ * The structure represents one alias property of 'aliases' node as
+ * an entry in aliases_lookup list.
+ */
+struct alias_prop {
+ struct list_head link;
+ const char *alias;
+ struct device_node *np;
+ int id;
+ char stem[0];
+};
+
+static LIST_HEAD(aliases_lookup);
+
+static LIST_HEAD(phandle_list);
+
+static LIST_HEAD(allnodes);
+
+struct device_node *root_node;
+
+struct device_node *of_aliases;
+
+int of_n_addr_cells(struct device_node *np)
+{
+ const __be32 *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip)
+ return be32_to_cpup(ip);
+ } while (np->parent);
+ /* No #address-cells property for the root node */
+ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+ const __be32 *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip)
+ return be32_to_cpup(ip);
+ } while (np->parent);
+ /* No #size-cells property for the root node */
+ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+static void of_bus_default_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = of_n_addr_cells(dev);
+ if (sizec)
+ *sizec = of_n_size_cells(dev);
+}
+
+void of_bus_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ of_bus_default_count_cells(dev, addrc, sizec);
+}
+
+struct property *of_find_property(const struct device_node *node, const char *name)
+{
+ struct property *p;
+
+ list_for_each_entry(p, &node->properties, list)
+ if (!strcmp(p->name, name))
+ return p;
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_property);
+
+static void of_alias_add(struct alias_prop *ap, struct device_node *np,
+ int id, const char *stem, int stem_len)
+{
+ ap->np = np;
+ ap->id = id;
+ strncpy(ap->stem, stem, stem_len);
+ ap->stem[stem_len] = 0;
+ list_add_tail(&ap->link, &aliases_lookup);
+ pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
+ ap->alias, ap->stem, ap->id, np->full_name);
+}
+
+/**
+ * of_alias_scan - Scan all properties of 'aliases' node
+ *
+ * The function scans all the properties of 'aliases' node and populates
+ * the global lookup table with the properties. It returns the
+ * number of alias_prop found, or error code in error case.
+ */
+void of_alias_scan(void)
+{
+ struct property *pp;
+
+ of_aliases = of_find_node_by_path("/aliases");
+ if (!of_aliases)
+ return;
+
+ list_for_each_entry(pp, &of_aliases->properties, list) {
+ const char *start = pp->name;
+ const char *end = start + strlen(start);
+ struct device_node *np;
+ struct alias_prop *ap;
+ int id, len;
+
+ /* Skip those we do not want to proceed */
+ if (!strcmp(pp->name, "name") ||
+ !strcmp(pp->name, "phandle") ||
+ !strcmp(pp->name, "linux,phandle"))
+ continue;
+
+ np = of_find_node_by_path(pp->value);
+ if (!np)
+ continue;
+
+ /* walk the alias backwards to extract the id and work out
+ * the 'stem' string */
+ while (isdigit(*(end-1)) && end > start)
+ end--;
+ len = end - start;
+
+ id = simple_strtol(end, 0, 10);
+ if (id < 0)
+ continue;
+
+ /* Allocate an alias_prop with enough space for the stem */
+ ap = xzalloc(sizeof(*ap) + len + 1);
+ if (!ap)
+ continue;
+ ap->alias = start;
+ of_alias_add(ap, np, id, start, len);
+ }
+}
+
+/**
+ * of_alias_get_id - Get alias id for the given device_node
+ * @np: Pointer to the given device_node
+ * @stem: Alias stem of the given device_node
+ *
+ * The function travels the lookup table to get alias id for the given
+ * device_node and alias stem. It returns the alias id if find it.
+ */
+int of_alias_get_id(struct device_node *np, const char *stem)
+{
+ struct alias_prop *app;
+ int id = -ENODEV;
+
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (strcmp(app->stem, stem) != 0)
+ continue;
+
+ if (np == app->np) {
+ id = app->id;
+ break;
+ }
+ }
+
+ return id;
+}
+EXPORT_SYMBOL_GPL(of_alias_get_id);
+
+u64 of_translate_address(struct device_node *node, const __be32 *in_addr)
+{
+ struct property *p;
+ u64 addr = be32_to_cpu(*in_addr);
+
+ while (1) {
+ int na, nc;
+
+ if (!node->parent)
+ return addr;
+
+ node = node->parent;
+ p = of_find_property(node, "ranges");
+ if (!p && node->parent)
+ return OF_BAD_ADDR;
+ of_bus_count_cells(node, &na, &nc);
+ if (na != 1 || nc != 1) {
+ printk("%s: #size-cells != 1 or #address-cells != 1 "
+ "currently not supported\n", node->name);
+ return OF_BAD_ADDR;
+ }
+ }
+}
+EXPORT_SYMBOL(of_translate_address);
+
+/*
+ * of_find_node_by_phandle - Find a node given a phandle
+ * @handle: phandle of the node to find
+ */
+struct device_node *of_find_node_by_phandle(phandle phandle)
+{
+ struct device_node *node;
+
+ list_for_each_entry(node, &phandle_list, phandles)
+ if (node->phandle == phandle)
+ return node;
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp = of_find_property(np, name);
+
+ if (!pp)
+ return NULL;
+
+ if (lenp)
+ *lenp = pp->length;
+
+ return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
+{
+ const char *cp;
+ int cplen, l;
+
+ cp = of_get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (strcmp(cp, compat) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+int of_match(struct device_d *dev, struct driver_d *drv)
+{
+ struct of_device_id *id;
+
+ id = drv->of_compatible;
+
+ while (id->compatible) {
+ if (of_device_is_compatible(dev->device_node, id->compatible) == 1) {
+ dev->of_id_entry = id;
+ return 0;
+ }
+ id++;
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL(of_match);
+
+/**
+ * of_property_read_u32_array - Find and read an array of 32 bit integers
+ * from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_value: pointer to return value, modified only if return value is 0.
+ *
+ * Search for a property in a device node and read 32-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid u32 value can be decoded.
+ */
+int of_property_read_u32_array(const struct device_node *np,
+ const char *propname, u32 *out_values,
+ size_t sz)
+{
+ struct property *prop = of_find_property(np, propname);
+ const __be32 *val;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ if ((sz * sizeof(*out_values)) > prop->length)
+ return -EOVERFLOW;
+
+ val = prop->value;
+ while (sz--)
+ *out_values++ = be32_to_cpup(val++);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_u32_array);
+
+/**
+ * of_parse_phandles_with_args - Find a node pointed by phandle in a list
+ * @np: pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name: property name that specifies phandles' arguments count
+ * @index: index of a phandle to parse out
+ * @out_node: optional pointer to device_node struct pointer (will be filled)
+ * @out_args: optional pointer to arguments pointer (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_node and out_args, on error returns
+ * appropriate errno value.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ * #list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ * #list-cells = <1>;
+ * }
+ *
+ * node3 {
+ * list = <&phandle1 1 2 &phandle2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
+ */
+int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
+ const char *cells_name, int index,
+ struct device_node **out_node,
+ const void **out_args)
+{
+ int ret = -EINVAL;
+ const __be32 *list;
+ const __be32 *list_end;
+ int size;
+ int cur_index = 0;
+ struct device_node *node = NULL;
+ const void *args = NULL;
+
+ list = of_get_property(np, list_name, &size);
+ if (!list) {
+ ret = -ENOENT;
+ goto err0;
+ }
+ list_end = list + size / sizeof(*list);
+
+ while (list < list_end) {
+ const __be32 *cells;
+ phandle phandle;
+
+ phandle = be32_to_cpup(list++);
+ args = list;
+
+ /* one cell hole in the list = <>; */
+ if (!phandle)
+ goto next;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ pr_debug("%s: could not find phandle %d\n",
+ np->full_name, phandle);
+ goto err0;
+ }
+
+ cells = of_get_property(node, cells_name, &size);
+ if (!cells || size != sizeof(*cells)) {
+ pr_debug("%s: could not get %s for %s\n",
+ np->full_name, cells_name, node->full_name);
+ goto err1;
+ }
+
+ list += be32_to_cpup(cells);
+ if (list > list_end) {
+ pr_debug("%s: insufficient arguments length\n",
+ np->full_name);
+ goto err1;
+ }
+next:
+ if (cur_index == index)
+ break;
+
+ node = NULL;
+ args = NULL;
+ cur_index++;
+ }
+
+ if (!node) {
+ /*
+ * args w/o node indicates that the loop above has stopped at
+ * the 'hole' cell. Report this differently.
+ */
+ if (args)
+ ret = -EEXIST;
+ else
+ ret = -ENOENT;
+ goto err0;
+ }
+
+ if (out_node)
+ *out_node = node;
+ if (out_args)
+ *out_args = args;
+
+ return 0;
+err1:
+err0:
+ pr_debug("%s failed with status %d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL(of_parse_phandles_with_args);
+
+/**
+ * of_machine_is_compatible - Test root of device tree for a given compatible value
+ * @compat: compatible string to look for in root node's compatible property.
+ *
+ * Returns true if the root node has the given value in its
+ * compatible property.
+ */
+int of_machine_is_compatible(const char *compat)
+{
+ if (!root_node)
+ return 0;
+
+ return of_device_is_compatible(root_node, compat);
+}
+EXPORT_SYMBOL(of_machine_is_compatible);
+
+/**
+ * of_find_node_by_path - Find a node matching a full OF path
+ * @path: The full path to match
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+ struct device_node *np;
+
+ list_for_each_entry(np, &allnodes, list) {
+ if (np->full_name && (strcmp(np->full_name, path) == 0))
+ break;
+ }
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+struct device_node *of_get_root_node(void)
+{
+ return root_node;
+}
+
+static int of_node_disabled(struct device_node *node)
+{
+ struct property *p;
+
+ p = of_find_property(node, "status");
+ if (p) {
+ if (!strcmp("disabled", p->value))
+ return 1;
+ }
+ return 0;
+}
+
+void of_print_nodes(struct device_node *node, int indent)
+{
+ struct device_node *n;
+ struct property *p;
+ int i;
+
+ if (!node)
+ return;
+
+ if (of_node_disabled(node))
+ return;
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+
+ printf("%s%s\n", node->name, node->name ? " {" : "{");
+
+ list_for_each_entry(p, &node->properties, list) {
+ for (i = 0; i < indent + 1; i++)
+ printf("\t");
+ printf("%s: ", p->name);
+ of_print_property(p->value, p->length);
+ printf("\n");
+ }
+
+ list_for_each_entry(n, &node->children, parent_list) {
+ of_print_nodes(n, indent + 1);
+ }
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+ printf("};\n");
+}
+
+static struct device_node *new_device_node(struct device_node *parent)
+{
+ struct device_node *node;
+
+ node = xzalloc(sizeof(*node));
+ node->parent = parent;
+ if (parent)
+ list_add_tail(&node->parent_list, &parent->children);
+
+ INIT_LIST_HEAD(&node->children);
+ INIT_LIST_HEAD(&node->properties);
+
+ return node;
+}
+
+static struct property *new_property(struct device_node *node, const char *name,
+ const void *data, int len)
+{
+ struct property *prop;
+
+ prop = xzalloc(sizeof(*prop));
+
+ prop->name = strdup(name);
+ prop->length = len;
+ prop->value = xzalloc(len);
+ memcpy(prop->value, data, len);
+
+ list_add_tail(&prop->list, &node->properties);
+
+ return prop;
+}
+
+static struct device_d *add_of_device(struct device_node *node)
+{
+ struct device_d *dev;
+ char *name, *at;
+ const struct property *cp;
+
+ if (of_node_disabled(node))
+ return NULL;
+
+ cp = of_get_property(node, "compatible", NULL);
+ if (!cp)
+ return NULL;
+
+ dev = xzalloc(sizeof(*dev));
+
+ name = xstrdup(node->name);
+ at = strchr(name, '@');
+ if (at) {
+ *at = 0;
+ snprintf(dev->name, MAX_DRIVER_NAME, "%s.%s", at + 1, name);
+ } else {
+ strncpy(dev->name, node->name, MAX_DRIVER_NAME);
+ }
+
+ dev->id = DEVICE_ID_SINGLE;
+ dev->resource = node->resource;
+ dev->num_resources = 1;
+ dev->device_node = node;
+ node->device = dev;
+
+ debug("register device 0x%08x\n", node->resource[0].start);
+
+ register_device(dev);
+
+ free(name);
+
+ return dev;
+}
+EXPORT_SYMBOL(add_of_device);
+
+static int add_of_device_resource(struct device_node *node)
+{
+ struct property *reg;
+ u64 address, size;
+ struct resource *res;
+ struct device_d *dev;
+ phandle phandle;
+ int ret;
+
+ ret = of_property_read_u32(node, "phandle", &phandle);
+ if (!ret) {
+ node->phandle = phandle;
+ list_add_tail(&node->phandles, &phandle_list);
+ }
+
+ reg = of_find_property(node, "reg");
+ if (!reg)
+ return -ENODEV;
+
+ address = of_translate_address(node, reg->value);
+ if (address == OF_BAD_ADDR)
+ return -EINVAL;
+
+ size = be32_to_cpu(((u32 *)reg->value)[1]);
+
+ /*
+ * A device may already be registered as platform_device.
+ * Instead of registering the same device again, just
+ * add this node to the existing device.
+ */
+ for_each_device(dev) {
+ if (!dev->resource)
+ continue;
+ if (dev->resource->start == address) {
+ debug("connecting %s to %s\n", node->name, dev_name(dev));
+ node->device = dev;
+ dev->device_node = node;
+ node->resource = dev->resource;
+ return 0;
+ }
+ }
+
+ res = xzalloc(sizeof(*res));
+ res->start = address;
+ res->end = address + size - 1;
+ res->flags = IORESOURCE_MEM;
+
+ node->resource = res;
+
+ add_of_device(node);
+
+ return 0;
+}
+
+void of_free(struct device_node *node)
+{
+ struct device_node *n, *nt;
+ struct property *p, *pt;
+
+ if (!node)
+ return;
+
+ list_for_each_entry_safe(p, pt, &node->properties, list) {
+ list_del(&p->list);
+ free(p->name);
+ free(p->value);
+ free(p);
+ }
+
+ list_for_each_entry_safe(n, nt, &node->children, parent_list) {
+ of_free(n);
+ }
+
+ if (node->parent)
+ list_del(&node->parent_list);
+
+ if (node->device)
+ node->device->device_node = NULL;
+ else
+ free(node->resource);
+
+ free(node->name);
+ free(node->full_name);
+ free(node);
+}
+
+static void __of_probe(struct device_node *node)
+{
+ struct device_node *n;
+
+ if (node->device)
+ return;
+
+ add_of_device_resource(node);
+
+ list_for_each_entry(n, &node->children, parent_list)
+ __of_probe(n);
+}
+
+int of_probe(void)
+{
+ if(!root_node)
+ return -ENODEV;
+
+ __of_probe(root_node);
+
+ return 0;
+}
+
+/*
+ * Parse a flat device tree binary blob and store it in the barebox
+ * internal tree format,
+ */
+int of_parse_dtb(struct fdt_header *fdt)
+{
+ const void *nodep; /* property node pointer */
+ int nodeoffset; /* node offset from libfdt */
+ int nextoffset; /* next node offset from libfdt */
+ uint32_t tag; /* tag */
+ int len; /* length of the property */
+ int level = 0; /* keep track of nesting level */
+ const struct fdt_property *fdt_prop;
+ const char *pathp;
+ int depth = 10000;
+ struct device_node *node = NULL;
+ char buf[1024];
+ int ret;
+
+ if (root_node)
+ return -EBUSY;
+
+ nodeoffset = fdt_path_offset(fdt, "/");
+ if (nodeoffset < 0) {
+ /*
+ * Not found or something else bad happened.
+ */
+ printf ("libfdt fdt_path_offset() returned %s\n",
+ fdt_strerror(nodeoffset));
+ return -EINVAL;
+ }
+
+ while (1) {
+ tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ pathp = fdt_get_name(fdt, nodeoffset, NULL);
+
+ if (pathp == NULL)
+ pathp = "/* NULL pointer error */";
+
+ ret = fdt_get_path(fdt, nodeoffset, buf, 1024);
+ if (ret)
+ return -EINVAL;
+
+ node = new_device_node(node);
+ if (!node->parent)
+ root_node = node;
+ node->full_name = xstrdup(buf);
+ node->name = xstrdup(pathp);
+ list_add_tail(&node->list, &allnodes);
+ break;
+ case FDT_END_NODE:
+ node = node->parent;
+ break;
+ case FDT_PROP:
+ fdt_prop = fdt_offset_ptr(fdt, nodeoffset,
+ sizeof(*fdt_prop));
+ pathp = fdt_string(fdt,
+ fdt32_to_cpu(fdt_prop->nameoff));
+ len = fdt32_to_cpu(fdt_prop->len);
+ nodep = fdt_prop->data;
+ new_property(node, pathp, nodep, len);
+ break;
+ case FDT_NOP:
+ break;
+ case FDT_END:
+ of_alias_scan();
+ return 0;
+ default:
+ if (level <= depth)
+ printf("Unknown tag 0x%08X\n", tag);
+ return -EINVAL;
+ }
+ nodeoffset = nextoffset;
+ }
+
+ return 0;
+}
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
new file mode 100644
index 0000000000..d4314f3e28
--- /dev/null
+++ b/drivers/of/gpio.c
@@ -0,0 +1,28 @@
+#define DEBUG
+
+#include <common.h>
+#include <errno.h>
+#include <of.h>
+#include <gpio.h>
+
+int of_get_named_gpio(struct device_node *np,
+ const char *propname, int index)
+{
+ int ret;
+ struct device_node *gpio_np;
+ const void *gpio_spec;
+
+ ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index,
+ &gpio_np, &gpio_spec);
+ if (ret) {
+ pr_debug("%s: can't parse gpios property: %d\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = gpio_get_num(gpio_np->device, be32_to_cpup(gpio_spec));
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
diff --git a/drivers/of/partition.c b/drivers/of/partition.c
new file mode 100644
index 0000000000..6a57a6036e
--- /dev/null
+++ b/drivers/of/partition.c
@@ -0,0 +1,64 @@
+/*
+ * partition.c - devicetree partition parsing
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * based on Linux devicetree support
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <common.h>
+#include <of.h>
+#include <malloc.h>
+#include <linux/mtd/mtd.h>
+
+int of_parse_partitions(const char *cdevname,
+ struct device_node *node)
+{
+ struct device_node *n;
+ const char *partname;
+ char *filename;
+
+ device_node_for_nach_child(node, n) {
+ const __be32 *reg;
+ unsigned long offset, size;
+ const char *name;
+ int len;
+ unsigned long flags = 0;
+
+ reg = of_get_property(n, "reg", &len);
+ if (!reg)
+ continue;
+
+ offset = be32_to_cpu(reg[0]);
+ size = be32_to_cpu(reg[1]);
+
+ partname = of_get_property(n, "label", &len);
+ if (!partname)
+ partname = of_get_property(n, "name", &len);
+ name = (char *)partname;
+
+ debug("add partition: %s.%s 0x%08lx 0x%08lx\n", cdevname, partname, offset, size);
+
+ if (of_get_property(n, "read-only", &len))
+ flags = DEVFS_PARTITION_READONLY;
+
+ filename = asprintf("%s.%s", cdevname, partname);
+
+ devfs_add_partition(cdevname, offset, size, flags, filename);
+
+ free(filename);
+ }
+
+ return 0;
+}
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index c6e61ee104..58c69e5c2d 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -31,6 +31,7 @@
#include <linux/amba/serial.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/amba/bus.h>
/*
* We wrap our port structure around the generic console_device.
@@ -40,6 +41,23 @@ struct amba_uart_port {
struct console_device uart; /* uart */
struct clk *clk; /* uart clock */
u32 uartclk;
+ struct vendor_data *vendor;
+};
+
+/* There is by now at least one vendor with differing details, so handle it */
+struct vendor_data {
+ unsigned int lcrh_tx;
+ unsigned int lcrh_rx;
+};
+
+static struct vendor_data vendor_arm = {
+ .lcrh_tx = UART011_LCRH,
+ .lcrh_rx = UART011_LCRH,
+};
+
+static struct vendor_data vendor_st = {
+ .lcrh_tx = ST_UART011_LCRH_TX,
+ .lcrh_rx = ST_UART011_LCRH_RX,
};
static inline struct amba_uart_port *
@@ -112,13 +130,27 @@ static int pl011_tstc(struct console_device *cdev)
return !(readl(uart->base + UART01x_FR) & UART01x_FR_RXFE);
}
+static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr)
+{
+ struct vendor_data *vendor = uart->vendor;
+
+ writew(lcr, uart->base + vendor->lcrh_rx);
+ if (vendor->lcrh_tx != vendor->lcrh_rx) {
+ int i;
+ /*
+ * Wait 10 PCLKs before writing LCRH_TX register,
+ * to get this delay write read only register 10 times
+ */
+ for (i = 0; i < 10; ++i)
+ writew(0xff, uart->base + UART011_MIS);
+ writew(lcr, uart->base + vendor->lcrh_tx);
+ }
+}
+
int pl011_init_port (struct console_device *cdev)
{
- struct device_d *dev = cdev->dev;
struct amba_uart_port *uart = to_amba_uart_port(cdev);
- uart->base = dev_request_mem_region(dev, 0);
-
/*
** First, disable everything.
*/
@@ -138,8 +170,7 @@ int pl011_init_port (struct console_device *cdev)
/*
** Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled.
*/
- writel((UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN),
- uart->base + UART011_LCRH);
+ pl011_rlcr(uart, UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN);
/*
** Finally, enable the UART
@@ -150,19 +181,21 @@ int pl011_init_port (struct console_device *cdev)
return 0;
}
-static int pl011_probe(struct device_d *dev)
+static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct amba_uart_port *uart;
struct console_device *cdev;
uart = xzalloc(sizeof(struct amba_uart_port));
- uart->clk = clk_get(dev, NULL);
+ uart->clk = clk_get(&dev->dev, NULL);
+ uart->base = amba_get_mem_region(dev);
+ uart->vendor = (void*)id->data;
if (IS_ERR(uart->clk))
return PTR_ERR(uart->clk);
cdev = &uart->uart;
- cdev->dev = dev;
+ cdev->dev = &dev->dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
cdev->tstc = pl011_tstc;
cdev->putc = pl011_putc;
@@ -178,14 +211,31 @@ static int pl011_probe(struct device_d *dev)
return 0;
}
-static struct driver_d pl011_driver = {
- .name = "uart-pl011",
- .probe = pl011_probe,
+static struct amba_id pl011_ids[] = {
+ {
+ .id = 0x00041011,
+ .mask = 0x000fffff,
+ .data = &vendor_arm,
+ },
+ {
+ .id = 0x00380802,
+ .mask = 0x00ffffff,
+ .data = &vendor_st,
+ },
+ { 0, 0 },
+};
+
+struct amba_driver pl011_driver = {
+ .drv = {
+ .name = "uart-pl011",
+ },
+ .probe = pl011_probe,
+ .id_table = pl011_ids,
};
static int pl011_init(void)
{
- register_driver(&pl011_driver);
+ amba_driver_register(&pl011_driver);
return 0;
}
diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c
index 827e838ff2..012ab028a1 100644
--- a/drivers/serial/serial_imx.c
+++ b/drivers/serial/serial_imx.c
@@ -354,10 +354,23 @@ static void imx_serial_remove(struct device_d *dev)
free(priv);
}
+static __maybe_unused struct of_device_id imx_serial_dt_ids[] = {
+ {
+ .compatible = "fsl,imx1-uart",
+ .data = 0,
+ }, {
+ .compatible = "fsl,imx21-uart",
+ .data = 1,
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d imx_serial_driver = {
- .name = "imx_serial",
- .probe = imx_serial_probe,
+ .name = "imx_serial",
+ .probe = imx_serial_probe,
.remove = imx_serial_remove,
+ .of_compatible = DRV_OF_COMPAT(imx_serial_dt_ids),
};
static int imx_serial_init(void)
diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c
index bdd6e8172a..c3dc6cc863 100644
--- a/drivers/spi/imx_spi.c
+++ b/drivers/spi/imx_spi.c
@@ -20,6 +20,7 @@
#include <spi/spi.h>
#include <xfuncs.h>
#include <io.h>
+#include <errno.h>
#include <gpio.h>
#include <mach/spi.h>
#include <mach/generic.h>
@@ -491,6 +492,32 @@ static struct spi_imx_devtype_data spi_imx_devtype_data[] = {
#endif
};
+static int imx_spi_dt_probe(struct imx_spi *imx)
+{
+ struct device_node *node = imx->master.dev->device_node;
+ int ret, i;
+ u32 num_cs;
+
+ if (!node)
+ return -ENODEV;
+
+ ret = of_property_read_u32(node, "fsl,spi-num-chipselects", &num_cs);
+ if (ret)
+ return ret;
+
+ imx->master.num_chipselect = num_cs;
+ imx->cs_array = xzalloc(sizeof(u32) * num_cs);
+
+ for (i = 0; i < num_cs; i++) {
+ int cs_gpio = of_get_named_gpio(node, "cs-gpios", i);
+ imx->cs_array[i] = cs_gpio;
+ }
+
+ spi_of_register_slaves(&imx->master, node);
+
+ return 0;
+}
+
static int imx_spi_probe(struct device_d *dev)
{
struct spi_master *master;
@@ -505,8 +532,13 @@ static int imx_spi_probe(struct device_d *dev)
master->setup = imx_spi_setup;
master->transfer = imx_spi_transfer;
- master->num_chipselect = pdata->num_chipselect;
- imx->cs_array = pdata->chipselect;
+ if (pdata) {
+ master->num_chipselect = pdata->num_chipselect;
+ imx->cs_array = pdata->chipselect;
+ } else {
+ if (IS_ENABLED(CONFIG_OFDEVICE))
+ imx_spi_dt_probe(imx);
+ }
#ifdef CONFIG_DRIVER_SPI_IMX_0_0
if (cpu_is_mx27())
@@ -532,9 +564,22 @@ static int imx_spi_probe(struct device_d *dev)
return 0;
}
+static __maybe_unused struct of_device_id imx_spi_dt_ids[] = {
+ {
+ .compatible = "fsl,imx27-cspi",
+ }, {
+ .compatible = "fsl,imx35-cspi",
+ }, {
+ .compatible = "fsl,imx51-ecspi",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d imx_spi_driver = {
.name = "imx_spi",
.probe = imx_spi_probe,
+ .of_compatible = DRV_OF_COMPAT(imx_spi_dt_ids),
};
static int imx_spi_init(void)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 39eae4eed7..44040e5f62 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -23,6 +23,8 @@
#include <xfuncs.h>
#include <malloc.h>
#include <errno.h>
+#include <init.h>
+#include <of.h>
/* SPI devices should normally not be created by SPI device drivers; that
* would make them board-specific. Similarly with SPI master drivers.
@@ -73,10 +75,12 @@ struct spi_device *spi_new_device(struct spi_master *master,
proxy->mode = chip->mode;
proxy->bits_per_word = chip->bits_per_word ? chip->bits_per_word : 8;
proxy->dev.platform_data = chip->platform_data;
+ proxy->dev.bus = &spi_bus;
strcpy(proxy->dev.name, chip->name);
/* allocate a free id for this chip */
proxy->dev.id = DEVICE_ID_DYNAMIC;
proxy->dev.type_data = proxy;
+ proxy->dev.device_node = chip->device_node;
dev_add_child(master->dev, &proxy->dev);
/* drivers may modify this initial i/o setup */
@@ -96,6 +100,27 @@ fail:
}
EXPORT_SYMBOL(spi_new_device);
+#ifdef CONFIG_OFDEVICE
+void spi_of_register_slaves(struct spi_master *master, struct device_node *node)
+{
+ struct device_node *n;
+ struct spi_board_info chip;
+ struct property *reg;
+
+ device_node_for_nach_child(node, n) {
+ chip.name = n->name;
+ chip.bus_num = master->bus_num;
+ chip.max_speed_hz = 300000; /* FIXME */
+ reg = of_find_property(n, "reg");
+ if (!reg)
+ continue;
+ chip.chip_select = of_read_number(reg->value, 1);
+ chip.device_node = n;
+ spi_register_board_info(&chip, 1);
+ }
+}
+#endif
+
/**
* spi_register_board_info - register SPI devices for a given board
* @info: array of chip descriptors
@@ -150,6 +175,8 @@ static void scan_boardinfo(struct spi_master *master)
}
}
+static LIST_HEAD(spi_master_list);
+
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
@@ -182,6 +209,8 @@ int spi_register_master(struct spi_master *master)
if (master->num_chipselect == 0)
return -EINVAL;
+ list_add_tail(&master->list, &spi_master_list);
+
/* populate children from any spi device tables */
scan_boardinfo(master);
status = 0;
@@ -236,3 +265,35 @@ int spi_write_then_read(struct spi_device *spi,
return status;
}
EXPORT_SYMBOL(spi_write_then_read);
+
+static int spi_match(struct device_d *dev, struct driver_d *drv)
+{
+ if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node &&
+ drv->of_compatible)
+ return of_match(dev, drv);
+
+ return strcmp(dev->name, drv->name) ? -1 : 0;
+}
+
+static int spi_probe(struct device_d *dev)
+{
+ return dev->driver->probe(dev);
+}
+
+static void spi_remove(struct device_d *dev)
+{
+ dev->driver->remove(dev);
+}
+
+struct bus_type spi_bus = {
+ .name = "spi",
+ .match = spi_match,
+ .probe = spi_probe,
+ .remove = spi_remove,
+};
+
+static int spi_bus_init(void)
+{
+ return bus_register(&spi_bus);
+}
+pure_initcall(spi_bus_init);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 662705ea5f..9dc931bdc6 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1418,3 +1418,8 @@ struct bus_type usb_bus_type = {
.remove = usb_remove,
};
+static int usb_bus_init(void)
+{
+ return bus_register(&usb_bus_type);
+}
+pure_initcall(usb_bus_init);
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index d885570b24..ae6ff74cab 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -125,6 +125,7 @@ int register_framebuffer(struct fb_info *info)
sprintf(dev->name, "fb");
+ info->dev.bus = &fb_bus;
register_device(&info->dev);
dev_add_param(dev, "enable", fb_enable_set, NULL, 0);
dev_set_param(dev, "enable", "0");
@@ -160,19 +161,41 @@ static void fb_info(struct device_d *dev)
printf("\n");
}
-static int fb_probe(struct device_d *hw_dev)
+static struct driver_d fb_driver = {
+ .name = "fb",
+ .info = fb_info,
+};
+
+static int fb_match(struct device_d *dev, struct driver_d *drv)
{
return 0;
}
-static struct driver_d fb_driver = {
- .name = "fb",
+static int fb_probe(struct device_d *dev)
+{
+ return 0;
+}
+
+static void fb_remove(struct device_d *dev)
+{
+}
+
+struct bus_type fb_bus = {
+ .name = "fb",
+ .match = fb_match,
.probe = fb_probe,
- .info = fb_info,
+ .remove = fb_remove,
};
+static int fb_bus_init(void)
+{
+ return bus_register(&fb_bus);
+}
+pure_initcall(fb_bus_init);
+
static int fb_init_driver(void)
{
+ fb_driver.bus = &fb_bus;
register_driver(&fb_driver);
return 0;
}